9cbd7b01创建于 2025年7月14日历史提交
/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef OHOS_SELECTION_FRAMEWORKS_COMMON_CONCURRENT_MAP_H
#define OHOS_SELECTION_FRAMEWORKS_COMMON_CONCURRENT_MAP_H
#include <functional>
#include <map>
#include <mutex>
namespace OHOS {
template<typename _Key, typename _Tp>
class ConcurrentMap {
    template<typename _First, typename... _Rest>
    static _First First();

public:
    using map_type = typename std::map<_Key, _Tp>;
    using filter_type = typename std::function<bool(map_type &)>;
    using key_type = typename std::map<_Key, _Tp>::key_type;
    using mapped_type = typename std::map<_Key, _Tp>::mapped_type;
    using value_type = typename std::map<_Key, _Tp>::value_type;
    using size_type = typename std::map<_Key, _Tp>::size_type;
    using reference = typename std::map<_Key, _Tp>::reference;
    using const_reference = typename std::map<_Key, _Tp>::const_reference;

    ConcurrentMap() = default;
    ~ConcurrentMap()
    {
        Clear();
    }

    ConcurrentMap(const ConcurrentMap &other)
    {
        operator=(std::move(other));
    }

    ConcurrentMap &operator=(const ConcurrentMap &other) noexcept
    {
        if (this == &other) {
            return *this;
        }
        auto tmp = other.Clone();
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        entries_ = std::move(tmp);
        return *this;
    }

    ConcurrentMap(ConcurrentMap &&other) noexcept
    {
        operator=(std::move(other));
    }

    ConcurrentMap &operator=(ConcurrentMap &&other) noexcept
    {
        if (this == &other) {
            return *this;
        }
        auto tmp = other.Steal();
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        entries_ = std::move(tmp);
        return *this;
    }

    bool Emplace() noexcept
    {
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        auto it = entries_.emplace();
        return it.second;
    }

    template<typename... _Args>
    typename std::enable_if<!std::is_convertible_v<decltype(First<_Args...>()), filter_type>, bool>::type Emplace(
        _Args &&...args) noexcept
    {
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        auto it = entries_.emplace(std::forward<_Args>(args)...);
        return it.second;
    }

    template<typename _Filter, typename... _Args>
    typename std::enable_if<std::is_convertible_v<_Filter, filter_type>, bool>::type Emplace(const _Filter &filter,
        _Args &&...args) noexcept
    {
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        if (!filter(entries_)) {
            return false;
        }
        auto it = entries_.emplace(std::forward<_Args>(args)...);
        return it.second;
    }

    std::pair<bool, mapped_type> Find(const key_type &key) const noexcept
    {
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        auto it = entries_.find(key);
        if (it == entries_.end()) {
            return std::pair{ false, mapped_type() };
        }

        return std::pair{ true, it->second };
    }

    bool Contains(const key_type &key) const noexcept
    {
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        return (entries_.find(key) != entries_.end());
    }

    template<typename _Obj>
    bool InsertOrAssign(const key_type &key, _Obj &&obj) noexcept
    {
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        auto it = entries_.insert_or_assign(key, std::forward<_Obj>(obj));
        return it.second;
    }

    bool Insert(const key_type &key, const mapped_type &value) noexcept
    {
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        auto it = entries_.insert(value_type{ key, value });
        return it.second;
    }

    size_type Erase(const key_type &key) noexcept
    {
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        return entries_.erase(key);
    }

    void Clear() noexcept
    {
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        return entries_.clear();
    }

    bool Empty() const noexcept
    {
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        return entries_.empty();
    }

    size_type Size() const noexcept
    {
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        return entries_.size();
    }

    // The action`s return true means meeting the erase condition
    // The action`s return false means not meeting the erase condition
    size_type EraseIf(const std::function<bool(const key_type &key, mapped_type &value)> &action) noexcept
    {
        if (action == nullptr) {
            return 0;
        }
        std::lock_guard<decltype(mutex_)> lock(mutex_);
#if __cplusplus > 201703L
        auto count = std::erase_if(entries_,
            [&action](value_type &value) -> bool { return action(value.first, value.second); });
#else
        auto count = entries_.size();
        for (auto it = entries_.begin(); it != entries_.end();) {
            if (action((*it).first, (*it).second)) {
                it = entries_.erase(it);
            } else {
                ++it;
            }
        }
        count -= entries_.size();
#endif
        return count;
    }

    void ForEach(const std::function<bool(const key_type &, mapped_type &)> &action)
    {
        if (action == nullptr) {
            return;
        }
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        for (auto &[key, value] : entries_) {
            if (action(key, value)) {
                break;
            }
        }
    }

    void ForEachCopies(const std::function<bool(const key_type &, mapped_type &)> &action)
    {
        if (action == nullptr) {
            return;
        }
        auto entries = Clone();
        for (auto &[key, value] : entries) {
            if (action(key, value)) {
                break;
            }
        }
    }

    // The action's return value means that the element is keep in map or not; true means keeping, false means removing.
    bool Compute(const key_type &key, const std::function<bool(const key_type &, mapped_type &)> &action)
    {
        if (action == nullptr) {
            return false;
        }
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        auto it = entries_.find(key);
        if (it == entries_.end()) {
            auto result = entries_.emplace(key, mapped_type());
            it = result.second ? result.first : entries_.end();
        }
        if (it == entries_.end()) {
            return false;
        }
        if (!action(it->first, it->second)) {
            entries_.erase(key);
        }
        return true;
    }

    // The action's return value means that the element is keep in map or not; true means keeping, false means removing.
    bool ComputeIfPresent(const key_type &key, const std::function<bool(const key_type &, mapped_type &)> &action)
    {
        if (action == nullptr) {
            return false;
        }
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        auto it = entries_.find(key);
        if (it == entries_.end()) {
            return false;
        }
        if (!action(key, it->second)) {
            entries_.erase(key);
        }
        return true;
    }

    bool ComputeIfAbsent(const key_type &key, const std::function<mapped_type(const key_type &)> &action)
    {
        if (action == nullptr) {
            return false;
        }
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        auto it = entries_.find(key);
        if (it != entries_.end()) {
            return false;
        }
        entries_.emplace(key, action(key));
        return true;
    }

    bool ComputeIfAbsent(const key_type &key, const std::function<bool(const key_type &, mapped_type &)> &action)
    {
        if (action == nullptr) {
            return false;
        }
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        auto it = entries_.find(key);
        if (it != entries_.end()) {
            return false;
        }
        auto result = entries_.emplace(key, mapped_type());
        it = result.second ? result.first : entries_.end();
        if (it == entries_.end()) {
            return false;
        }
        if (!action(it->first, it->second)) {
            entries_.erase(key);
            return false;
        }
        return true;
    }

private:
    std::map<_Key, _Tp> Steal() noexcept
    {
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        return std::move(entries_);
    }

    std::map<_Key, _Tp> Clone() const noexcept
    {
        std::lock_guard<decltype(mutex_)> lock(mutex_);
        return entries_;
    }

private:
    mutable std::recursive_mutex mutex_;
    std::map<_Key, _Tp> entries_;
};
} // namespace OHOS
#endif // OHOS_SELECTION_FRAMEWORKS_COMMON_CONCURRENT_MAP_H