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_CONCURRENT_MAP_H 17 #define OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_CONCURRENT_MAP_H 18 #include <functional> 19 #include <map> 20 #include <mutex> 21 namespace OHOS { 22 template<typename _Key, typename _Tp> 23 class ConcurrentMap { 24 template<typename _First, typename... _Rest> 25 static _First First(); 26 27 public: 28 using map_type = typename std::map<_Key, _Tp>; 29 using filter_type = typename std::function<bool(map_type &)>; 30 using key_type = typename std::map<_Key, _Tp>::key_type; 31 using mapped_type = typename std::map<_Key, _Tp>::mapped_type; 32 using value_type = typename std::map<_Key, _Tp>::value_type; 33 using size_type = typename std::map<_Key, _Tp>::size_type; 34 using reference = typename std::map<_Key, _Tp>::reference; 35 using const_reference = typename std::map<_Key, _Tp>::const_reference; 36 37 ConcurrentMap() = default; ~ConcurrentMap()38 ~ConcurrentMap() 39 { 40 Clear(); 41 } 42 ConcurrentMap(const ConcurrentMap & other)43 ConcurrentMap(const ConcurrentMap &other) 44 { 45 operator=(std::move(other)); 46 } 47 48 ConcurrentMap &operator=(const ConcurrentMap &other) noexcept 49 { 50 if (this == &other) { 51 return *this; 52 } 53 auto tmp = other.Clone(); 54 std::lock_guard<decltype(mutex_)> lock(mutex_); 55 entries_ = std::move(tmp); 56 return *this; 57 } 58 ConcurrentMap(ConcurrentMap && other)59 ConcurrentMap(ConcurrentMap &&other) noexcept 60 { 61 operator=(std::move(other)); 62 } 63 64 ConcurrentMap &operator=(ConcurrentMap &&other) noexcept 65 { 66 if (this == &other) { 67 return *this; 68 } 69 auto tmp = other.Steal(); 70 std::lock_guard<decltype(mutex_)> lock(mutex_); 71 entries_ = std::move(tmp); 72 return *this; 73 } 74 Emplace()75 bool Emplace() noexcept 76 { 77 std::lock_guard<decltype(mutex_)> lock(mutex_); 78 auto it = entries_.emplace(); 79 return it.second; 80 } 81 82 template<typename... _Args> 83 typename std::enable_if<!std::is_convertible_v<decltype(First<_Args...>()), filter_type>, bool>::type 84 Emplace(_Args &&...args) noexcept 85 { 86 std::lock_guard<decltype(mutex_)> lock(mutex_); 87 auto it = entries_.emplace(std::forward<_Args>(args)...); 88 return it.second; 89 } 90 91 template<typename _Filter, typename... _Args> 92 typename std::enable_if<std::is_convertible_v<_Filter, filter_type>, bool>::type Emplace(const _Filter & filter,_Args &&...args)93 Emplace(const _Filter &filter, _Args &&...args) noexcept 94 { 95 std::lock_guard<decltype(mutex_)> lock(mutex_); 96 if (!filter(entries_)) { 97 return false; 98 } 99 auto it = entries_.emplace(std::forward<_Args>(args)...); 100 return it.second; 101 } 102 Find(const key_type & key)103 std::pair<bool, mapped_type> Find(const key_type &key) const noexcept 104 { 105 std::lock_guard<decltype(mutex_)> lock(mutex_); 106 auto it = entries_.find(key); 107 if (it == entries_.end()) { 108 return std::pair { false, mapped_type() }; 109 } 110 111 return std::pair { true, it->second }; 112 } 113 ContainIf(const key_type & key,const std::function<bool (const mapped_type & value)> & action)114 bool ContainIf(const key_type &key, const std::function<bool(const mapped_type &value)> &action) const noexcept 115 { 116 std::lock_guard<decltype(mutex_)> lock(mutex_); 117 auto it = entries_.find(key); 118 if (it == entries_.end()) { 119 return false; 120 } 121 if (action) { 122 return action(it->second); 123 } 124 return true; 125 } 126 Contains(const key_type & key)127 bool Contains(const key_type &key) const noexcept 128 { 129 std::lock_guard<decltype(mutex_)> lock(mutex_); 130 return (entries_.find(key) != entries_.end()); 131 } 132 133 template <typename _Obj> InsertOrAssign(const key_type & key,_Obj && obj)134 bool InsertOrAssign(const key_type &key, _Obj &&obj) noexcept 135 { 136 std::lock_guard<decltype(mutex_)> lock(mutex_); 137 auto it = entries_.insert_or_assign(key, std::forward<_Obj>(obj)); 138 return it.second; 139 } 140 Insert(const key_type & key,const mapped_type & value)141 bool Insert(const key_type &key, const mapped_type &value) noexcept 142 { 143 std::lock_guard<decltype(mutex_)> lock(mutex_); 144 auto it = entries_.insert(value_type { key, value }); 145 return it.second; 146 } 147 Erase(const key_type & key)148 size_type Erase(const key_type &key) noexcept 149 { 150 std::lock_guard<decltype(mutex_)> lock(mutex_); 151 return entries_.erase(key); 152 } 153 Clear()154 void Clear() noexcept 155 { 156 std::lock_guard<decltype(mutex_)> lock(mutex_); 157 return entries_.clear(); 158 } 159 Empty()160 bool Empty() const noexcept 161 { 162 std::lock_guard<decltype(mutex_)> lock(mutex_); 163 return entries_.empty(); 164 } 165 Size()166 size_type Size() const noexcept 167 { 168 std::lock_guard<decltype(mutex_)> lock(mutex_); 169 return entries_.size(); 170 } 171 172 // The action`s return true means meeting the erase condition 173 // The action`s return false means not meeting the erase condition EraseIf(const std::function<bool (const key_type & key,mapped_type & value)> & action)174 size_type EraseIf(const std::function<bool(const key_type &key, mapped_type &value)> &action) noexcept 175 { 176 if (action == nullptr) { 177 return 0; 178 } 179 std::lock_guard<decltype(mutex_)> lock(mutex_); 180 #if __cplusplus > 201703L 181 auto count = std::erase_if(entries_, 182 [&action](value_type &value) -> bool { return action(value.first, value.second); }); 183 #else 184 auto count = entries_.size(); 185 for (auto it = entries_.begin(); it != entries_.end();) { 186 if (action((*it).first, (*it).second)) { 187 it = entries_.erase(it); 188 } else { 189 ++it; 190 } 191 } 192 count -= entries_.size(); 193 #endif 194 return count; 195 } 196 ForEach(const std::function<bool (const key_type &,mapped_type &)> & action)197 void ForEach(const std::function<bool(const key_type &, mapped_type &)> &action) 198 { 199 if (action == nullptr) { 200 return; 201 } 202 std::lock_guard<decltype(mutex_)> lock(mutex_); 203 for (auto &[key, value] : entries_) { 204 if (action(key, value)) { 205 break; 206 } 207 } 208 } 209 ForEachCopies(const std::function<bool (const key_type &,mapped_type &)> & action)210 void ForEachCopies(const std::function<bool(const key_type &, mapped_type &)> &action) 211 { 212 if (action == nullptr) { 213 return; 214 } 215 auto entries = Clone(); 216 for (auto &[key, value] : entries) { 217 if (action(key, value)) { 218 break; 219 } 220 } 221 } 222 223 // The action's return value means that the element is keep in map or not; true means keeping, false means removing. Compute(const key_type & key,const std::function<bool (const key_type &,mapped_type &)> & action)224 bool Compute(const key_type &key, const std::function<bool(const key_type &, mapped_type &)> &action) 225 { 226 if (action == nullptr) { 227 return false; 228 } 229 std::lock_guard<decltype(mutex_)> lock(mutex_); 230 auto it = entries_.find(key); 231 if (it == entries_.end()) { 232 auto result = entries_.emplace(key, mapped_type()); 233 it = result.second ? result.first : entries_.end(); 234 } 235 if (it == entries_.end()) { 236 return false; 237 } 238 if (!action(it->first, it->second)) { 239 entries_.erase(key); 240 } 241 return true; 242 } 243 244 // The action's return value means that the element is keep in map or not; true means keeping, false means removing. ComputeIfPresent(const key_type & key,const std::function<bool (const key_type &,mapped_type &)> & action)245 bool ComputeIfPresent(const key_type &key, const std::function<bool(const key_type &, mapped_type &)> &action) 246 { 247 if (action == nullptr) { 248 return false; 249 } 250 std::lock_guard<decltype(mutex_)> lock(mutex_); 251 auto it = entries_.find(key); 252 if (it == entries_.end()) { 253 return false; 254 } 255 if (!action(key, it->second)) { 256 entries_.erase(key); 257 } 258 return true; 259 } 260 ComputeIfAbsent(const key_type & key,const std::function<mapped_type (const key_type &)> & action)261 bool ComputeIfAbsent(const key_type &key, const std::function<mapped_type(const key_type &)> &action) 262 { 263 if (action == nullptr) { 264 return false; 265 } 266 std::lock_guard<decltype(mutex_)> lock(mutex_); 267 auto it = entries_.find(key); 268 if (it != entries_.end()) { 269 return false; 270 } 271 entries_.emplace(key, action(key)); 272 return true; 273 } 274 DoActionIfEmpty(const std::function<void (void)> & action)275 void DoActionIfEmpty(const std::function<void(void)> &action) 276 { 277 if (action == nullptr) { 278 return; 279 } 280 std::lock_guard<decltype(mutex_)> lock(mutex_); 281 if (entries_.empty()) { 282 action(); 283 } 284 return; 285 } 286 287 private: Steal()288 std::map<_Key, _Tp> Steal() noexcept 289 { 290 std::lock_guard<decltype(mutex_)> lock(mutex_); 291 return std::move(entries_); 292 } 293 Clone()294 std::map<_Key, _Tp> Clone() const noexcept 295 { 296 std::lock_guard<decltype(mutex_)> lock(mutex_); 297 return entries_; 298 } 299 300 private: 301 mutable std::recursive_mutex mutex_; 302 std::map<_Key, _Tp> entries_; 303 }; 304 } // namespace OHOS 305 #endif // OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_CONCURRENT_MAP_H 306