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