1 /* 2 * Copyright (c) 2023 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_INPUTMETHOD_IMF_FRAMEWORKS_COMMON_CONCURRENT_MAP_H 17 #define OHOS_INPUTMETHOD_IMF_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 Emplace(_Args &&...__args)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 184 mapped_type &operator[](const key_type &key) noexcept 185 { 186 std::lock_guard<decltype(mutex_)> lock(mutex_); 187 return entries_[key]; 188 } 189 ForEach(const std::function<bool (const key_type &,mapped_type &)> & action)190 void ForEach(const std::function<bool(const key_type &, mapped_type &)> &action) 191 { 192 if (action == nullptr) { 193 return; 194 } 195 std::lock_guard<decltype(mutex_)> lock(mutex_); 196 for (auto &[key, value] : entries_) { 197 if (action(key, value)) { 198 break; 199 } 200 } 201 } 202 ForEachCopies(const std::function<bool (const key_type &,mapped_type &)> & action)203 void ForEachCopies(const std::function<bool(const key_type &, mapped_type &)> &action) 204 { 205 if (action == nullptr) { 206 return; 207 } 208 auto entries = Clone(); 209 for (auto &[key, value] : entries) { 210 if (action(key, value)) { 211 break; 212 } 213 } 214 } 215 216 // 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)217 bool Compute(const key_type &key, const std::function<bool(const key_type &, mapped_type &)> &action) 218 { 219 if (action == nullptr) { 220 return false; 221 } 222 std::lock_guard<decltype(mutex_)> lock(mutex_); 223 auto it = entries_.find(key); 224 if (it == entries_.end()) { 225 auto result = entries_.emplace(key, mapped_type()); 226 it = result.second ? result.first : entries_.end(); 227 } 228 if (it == entries_.end()) { 229 return false; 230 } 231 if (!action(it->first, it->second)) { 232 entries_.erase(key); 233 } 234 return true; 235 } 236 237 // 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)238 bool ComputeIfPresent(const key_type &key, const std::function<bool(const key_type &, mapped_type &)> &action) 239 { 240 if (action == nullptr) { 241 return false; 242 } 243 std::lock_guard<decltype(mutex_)> lock(mutex_); 244 auto it = entries_.find(key); 245 if (it == entries_.end()) { 246 return false; 247 } 248 if (!action(key, it->second)) { 249 entries_.erase(key); 250 } 251 return true; 252 } 253 ComputeIfAbsent(const key_type & key,const std::function<mapped_type (const key_type &)> & action)254 bool ComputeIfAbsent(const key_type &key, const std::function<mapped_type(const key_type &)> &action) 255 { 256 if (action == nullptr) { 257 return false; 258 } 259 std::lock_guard<decltype(mutex_)> lock(mutex_); 260 auto it = entries_.find(key); 261 if (it != entries_.end()) { 262 return false; 263 } 264 entries_.emplace(key, action(key)); 265 return true; 266 } 267 268 private: Steal()269 std::map<_Key, _Tp> Steal() noexcept 270 { 271 std::lock_guard<decltype(mutex_)> lock(mutex_); 272 return std::move(entries_); 273 } 274 Clone()275 std::map<_Key, _Tp> Clone() const noexcept 276 { 277 std::lock_guard<decltype(mutex_)> lock(mutex_); 278 return entries_; 279 } 280 281 private: 282 mutable std::recursive_mutex mutex_; 283 std::map<_Key, _Tp> entries_; 284 }; 285 } // namespace OHOS 286 #endif // OHOS_INPUTMETHOD_IMF_FRAMEWORKS_COMMON_CONCURRENT_MAP_H 287