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