/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
deps/v8/src/base/string-format.h
221 строка
8 KB
Michaël Zasso
deps: update V8 to 14.3.127.12
13 ноя 2025, 17:08
Не верифицирован
13 ноя 2025, 17:08
53379f3
Код
Авторство
О чём код?
// Copyright 2022 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_BASE_STRING_FORMAT_H_ #define V8_BASE_STRING_FORMAT_H_ #include <array> #include <cinttypes> #include <limits> #include <string_view> #include <tuple> #include "src/base/logging.h" #include "src/base/platform/platform.h" namespace v8::base { // Implementation detail, do not use outside this header. The public interface // is below. namespace impl { template <const std::string_view&... strs> struct JoinedStringViews { static constexpr auto JoinIntoNullTerminatedArray() noexcept { constexpr size_t kArraySize = (1 + ... + strs.size()); std::array<char, kArraySize> arr{}; char* ptr = arr.data(); for (auto str : std::initializer_list<std::string_view>{strs...}) { for (auto c : str) *ptr++ = c; } *ptr++ = '\0'; DCHECK_EQ(arr.data() + arr.size(), ptr); return arr; } // Store in an array with static linkage, so we can reference it from the // {std::string_view} below. static constexpr auto array = JoinIntoNullTerminatedArray(); // Create a string view to the null-terminated array. The null byte is not // included. static constexpr std::string_view string_view = {array.data(), array.size() - 1}; }; template <typename T> concept FixedSizeString = std::is_bounded_array_v<T> && std::is_same_v<char, std::remove_cv_t<std::remove_pointer_t<std::decay_t<T>>>>; template <typename T> struct FormattedStringPart; // Specializations below. // Use a single implementation for all integral types; this avoids hassle with // int32_t, int64_t, long, long long sometimes being the same types and // sometimes not, depending on the platform. template <typename I> requires std::is_integral_v<I> struct FormattedStringPart<I> { static_assert(sizeof(I) == 4 || sizeof(I) == 8); constexpr static bool kIs64Bit = sizeof(I) == 8; constexpr static bool kIsSigned = std::is_signed_v<I>; static constexpr int kMaxLen = (kIs64Bit ? 20 : 10) + (kIsSigned ? 1 : 0); static constexpr std::string_view kFormats[2][2]{{"%" PRIu32, "%" PRId32}, {"%" PRIu64, "%" PRId64}}; static constexpr std::string_view kFormatPart = kFormats[kIs64Bit][kIsSigned]; using StorageType = std::conditional_t<kIs64Bit, std::conditional_t<kIsSigned, int64_t, uint64_t>, std::conditional_t<kIsSigned, int32_t, uint32_t>>; StorageType value; }; template <typename S> requires FixedSizeString<S> struct FormattedStringPart<S> { static constexpr size_t kCharArraySize = std::extent_v<S>; static_assert(kCharArraySize >= 1, "Do not print (static) empty strings"); static_assert(kCharArraySize <= 128, "Do not include huge strings"); static constexpr int kMaxLen = kCharArraySize - 1; static constexpr std::string_view kFormatPart = "%s"; const char* value; }; template <const std::string_view& kFormat, int kMaxLen, typename... Parts> std::array<char, kMaxLen> PrintFormattedStringToArray(Parts... parts) { std::array<char, kMaxLen> message; static_assert(kMaxLen > 0); static_assert( kMaxLen < 128, "Don't generate overly large strings; this limit can be increased, but " "consider that the array lives on the stack of the caller."); // Add a special case for empty strings, because compilers complain about // empty format strings. static_assert((kFormat.size() == 0) == (sizeof...(Parts) == 0)); if constexpr (kFormat.size() == 0) { message[0] = '\0'; } else { int characters = base::OS::SNPrintF(message.data(), kMaxLen, kFormat.data(), parts.value...); CHECK(characters >= 0 && characters < kMaxLen); DCHECK_EQ('\0', message[characters]); } return message; } } // namespace impl // `FormattedString` allows to format strings with statically known number and // type of constituents. // The class stores all values that should be printed, and generates the final // string via `SNPrintF` into a `std::array`, without any dynamic memory // allocation. The format string is computed statically. // This makes this class not only very performant, but also suitable for // situations where we do not want to perform any memory allocation (like for // reporting OOM or fatal errors). // // Use like this: // auto message = FormattedString{} << "Cannot allocate " << size << " bytes"; // V8::FatalProcessOutOfMemory(nullptr, message.PrintToArray().data()); // // This code is compiled into the equivalent of // std::array<char, 34> message_arr; // int chars = SNPrintF(message_arr.data(), 34, "%s%d%s", "Cannot allocate ", // size, " bytes"); // CHECK(chars >= 0 && chars < 34); // V8::FatalProcessOutOfMemory(nullptr, message_arr.data()); template <typename... Ts> class FormattedString { template <typename T> using Part = impl::FormattedStringPart<T>; static_assert(std::conjunction_v<std::is_trivial<Part<Ts>>...>, "All parts needs to be trivial to guarantee optimal code"); public: static constexpr int kMaxLen = (1 + ... + Part<Ts>::kMaxLen); static constexpr std::string_view kFormat = impl::JoinedStringViews<Part<Ts>::kFormatPart...>::string_view; FormattedString() { static_assert(sizeof...(Ts) == 0, "Only explicitly construct empty FormattedString, use " "operator<< to appending"); } // Add one more part to the FormattedString. Only allowed on r-value ref (i.e. // temporary object) to avoid misuse like `FormattedString<> str; str << 3;` // instead of `auto str = FormattedString{} << 3;`. template <typename T> V8_WARN_UNUSED_RESULT auto operator<<(T&& t) const&& { using PlainT = std::remove_cv_t<std::remove_reference_t<T>>; return FormattedString<Ts..., PlainT>{ std::tuple_cat(parts_, std::make_tuple(Part<PlainT>{t}))}; } // Print this FormattedString into an array. Does not allocate any dynamic // memory. The result lives on the stack of the caller. V8_INLINE V8_WARN_UNUSED_RESULT std::array<char, kMaxLen> PrintToArray() const { return std::apply( impl::PrintFormattedStringToArray<kFormat, kMaxLen, Part<Ts>...>, parts_); } private: template <typename... Us> friend class FormattedString; explicit FormattedString(std::tuple<Part<Ts>...> parts) : parts_(parts) {} std::tuple<Part<Ts>...> parts_; }; // Add an explicit deduction guide for empty template parameters (fixes // clang's -Wctad-maybe-unsupported warning). Non-empty formatted strings // explicitly declare template parameters anyway. FormattedString()->FormattedString<>; class JSONEscaped { public: template <typename T> explicit JSONEscaped(const T& value) { std::ostringstream s; s << value; str_ = s.str(); } explicit JSONEscaped(std::string str) : str_(std::move(str)) {} explicit JSONEscaped(const std::ostringstream& os) : str_(os.str()) {} friend std::ostream& operator<<(std::ostream& os, const JSONEscaped& e) { for (char c : e.str_) PipeCharacter(os, c); return os; } private: static std::ostream& PipeCharacter(std::ostream& os, char c) { if (c == '"') return os << "\\\""; if (c == '\\') return os << "\\\\"; if (c == '\b') return os << "\\b"; if (c == '\f') return os << "\\f"; if (c == '\n') return os << "\\n"; if (c == '\r') return os << "\\r"; if (c == '\t') return os << "\\t"; return os << c; } std::string str_; }; } // namespace v8::base #endif // V8_BASE_STRING_FORMAT_H_