1 /*
2  * Copyright (c) 2021 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 UTILS_BASE_SAFE_MAP_H
17 #define UTILS_BASE_SAFE_MAP_H
18 
19 #include <map>
20 #include <mutex>
21 
22 namespace OHOS {
23 
24 /**
25  * @brief Provides interfaces for thread-safe map operations.
26  */
27 template <typename K, typename V>
28 class SafeMap {
29 public:
SafeMap()30     SafeMap() {}
31 
~SafeMap()32     ~SafeMap() {}
33 
SafeMap(const SafeMap & rhs)34     SafeMap(const SafeMap& rhs)
35     {
36         operator=(rhs);
37     }
38 
39     SafeMap& operator=(const SafeMap& rhs)
40     {
41         if (this == &rhs) {
42             return *this;
43         }
44         auto tmp = rhs.Clone();
45         std::lock_guard<std::mutex> lock(mutex_);
46         map_ = std::move(tmp);
47 
48         return *this;
49     }
50 
ReadVal(const K & key)51     V ReadVal(const K& key)
52     {
53         std::lock_guard<std::mutex> lock(mutex_);
54         return map_[key];
55     }
56 
57     template<typename LambdaCallback>
ChangeValueByLambda(const K & key,LambdaCallback callback)58     void ChangeValueByLambda(const K& key, LambdaCallback callback)
59     {
60         std::lock_guard<std::mutex> lock(mutex_);
61         callback(map_[key]);
62     }
63 
64     /**
65      * @brief Obtains the map size.
66      *
67      * In the multithread scenario, the map size returned is a tmp status,
68      * because elements may be inserted or removed by other threads after
69      * <b>Size()</b> is called.
70      */
Size()71     int Size()
72     {
73         std::lock_guard<std::mutex> lock(mutex_);
74         return map_.size();
75     }
76 
77     /**
78      * @brief Checks whether the map is empty.
79      *
80      * In the multithread scenario, the value returned by <b>Empty()</b> is a
81      * tmp status, because elements may be inserted or removed by other threads
82      * after <b>Empty()</b> is called.
83      *
84      * @return Returns <b>true</b> if the map is empty;
85      * returns <b>false</b> otherwise.
86      */
IsEmpty()87     bool IsEmpty()
88     {
89         std::lock_guard<std::mutex> lock(mutex_);
90         return map_.empty();
91     }
92 
93     /**
94      * @brief Inserts an element to the map.
95      *
96      * @param key Indicates the key of the key-value (KV) pair to insert.
97      * @param value Indicates the value of the KV pair to insert.
98      * @return Returns <b>true</b> if the KV pair is inserted; returns
99      * <b>false</b> otherwise.
100      */
Insert(const K & key,const V & value)101     bool Insert(const K& key, const V& value)
102     {
103         std::lock_guard<std::mutex> lock(mutex_);
104         auto ret = map_.insert(std::pair<K, V>(key, value));
105         return ret.second;
106     }
107 
108     /**
109      * @brief Forcibly inserts an element to the map.
110      *
111      * @param key Indicates the key of the KV pair to insert.
112      * @param value Indicates the value of the KV pair to insert.
113      * @note If the key to insert already exists, delete and then insert
114      * the KV pair to ensure that the value is inserted.
115      */
EnsureInsert(const K & key,const V & value)116     void EnsureInsert(const K& key, const V& value)
117     {
118         std::lock_guard<std::mutex> lock(mutex_);
119         auto ret = map_.insert(std::pair<K, V>(key, value));
120         // find key and cannot insert
121         if (!ret.second) {
122             map_.erase(ret.first);
123             map_.insert(std::pair<K, V>(key, value));
124             return;
125         }
126         return;
127     }
128 
129     /**
130      * @brief Searches for an element in the map.
131      *
132      * @param Key Indicates the key to search.
133      * @param value Indicates the value of the KV pair to search.
134      * @return Returns <b>true</b> if the KV pair is found;
135      * returns <b>false</b> otherwise.
136      */
Find(const K & key,V & value)137     bool Find(const K& key, V& value)
138     {
139         bool ret = false;
140         std::lock_guard<std::mutex> lock(mutex_);
141 
142         auto iter = map_.find(key);
143         if (iter != map_.end()) {
144             value = iter->second;
145             ret = true;
146         }
147 
148         return ret;
149     }
150 
151     /**
152      * @brief Replaces the value of a KV pair.
153      *
154      * @param Key Indicates the key of the KV pair.
155      * @param oldValue Indicates the value to be replaced.
156      * @param newValue Indicates the new value of the KV pair.
157      * @return Returns <b>true</b> if the key is replaced;
158      * returns <b>false</b> otherwise.
159      */
FindOldAndSetNew(const K & key,V & oldValue,const V & newValue)160     bool FindOldAndSetNew(const K& key, V& oldValue, const V& newValue)
161     {
162         bool ret = false;
163         std::lock_guard<std::mutex> lock(mutex_);
164         if (map_.size() > 0) {
165             auto iter = map_.find(key);
166             if (iter != map_.end()) {
167                 oldValue = iter->second;
168                 map_.erase(iter);
169                 map_.insert(std::pair<K, V>(key, newValue));
170                 ret = true;
171             }
172         }
173 
174         return ret;
175     }
176 
177     /**
178      * @brief Erases a KV pair.
179      *
180      * @param Key Indicates the key of the KV pair to erase.
181      */
Erase(const K & key)182     void Erase(const K& key)
183     {
184         std::lock_guard<std::mutex> lock(mutex_);
185         map_.erase(key);
186     }
187 
188     /**
189      * @brief Deletes all KV pairs from the map.
190      */
Clear()191     void Clear()
192     {
193         std::lock_guard<std::mutex> lock(mutex_);
194         map_.clear();
195         return;
196     }
197 
198     using SafeMapCallBack = std::function<void(const K, V&)>;
199 
200     /**
201      * @brief Iterates over the elements of the map.
202      *
203      * @param callback Called to perform the custom operations on
204      * each KV pair.
205      */
Iterate(const SafeMapCallBack & callback)206     void Iterate(const SafeMapCallBack& callback)
207     {
208         std::lock_guard<std::mutex> lock(mutex_);
209         if (!map_.empty()) {
210             for (auto it = map_.begin(); it != map_.end(); it++) {
211                 callback(it -> first, it -> second);
212             }
213         }
214     }
215 
216 private:
217     mutable std::mutex mutex_;
218     std::map<K, V> map_;
219 
Clone()220     std::map<K, V> Clone() const noexcept
221     {
222         std::lock_guard<std::mutex> lock(mutex_);
223         return map_;
224     }
225 };
226 
227 } // namespace OHOS
228 #endif
229