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 7339 : size_t BytesCircularBuffer::Advance(size_t dataLocation, size_t amount) const
30 : {
31 7339 : dataLocation += amount;
32 7339 : if (dataLocation >= mCapacity)
33 1185 : dataLocation -= mCapacity;
34 7339 : return dataLocation;
35 : }
36 :
37 3781 : 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 3781 : VerifyOrDie(StorageUsed() >= offset + length);
44 :
45 3781 : size_t start = Advance(mDataStart, offset);
46 3781 : size_t firstPiece = std::min(mCapacity - start, length);
47 3781 : size_t secondPiece = length - firstPiece;
48 3781 : ::memcpy(dest, mStorage + start, firstPiece);
49 3781 : ::memcpy(dest + firstPiece, mStorage, secondPiece);
50 3781 : }
51 :
52 1786 : 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 1786 : VerifyOrDie(StorageAvailable() - 1 >= length);
57 :
58 1786 : size_t firstPiece = std::min(mCapacity - mDataEnd, length);
59 1786 : size_t secondPiece = length - firstPiece;
60 1786 : ::memcpy(mStorage + mDataEnd, source, firstPiece);
61 1786 : ::memcpy(mStorage, source + firstPiece, secondPiece);
62 1786 : mDataEnd = Advance(mDataEnd, length);
63 1786 : }
64 :
65 1772 : void BytesCircularBuffer::Drop(size_t length)
66 : {
67 1772 : VerifyOrDie(StorageUsed() >= length);
68 1772 : mDataStart = Advance(mDataStart, length);
69 1772 : }
70 :
71 3239 : size_t BytesCircularBuffer::StorageAvailable() const
72 : {
73 3239 : return mCapacity - StorageUsed();
74 : }
75 :
76 15898 : size_t BytesCircularBuffer::StorageUsed() const
77 : {
78 15898 : if (mDataStart <= mDataEnd)
79 : {
80 7699 : return mDataEnd - mDataStart;
81 : }
82 :
83 8199 : return mCapacity + mDataEnd - mDataStart;
84 : }
85 :
86 896 : CHIP_ERROR BytesCircularBuffer::Push(const ByteSpan & payload)
87 : {
88 896 : size_t length = payload.size();
89 896 : 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 895 : size_t storageNeed = length + sizeof(SizeType) + 1;
95 895 : if (storageNeed > mCapacity)
96 2 : return CHIP_ERROR_INVALID_ARGUMENT;
97 :
98 : // Free up space until there is enough space.
99 1453 : while (storageNeed > StorageAvailable())
100 : {
101 560 : VerifyOrDie(Pop() == CHIP_NO_ERROR);
102 : }
103 :
104 893 : SizeType size = static_cast<SizeType>(length);
105 893 : Write(reinterpret_cast<uint8_t *>(&size), sizeof(size));
106 893 : Write(payload.data(), length);
107 :
108 893 : 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 886 : CHIP_ERROR BytesCircularBuffer::Pop()
142 : {
143 886 : if (IsEmpty())
144 0 : return CHIP_ERROR_INCORRECT_STATE;
145 :
146 886 : size_t length = GetFrontSize();
147 886 : Drop(sizeof(SizeType));
148 886 : Drop(length);
149 :
150 886 : return CHIP_NO_ERROR;
151 : }
152 :
153 7106 : bool BytesCircularBuffer::IsEmpty() const
154 : {
155 7106 : return StorageUsed() == 0;
156 : }
157 :
158 2816 : size_t BytesCircularBuffer::GetFrontSize() const
159 : {
160 2816 : if (IsEmpty())
161 0 : return 0;
162 :
163 : SizeType length;
164 2816 : Read(reinterpret_cast<uint8_t *>(&length), sizeof(length), 0 /* offset */);
165 2816 : return length;
166 : }
167 :
168 965 : CHIP_ERROR BytesCircularBuffer::ReadFront(MutableByteSpan & dest) const
169 : {
170 965 : if (IsEmpty())
171 0 : return CHIP_ERROR_INCORRECT_STATE;
172 :
173 965 : size_t length = GetFrontSize();
174 965 : if (dest.size() < length)
175 0 : return CHIP_ERROR_INVALID_ARGUMENT;
176 :
177 965 : dest = dest.SubSpan(0, length);
178 :
179 965 : Read(dest.data(), length, sizeof(SizeType) /* offset */);
180 965 : return CHIP_NO_ERROR;
181 : }
182 :
183 : } // namespace chip
|