1/*
2 * Copyright (c) 2023-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#include "light_lux_buffer.h"
17
18#include <cerrno>
19#include <cstdlib>
20#include <new>
21#include <string>
22#include <securec.h>
23#include <securectype.h>
24
25#include "display_log.h"
26
27namespace OHOS {
28namespace DisplayPowerMgr {
29
30namespace {
31const unsigned int BUFFER_SIZE_INCREASE = 2;
32const unsigned int LUX_BUFFER_SIZE_MAX = 512;
33}
34
35LightLuxBuffer::LightLuxBuffer(unsigned int initialCapacity)
36{
37    if (initialCapacity == 0 || initialCapacity >= LUX_BUFFER_SIZE_MAX) {
38        DISPLAY_HILOGE(FEAT_BRIGHTNESS, "initialCapacity=%{public}d out of range, Reset to %{public}d",
39            initialCapacity, LUX_BUFFER_SIZE_DEFAULT);
40        mCapacity = LUX_BUFFER_SIZE_DEFAULT;
41    } else {
42        mCapacity = initialCapacity;
43    }
44}
45
46LightLuxBuffer::~LightLuxBuffer()
47{
48    if (mBufferData != nullptr) {
49        delete[] mBufferData;
50        mBufferData = nullptr;
51    }
52
53    if (mBufferTime != nullptr) {
54        delete[] mBufferTime;
55        mBufferTime = nullptr;
56    }
57}
58
59int LightLuxBuffer::LuxBufferCheck()
60{
61    if (mBufferData == nullptr) {
62        mBufferData = new(std::nothrow) float[mCapacity];
63        if (mBufferData == nullptr) {
64            DISPLAY_HILOGE(FEAT_BRIGHTNESS, "new mBufferData failed!");
65            return -1;
66        }
67    }
68    if (mBufferTime == nullptr) {
69        mBufferTime = new(std::nothrow) int64_t[mCapacity];
70        if (mBufferTime == nullptr) {
71            DISPLAY_HILOGE(FEAT_BRIGHTNESS, "new mBufferTime failed!");
72            delete[] mBufferData;
73            mBufferData = nullptr;
74            return -1;
75        }
76    }
77    return 0;
78}
79
80int LightLuxBuffer::CopyLuxBuffer(int newSize)
81{
82    auto newBufferData = new(std::nothrow) float[newSize];
83    if (newBufferData == nullptr) {
84        DISPLAY_HILOGE(FEAT_BRIGHTNESS, "newBufferData id null");
85        return -1;
86    }
87    auto newBufferTime = new(std::nothrow) int64_t[newSize];
88    if (newBufferTime == nullptr) {
89        DISPLAY_HILOGE(FEAT_BRIGHTNESS, "newBufferTime id null");
90        delete[] newBufferData;
91        return -1;
92    }
93    unsigned int length = mCapacity - mStart;
94    bool isError = false;
95    isError = isError || (memcpy_s(newBufferData, newSize * sizeof(newBufferData[0]),
96        mBufferData + mStart, length * sizeof(mBufferData[0])) != EOK);
97    isError = isError || (memcpy_s(newBufferTime, newSize * sizeof(newBufferTime[0]),
98        mBufferTime + mStart, length * sizeof(mBufferTime[0])) != EOK);
99    if (mStart != 0) {
100        isError = isError || (memcpy_s(newBufferData + length, (newSize - length) * sizeof(newBufferData[0]),
101            mBufferData, mStart * sizeof(mBufferData[0])) != EOK);
102        isError = isError || (memcpy_s(newBufferTime + length, (newSize - length) * sizeof(newBufferTime[0]),
103            mBufferTime, mStart * sizeof(mBufferTime[0])) != EOK);
104    }
105    if (isError) {
106        DISPLAY_HILOGE(FEAT_BRIGHTNESS, "memcpy_s error, mCapacity=%{public}d, mStart=%{public}d", mCapacity, mStart);
107        delete[] newBufferData;
108        delete[] newBufferTime;
109        return -1;
110    }
111    delete[] mBufferData;
112    mBufferData = newBufferData;
113    delete[] mBufferTime;
114    mBufferTime = newBufferTime;
115
116    return 0;
117}
118
119void LightLuxBuffer::Push(const int64_t timestamp, const float data)
120{
121    if (LuxBufferCheck() != 0) {
122        return;
123    }
124
125    unsigned int next = mEnd;
126    if (mCount == mCapacity) {
127        unsigned long newSize = mCapacity * static_cast<unsigned long>(BUFFER_SIZE_INCREASE);
128        if (newSize > static_cast<unsigned long>(LUX_BUFFER_SIZE_MAX)) {
129            DISPLAY_HILOGW(FEAT_BRIGHTNESS, "buffer size larger than max value %{public}d already, stop expand",
130                LUX_BUFFER_SIZE_MAX);
131            return;
132        }
133        if (mStart >= mCapacity) {
134            DISPLAY_HILOGE(FEAT_BRIGHTNESS, "mStart error! mStart(%{public}d) >= mCapacity(%{public}d)",
135                mStart, mCapacity);
136            return;
137        }
138
139        if (CopyLuxBuffer(newSize) != 0) {
140            return;
141        }
142
143        next = mCapacity;
144        mCapacity = static_cast<unsigned int>(newSize);
145        mStart = 0;
146    }
147
148    if (mBufferTime != nullptr) {
149        mBufferTime[next] = timestamp;
150    }
151
152    if (mBufferData != nullptr) {
153        mBufferData[next] = data;
154    }
155
156    mEnd = next + 1;
157    if (mEnd == mCapacity) {
158        mEnd = 0;
159    }
160    mCount++;
161}
162
163void LightLuxBuffer::Prune(const int64_t horizon)
164{
165    if (mCount == 0 || mBufferTime == nullptr) {
166        return;
167    }
168
169    while (mCount > 1) {
170        unsigned int next = mStart + 1;
171        if (next >= mCapacity) {
172            next -= mCapacity;
173        }
174        if (mBufferTime[next] > horizon) {
175            break;
176        }
177        mStart = next;
178        mCount--;
179    }
180    if (mBufferTime[mStart] < horizon) {
181        mBufferTime[mStart] = horizon;
182    }
183}
184
185void LightLuxBuffer::Clear()
186{
187    mStart = 0;
188    mEnd = 0;
189    mCount = 0;
190}
191
192float LightLuxBuffer::GetData(const unsigned int index) const
193{
194    if (mBufferData == nullptr) {
195        DISPLAY_HILOGE(FEAT_BRIGHTNESS, "mBufferData is nullptr.");
196        return 0;
197    }
198    if (index >= mCount) {
199        DISPLAY_HILOGE(FEAT_BRIGHTNESS, "error! index = %{public}d, out of range mCount = %{public}d", index, mCount);
200        return 0;
201    }
202    return mBufferData[OffsetOf(index)];
203}
204
205int64_t LightLuxBuffer::GetTime(const unsigned int index) const
206{
207    if (mBufferTime == nullptr) {
208        DISPLAY_HILOGE(FEAT_BRIGHTNESS, "mBufferTime is nullptr");
209        return 0;
210    }
211
212    if (index >= mCount) {
213        DISPLAY_HILOGE(FEAT_BRIGHTNESS, "error! index = %{public}d, out of range mCount = %{public}d", index, mCount);
214        return 0;
215    }
216    return mBufferTime[OffsetOf(index)];
217}
218
219unsigned int LightLuxBuffer::GetSize() const
220{
221    return mCount;
222}
223
224unsigned int LightLuxBuffer::OffsetOf(const unsigned int index) const
225{
226    unsigned actualIndex = index + mStart;
227    if (actualIndex >= mCapacity) {
228        actualIndex -= mCapacity;
229    }
230    return actualIndex;
231}
232
233std::string LightLuxBuffer::ToString(unsigned int n)
234{
235    std::ostringstream result;
236    if (n > mCount) {
237        n = mCount;
238    }
239    result << "[";
240    for (unsigned int i = mCount-n; i>=0 && i < mCount;i++) {
241        result << GetData(i);
242        result << "/";
243        result << GetTime(i);
244        result << ", ";
245    }
246    result << "]";
247    return result.str();
248}
249} // namespace DisplayPowerMgr
250} // namespace OHOS