Matter SDK Coverage Report
Current view: top level - lib/support - StringBuilder.h (source / functions) Coverage Total Hit
Test: SHA:704d97f9c619242ad76fcf75aeabc67802fa72d4 Lines: 100.0 % 54 54
Test Date: 2026-05-18 07:37:39 Functions: 86.8 % 38 33

            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 <cctype>
      21              : #include <cstdio>
      22              : #include <lib/support/Assertions.h>
      23              : 
      24              : #include "BufferWriter.h"
      25              : 
      26              : namespace chip {
      27              : 
      28              : /// Build a c-style string out of distinct parts
      29              : class StringBuilderBase
      30              : {
      31              : public:
      32          577 :     StringBuilderBase(char * buffer, size_t size) : mWriter(reinterpret_cast<uint8_t *>(buffer), size - 1)
      33              :     {
      34          577 :         VerifyOrDieWithoutLogging(size > 0);
      35          577 :         buffer[0] = 0; // make c-str work by default
      36          577 :     }
      37              : 
      38              :     /// Append a null terminated string
      39          843 :     StringBuilderBase & Add(const char * s)
      40              :     {
      41          843 :         mWriter.Put(s);
      42          843 :         NullTerminate();
      43          843 :         return *this;
      44              :     }
      45              : 
      46              :     /// Append an integer value
      47            3 :     StringBuilderBase & Add(int value)
      48              :     {
      49              :         char buff[32];
      50            3 :         snprintf(buff, sizeof(buff), "%d", value);
      51            3 :         buff[sizeof(buff) - 1] = 0;
      52            3 :         return Add(buff);
      53              :     }
      54              : 
      55              :     /// Append an uint8_t value
      56              :     StringBuilderBase & Add(uint8_t value)
      57              :     {
      58              :         uint8_t actual = std::isprint(value) ? value : '.';
      59              :         mWriter.Put(actual);
      60              :         NullTerminate();
      61              :         return *this;
      62              :     }
      63              : 
      64              :     /// Append a memory block
      65           24 :     StringBuilderBase & Add(const void * data, size_t size)
      66              :     {
      67           24 :         mWriter.Put(data, size);
      68           24 :         NullTerminate();
      69           24 :         return *this;
      70              :     }
      71              : 
      72              :     /// Did all the values fit?
      73          168 :     bool Fit() const { return mWriter.Fit(); }
      74              : 
      75              :     /// Was nothing written yet?
      76              :     bool Empty() const { return mWriter.Needed() == 0; }
      77              : 
      78              :     /// Write a formatted string to the stringbuilder
      79              :     StringBuilderBase & AddFormat(const char * format, ...) ENFORCE_FORMAT(2, 3);
      80              : 
      81              :     /// For strings we often want to know when they were truncated. If the underlying writer did
      82              :     /// not fit, this replaces the last 3 characters with "."
      83              :     StringBuilderBase & AddMarkerIfOverflow();
      84              : 
      85          384 :     StringBuilderBase & Reset()
      86              :     {
      87          384 :         mWriter.Reset();
      88          384 :         NullTerminate();
      89          384 :         return *this;
      90              :     }
      91              : 
      92              :     /// access the underlying value
      93          566 :     const char * c_str() const { return reinterpret_cast<const char *>(mWriter.Buffer()); }
      94              : 
      95              : protected:
      96              :     /// Number of bytes actually needed
      97            8 :     size_t Needed() const { return mWriter.Needed(); }
      98              : 
      99              :     /// Size of the output buffer
     100           16 :     size_t Size() const { return mWriter.Size(); }
     101              : 
     102              : private:
     103              :     Encoding::BufferWriter mWriter;
     104              : 
     105         4319 :     void NullTerminate()
     106              :     {
     107         4319 :         if (mWriter.Fit())
     108              :         {
     109         4280 :             mWriter.Buffer()[mWriter.Needed()] = 0;
     110              :         }
     111              :         else
     112              :         {
     113           39 :             mWriter.Buffer()[mWriter.Size()] = 0;
     114              :         }
     115         4319 :     }
     116              : };
     117              : 
     118              : /// A preallocated sized string builder
     119              : template <size_t kSize>
     120              : class StringBuilder : public StringBuilderBase
     121              : {
     122              : public:
     123          566 :     StringBuilder() : StringBuilderBase(mBuffer, kSize) {}
     124              : 
     125           12 :     StringBuilder(const char * data, size_t size, bool add_marker_if_overflow = true) : StringBuilder()
     126              :     {
     127           12 :         Add(data, size);
     128              : 
     129           12 :         if (add_marker_if_overflow)
     130              :         {
     131            8 :             AddMarkerIfOverflow();
     132              :         }
     133              : 
     134           12 :         size_t length = Fit() ? Needed() : Size();
     135          150 :         for (size_t i = 0; i < length; ++i)
     136              :         {
     137          138 :             if (mBuffer[i] == '\0')
     138              :             {
     139           18 :                 mBuffer[i] = '.';
     140              :             }
     141              :         }
     142           12 :     }
     143              : 
     144            6 :     StringBuilder(const CharSpan & span, bool add_marker_if_overflow = true) :
     145            6 :         StringBuilder(span.data(), span.size(), add_marker_if_overflow)
     146            6 :     {}
     147              : 
     148           12 :     StringBuilder(const uint8_t * data, size_t size, bool add_marker_if_overflow = true) : StringBuilder()
     149              :     {
     150           12 :         Add(data, size);
     151              : 
     152           12 :         if (add_marker_if_overflow)
     153              :         {
     154            8 :             AddMarkerIfOverflow();
     155              :         }
     156              : 
     157           12 :         size_t length = Fit() ? Needed() : Size();
     158          168 :         for (size_t i = 0; i < length; ++i)
     159              :         {
     160          156 :             if (!std::isprint(mBuffer[i]))
     161              :             {
     162           36 :                 mBuffer[i] = '.';
     163              :             }
     164              :         }
     165           12 :     }
     166              : 
     167            6 :     StringBuilder(const ByteSpan & span, bool add_marker_if_overflow = true) :
     168            6 :         StringBuilder(span.data(), span.size(), add_marker_if_overflow)
     169            6 :     {}
     170              : 
     171              : private:
     172              :     char mBuffer[kSize];
     173              : };
     174              : 
     175              : /// Default buffer size is 257 to accommodate values with size up to 256
     176              : /// If the buffer size is not enough the value will be truncated and an overflow marker will be added
     177              : /// TODO Note that this buffer size will be used always by default even for much smaller values
     178              : /// TODO Preferably the buffer size should be the one appropriate for each value
     179              : using NullTerminated = StringBuilder<257>;
     180              : 
     181              : } // namespace chip
        

Generated by: LCOV version 2.0-1