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 <nlassert.h> 24 : #include <string.h> 25 : 26 : #include <lib/support/CodeUtils.h> 27 : 28 : namespace chip { 29 : 30 7352 : size_t BytesCircularBuffer::Advance(size_t dataLocation, size_t amount) const 31 : { 32 7352 : dataLocation += amount; 33 7352 : if (dataLocation >= mCapacity) 34 1176 : dataLocation -= mCapacity; 35 7352 : return dataLocation; 36 : } 37 : 38 3784 : void BytesCircularBuffer::Read(uint8_t * dest, size_t length, size_t offset) const 39 : { 40 : // length is an instance of SizeType 41 : // offset is maximized at sizeof(SizeType) for all use cases. 42 : static_assert(std::numeric_limits<SizeType>::max() < std::numeric_limits<size_t>::max() - sizeof(SizeType), 43 : "SizeType too large, may cause overflow"); 44 3784 : VerifyOrDie(StorageUsed() >= offset + length); 45 : 46 3784 : size_t start = Advance(mDataStart, offset); 47 3784 : size_t firstPiece = std::min(mCapacity - start, length); 48 3784 : size_t secondPiece = length - firstPiece; 49 3784 : ::memcpy(dest, mStorage + start, firstPiece); 50 3784 : ::memcpy(dest + firstPiece, mStorage, secondPiece); 51 3784 : } 52 : 53 1790 : void BytesCircularBuffer::Write(const uint8_t * source, size_t length) 54 : { 55 : // Always reserve 1 byte to prevent mDataStart == mDataEnd because then it would be 56 : // ambiguous whether we have 0 bytes or mCapacity bytes stored. 57 1790 : VerifyOrDie(StorageAvailable() - 1 >= length); 58 : 59 1790 : size_t firstPiece = std::min(mCapacity - mDataEnd, length); 60 1790 : size_t secondPiece = length - firstPiece; 61 1790 : ::memcpy(mStorage + mDataEnd, source, firstPiece); 62 1790 : ::memcpy(mStorage, source + firstPiece, secondPiece); 63 1790 : mDataEnd = Advance(mDataEnd, length); 64 1790 : } 65 : 66 1778 : void BytesCircularBuffer::Drop(size_t length) 67 : { 68 1778 : VerifyOrDie(StorageUsed() >= length); 69 1778 : mDataStart = Advance(mDataStart, length); 70 1778 : } 71 : 72 3250 : size_t BytesCircularBuffer::StorageAvailable() const 73 : { 74 3250 : return mCapacity - StorageUsed(); 75 : } 76 : 77 15924 : size_t BytesCircularBuffer::StorageUsed() const 78 : { 79 15924 : if (mDataStart <= mDataEnd) 80 : { 81 7638 : return mDataEnd - mDataStart; 82 : } 83 : 84 8286 : return mCapacity + mDataEnd - mDataStart; 85 : } 86 : 87 898 : CHIP_ERROR BytesCircularBuffer::Push(const ByteSpan & payload) 88 : { 89 898 : size_t length = payload.size(); 90 898 : if (length > std::numeric_limits<SizeType>::max()) 91 1 : return CHIP_ERROR_INVALID_ARGUMENT; 92 : 93 : static_assert(std::numeric_limits<SizeType>::max() < std::numeric_limits<size_t>::max() - (sizeof(SizeType) + 1), 94 : "SizeType too large, may cause overflow"); 95 897 : size_t storageNeed = length + sizeof(SizeType) + 1; 96 897 : if (storageNeed > mCapacity) 97 2 : return CHIP_ERROR_INVALID_ARGUMENT; 98 : 99 : // Free up space until there is enough space. 100 1460 : while (storageNeed > StorageAvailable()) 101 : { 102 565 : VerifyOrDie(Pop() == CHIP_NO_ERROR); 103 : } 104 : 105 895 : SizeType size = static_cast<SizeType>(length); 106 895 : Write(reinterpret_cast<uint8_t *>(&size), sizeof(size)); 107 895 : Write(payload.data(), length); 108 : 109 895 : return CHIP_NO_ERROR; 110 : } 111 : 112 0 : CHIP_ERROR BytesCircularBuffer::Push(const ByteSpan & payload1, const ByteSpan & payload2) 113 : { 114 0 : size_t length = payload1.size() + payload2.size(); 115 0 : if (length > std::numeric_limits<SizeType>::max()) 116 : { 117 0 : return CHIP_ERROR_INVALID_ARGUMENT; 118 : } 119 : 120 : static_assert(std::numeric_limits<SizeType>::max() < std::numeric_limits<size_t>::max() - (sizeof(SizeType) + 1), 121 : "SizeType too large, may cause overflow"); 122 0 : size_t storageNeed = length + sizeof(SizeType) + 1; 123 0 : if (storageNeed > mCapacity) 124 : { 125 0 : return CHIP_ERROR_INVALID_ARGUMENT; 126 : } 127 : 128 : // Free up space until there is enough space. 129 0 : while (storageNeed > StorageAvailable()) 130 : { 131 0 : VerifyOrDie(Pop() == CHIP_NO_ERROR); 132 : } 133 : 134 0 : SizeType size = static_cast<SizeType>(length); 135 0 : Write(reinterpret_cast<uint8_t *>(&size), sizeof(size)); 136 0 : Write(payload1.data(), payload1.size()); 137 0 : Write(payload2.data(), payload2.size()); 138 : 139 0 : return CHIP_NO_ERROR; 140 : } 141 : 142 889 : CHIP_ERROR BytesCircularBuffer::Pop() 143 : { 144 889 : if (IsEmpty()) 145 0 : return CHIP_ERROR_INCORRECT_STATE; 146 : 147 889 : size_t length = GetFrontSize(); 148 889 : Drop(sizeof(SizeType)); 149 889 : Drop(length); 150 : 151 889 : return CHIP_NO_ERROR; 152 : } 153 : 154 7112 : bool BytesCircularBuffer::IsEmpty() const 155 : { 156 7112 : return StorageUsed() == 0; 157 : } 158 : 159 2819 : size_t BytesCircularBuffer::GetFrontSize() const 160 : { 161 2819 : if (IsEmpty()) 162 0 : return 0; 163 : 164 : SizeType length; 165 2819 : Read(reinterpret_cast<uint8_t *>(&length), sizeof(length), 0 /* offset */); 166 2819 : return length; 167 : } 168 : 169 965 : CHIP_ERROR BytesCircularBuffer::ReadFront(MutableByteSpan & dest) const 170 : { 171 965 : if (IsEmpty()) 172 0 : return CHIP_ERROR_INCORRECT_STATE; 173 : 174 965 : size_t length = GetFrontSize(); 175 965 : if (dest.size() < length) 176 0 : return CHIP_ERROR_INVALID_ARGUMENT; 177 : 178 965 : dest = dest.SubSpan(0, length); 179 : 180 965 : Read(dest.data(), length, sizeof(SizeType) /* offset */); 181 965 : return CHIP_NO_ERROR; 182 : } 183 : 184 : } // namespace chip