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