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 #ifndef EXPIRE_LRU_CACHE_H 16 #define EXPIRE_LRU_CACHE_H 17 18 #include <map> 19 #include <mutex> 20 #include <memory> 21 #include <list> 22 #include <algorithm> 23 #include "datetime_ex.h" 24 25 namespace OHOS { 26 namespace { 27 constexpr int64_t DEFAULT_EXPIRE_TIME = 1000; 28 } 29 30 template <typename TKey, typename TValue> 31 class ExpireLruCache { 32 public: 33 ExpireLruCache(size_t cacheSize = 8, int64_t expireTimeSec = 1000) : size_(cacheSize), 34 expireTimeMilliSec_(expireTimeSec) 35 { 36 size_ = (size_ > 0) ? size_ : 1; 37 expireTimeMilliSec_ = (expireTimeMilliSec_ < 0) ? DEFAULT_EXPIRE_TIME : expireTimeMilliSec_; 38 } ~ExpireLruCache()39 ~ExpireLruCache() {} 40 Add(const TKey & key,const TValue & val)41 void Add(const TKey& key, const TValue& val) 42 { 43 std::lock_guard<std::mutex> lock(lock_); 44 DoAdd(key, val); 45 return; 46 } 47 Get(const TKey & key)48 std::shared_ptr<TValue> Get(const TKey& key) 49 { 50 std::lock_guard<std::mutex> lock(lock_); 51 return DoGet(key); 52 } 53 Remove(const TKey & key)54 void Remove(const TKey& key) 55 { 56 std::lock_guard<std::mutex> lock(lock_); 57 return DoRemove(key); 58 } 59 Clear()60 void Clear() 61 { 62 std::lock_guard<std::mutex> lock(lock_); 63 DoClear(); 64 return; 65 } 66 private: 67 class Timestamp { 68 public: Timestamp()69 Timestamp() 70 { 71 ts_ = GetTickCount(); 72 } ~Timestamp()73 ~Timestamp() {} 74 75 int64_t operator-(const Timestamp& ts) 76 { 77 return ts_ - ts.ts_; 78 } 79 IsExpired(int64_t interval)80 bool IsExpired(int64_t interval) const 81 { 82 Timestamp now; 83 int64_t diff = now - *this; 84 return diff > interval; 85 } 86 Raw()87 int64_t Raw() const 88 { 89 return ts_; 90 } 91 private: 92 /* unit:ms */ 93 int64_t ts_; 94 }; 95 size_t size_; 96 int64_t expireTimeMilliSec_; 97 std::mutex lock_; 98 std::map<TKey, std::shared_ptr<TValue>> data_; 99 std::map<TKey, Timestamp> timestamp_; 100 std::list<TKey> keys_; 101 DoAdd(const TKey & key,const TValue & value)102 void DoAdd(const TKey& key, const TValue& value) 103 { 104 Timestamp now; 105 size_t curSize = data_.size(); 106 auto iter = data_.find(key); 107 auto timestampIter = timestamp_.find(key); 108 109 if (iter != data_.end()) { 110 data_.erase(iter); 111 timestamp_.erase(timestampIter); 112 data_.insert(std::make_pair(key, std::make_shared<TValue>(value))); 113 timestamp_.insert(std::make_pair(key, now)); 114 auto keyiter = std::find(keys_.begin(), keys_.end(), key); 115 keys_.splice(keys_.begin(), keys_, keyiter); 116 117 return; 118 } 119 120 if (curSize >= size_) { 121 bool ifClearExpiredCache = false; 122 if (expireTimeMilliSec_ > 0) { 123 ifClearExpiredCache = DoClearExpiredCache(); 124 } 125 if (ifClearExpiredCache == false) { 126 auto lruKey = keys_.back(); 127 data_.erase(lruKey); 128 timestamp_.erase(lruKey); 129 keys_.pop_back(); 130 } 131 } 132 133 data_.insert(std::make_pair(key, std::make_shared<TValue>(value))); 134 timestamp_.insert(std::make_pair(key, now)); 135 keys_.push_front(key); 136 137 return; 138 } 139 DoGet(const TKey & key)140 std::shared_ptr<TValue> DoGet(const TKey& key) 141 { 142 auto dataIter = data_.find(key); 143 if (dataIter == data_.end()) { 144 return nullptr; 145 } 146 147 auto timestampIter = timestamp_.find(key); 148 if ((expireTimeMilliSec_ > 0) && (timestampIter->second.IsExpired(expireTimeMilliSec_))) { 149 data_.erase(dataIter); 150 timestamp_.erase(timestampIter); 151 keys_.remove(key); 152 153 return nullptr; 154 } else { 155 auto keyiter = std::find(keys_.begin(), keys_.end(), key); 156 keys_.splice(keys_.begin(), keys_, keyiter) ; 157 158 return dataIter->second; 159 } 160 } 161 DoRemove(const TKey & key)162 void DoRemove(const TKey& key) 163 { 164 keys_.remove(key); 165 data_.erase(key); 166 timestamp_.erase(key); 167 } 168 DoClear()169 void DoClear() 170 { 171 data_.clear(); 172 timestamp_.clear(); 173 keys_.clear(); 174 } 175 DoClearExpiredCache()176 bool DoClearExpiredCache() 177 { 178 bool ifClear = false; 179 for (auto iter = timestamp_.begin(); iter != timestamp_.end();) { 180 if (iter->second.IsExpired(expireTimeMilliSec_)) { 181 ifClear = true; 182 keys_.remove(iter->first); 183 data_.erase(iter->first); 184 iter = timestamp_.erase(iter); 185 } else { 186 iter++; 187 } 188 } 189 return ifClear; 190 } 191 }; 192 } 193 194 #endif 195