/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 |