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 Contains(const key_type & key)114 bool Contains(const key_type &key) const noexcept 115 { 116 std::lock_guard<decltype(mutex_)> lock(mutex_); 117 return (entries_.find(key) != entries_.end()); 118 } 119 120 template <typename _Obj> InsertOrAssign(const key_type & key,_Obj && obj)121 bool InsertOrAssign(const key_type &key, _Obj &&obj) noexcept 122 { 123 std::lock_guard<decltype(mutex_)> lock(mutex_); 124 auto it = entries_.insert_or_assign(key, std::forward<_Obj>(obj)); 125 return it.second; 126 } 127 Insert(const key_type & key,const mapped_type & value)128 bool Insert(const key_type &key, const mapped_type &value) noexcept 129 { 130 std::lock_guard<decltype(mutex_)> lock(mutex_); 131 auto it = entries_.insert(value_type { key, value }); 132 return it.second; 133 } 134 Erase(const key_type & key)135 size_type Erase(const key_type &key) noexcept 136 { 137 std::lock_guard<decltype(mutex_)> lock(mutex_); 138 return entries_.erase(key); 139 } 140 Clear()141 void Clear() noexcept 142 { 143 std::lock_guard<decltype(mutex_)> lock(mutex_); 144 return entries_.clear(); 145 } 146 Empty()147 bool Empty() const noexcept 148 { 149 std::lock_guard<decltype(mutex_)> lock(mutex_); 150 return entries_.empty(); 151 } 152 Size()153 size_type Size() const noexcept 154 { 155 std::lock_guard<decltype(mutex_)> lock(mutex_); 156 return entries_.size(); 157 } 158 159 // The action`s return true means meeting the erase condition 160 // The action`s return false means not meeting the erase condition EraseIf(const std::function<bool (const key_type & key,mapped_type & value)> & action)161 size_type EraseIf(const std::function<bool(const key_type &key, mapped_type &value)> &action) noexcept 162 { 163 if (action == nullptr) { 164 return 0; 165 } 166 std::lock_guard<decltype(mutex_)> lock(mutex_); 167 #if __cplusplus > 201703L 168 auto count = std::erase_if(entries_, 169 [&action](value_type &value) -> bool { return action(value.first, value.second); }); 170 #else 171 auto count = entries_.size(); 172 for (auto it = entries_.begin(); it != entries_.end();) { 173 if (action((*it).first, (*it).second)) { 174 it = entries_.erase(it); 175 } else { 176 ++it; 177 } 178 } 179 count -= entries_.size(); 180 #endif 181 return count; 182 } 183 ForEach(const std::function<bool (const key_type &,mapped_type &)> & action)184 void ForEach(const std::function<bool(const key_type &, mapped_type &)> &action) 185 { 186 if (action == nullptr) { 187 return; 188 } 189 std::lock_guard<decltype(mutex_)> lock(mutex_); 190 for (auto &[key, value] : entries_) { 191 if (action(key, value)) { 192 break; 193 } 194 } 195 } 196 ForEachCopies(const std::function<bool (const key_type &,mapped_type &)> & action)197 void ForEachCopies(const std::function<bool(const key_type &, mapped_type &)> &action) 198 { 199 if (action == nullptr) { 200 return; 201 } 202 auto entries = Clone(); 203 for (auto &[key, value] : entries) { 204 if (action(key, value)) { 205 break; 206 } 207 } 208 } 209 210 // 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)211 bool Compute(const key_type &key, const std::function<bool(const key_type &, mapped_type &)> &action) 212 { 213 if (action == nullptr) { 214 return false; 215 } 216 std::lock_guard<decltype(mutex_)> lock(mutex_); 217 auto it = entries_.find(key); 218 if (it == entries_.end()) { 219 auto result = entries_.emplace(key, mapped_type()); 220 it = result.second ? result.first : entries_.end(); 221 } 222 if (it == entries_.end()) { 223 return false; 224 } 225 if (!action(it->first, it->second)) { 226 entries_.erase(key); 227 } 228 return true; 229 } 230 231 // 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)232 bool ComputeIfPresent(const key_type &key, const std::function<bool(const key_type &, mapped_type &)> &action) 233 { 234 if (action == nullptr) { 235 return false; 236 } 237 std::lock_guard<decltype(mutex_)> lock(mutex_); 238 auto it = entries_.find(key); 239 if (it == entries_.end()) { 240 return false; 241 } 242 if (!action(key, it->second)) { 243 entries_.erase(key); 244 } 245 return true; 246 } 247 ComputeIfAbsent(const key_type & key,const std::function<mapped_type (const key_type &)> & action)248 bool ComputeIfAbsent(const key_type &key, const std::function<mapped_type(const key_type &)> &action) 249 { 250 if (action == nullptr) { 251 return false; 252 } 253 std::lock_guard<decltype(mutex_)> lock(mutex_); 254 auto it = entries_.find(key); 255 if (it != entries_.end()) { 256 return false; 257 } 258 entries_.emplace(key, action(key)); 259 return true; 260 } 261 262 private: Steal()263 std::map<_Key, _Tp> Steal() noexcept 264 { 265 std::lock_guard<decltype(mutex_)> lock(mutex_); 266 return std::move(entries_); 267 } 268 Clone()269 std::map<_Key, _Tp> Clone() const noexcept 270 { 271 std::lock_guard<decltype(mutex_)> lock(mutex_); 272 return entries_; 273 } 274 275 private: 276 mutable std::recursive_mutex mutex_; 277 std::map<_Key, _Tp> entries_; 278 }; 279 } // namespace OHOS 280 #endif // OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_CONCURRENT_MAP_H 281