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