Line data Source code
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 36233 : GenericAppendOnlyBuffer::~GenericAppendOnlyBuffer()
27 : {
28 36233 : if (mBufferIsAllocated && (mBuffer != nullptr))
29 : {
30 1 : Platform::MemoryFree(mBuffer);
31 : }
32 36233 : }
33 :
34 6 : GenericAppendOnlyBuffer::GenericAppendOnlyBuffer(GenericAppendOnlyBuffer && other) : mElementSize(other.mElementSize)
35 : {
36 : // take over the data
37 6 : mBuffer = other.mBuffer;
38 6 : mElementCount = other.mElementCount;
39 6 : mCapacity = other.mCapacity;
40 6 : mBufferIsAllocated = other.mBufferIsAllocated;
41 :
42 : // clear other
43 6 : other.mBuffer = nullptr;
44 6 : other.mElementCount = 0;
45 6 : other.mCapacity = 0;
46 6 : other.mBufferIsAllocated = false;
47 6 : }
48 :
49 1 : GenericAppendOnlyBuffer & GenericAppendOnlyBuffer::operator=(GenericAppendOnlyBuffer && other)
50 : {
51 1 : VerifyOrDie(mElementSize == other.mElementSize);
52 :
53 1 : if (mBufferIsAllocated && (mBuffer != nullptr))
54 : {
55 1 : Platform::Impl::PlatformMemoryManagement::MemoryFree(mBuffer);
56 : }
57 :
58 : // take over the data
59 1 : mBuffer = other.mBuffer;
60 1 : mElementCount = other.mElementCount;
61 1 : mCapacity = other.mCapacity;
62 1 : mBufferIsAllocated = other.mBufferIsAllocated;
63 :
64 : // clear other
65 1 : other.mBuffer = nullptr;
66 1 : other.mElementCount = 0;
67 1 : other.mCapacity = 0;
68 1 : other.mBufferIsAllocated = false;
69 :
70 1 : return *this;
71 : }
72 :
73 43226 : CHIP_ERROR GenericAppendOnlyBuffer::EnsureAppendCapacity(size_t numElements)
74 : {
75 43226 : if (mCapacity >= mElementCount + numElements)
76 : {
77 : // Sufficient capacity already exists
78 16929 : return CHIP_NO_ERROR;
79 : }
80 :
81 26297 : if (mBuffer == nullptr)
82 : {
83 26293 : mBuffer = static_cast<uint8_t *>(Platform::MemoryCalloc(numElements, mElementSize));
84 26293 : VerifyOrReturnError(mBuffer != nullptr, CHIP_ERROR_NO_MEMORY);
85 26293 : mCapacity = numElements;
86 26293 : mBufferIsAllocated = true;
87 26293 : return CHIP_NO_ERROR;
88 : }
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 4 : if (mBufferIsAllocated)
94 : {
95 3 : auto new_buffer = static_cast<uint8_t *>(Platform::MemoryRealloc(mBuffer, (mElementCount + numElements) * mElementSize));
96 3 : VerifyOrReturnError(new_buffer != nullptr, CHIP_ERROR_NO_MEMORY);
97 3 : mBuffer = new_buffer;
98 : }
99 : else
100 : {
101 : // this is NOT an allocated buffer, but it should become one
102 1 : auto new_buffer = static_cast<uint8_t *>(Platform::MemoryCalloc(mElementCount + numElements, mElementSize));
103 1 : VerifyOrReturnError(new_buffer != nullptr, CHIP_ERROR_NO_MEMORY);
104 1 : mBufferIsAllocated = true;
105 1 : memcpy(new_buffer, mBuffer, mElementCount * mElementSize);
106 1 : mBuffer = new_buffer;
107 : }
108 4 : mCapacity = mElementCount + numElements;
109 :
110 4 : return CHIP_NO_ERROR;
111 : }
112 :
113 129153 : CHIP_ERROR GenericAppendOnlyBuffer::AppendSingleElementRaw(const void * buffer)
114 : {
115 129153 : VerifyOrReturnError(mElementCount < mCapacity, CHIP_ERROR_BUFFER_TOO_SMALL);
116 129148 : memcpy(mBuffer + mElementCount * mElementSize, buffer, mElementSize);
117 129148 : mElementCount++;
118 129148 : return CHIP_NO_ERROR;
119 : }
120 :
121 4 : CHIP_ERROR GenericAppendOnlyBuffer::AppendElementArrayRaw(const void * __restrict__ buffer, size_t numElements)
122 : {
123 4 : ReturnErrorOnFailure(EnsureAppendCapacity(numElements));
124 :
125 4 : memcpy(mBuffer + mElementCount * mElementSize, buffer, numElements * mElementSize);
126 4 : mElementCount += numElements;
127 :
128 4 : return CHIP_NO_ERROR;
129 : }
130 :
131 14 : CHIP_ERROR GenericAppendOnlyBuffer::ReferenceExistingElementArrayRaw(const void * buffer, size_t numElements)
132 : {
133 14 : if (mBuffer == nullptr)
134 : {
135 : // we can NEVER append with 0 capacity, so const cast is safe
136 11 : mBuffer = const_cast<uint8_t *>(static_cast<const uint8_t *>(buffer));
137 11 : mElementCount = numElements;
138 : // The assertions below are because we know the buffer is null/not allocated yet
139 11 : VerifyOrDie(mCapacity == 0);
140 11 : VerifyOrDie(!mBufferIsAllocated);
141 11 : return CHIP_NO_ERROR;
142 : }
143 :
144 3 : return AppendElementArrayRaw(buffer, numElements);
145 : }
146 :
147 36232 : void GenericAppendOnlyBuffer::ReleaseBuffer(void *& buffer, size_t & size, bool & allocated)
148 : {
149 36232 : buffer = mBuffer;
150 36232 : size = mElementCount;
151 36232 : allocated = mBufferIsAllocated;
152 :
153 : // we release the ownership
154 36232 : mBuffer = nullptr;
155 36232 : mCapacity = 0;
156 36232 : mElementCount = 0;
157 36232 : mBufferIsAllocated = false;
158 36232 : }
159 :
160 59477 : ScopedBuffer::~ScopedBuffer()
161 : {
162 59477 : if (mBuffer != nullptr)
163 : {
164 22042 : Platform::MemoryFree(mBuffer);
165 : }
166 59477 : }
167 :
168 26525 : ScopedBuffer & ScopedBuffer::operator=(ScopedBuffer && other)
169 : {
170 26525 : if (mBuffer != nullptr)
171 : {
172 4250 : Platform::MemoryFree(mBuffer);
173 : }
174 :
175 26525 : mBuffer = other.mBuffer;
176 26525 : other.mBuffer = nullptr;
177 26525 : return *this;
178 : }
179 :
180 : } // namespace detail
181 : } // namespace chip
|