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