13f4cbf05Sopenharmony_ci/*
23f4cbf05Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
33f4cbf05Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43f4cbf05Sopenharmony_ci * you may not use this file except in compliance with the License.
53f4cbf05Sopenharmony_ci * You may obtain a copy of the License at
63f4cbf05Sopenharmony_ci *
73f4cbf05Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
83f4cbf05Sopenharmony_ci *
93f4cbf05Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103f4cbf05Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113f4cbf05Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123f4cbf05Sopenharmony_ci * See the License for the specific language governing permissions and
133f4cbf05Sopenharmony_ci * limitations under the License.
143f4cbf05Sopenharmony_ci */
153f4cbf05Sopenharmony_ci
163f4cbf05Sopenharmony_ci#ifndef UTILS_BASE_SAFE_MAP_H
173f4cbf05Sopenharmony_ci#define UTILS_BASE_SAFE_MAP_H
183f4cbf05Sopenharmony_ci
193f4cbf05Sopenharmony_ci#include <map>
203f4cbf05Sopenharmony_ci#include <mutex>
213f4cbf05Sopenharmony_ci
223f4cbf05Sopenharmony_cinamespace OHOS {
233f4cbf05Sopenharmony_ci
243f4cbf05Sopenharmony_ci/**
253f4cbf05Sopenharmony_ci * @brief Provides interfaces for thread-safe map operations.
263f4cbf05Sopenharmony_ci */
273f4cbf05Sopenharmony_citemplate <typename K, typename V>
283f4cbf05Sopenharmony_ciclass SafeMap {
293f4cbf05Sopenharmony_cipublic:
303f4cbf05Sopenharmony_ci    SafeMap() {}
313f4cbf05Sopenharmony_ci
323f4cbf05Sopenharmony_ci    ~SafeMap() {}
333f4cbf05Sopenharmony_ci
343f4cbf05Sopenharmony_ci    SafeMap(const SafeMap& rhs)
353f4cbf05Sopenharmony_ci    {
363f4cbf05Sopenharmony_ci        operator=(rhs);
373f4cbf05Sopenharmony_ci    }
383f4cbf05Sopenharmony_ci
393f4cbf05Sopenharmony_ci    SafeMap& operator=(const SafeMap& rhs)
403f4cbf05Sopenharmony_ci    {
413f4cbf05Sopenharmony_ci        if (this == &rhs) {
423f4cbf05Sopenharmony_ci            return *this;
433f4cbf05Sopenharmony_ci        }
443f4cbf05Sopenharmony_ci        auto tmp = rhs.Clone();
453f4cbf05Sopenharmony_ci        std::lock_guard<std::mutex> lock(mutex_);
463f4cbf05Sopenharmony_ci        map_ = std::move(tmp);
473f4cbf05Sopenharmony_ci
483f4cbf05Sopenharmony_ci        return *this;
493f4cbf05Sopenharmony_ci    }
503f4cbf05Sopenharmony_ci
513f4cbf05Sopenharmony_ci    V ReadVal(const K& key)
523f4cbf05Sopenharmony_ci    {
533f4cbf05Sopenharmony_ci        std::lock_guard<std::mutex> lock(mutex_);
543f4cbf05Sopenharmony_ci        return map_[key];
553f4cbf05Sopenharmony_ci    }
563f4cbf05Sopenharmony_ci
573f4cbf05Sopenharmony_ci    template<typename LambdaCallback>
583f4cbf05Sopenharmony_ci    void ChangeValueByLambda(const K& key, LambdaCallback callback)
593f4cbf05Sopenharmony_ci    {
603f4cbf05Sopenharmony_ci        std::lock_guard<std::mutex> lock(mutex_);
613f4cbf05Sopenharmony_ci        callback(map_[key]);
623f4cbf05Sopenharmony_ci    }
633f4cbf05Sopenharmony_ci
643f4cbf05Sopenharmony_ci    /**
653f4cbf05Sopenharmony_ci     * @brief Obtains the map size.
663f4cbf05Sopenharmony_ci     *
673f4cbf05Sopenharmony_ci     * In the multithread scenario, the map size returned is a tmp status,
683f4cbf05Sopenharmony_ci     * because elements may be inserted or removed by other threads after
693f4cbf05Sopenharmony_ci     * <b>Size()</b> is called.
703f4cbf05Sopenharmony_ci     */
713f4cbf05Sopenharmony_ci    int Size()
723f4cbf05Sopenharmony_ci    {
733f4cbf05Sopenharmony_ci        std::lock_guard<std::mutex> lock(mutex_);
743f4cbf05Sopenharmony_ci        return map_.size();
753f4cbf05Sopenharmony_ci    }
763f4cbf05Sopenharmony_ci
773f4cbf05Sopenharmony_ci    /**
783f4cbf05Sopenharmony_ci     * @brief Checks whether the map is empty.
793f4cbf05Sopenharmony_ci     *
803f4cbf05Sopenharmony_ci     * In the multithread scenario, the value returned by <b>Empty()</b> is a
813f4cbf05Sopenharmony_ci     * tmp status, because elements may be inserted or removed by other threads
823f4cbf05Sopenharmony_ci     * after <b>Empty()</b> is called.
833f4cbf05Sopenharmony_ci     *
843f4cbf05Sopenharmony_ci     * @return Returns <b>true</b> if the map is empty;
853f4cbf05Sopenharmony_ci     * returns <b>false</b> otherwise.
863f4cbf05Sopenharmony_ci     */
873f4cbf05Sopenharmony_ci    bool IsEmpty()
883f4cbf05Sopenharmony_ci    {
893f4cbf05Sopenharmony_ci        std::lock_guard<std::mutex> lock(mutex_);
903f4cbf05Sopenharmony_ci        return map_.empty();
913f4cbf05Sopenharmony_ci    }
923f4cbf05Sopenharmony_ci
933f4cbf05Sopenharmony_ci    /**
943f4cbf05Sopenharmony_ci     * @brief Inserts an element to the map.
953f4cbf05Sopenharmony_ci     *
963f4cbf05Sopenharmony_ci     * @param key Indicates the key of the key-value (KV) pair to insert.
973f4cbf05Sopenharmony_ci     * @param value Indicates the value of the KV pair to insert.
983f4cbf05Sopenharmony_ci     * @return Returns <b>true</b> if the KV pair is inserted; returns
993f4cbf05Sopenharmony_ci     * <b>false</b> otherwise.
1003f4cbf05Sopenharmony_ci     */
1013f4cbf05Sopenharmony_ci    bool Insert(const K& key, const V& value)
1023f4cbf05Sopenharmony_ci    {
1033f4cbf05Sopenharmony_ci        std::lock_guard<std::mutex> lock(mutex_);
1043f4cbf05Sopenharmony_ci        auto ret = map_.insert(std::pair<K, V>(key, value));
1053f4cbf05Sopenharmony_ci        return ret.second;
1063f4cbf05Sopenharmony_ci    }
1073f4cbf05Sopenharmony_ci
1083f4cbf05Sopenharmony_ci    /**
1093f4cbf05Sopenharmony_ci     * @brief Forcibly inserts an element to the map.
1103f4cbf05Sopenharmony_ci     *
1113f4cbf05Sopenharmony_ci     * @param key Indicates the key of the KV pair to insert.
1123f4cbf05Sopenharmony_ci     * @param value Indicates the value of the KV pair to insert.
1133f4cbf05Sopenharmony_ci     * @note If the key to insert already exists, delete and then insert
1143f4cbf05Sopenharmony_ci     * the KV pair to ensure that the value is inserted.
1153f4cbf05Sopenharmony_ci     */
1163f4cbf05Sopenharmony_ci    void EnsureInsert(const K& key, const V& value)
1173f4cbf05Sopenharmony_ci    {
1183f4cbf05Sopenharmony_ci        std::lock_guard<std::mutex> lock(mutex_);
1193f4cbf05Sopenharmony_ci        auto ret = map_.insert(std::pair<K, V>(key, value));
1203f4cbf05Sopenharmony_ci        // find key and cannot insert
1213f4cbf05Sopenharmony_ci        if (!ret.second) {
1223f4cbf05Sopenharmony_ci            map_.erase(ret.first);
1233f4cbf05Sopenharmony_ci            map_.insert(std::pair<K, V>(key, value));
1243f4cbf05Sopenharmony_ci            return;
1253f4cbf05Sopenharmony_ci        }
1263f4cbf05Sopenharmony_ci        return;
1273f4cbf05Sopenharmony_ci    }
1283f4cbf05Sopenharmony_ci
1293f4cbf05Sopenharmony_ci    /**
1303f4cbf05Sopenharmony_ci     * @brief Searches for an element in the map.
1313f4cbf05Sopenharmony_ci     *
1323f4cbf05Sopenharmony_ci     * @param Key Indicates the key to search.
1333f4cbf05Sopenharmony_ci     * @param value Indicates the value of the KV pair to search.
1343f4cbf05Sopenharmony_ci     * @return Returns <b>true</b> if the KV pair is found;
1353f4cbf05Sopenharmony_ci     * returns <b>false</b> otherwise.
1363f4cbf05Sopenharmony_ci     */
1373f4cbf05Sopenharmony_ci    bool Find(const K& key, V& value)
1383f4cbf05Sopenharmony_ci    {
1393f4cbf05Sopenharmony_ci        bool ret = false;
1403f4cbf05Sopenharmony_ci        std::lock_guard<std::mutex> lock(mutex_);
1413f4cbf05Sopenharmony_ci
1423f4cbf05Sopenharmony_ci        auto iter = map_.find(key);
1433f4cbf05Sopenharmony_ci        if (iter != map_.end()) {
1443f4cbf05Sopenharmony_ci            value = iter->second;
1453f4cbf05Sopenharmony_ci            ret = true;
1463f4cbf05Sopenharmony_ci        }
1473f4cbf05Sopenharmony_ci
1483f4cbf05Sopenharmony_ci        return ret;
1493f4cbf05Sopenharmony_ci    }
1503f4cbf05Sopenharmony_ci
1513f4cbf05Sopenharmony_ci    /**
1523f4cbf05Sopenharmony_ci     * @brief Replaces the value of a KV pair.
1533f4cbf05Sopenharmony_ci     *
1543f4cbf05Sopenharmony_ci     * @param Key Indicates the key of the KV pair.
1553f4cbf05Sopenharmony_ci     * @param oldValue Indicates the value to be replaced.
1563f4cbf05Sopenharmony_ci     * @param newValue Indicates the new value of the KV pair.
1573f4cbf05Sopenharmony_ci     * @return Returns <b>true</b> if the key is replaced;
1583f4cbf05Sopenharmony_ci     * returns <b>false</b> otherwise.
1593f4cbf05Sopenharmony_ci     */
1603f4cbf05Sopenharmony_ci    bool FindOldAndSetNew(const K& key, V& oldValue, const V& newValue)
1613f4cbf05Sopenharmony_ci    {
1623f4cbf05Sopenharmony_ci        bool ret = false;
1633f4cbf05Sopenharmony_ci        std::lock_guard<std::mutex> lock(mutex_);
1643f4cbf05Sopenharmony_ci        if (map_.size() > 0) {
1653f4cbf05Sopenharmony_ci            auto iter = map_.find(key);
1663f4cbf05Sopenharmony_ci            if (iter != map_.end()) {
1673f4cbf05Sopenharmony_ci                oldValue = iter->second;
1683f4cbf05Sopenharmony_ci                map_.erase(iter);
1693f4cbf05Sopenharmony_ci                map_.insert(std::pair<K, V>(key, newValue));
1703f4cbf05Sopenharmony_ci                ret = true;
1713f4cbf05Sopenharmony_ci            }
1723f4cbf05Sopenharmony_ci        }
1733f4cbf05Sopenharmony_ci
1743f4cbf05Sopenharmony_ci        return ret;
1753f4cbf05Sopenharmony_ci    }
1763f4cbf05Sopenharmony_ci
1773f4cbf05Sopenharmony_ci    /**
1783f4cbf05Sopenharmony_ci     * @brief Erases a KV pair.
1793f4cbf05Sopenharmony_ci     *
1803f4cbf05Sopenharmony_ci     * @param Key Indicates the key of the KV pair to erase.
1813f4cbf05Sopenharmony_ci     */
1823f4cbf05Sopenharmony_ci    void Erase(const K& key)
1833f4cbf05Sopenharmony_ci    {
1843f4cbf05Sopenharmony_ci        std::lock_guard<std::mutex> lock(mutex_);
1853f4cbf05Sopenharmony_ci        map_.erase(key);
1863f4cbf05Sopenharmony_ci    }
1873f4cbf05Sopenharmony_ci
1883f4cbf05Sopenharmony_ci    /**
1893f4cbf05Sopenharmony_ci     * @brief Deletes all KV pairs from the map.
1903f4cbf05Sopenharmony_ci     */
1913f4cbf05Sopenharmony_ci    void Clear()
1923f4cbf05Sopenharmony_ci    {
1933f4cbf05Sopenharmony_ci        std::lock_guard<std::mutex> lock(mutex_);
1943f4cbf05Sopenharmony_ci        map_.clear();
1953f4cbf05Sopenharmony_ci        return;
1963f4cbf05Sopenharmony_ci    }
1973f4cbf05Sopenharmony_ci
1983f4cbf05Sopenharmony_ci    using SafeMapCallBack = std::function<void(const K, V&)>;
1993f4cbf05Sopenharmony_ci
2003f4cbf05Sopenharmony_ci    /**
2013f4cbf05Sopenharmony_ci     * @brief Iterates over the elements of the map.
2023f4cbf05Sopenharmony_ci     *
2033f4cbf05Sopenharmony_ci     * @param callback Called to perform the custom operations on
2043f4cbf05Sopenharmony_ci     * each KV pair.
2053f4cbf05Sopenharmony_ci     */
2063f4cbf05Sopenharmony_ci    void Iterate(const SafeMapCallBack& callback)
2073f4cbf05Sopenharmony_ci    {
2083f4cbf05Sopenharmony_ci        std::lock_guard<std::mutex> lock(mutex_);
2093f4cbf05Sopenharmony_ci        if (!map_.empty()) {
2103f4cbf05Sopenharmony_ci            for (auto it = map_.begin(); it != map_.end(); it++) {
2113f4cbf05Sopenharmony_ci                callback(it -> first, it -> second);
2123f4cbf05Sopenharmony_ci            }
2133f4cbf05Sopenharmony_ci        }
2143f4cbf05Sopenharmony_ci    }
2153f4cbf05Sopenharmony_ci
2163f4cbf05Sopenharmony_ciprivate:
2173f4cbf05Sopenharmony_ci    mutable std::mutex mutex_;
2183f4cbf05Sopenharmony_ci    std::map<K, V> map_;
2193f4cbf05Sopenharmony_ci
2203f4cbf05Sopenharmony_ci    std::map<K, V> Clone() const noexcept
2213f4cbf05Sopenharmony_ci    {
2223f4cbf05Sopenharmony_ci        std::lock_guard<std::mutex> lock(mutex_);
2233f4cbf05Sopenharmony_ci        return map_;
2243f4cbf05Sopenharmony_ci    }
2253f4cbf05Sopenharmony_ci};
2263f4cbf05Sopenharmony_ci
2273f4cbf05Sopenharmony_ci} // namespace OHOS
2283f4cbf05Sopenharmony_ci#endif
229