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