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 // This size report uses pw::StringBuilder and std::snprintf to write several
16 // strings to a buffer. Ten strings are written using pw::StringBuilder and
17 // std::snprintf, tracking the number of bytes written and whether an error
18 // occurred.
19 //
20 // This compares the incremental cost of using StringBuilder instead of
21 // std::snprintf when both are already in use in a binary.
22
23 #include <cstdio>
24
25 #include "pw_bloat/bloat_this_binary.h"
26 #include "pw_string/string_builder.h"
27
28 #if !defined(USE_STRING_BUILDER)
29 #error "USE_STRING_BUILDER must be defined"
30 #endif // !defined(USE_STRING_BUILDER)
31
32 #if USE_STRING_BUILDER
33
34 #define FORMAT_STRING(string_builder_out, ...) sb << string_builder_out
35
36 #else // std::snprintf
37
38 #define FORMAT_STRING(unused_string_builder_out, ...) \
39 ProcessResult(buffer, \
40 &bytes, \
41 sizeof(buffer) - bytes, \
42 std::snprintf(buffer, sizeof(buffer) - bytes, __VA_ARGS__))
43
44 #endif // USE_STRING_BUILDER
45
ProcessResult(char * buffer,unsigned * total,unsigned size,int result)46 bool ProcessResult(char* buffer, unsigned* total, unsigned size, int result) {
47 if (result < 0) {
48 // Null-terminate since snprintf doesn't report the written count.
49 buffer[size] = '\0';
50 return false;
51 }
52
53 if (static_cast<unsigned>(result) >= size) {
54 if (size > 0u) {
55 *total += size - 1;
56 }
57 return false;
58 }
59
60 *total += result;
61 return true;
62 }
63
64 volatile bool get_boolean;
65 volatile int get_integer;
66 char* volatile get_buffer;
67 char* volatile get_string;
68
main()69 int main() {
70 int integer = get_integer;
71 bool boolean = get_boolean;
72 auto string = get_string;
73
74 char* buffer = get_buffer;
75 unsigned size = get_integer;
76
77 unsigned bytes = 0;
78
79 // Use std::snprintf and pw::StringBuilder so they're both accounted for in
80 // the base.
81 int result = std::snprintf(buffer,
82 size,
83 "Hello, %s. The answer to 3 == %d is %s.",
84 string,
85 integer,
86 boolean ? "true" : "false");
87
88 ProcessResult(buffer, &bytes, size, result);
89
90 pw::StringBuilder sb(std::span(buffer, size));
91 sb << "This is part of the base " << 123 << false << '\n';
92
93 sb.clear();
94
95 // Add five strings with either StringBuilder or std::snprintf.
96 FORMAT_STRING("Three", "Three");
97 FORMAT_STRING("point " << 1, "Three point %d", 1);
98 FORMAT_STRING("four "
99 << "one" << ' ' << 5u,
100 "four %s %u",
101 "one",
102 5u);
103 FORMAT_STRING(string, "%s", string);
104 FORMAT_STRING("-->" << string << string << string << ' ' << integer << ' '
105 << boolean << '!',
106 "--> %s%s%s %d %d!",
107 string,
108 string,
109 string,
110 integer,
111 boolean);
112
113 // Add five more strings with either StringBuilder or std::snprintf.
114 FORMAT_STRING("Three", "Three");
115 FORMAT_STRING("point " << 1, "Three point %d", 1);
116 FORMAT_STRING("four "
117 << "one" << ' ' << 5u,
118 "four %s %u",
119 "one",
120 5u);
121 FORMAT_STRING(string, "%s", string);
122 FORMAT_STRING(string << string << string << ' ' << integer << ' ' << boolean,
123 "%s%s%s %d %d",
124 string,
125 string,
126 string,
127 integer,
128 boolean);
129
130 bytes += sb.size();
131 return bytes;
132 }
133