1/*
2 * Copyright (c) 2023 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_HDI_DISPLAY_V1_0_CACHE_MANAGER_H
17#define OHOS_HDI_DISPLAY_V1_0_CACHE_MANAGER_H
18
19#include <functional>
20#include <memory>
21#include <unordered_map>
22#include "hdf_log.h"
23#include "nocopyable.h"
24#include <mutex>
25#include "hdf_base.h"
26#include "hilog/log.h"
27#include "base/native_buffer.h"
28
29#undef LOG_TAG
30#define LOG_TAG "DISP_CACHE_MGR"
31#undef LOG_DOMAIN
32#define LOG_DOMAIN 0xD002515
33
34namespace OHOS {
35namespace HDI {
36namespace Display {
37namespace Composer {
38
39template <typename IdType, typename CacheType>
40class CacheManager : public NoCopyable {
41public:
42    CacheManager()
43        : cacheCountMax_ { 0 },
44          cleanUpFunc_ { nullptr },
45          initFunc_ { nullptr }
46    {}
47
48    virtual ~CacheManager()
49    {
50        std::lock_guard<std::mutex> lock(mutex_);
51        if (cleanUpFunc_) {
52            for (auto& cache : caches_) {
53                cleanUpFunc_(cache.second);
54            }
55        }
56        caches_.clear();
57    }
58
59    bool SetCacheMaxCount(uint32_t count)
60    {
61        bool ret = true;
62        uint32_t originalMaxCount = cacheCountMax_;
63        if (count >= cacheCountMax_) {
64            cacheCountMax_ = count;
65        } else if (Size() <= count) {
66            cacheCountMax_ = count;
67        } else {
68            HDF_LOGE("%{public}s error: clientCacheCount can't be set, because cacheCountMax_ > count", __func__);
69            ret = false;
70        }
71        HDF_LOGD("%{public}s: set cache max count from %{public}u to %{public}u",
72            __func__, originalMaxCount, cacheCountMax_);
73        return ret;
74    }
75
76    uint32_t Size()
77    {
78        std::lock_guard<std::mutex> lock(mutex_);
79        return caches_.size();
80    }
81
82    bool InsertCache(IdType id, CacheType* cache)
83    {
84        std::lock_guard<std::mutex> lock(mutex_);
85        auto cacheItem = caches_.find(id);
86        if (cacheItem != caches_.end()) {
87            HDF_LOGI("%{public}s: intend to insert a existing cache, SeqNo=%{public}d", __func__, id);
88            cacheItem->second.reset(cache);
89        } else {
90            if (cacheCountMax_ != 0 && caches_.size() >= cacheCountMax_) {
91                HDF_LOGE("%{public}s: Caches is full, new seqNo:%{public}d can't be inserted", __func__, id);
92                return false;
93            }
94            caches_[id] = std::move(std::unique_ptr<CacheType>(cache));
95        }
96        if (initFunc_) {
97            initFunc_(caches_[id]);
98        }
99        return true;
100    }
101
102    bool EraseCache(IdType id)
103    {
104        std::lock_guard<std::mutex> lock(mutex_);
105        auto cacheItem = caches_.find(id);
106        if (cacheItem == caches_.end()) {
107            return false;
108        }
109
110        if (cleanUpFunc_ && cacheItem->second != nullptr) {
111            cleanUpFunc_(cacheItem->second);
112        }
113
114        caches_.erase(cacheItem);
115        return true;
116    }
117
118    CacheType* SearchCache(IdType id)
119    {
120        std::lock_guard<std::mutex> lock(mutex_);
121        auto cacheItem = caches_.find(id);
122        if (cacheItem == caches_.end()) {
123            return nullptr;
124        }
125
126        return cacheItem->second.get();
127    }
128
129    void TravelCaches(std::function<void (IdType id, const CacheType& cache)> func)
130    {
131        std::lock_guard<std::mutex> lock(mutex_);
132        for (auto const& [key, value] : caches_) {
133            func(key, *value.get());
134        }
135    }
136
137    void SetCleanUpFunc(void (*func)(std::unique_ptr<CacheType>&))
138    {
139        cleanUpFunc_ = func;
140    }
141
142    void SetInitFunc(void (*func)(std::unique_ptr<CacheType>&))
143    {
144        initFunc_ = func;
145    }
146
147private:
148    uint32_t cacheCountMax_;
149    std::unordered_map<IdType, std::unique_ptr<CacheType>> caches_;
150    void (*cleanUpFunc_)(std::unique_ptr<CacheType>&);
151    void (*initFunc_)(std::unique_ptr<CacheType>&);
152    std::mutex mutex_;
153};
154
155template <typename IdType>
156class CacheManager<IdType, Base::NativeBuffer> : public NoCopyable {
157public:
158    CacheManager()
159        : cacheCountMax_ { 0 },
160          cleanUpFunc_ { nullptr },
161          initFunc_ { nullptr }
162    {}
163
164    virtual ~CacheManager()
165    {
166        std::lock_guard<std::mutex> lock(mutex_);
167        if (cleanUpFunc_) {
168            for (auto& cache : caches_) {
169                cleanUpFunc_(cache.second);
170            }
171        }
172        caches_.clear();
173    }
174
175    bool SetCacheMaxCount(uint32_t count)
176    {
177        bool ret = true;
178        uint32_t originalMaxCount = cacheCountMax_;
179        if (count >= cacheCountMax_) {
180            cacheCountMax_ = count;
181        } else if (Size() <= count) {
182            cacheCountMax_ = count;
183        } else {
184            HDF_LOGE("%{public}s error: clientCacheCount can't be set, because cacheCountMax_ > count", __func__);
185            ret = false;
186        }
187        HDF_LOGI("%{public}s: set cache max count from %{public}u to %{public}u",
188            __func__, originalMaxCount, cacheCountMax_);
189        return ret;
190    }
191
192    uint32_t Size()
193    {
194        std::lock_guard<std::mutex> lock(mutex_);
195        return caches_.size();
196    }
197
198    bool InsertCache(IdType id, Base::NativeBuffer* cache)
199    {
200        std::lock_guard<std::mutex> lock(mutex_);
201        auto cacheItem = caches_.find(id);
202        if (cacheItem != caches_.end()) {
203            HDF_LOGI("%{public}s: intend to insert a existing cache, SeqNo=%{public}d", __func__, id);
204            cacheItem->second = OHOS::sptr<Base::NativeBuffer>(cache);
205        } else {
206            if (cacheCountMax_ != 0 && caches_.size() >= cacheCountMax_) {
207                HDF_LOGE("%{public}s: Caches is full, new seqNo:%{public}d can't be inserted", __func__, id);
208                return false;
209            }
210            caches_[id] = OHOS::sptr<Base::NativeBuffer>(cache);
211        }
212        if (initFunc_) {
213            initFunc_(caches_[id]);
214        }
215        return true;
216    }
217
218    bool EraseCache(IdType id)
219    {
220        std::lock_guard<std::mutex> lock(mutex_);
221        auto cacheItem = caches_.find(id);
222        if (cacheItem == caches_.end()) {
223            HDF_LOGE("%{public}s: Cache %{public}d is not existing\n", __func__, id);
224            return false;
225        }
226
227        if (cleanUpFunc_ && cacheItem->second != nullptr) {
228            cleanUpFunc_(cacheItem->second);
229        }
230
231        caches_.erase(cacheItem);
232        return true;
233    }
234
235    Base::NativeBuffer* SearchCache(IdType id)
236    {
237        std::lock_guard<std::mutex> lock(mutex_);
238        auto cacheItem = caches_.find(id);
239        if (cacheItem == caches_.end()) {
240            return nullptr;
241        }
242
243        return cacheItem->second.GetRefPtr();
244    }
245
246    void TravelCaches(std::function<void (IdType id, const Base::NativeBuffer& cache)> func)
247    {
248        std::lock_guard<std::mutex> lock(mutex_);
249        for (auto const& [key, value] : caches_) {
250            func(key, *value.GetRefPtr());
251        }
252    }
253
254    void SetCleanUpFunc(void (*func)(OHOS::sptr<Base::NativeBuffer>&))
255    {
256        cleanUpFunc_ = func;
257    }
258
259    void SetInitFunc(void (*func)(OHOS::sptr<Base::NativeBuffer>&))
260    {
261        initFunc_ = func;
262    }
263
264private:
265    uint32_t cacheCountMax_;
266    std::unordered_map<IdType, OHOS::sptr<Base::NativeBuffer>> caches_;
267    void (*cleanUpFunc_)(OHOS::sptr<Base::NativeBuffer>&);
268    void (*initFunc_)(OHOS::sptr<Base::NativeBuffer>&);
269    std::mutex mutex_;
270};
271} // namespace Composer
272} // namespace Display
273} // namespace HDI
274} // namespace OHOS
275#endif // OHOS_HDI_DISPLAY_V1_0_CACHE_MANAGER_H
276