xref: /aosp_15_r20/external/pigweed/pw_string/string_builder.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2019 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_string/string_builder.h"
16 
17 #include <cstdio>
18 
19 #include "pw_string/format.h"
20 #include "pw_string/util.h"
21 
22 namespace pw {
23 
clear()24 void StringBuilder::clear() {
25   *size_ = 0;
26   NullTerminate();
27   status_ = StatusCode(OkStatus());
28   last_status_ = StatusCode(OkStatus());
29 }
30 
append(size_t count,char ch)31 StringBuilder& StringBuilder::append(size_t count, char ch) {
32   char* const append_destination = buffer_.data() + size();
33   std::fill_n(append_destination, ResizeAndTerminate(count), ch);
34   return *this;
35 }
36 
append(const char * str,size_t count)37 StringBuilder& StringBuilder::append(const char* str, size_t count) {
38   char* const append_destination = buffer_.data() + size();
39   std::copy_n(str, ResizeAndTerminate(count), append_destination);
40   return *this;
41 }
42 
append(const char * str)43 StringBuilder& StringBuilder::append(const char* str) {
44   // Use buffer_.size() - size() as the maximum length so that strings too long
45   // to fit in the buffer will request one character too many, which sets the
46   // status to RESOURCE_EXHAUSTED.
47   return append(string::ClampedCString(str, buffer_.size() - size()));
48 }
49 
append(std::string_view str)50 StringBuilder& StringBuilder::append(std::string_view str) {
51   return append(str.data(), str.size());
52 }
53 
append(std::string_view str,size_t pos,size_t count)54 StringBuilder& StringBuilder::append(std::string_view str,
55                                      size_t pos,
56                                      size_t count) {
57   if (pos > str.size()) {
58     SetErrorStatus(Status::OutOfRange());
59     return *this;
60   }
61 
62   return append(str.data() + pos, std::min(str.size() - pos, count));
63 }
64 
ResizeAndTerminate(size_t chars_to_append)65 size_t StringBuilder::ResizeAndTerminate(size_t chars_to_append) {
66   const size_t copied = std::min(chars_to_append, max_size() - size());
67   // NOTE: `+=` is not used in order to avoid implicit integer conversion which
68   // results in an error on some compilers.
69   *size_ = static_cast<InlineString<>::size_type>(copied + *size_);
70   NullTerminate();
71 
72   if (buffer_.empty() || chars_to_append != copied) {
73     SetErrorStatus(Status::ResourceExhausted());
74   } else {
75     last_status_ = StatusCode(OkStatus());
76   }
77   return copied;
78 }
79 
resize(size_t new_size)80 void StringBuilder::resize(size_t new_size) {
81   if (new_size <= size()) {
82     *size_ = static_cast<InlineString<>::size_type>(new_size);
83     NullTerminate();
84     last_status_ = StatusCode(OkStatus());
85   } else {
86     SetErrorStatus(Status::OutOfRange());
87   }
88 }
89 
Format(const char * format,...)90 StringBuilder& StringBuilder::Format(const char* format, ...) {
91   va_list args;
92   va_start(args, format);
93   FormatVaList(format, args);
94   va_end(args);
95 
96   return *this;
97 }
98 
FormatVaList(const char * format,va_list args)99 StringBuilder& StringBuilder::FormatVaList(const char* format, va_list args) {
100   HandleStatusWithSize(
101       string::FormatVaList(buffer_.subspan(size()), format, args));
102   return *this;
103 }
104 
WriteBytes(span<const std::byte> data)105 void StringBuilder::WriteBytes(span<const std::byte> data) {
106   if (size() + data.size() * 2 > max_size()) {
107     SetErrorStatus(Status::ResourceExhausted());
108   } else {
109     for (std::byte val : data) {
110       *this << val;
111     }
112   }
113 }
114 
CopySizeAndStatus(const StringBuilder & other)115 void StringBuilder::CopySizeAndStatus(const StringBuilder& other) {
116   *size_ = static_cast<InlineString<>::size_type>(other.size());
117   status_ = other.status_;
118   last_status_ = other.last_status_;
119 }
120 
HandleStatusWithSize(StatusWithSize written)121 void StringBuilder::HandleStatusWithSize(StatusWithSize written) {
122   const Status status = written.status();
123   last_status_ = StatusCode(status);
124   if (!status.ok()) {
125     status_ = StatusCode(status);
126   }
127 
128   // NOTE: `+=` is not used in order to avoid implicit integer conversion which
129   // results in an error on some compilers.
130   *size_ = static_cast<InlineString<>::size_type>(written.size() + *size_);
131 }
132 
SetErrorStatus(Status status)133 void StringBuilder::SetErrorStatus(Status status) {
134   last_status_ = StatusCode(status);
135   status_ = StatusCode(status);
136 }
137 
138 }  // namespace pw
139