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