blob: a37fdbea4c3d65c6ab9e8d071feaf64e03165b81 [file] [log] [blame]
// Copyright 2019 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
// This size report uses pw::StringBuilder and std::snprintf to write several
// strings to a buffer. Ten strings are written using pw::StringBuilder and
// std::snprintf, tracking the number of bytes written and whether an error
// occurred.
//
// This compares the incremental cost of using StringBuilder instead of
// std::snprintf when both are already in use in a binary.
#include <cstdio>
#include "pw_bloat/bloat_this_binary.h"
#include "pw_string/string_builder.h"
#if !defined(USE_STRING_BUILDER)
#error "USE_STRING_BUILDER must be defined"
#endif // !defined(USE_STRING_BUILDER)
#if USE_STRING_BUILDER
#define FORMAT_STRING(string_builder_out, ...) sb << string_builder_out
#else // std::snprintf
#define FORMAT_STRING(unused_string_builder_out, ...) \
ProcessResult(buffer, \
&bytes, \
sizeof(buffer) - bytes, \
std::snprintf(buffer, sizeof(buffer) - bytes, __VA_ARGS__))
#endif // USE_STRING_BUILDER
bool ProcessResult(char* buffer, unsigned* total, unsigned size, int result) {
if (result < 0) {
// Null-terminate since snprintf doesn't report the written count.
buffer[size] = '\0';
return false;
}
if (static_cast<unsigned>(result) >= size) {
if (size > 0u) {
*total += size - 1;
}
return false;
}
*total += result;
return true;
}
volatile bool get_boolean;
volatile int get_integer;
char* volatile get_buffer;
char* volatile get_string;
int main() {
int integer = get_integer;
bool boolean = get_boolean;
auto string = get_string;
char* buffer = get_buffer;
unsigned size = get_integer;
unsigned bytes = 0;
// Use std::snprintf and pw::StringBuilder so they're both accounted for in
// the base.
int result = std::snprintf(buffer,
size,
"Hello, %s. The answer to 3 == %d is %s.",
string,
integer,
boolean ? "true" : "false");
ProcessResult(buffer, &bytes, size, result);
pw::StringBuilder sb(std::span(buffer, size));
sb << "This is part of the base " << 123 << false << '\n';
sb.clear();
// Add five strings with either StringBuilder or std::snprintf.
FORMAT_STRING("Three", "Three");
FORMAT_STRING("point " << 1, "Three point %d", 1);
FORMAT_STRING("four "
<< "one" << ' ' << 5u,
"four %s %u",
"one",
5u);
FORMAT_STRING(string, "%s", string);
FORMAT_STRING("-->" << string << string << string << ' ' << integer << ' '
<< boolean << '!',
"--> %s%s%s %d %d!",
string,
string,
string,
integer,
boolean);
// Add five more strings with either StringBuilder or std::snprintf.
FORMAT_STRING("Three", "Three");
FORMAT_STRING("point " << 1, "Three point %d", 1);
FORMAT_STRING("four "
<< "one" << ' ' << 5u,
"four %s %u",
"one",
5u);
FORMAT_STRING(string, "%s", string);
FORMAT_STRING(string << string << string << ' ' << integer << ' ' << boolean,
"%s%s%s %d %d",
string,
string,
string,
integer,
boolean);
bytes += sb.size();
return bytes;
}