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 34011 : GenericAppendOnlyBuffer::~GenericAppendOnlyBuffer()
29 : {
30 34011 : if (mBufferIsAllocated && (mBuffer != nullptr))
31 : {
32 1 : Platform::MemoryFree(mBuffer);
33 : }
34 34011 : }
35 :
36 6 : GenericAppendOnlyBuffer::GenericAppendOnlyBuffer(GenericAppendOnlyBuffer && other) : mElementSize(other.mElementSize)
37 : {
38 : // take over the data
39 6 : mBuffer = other.mBuffer;
40 6 : mElementCount = other.mElementCount;
41 6 : mCapacity = other.mCapacity;
42 6 : mBufferIsAllocated = other.mBufferIsAllocated;
43 :
44 : // clear other
45 6 : other.mBuffer = nullptr;
46 6 : other.mElementCount = 0;
47 6 : other.mCapacity = 0;
48 6 : other.mBufferIsAllocated = false;
49 6 : }
50 :
51 1 : GenericAppendOnlyBuffer & GenericAppendOnlyBuffer::operator=(GenericAppendOnlyBuffer && other)
52 : {
53 1 : VerifyOrDie(mElementSize == other.mElementSize);
54 :
55 1 : if (mBufferIsAllocated && (mBuffer != nullptr))
56 : {
57 1 : Platform::Impl::PlatformMemoryManagement::MemoryFree(mBuffer);
58 : }
59 :
60 : // take over the data
61 1 : mBuffer = other.mBuffer;
62 1 : mElementCount = other.mElementCount;
63 1 : mCapacity = other.mCapacity;
64 1 : mBufferIsAllocated = other.mBufferIsAllocated;
65 :
66 : // clear other
67 1 : other.mBuffer = nullptr;
68 1 : other.mElementCount = 0;
69 1 : other.mCapacity = 0;
70 1 : other.mBufferIsAllocated = false;
71 :
72 1 : return *this;
73 : }
74 :
75 40995 : CHIP_ERROR GenericAppendOnlyBuffer::EnsureAppendCapacity(size_t numElements)
76 : {
77 40995 : if (mCapacity >= mElementCount + numElements)
78 : {
79 : // Sufficient capacity already exists
80 16911 : return CHIP_NO_ERROR;
81 : }
82 :
83 24084 : if (mBuffer == nullptr)
84 : {
85 24080 : mBuffer = static_cast<uint8_t *>(Platform::MemoryCalloc(numElements, mElementSize));
86 24080 : VerifyOrReturnError(mBuffer != nullptr, CHIP_ERROR_NO_MEMORY);
87 24080 : mCapacity = numElements;
88 24080 : mBufferIsAllocated = true;
89 24080 : 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 4 : if (mBufferIsAllocated)
96 : {
97 3 : auto new_buffer = static_cast<uint8_t *>(Platform::MemoryRealloc(mBuffer, (mElementCount + numElements) * mElementSize));
98 3 : VerifyOrReturnError(new_buffer != nullptr, CHIP_ERROR_NO_MEMORY);
99 3 : 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 4 : mCapacity = mElementCount + numElements;
111 :
112 4 : return CHIP_NO_ERROR;
113 : }
114 :
115 115865 : CHIP_ERROR GenericAppendOnlyBuffer::AppendSingleElementRaw(const void * buffer)
116 : {
117 115865 : VerifyOrReturnError(mElementCount < mCapacity, CHIP_ERROR_BUFFER_TOO_SMALL);
118 115860 : memcpy(mBuffer + mElementCount * mElementSize, buffer, mElementSize);
119 115860 : mElementCount++;
120 115860 : 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 14 : CHIP_ERROR GenericAppendOnlyBuffer::ReferenceExistingElementArrayRaw(const void * buffer, size_t numElements)
134 : {
135 14 : if (mBuffer == nullptr)
136 : {
137 : // we can NEVER append with 0 capacity, so const cast is safe
138 11 : mBuffer = const_cast<uint8_t *>(static_cast<const uint8_t *>(buffer));
139 11 : mElementCount = numElements;
140 : // The assertions below are because we know the buffer is null/not allocated yet
141 11 : VerifyOrDie(mCapacity == 0);
142 11 : VerifyOrDie(!mBufferIsAllocated);
143 11 : return CHIP_NO_ERROR;
144 : }
145 :
146 3 : return AppendElementArrayRaw(buffer, numElements);
147 : }
148 :
149 34010 : void GenericAppendOnlyBuffer::ReleaseBuffer(void *& buffer, size_t & size, bool & allocated)
150 : {
151 34010 : buffer = mBuffer;
152 34010 : size = mElementCount;
153 34010 : allocated = mBufferIsAllocated;
154 :
155 : // we release the ownership
156 34010 : mBuffer = nullptr;
157 34010 : mCapacity = 0;
158 34010 : mElementCount = 0;
159 34010 : mBufferIsAllocated = false;
160 34010 : }
161 :
162 55051 : ScopedBuffer::~ScopedBuffer()
163 : {
164 55051 : if (mBuffer != nullptr)
165 : {
166 19838 : Platform::MemoryFree(mBuffer);
167 : }
168 55051 : }
169 :
170 24312 : ScopedBuffer & ScopedBuffer::operator=(ScopedBuffer && other)
171 : {
172 24312 : if (mBuffer != nullptr)
173 : {
174 4241 : Platform::MemoryFree(mBuffer);
175 : }
176 :
177 24312 : mBuffer = other.mBuffer;
178 24312 : other.mBuffer = nullptr;
179 24312 : return *this;
180 : }
181 :
182 : } // namespace detail
183 : } // namespace DataModel
184 : } // namespace app
185 : } // namespace chip
|