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 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 mains meet the erase condition 135 // The action`s return false mains not meet 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 178 // The action's return value mains that the element is keep in map or not; true mains keep, false mains remove. Compute(const key_type & key,const std::function<bool (const key_type &,mapped_type &)> & action)179 bool Compute(const key_type &key, const std::function<bool(const key_type &, mapped_type &)> &action) 180 { 181 if (action == nullptr) { 182 return false; 183 } 184 std::lock_guard<decltype(mutex_)> lock(mutex_); 185 auto it = entries_.find(key); 186 if (it == entries_.end()) { 187 auto result = entries_.emplace(key, mapped_type()); 188 it = result.second ? result.first : entries_.end(); 189 } 190 if (it == entries_.end()) { 191 return false; 192 } 193 if (!action(it->first, it->second)) { 194 entries_.erase(key); 195 } 196 return true; 197 } 198 199 // The action's return value mains that the element is keep in map or not; true mains keep, false mains remove. ComputeIfPresent(const key_type & key,const std::function<bool (const key_type &,mapped_type &)> & action)200 bool ComputeIfPresent(const key_type &key, const std::function<bool(const key_type &, mapped_type &)> &action) 201 { 202 if (action == nullptr) { 203 return false; 204 } 205 std::lock_guard<decltype(mutex_)> lock(mutex_); 206 auto it = entries_.find(key); 207 if (it == entries_.end()) { 208 return false; 209 } 210 if (!action(key, it->second)) { 211 entries_.erase(key); 212 } 213 return true; 214 } 215 ComputeIfAbsent(const key_type & key,const std::function<mapped_type (const key_type &)> & action)216 bool ComputeIfAbsent(const key_type &key, const std::function<mapped_type(const key_type &)> &action) 217 { 218 if (action == nullptr) { 219 return false; 220 } 221 std::lock_guard<decltype(mutex_)> lock(mutex_); 222 auto it = entries_.find(key); 223 if (it != entries_.end()) { 224 return false; 225 } 226 entries_.emplace(key, action(key)); 227 return true; 228 } 229 230 private: Steal()231 std::map<_Key, _Tp> Steal() noexcept 232 { 233 std::lock_guard<decltype(mutex_)> lock(mutex_); 234 return std::move(entries_); 235 } 236 Clone()237 std::map<_Key, _Tp> Clone() const noexcept 238 { 239 std::lock_guard<decltype(mutex_)> lock(mutex_); 240 return entries_; 241 } 242 243 private: 244 mutable std::recursive_mutex mutex_; 245 std::map<_Key, _Tp> entries_; 246 }; 247 } // namespace OHOS 248 #endif // OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_CONCURRENT_MAP_H 249