blob: 9317cc217de47650d1442b7c08a951a14ae5d6d8 [file] [log] [blame]
Wyatt Heplerce9b9522019-11-11 10:45:48 -08001// Copyright 2019 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
Wyatt Hepler1a960942019-11-26 14:13:38 -08004// use this file except in compliance with the License. You may obtain a copy of
5// the License at
Wyatt Heplerce9b9522019-11-11 10:45:48 -08006//
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
Wyatt Hepler1a960942019-11-26 14:13:38 -080012// License for the specific language governing permissions and limitations under
13// the License.
Wyatt Heplerce9b9522019-11-11 10:45:48 -080014
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
22namespace pw {
23
24void StringBuilder::clear() {
25 size_ = 0;
26 NullTerminate();
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080027 status_ = OkStatus();
28 last_status_ = OkStatus();
Wyatt Heplerce9b9522019-11-11 10:45:48 -080029}
30
31StringBuilder& StringBuilder::append(size_t count, char ch) {
Armando Montanezeb90ca52022-03-14 09:11:25 -070032 char* const append_destination = buffer_.data() + size_;
Wyatt Heplere5559002021-11-12 13:58:05 -080033 std::fill_n(append_destination, ResizeAndTerminate(count), ch);
Wyatt Heplerce9b9522019-11-11 10:45:48 -080034 return *this;
35}
36
37StringBuilder& StringBuilder::append(const char* str, size_t count) {
Armando Montanezeb90ca52022-03-14 09:11:25 -070038 char* const append_destination = buffer_.data() + size_;
Wyatt Heplere5559002021-11-12 13:58:05 -080039 std::copy_n(str, ResizeAndTerminate(count), append_destination);
Wyatt Heplerce9b9522019-11-11 10:45:48 -080040 return *this;
41}
42
43StringBuilder& 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.
Ewout van Bekkumf89f1372021-05-03 11:15:54 -070047 return append(string::ClampedCString(str, buffer_.size() - size()));
Wyatt Heplerce9b9522019-11-11 10:45:48 -080048}
49
50StringBuilder& StringBuilder::append(const std::string_view& str) {
51 return append(str.data(), str.size());
52}
53
54StringBuilder& StringBuilder::append(const std::string_view& str,
55 size_t pos,
56 size_t count) {
57 if (pos > str.size()) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -070058 SetErrorStatus(Status::OutOfRange());
Wyatt Heplerce9b9522019-11-11 10:45:48 -080059 return *this;
60 }
61
62 return append(str.data() + pos, std::min(str.size() - pos, count));
63}
64
65size_t StringBuilder::ResizeAndTerminate(size_t chars_to_append) {
66 const size_t copied = std::min(chars_to_append, max_size() - size());
67 size_ += copied;
68 NullTerminate();
69
70 if (buffer_.empty() || chars_to_append != copied) {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -070071 SetErrorStatus(Status::ResourceExhausted());
Wyatt Heplerce9b9522019-11-11 10:45:48 -080072 } else {
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080073 last_status_ = OkStatus();
Wyatt Heplerce9b9522019-11-11 10:45:48 -080074 }
75 return copied;
76}
77
78void StringBuilder::resize(size_t new_size) {
79 if (new_size <= size_) {
80 size_ = new_size;
81 NullTerminate();
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080082 last_status_ = OkStatus();
Wyatt Heplerce9b9522019-11-11 10:45:48 -080083 } else {
Wyatt Heplerd78f7c62020-09-28 14:27:32 -070084 SetErrorStatus(Status::OutOfRange());
Wyatt Heplerce9b9522019-11-11 10:45:48 -080085 }
86}
87
88StringBuilder& StringBuilder::Format(const char* format, ...) {
89 va_list args;
90 va_start(args, format);
Wyatt Hepler2596fe52020-01-23 17:40:10 -080091 FormatVaList(format, args);
Wyatt Heplerce9b9522019-11-11 10:45:48 -080092 va_end(args);
93
94 return *this;
95}
96
Wyatt Hepler2596fe52020-01-23 17:40:10 -080097StringBuilder& StringBuilder::FormatVaList(const char* format, va_list args) {
98 HandleStatusWithSize(
99 string::FormatVaList(buffer_.subspan(size_), format, args));
Wyatt Heplerce9b9522019-11-11 10:45:48 -0800100 return *this;
101}
102
Armando Montanez30c5d382021-11-29 12:26:09 -0800103void StringBuilder::WriteBytes(std::span<const std::byte> data) {
Armando Montanez1cbc49a2021-11-19 18:30:27 -0800104 if (size() + data.size() * 2 > max_size()) {
105 SetErrorStatus(Status::ResourceExhausted());
106 } else {
107 for (std::byte val : data) {
108 *this << val;
109 }
110 }
Armando Montanez1cbc49a2021-11-19 18:30:27 -0800111}
112
Wyatt Heplerce9b9522019-11-11 10:45:48 -0800113void StringBuilder::CopySizeAndStatus(const StringBuilder& other) {
114 size_ = other.size_;
115 status_ = other.status_;
116 last_status_ = other.last_status_;
117}
118
119void StringBuilder::HandleStatusWithSize(StatusWithSize written) {
120 const Status status = written.status();
121 last_status_ = status;
122 if (!status.ok()) {
123 status_ = status;
124 }
125
126 size_ += written.size();
127}
128
129void StringBuilder::SetErrorStatus(Status status) {
130 last_status_ = status;
131 status_ = status;
132}
133
134} // namespace pw