1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef NETMANAGER_BASE_LRU_CACHE_H
17#define NETMANAGER_BASE_LRU_CACHE_H
18
19#include <list>
20#include <mutex>
21#include <string>
22#include <unordered_map>
23#include <vector>
24
25namespace OHOS::NetManagerStandard {
26static constexpr const size_t DEFAULT_CAPABILITY = 600;
27template <typename T> class LRUCache {
28public:
29    LRUCache() : capacity_(DEFAULT_CAPABILITY) {}
30
31    std::vector<T> Get(const std::string &key)
32    {
33        std::lock_guard<std::mutex> guard(mutex_);
34
35        if (cache_.find(key) == cache_.end()) {
36            return {};
37        }
38        auto it = cache_[key];
39        auto value = it->value;
40        MoveNodeToHead(it);
41        return value;
42    }
43
44    void Put(const std::string &key, const T &value)
45    {
46        std::lock_guard<std::mutex> guard(mutex_);
47
48        if (cache_.find(key) == cache_.end()) {
49            AddNode(Node(key, {value}));
50            if (cache_.size() > capacity_) {
51                EraseTailNode();
52            }
53            return;
54        }
55
56        auto it = cache_[key];
57        it->value.emplace_back(value);
58        MoveNodeToHead(it);
59        if (cache_.size() > capacity_) {
60            EraseTailNode();
61        }
62    }
63
64    void Delete(const std::string &key)
65    {
66        std::lock_guard<std::mutex> guard(mutex_);
67
68        if (cache_.find(key) == cache_.end()) {
69            return;
70        }
71
72        auto it = cache_[key];
73        cache_.erase(key);
74        nodeList_.erase(it);
75    }
76
77    void Clear()
78    {
79        std::lock_guard<std::mutex> guard(mutex_);
80
81        cache_.clear();
82        nodeList_.clear();
83    }
84
85private:
86    struct Node {
87        std::string key;
88        std::vector<T> value;
89
90        Node() = delete;
91
92        Node(std::string key, std::vector<T> value) : key(std::move(key)), value(std::move(value)) {}
93    };
94
95    void AddNode(const Node &node)
96    {
97        nodeList_.emplace_front(node);
98        cache_[node.key] = nodeList_.begin();
99    }
100
101    void MoveNodeToHead(const typename std::list<Node>::iterator &it)
102    {
103        std::string key = it->key;
104        auto value = it->value;
105        nodeList_.erase(it);
106        nodeList_.emplace_front(key, value);
107        cache_[key] = nodeList_.begin();
108    }
109
110    void EraseTailNode()
111    {
112        if (nodeList_.empty()) {
113            return;
114        }
115        Node node = nodeList_.back();
116        nodeList_.pop_back();
117        cache_.erase(node.key);
118    }
119
120    std::mutex mutex_;
121    std::unordered_map<std::string, typename std::list<Node>::iterator> cache_;
122    std::list<Node> nodeList_;
123    size_t capacity_;
124};
125} // namespace OHOS::NetManagerStandard
126#endif // NETMANAGER_BASE_LRU_CACHE_H
127