1 /* 2 * Copyright (c) 2021 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 UTILS_BASE_SAFE_MAP_H 17 #define UTILS_BASE_SAFE_MAP_H 18 19 #include <map> 20 #include <mutex> 21 22 namespace OHOS { 23 24 /** 25 * @brief Provides interfaces for thread-safe map operations. 26 */ 27 template <typename K, typename V> 28 class SafeMap { 29 public: SafeMap()30 SafeMap() {} 31 ~SafeMap()32 ~SafeMap() {} 33 SafeMap(const SafeMap & rhs)34 SafeMap(const SafeMap& rhs) 35 { 36 operator=(rhs); 37 } 38 39 SafeMap& operator=(const SafeMap& rhs) 40 { 41 if (this == &rhs) { 42 return *this; 43 } 44 auto tmp = rhs.Clone(); 45 std::lock_guard<std::mutex> lock(mutex_); 46 map_ = std::move(tmp); 47 48 return *this; 49 } 50 ReadVal(const K & key)51 V ReadVal(const K& key) 52 { 53 std::lock_guard<std::mutex> lock(mutex_); 54 return map_[key]; 55 } 56 57 template<typename LambdaCallback> ChangeValueByLambda(const K & key,LambdaCallback callback)58 void ChangeValueByLambda(const K& key, LambdaCallback callback) 59 { 60 std::lock_guard<std::mutex> lock(mutex_); 61 callback(map_[key]); 62 } 63 64 /** 65 * @brief Obtains the map size. 66 * 67 * In the multithread scenario, the map size returned is a tmp status, 68 * because elements may be inserted or removed by other threads after 69 * <b>Size()</b> is called. 70 */ Size()71 int Size() 72 { 73 std::lock_guard<std::mutex> lock(mutex_); 74 return map_.size(); 75 } 76 77 /** 78 * @brief Checks whether the map is empty. 79 * 80 * In the multithread scenario, the value returned by <b>Empty()</b> is a 81 * tmp status, because elements may be inserted or removed by other threads 82 * after <b>Empty()</b> is called. 83 * 84 * @return Returns <b>true</b> if the map is empty; 85 * returns <b>false</b> otherwise. 86 */ IsEmpty()87 bool IsEmpty() 88 { 89 std::lock_guard<std::mutex> lock(mutex_); 90 return map_.empty(); 91 } 92 93 /** 94 * @brief Inserts an element to the map. 95 * 96 * @param key Indicates the key of the key-value (KV) pair to insert. 97 * @param value Indicates the value of the KV pair to insert. 98 * @return Returns <b>true</b> if the KV pair is inserted; returns 99 * <b>false</b> otherwise. 100 */ Insert(const K & key,const V & value)101 bool Insert(const K& key, const V& value) 102 { 103 std::lock_guard<std::mutex> lock(mutex_); 104 auto ret = map_.insert(std::pair<K, V>(key, value)); 105 return ret.second; 106 } 107 108 /** 109 * @brief Forcibly inserts an element to the map. 110 * 111 * @param key Indicates the key of the KV pair to insert. 112 * @param value Indicates the value of the KV pair to insert. 113 * @note If the key to insert already exists, delete and then insert 114 * the KV pair to ensure that the value is inserted. 115 */ EnsureInsert(const K & key,const V & value)116 void EnsureInsert(const K& key, const V& value) 117 { 118 std::lock_guard<std::mutex> lock(mutex_); 119 auto ret = map_.insert(std::pair<K, V>(key, value)); 120 // find key and cannot insert 121 if (!ret.second) { 122 map_.erase(ret.first); 123 map_.insert(std::pair<K, V>(key, value)); 124 return; 125 } 126 return; 127 } 128 129 /** 130 * @brief Searches for an element in the map. 131 * 132 * @param Key Indicates the key to search. 133 * @param value Indicates the value of the KV pair to search. 134 * @return Returns <b>true</b> if the KV pair is found; 135 * returns <b>false</b> otherwise. 136 */ Find(const K & key,V & value)137 bool Find(const K& key, V& value) 138 { 139 bool ret = false; 140 std::lock_guard<std::mutex> lock(mutex_); 141 142 auto iter = map_.find(key); 143 if (iter != map_.end()) { 144 value = iter->second; 145 ret = true; 146 } 147 148 return ret; 149 } 150 151 /** 152 * @brief Replaces the value of a KV pair. 153 * 154 * @param Key Indicates the key of the KV pair. 155 * @param oldValue Indicates the value to be replaced. 156 * @param newValue Indicates the new value of the KV pair. 157 * @return Returns <b>true</b> if the key is replaced; 158 * returns <b>false</b> otherwise. 159 */ FindOldAndSetNew(const K & key,V & oldValue,const V & newValue)160 bool FindOldAndSetNew(const K& key, V& oldValue, const V& newValue) 161 { 162 bool ret = false; 163 std::lock_guard<std::mutex> lock(mutex_); 164 if (map_.size() > 0) { 165 auto iter = map_.find(key); 166 if (iter != map_.end()) { 167 oldValue = iter->second; 168 map_.erase(iter); 169 map_.insert(std::pair<K, V>(key, newValue)); 170 ret = true; 171 } 172 } 173 174 return ret; 175 } 176 177 /** 178 * @brief Erases a KV pair. 179 * 180 * @param Key Indicates the key of the KV pair to erase. 181 */ Erase(const K & key)182 void Erase(const K& key) 183 { 184 std::lock_guard<std::mutex> lock(mutex_); 185 map_.erase(key); 186 } 187 188 /** 189 * @brief Deletes all KV pairs from the map. 190 */ Clear()191 void Clear() 192 { 193 std::lock_guard<std::mutex> lock(mutex_); 194 map_.clear(); 195 return; 196 } 197 198 using SafeMapCallBack = std::function<void(const K, V&)>; 199 200 /** 201 * @brief Iterates over the elements of the map. 202 * 203 * @param callback Called to perform the custom operations on 204 * each KV pair. 205 */ Iterate(const SafeMapCallBack & callback)206 void Iterate(const SafeMapCallBack& callback) 207 { 208 std::lock_guard<std::mutex> lock(mutex_); 209 if (!map_.empty()) { 210 for (auto it = map_.begin(); it != map_.end(); it++) { 211 callback(it -> first, it -> second); 212 } 213 } 214 } 215 216 private: 217 mutable std::mutex mutex_; 218 std::map<K, V> map_; 219 Clone()220 std::map<K, V> Clone() const noexcept 221 { 222 std::lock_guard<std::mutex> lock(mutex_); 223 return map_; 224 } 225 }; 226 227 } // namespace OHOS 228 #endif 229