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::string::Format and std::snprintf to build a string
16 // in a buffer with multiple calls. The process aborts if an error occurs and
17 // the total string size is returned.
18 //
19 // This compares the overhead of using pw::string::Format to directly calling
20 // std::snprintf and doing error handling. It demonstrates that the code for
21 // using pw::string::Format is much simpler.
22
23 #include "pw_bloat/bloat_this_binary.h"
24
25 #ifndef USE_FORMAT
26 #error "USE_FORMAT must be defined"
27 #endif // USE_FORMAT
28
29 #if USE_FORMAT
30
31 #include "pw_string/format.h"
32
33 #define FORMAT_FUNCTION(...) \
34 pw::string::Format(std::span(buffer, buffer_size - string_size), __VA_ARGS__)
35 #define CHECK_RESULT(result) ProcessResult(&string_size, result)
36
37 namespace {
38
ProcessResult(unsigned * total,pw::StatusWithSize result)39 bool ProcessResult(unsigned* total, pw::StatusWithSize result) {
40 *total += result.size();
41 return result.ok();
42 }
43
44 } // namespace
45
46 #else // std::snprintf
47
48 #include <cstdio>
49
50 #define FORMAT_FUNCTION(...) std::snprintf(buffer, buffer_size, __VA_ARGS__)
51 #define CHECK_RESULT(result) \
52 ProcessResult(buffer, &string_size, buffer_size - string_size, result)
53
54 namespace {
55
ProcessResult(char * buffer,unsigned * total,unsigned size,int result)56 bool ProcessResult(char* buffer, unsigned* total, unsigned size, int result) {
57 if (result < 0) {
58 // Null-terminate since snprintf doesn't report the written count.
59 buffer[size] = '\0';
60 return false;
61 }
62
63 if (static_cast<unsigned>(result) >= size) {
64 if (size > 0u) {
65 *total += size - 1;
66 }
67 return false;
68 }
69
70 *total += result;
71 return true;
72 }
73
74 } // namespace
75
76 #endif // USE_FORMAT
77
78 #define FORMAT_CASE(...) \
79 if (!CHECK_RESULT(FORMAT_FUNCTION(__VA_ARGS__))) { \
80 return string_size; \
81 }
82
83 namespace pw::string {
84
85 char buffer_1[128];
86 char buffer_2[128];
87
88 char* volatile get_buffer_1 = buffer_1;
89 char* volatile get_buffer_2 = buffer_2;
90 volatile unsigned get_size;
91
OutputStringsToBuffer()92 unsigned OutputStringsToBuffer() {
93 char* buffer = get_buffer_1;
94 const char* string = get_buffer_2;
95
96 unsigned buffer_size = get_size;
97 unsigned string_size = 0;
98
99 FORMAT_CASE("The quick brown");
100 FORMAT_CASE("%s", string);
101 FORMAT_CASE("jumped over the %s d%ug.", string, buffer_size);
102 FORMAT_CASE("One two %s %d %s", "three", 4, "five");
103 FORMAT_CASE("a %c %x d %s %f g", 'b', 0xc, "e", 0.0f);
104
105 FORMAT_CASE("The quick brown");
106 FORMAT_CASE("%s", string);
107 FORMAT_CASE("jumped over the %s d%ug.", string, buffer_size);
108 FORMAT_CASE("One two %s %d %s", "three", 4, "five");
109 FORMAT_CASE("a %c %x d %s %f g", 'b', 0xc, "e", 0.0f);
110
111 return string_size;
112 }
113
114 } // namespace pw::string
115
main()116 int main() {
117 pw::bloat::BloatThisBinary();
118 return pw::string::OutputStringsToBuffer();
119 }
120