blob: c38ff0a823160189325ef068737651ac4c132f41 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <utils/String8.h>
#include <cassert>
#include <codecvt>
#include <cwchar>
#include <locale>
#include <string>
namespace android {
String8::String8() = default;
status_t String8::appendFormat(const char* format, ...) {
va_list ap;
va_start(ap, format);
status_t result = appendFormatV(format, ap);
va_end(ap);
return result;
}
status_t String8::appendFormatV(const char* format, va_list ap) {
va_list tmp_ap;
// ap is undefined after vsnprintf, so we need a copy here to avoid the secodn
// vsnprintf accessing undefined ap.
va_copy(tmp_ap, ap);
int n = vsnprintf(nullptr, 0, format, tmp_ap);
va_end(tmp_ap);
if (n) {
size_t old_length = size();
// With -fno-exceptions, I believe the behavior will be to abort() the
// process instead of throwing std::bad_alloc.
reserve(old_length + n);
// TODO: C++17 has a data() accessor that'll return non-const CharT*.
// Once all relevant toolchains are C++17, we could switch to using that
// here to avoid this allocation and copy, and just vsnprintf() directly
// into the latter part of the string instead.
// Similar to above, with -fno-exceptions, I believe the behavior will be to
// abort() the proces instead of throwing std::bad_alloc.
std::unique_ptr<char> temp = std::make_unique<char>(n + 1);
int actual = vsnprintf(temp.get(), n + 1, format, ap);
(void)actual;
// Concurrent modification of the string by mulitple threads isn't
// supported.
assert(n == actual);
// passing the "n" only to avoid forcing a re-count
append(temp.get(), n);
}
return NO_ERROR;
}
const char* String8::string() const { return c_str(); }
} // namespace android