• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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