LCOV - code coverage report
Current view: top level - lib/support - BytesCircularBuffer.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 63 81 77.8 %
Date: 2024-02-15 08:20:41 Functions: 11 12 91.7 %

          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

Generated by: LCOV version 1.14