Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021 Project CHIP Authors
4 : * All rights reserved.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : #include <lib/support/BytesCircularBuffer.h>
20 :
21 : #include <algorithm>
22 : #include <limits>
23 : #include <string.h>
24 :
25 : #include <lib/support/CodeUtils.h>
26 :
27 : namespace chip {
28 :
29 7362 : size_t BytesCircularBuffer::Advance(size_t dataLocation, size_t amount) const
30 : {
31 7362 : dataLocation += amount;
32 7362 : if (dataLocation >= mCapacity)
33 1174 : dataLocation -= mCapacity;
34 7362 : return dataLocation;
35 : }
36 :
37 3804 : void BytesCircularBuffer::Read(uint8_t * dest, size_t length, size_t offset) const
38 : {
39 : // length is an instance of SizeType
40 : // offset is maximized at sizeof(SizeType) for all use cases.
41 : static_assert(std::numeric_limits<SizeType>::max() < std::numeric_limits<size_t>::max() - sizeof(SizeType),
42 : "SizeType too large, may cause overflow");
43 3804 : VerifyOrDie(StorageUsed() >= offset + length);
44 :
45 3804 : size_t start = Advance(mDataStart, offset);
46 3804 : size_t firstPiece = std::min(mCapacity - start, length);
47 3804 : size_t secondPiece = length - firstPiece;
48 3804 : ::memcpy(dest, mStorage + start, firstPiece);
49 3804 : ::memcpy(dest + firstPiece, mStorage, secondPiece);
50 3804 : }
51 :
52 1788 : void BytesCircularBuffer::Write(const uint8_t * source, size_t length)
53 : {
54 : // Always reserve 1 byte to prevent mDataStart == mDataEnd because then it would be
55 : // ambiguous whether we have 0 bytes or mCapacity bytes stored.
56 1788 : VerifyOrDie(StorageAvailable() - 1 >= length);
57 :
58 1788 : size_t firstPiece = std::min(mCapacity - mDataEnd, length);
59 1788 : size_t secondPiece = length - firstPiece;
60 1788 : ::memcpy(mStorage + mDataEnd, source, firstPiece);
61 1788 : ::memcpy(mStorage, source + firstPiece, secondPiece);
62 1788 : mDataEnd = Advance(mDataEnd, length);
63 1788 : }
64 :
65 1770 : void BytesCircularBuffer::Drop(size_t length)
66 : {
67 1770 : VerifyOrDie(StorageUsed() >= length);
68 1770 : mDataStart = Advance(mDataStart, length);
69 1770 : }
70 :
71 3242 : size_t BytesCircularBuffer::StorageAvailable() const
72 : {
73 3242 : return mCapacity - StorageUsed();
74 : }
75 :
76 15944 : size_t BytesCircularBuffer::StorageUsed() const
77 : {
78 15944 : if (mDataStart <= mDataEnd)
79 : {
80 7754 : return mDataEnd - mDataStart;
81 : }
82 :
83 8190 : return mCapacity + mDataEnd - mDataStart;
84 : }
85 :
86 897 : CHIP_ERROR BytesCircularBuffer::Push(const ByteSpan & payload)
87 : {
88 897 : size_t length = payload.size();
89 897 : if (length > std::numeric_limits<SizeType>::max())
90 1 : return CHIP_ERROR_INVALID_ARGUMENT;
91 :
92 : static_assert(std::numeric_limits<SizeType>::max() < std::numeric_limits<size_t>::max() - (sizeof(SizeType) + 1),
93 : "SizeType too large, may cause overflow");
94 896 : size_t storageNeed = length + sizeof(SizeType) + 1;
95 896 : if (storageNeed > mCapacity)
96 2 : return CHIP_ERROR_INVALID_ARGUMENT;
97 :
98 : // Free up space until there is enough space.
99 1454 : while (storageNeed > StorageAvailable())
100 : {
101 560 : VerifyOrDie(Pop() == CHIP_NO_ERROR);
102 : }
103 :
104 894 : SizeType size = static_cast<SizeType>(length);
105 894 : Write(reinterpret_cast<uint8_t *>(&size), sizeof(size));
106 894 : Write(payload.data(), length);
107 :
108 894 : return CHIP_NO_ERROR;
109 : }
110 :
111 0 : CHIP_ERROR BytesCircularBuffer::Push(const ByteSpan & payload1, const ByteSpan & payload2)
112 : {
113 0 : size_t length = payload1.size() + payload2.size();
114 0 : if (length > std::numeric_limits<SizeType>::max())
115 : {
116 0 : return CHIP_ERROR_INVALID_ARGUMENT;
117 : }
118 :
119 : static_assert(std::numeric_limits<SizeType>::max() < std::numeric_limits<size_t>::max() - (sizeof(SizeType) + 1),
120 : "SizeType too large, may cause overflow");
121 0 : size_t storageNeed = length + sizeof(SizeType) + 1;
122 0 : if (storageNeed > mCapacity)
123 : {
124 0 : return CHIP_ERROR_INVALID_ARGUMENT;
125 : }
126 :
127 : // Free up space until there is enough space.
128 0 : while (storageNeed > StorageAvailable())
129 : {
130 0 : VerifyOrDie(Pop() == CHIP_NO_ERROR);
131 : }
132 :
133 0 : SizeType size = static_cast<SizeType>(length);
134 0 : Write(reinterpret_cast<uint8_t *>(&size), sizeof(size));
135 0 : Write(payload1.data(), payload1.size());
136 0 : Write(payload2.data(), payload2.size());
137 :
138 0 : return CHIP_NO_ERROR;
139 : }
140 :
141 885 : CHIP_ERROR BytesCircularBuffer::Pop()
142 : {
143 885 : if (IsEmpty())
144 0 : return CHIP_ERROR_INCORRECT_STATE;
145 :
146 885 : size_t length = GetFrontSize();
147 885 : Drop(sizeof(SizeType));
148 885 : Drop(length);
149 :
150 885 : return CHIP_NO_ERROR;
151 : }
152 :
153 7128 : bool BytesCircularBuffer::IsEmpty() const
154 : {
155 7128 : return StorageUsed() == 0;
156 : }
157 :
158 2831 : size_t BytesCircularBuffer::GetFrontSize() const
159 : {
160 2831 : if (IsEmpty())
161 0 : return 0;
162 :
163 : SizeType length;
164 2831 : Read(reinterpret_cast<uint8_t *>(&length), sizeof(length), 0 /* offset */);
165 2831 : return length;
166 : }
167 :
168 973 : CHIP_ERROR BytesCircularBuffer::ReadFront(MutableByteSpan & dest) const
169 : {
170 973 : if (IsEmpty())
171 0 : return CHIP_ERROR_INCORRECT_STATE;
172 :
173 973 : size_t length = GetFrontSize();
174 973 : if (dest.size() < length)
175 0 : return CHIP_ERROR_INVALID_ARGUMENT;
176 :
177 973 : dest = dest.SubSpan(0, length);
178 :
179 973 : Read(dest.data(), length, sizeof(SizeType) /* offset */);
180 973 : return CHIP_NO_ERROR;
181 : }
182 :
183 : } // namespace chip
|