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 
25 namespace OHOS::NetManagerStandard {
26 static constexpr const size_t DEFAULT_CAPABILITY = 100;
27 template <typename T> class LRUCache {
28 public:
LRUCache()29     LRUCache() : capacity_(DEFAULT_CAPABILITY) {}
30 
Get(const std::string & key)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 
Put(const std::string & key,const T & value)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 
Delete(const std::string & key)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 
Clear()77     void Clear()
78     {
79         std::lock_guard<std::mutex> guard(mutex_);
80 
81         cache_.clear();
82         nodeList_.clear();
83     }
84 
85 private:
86     struct Node {
87         std::string key;
88         std::vector<T> value;
89 
90         Node() = delete;
91 
NodeNode92         Node(std::string key, std::vector<T> value) : key(std::move(key)), value(std::move(value)) {}
93     };
94 
AddNode(const Node & node)95     void AddNode(const Node &node)
96     {
97         nodeList_.emplace_front(node);
98         cache_[node.key] = nodeList_.begin();
99     }
100 
MoveNodeToHead(const typename std::list<Node>::iterator & it)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 
EraseTailNode()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