Coverage Report

Created: 2025-08-28 06:31

/src/connectedhomeip/src/lib/support/ReadOnlyBuffer.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *    Copyright (c) 2024 Project CHIP Authors
3
 *
4
 *    Licensed under the Apache License, Version 2.0 (the "License");
5
 *    you may not use this file except in compliance with the License.
6
 *    You may obtain a copy of the License at
7
 *
8
 *        http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 *    Unless required by applicable law or agreed to in writing, software
11
 *    distributed under the License is distributed on an "AS IS" BASIS,
12
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 *    See the License for the specific language governing permissions and
14
 *    limitations under the License.
15
 */
16
#include <lib/support/ReadOnlyBuffer.h>
17
18
#include <lib/core/CHIPError.h>
19
#include <lib/support/CHIPMem.h>
20
#include <lib/support/CodeUtils.h>
21
#include <lib/support/ScopedBuffer.h>
22
23
namespace chip {
24
namespace detail {
25
26
GenericAppendOnlyBuffer::~GenericAppendOnlyBuffer()
27
0
{
28
0
    if (mBufferIsAllocated && (mBuffer != nullptr))
29
0
    {
30
0
        Platform::MemoryFree(mBuffer);
31
0
    }
32
0
}
33
34
0
GenericAppendOnlyBuffer::GenericAppendOnlyBuffer(GenericAppendOnlyBuffer && other) : mElementSize(other.mElementSize)
35
0
{
36
    // take over the data
37
0
    mBuffer            = other.mBuffer;
38
0
    mElementCount      = other.mElementCount;
39
0
    mCapacity          = other.mCapacity;
40
0
    mBufferIsAllocated = other.mBufferIsAllocated;
41
42
    // clear other
43
0
    other.mBuffer            = nullptr;
44
0
    other.mElementCount      = 0;
45
0
    other.mCapacity          = 0;
46
0
    other.mBufferIsAllocated = false;
47
0
}
48
49
GenericAppendOnlyBuffer & GenericAppendOnlyBuffer::operator=(GenericAppendOnlyBuffer && other)
50
0
{
51
0
    VerifyOrDie(mElementSize == other.mElementSize);
52
53
0
    if (mBufferIsAllocated && (mBuffer != nullptr))
54
0
    {
55
0
        Platform::Impl::PlatformMemoryManagement::MemoryFree(mBuffer);
56
0
    }
57
58
    // take over the data
59
0
    mBuffer            = other.mBuffer;
60
0
    mElementCount      = other.mElementCount;
61
0
    mCapacity          = other.mCapacity;
62
0
    mBufferIsAllocated = other.mBufferIsAllocated;
63
64
    // clear other
65
0
    other.mBuffer            = nullptr;
66
0
    other.mElementCount      = 0;
67
0
    other.mCapacity          = 0;
68
0
    other.mBufferIsAllocated = false;
69
70
0
    return *this;
71
0
}
72
73
CHIP_ERROR GenericAppendOnlyBuffer::EnsureAppendCapacity(size_t numElements)
74
0
{
75
0
    if (mCapacity >= mElementCount + numElements)
76
0
    {
77
        // Sufficient capacity already exists
78
0
        return CHIP_NO_ERROR;
79
0
    }
80
81
0
    if (mBuffer == nullptr)
82
0
    {
83
0
        mBuffer = static_cast<uint8_t *>(Platform::MemoryCalloc(numElements, mElementSize));
84
0
        VerifyOrReturnError(mBuffer != nullptr, CHIP_ERROR_NO_MEMORY);
85
0
        mCapacity          = numElements;
86
0
        mBufferIsAllocated = true;
87
0
        return CHIP_NO_ERROR;
88
0
    }
89
90
    // we already have the data in buffer. we have two choices:
91
    //   - allocated buffer needs to be extended
92
    //   - re-used const buffer needs to be copied over
93
0
    if (mBufferIsAllocated)
94
0
    {
95
0
        auto new_buffer = static_cast<uint8_t *>(Platform::MemoryRealloc(mBuffer, (mElementCount + numElements) * mElementSize));
96
0
        VerifyOrReturnError(new_buffer != nullptr, CHIP_ERROR_NO_MEMORY);
97
0
        mBuffer = new_buffer;
98
0
    }
99
0
    else
100
0
    {
101
        // this is NOT an allocated buffer, but it should become one
102
0
        auto new_buffer = static_cast<uint8_t *>(Platform::MemoryCalloc(mElementCount + numElements, mElementSize));
103
0
        VerifyOrReturnError(new_buffer != nullptr, CHIP_ERROR_NO_MEMORY);
104
0
        mBufferIsAllocated = true;
105
0
        memcpy(new_buffer, mBuffer, mElementCount * mElementSize);
106
0
        mBuffer = new_buffer;
107
0
    }
108
0
    mCapacity = mElementCount + numElements;
109
110
0
    return CHIP_NO_ERROR;
111
0
}
112
113
CHIP_ERROR GenericAppendOnlyBuffer::AppendSingleElementRaw(const void * buffer)
114
0
{
115
0
    VerifyOrReturnError(mElementCount < mCapacity, CHIP_ERROR_BUFFER_TOO_SMALL);
116
0
    memcpy(mBuffer + mElementCount * mElementSize, buffer, mElementSize);
117
0
    mElementCount++;
118
0
    return CHIP_NO_ERROR;
119
0
}
120
121
CHIP_ERROR GenericAppendOnlyBuffer::AppendElementArrayRaw(const void * __restrict__ buffer, size_t numElements)
122
0
{
123
0
    ReturnErrorOnFailure(EnsureAppendCapacity(numElements));
124
125
0
    memcpy(mBuffer + mElementCount * mElementSize, buffer, numElements * mElementSize);
126
0
    mElementCount += numElements;
127
128
0
    return CHIP_NO_ERROR;
129
0
}
130
131
CHIP_ERROR GenericAppendOnlyBuffer::ReferenceExistingElementArrayRaw(const void * buffer, size_t numElements)
132
0
{
133
0
    if (mBuffer == nullptr)
134
0
    {
135
        // we can NEVER append with 0 capacity, so const cast is safe
136
0
        mBuffer       = const_cast<uint8_t *>(static_cast<const uint8_t *>(buffer));
137
0
        mElementCount = numElements;
138
        // The assertions below are because we know the buffer is null/not allocated yet
139
0
        VerifyOrDie(mCapacity == 0);
140
0
        VerifyOrDie(!mBufferIsAllocated);
141
0
        return CHIP_NO_ERROR;
142
0
    }
143
144
0
    return AppendElementArrayRaw(buffer, numElements);
145
0
}
146
147
void GenericAppendOnlyBuffer::ReleaseBuffer(void *& buffer, size_t & size, bool & allocated)
148
0
{
149
0
    buffer    = mBuffer;
150
0
    size      = mElementCount;
151
0
    allocated = mBufferIsAllocated;
152
153
    // we release the ownership
154
0
    mBuffer            = nullptr;
155
0
    mCapacity          = 0;
156
0
    mElementCount      = 0;
157
0
    mBufferIsAllocated = false;
158
0
}
159
160
ScopedBuffer::~ScopedBuffer()
161
0
{
162
0
    if (mBuffer != nullptr)
163
0
    {
164
0
        Platform::MemoryFree(mBuffer);
165
0
    }
166
0
}
167
168
ScopedBuffer & ScopedBuffer::operator=(ScopedBuffer && other)
169
0
{
170
0
    if (mBuffer != nullptr)
171
0
    {
172
0
        Platform::MemoryFree(mBuffer);
173
0
    }
174
175
0
    mBuffer       = other.mBuffer;
176
0
    other.mBuffer = nullptr;
177
0
    return *this;
178
0
}
179
180
} // namespace detail
181
} // namespace chip