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/ScopedMemoryBuffer.h>
22 :
23 : namespace chip {
24 : namespace detail {
25 :
26 43384 : GenericAppendOnlyBuffer::~GenericAppendOnlyBuffer()
27 : {
28 43384 : if (mBufferIsAllocated && (mBuffer != nullptr))
29 : {
30 1 : Platform::MemoryFree(mBuffer);
31 : }
32 43384 : }
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 53977 : CHIP_ERROR GenericAppendOnlyBuffer::EnsureAppendCapacity(size_t numElements)
74 : {
75 53977 : if (mCapacity >= mElementCount + numElements)
76 : {
77 : // Sufficient capacity already exists
78 20365 : return CHIP_NO_ERROR;
79 : }
80 :
81 33612 : if (mBuffer == nullptr)
82 : {
83 32819 : mBuffer = static_cast<uint8_t *>(Platform::MemoryCalloc(numElements, mElementSize));
84 32819 : VerifyOrReturnError(mBuffer != nullptr, CHIP_ERROR_NO_MEMORY);
85 32819 : mCapacity = numElements;
86 32819 : mBufferIsAllocated = true;
87 32819 : 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 793 : if (mBufferIsAllocated)
94 : {
95 762 : auto new_buffer = static_cast<uint8_t *>(Platform::MemoryRealloc(mBuffer, (mElementCount + numElements) * mElementSize));
96 762 : VerifyOrReturnError(new_buffer != nullptr, CHIP_ERROR_NO_MEMORY);
97 762 : mBuffer = new_buffer;
98 : }
99 : else
100 : {
101 : // this is NOT an allocated buffer, but it should become one
102 31 : auto new_buffer = static_cast<uint8_t *>(Platform::MemoryCalloc(mElementCount + numElements, mElementSize));
103 31 : VerifyOrReturnError(new_buffer != nullptr, CHIP_ERROR_NO_MEMORY);
104 31 : mBufferIsAllocated = true;
105 31 : memcpy(new_buffer, mBuffer, mElementCount * mElementSize);
106 31 : mBuffer = new_buffer;
107 : }
108 793 : mCapacity = mElementCount + numElements;
109 :
110 793 : return CHIP_NO_ERROR;
111 : }
112 :
113 176086 : CHIP_ERROR GenericAppendOnlyBuffer::AppendSingleElementRaw(const void * buffer)
114 : {
115 176086 : VerifyOrReturnError(mElementCount < mCapacity, CHIP_ERROR_BUFFER_TOO_SMALL);
116 176081 : memcpy(mBuffer + mElementCount * mElementSize, buffer, mElementSize);
117 176081 : mElementCount++;
118 176081 : return CHIP_NO_ERROR;
119 : }
120 :
121 3437 : CHIP_ERROR GenericAppendOnlyBuffer::AppendElementArrayRaw(const void * __restrict__ buffer, size_t numElements)
122 : {
123 3437 : ReturnErrorOnFailure(EnsureAppendCapacity(numElements));
124 :
125 3437 : memcpy(mBuffer + mElementCount * mElementSize, buffer, numElements * mElementSize);
126 3437 : mElementCount += numElements;
127 :
128 3437 : return CHIP_NO_ERROR;
129 : }
130 :
131 3194 : CHIP_ERROR GenericAppendOnlyBuffer::ReferenceExistingElementArrayRaw(const void * buffer, size_t numElements)
132 : {
133 3194 : if (mBuffer == nullptr)
134 : {
135 : // we can NEVER append with 0 capacity, so const cast is safe
136 588 : mBuffer = const_cast<uint8_t *>(static_cast<const uint8_t *>(buffer));
137 588 : mElementCount = numElements;
138 : // The assertions below are because we know the buffer is null/not allocated yet
139 588 : VerifyOrDie(mCapacity == 0);
140 588 : VerifyOrDie(!mBufferIsAllocated);
141 588 : return CHIP_NO_ERROR;
142 : }
143 :
144 2606 : return AppendElementArrayRaw(buffer, numElements);
145 : }
146 :
147 43378 : void GenericAppendOnlyBuffer::ReleaseBuffer(void *& buffer, size_t & size, bool & allocated)
148 : {
149 43378 : buffer = mBuffer;
150 43378 : size = mElementCount;
151 43378 : allocated = mBufferIsAllocated;
152 :
153 : // we release the ownership
154 43378 : mBuffer = nullptr;
155 43378 : mCapacity = 0;
156 43378 : mElementCount = 0;
157 43378 : mBufferIsAllocated = false;
158 43378 : }
159 :
160 70447 : ScopedBuffer::~ScopedBuffer()
161 : {
162 70447 : if (mBuffer != nullptr)
163 : {
164 28529 : Platform::MemoryFree(mBuffer);
165 : }
166 70447 : }
167 :
168 30419 : ScopedBuffer & ScopedBuffer::operator=(ScopedBuffer && other)
169 : {
170 30419 : if (mBuffer != nullptr)
171 : {
172 4319 : Platform::MemoryFree(mBuffer);
173 : }
174 :
175 30419 : mBuffer = other.mBuffer;
176 30419 : other.mBuffer = nullptr;
177 30419 : return *this;
178 : }
179 :
180 : } // namespace detail
181 : } // namespace chip
|