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