• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_LRU_BUCKET_H
17 #define OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_LRU_BUCKET_H
18 
19 #include <list>
20 #include <map>
21 #include <mutex>
22 
23 namespace OHOS {
24 template<typename _Key, typename _Tp>
25 class LRUBucket {
26 public:
LRUBucket(size_t capacity)27     LRUBucket(size_t capacity) : size_(0), capacity_(capacity)
28     {
29     }
30 
31     LRUBucket(LRUBucket &&bucket) noexcept = delete;
32     LRUBucket(const LRUBucket &bucket) = delete;
33     LRUBucket &operator=(LRUBucket &&bucket) noexcept = delete;
34     LRUBucket &operator=(const LRUBucket &bucket) = delete;
35 
~LRUBucket()36     ~LRUBucket()
37     {
38         std::lock_guard<decltype(mutex_)> lock(mutex_);
39         while (size_ > 0) {
40             PopBack();
41         }
42     }
43 
Size()44     size_t Size() const
45     {
46         return size_;
47     }
48 
Capacity()49     size_t Capacity() const
50     {
51         return capacity_;
52     }
53 
ResetCapacity(size_t capacity)54     bool ResetCapacity(size_t capacity)
55     {
56         std::lock_guard<decltype(mutex_)> lock(mutex_);
57         capacity_ = capacity;
58         while (capacity_ < size_) {
59             PopBack();
60         }
61         return capacity_ == capacity;
62     }
63 
64     /**
65      * The time complexity is O(log(index size))
66      **/
67     bool Get(const _Key &key, _Tp &value, bool isLRU = true)
68     {
69         std::lock_guard<decltype(mutex_)> lock(mutex_);
70         auto it = indexes_.find(key);
71         if (it != indexes_.end()) {
72             if (isLRU) {
73                 // move node from the list;
74                 Remove(it->second);
75                 // insert node to the head
76                 Insert(&head_, it->second);
77             }
78             value = it->second->value_;
79             return true;
80         }
81         return false;
82     }
83 
84     /**
85      * The time complexity is O(log(index size))
86      **/
Set(const _Key & key,const _Tp & value)87     bool Set(const _Key &key, const _Tp &value)
88     {
89         std::lock_guard<decltype(mutex_)> lock(mutex_);
90         if (capacity_ == 0) {
91             return false;
92         }
93 
94         auto it = indexes_.find(key);
95         if (it != indexes_.end()) {
96             Update(it->second, value);
97             Remove(it->second);
98             Insert(&head_, it->second);
99             return true;
100         }
101 
102         while (capacity_ <= size_) {
103             PopBack();
104         }
105 
106         auto *node = new (std::nothrow) Node(value);
107         if (node == nullptr) {
108             return false;
109         }
110 
111         Insert(&head_, node);
112         auto pair = indexes_.emplace(key, node);
113         node->iterator_ = pair.first;
114         return true;
115     }
116 
117     /**
118      * Just update the values, not change the lru
119      **/
Update(const _Key & key,const _Tp & value)120     bool Update(const _Key &key, const _Tp &value)
121     {
122         std::lock_guard<decltype(mutex_)> lock(mutex_);
123         auto it = indexes_.find(key);
124         if (it != indexes_.end()) {
125             Update(it->second, value);
126             return true;
127         }
128         return false;
129     }
130 
131     /**
132      * The time complexity is O(min(indexes, values))
133      * Just update the values, not change the lru chain
134      */
Update(const std::map<_Key,_Tp> & values)135     bool Update(const std::map<_Key, _Tp> &values)
136     {
137         std::lock_guard<decltype(mutex_)> lock(mutex_);
138         auto idx = indexes_.begin();
139         auto val = values.begin();
140         bool updated = false;
141         auto comp = indexes_.key_comp();
142         while (idx != indexes_.end() && val != values.end()) {
143             if (comp(idx->first, val->first)) {
144                 ++idx;
145                 continue;
146             }
147             if (comp(val->first, idx->first)) {
148                 ++val;
149                 continue;
150             }
151             updated = true;
152             Update(idx->second, val->second);
153             ++idx;
154             ++val;
155         }
156         return updated;
157     }
158 
159     /**
160      * The time complexity is O(log(index size))
161      * */
Delete(const _Key & key)162     bool Delete(const _Key &key)
163     {
164         std::lock_guard<decltype(mutex_)> lock(mutex_);
165         auto it = indexes_.find(key);
166         if (it != indexes_.end()) {
167             Remove(it->second);
168             Delete(it->second);
169             return true;
170         }
171         return false;
172     }
173 
174 private:
175     struct Node final {
176         using iterator = typename std::map<_Key, Node *>::iterator;
Nodefinal177         Node(const _Tp &value) : value_(value) {}
Nodefinal178         Node() : value_() {}
179         ~Node() = default;
180         _Tp value_;
181         iterator iterator_;
182         Node *prev_ = this;
183         Node *next_ = this;
184     };
185 
PopBack()186     void PopBack()
187     {
188         auto *node = head_.prev_;
189         Remove(node);
190         Delete(node);
191     }
192 
Update(Node * node,const _Tp & value)193     void Update(Node *node, const _Tp &value)
194     {
195         node->value_ = value;
196     }
197 
Remove(Node * node)198     void Remove(Node *node)
199     {
200         node->prev_->next_ = node->next_;
201         node->next_->prev_ = node->prev_;
202         size_--;
203     }
204 
Insert(Node * prev,Node * node)205     void Insert(Node *prev, Node *node)
206     {
207         prev->next_->prev_ = node;
208         node->next_ = prev->next_;
209         prev->next_ = node;
210         node->prev_ = prev;
211         size_++;
212     }
213 
Delete(Node * node)214     void Delete(Node *node)
215     {
216         indexes_.erase(node->iterator_);
217         delete node;
218     }
219 
220     mutable std::recursive_mutex mutex_;
221     std::map<_Key, Node *> indexes_;
222     Node head_;
223     size_t size_;
224     size_t capacity_;
225 };
226 } // namespace OHOS
227 #endif // OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_LRU_BUCKET_H
228