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