Matter SDK Coverage Report
Current view: top level - lib/support - StringBuilder.h (source / functions) Coverage Total Hit
Test: SHA:4d2388ac7eed75b2fe5e05e20de377999c632502 Lines: 100.0 % 53 53
Test Date: 2025-07-27 07:17:09 Functions: 94.6 % 37 35

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

Generated by: LCOV version 2.0-1