LCOV - code coverage report
Current view: top level - lib/support - BufferWriter.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 35 35 100.0 %
Date: 2024-02-15 08:20:41 Functions: 31 31 100.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2020-2021 Project CHIP Authors
       4             :  *
       5             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       6             :  *    you may not use this file except in compliance with the License.
       7             :  *    You may obtain a copy of the License at
       8             :  *
       9             :  *        http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  *    Unless required by applicable law or agreed to in writing, software
      12             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      13             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  *    See the License for the specific language governing permissions and
      15             :  *    limitations under the License.
      16             :  */
      17             : 
      18             : #pragma once
      19             : 
      20             : #include <climits>
      21             : #include <stdint.h>
      22             : #include <string.h>
      23             : 
      24             : #include <lib/support/Span.h>
      25             : 
      26             : namespace chip {
      27             : namespace Encoding {
      28             : 
      29             : class BufferWriter
      30             : {
      31             : public:
      32       22314 :     BufferWriter(uint8_t * buf, size_t len) : mBuf(buf), mSize(len), mNeeded(0)
      33             :     {
      34       22314 :         if (buf == nullptr)
      35             :         {
      36         150 :             mSize = 0;
      37             :         }
      38       22314 :     }
      39         224 :     BufferWriter(MutableByteSpan buf) : BufferWriter(buf.data(), buf.size()) {}
      40             :     BufferWriter(const BufferWriter & other)             = default;
      41             :     BufferWriter & operator=(const BufferWriter & other) = default;
      42             : 
      43             :     /// Append a null terminated string, exclude the null terminator
      44             :     BufferWriter & Put(const char * s);
      45             : 
      46             :     /// Raw append a buffer, regardless of endianess.
      47             :     /// This is memmove-safe: if `buf` points to the underlying buffer, where output
      48             :     /// will be written, and the overlap is legal for a memmove to have worked properly,
      49             :     /// then this method will properly copy data.
      50             :     BufferWriter & Put(const void * buf, size_t len);
      51             : 
      52             :     /// Append a single byte
      53             :     BufferWriter & Put(uint8_t c);
      54             : 
      55        1816 :     BufferWriter & Skip(size_t len)
      56             :     {
      57        1816 :         mNeeded += len;
      58        1816 :         return *this;
      59             :     }
      60             : 
      61             :     /// Number of bytes required to satisfy all calls to Put() so far
      62       17200 :     inline size_t Needed() const { return mNeeded; }
      63             : 
      64             :     /// Alias to Needed() for code clarity: current writing position for the buffer.
      65        8252 :     inline size_t WritePos() const { return Needed(); }
      66             : 
      67             :     /// Number of bytes still available for writing
      68       10989 :     size_t Available() const { return mSize < mNeeded ? 0 : mSize - mNeeded; }
      69             : 
      70             :     /// Whether the input fit in the buffer
      71       30621 :     bool Fit() const
      72             :     {
      73             :         size_t _;
      74       30621 :         return Fit(_);
      75             :     }
      76             : 
      77             :     /// Returns whether the input fit in the buffer, outputs what was actually written
      78       30936 :     bool Fit(size_t & actuallyWritten) const
      79             :     {
      80       30936 :         actuallyWritten = mSize >= mNeeded ? mNeeded : mSize;
      81       30936 :         return mSize >= mNeeded;
      82             :     }
      83             : 
      84             :     /// Size of the output buffer
      85          26 :     size_t Size() const { return mSize; }
      86             : 
      87       24724 :     uint8_t * Buffer() { return mBuf; }
      88         668 :     const uint8_t * Buffer() const { return mBuf; }
      89             : 
      90             :     BufferWriter & Format(const char * format, ...) ENFORCE_FORMAT(2, 3)
      91             :     {
      92             :         va_list args;
      93             :         va_start(args, format);
      94             :         VFormat(format, args);
      95             :         va_end(args);
      96             :         return *this;
      97             :     }
      98             : 
      99         296 :     void Reset() { mNeeded = 0; }
     100             : 
     101             :     /// Since this uses vsnprintf internally, on overflow
     102             :     /// this will write one less byte that strictly can be
     103             :     /// written (since null terminator will be in the binary data)
     104             :     BufferWriter & VFormat(const char * format, va_list args) ENFORCE_FORMAT(2, 0);
     105             : 
     106             :     /// Assume a specific size for the buffer instead of mSize
     107             :     ///
     108             :     /// This is to allow avoiding off-by-one overflow truncation
     109             :     /// when we know the underlying buffer size is larger.
     110             :     BufferWriter & VFormatWithSize(size_t size, const char * format, va_list args) ENFORCE_FORMAT(3, 0);
     111             : 
     112             : protected:
     113             :     uint8_t * mBuf;
     114             :     size_t mSize;
     115             :     size_t mNeeded;
     116             : };
     117             : 
     118             : template <class Derived>
     119             : class EndianBufferWriterBase : public BufferWriter
     120             : {
     121             : public:
     122             :     // typed BufferWriter forwards
     123             : 
     124         947 :     Derived & Put(const char * s) { return static_cast<Derived &>(BufferWriter::Put(s)); }
     125         437 :     Derived & Put(const void * buf, size_t len) { return static_cast<Derived &>(BufferWriter::Put(buf, len)); }
     126      256409 :     Derived & Put(uint8_t c) { return static_cast<Derived &>(BufferWriter::Put(c)); }
     127         110 :     Derived & Skip(size_t len) { return static_cast<Derived &>(BufferWriter::Skip(len)); }
     128             : 
     129             :     // write an integer into a buffer, in an endian-specific way
     130             : 
     131       20166 :     Derived & Put8(uint8_t c) { return static_cast<Derived *>(this)->Put(c); }
     132        3124 :     Derived & Put16(uint16_t x) { return static_cast<Derived *>(this)->EndianPut(x, sizeof(x)); }
     133       19922 :     Derived & Put32(uint32_t x) { return static_cast<Derived *>(this)->EndianPut(x, sizeof(x)); }
     134       18945 :     Derived & Put64(uint64_t x) { return static_cast<Derived *>(this)->EndianPut(x, sizeof(x)); }
     135             : 
     136             :     Derived & PutSigned8(int8_t x) { return static_cast<Derived *>(this)->EndianPutSigned(x, sizeof(x)); }
     137             :     Derived & PutSigned16(int16_t x) { return static_cast<Derived *>(this)->EndianPutSigned(x, sizeof(x)); }
     138             :     Derived & PutSigned32(int32_t x) { return static_cast<Derived *>(this)->EndianPutSigned(x, sizeof(x)); }
     139             :     Derived & PutSigned64(int64_t x) { return static_cast<Derived *>(this)->EndianPutSigned(x, sizeof(x)); }
     140             : 
     141             : protected:
     142       19276 :     EndianBufferWriterBase(uint8_t * buf, size_t len) : BufferWriter(buf, len) {}
     143          40 :     EndianBufferWriterBase(MutableByteSpan buf) : BufferWriter(buf.data(), buf.size()) {}
     144             :     EndianBufferWriterBase(const EndianBufferWriterBase & other)             = default;
     145             :     EndianBufferWriterBase & operator=(const EndianBufferWriterBase & other) = default;
     146             : };
     147             : 
     148             : namespace LittleEndian {
     149             : 
     150             : class BufferWriter : public EndianBufferWriterBase<BufferWriter>
     151             : {
     152             : public:
     153       19159 :     BufferWriter(uint8_t * buf, size_t len) : EndianBufferWriterBase<BufferWriter>(buf, len)
     154             :     {
     155             :         static_assert((-1 & 3) == 3, "LittleEndian::BufferWriter only works with 2's complement architectures.");
     156       19159 :     }
     157          40 :     BufferWriter(MutableByteSpan buf) : EndianBufferWriterBase<BufferWriter>(buf) {}
     158             :     BufferWriter(const BufferWriter & other)             = default;
     159             :     BufferWriter & operator=(const BufferWriter & other) = default;
     160             :     BufferWriter & EndianPut(uint64_t x, size_t size);
     161             :     BufferWriter & EndianPutSigned(int64_t x, size_t size);
     162             : };
     163             : 
     164             : } // namespace LittleEndian
     165             : 
     166             : namespace BigEndian {
     167             : 
     168             : class BufferWriter : public EndianBufferWriterBase<BufferWriter>
     169             : {
     170             : public:
     171         117 :     BufferWriter(uint8_t * buf, size_t len) : EndianBufferWriterBase<BufferWriter>(buf, len)
     172             :     {
     173             :         static_assert((-1 & 3) == 3, "BigEndian::BufferWriter only works with 2's complement architectures.");
     174         117 :     }
     175             :     BufferWriter(MutableByteSpan buf) : EndianBufferWriterBase<BufferWriter>(buf) {}
     176             :     BufferWriter(const BufferWriter & other)             = default;
     177             :     BufferWriter & operator=(const BufferWriter & other) = default;
     178             :     BufferWriter & EndianPut(uint64_t x, size_t size);
     179             :     BufferWriter & EndianPutSigned(int64_t x, size_t size);
     180             : };
     181             : 
     182             : } // namespace BigEndian
     183             : 
     184             : } // namespace Encoding
     185             : } // namespace chip

Generated by: LCOV version 1.14