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 Insert(const key_type & key,const mapped_type & value)95 bool Insert(const key_type &key, const mapped_type &value) noexcept 96 { 97 std::lock_guard<decltype(mutex_)> lock(mutex_); 98 auto it = entries_.insert(value_type { key, value }); 99 return it.second; 100 } 101 Erase(const key_type & key)102 size_type Erase(const key_type &key) noexcept 103 { 104 std::lock_guard<decltype(mutex_)> lock(mutex_); 105 return entries_.erase(key); 106 } 107 Clear()108 void Clear() noexcept 109 { 110 std::lock_guard<decltype(mutex_)> lock(mutex_); 111 return entries_.clear(); 112 } 113 Empty()114 bool Empty() const noexcept 115 { 116 std::lock_guard<decltype(mutex_)> lock(mutex_); 117 return entries_.empty(); 118 } 119 Size()120 size_type Size() const noexcept 121 { 122 std::lock_guard<decltype(mutex_)> lock(mutex_); 123 return entries_.size(); 124 } 125 EraseIf(const std::function<bool (const key_type & key,mapped_type & value)> & action)126 size_type EraseIf(const std::function<bool(const key_type &key, mapped_type &value)> &action) noexcept 127 { 128 if (action == nullptr) { 129 return 0; 130 } 131 std::lock_guard<decltype(mutex_)> lock(mutex_); 132 #if __cplusplus > 201703L 133 auto count = std::erase_if(entries_, 134 [&action](value_type &value) -> bool { return action(value.first, value.second); }); 135 #else 136 auto count = entries_.size(); 137 for (auto it = entries_.begin(); it != entries_.end();) { 138 if (action((*it).first, (*it).second)) { 139 it = entries_.erase(it); 140 } else { 141 ++it; 142 } 143 } 144 count -= entries_.size(); 145 #endif 146 return count; 147 } 148 149 mapped_type &operator[](const key_type &key) noexcept 150 { 151 std::lock_guard<decltype(mutex_)> lock(mutex_); 152 return entries_[key]; 153 } 154 ForEach(const std::function<bool (const key_type &,mapped_type &)> & action)155 void ForEach(const std::function<bool(const key_type &, mapped_type &)> &action) 156 { 157 if (action == nullptr) { 158 return; 159 } 160 std::lock_guard<decltype(mutex_)> lock(mutex_); 161 for (auto &[key, value] : entries_) { 162 if (action(key, value)) { 163 break; 164 } 165 } 166 } 167 Compute(const key_type & key,const std::function<bool (const key_type &,mapped_type &)> & action)168 bool Compute(const key_type &key, const std::function<bool(const key_type &, mapped_type &)> &action) 169 { 170 if (action == nullptr) { 171 return false; 172 } 173 std::lock_guard<decltype(mutex_)> lock(mutex_); 174 auto it = entries_.find(key); 175 if (it == entries_.end()) { 176 auto result = entries_.emplace(key, mapped_type()); 177 it = result.second ? result.first : entries_.end(); 178 } 179 if (it == entries_.end()) { 180 return false; 181 } 182 action(it->first, it->second); 183 return true; 184 } 185 ComputeIfPresent(const key_type & key,const std::function<void (const key_type &,mapped_type &)> & action)186 bool ComputeIfPresent(const key_type &key, const std::function<void(const key_type &, mapped_type &)> &action) 187 { 188 if (action == nullptr) { 189 return false; 190 } 191 std::lock_guard<decltype(mutex_)> lock(mutex_); 192 auto it = entries_.find(key); 193 if (it == entries_.end()) { 194 return false; 195 } 196 action(key, it->second); 197 return true; 198 } 199 ComputeIfAbsent(const key_type & key,const std::function<mapped_type (const key_type &)> & action)200 bool ComputeIfAbsent(const key_type &key, const std::function<mapped_type(const key_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 entries_.insert(value_type{key, action(key)}); 211 return true; 212 } 213 private: Steal()214 std::map<_Key, _Tp> Steal() noexcept 215 { 216 std::lock_guard<decltype(mutex_)> lock(mutex_); 217 return std::move(entries_); 218 } 219 Clone()220 std::map<_Key, _Tp> Clone() const noexcept 221 { 222 std::lock_guard<decltype(mutex_)> lock(mutex_); 223 return entries_; 224 } 225 private: 226 mutable std::recursive_mutex mutex_; 227 std::map<_Key, _Tp> entries_; 228 }; 229 } 230 #endif // OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_CONCURRENT_MAP_H 231