From 7acd4703dad30fe1331bc897cd5298b7b5ecf697 Mon Sep 17 00:00:00 2001 From: Bo-Ru Ju Date: Mon, 13 Jun 2022 18:29:35 +0800 Subject: [PATCH] New package: libdpp-10.0.10 --- srcpkgs/libdpp-devel | 1 + .../libdpp/files/fix-headers-and-cmakefiles | 38772 ++++++++++++++++ srcpkgs/libdpp/files/fix-installed-cmakefiles | 86 + srcpkgs/libdpp/template | 37 + 4 files changed, 38896 insertions(+) create mode 120000 srcpkgs/libdpp-devel create mode 100644 srcpkgs/libdpp/files/fix-headers-and-cmakefiles create mode 100644 srcpkgs/libdpp/files/fix-installed-cmakefiles create mode 100644 srcpkgs/libdpp/template diff --git a/srcpkgs/libdpp-devel b/srcpkgs/libdpp-devel new file mode 120000 index 000000000000..9176d7a850be --- /dev/null +++ b/srcpkgs/libdpp-devel @@ -0,0 +1 @@ +libdpp \ No newline at end of file diff --git a/srcpkgs/libdpp/files/fix-headers-and-cmakefiles b/srcpkgs/libdpp/files/fix-headers-and-cmakefiles new file mode 100644 index 000000000000..f63df5313e96 --- /dev/null +++ b/srcpkgs/libdpp/files/fix-headers-and-cmakefiles @@ -0,0 +1,38772 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index bbcc4b3..524a3ca 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -43,7 +43,7 @@ math(EXPR DPP_VERSION_PATCH ${CMAKE_MATCH_3}) + + string(CONCAT DPP_VERSION ${DPP_VERSION_MAJOR}.${DPP_VERSION_MINOR}.${DPP_VERSION_PATCH}) + +-project(libdpp VERSION ${DPP_VERSION} LANGUAGES CXX) ++project(dpp VERSION ${DPP_VERSION} LANGUAGES CXX) + + check_cxx_symbol_exists(prctl "sys/prctl.h" HAVE_PRCTL) + check_cxx_symbol_exists(pthread_setname_np "pthread.h" HAVE_PTHREAD_SETNAME_NP) +@@ -240,8 +240,8 @@ foreach (fullmodname ${subdirlist}) + target_precompile_headers( + ${modname} + PRIVATE +- "${PROJECT_SOURCE_DIR}/include/dpp/nlohmann/json.hpp" +- "${PROJECT_SOURCE_DIR}/include/dpp/nlohmann/json_fwd.hpp" ++ ++ + ) + + if (WIN32 AND NOT MINGW) +@@ -325,14 +325,16 @@ if(NOT WIN32) + # Installation + + include(GNUInstallDirs) +- install(TARGETS dpp LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) ++ install(TARGETS dpp EXPORT dpp-targets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) ++install(EXPORT dpp-targets DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -DRUN_LDCONFIG=${RUN_LDCONFIG} -DLDCONFIG_EXECUTABLE=${LDCONFIG_EXECUTABLE} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/PostInstall.cmake)") + + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/dpp.pc.in" "${CMAKE_BINARY_DIR}/dpp.pc" @ONLY) + install(FILES "${CMAKE_BINARY_DIR}/dpp.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + elseif(MINGW) +- install(TARGETS dpp LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) ++ install(TARGETS dpp EXPORT dpp-targets LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) ++install(EXPORT dpp-targets DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) + install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_PREFIX}/include) + endif() + +diff --git a/cmake/CPackSetup.cmake b/cmake/CPackSetup.cmake +index a6bcf59..73abe7e 100644 +--- a/cmake/CPackSetup.cmake ++++ b/cmake/CPackSetup.cmake +@@ -24,7 +24,7 @@ write_basic_package_version_file(${DPP_VERSION_FILE} + install(DIRECTORY include/ DESTINATION ${DPP_INSTALL_INCLUDE_DIR}) + + ## Include the file which allows `find_package(libdpp)` to function. +-install(FILES cmake/libdpp-config.cmake ${DPP_VERSION_FILE} DESTINATION ${DPP_INSTALL_LIBRARY_DIR}) ++install(FILES cmake/dpp-config.cmake ${DPP_VERSION_FILE} DESTINATION ${DPP_INSTALL_LIBRARY_DIR}) + + ## Export the targets to allow other projects to easily include this project + install(EXPORT ${DPP_EXPORT_NAME} DESTINATION ${DPP_INSTALL_LIBRARY_DIR} NAMESPACE dpp::) +diff --git a/cmake/libdpp-config.cmake b/cmake/libdpp-config.cmake +deleted file mode 100644 +index d6dd5bd..0000000 +--- a/cmake/libdpp-config.cmake ++++ /dev/null +@@ -1,21 +0,0 @@ +-# libdpp-config.cmake - package configuration file +- +-## Get current filesystem path (will a prefixed by where this package was installed) +-get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +- +-## Use this directory to include libdpp which has the rest of the project targets +-include(${SELF_DIR}/libdpp.cmake) +- +-## Set OpenSSl directory for macos. It is also in our main CMakeLists.txt, but this file is independent from that. +-if(APPLE) +- if(CMAKE_APPLE_SILICON_PROCESSOR) +- set(OPENSSL_ROOT_DIR "/opt/homebrew/opt/openssl") +- else() +- set(OPENSSL_ROOT_DIR "/usr/local/opt/openssl") +- endif() +- find_package(OpenSSL REQUIRED) +-endif() +- +-# Search for libdpp dependencies +-include(CMakeFindDependencyMacro) +-find_dependency(OpenSSL REQUIRED) +diff --git a/include/dpp/appcommand.h b/include/dpp/appcommand.h +index 424823c..36f8f82 100644 +--- a/include/dpp/appcommand.h ++++ b/include/dpp/appcommand.h +@@ -27,7 +27,7 @@ + #include + #include + #include +-#include ++#include + #include + + namespace dpp { +diff --git a/include/dpp/application.h b/include/dpp/application.h +index 7e9d80d..19fad83 100644 +--- a/include/dpp/application.h ++++ b/include/dpp/application.h +@@ -26,7 +26,7 @@ + #include + #include + #include +-#include ++#include + #include + + namespace dpp { +diff --git a/include/dpp/auditlog.h b/include/dpp/auditlog.h +index 3469630..ca878da 100644 +--- a/include/dpp/auditlog.h ++++ b/include/dpp/auditlog.h +@@ -22,7 +22,7 @@ + #pragma once + #include + #include +-#include ++#include + #include + #include + +diff --git a/include/dpp/ban.h b/include/dpp/ban.h +index 6bbcdd2..8ad88d6 100644 +--- a/include/dpp/ban.h ++++ b/include/dpp/ban.h +@@ -22,7 +22,7 @@ + #pragma once + #include + #include +-#include ++#include + #include + #include + +diff --git a/include/dpp/channel.h b/include/dpp/channel.h +index 7335b28..b2fcc33 100644 +--- a/include/dpp/channel.h ++++ b/include/dpp/channel.h +@@ -25,7 +25,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +diff --git a/include/dpp/cluster.h b/include/dpp/cluster.h +index 5400695..6e7b41b 100644 +--- a/include/dpp/cluster.h ++++ b/include/dpp/cluster.h +@@ -29,7 +29,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +diff --git a/include/dpp/commandhandler.h b/include/dpp/commandhandler.h +index 29da473..0b15417 100644 +--- a/include/dpp/commandhandler.h ++++ b/include/dpp/commandhandler.h +@@ -29,7 +29,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +diff --git a/include/dpp/discordclient.h b/include/dpp/discordclient.h +index 1eb875a..10f010e 100644 +--- a/include/dpp/discordclient.h ++++ b/include/dpp/discordclient.h +@@ -24,7 +24,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +diff --git a/include/dpp/discordevents.h b/include/dpp/discordevents.h +index c6474a4..1a70b18 100644 +--- a/include/dpp/discordevents.h ++++ b/include/dpp/discordevents.h +@@ -21,7 +21,7 @@ + #pragma once + + #include +-#include ++#include + + namespace dpp { + +diff --git a/include/dpp/discordvoiceclient.h b/include/dpp/discordvoiceclient.h +index e11d653..6692e54 100644 +--- a/include/dpp/discordvoiceclient.h ++++ b/include/dpp/discordvoiceclient.h +@@ -32,7 +32,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +diff --git a/include/dpp/dtemplate.h b/include/dpp/dtemplate.h +index 948b25d..5fbe17e 100644 +--- a/include/dpp/dtemplate.h ++++ b/include/dpp/dtemplate.h +@@ -21,7 +21,7 @@ + #pragma once + #include + #include +-#include ++#include + #include + #include + +diff --git a/include/dpp/emoji.h b/include/dpp/emoji.h +index a73e58a..9ab9c1e 100644 +--- a/include/dpp/emoji.h ++++ b/include/dpp/emoji.h +@@ -23,7 +23,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + +diff --git a/include/dpp/etf.h b/include/dpp/etf.h +index 1c98e6a..1acd63b 100644 +--- a/include/dpp/etf.h ++++ b/include/dpp/etf.h +@@ -34,7 +34,7 @@ + #pragma once + #include + #include +-#include ++#include + + namespace dpp { + +diff --git a/include/dpp/event.h b/include/dpp/event.h +index cd945f5..388a0d6 100644 +--- a/include/dpp/event.h ++++ b/include/dpp/event.h +@@ -21,7 +21,7 @@ + #pragma once + #include + #include +-#include ++#include + + #define event_decl(x,wstype) /** @brief Internal event handler for wstype websocket events. Called for each websocket message of this type. @internal */ \ + class x : public event { public: virtual void handle(dpp::discord_client* client, nlohmann::json &j, const std::string &raw); }; +diff --git a/include/dpp/fmt-minimal.h b/include/dpp/fmt-minimal.h +index a5e7a5d..88f1e38 100644 +--- a/include/dpp/fmt-minimal.h ++++ b/include/dpp/fmt-minimal.h +@@ -1,3 +1,3 @@ + #pragma once +-#include ++#include + #define FMT_STRING(s) s +diff --git a/include/dpp/fmt/args.h b/include/dpp/fmt/args.h +deleted file mode 100644 +index 9a8e4ed..0000000 +--- a/include/dpp/fmt/args.h ++++ /dev/null +@@ -1,234 +0,0 @@ +-// Formatting library for C++ - dynamic format arguments +-// +-// Copyright (c) 2012 - present, Victor Zverovich +-// All rights reserved. +-// +-// For the license information refer to format.h. +- +-#ifndef FMT_ARGS_H_ +-#define FMT_ARGS_H_ +- +-#include // std::reference_wrapper +-#include // std::unique_ptr +-#include +- +-#include "core.h" +- +-FMT_BEGIN_NAMESPACE +- +-namespace detail { +- +-template struct is_reference_wrapper : std::false_type {}; +-template +-struct is_reference_wrapper> : std::true_type {}; +- +-template const T& unwrap(const T& v) { return v; } +-template const T& unwrap(const std::reference_wrapper& v) { +- return static_cast(v); +-} +- +-class dynamic_arg_list { +- // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for +- // templates it doesn't complain about inability to deduce single translation +- // unit for placing vtable. So storage_node_base is made a fake template. +- template struct node { +- virtual ~node() = default; +- std::unique_ptr> next; +- }; +- +- template struct typed_node : node<> { +- T value; +- +- template +- FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {} +- +- template +- FMT_CONSTEXPR typed_node(const basic_string_view& arg) +- : value(arg.data(), arg.size()) {} +- }; +- +- std::unique_ptr> head_; +- +- public: +- template const T& push(const Arg& arg) { +- auto new_node = std::unique_ptr>(new typed_node(arg)); +- auto& value = new_node->value; +- new_node->next = std::move(head_); +- head_ = std::move(new_node); +- return value; +- } +-}; +-} // namespace detail +- +-/** +- \rst +- A dynamic version of `fmt::format_arg_store`. +- It's equipped with a storage to potentially temporary objects which lifetimes +- could be shorter than the format arguments object. +- +- It can be implicitly converted into `~fmt::basic_format_args` for passing +- into type-erased formatting functions such as `~fmt::vformat`. +- \endrst +- */ +-template +-class dynamic_format_arg_store +-#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 +- // Workaround a GCC template argument substitution bug. +- : public basic_format_args +-#endif +-{ +- private: +- using char_type = typename Context::char_type; +- +- template struct need_copy { +- static constexpr detail::type mapped_type = +- detail::mapped_type_constant::value; +- +- enum { +- value = !(detail::is_reference_wrapper::value || +- std::is_same>::value || +- std::is_same>::value || +- (mapped_type != detail::type::cstring_type && +- mapped_type != detail::type::string_type && +- mapped_type != detail::type::custom_type)) +- }; +- }; +- +- template +- using stored_type = conditional_t::value && +- !has_formatter::value && +- !detail::is_reference_wrapper::value, +- std::basic_string, T>; +- +- // Storage of basic_format_arg must be contiguous. +- std::vector> data_; +- std::vector> named_info_; +- +- // Storage of arguments not fitting into basic_format_arg must grow +- // without relocation because items in data_ refer to it. +- detail::dynamic_arg_list dynamic_args_; +- +- friend class basic_format_args; +- +- unsigned long long get_types() const { +- return detail::is_unpacked_bit | data_.size() | +- (named_info_.empty() +- ? 0ULL +- : static_cast(detail::has_named_args_bit)); +- } +- +- const basic_format_arg* data() const { +- return named_info_.empty() ? data_.data() : data_.data() + 1; +- } +- +- template void emplace_arg(const T& arg) { +- data_.emplace_back(detail::make_arg(arg)); +- } +- +- template +- void emplace_arg(const detail::named_arg& arg) { +- if (named_info_.empty()) { +- constexpr const detail::named_arg_info* zero_ptr{nullptr}; +- data_.insert(data_.begin(), {zero_ptr, 0}); +- } +- data_.emplace_back(detail::make_arg(detail::unwrap(arg.value))); +- auto pop_one = [](std::vector>* data) { +- data->pop_back(); +- }; +- std::unique_ptr>, decltype(pop_one)> +- guard{&data_, pop_one}; +- named_info_.push_back({arg.name, static_cast(data_.size() - 2u)}); +- data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; +- guard.release(); +- } +- +- public: +- constexpr dynamic_format_arg_store() = default; +- +- /** +- \rst +- Adds an argument into the dynamic store for later passing to a formatting +- function. +- +- Note that custom types and string types (but not string views) are copied +- into the store dynamically allocating memory if necessary. +- +- **Example**:: +- +- fmt::dynamic_format_arg_store store; +- store.push_back(42); +- store.push_back("abc"); +- store.push_back(1.5f); +- std::string result = fmt::vformat("{} and {} and {}", store); +- \endrst +- */ +- template void push_back(const T& arg) { +- if (detail::const_check(need_copy::value)) +- emplace_arg(dynamic_args_.push>(arg)); +- else +- emplace_arg(detail::unwrap(arg)); +- } +- +- /** +- \rst +- Adds a reference to the argument into the dynamic store for later passing to +- a formatting function. +- +- **Example**:: +- +- fmt::dynamic_format_arg_store store; +- char band[] = "Rolling Stones"; +- store.push_back(std::cref(band)); +- band[9] = 'c'; // Changing str affects the output. +- std::string result = fmt::vformat("{}", store); +- // result == "Rolling Scones" +- \endrst +- */ +- template void push_back(std::reference_wrapper arg) { +- static_assert( +- need_copy::value, +- "objects of built-in types and string views are always copied"); +- emplace_arg(arg.get()); +- } +- +- /** +- Adds named argument into the dynamic store for later passing to a formatting +- function. ``std::reference_wrapper`` is supported to avoid copying of the +- argument. The name is always copied into the store. +- */ +- template +- void push_back(const detail::named_arg& arg) { +- const char_type* arg_name = +- dynamic_args_.push>(arg.name).c_str(); +- if (detail::const_check(need_copy::value)) { +- emplace_arg( +- fmt::arg(arg_name, dynamic_args_.push>(arg.value))); +- } else { +- emplace_arg(fmt::arg(arg_name, arg.value)); +- } +- } +- +- /** Erase all elements from the store */ +- void clear() { +- data_.clear(); +- named_info_.clear(); +- dynamic_args_ = detail::dynamic_arg_list(); +- } +- +- /** +- \rst +- Reserves space to store at least *new_cap* arguments including +- *new_cap_named* named arguments. +- \endrst +- */ +- void reserve(size_t new_cap, size_t new_cap_named) { +- FMT_ASSERT(new_cap >= new_cap_named, +- "Set of arguments includes set of named arguments"); +- data_.reserve(new_cap); +- named_info_.reserve(new_cap_named); +- } +-}; +- +-FMT_END_NAMESPACE +- +-#endif // FMT_ARGS_H_ +diff --git a/include/dpp/fmt/chrono.h b/include/dpp/fmt/chrono.h +deleted file mode 100644 +index 682efd8..0000000 +--- a/include/dpp/fmt/chrono.h ++++ /dev/null +@@ -1,2067 +0,0 @@ +-// Formatting library for C++ - chrono support +-// +-// Copyright (c) 2012 - present, Victor Zverovich +-// All rights reserved. +-// +-// For the license information refer to format.h. +- +-#ifndef FMT_CHRONO_H_ +-#define FMT_CHRONO_H_ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "format.h" +- +-FMT_BEGIN_NAMESPACE +- +-// Enable tzset. +-#ifndef FMT_USE_TZSET +-// UWP doesn't provide _tzset. +-# if FMT_HAS_INCLUDE("winapifamily.h") +-# include +-# endif +-# if defined(_WIN32) && (!defined(WINAPI_FAMILY) || \ +- (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) +-# define FMT_USE_TZSET 1 +-# else +-# define FMT_USE_TZSET 0 +-# endif +-#endif +- +-// Enable safe chrono durations, unless explicitly disabled. +-#ifndef FMT_SAFE_DURATION_CAST +-# define FMT_SAFE_DURATION_CAST 1 +-#endif +-#if FMT_SAFE_DURATION_CAST +- +-// For conversion between std::chrono::durations without undefined +-// behaviour or erroneous results. +-// This is a stripped down version of duration_cast, for inclusion in fmt. +-// See https://github.com/pauldreik/safe_duration_cast +-// +-// Copyright Paul Dreik 2019 +-namespace safe_duration_cast { +- +-template ::value && +- std::numeric_limits::is_signed == +- std::numeric_limits::is_signed)> +-FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { +- ec = 0; +- using F = std::numeric_limits; +- using T = std::numeric_limits; +- static_assert(F::is_integer, "From must be integral"); +- static_assert(T::is_integer, "To must be integral"); +- +- // A and B are both signed, or both unsigned. +- if (detail::const_check(F::digits <= T::digits)) { +- // From fits in To without any problem. +- } else { +- // From does not always fit in To, resort to a dynamic check. +- if (from < (T::min)() || from > (T::max)()) { +- // outside range. +- ec = 1; +- return {}; +- } +- } +- return static_cast(from); +-} +- +-/** +- * converts From to To, without loss. If the dynamic value of from +- * can't be converted to To without loss, ec is set. +- */ +-template ::value && +- std::numeric_limits::is_signed != +- std::numeric_limits::is_signed)> +-FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { +- ec = 0; +- using F = std::numeric_limits; +- using T = std::numeric_limits; +- static_assert(F::is_integer, "From must be integral"); +- static_assert(T::is_integer, "To must be integral"); +- +- if (detail::const_check(F::is_signed && !T::is_signed)) { +- // From may be negative, not allowed! +- if (fmt::detail::is_negative(from)) { +- ec = 1; +- return {}; +- } +- // From is positive. Can it always fit in To? +- if (detail::const_check(F::digits > T::digits) && +- from > static_cast(detail::max_value())) { +- ec = 1; +- return {}; +- } +- } +- +- if (detail::const_check(!F::is_signed && T::is_signed && +- F::digits >= T::digits) && +- from > static_cast(detail::max_value())) { +- ec = 1; +- return {}; +- } +- return static_cast(from); // Lossless conversion. +-} +- +-template ::value)> +-FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { +- ec = 0; +- return from; +-} // function +- +-// clang-format off +-/** +- * converts From to To if possible, otherwise ec is set. +- * +- * input | output +- * ---------------------------------|--------------- +- * NaN | NaN +- * Inf | Inf +- * normal, fits in output | converted (possibly lossy) +- * normal, does not fit in output | ec is set +- * subnormal | best effort +- * -Inf | -Inf +- */ +-// clang-format on +-template ::value)> +-FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) { +- ec = 0; +- using T = std::numeric_limits; +- static_assert(std::is_floating_point::value, "From must be floating"); +- static_assert(std::is_floating_point::value, "To must be floating"); +- +- // catch the only happy case +- if (std::isfinite(from)) { +- if (from >= T::lowest() && from <= (T::max)()) { +- return static_cast(from); +- } +- // not within range. +- ec = 1; +- return {}; +- } +- +- // nan and inf will be preserved +- return static_cast(from); +-} // function +- +-template ::value)> +-FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) { +- ec = 0; +- static_assert(std::is_floating_point::value, "From must be floating"); +- return from; +-} +- +-/** +- * safe duration cast between integral durations +- */ +-template ::value), +- FMT_ENABLE_IF(std::is_integral::value)> +-To safe_duration_cast(std::chrono::duration from, +- int& ec) { +- using From = std::chrono::duration; +- ec = 0; +- // the basic idea is that we need to convert from count() in the from type +- // to count() in the To type, by multiplying it with this: +- struct Factor +- : std::ratio_divide {}; +- +- static_assert(Factor::num > 0, "num must be positive"); +- static_assert(Factor::den > 0, "den must be positive"); +- +- // the conversion is like this: multiply from.count() with Factor::num +- // /Factor::den and convert it to To::rep, all this without +- // overflow/underflow. let's start by finding a suitable type that can hold +- // both To, From and Factor::num +- using IntermediateRep = +- typename std::common_type::type; +- +- // safe conversion to IntermediateRep +- IntermediateRep count = +- lossless_integral_conversion(from.count(), ec); +- if (ec) return {}; +- // multiply with Factor::num without overflow or underflow +- if (detail::const_check(Factor::num != 1)) { +- const auto max1 = detail::max_value() / Factor::num; +- if (count > max1) { +- ec = 1; +- return {}; +- } +- const auto min1 = +- (std::numeric_limits::min)() / Factor::num; +- if (count < min1) { +- ec = 1; +- return {}; +- } +- count *= Factor::num; +- } +- +- if (detail::const_check(Factor::den != 1)) count /= Factor::den; +- auto tocount = lossless_integral_conversion(count, ec); +- return ec ? To() : To(tocount); +-} +- +-/** +- * safe duration_cast between floating point durations +- */ +-template ::value), +- FMT_ENABLE_IF(std::is_floating_point::value)> +-To safe_duration_cast(std::chrono::duration from, +- int& ec) { +- using From = std::chrono::duration; +- ec = 0; +- if (std::isnan(from.count())) { +- // nan in, gives nan out. easy. +- return To{std::numeric_limits::quiet_NaN()}; +- } +- // maybe we should also check if from is denormal, and decide what to do about +- // it. +- +- // +-inf should be preserved. +- if (std::isinf(from.count())) { +- return To{from.count()}; +- } +- +- // the basic idea is that we need to convert from count() in the from type +- // to count() in the To type, by multiplying it with this: +- struct Factor +- : std::ratio_divide {}; +- +- static_assert(Factor::num > 0, "num must be positive"); +- static_assert(Factor::den > 0, "den must be positive"); +- +- // the conversion is like this: multiply from.count() with Factor::num +- // /Factor::den and convert it to To::rep, all this without +- // overflow/underflow. let's start by finding a suitable type that can hold +- // both To, From and Factor::num +- using IntermediateRep = +- typename std::common_type::type; +- +- // force conversion of From::rep -> IntermediateRep to be safe, +- // even if it will never happen be narrowing in this context. +- IntermediateRep count = +- safe_float_conversion(from.count(), ec); +- if (ec) { +- return {}; +- } +- +- // multiply with Factor::num without overflow or underflow +- if (detail::const_check(Factor::num != 1)) { +- constexpr auto max1 = detail::max_value() / +- static_cast(Factor::num); +- if (count > max1) { +- ec = 1; +- return {}; +- } +- constexpr auto min1 = std::numeric_limits::lowest() / +- static_cast(Factor::num); +- if (count < min1) { +- ec = 1; +- return {}; +- } +- count *= static_cast(Factor::num); +- } +- +- // this can't go wrong, right? den>0 is checked earlier. +- if (detail::const_check(Factor::den != 1)) { +- using common_t = typename std::common_type::type; +- count /= static_cast(Factor::den); +- } +- +- // convert to the to type, safely +- using ToRep = typename To::rep; +- +- const ToRep tocount = safe_float_conversion(count, ec); +- if (ec) { +- return {}; +- } +- return To{tocount}; +-} +-} // namespace safe_duration_cast +-#endif +- +-// Prevents expansion of a preceding token as a function-style macro. +-// Usage: f FMT_NOMACRO() +-#define FMT_NOMACRO +- +-namespace detail { +-template struct null {}; +-inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); } +-inline null<> localtime_s(...) { return null<>(); } +-inline null<> gmtime_r(...) { return null<>(); } +-inline null<> gmtime_s(...) { return null<>(); } +- +-inline const std::locale& get_classic_locale() { +- static const auto& locale = std::locale::classic(); +- return locale; +-} +- +-template struct codecvt_result { +- static constexpr const size_t max_size = 32; +- CodeUnit buf[max_size]; +- CodeUnit* end; +-}; +-template +-constexpr const size_t codecvt_result::max_size; +- +-template +-void write_codecvt(codecvt_result& out, string_view in_buf, +- const std::locale& loc) { +- using codecvt = std::codecvt; +-#if FMT_CLANG_VERSION +-# pragma clang diagnostic push +-# pragma clang diagnostic ignored "-Wdeprecated" +- auto& f = std::use_facet(loc); +-# pragma clang diagnostic pop +-#else +- auto& f = std::use_facet(loc); +-#endif +- auto mb = std::mbstate_t(); +- const char* from_next = nullptr; +- auto result = f.in(mb, in_buf.begin(), in_buf.end(), from_next, +- std::begin(out.buf), std::end(out.buf), out.end); +- if (result != std::codecvt_base::ok) +- FMT_THROW(format_error("failed to format time")); +-} +- +-template +-auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc) +- -> OutputIt { +- if (detail::is_utf8() && loc != get_classic_locale()) { +- // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and +- // gcc-4. +-#if FMT_MSC_VER != 0 || \ +- (defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI)) +- // The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5 +- // and newer. +- using code_unit = wchar_t; +-#else +- using code_unit = char32_t; +-#endif +- +- using unit_t = codecvt_result; +- unit_t unit; +- write_codecvt(unit, in, loc); +- // In UTF-8 is used one to four one-byte code units. +- auto&& buf = basic_memory_buffer(); +- for (code_unit* p = unit.buf; p != unit.end; ++p) { +- uint32_t c = static_cast(*p); +- if (sizeof(code_unit) == 2 && c >= 0xd800 && c <= 0xdfff) { +- // surrogate pair +- ++p; +- if (p == unit.end || (c & 0xfc00) != 0xd800 || +- (*p & 0xfc00) != 0xdc00) { +- FMT_THROW(format_error("failed to format time")); +- } +- c = (c << 10) + static_cast(*p) - 0x35fdc00; +- } +- if (c < 0x80) { +- buf.push_back(static_cast(c)); +- } else if (c < 0x800) { +- buf.push_back(static_cast(0xc0 | (c >> 6))); +- buf.push_back(static_cast(0x80 | (c & 0x3f))); +- } else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) { +- buf.push_back(static_cast(0xe0 | (c >> 12))); +- buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); +- buf.push_back(static_cast(0x80 | (c & 0x3f))); +- } else if (c >= 0x10000 && c <= 0x10ffff) { +- buf.push_back(static_cast(0xf0 | (c >> 18))); +- buf.push_back(static_cast(0x80 | ((c & 0x3ffff) >> 12))); +- buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); +- buf.push_back(static_cast(0x80 | (c & 0x3f))); +- } else { +- FMT_THROW(format_error("failed to format time")); +- } +- } +- return copy_str(buf.data(), buf.data() + buf.size(), out); +- } +- return copy_str(in.data(), in.data() + in.size(), out); +-} +- +-template ::value)> +-auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) +- -> OutputIt { +- codecvt_result unit; +- write_codecvt(unit, sv, loc); +- return copy_str(unit.buf, unit.end, out); +-} +- +-template ::value)> +-auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) +- -> OutputIt { +- return write_encoded_tm_str(out, sv, loc); +-} +- +-template +-inline void do_write(buffer& buf, const std::tm& time, +- const std::locale& loc, char format, char modifier) { +- auto&& format_buf = formatbuf>(buf); +- auto&& os = std::basic_ostream(&format_buf); +- os.imbue(loc); +- using iterator = std::ostreambuf_iterator; +- const auto& facet = std::use_facet>(loc); +- auto end = facet.put(os, os, Char(' '), &time, format, modifier); +- if (end.failed()) FMT_THROW(format_error("failed to format time")); +-} +- +-template ::value)> +-auto write(OutputIt out, const std::tm& time, const std::locale& loc, +- char format, char modifier = 0) -> OutputIt { +- auto&& buf = get_buffer(out); +- do_write(buf, time, loc, format, modifier); +- return buf.out(); +-} +- +-template ::value)> +-auto write(OutputIt out, const std::tm& time, const std::locale& loc, +- char format, char modifier = 0) -> OutputIt { +- auto&& buf = basic_memory_buffer(); +- do_write(buf, time, loc, format, modifier); +- return write_encoded_tm_str(out, string_view(buf.data(), buf.size()), loc); +-} +- +-} // namespace detail +- +-FMT_MODULE_EXPORT_BEGIN +- +-/** +- Converts given time since epoch as ``std::time_t`` value into calendar time, +- expressed in local time. Unlike ``std::localtime``, this function is +- thread-safe on most platforms. +- */ +-inline std::tm localtime(std::time_t time) { +- struct dispatcher { +- std::time_t time_; +- std::tm tm_; +- +- dispatcher(std::time_t t) : time_(t) {} +- +- bool run() { +- using namespace fmt::detail; +- return handle(localtime_r(&time_, &tm_)); +- } +- +- bool handle(std::tm* tm) { return tm != nullptr; } +- +- bool handle(detail::null<>) { +- using namespace fmt::detail; +- return fallback(localtime_s(&tm_, &time_)); +- } +- +- bool fallback(int res) { return res == 0; } +- +-#if !FMT_MSC_VER +- bool fallback(detail::null<>) { +- using namespace fmt::detail; +- std::tm* tm = std::localtime(&time_); +- if (tm) tm_ = *tm; +- return tm != nullptr; +- } +-#endif +- }; +- dispatcher lt(time); +- // Too big time values may be unsupported. +- if (!lt.run()) FMT_THROW(format_error("time_t value out of range")); +- return lt.tm_; +-} +- +-inline std::tm localtime( +- std::chrono::time_point time_point) { +- return localtime(std::chrono::system_clock::to_time_t(time_point)); +-} +- +-/** +- Converts given time since epoch as ``std::time_t`` value into calendar time, +- expressed in Coordinated Universal Time (UTC). Unlike ``std::gmtime``, this +- function is thread-safe on most platforms. +- */ +-inline std::tm gmtime(std::time_t time) { +- struct dispatcher { +- std::time_t time_; +- std::tm tm_; +- +- dispatcher(std::time_t t) : time_(t) {} +- +- bool run() { +- using namespace fmt::detail; +- return handle(gmtime_r(&time_, &tm_)); +- } +- +- bool handle(std::tm* tm) { return tm != nullptr; } +- +- bool handle(detail::null<>) { +- using namespace fmt::detail; +- return fallback(gmtime_s(&tm_, &time_)); +- } +- +- bool fallback(int res) { return res == 0; } +- +-#if !FMT_MSC_VER +- bool fallback(detail::null<>) { +- std::tm* tm = std::gmtime(&time_); +- if (tm) tm_ = *tm; +- return tm != nullptr; +- } +-#endif +- }; +- dispatcher gt(time); +- // Too big time values may be unsupported. +- if (!gt.run()) FMT_THROW(format_error("time_t value out of range")); +- return gt.tm_; +-} +- +-inline std::tm gmtime( +- std::chrono::time_point time_point) { +- return gmtime(std::chrono::system_clock::to_time_t(time_point)); +-} +- +-FMT_BEGIN_DETAIL_NAMESPACE +- +-// Writes two-digit numbers a, b and c separated by sep to buf. +-// The method by Pavel Novikov based on +-// https://johnnylee-sde.github.io/Fast-unsigned-integer-to-time-string/. +-inline void write_digit2_separated(char* buf, unsigned a, unsigned b, +- unsigned c, char sep) { +- unsigned long long digits = +- a | (b << 24) | (static_cast(c) << 48); +- // Convert each value to BCD. +- // We have x = a * 10 + b and we want to convert it to BCD y = a * 16 + b. +- // The difference is +- // y - x = a * 6 +- // a can be found from x: +- // a = floor(x / 10) +- // then +- // y = x + a * 6 = x + floor(x / 10) * 6 +- // floor(x / 10) is (x * 205) >> 11 (needs 16 bits). +- digits += (((digits * 205) >> 11) & 0x000f00000f00000f) * 6; +- // Put low nibbles to high bytes and high nibbles to low bytes. +- digits = ((digits & 0x00f00000f00000f0) >> 4) | +- ((digits & 0x000f00000f00000f) << 8); +- auto usep = static_cast(sep); +- // Add ASCII '0' to each digit byte and insert separators. +- digits |= 0x3030003030003030 | (usep << 16) | (usep << 40); +- +- constexpr const size_t len = 8; +- if (const_check(is_big_endian())) { +- char tmp[len]; +- memcpy(tmp, &digits, len); +- std::reverse_copy(tmp, tmp + len, buf); +- } else { +- memcpy(buf, &digits, len); +- } +-} +- +-template FMT_CONSTEXPR inline const char* get_units() { +- if (std::is_same::value) return "as"; +- if (std::is_same::value) return "fs"; +- if (std::is_same::value) return "ps"; +- if (std::is_same::value) return "ns"; +- if (std::is_same::value) return "µs"; +- if (std::is_same::value) return "ms"; +- if (std::is_same::value) return "cs"; +- if (std::is_same::value) return "ds"; +- if (std::is_same>::value) return "s"; +- if (std::is_same::value) return "das"; +- if (std::is_same::value) return "hs"; +- if (std::is_same::value) return "ks"; +- if (std::is_same::value) return "Ms"; +- if (std::is_same::value) return "Gs"; +- if (std::is_same::value) return "Ts"; +- if (std::is_same::value) return "Ps"; +- if (std::is_same::value) return "Es"; +- if (std::is_same>::value) return "m"; +- if (std::is_same>::value) return "h"; +- return nullptr; +-} +- +-enum class numeric_system { +- standard, +- // Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale. +- alternative +-}; +- +-// Parses a put_time-like format string and invokes handler actions. +-template +-FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, +- const Char* end, +- Handler&& handler) { +- auto ptr = begin; +- while (ptr != end) { +- auto c = *ptr; +- if (c == '}') break; +- if (c != '%') { +- ++ptr; +- continue; +- } +- if (begin != ptr) handler.on_text(begin, ptr); +- ++ptr; // consume '%' +- if (ptr == end) FMT_THROW(format_error("invalid format")); +- c = *ptr++; +- switch (c) { +- case '%': +- handler.on_text(ptr - 1, ptr); +- break; +- case 'n': { +- const Char newline[] = {'\n'}; +- handler.on_text(newline, newline + 1); +- break; +- } +- case 't': { +- const Char tab[] = {'\t'}; +- handler.on_text(tab, tab + 1); +- break; +- } +- // Year: +- case 'Y': +- handler.on_year(numeric_system::standard); +- break; +- case 'y': +- handler.on_short_year(numeric_system::standard); +- break; +- case 'C': +- handler.on_century(numeric_system::standard); +- break; +- case 'G': +- handler.on_iso_week_based_year(); +- break; +- case 'g': +- handler.on_iso_week_based_short_year(); +- break; +- // Day of the week: +- case 'a': +- handler.on_abbr_weekday(); +- break; +- case 'A': +- handler.on_full_weekday(); +- break; +- case 'w': +- handler.on_dec0_weekday(numeric_system::standard); +- break; +- case 'u': +- handler.on_dec1_weekday(numeric_system::standard); +- break; +- // Month: +- case 'b': +- case 'h': +- handler.on_abbr_month(); +- break; +- case 'B': +- handler.on_full_month(); +- break; +- case 'm': +- handler.on_dec_month(numeric_system::standard); +- break; +- // Day of the year/month: +- case 'U': +- handler.on_dec0_week_of_year(numeric_system::standard); +- break; +- case 'W': +- handler.on_dec1_week_of_year(numeric_system::standard); +- break; +- case 'V': +- handler.on_iso_week_of_year(numeric_system::standard); +- break; +- case 'j': +- handler.on_day_of_year(); +- break; +- case 'd': +- handler.on_day_of_month(numeric_system::standard); +- break; +- case 'e': +- handler.on_day_of_month_space(numeric_system::standard); +- break; +- // Hour, minute, second: +- case 'H': +- handler.on_24_hour(numeric_system::standard); +- break; +- case 'I': +- handler.on_12_hour(numeric_system::standard); +- break; +- case 'M': +- handler.on_minute(numeric_system::standard); +- break; +- case 'S': +- handler.on_second(numeric_system::standard); +- break; +- // Other: +- case 'c': +- handler.on_datetime(numeric_system::standard); +- break; +- case 'x': +- handler.on_loc_date(numeric_system::standard); +- break; +- case 'X': +- handler.on_loc_time(numeric_system::standard); +- break; +- case 'D': +- handler.on_us_date(); +- break; +- case 'F': +- handler.on_iso_date(); +- break; +- case 'r': +- handler.on_12_hour_time(); +- break; +- case 'R': +- handler.on_24_hour_time(); +- break; +- case 'T': +- handler.on_iso_time(); +- break; +- case 'p': +- handler.on_am_pm(); +- break; +- case 'Q': +- handler.on_duration_value(); +- break; +- case 'q': +- handler.on_duration_unit(); +- break; +- case 'z': +- handler.on_utc_offset(); +- break; +- case 'Z': +- handler.on_tz_name(); +- break; +- // Alternative representation: +- case 'E': { +- if (ptr == end) FMT_THROW(format_error("invalid format")); +- c = *ptr++; +- switch (c) { +- case 'Y': +- handler.on_year(numeric_system::alternative); +- break; +- case 'y': +- handler.on_offset_year(); +- break; +- case 'C': +- handler.on_century(numeric_system::alternative); +- break; +- case 'c': +- handler.on_datetime(numeric_system::alternative); +- break; +- case 'x': +- handler.on_loc_date(numeric_system::alternative); +- break; +- case 'X': +- handler.on_loc_time(numeric_system::alternative); +- break; +- default: +- FMT_THROW(format_error("invalid format")); +- } +- break; +- } +- case 'O': +- if (ptr == end) FMT_THROW(format_error("invalid format")); +- c = *ptr++; +- switch (c) { +- case 'y': +- handler.on_short_year(numeric_system::alternative); +- break; +- case 'm': +- handler.on_dec_month(numeric_system::alternative); +- break; +- case 'U': +- handler.on_dec0_week_of_year(numeric_system::alternative); +- break; +- case 'W': +- handler.on_dec1_week_of_year(numeric_system::alternative); +- break; +- case 'V': +- handler.on_iso_week_of_year(numeric_system::alternative); +- break; +- case 'd': +- handler.on_day_of_month(numeric_system::alternative); +- break; +- case 'e': +- handler.on_day_of_month_space(numeric_system::alternative); +- break; +- case 'w': +- handler.on_dec0_weekday(numeric_system::alternative); +- break; +- case 'u': +- handler.on_dec1_weekday(numeric_system::alternative); +- break; +- case 'H': +- handler.on_24_hour(numeric_system::alternative); +- break; +- case 'I': +- handler.on_12_hour(numeric_system::alternative); +- break; +- case 'M': +- handler.on_minute(numeric_system::alternative); +- break; +- case 'S': +- handler.on_second(numeric_system::alternative); +- break; +- default: +- FMT_THROW(format_error("invalid format")); +- } +- break; +- default: +- FMT_THROW(format_error("invalid format")); +- } +- begin = ptr; +- } +- if (begin != ptr) handler.on_text(begin, ptr); +- return ptr; +-} +- +-template struct null_chrono_spec_handler { +- FMT_CONSTEXPR void unsupported() { +- static_cast(this)->unsupported(); +- } +- FMT_CONSTEXPR void on_year(numeric_system) { unsupported(); } +- FMT_CONSTEXPR void on_short_year(numeric_system) { unsupported(); } +- FMT_CONSTEXPR void on_offset_year() { unsupported(); } +- FMT_CONSTEXPR void on_century(numeric_system) { unsupported(); } +- FMT_CONSTEXPR void on_iso_week_based_year() { unsupported(); } +- FMT_CONSTEXPR void on_iso_week_based_short_year() { unsupported(); } +- FMT_CONSTEXPR void on_abbr_weekday() { unsupported(); } +- FMT_CONSTEXPR void on_full_weekday() { unsupported(); } +- FMT_CONSTEXPR void on_dec0_weekday(numeric_system) { unsupported(); } +- FMT_CONSTEXPR void on_dec1_weekday(numeric_system) { unsupported(); } +- FMT_CONSTEXPR void on_abbr_month() { unsupported(); } +- FMT_CONSTEXPR void on_full_month() { unsupported(); } +- FMT_CONSTEXPR void on_dec_month(numeric_system) { unsupported(); } +- FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system) { unsupported(); } +- FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system) { unsupported(); } +- FMT_CONSTEXPR void on_iso_week_of_year(numeric_system) { unsupported(); } +- FMT_CONSTEXPR void on_day_of_year() { unsupported(); } +- FMT_CONSTEXPR void on_day_of_month(numeric_system) { unsupported(); } +- FMT_CONSTEXPR void on_day_of_month_space(numeric_system) { unsupported(); } +- FMT_CONSTEXPR void on_24_hour(numeric_system) { unsupported(); } +- FMT_CONSTEXPR void on_12_hour(numeric_system) { unsupported(); } +- FMT_CONSTEXPR void on_minute(numeric_system) { unsupported(); } +- FMT_CONSTEXPR void on_second(numeric_system) { unsupported(); } +- FMT_CONSTEXPR void on_datetime(numeric_system) { unsupported(); } +- FMT_CONSTEXPR void on_loc_date(numeric_system) { unsupported(); } +- FMT_CONSTEXPR void on_loc_time(numeric_system) { unsupported(); } +- FMT_CONSTEXPR void on_us_date() { unsupported(); } +- FMT_CONSTEXPR void on_iso_date() { unsupported(); } +- FMT_CONSTEXPR void on_12_hour_time() { unsupported(); } +- FMT_CONSTEXPR void on_24_hour_time() { unsupported(); } +- FMT_CONSTEXPR void on_iso_time() { unsupported(); } +- FMT_CONSTEXPR void on_am_pm() { unsupported(); } +- FMT_CONSTEXPR void on_duration_value() { unsupported(); } +- FMT_CONSTEXPR void on_duration_unit() { unsupported(); } +- FMT_CONSTEXPR void on_utc_offset() { unsupported(); } +- FMT_CONSTEXPR void on_tz_name() { unsupported(); } +-}; +- +-struct tm_format_checker : null_chrono_spec_handler { +- FMT_NORETURN void unsupported() { FMT_THROW(format_error("no format")); } +- +- template +- FMT_CONSTEXPR void on_text(const Char*, const Char*) {} +- FMT_CONSTEXPR void on_year(numeric_system) {} +- FMT_CONSTEXPR void on_short_year(numeric_system) {} +- FMT_CONSTEXPR void on_offset_year() {} +- FMT_CONSTEXPR void on_century(numeric_system) {} +- FMT_CONSTEXPR void on_iso_week_based_year() {} +- FMT_CONSTEXPR void on_iso_week_based_short_year() {} +- FMT_CONSTEXPR void on_abbr_weekday() {} +- FMT_CONSTEXPR void on_full_weekday() {} +- FMT_CONSTEXPR void on_dec0_weekday(numeric_system) {} +- FMT_CONSTEXPR void on_dec1_weekday(numeric_system) {} +- FMT_CONSTEXPR void on_abbr_month() {} +- FMT_CONSTEXPR void on_full_month() {} +- FMT_CONSTEXPR void on_dec_month(numeric_system) {} +- FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system) {} +- FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system) {} +- FMT_CONSTEXPR void on_iso_week_of_year(numeric_system) {} +- FMT_CONSTEXPR void on_day_of_year() {} +- FMT_CONSTEXPR void on_day_of_month(numeric_system) {} +- FMT_CONSTEXPR void on_day_of_month_space(numeric_system) {} +- FMT_CONSTEXPR void on_24_hour(numeric_system) {} +- FMT_CONSTEXPR void on_12_hour(numeric_system) {} +- FMT_CONSTEXPR void on_minute(numeric_system) {} +- FMT_CONSTEXPR void on_second(numeric_system) {} +- FMT_CONSTEXPR void on_datetime(numeric_system) {} +- FMT_CONSTEXPR void on_loc_date(numeric_system) {} +- FMT_CONSTEXPR void on_loc_time(numeric_system) {} +- FMT_CONSTEXPR void on_us_date() {} +- FMT_CONSTEXPR void on_iso_date() {} +- FMT_CONSTEXPR void on_12_hour_time() {} +- FMT_CONSTEXPR void on_24_hour_time() {} +- FMT_CONSTEXPR void on_iso_time() {} +- FMT_CONSTEXPR void on_am_pm() {} +- FMT_CONSTEXPR void on_utc_offset() {} +- FMT_CONSTEXPR void on_tz_name() {} +-}; +- +-inline const char* tm_wday_full_name(int wday) { +- static constexpr const char* full_name_list[] = { +- "Sunday", "Monday", "Tuesday", "Wednesday", +- "Thursday", "Friday", "Saturday"}; +- return wday >= 0 && wday <= 6 ? full_name_list[wday] : "?"; +-} +-inline const char* tm_wday_short_name(int wday) { +- static constexpr const char* short_name_list[] = {"Sun", "Mon", "Tue", "Wed", +- "Thu", "Fri", "Sat"}; +- return wday >= 0 && wday <= 6 ? short_name_list[wday] : "???"; +-} +- +-inline const char* tm_mon_full_name(int mon) { +- static constexpr const char* full_name_list[] = { +- "January", "February", "March", "April", "May", "June", +- "July", "August", "September", "October", "November", "December"}; +- return mon >= 0 && mon <= 11 ? full_name_list[mon] : "?"; +-} +-inline const char* tm_mon_short_name(int mon) { +- static constexpr const char* short_name_list[] = { +- "Jan", "Feb", "Mar", "Apr", "May", "Jun", +- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", +- }; +- return mon >= 0 && mon <= 11 ? short_name_list[mon] : "???"; +-} +- +-template +-struct has_member_data_tm_gmtoff : std::false_type {}; +-template +-struct has_member_data_tm_gmtoff> +- : std::true_type {}; +- +-template +-struct has_member_data_tm_zone : std::false_type {}; +-template +-struct has_member_data_tm_zone> +- : std::true_type {}; +- +-#if FMT_USE_TZSET +-inline void tzset_once() { +- static bool init = []() -> bool { +- _tzset(); +- return true; +- }(); +- ignore_unused(init); +-} +-#endif +- +-template class tm_writer { +- private: +- static constexpr int days_per_week = 7; +- +- const std::locale& loc_; +- const bool is_classic_; +- OutputIt out_; +- const std::tm& tm_; +- +- auto tm_sec() const noexcept -> int { +- FMT_ASSERT(tm_.tm_sec >= 0 && tm_.tm_sec <= 61, ""); +- return tm_.tm_sec; +- } +- auto tm_min() const noexcept -> int { +- FMT_ASSERT(tm_.tm_min >= 0 && tm_.tm_min <= 59, ""); +- return tm_.tm_min; +- } +- auto tm_hour() const noexcept -> int { +- FMT_ASSERT(tm_.tm_hour >= 0 && tm_.tm_hour <= 23, ""); +- return tm_.tm_hour; +- } +- auto tm_mday() const noexcept -> int { +- FMT_ASSERT(tm_.tm_mday >= 1 && tm_.tm_mday <= 31, ""); +- return tm_.tm_mday; +- } +- auto tm_mon() const noexcept -> int { +- FMT_ASSERT(tm_.tm_mon >= 0 && tm_.tm_mon <= 11, ""); +- return tm_.tm_mon; +- } +- auto tm_year() const noexcept -> long long { return 1900ll + tm_.tm_year; } +- auto tm_wday() const noexcept -> int { +- FMT_ASSERT(tm_.tm_wday >= 0 && tm_.tm_wday <= 6, ""); +- return tm_.tm_wday; +- } +- auto tm_yday() const noexcept -> int { +- FMT_ASSERT(tm_.tm_yday >= 0 && tm_.tm_yday <= 365, ""); +- return tm_.tm_yday; +- } +- +- auto tm_hour12() const noexcept -> int { +- const auto h = tm_hour(); +- const auto z = h < 12 ? h : h - 12; +- return z == 0 ? 12 : z; +- } +- +- // POSIX and the C Standard are unclear or inconsistent about what %C and %y +- // do if the year is negative or exceeds 9999. Use the convention that %C +- // concatenated with %y yields the same output as %Y, and that %Y contains at +- // least 4 characters, with more only if necessary. +- auto split_year_lower(long long year) const noexcept -> int { +- auto l = year % 100; +- if (l < 0) l = -l; // l in [0, 99] +- return static_cast(l); +- } +- +- // Algorithm: +- // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_the_week_number_from_a_month_and_day_of_the_month_or_ordinal_date +- auto iso_year_weeks(long long curr_year) const noexcept -> int { +- const auto prev_year = curr_year - 1; +- const auto curr_p = +- (curr_year + curr_year / 4 - curr_year / 100 + curr_year / 400) % +- days_per_week; +- const auto prev_p = +- (prev_year + prev_year / 4 - prev_year / 100 + prev_year / 400) % +- days_per_week; +- return 52 + ((curr_p == 4 || prev_p == 3) ? 1 : 0); +- } +- auto iso_week_num(int tm_yday, int tm_wday) const noexcept -> int { +- return (tm_yday + 11 - (tm_wday == 0 ? days_per_week : tm_wday)) / +- days_per_week; +- } +- auto tm_iso_week_year() const noexcept -> long long { +- const auto year = tm_year(); +- const auto w = iso_week_num(tm_yday(), tm_wday()); +- if (w < 1) return year - 1; +- if (w > iso_year_weeks(year)) return year + 1; +- return year; +- } +- auto tm_iso_week_of_year() const noexcept -> int { +- const auto year = tm_year(); +- const auto w = iso_week_num(tm_yday(), tm_wday()); +- if (w < 1) return iso_year_weeks(year - 1); +- if (w > iso_year_weeks(year)) return 1; +- return w; +- } +- +- void write1(int value) { +- *out_++ = static_cast('0' + to_unsigned(value) % 10); +- } +- void write2(int value) { +- const char* d = digits2(to_unsigned(value) % 100); +- *out_++ = *d++; +- *out_++ = *d; +- } +- +- void write_year_extended(long long year) { +- // At least 4 characters. +- int width = 4; +- if (year < 0) { +- *out_++ = '-'; +- year = 0 - year; +- --width; +- } +- uint32_or_64_or_128_t n = to_unsigned(year); +- const int num_digits = count_digits(n); +- if (width > num_digits) out_ = std::fill_n(out_, width - num_digits, '0'); +- out_ = format_decimal(out_, n, num_digits).end; +- } +- void write_year(long long year) { +- if (year >= 0 && year < 10000) { +- write2(static_cast(year / 100)); +- write2(static_cast(year % 100)); +- } else { +- write_year_extended(year); +- } +- } +- +- void write_utc_offset(long offset) { +- if (offset < 0) { +- *out_++ = '-'; +- offset = -offset; +- } else { +- *out_++ = '+'; +- } +- offset /= 60; +- write2(static_cast(offset / 60)); +- write2(static_cast(offset % 60)); +- } +- template ::value)> +- void format_utc_offset_impl(const T& tm) { +- write_utc_offset(tm.tm_gmtoff); +- } +- template ::value)> +- void format_utc_offset_impl(const T& tm) { +-#if defined(_WIN32) && defined(_UCRT) +-# if FMT_USE_TZSET +- tzset_once(); +-# endif +- long offset = 0; +- _get_timezone(&offset); +- if (tm.tm_isdst) { +- long dstbias = 0; +- _get_dstbias(&dstbias); +- offset += dstbias; +- } +- write_utc_offset(-offset); +-#else +- ignore_unused(tm); +- format_localized('z'); +-#endif +- } +- +- template ::value)> +- void format_tz_name_impl(const T& tm) { +- if (is_classic_) +- out_ = write_tm_str(out_, tm.tm_zone, loc_); +- else +- format_localized('Z'); +- } +- template ::value)> +- void format_tz_name_impl(const T&) { +- format_localized('Z'); +- } +- +- void format_localized(char format, char modifier = 0) { +- out_ = write(out_, tm_, loc_, format, modifier); +- } +- +- public: +- tm_writer(const std::locale& loc, OutputIt out, const std::tm& tm) +- : loc_(loc), +- is_classic_(loc_ == get_classic_locale()), +- out_(out), +- tm_(tm) {} +- +- OutputIt out() const { return out_; } +- +- FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { +- out_ = copy_str(begin, end, out_); +- } +- +- void on_abbr_weekday() { +- if (is_classic_) +- out_ = write(out_, tm_wday_short_name(tm_wday())); +- else +- format_localized('a'); +- } +- void on_full_weekday() { +- if (is_classic_) +- out_ = write(out_, tm_wday_full_name(tm_wday())); +- else +- format_localized('A'); +- } +- void on_dec0_weekday(numeric_system ns) { +- if (is_classic_ || ns == numeric_system::standard) return write1(tm_wday()); +- format_localized('w', 'O'); +- } +- void on_dec1_weekday(numeric_system ns) { +- if (is_classic_ || ns == numeric_system::standard) { +- auto wday = tm_wday(); +- write1(wday == 0 ? days_per_week : wday); +- } else { +- format_localized('u', 'O'); +- } +- } +- +- void on_abbr_month() { +- if (is_classic_) +- out_ = write(out_, tm_mon_short_name(tm_mon())); +- else +- format_localized('b'); +- } +- void on_full_month() { +- if (is_classic_) +- out_ = write(out_, tm_mon_full_name(tm_mon())); +- else +- format_localized('B'); +- } +- +- void on_datetime(numeric_system ns) { +- if (is_classic_) { +- on_abbr_weekday(); +- *out_++ = ' '; +- on_abbr_month(); +- *out_++ = ' '; +- on_day_of_month_space(numeric_system::standard); +- *out_++ = ' '; +- on_iso_time(); +- *out_++ = ' '; +- on_year(numeric_system::standard); +- } else { +- format_localized('c', ns == numeric_system::standard ? '\0' : 'E'); +- } +- } +- void on_loc_date(numeric_system ns) { +- if (is_classic_) +- on_us_date(); +- else +- format_localized('x', ns == numeric_system::standard ? '\0' : 'E'); +- } +- void on_loc_time(numeric_system ns) { +- if (is_classic_) +- on_iso_time(); +- else +- format_localized('X', ns == numeric_system::standard ? '\0' : 'E'); +- } +- void on_us_date() { +- char buf[8]; +- write_digit2_separated(buf, to_unsigned(tm_mon() + 1), +- to_unsigned(tm_mday()), +- to_unsigned(split_year_lower(tm_year())), '/'); +- out_ = copy_str(std::begin(buf), std::end(buf), out_); +- } +- void on_iso_date() { +- auto year = tm_year(); +- char buf[10]; +- size_t offset = 0; +- if (year >= 0 && year < 10000) { +- copy2(buf, digits2(to_unsigned(year / 100))); +- } else { +- offset = 4; +- write_year_extended(year); +- year = 0; +- } +- write_digit2_separated(buf + 2, static_cast(year % 100), +- to_unsigned(tm_mon() + 1), to_unsigned(tm_mday()), +- '-'); +- out_ = copy_str(std::begin(buf) + offset, std::end(buf), out_); +- } +- +- void on_utc_offset() { format_utc_offset_impl(tm_); } +- void on_tz_name() { format_tz_name_impl(tm_); } +- +- void on_year(numeric_system ns) { +- if (is_classic_ || ns == numeric_system::standard) +- return write_year(tm_year()); +- format_localized('Y', 'E'); +- } +- void on_short_year(numeric_system ns) { +- if (is_classic_ || ns == numeric_system::standard) +- return write2(split_year_lower(tm_year())); +- format_localized('y', 'O'); +- } +- void on_offset_year() { +- if (is_classic_) return write2(split_year_lower(tm_year())); +- format_localized('y', 'E'); +- } +- +- void on_century(numeric_system ns) { +- if (is_classic_ || ns == numeric_system::standard) { +- auto year = tm_year(); +- auto upper = year / 100; +- if (year >= -99 && year < 0) { +- // Zero upper on negative year. +- *out_++ = '-'; +- *out_++ = '0'; +- } else if (upper >= 0 && upper < 100) { +- write2(static_cast(upper)); +- } else { +- out_ = write(out_, upper); +- } +- } else { +- format_localized('C', 'E'); +- } +- } +- +- void on_dec_month(numeric_system ns) { +- if (is_classic_ || ns == numeric_system::standard) +- return write2(tm_mon() + 1); +- format_localized('m', 'O'); +- } +- +- void on_dec0_week_of_year(numeric_system ns) { +- if (is_classic_ || ns == numeric_system::standard) +- return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week); +- format_localized('U', 'O'); +- } +- void on_dec1_week_of_year(numeric_system ns) { +- if (is_classic_ || ns == numeric_system::standard) { +- auto wday = tm_wday(); +- write2((tm_yday() + days_per_week - +- (wday == 0 ? (days_per_week - 1) : (wday - 1))) / +- days_per_week); +- } else { +- format_localized('W', 'O'); +- } +- } +- void on_iso_week_of_year(numeric_system ns) { +- if (is_classic_ || ns == numeric_system::standard) +- return write2(tm_iso_week_of_year()); +- format_localized('V', 'O'); +- } +- +- void on_iso_week_based_year() { write_year(tm_iso_week_year()); } +- void on_iso_week_based_short_year() { +- write2(split_year_lower(tm_iso_week_year())); +- } +- +- void on_day_of_year() { +- auto yday = tm_yday() + 1; +- write1(yday / 100); +- write2(yday % 100); +- } +- void on_day_of_month(numeric_system ns) { +- if (is_classic_ || ns == numeric_system::standard) return write2(tm_mday()); +- format_localized('d', 'O'); +- } +- void on_day_of_month_space(numeric_system ns) { +- if (is_classic_ || ns == numeric_system::standard) { +- auto mday = to_unsigned(tm_mday()) % 100; +- const char* d2 = digits2(mday); +- *out_++ = mday < 10 ? ' ' : d2[0]; +- *out_++ = d2[1]; +- } else { +- format_localized('e', 'O'); +- } +- } +- +- void on_24_hour(numeric_system ns) { +- if (is_classic_ || ns == numeric_system::standard) return write2(tm_hour()); +- format_localized('H', 'O'); +- } +- void on_12_hour(numeric_system ns) { +- if (is_classic_ || ns == numeric_system::standard) +- return write2(tm_hour12()); +- format_localized('I', 'O'); +- } +- void on_minute(numeric_system ns) { +- if (is_classic_ || ns == numeric_system::standard) return write2(tm_min()); +- format_localized('M', 'O'); +- } +- void on_second(numeric_system ns) { +- if (is_classic_ || ns == numeric_system::standard) return write2(tm_sec()); +- format_localized('S', 'O'); +- } +- +- void on_12_hour_time() { +- if (is_classic_) { +- char buf[8]; +- write_digit2_separated(buf, to_unsigned(tm_hour12()), +- to_unsigned(tm_min()), to_unsigned(tm_sec()), ':'); +- out_ = copy_str(std::begin(buf), std::end(buf), out_); +- *out_++ = ' '; +- on_am_pm(); +- } else { +- format_localized('r'); +- } +- } +- void on_24_hour_time() { +- write2(tm_hour()); +- *out_++ = ':'; +- write2(tm_min()); +- } +- void on_iso_time() { +- char buf[8]; +- write_digit2_separated(buf, to_unsigned(tm_hour()), to_unsigned(tm_min()), +- to_unsigned(tm_sec()), ':'); +- out_ = copy_str(std::begin(buf), std::end(buf), out_); +- } +- +- void on_am_pm() { +- if (is_classic_) { +- *out_++ = tm_hour() < 12 ? 'A' : 'P'; +- *out_++ = 'M'; +- } else { +- format_localized('p'); +- } +- } +- +- // These apply to chrono durations but not tm. +- void on_duration_value() {} +- void on_duration_unit() {} +-}; +- +-struct chrono_format_checker : null_chrono_spec_handler { +- FMT_NORETURN void unsupported() { FMT_THROW(format_error("no date")); } +- +- template +- FMT_CONSTEXPR void on_text(const Char*, const Char*) {} +- FMT_CONSTEXPR void on_24_hour(numeric_system) {} +- FMT_CONSTEXPR void on_12_hour(numeric_system) {} +- FMT_CONSTEXPR void on_minute(numeric_system) {} +- FMT_CONSTEXPR void on_second(numeric_system) {} +- FMT_CONSTEXPR void on_12_hour_time() {} +- FMT_CONSTEXPR void on_24_hour_time() {} +- FMT_CONSTEXPR void on_iso_time() {} +- FMT_CONSTEXPR void on_am_pm() {} +- FMT_CONSTEXPR void on_duration_value() {} +- FMT_CONSTEXPR void on_duration_unit() {} +-}; +- +-template ::value)> +-inline bool isnan(T) { +- return false; +-} +-template ::value)> +-inline bool isnan(T value) { +- return std::isnan(value); +-} +- +-template ::value)> +-inline bool isfinite(T) { +- return true; +-} +- +-// Converts value to Int and checks that it's in the range [0, upper). +-template ::value)> +-inline Int to_nonnegative_int(T value, Int upper) { +- FMT_ASSERT(value >= 0 && to_unsigned(value) <= to_unsigned(upper), +- "invalid value"); +- (void)upper; +- return static_cast(value); +-} +-template ::value)> +-inline Int to_nonnegative_int(T value, Int upper) { +- if (value < 0 || value > static_cast(upper)) +- FMT_THROW(format_error("invalid value")); +- return static_cast(value); +-} +- +-template ::value)> +-inline T mod(T x, int y) { +- return x % static_cast(y); +-} +-template ::value)> +-inline T mod(T x, int y) { +- return std::fmod(x, static_cast(y)); +-} +- +-// If T is an integral type, maps T to its unsigned counterpart, otherwise +-// leaves it unchanged (unlike std::make_unsigned). +-template ::value> +-struct make_unsigned_or_unchanged { +- using type = T; +-}; +- +-template struct make_unsigned_or_unchanged { +- using type = typename std::make_unsigned::type; +-}; +- +-#if FMT_SAFE_DURATION_CAST +-// throwing version of safe_duration_cast +-template +-To fmt_safe_duration_cast(std::chrono::duration from) { +- int ec; +- To to = safe_duration_cast::safe_duration_cast(from, ec); +- if (ec) FMT_THROW(format_error("cannot format duration")); +- return to; +-} +-#endif +- +-template ::value)> +-inline std::chrono::duration get_milliseconds( +- std::chrono::duration d) { +- // this may overflow and/or the result may not fit in the +- // target type. +-#if FMT_SAFE_DURATION_CAST +- using CommonSecondsType = +- typename std::common_type::type; +- const auto d_as_common = fmt_safe_duration_cast(d); +- const auto d_as_whole_seconds = +- fmt_safe_duration_cast(d_as_common); +- // this conversion should be nonproblematic +- const auto diff = d_as_common - d_as_whole_seconds; +- const auto ms = +- fmt_safe_duration_cast>(diff); +- return ms; +-#else +- auto s = std::chrono::duration_cast(d); +- return std::chrono::duration_cast(d - s); +-#endif +-} +- +-// Returns the number of fractional digits in the range [0, 18] according to the +-// C++20 spec. If more than 18 fractional digits are required then returns 6 for +-// microseconds precision. +-constexpr int count_fractional_digits(long long num, long long den, int n = 0) { +- return num % den == 0 +- ? n +- : (n > 18 ? 6 : count_fractional_digits(num * 10, den, n + 1)); +-} +- +-constexpr long long pow10(std::uint32_t n) { +- return n == 0 ? 1 : 10 * pow10(n - 1); +-} +- +-template ::is_signed)> +-constexpr std::chrono::duration abs( +- std::chrono::duration d) { +- // We need to compare the duration using the count() method directly +- // due to a compiler bug in clang-11 regarding the spaceship operator, +- // when -Wzero-as-null-pointer-constant is enabled. +- // In clang-12 the bug has been fixed. See +- // https://bugs.llvm.org/show_bug.cgi?id=46235 and the reproducible example: +- // https://www.godbolt.org/z/Knbb5joYx. +- return d.count() >= d.zero().count() ? d : -d; +-} +- +-template ::is_signed)> +-constexpr std::chrono::duration abs( +- std::chrono::duration d) { +- return d; +-} +- +-template ::value)> +-OutputIt format_duration_value(OutputIt out, Rep val, int) { +- return write(out, val); +-} +- +-template ::value)> +-OutputIt format_duration_value(OutputIt out, Rep val, int precision) { +- auto specs = basic_format_specs(); +- specs.precision = precision; +- specs.type = precision >= 0 ? presentation_type::fixed_lower +- : presentation_type::general_lower; +- return write(out, val, specs); +-} +- +-template +-OutputIt copy_unit(string_view unit, OutputIt out, Char) { +- return std::copy(unit.begin(), unit.end(), out); +-} +- +-template +-OutputIt copy_unit(string_view unit, OutputIt out, wchar_t) { +- // This works when wchar_t is UTF-32 because units only contain characters +- // that have the same representation in UTF-16 and UTF-32. +- utf8_to_utf16 u(unit); +- return std::copy(u.c_str(), u.c_str() + u.size(), out); +-} +- +-template +-OutputIt format_duration_unit(OutputIt out) { +- if (const char* unit = get_units()) +- return copy_unit(string_view(unit), out, Char()); +- *out++ = '['; +- out = write(out, Period::num); +- if (const_check(Period::den != 1)) { +- *out++ = '/'; +- out = write(out, Period::den); +- } +- *out++ = ']'; +- *out++ = 's'; +- return out; +-} +- +-class get_locale { +- private: +- union { +- std::locale locale_; +- }; +- bool has_locale_ = false; +- +- public: +- get_locale(bool localized, locale_ref loc) : has_locale_(localized) { +- if (localized) +- ::new (&locale_) std::locale(loc.template get()); +- } +- ~get_locale() { +- if (has_locale_) locale_.~locale(); +- } +- operator const std::locale&() const { +- return has_locale_ ? locale_ : get_classic_locale(); +- } +-}; +- +-template +-struct chrono_formatter { +- FormatContext& context; +- OutputIt out; +- int precision; +- bool localized = false; +- // rep is unsigned to avoid overflow. +- using rep = +- conditional_t::value && sizeof(Rep) < sizeof(int), +- unsigned, typename make_unsigned_or_unchanged::type>; +- rep val; +- using seconds = std::chrono::duration; +- seconds s; +- using milliseconds = std::chrono::duration; +- bool negative; +- +- using char_type = typename FormatContext::char_type; +- using tm_writer_type = tm_writer; +- +- chrono_formatter(FormatContext& ctx, OutputIt o, +- std::chrono::duration d) +- : context(ctx), +- out(o), +- val(static_cast(d.count())), +- negative(false) { +- if (d.count() < 0) { +- val = 0 - val; +- negative = true; +- } +- +- // this may overflow and/or the result may not fit in the +- // target type. +-#if FMT_SAFE_DURATION_CAST +- // might need checked conversion (rep!=Rep) +- auto tmpval = std::chrono::duration(val); +- s = fmt_safe_duration_cast(tmpval); +-#else +- s = std::chrono::duration_cast( +- std::chrono::duration(val)); +-#endif +- } +- +- // returns true if nan or inf, writes to out. +- bool handle_nan_inf() { +- if (isfinite(val)) { +- return false; +- } +- if (isnan(val)) { +- write_nan(); +- return true; +- } +- // must be +-inf +- if (val > 0) { +- write_pinf(); +- } else { +- write_ninf(); +- } +- return true; +- } +- +- Rep hour() const { return static_cast(mod((s.count() / 3600), 24)); } +- +- Rep hour12() const { +- Rep hour = static_cast(mod((s.count() / 3600), 12)); +- return hour <= 0 ? 12 : hour; +- } +- +- Rep minute() const { return static_cast(mod((s.count() / 60), 60)); } +- Rep second() const { return static_cast(mod(s.count(), 60)); } +- +- std::tm time() const { +- auto time = std::tm(); +- time.tm_hour = to_nonnegative_int(hour(), 24); +- time.tm_min = to_nonnegative_int(minute(), 60); +- time.tm_sec = to_nonnegative_int(second(), 60); +- return time; +- } +- +- void write_sign() { +- if (negative) { +- *out++ = '-'; +- negative = false; +- } +- } +- +- void write(Rep value, int width) { +- write_sign(); +- if (isnan(value)) return write_nan(); +- uint32_or_64_or_128_t n = +- to_unsigned(to_nonnegative_int(value, max_value())); +- int num_digits = detail::count_digits(n); +- if (width > num_digits) out = std::fill_n(out, width - num_digits, '0'); +- out = format_decimal(out, n, num_digits).end; +- } +- +- template void write_fractional_seconds(Duration d) { +- constexpr auto num_fractional_digits = +- count_fractional_digits(Duration::period::num, Duration::period::den); +- +- using subsecond_precision = std::chrono::duration< +- typename std::common_type::type, +- std::ratio<1, detail::pow10(num_fractional_digits)>>; +- if (std::ratio_less::value) { +- *out++ = '.'; +- // Don't convert long double to integer seconds to avoid overflow. +- using sec = conditional_t< +- std::is_same::value, +- std::chrono::duration, std::chrono::seconds>; +- auto fractional = detail::abs(d) - std::chrono::duration_cast(d); +- const auto subseconds = +- std::chrono::treat_as_floating_point< +- typename subsecond_precision::rep>::value +- ? fractional.count() +- : std::chrono::duration_cast(fractional) +- .count(); +- uint32_or_64_or_128_t n = +- to_unsigned(to_nonnegative_int(subseconds, max_value())); +- int num_digits = detail::count_digits(n); +- if (num_fractional_digits > num_digits) +- out = std::fill_n(out, num_fractional_digits - num_digits, '0'); +- out = format_decimal(out, n, num_digits).end; +- } +- } +- +- void write_nan() { std::copy_n("nan", 3, out); } +- void write_pinf() { std::copy_n("inf", 3, out); } +- void write_ninf() { std::copy_n("-inf", 4, out); } +- +- template +- void format_tm(const tm& time, Callback cb, Args... args) { +- if (isnan(val)) return write_nan(); +- get_locale loc(localized, context.locale()); +- auto w = tm_writer_type(loc, out, time); +- (w.*cb)(args...); +- out = w.out(); +- } +- +- void on_text(const char_type* begin, const char_type* end) { +- std::copy(begin, end, out); +- } +- +- // These are not implemented because durations don't have date information. +- void on_abbr_weekday() {} +- void on_full_weekday() {} +- void on_dec0_weekday(numeric_system) {} +- void on_dec1_weekday(numeric_system) {} +- void on_abbr_month() {} +- void on_full_month() {} +- void on_datetime(numeric_system) {} +- void on_loc_date(numeric_system) {} +- void on_loc_time(numeric_system) {} +- void on_us_date() {} +- void on_iso_date() {} +- void on_utc_offset() {} +- void on_tz_name() {} +- void on_year(numeric_system) {} +- void on_short_year(numeric_system) {} +- void on_offset_year() {} +- void on_century(numeric_system) {} +- void on_iso_week_based_year() {} +- void on_iso_week_based_short_year() {} +- void on_dec_month(numeric_system) {} +- void on_dec0_week_of_year(numeric_system) {} +- void on_dec1_week_of_year(numeric_system) {} +- void on_iso_week_of_year(numeric_system) {} +- void on_day_of_year() {} +- void on_day_of_month(numeric_system) {} +- void on_day_of_month_space(numeric_system) {} +- +- void on_24_hour(numeric_system ns) { +- if (handle_nan_inf()) return; +- +- if (ns == numeric_system::standard) return write(hour(), 2); +- auto time = tm(); +- time.tm_hour = to_nonnegative_int(hour(), 24); +- format_tm(time, &tm_writer_type::on_24_hour, ns); +- } +- +- void on_12_hour(numeric_system ns) { +- if (handle_nan_inf()) return; +- +- if (ns == numeric_system::standard) return write(hour12(), 2); +- auto time = tm(); +- time.tm_hour = to_nonnegative_int(hour12(), 12); +- format_tm(time, &tm_writer_type::on_12_hour, ns); +- } +- +- void on_minute(numeric_system ns) { +- if (handle_nan_inf()) return; +- +- if (ns == numeric_system::standard) return write(minute(), 2); +- auto time = tm(); +- time.tm_min = to_nonnegative_int(minute(), 60); +- format_tm(time, &tm_writer_type::on_minute, ns); +- } +- +- void on_second(numeric_system ns) { +- if (handle_nan_inf()) return; +- +- if (ns == numeric_system::standard) { +- write(second(), 2); +- write_fractional_seconds(std::chrono::duration{val}); +- return; +- } +- auto time = tm(); +- time.tm_sec = to_nonnegative_int(second(), 60); +- format_tm(time, &tm_writer_type::on_second, ns); +- } +- +- void on_12_hour_time() { +- if (handle_nan_inf()) return; +- format_tm(time(), &tm_writer_type::on_12_hour_time); +- } +- +- void on_24_hour_time() { +- if (handle_nan_inf()) { +- *out++ = ':'; +- handle_nan_inf(); +- return; +- } +- +- write(hour(), 2); +- *out++ = ':'; +- write(minute(), 2); +- } +- +- void on_iso_time() { +- on_24_hour_time(); +- *out++ = ':'; +- if (handle_nan_inf()) return; +- on_second(numeric_system::standard); +- } +- +- void on_am_pm() { +- if (handle_nan_inf()) return; +- format_tm(time(), &tm_writer_type::on_am_pm); +- } +- +- void on_duration_value() { +- if (handle_nan_inf()) return; +- write_sign(); +- out = format_duration_value(out, val, precision); +- } +- +- void on_duration_unit() { +- out = format_duration_unit(out); +- } +-}; +- +-FMT_END_DETAIL_NAMESPACE +- +-#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907 +-using weekday = std::chrono::weekday; +-#else +-// A fallback version of weekday. +-class weekday { +- private: +- unsigned char value; +- +- public: +- weekday() = default; +- explicit constexpr weekday(unsigned wd) noexcept +- : value(static_cast(wd != 7 ? wd : 0)) {} +- constexpr unsigned c_encoding() const noexcept { return value; } +-}; +- +-class year_month_day {}; +-#endif +- +-// A rudimentary weekday formatter. +-template struct formatter { +- private: +- bool localized = false; +- +- public: +- FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) +- -> decltype(ctx.begin()) { +- auto begin = ctx.begin(), end = ctx.end(); +- if (begin != end && *begin == 'L') { +- ++begin; +- localized = true; +- } +- return begin; +- } +- +- template +- auto format(weekday wd, FormatContext& ctx) const -> decltype(ctx.out()) { +- auto time = std::tm(); +- time.tm_wday = static_cast(wd.c_encoding()); +- detail::get_locale loc(localized, ctx.locale()); +- auto w = detail::tm_writer(loc, ctx.out(), time); +- w.on_abbr_weekday(); +- return w.out(); +- } +-}; +- +-template +-struct formatter, Char> { +- private: +- basic_format_specs specs; +- int precision = -1; +- using arg_ref_type = detail::arg_ref; +- arg_ref_type width_ref; +- arg_ref_type precision_ref; +- bool localized = false; +- basic_string_view format_str; +- using duration = std::chrono::duration; +- +- struct spec_handler { +- formatter& f; +- basic_format_parse_context& context; +- basic_string_view format_str; +- +- template FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) { +- context.check_arg_id(arg_id); +- return arg_ref_type(arg_id); +- } +- +- FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view arg_id) { +- context.check_arg_id(arg_id); +- return arg_ref_type(arg_id); +- } +- +- FMT_CONSTEXPR arg_ref_type make_arg_ref(detail::auto_id) { +- return arg_ref_type(context.next_arg_id()); +- } +- +- void on_error(const char* msg) { FMT_THROW(format_error(msg)); } +- FMT_CONSTEXPR void on_fill(basic_string_view fill) { +- f.specs.fill = fill; +- } +- FMT_CONSTEXPR void on_align(align_t align) { f.specs.align = align; } +- FMT_CONSTEXPR void on_width(int width) { f.specs.width = width; } +- FMT_CONSTEXPR void on_precision(int _precision) { +- f.precision = _precision; +- } +- FMT_CONSTEXPR void end_precision() {} +- +- template FMT_CONSTEXPR void on_dynamic_width(Id arg_id) { +- f.width_ref = make_arg_ref(arg_id); +- } +- +- template FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) { +- f.precision_ref = make_arg_ref(arg_id); +- } +- }; +- +- using iterator = typename basic_format_parse_context::iterator; +- struct parse_range { +- iterator begin; +- iterator end; +- }; +- +- FMT_CONSTEXPR parse_range do_parse(basic_format_parse_context& ctx) { +- auto begin = ctx.begin(), end = ctx.end(); +- if (begin == end || *begin == '}') return {begin, begin}; +- spec_handler handler{*this, ctx, format_str}; +- begin = detail::parse_align(begin, end, handler); +- if (begin == end) return {begin, begin}; +- begin = detail::parse_width(begin, end, handler); +- if (begin == end) return {begin, begin}; +- if (*begin == '.') { +- if (std::is_floating_point::value) +- begin = detail::parse_precision(begin, end, handler); +- else +- handler.on_error("precision not allowed for this argument type"); +- } +- if (begin != end && *begin == 'L') { +- ++begin; +- localized = true; +- } +- end = detail::parse_chrono_format(begin, end, +- detail::chrono_format_checker()); +- return {begin, end}; +- } +- +- public: +- FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) +- -> decltype(ctx.begin()) { +- auto range = do_parse(ctx); +- format_str = basic_string_view( +- &*range.begin, detail::to_unsigned(range.end - range.begin)); +- return range.end; +- } +- +- template +- auto format(const duration& d, FormatContext& ctx) const +- -> decltype(ctx.out()) { +- auto specs_copy = specs; +- auto precision_copy = precision; +- auto begin = format_str.begin(), end = format_str.end(); +- // As a possible future optimization, we could avoid extra copying if width +- // is not specified. +- basic_memory_buffer buf; +- auto out = std::back_inserter(buf); +- detail::handle_dynamic_spec(specs_copy.width, +- width_ref, ctx); +- detail::handle_dynamic_spec(precision_copy, +- precision_ref, ctx); +- if (begin == end || *begin == '}') { +- out = detail::format_duration_value(out, d.count(), precision_copy); +- detail::format_duration_unit(out); +- } else { +- detail::chrono_formatter f( +- ctx, out, d); +- f.precision = precision_copy; +- f.localized = localized; +- detail::parse_chrono_format(begin, end, f); +- } +- return detail::write( +- ctx.out(), basic_string_view(buf.data(), buf.size()), specs_copy); +- } +-}; +- +-template +-struct formatter, +- Char> : formatter { +- FMT_CONSTEXPR formatter() { +- this->do_parse(default_specs, +- default_specs + sizeof(default_specs) / sizeof(Char)); +- } +- +- template +- FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { +- return this->do_parse(ctx.begin(), ctx.end(), true); +- } +- +- template +- auto format(std::chrono::time_point val, +- FormatContext& ctx) const -> decltype(ctx.out()) { +- return formatter::format(localtime(val), ctx); +- } +- +- static constexpr const Char default_specs[] = {'%', 'F', ' ', '%', 'T'}; +-}; +- +-template +-constexpr const Char +- formatter, +- Char>::default_specs[]; +- +-template struct formatter { +- private: +- enum class spec { +- unknown, +- year_month_day, +- hh_mm_ss, +- }; +- spec spec_ = spec::unknown; +- basic_string_view specs; +- +- protected: +- template +- FMT_CONSTEXPR auto do_parse(It begin, It end, bool with_default = false) +- -> It { +- if (begin != end && *begin == ':') ++begin; +- end = detail::parse_chrono_format(begin, end, detail::tm_format_checker()); +- if (!with_default || end != begin) +- specs = {begin, detail::to_unsigned(end - begin)}; +- // basic_string_view<>::compare isn't constexpr before C++17. +- if (specs.size() == 2 && specs[0] == Char('%')) { +- if (specs[1] == Char('F')) +- spec_ = spec::year_month_day; +- else if (specs[1] == Char('T')) +- spec_ = spec::hh_mm_ss; +- } +- return end; +- } +- +- public: +- template +- FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { +- return this->do_parse(ctx.begin(), ctx.end()); +- } +- +- template +- auto format(const std::tm& tm, FormatContext& ctx) const +- -> decltype(ctx.out()) { +- const auto loc_ref = ctx.locale(); +- detail::get_locale loc(static_cast(loc_ref), loc_ref); +- auto w = detail::tm_writer(loc, ctx.out(), tm); +- if (spec_ == spec::year_month_day) +- w.on_iso_date(); +- else if (spec_ == spec::hh_mm_ss) +- w.on_iso_time(); +- else +- detail::parse_chrono_format(specs.begin(), specs.end(), w); +- return w.out(); +- } +-}; +- +-FMT_MODULE_EXPORT_END +-FMT_END_NAMESPACE +- +-#endif // FMT_CHRONO_H_ +diff --git a/include/dpp/fmt/color.h b/include/dpp/fmt/color.h +deleted file mode 100644 +index dfbe482..0000000 +--- a/include/dpp/fmt/color.h ++++ /dev/null +@@ -1,638 +0,0 @@ +-// Formatting library for C++ - color support +-// +-// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors +-// All rights reserved. +-// +-// For the license information refer to format.h. +- +-#ifndef FMT_COLOR_H_ +-#define FMT_COLOR_H_ +- +-#include "format.h" +- +-// __declspec(deprecated) is broken in some MSVC versions. +-#if FMT_MSC_VER +-# define FMT_DEPRECATED_NONMSVC +-#else +-# define FMT_DEPRECATED_NONMSVC FMT_DEPRECATED +-#endif +- +-FMT_BEGIN_NAMESPACE +-FMT_MODULE_EXPORT_BEGIN +- +-enum class color : uint32_t { +- alice_blue = 0xF0F8FF, // rgb(240,248,255) +- antique_white = 0xFAEBD7, // rgb(250,235,215) +- aqua = 0x00FFFF, // rgb(0,255,255) +- aquamarine = 0x7FFFD4, // rgb(127,255,212) +- azure = 0xF0FFFF, // rgb(240,255,255) +- beige = 0xF5F5DC, // rgb(245,245,220) +- bisque = 0xFFE4C4, // rgb(255,228,196) +- black = 0x000000, // rgb(0,0,0) +- blanched_almond = 0xFFEBCD, // rgb(255,235,205) +- blue = 0x0000FF, // rgb(0,0,255) +- blue_violet = 0x8A2BE2, // rgb(138,43,226) +- brown = 0xA52A2A, // rgb(165,42,42) +- burly_wood = 0xDEB887, // rgb(222,184,135) +- cadet_blue = 0x5F9EA0, // rgb(95,158,160) +- chartreuse = 0x7FFF00, // rgb(127,255,0) +- chocolate = 0xD2691E, // rgb(210,105,30) +- coral = 0xFF7F50, // rgb(255,127,80) +- cornflower_blue = 0x6495ED, // rgb(100,149,237) +- cornsilk = 0xFFF8DC, // rgb(255,248,220) +- crimson = 0xDC143C, // rgb(220,20,60) +- cyan = 0x00FFFF, // rgb(0,255,255) +- dark_blue = 0x00008B, // rgb(0,0,139) +- dark_cyan = 0x008B8B, // rgb(0,139,139) +- dark_golden_rod = 0xB8860B, // rgb(184,134,11) +- dark_gray = 0xA9A9A9, // rgb(169,169,169) +- dark_green = 0x006400, // rgb(0,100,0) +- dark_khaki = 0xBDB76B, // rgb(189,183,107) +- dark_magenta = 0x8B008B, // rgb(139,0,139) +- dark_olive_green = 0x556B2F, // rgb(85,107,47) +- dark_orange = 0xFF8C00, // rgb(255,140,0) +- dark_orchid = 0x9932CC, // rgb(153,50,204) +- dark_red = 0x8B0000, // rgb(139,0,0) +- dark_salmon = 0xE9967A, // rgb(233,150,122) +- dark_sea_green = 0x8FBC8F, // rgb(143,188,143) +- dark_slate_blue = 0x483D8B, // rgb(72,61,139) +- dark_slate_gray = 0x2F4F4F, // rgb(47,79,79) +- dark_turquoise = 0x00CED1, // rgb(0,206,209) +- dark_violet = 0x9400D3, // rgb(148,0,211) +- deep_pink = 0xFF1493, // rgb(255,20,147) +- deep_sky_blue = 0x00BFFF, // rgb(0,191,255) +- dim_gray = 0x696969, // rgb(105,105,105) +- dodger_blue = 0x1E90FF, // rgb(30,144,255) +- fire_brick = 0xB22222, // rgb(178,34,34) +- floral_white = 0xFFFAF0, // rgb(255,250,240) +- forest_green = 0x228B22, // rgb(34,139,34) +- fuchsia = 0xFF00FF, // rgb(255,0,255) +- gainsboro = 0xDCDCDC, // rgb(220,220,220) +- ghost_white = 0xF8F8FF, // rgb(248,248,255) +- gold = 0xFFD700, // rgb(255,215,0) +- golden_rod = 0xDAA520, // rgb(218,165,32) +- gray = 0x808080, // rgb(128,128,128) +- green = 0x008000, // rgb(0,128,0) +- green_yellow = 0xADFF2F, // rgb(173,255,47) +- honey_dew = 0xF0FFF0, // rgb(240,255,240) +- hot_pink = 0xFF69B4, // rgb(255,105,180) +- indian_red = 0xCD5C5C, // rgb(205,92,92) +- indigo = 0x4B0082, // rgb(75,0,130) +- ivory = 0xFFFFF0, // rgb(255,255,240) +- khaki = 0xF0E68C, // rgb(240,230,140) +- lavender = 0xE6E6FA, // rgb(230,230,250) +- lavender_blush = 0xFFF0F5, // rgb(255,240,245) +- lawn_green = 0x7CFC00, // rgb(124,252,0) +- lemon_chiffon = 0xFFFACD, // rgb(255,250,205) +- light_blue = 0xADD8E6, // rgb(173,216,230) +- light_coral = 0xF08080, // rgb(240,128,128) +- light_cyan = 0xE0FFFF, // rgb(224,255,255) +- light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210) +- light_gray = 0xD3D3D3, // rgb(211,211,211) +- light_green = 0x90EE90, // rgb(144,238,144) +- light_pink = 0xFFB6C1, // rgb(255,182,193) +- light_salmon = 0xFFA07A, // rgb(255,160,122) +- light_sea_green = 0x20B2AA, // rgb(32,178,170) +- light_sky_blue = 0x87CEFA, // rgb(135,206,250) +- light_slate_gray = 0x778899, // rgb(119,136,153) +- light_steel_blue = 0xB0C4DE, // rgb(176,196,222) +- light_yellow = 0xFFFFE0, // rgb(255,255,224) +- lime = 0x00FF00, // rgb(0,255,0) +- lime_green = 0x32CD32, // rgb(50,205,50) +- linen = 0xFAF0E6, // rgb(250,240,230) +- magenta = 0xFF00FF, // rgb(255,0,255) +- maroon = 0x800000, // rgb(128,0,0) +- medium_aquamarine = 0x66CDAA, // rgb(102,205,170) +- medium_blue = 0x0000CD, // rgb(0,0,205) +- medium_orchid = 0xBA55D3, // rgb(186,85,211) +- medium_purple = 0x9370DB, // rgb(147,112,219) +- medium_sea_green = 0x3CB371, // rgb(60,179,113) +- medium_slate_blue = 0x7B68EE, // rgb(123,104,238) +- medium_spring_green = 0x00FA9A, // rgb(0,250,154) +- medium_turquoise = 0x48D1CC, // rgb(72,209,204) +- medium_violet_red = 0xC71585, // rgb(199,21,133) +- midnight_blue = 0x191970, // rgb(25,25,112) +- mint_cream = 0xF5FFFA, // rgb(245,255,250) +- misty_rose = 0xFFE4E1, // rgb(255,228,225) +- moccasin = 0xFFE4B5, // rgb(255,228,181) +- navajo_white = 0xFFDEAD, // rgb(255,222,173) +- navy = 0x000080, // rgb(0,0,128) +- old_lace = 0xFDF5E6, // rgb(253,245,230) +- olive = 0x808000, // rgb(128,128,0) +- olive_drab = 0x6B8E23, // rgb(107,142,35) +- orange = 0xFFA500, // rgb(255,165,0) +- orange_red = 0xFF4500, // rgb(255,69,0) +- orchid = 0xDA70D6, // rgb(218,112,214) +- pale_golden_rod = 0xEEE8AA, // rgb(238,232,170) +- pale_green = 0x98FB98, // rgb(152,251,152) +- pale_turquoise = 0xAFEEEE, // rgb(175,238,238) +- pale_violet_red = 0xDB7093, // rgb(219,112,147) +- papaya_whip = 0xFFEFD5, // rgb(255,239,213) +- peach_puff = 0xFFDAB9, // rgb(255,218,185) +- peru = 0xCD853F, // rgb(205,133,63) +- pink = 0xFFC0CB, // rgb(255,192,203) +- plum = 0xDDA0DD, // rgb(221,160,221) +- powder_blue = 0xB0E0E6, // rgb(176,224,230) +- purple = 0x800080, // rgb(128,0,128) +- rebecca_purple = 0x663399, // rgb(102,51,153) +- red = 0xFF0000, // rgb(255,0,0) +- rosy_brown = 0xBC8F8F, // rgb(188,143,143) +- royal_blue = 0x4169E1, // rgb(65,105,225) +- saddle_brown = 0x8B4513, // rgb(139,69,19) +- salmon = 0xFA8072, // rgb(250,128,114) +- sandy_brown = 0xF4A460, // rgb(244,164,96) +- sea_green = 0x2E8B57, // rgb(46,139,87) +- sea_shell = 0xFFF5EE, // rgb(255,245,238) +- sienna = 0xA0522D, // rgb(160,82,45) +- silver = 0xC0C0C0, // rgb(192,192,192) +- sky_blue = 0x87CEEB, // rgb(135,206,235) +- slate_blue = 0x6A5ACD, // rgb(106,90,205) +- slate_gray = 0x708090, // rgb(112,128,144) +- snow = 0xFFFAFA, // rgb(255,250,250) +- spring_green = 0x00FF7F, // rgb(0,255,127) +- steel_blue = 0x4682B4, // rgb(70,130,180) +- tan = 0xD2B48C, // rgb(210,180,140) +- teal = 0x008080, // rgb(0,128,128) +- thistle = 0xD8BFD8, // rgb(216,191,216) +- tomato = 0xFF6347, // rgb(255,99,71) +- turquoise = 0x40E0D0, // rgb(64,224,208) +- violet = 0xEE82EE, // rgb(238,130,238) +- wheat = 0xF5DEB3, // rgb(245,222,179) +- white = 0xFFFFFF, // rgb(255,255,255) +- white_smoke = 0xF5F5F5, // rgb(245,245,245) +- yellow = 0xFFFF00, // rgb(255,255,0) +- yellow_green = 0x9ACD32 // rgb(154,205,50) +-}; // enum class color +- +-enum class terminal_color : uint8_t { +- black = 30, +- red, +- green, +- yellow, +- blue, +- magenta, +- cyan, +- white, +- bright_black = 90, +- bright_red, +- bright_green, +- bright_yellow, +- bright_blue, +- bright_magenta, +- bright_cyan, +- bright_white +-}; +- +-enum class emphasis : uint8_t { +- bold = 1, +- faint = 1 << 1, +- italic = 1 << 2, +- underline = 1 << 3, +- blink = 1 << 4, +- reverse = 1 << 5, +- conceal = 1 << 6, +- strikethrough = 1 << 7, +-}; +- +-// rgb is a struct for red, green and blue colors. +-// Using the name "rgb" makes some editors show the color in a tooltip. +-struct rgb { +- FMT_CONSTEXPR rgb() : r(0), g(0), b(0) {} +- FMT_CONSTEXPR rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {} +- FMT_CONSTEXPR rgb(uint32_t hex) +- : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {} +- FMT_CONSTEXPR rgb(color hex) +- : r((uint32_t(hex) >> 16) & 0xFF), +- g((uint32_t(hex) >> 8) & 0xFF), +- b(uint32_t(hex) & 0xFF) {} +- uint8_t r; +- uint8_t g; +- uint8_t b; +-}; +- +-FMT_BEGIN_DETAIL_NAMESPACE +- +-// color is a struct of either a rgb color or a terminal color. +-struct color_type { +- FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {} +- FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true), +- value{} { +- value.rgb_color = static_cast(rgb_color); +- } +- FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} { +- value.rgb_color = (static_cast(rgb_color.r) << 16) | +- (static_cast(rgb_color.g) << 8) | rgb_color.b; +- } +- FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(), +- value{} { +- value.term_color = static_cast(term_color); +- } +- bool is_rgb; +- union color_union { +- uint8_t term_color; +- uint32_t rgb_color; +- } value; +-}; +- +-FMT_END_DETAIL_NAMESPACE +- +-/** A text style consisting of foreground and background colors and emphasis. */ +-class text_style { +- public: +- FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT +- : set_foreground_color(), +- set_background_color(), +- ems(em) {} +- +- FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) { +- if (!set_foreground_color) { +- set_foreground_color = rhs.set_foreground_color; +- foreground_color = rhs.foreground_color; +- } else if (rhs.set_foreground_color) { +- if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) +- FMT_THROW(format_error("can't OR a terminal color")); +- foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color; +- } +- +- if (!set_background_color) { +- set_background_color = rhs.set_background_color; +- background_color = rhs.background_color; +- } else if (rhs.set_background_color) { +- if (!background_color.is_rgb || !rhs.background_color.is_rgb) +- FMT_THROW(format_error("can't OR a terminal color")); +- background_color.value.rgb_color |= rhs.background_color.value.rgb_color; +- } +- +- ems = static_cast(static_cast(ems) | +- static_cast(rhs.ems)); +- return *this; +- } +- +- friend FMT_CONSTEXPR text_style operator|(text_style lhs, +- const text_style& rhs) { +- return lhs |= rhs; +- } +- +- FMT_DEPRECATED_NONMSVC FMT_CONSTEXPR text_style& operator&=( +- const text_style& rhs) { +- return and_assign(rhs); +- } +- +- FMT_DEPRECATED_NONMSVC friend FMT_CONSTEXPR text_style +- operator&(text_style lhs, const text_style& rhs) { +- return lhs.and_assign(rhs); +- } +- +- FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT { +- return set_foreground_color; +- } +- FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT { +- return set_background_color; +- } +- FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT { +- return static_cast(ems) != 0; +- } +- FMT_CONSTEXPR detail::color_type get_foreground() const FMT_NOEXCEPT { +- FMT_ASSERT(has_foreground(), "no foreground specified for this style"); +- return foreground_color; +- } +- FMT_CONSTEXPR detail::color_type get_background() const FMT_NOEXCEPT { +- FMT_ASSERT(has_background(), "no background specified for this style"); +- return background_color; +- } +- FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT { +- FMT_ASSERT(has_emphasis(), "no emphasis specified for this style"); +- return ems; +- } +- +- private: +- FMT_CONSTEXPR text_style(bool is_foreground, +- detail::color_type text_color) FMT_NOEXCEPT +- : set_foreground_color(), +- set_background_color(), +- ems() { +- if (is_foreground) { +- foreground_color = text_color; +- set_foreground_color = true; +- } else { +- background_color = text_color; +- set_background_color = true; +- } +- } +- +- // DEPRECATED! +- FMT_CONSTEXPR text_style& and_assign(const text_style& rhs) { +- if (!set_foreground_color) { +- set_foreground_color = rhs.set_foreground_color; +- foreground_color = rhs.foreground_color; +- } else if (rhs.set_foreground_color) { +- if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) +- FMT_THROW(format_error("can't AND a terminal color")); +- foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color; +- } +- +- if (!set_background_color) { +- set_background_color = rhs.set_background_color; +- background_color = rhs.background_color; +- } else if (rhs.set_background_color) { +- if (!background_color.is_rgb || !rhs.background_color.is_rgb) +- FMT_THROW(format_error("can't AND a terminal color")); +- background_color.value.rgb_color &= rhs.background_color.value.rgb_color; +- } +- +- ems = static_cast(static_cast(ems) & +- static_cast(rhs.ems)); +- return *this; +- } +- +- friend FMT_CONSTEXPR_DECL text_style fg(detail::color_type foreground) +- FMT_NOEXCEPT; +- +- friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background) +- FMT_NOEXCEPT; +- +- detail::color_type foreground_color; +- detail::color_type background_color; +- bool set_foreground_color; +- bool set_background_color; +- emphasis ems; +-}; +- +-/** Creates a text style from the foreground (text) color. */ +-FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) FMT_NOEXCEPT { +- return text_style(true, foreground); +-} +- +-/** Creates a text style from the background color. */ +-FMT_CONSTEXPR inline text_style bg(detail::color_type background) FMT_NOEXCEPT { +- return text_style(false, background); +-} +- +-FMT_CONSTEXPR inline text_style operator|(emphasis lhs, +- emphasis rhs) FMT_NOEXCEPT { +- return text_style(lhs) | rhs; +-} +- +-FMT_BEGIN_DETAIL_NAMESPACE +- +-template struct ansi_color_escape { +- FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color, +- const char* esc) FMT_NOEXCEPT { +- // If we have a terminal color, we need to output another escape code +- // sequence. +- if (!text_color.is_rgb) { +- bool is_background = esc == string_view("\x1b[48;2;"); +- uint32_t value = text_color.value.term_color; +- // Background ASCII codes are the same as the foreground ones but with +- // 10 more. +- if (is_background) value += 10u; +- +- size_t index = 0; +- buffer[index++] = static_cast('\x1b'); +- buffer[index++] = static_cast('['); +- +- if (value >= 100u) { +- buffer[index++] = static_cast('1'); +- value %= 100u; +- } +- buffer[index++] = static_cast('0' + value / 10u); +- buffer[index++] = static_cast('0' + value % 10u); +- +- buffer[index++] = static_cast('m'); +- buffer[index++] = static_cast('\0'); +- return; +- } +- +- for (int i = 0; i < 7; i++) { +- buffer[i] = static_cast(esc[i]); +- } +- rgb color(text_color.value.rgb_color); +- to_esc(color.r, buffer + 7, ';'); +- to_esc(color.g, buffer + 11, ';'); +- to_esc(color.b, buffer + 15, 'm'); +- buffer[19] = static_cast(0); +- } +- FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT { +- uint8_t em_codes[num_emphases] = {}; +- if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1; +- if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2; +- if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3; +- if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4; +- if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5; +- if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7; +- if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8; +- if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9; +- +- size_t index = 0; +- for (size_t i = 0; i < num_emphases; ++i) { +- if (!em_codes[i]) continue; +- buffer[index++] = static_cast('\x1b'); +- buffer[index++] = static_cast('['); +- buffer[index++] = static_cast('0' + em_codes[i]); +- buffer[index++] = static_cast('m'); +- } +- buffer[index++] = static_cast(0); +- } +- FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; } +- +- FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; } +- FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const FMT_NOEXCEPT { +- return buffer + std::char_traits::length(buffer); +- } +- +- private: +- static constexpr size_t num_emphases = 8; +- Char buffer[7u + 3u * num_emphases + 1u]; +- +- static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out, +- char delimiter) FMT_NOEXCEPT { +- out[0] = static_cast('0' + c / 100); +- out[1] = static_cast('0' + c / 10 % 10); +- out[2] = static_cast('0' + c % 10); +- out[3] = static_cast(delimiter); +- } +- static FMT_CONSTEXPR bool has_emphasis(emphasis em, +- emphasis mask) FMT_NOEXCEPT { +- return static_cast(em) & static_cast(mask); +- } +-}; +- +-template +-FMT_CONSTEXPR ansi_color_escape make_foreground_color( +- detail::color_type foreground) FMT_NOEXCEPT { +- return ansi_color_escape(foreground, "\x1b[38;2;"); +-} +- +-template +-FMT_CONSTEXPR ansi_color_escape make_background_color( +- detail::color_type background) FMT_NOEXCEPT { +- return ansi_color_escape(background, "\x1b[48;2;"); +-} +- +-template +-FMT_CONSTEXPR ansi_color_escape make_emphasis(emphasis em) FMT_NOEXCEPT { +- return ansi_color_escape(em); +-} +- +-template +-inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT { +- std::fputs(chars, stream); +-} +- +-template <> +-inline void fputs(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT { +- std::fputws(chars, stream); +-} +- +-template inline void reset_color(FILE* stream) FMT_NOEXCEPT { +- fputs("\x1b[0m", stream); +-} +- +-template <> inline void reset_color(FILE* stream) FMT_NOEXCEPT { +- fputs(L"\x1b[0m", stream); +-} +- +-template +-inline void reset_color(buffer& buffer) FMT_NOEXCEPT { +- auto reset_color = string_view("\x1b[0m"); +- buffer.append(reset_color.begin(), reset_color.end()); +-} +- +-template +-void vformat_to(buffer& buf, const text_style& ts, +- basic_string_view format_str, +- basic_format_args>> args) { +- bool has_style = false; +- if (ts.has_emphasis()) { +- has_style = true; +- auto emphasis = detail::make_emphasis(ts.get_emphasis()); +- buf.append(emphasis.begin(), emphasis.end()); +- } +- if (ts.has_foreground()) { +- has_style = true; +- auto foreground = detail::make_foreground_color(ts.get_foreground()); +- buf.append(foreground.begin(), foreground.end()); +- } +- if (ts.has_background()) { +- has_style = true; +- auto background = detail::make_background_color(ts.get_background()); +- buf.append(background.begin(), background.end()); +- } +- detail::vformat_to(buf, format_str, args, {}); +- if (has_style) detail::reset_color(buf); +-} +- +-FMT_END_DETAIL_NAMESPACE +- +-template > +-void vprint(std::FILE* f, const text_style& ts, const S& format, +- basic_format_args>> args) { +- basic_memory_buffer buf; +- detail::vformat_to(buf, ts, to_string_view(format), args); +- buf.push_back(Char(0)); +- detail::fputs(buf.data(), f); +-} +- +-/** +- \rst +- Formats a string and prints it to the specified file stream using ANSI +- escape sequences to specify text formatting. +- +- **Example**:: +- +- fmt::print(fmt::emphasis::bold | fg(fmt::color::red), +- "Elapsed time: {0:.2f} seconds", 1.23); +- \endrst +- */ +-template ::value)> +-void print(std::FILE* f, const text_style& ts, const S& format_str, +- const Args&... args) { +- vprint(f, ts, format_str, +- fmt::make_args_checked(format_str, args...)); +-} +- +-/** +- \rst +- Formats a string and prints it to stdout using ANSI escape sequences to +- specify text formatting. +- +- **Example**:: +- +- fmt::print(fmt::emphasis::bold | fg(fmt::color::red), +- "Elapsed time: {0:.2f} seconds", 1.23); +- \endrst +- */ +-template ::value)> +-void print(const text_style& ts, const S& format_str, const Args&... args) { +- return print(stdout, ts, format_str, args...); +-} +- +-template > +-inline std::basic_string vformat( +- const text_style& ts, const S& format_str, +- basic_format_args>> args) { +- basic_memory_buffer buf; +- detail::vformat_to(buf, ts, to_string_view(format_str), args); +- return fmt::to_string(buf); +-} +- +-/** +- \rst +- Formats arguments and returns the result as a string using ANSI +- escape sequences to specify text formatting. +- +- **Example**:: +- +- #include +- std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red), +- "The answer is {}", 42); +- \endrst +-*/ +-template > +-inline std::basic_string format(const text_style& ts, const S& format_str, +- const Args&... args) { +- return fmt::vformat(ts, to_string_view(format_str), +- fmt::make_args_checked(format_str, args...)); +-} +- +-/** +- Formats a string with the given text_style and writes the output to ``out``. +- */ +-template ::value)> +-OutputIt vformat_to( +- OutputIt out, const text_style& ts, basic_string_view format_str, +- basic_format_args>> args) { +- auto&& buf = detail::get_buffer(out); +- detail::vformat_to(buf, ts, format_str, args); +- return detail::get_iterator(buf); +-} +- +-/** +- \rst +- Formats arguments with the given text_style, writes the result to the output +- iterator ``out`` and returns the iterator past the end of the output range. +- +- **Example**:: +- +- std::vector out; +- fmt::format_to(std::back_inserter(out), +- fmt::emphasis::bold | fg(fmt::color::red), "{}", 42); +- \endrst +-*/ +-template >::value&& +- detail::is_string::value> +-inline auto format_to(OutputIt out, const text_style& ts, const S& format_str, +- Args&&... args) -> +- typename std::enable_if::type { +- return vformat_to(out, ts, to_string_view(format_str), +- fmt::make_args_checked(format_str, args...)); +-} +- +-FMT_MODULE_EXPORT_END +-FMT_END_NAMESPACE +- +-#endif // FMT_COLOR_H_ +diff --git a/include/dpp/fmt/compile.h b/include/dpp/fmt/compile.h +deleted file mode 100644 +index 1dba3dd..0000000 +--- a/include/dpp/fmt/compile.h ++++ /dev/null +@@ -1,642 +0,0 @@ +-// Formatting library for C++ - experimental format string compilation +-// +-// Copyright (c) 2012 - present, Victor Zverovich and fmt contributors +-// All rights reserved. +-// +-// For the license information refer to format.h. +- +-#ifndef FMT_COMPILE_H_ +-#define FMT_COMPILE_H_ +- +-#include "format.h" +- +-FMT_BEGIN_NAMESPACE +-namespace detail { +- +-// An output iterator that counts the number of objects written to it and +-// discards them. +-class counting_iterator { +- private: +- size_t count_; +- +- public: +- using iterator_category = std::output_iterator_tag; +- using difference_type = std::ptrdiff_t; +- using pointer = void; +- using reference = void; +- using _Unchecked_type = counting_iterator; // Mark iterator as checked. +- +- struct value_type { +- template void operator=(const T&) {} +- }; +- +- counting_iterator() : count_(0) {} +- +- size_t count() const { return count_; } +- +- counting_iterator& operator++() { +- ++count_; +- return *this; +- } +- counting_iterator operator++(int) { +- auto it = *this; +- ++*this; +- return it; +- } +- +- friend counting_iterator operator+(counting_iterator it, difference_type n) { +- it.count_ += static_cast(n); +- return it; +- } +- +- value_type operator*() const { return {}; } +-}; +- +-template +-inline counting_iterator copy_str(InputIt begin, InputIt end, +- counting_iterator it) { +- return it + (end - begin); +-} +- +-template class truncating_iterator_base { +- protected: +- OutputIt out_; +- size_t limit_; +- size_t count_ = 0; +- +- truncating_iterator_base() : out_(), limit_(0) {} +- +- truncating_iterator_base(OutputIt out, size_t limit) +- : out_(out), limit_(limit) {} +- +- public: +- using iterator_category = std::output_iterator_tag; +- using value_type = typename std::iterator_traits::value_type; +- using difference_type = std::ptrdiff_t; +- using pointer = void; +- using reference = void; +- using _Unchecked_type = +- truncating_iterator_base; // Mark iterator as checked. +- +- OutputIt base() const { return out_; } +- size_t count() const { return count_; } +-}; +- +-// An output iterator that truncates the output and counts the number of objects +-// written to it. +-template ::value_type>::type> +-class truncating_iterator; +- +-template +-class truncating_iterator +- : public truncating_iterator_base { +- mutable typename truncating_iterator_base::value_type blackhole_; +- +- public: +- using value_type = typename truncating_iterator_base::value_type; +- +- truncating_iterator() = default; +- +- truncating_iterator(OutputIt out, size_t limit) +- : truncating_iterator_base(out, limit) {} +- +- truncating_iterator& operator++() { +- if (this->count_++ < this->limit_) ++this->out_; +- return *this; +- } +- +- truncating_iterator operator++(int) { +- auto it = *this; +- ++*this; +- return it; +- } +- +- value_type& operator*() const { +- return this->count_ < this->limit_ ? *this->out_ : blackhole_; +- } +-}; +- +-template +-class truncating_iterator +- : public truncating_iterator_base { +- public: +- truncating_iterator() = default; +- +- truncating_iterator(OutputIt out, size_t limit) +- : truncating_iterator_base(out, limit) {} +- +- template truncating_iterator& operator=(T val) { +- if (this->count_++ < this->limit_) *this->out_++ = val; +- return *this; +- } +- +- truncating_iterator& operator++() { return *this; } +- truncating_iterator& operator++(int) { return *this; } +- truncating_iterator& operator*() { return *this; } +-}; +- +-// A compile-time string which is compiled into fast formatting code. +-class compiled_string {}; +- +-template +-struct is_compiled_string : std::is_base_of {}; +- +-/** +- \rst +- Converts a string literal *s* into a format string that will be parsed at +- compile time and converted into efficient formatting code. Requires C++17 +- ``constexpr if`` compiler support. +- +- **Example**:: +- +- // Converts 42 into std::string using the most efficient method and no +- // runtime format string processing. +- std::string s = fmt::format(FMT_COMPILE("{}"), 42); +- \endrst +- */ +-#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) +-# define FMT_COMPILE(s) \ +- FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit) +-#else +-# define FMT_COMPILE(s) FMT_STRING(s) +-#endif +- +-#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +-template Str> +-struct udl_compiled_string : compiled_string { +- using char_type = Char; +- constexpr operator basic_string_view() const { +- return {Str.data, N - 1}; +- } +-}; +-#endif +- +-template +-const T& first(const T& value, const Tail&...) { +- return value; +-} +- +-#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) +-template struct type_list {}; +- +-// Returns a reference to the argument at index N from [first, rest...]. +-template +-constexpr const auto& get([[maybe_unused]] const T& first, +- [[maybe_unused]] const Args&... rest) { +- static_assert(N < 1 + sizeof...(Args), "index is out of bounds"); +- if constexpr (N == 0) +- return first; +- else +- return detail::get(rest...); +-} +- +-template +-constexpr int get_arg_index_by_name(basic_string_view name, +- type_list) { +- return get_arg_index_by_name(name); +-} +- +-template struct get_type_impl; +- +-template struct get_type_impl> { +- using type = +- remove_cvref_t(std::declval()...))>; +-}; +- +-template +-using get_type = typename get_type_impl::type; +- +-template struct is_compiled_format : std::false_type {}; +- +-template struct text { +- basic_string_view data; +- using char_type = Char; +- +- template +- constexpr OutputIt format(OutputIt out, const Args&...) const { +- return write(out, data); +- } +-}; +- +-template +-struct is_compiled_format> : std::true_type {}; +- +-template +-constexpr text make_text(basic_string_view s, size_t pos, +- size_t size) { +- return {{&s[pos], size}}; +-} +- +-template struct code_unit { +- Char value; +- using char_type = Char; +- +- template +- constexpr OutputIt format(OutputIt out, const Args&...) const { +- return write(out, value); +- } +-}; +- +-// This ensures that the argument type is convertible to `const T&`. +-template +-constexpr const T& get_arg_checked(const Args&... args) { +- const auto& arg = detail::get(args...); +- if constexpr (detail::is_named_arg>()) { +- return arg.value; +- } else { +- return arg; +- } +-} +- +-template +-struct is_compiled_format> : std::true_type {}; +- +-// A replacement field that refers to argument N. +-template struct field { +- using char_type = Char; +- +- template +- constexpr OutputIt format(OutputIt out, const Args&... args) const { +- return write(out, get_arg_checked(args...)); +- } +-}; +- +-template +-struct is_compiled_format> : std::true_type {}; +- +-// A replacement field that refers to argument with name. +-template struct runtime_named_field { +- using char_type = Char; +- basic_string_view name; +- +- template +- constexpr static bool try_format_argument( +- OutputIt& out, +- // [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9 +- [[maybe_unused]] basic_string_view arg_name, const T& arg) { +- if constexpr (is_named_arg::type>::value) { +- if (arg_name == arg.name) { +- out = write(out, arg.value); +- return true; +- } +- } +- return false; +- } +- +- template +- constexpr OutputIt format(OutputIt out, const Args&... args) const { +- bool found = (try_format_argument(out, name, args) || ...); +- if (!found) { +- FMT_THROW(format_error("argument with specified name is not found")); +- } +- return out; +- } +-}; +- +-template +-struct is_compiled_format> : std::true_type {}; +- +-// A replacement field that refers to argument N and has format specifiers. +-template struct spec_field { +- using char_type = Char; +- formatter fmt; +- +- template +- constexpr FMT_INLINE OutputIt format(OutputIt out, +- const Args&... args) const { +- const auto& vargs = +- fmt::make_format_args>(args...); +- basic_format_context ctx(out, vargs); +- return fmt.format(get_arg_checked(args...), ctx); +- } +-}; +- +-template +-struct is_compiled_format> : std::true_type {}; +- +-template struct concat { +- L lhs; +- R rhs; +- using char_type = typename L::char_type; +- +- template +- constexpr OutputIt format(OutputIt out, const Args&... args) const { +- out = lhs.format(out, args...); +- return rhs.format(out, args...); +- } +-}; +- +-template +-struct is_compiled_format> : std::true_type {}; +- +-template +-constexpr concat make_concat(L lhs, R rhs) { +- return {lhs, rhs}; +-} +- +-struct unknown_format {}; +- +-template +-constexpr size_t parse_text(basic_string_view str, size_t pos) { +- for (size_t size = str.size(); pos != size; ++pos) { +- if (str[pos] == '{' || str[pos] == '}') break; +- } +- return pos; +-} +- +-template +-constexpr auto compile_format_string(S format_str); +- +-template +-constexpr auto parse_tail(T head, S format_str) { +- if constexpr (POS != +- basic_string_view(format_str).size()) { +- constexpr auto tail = compile_format_string(format_str); +- if constexpr (std::is_same, +- unknown_format>()) +- return tail; +- else +- return make_concat(head, tail); +- } else { +- return head; +- } +-} +- +-template struct parse_specs_result { +- formatter fmt; +- size_t end; +- int next_arg_id; +-}; +- +-constexpr int manual_indexing_id = -1; +- +-template +-constexpr parse_specs_result parse_specs(basic_string_view str, +- size_t pos, int next_arg_id) { +- str.remove_prefix(pos); +- auto ctx = basic_format_parse_context(str, {}, next_arg_id); +- auto f = formatter(); +- auto end = f.parse(ctx); +- return {f, pos + fmt::detail::to_unsigned(end - str.data()) + 1, +- next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()}; +-} +- +-template struct arg_id_handler { +- arg_ref arg_id; +- +- constexpr int operator()() { +- FMT_ASSERT(false, "handler cannot be used with automatic indexing"); +- return 0; +- } +- constexpr int operator()(int id) { +- arg_id = arg_ref(id); +- return 0; +- } +- constexpr int operator()(basic_string_view id) { +- arg_id = arg_ref(id); +- return 0; +- } +- +- constexpr void on_error(const char* message) { +- FMT_THROW(format_error(message)); +- } +-}; +- +-template struct parse_arg_id_result { +- arg_ref arg_id; +- const Char* arg_id_end; +-}; +- +-template +-constexpr auto parse_arg_id(const Char* begin, const Char* end) { +- auto handler = arg_id_handler{arg_ref{}}; +- auto arg_id_end = parse_arg_id(begin, end, handler); +- return parse_arg_id_result{handler.arg_id, arg_id_end}; +-} +- +-template struct field_type { +- using type = remove_cvref_t; +-}; +- +-template +-struct field_type::value>> { +- using type = remove_cvref_t; +-}; +- +-template +-constexpr auto parse_replacement_field_then_tail(S format_str) { +- using char_type = typename S::char_type; +- constexpr auto str = basic_string_view(format_str); +- constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type(); +- if constexpr (c == '}') { +- return parse_tail( +- field::type, ARG_INDEX>(), +- format_str); +- } else if constexpr (c == ':') { +- constexpr auto result = parse_specs::type>( +- str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID); +- return parse_tail( +- spec_field::type, ARG_INDEX>{ +- result.fmt}, +- format_str); +- } +-} +- +-// Compiles a non-empty format string and returns the compiled representation +-// or unknown_format() on unrecognized input. +-template +-constexpr auto compile_format_string(S format_str) { +- using char_type = typename S::char_type; +- constexpr auto str = basic_string_view(format_str); +- if constexpr (str[POS] == '{') { +- if constexpr (POS + 1 == str.size()) +- FMT_THROW(format_error("unmatched '{' in format string")); +- if constexpr (str[POS + 1] == '{') { +- return parse_tail(make_text(str, POS, 1), format_str); +- } else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') { +- static_assert(ID != manual_indexing_id, +- "cannot switch from manual to automatic argument indexing"); +- constexpr auto next_id = +- ID != manual_indexing_id ? ID + 1 : manual_indexing_id; +- return parse_replacement_field_then_tail, Args, +- POS + 1, ID, next_id>( +- format_str); +- } else { +- constexpr auto arg_id_result = +- parse_arg_id(str.data() + POS + 1, str.data() + str.size()); +- constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data(); +- constexpr char_type c = +- arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type(); +- static_assert(c == '}' || c == ':', "missing '}' in format string"); +- if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) { +- static_assert( +- ID == manual_indexing_id || ID == 0, +- "cannot switch from automatic to manual argument indexing"); +- constexpr auto arg_index = arg_id_result.arg_id.val.index; +- return parse_replacement_field_then_tail, +- Args, arg_id_end_pos, +- arg_index, manual_indexing_id>( +- format_str); +- } else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) { +- constexpr auto arg_index = +- get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{}); +- if constexpr (arg_index != invalid_arg_index) { +- constexpr auto next_id = +- ID != manual_indexing_id ? ID + 1 : manual_indexing_id; +- return parse_replacement_field_then_tail< +- decltype(get_type::value), Args, arg_id_end_pos, +- arg_index, next_id>(format_str); +- } else { +- if constexpr (c == '}') { +- return parse_tail( +- runtime_named_field{arg_id_result.arg_id.val.name}, +- format_str); +- } else if constexpr (c == ':') { +- return unknown_format(); // no type info for specs parsing +- } +- } +- } +- } +- } else if constexpr (str[POS] == '}') { +- if constexpr (POS + 1 == str.size()) +- FMT_THROW(format_error("unmatched '}' in format string")); +- return parse_tail(make_text(str, POS, 1), format_str); +- } else { +- constexpr auto end = parse_text(str, POS + 1); +- if constexpr (end - POS > 1) { +- return parse_tail(make_text(str, POS, end - POS), +- format_str); +- } else { +- return parse_tail(code_unit{str[POS]}, +- format_str); +- } +- } +-} +- +-template ::value)> +-constexpr auto compile(S format_str) { +- constexpr auto str = basic_string_view(format_str); +- if constexpr (str.size() == 0) { +- return detail::make_text(str, 0, 0); +- } else { +- constexpr auto result = +- detail::compile_format_string, 0, 0>( +- format_str); +- return result; +- } +-} +-#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) +-} // namespace detail +- +-FMT_MODULE_EXPORT_BEGIN +- +-#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) +- +-template ::value)> +-FMT_INLINE std::basic_string format(const CompiledFormat& cf, +- const Args&... args) { +- auto s = std::basic_string(); +- cf.format(std::back_inserter(s), args...); +- return s; +-} +- +-template ::value)> +-constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf, +- const Args&... args) { +- return cf.format(out, args...); +-} +- +-template ::value)> +-FMT_INLINE std::basic_string format(const S&, +- Args&&... args) { +- if constexpr (std::is_same::value) { +- constexpr auto str = basic_string_view(S()); +- if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') { +- const auto& first = detail::first(args...); +- if constexpr (detail::is_named_arg< +- remove_cvref_t>::value) { +- return fmt::to_string(first.value); +- } else { +- return fmt::to_string(first); +- } +- } +- } +- constexpr auto compiled = detail::compile(S()); +- if constexpr (std::is_same, +- detail::unknown_format>()) { +- return format(static_cast>(S()), +- std::forward(args)...); +- } else { +- return format(compiled, std::forward(args)...); +- } +-} +- +-template ::value)> +-FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) { +- constexpr auto compiled = detail::compile(S()); +- if constexpr (std::is_same, +- detail::unknown_format>()) { +- return format_to(out, +- static_cast>(S()), +- std::forward(args)...); +- } else { +- return format_to(out, compiled, std::forward(args)...); +- } +-} +-#endif +- +-template ::value)> +-format_to_n_result format_to_n(OutputIt out, size_t n, +- const S& format_str, Args&&... args) { +- auto it = format_to(detail::truncating_iterator(out, n), format_str, +- std::forward(args)...); +- return {it.base(), it.count()}; +-} +- +-template ::value)> +-size_t formatted_size(const S& format_str, const Args&... args) { +- return format_to(detail::counting_iterator(), format_str, args...).count(); +-} +- +-template ::value)> +-void print(std::FILE* f, const S& format_str, const Args&... args) { +- memory_buffer buffer; +- format_to(std::back_inserter(buffer), format_str, args...); +- detail::print(f, {buffer.data(), buffer.size()}); +-} +- +-template ::value)> +-void print(const S& format_str, const Args&... args) { +- print(stdout, format_str, args...); +-} +- +-#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +-inline namespace literals { +-template +-constexpr detail::udl_compiled_string< +- remove_cvref_t, +- sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str> +-operator""_cf() { +- return {}; +-} +-} // namespace literals +-#endif +- +-FMT_MODULE_EXPORT_END +-FMT_END_NAMESPACE +- +-#endif // FMT_COMPILE_H_ +diff --git a/include/dpp/fmt/core.h b/include/dpp/fmt/core.h +deleted file mode 100644 +index 92a7aa1..0000000 +--- a/include/dpp/fmt/core.h ++++ /dev/null +@@ -1,3236 +0,0 @@ +-// Formatting library for C++ - the core API for char/UTF-8 +-// +-// Copyright (c) 2012 - present, Victor Zverovich +-// All rights reserved. +-// +-// For the license information refer to format.h. +- +-#ifndef FMT_CORE_H_ +-#define FMT_CORE_H_ +- +-#include // std::byte +-#include // std::FILE +-#include +-#include +-#include +-#include +-#include +- +-// The fmt library version in the form major * 10000 + minor * 100 + patch. +-#define FMT_VERSION 80101 +- +-#if defined(__clang__) && !defined(__ibmxl__) +-# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) +-#else +-# define FMT_CLANG_VERSION 0 +-#endif +- +-#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && \ +- !defined(__NVCOMPILER) +-# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +-#else +-# define FMT_GCC_VERSION 0 +-#endif +- +-#ifndef FMT_GCC_PRAGMA +-// Workaround _Pragma bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59884. +-# if FMT_GCC_VERSION >= 504 +-# define FMT_GCC_PRAGMA(arg) _Pragma(arg) +-# else +-# define FMT_GCC_PRAGMA(arg) +-# endif +-#endif +- +-#ifdef __ICL +-# define FMT_ICC_VERSION __ICL +-#elif defined(__INTEL_COMPILER) +-# define FMT_ICC_VERSION __INTEL_COMPILER +-#else +-# define FMT_ICC_VERSION 0 +-#endif +- +-#ifdef __NVCC__ +-# define FMT_NVCC __NVCC__ +-#else +-# define FMT_NVCC 0 +-#endif +- +-#ifdef _MSC_VER +-# define FMT_MSC_VER _MSC_VER +-# define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__)) +-#else +-# define FMT_MSC_VER 0 +-# define FMT_MSC_WARNING(...) +-#endif +- +-#ifdef __has_feature +-# define FMT_HAS_FEATURE(x) __has_feature(x) +-#else +-# define FMT_HAS_FEATURE(x) 0 +-#endif +- +-#if defined(__has_include) && \ +- (!defined(__INTELLISENSE__) || FMT_MSC_VER > 1900) && \ +- (!FMT_ICC_VERSION || FMT_ICC_VERSION >= 1600) +-# define FMT_HAS_INCLUDE(x) __has_include(x) +-#else +-# define FMT_HAS_INCLUDE(x) 0 +-#endif +- +-#ifdef __has_cpp_attribute +-# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +-#else +-# define FMT_HAS_CPP_ATTRIBUTE(x) 0 +-#endif +- +-#ifdef _MSVC_LANG +-# define FMT_CPLUSPLUS _MSVC_LANG +-#else +-# define FMT_CPLUSPLUS __cplusplus +-#endif +- +-#define FMT_HAS_CPP14_ATTRIBUTE(attribute) \ +- (FMT_CPLUSPLUS >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute)) +- +-#define FMT_HAS_CPP17_ATTRIBUTE(attribute) \ +- (FMT_CPLUSPLUS >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute)) +- +-// Check if relaxed C++14 constexpr is supported. +-// GCC doesn't allow throw in constexpr until version 6 (bug 67371). +-#ifndef FMT_USE_CONSTEXPR +-# define FMT_USE_CONSTEXPR \ +- (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1912 || \ +- (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) && \ +- !FMT_NVCC && !FMT_ICC_VERSION +-#endif +-#if FMT_USE_CONSTEXPR +-# define FMT_CONSTEXPR constexpr +-# define FMT_CONSTEXPR_DECL constexpr +-#else +-# define FMT_CONSTEXPR +-# define FMT_CONSTEXPR_DECL +-#endif +- +-#if ((__cplusplus >= 202002L) && \ +- (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE > 9)) || \ +- (__cplusplus >= 201709L && FMT_GCC_VERSION >= 1002) +-# define FMT_CONSTEXPR20 constexpr +-#else +-# define FMT_CONSTEXPR20 +-#endif +- +-// Check if constexpr std::char_traits<>::compare,length is supported. +-#if defined(__GLIBCXX__) +-# if __cplusplus >= 201703L && defined(_GLIBCXX_RELEASE) && \ +- _GLIBCXX_RELEASE >= 7 // GCC 7+ libstdc++ has _GLIBCXX_RELEASE. +-# define FMT_CONSTEXPR_CHAR_TRAITS constexpr +-# endif +-#elif defined(_LIBCPP_VERSION) && __cplusplus >= 201703L && \ +- _LIBCPP_VERSION >= 4000 +-# define FMT_CONSTEXPR_CHAR_TRAITS constexpr +-#elif FMT_MSC_VER >= 1914 && _MSVC_LANG >= 201703L +-# define FMT_CONSTEXPR_CHAR_TRAITS constexpr +-#endif +-#ifndef FMT_CONSTEXPR_CHAR_TRAITS +-# define FMT_CONSTEXPR_CHAR_TRAITS +-#endif +- +-// Check if exceptions are disabled. +-#ifndef FMT_EXCEPTIONS +-# if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \ +- FMT_MSC_VER && !_HAS_EXCEPTIONS +-# define FMT_EXCEPTIONS 0 +-# else +-# define FMT_EXCEPTIONS 1 +-# endif +-#endif +- +-// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature). +-#ifndef FMT_USE_NOEXCEPT +-# define FMT_USE_NOEXCEPT 0 +-#endif +- +-#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ +- FMT_GCC_VERSION >= 408 || FMT_MSC_VER >= 1900 +-# define FMT_DETECTED_NOEXCEPT noexcept +-# define FMT_HAS_CXX11_NOEXCEPT 1 +-#else +-# define FMT_DETECTED_NOEXCEPT throw() +-# define FMT_HAS_CXX11_NOEXCEPT 0 +-#endif +- +-#ifndef FMT_NOEXCEPT +-# if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT +-# define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT +-# else +-# define FMT_NOEXCEPT +-# endif +-#endif +- +-// [[noreturn]] is disabled on MSVC and NVCC because of bogus unreachable code +-// warnings. +-#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER && \ +- !FMT_NVCC +-# define FMT_NORETURN [[noreturn]] +-#else +-# define FMT_NORETURN +-#endif +- +-#if __cplusplus == 201103L || __cplusplus == 201402L +-# if defined(__INTEL_COMPILER) || defined(__PGI) +-# define FMT_FALLTHROUGH +-# elif defined(__clang__) +-# define FMT_FALLTHROUGH [[clang::fallthrough]] +-# elif FMT_GCC_VERSION >= 700 && \ +- (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520) +-# define FMT_FALLTHROUGH [[gnu::fallthrough]] +-# else +-# define FMT_FALLTHROUGH +-# endif +-#elif FMT_HAS_CPP17_ATTRIBUTE(fallthrough) +-# define FMT_FALLTHROUGH [[fallthrough]] +-#else +-# define FMT_FALLTHROUGH +-#endif +- +-#ifndef FMT_NODISCARD +-# if FMT_HAS_CPP17_ATTRIBUTE(nodiscard) +-# define FMT_NODISCARD [[nodiscard]] +-# else +-# define FMT_NODISCARD +-# endif +-#endif +- +-#ifndef FMT_USE_FLOAT +-# define FMT_USE_FLOAT 1 +-#endif +-#ifndef FMT_USE_DOUBLE +-# define FMT_USE_DOUBLE 1 +-#endif +-#ifndef FMT_USE_LONG_DOUBLE +-# define FMT_USE_LONG_DOUBLE 1 +-#endif +- +-#ifndef FMT_INLINE +-# if FMT_GCC_VERSION || FMT_CLANG_VERSION +-# define FMT_INLINE inline __attribute__((always_inline)) +-# else +-# define FMT_INLINE inline +-# endif +-#endif +- +-#ifndef FMT_DEPRECATED +-# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900 +-# define FMT_DEPRECATED [[deprecated]] +-# else +-# if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__) +-# define FMT_DEPRECATED __attribute__((deprecated)) +-# elif FMT_MSC_VER +-# define FMT_DEPRECATED __declspec(deprecated) +-# else +-# define FMT_DEPRECATED /* deprecated */ +-# endif +-# endif +-#endif +- +-#ifndef FMT_BEGIN_NAMESPACE +-# define FMT_BEGIN_NAMESPACE \ +- namespace fmt { \ +- inline namespace v8 { +-# define FMT_END_NAMESPACE \ +- } \ +- } +-#endif +- +-#ifndef FMT_MODULE_EXPORT +-# define FMT_MODULE_EXPORT +-# define FMT_MODULE_EXPORT_BEGIN +-# define FMT_MODULE_EXPORT_END +-# define FMT_BEGIN_DETAIL_NAMESPACE namespace detail { +-# define FMT_END_DETAIL_NAMESPACE } +-#endif +- +-#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) +-# define FMT_CLASS_API FMT_MSC_WARNING(suppress : 4275) +-# ifdef FMT_EXPORT +-# define FMT_API __declspec(dllexport) +-# elif defined(FMT_SHARED) +-# define FMT_API __declspec(dllimport) +-# endif +-#else +-# define FMT_CLASS_API +-# if defined(FMT_EXPORT) || defined(FMT_SHARED) +-# if defined(__GNUC__) || defined(__clang__) +-# define FMT_API __attribute__((visibility("default"))) +-# endif +-# endif +-#endif +-#ifndef FMT_API +-# define FMT_API +-#endif +- +-// libc++ supports string_view in pre-c++17. +-#if (FMT_HAS_INCLUDE() && \ +- (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \ +- (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) +-# include +-# define FMT_USE_STRING_VIEW +-#elif FMT_HAS_INCLUDE("experimental/string_view") && __cplusplus >= 201402L +-# include +-# define FMT_USE_EXPERIMENTAL_STRING_VIEW +-#endif +- +-#ifndef FMT_UNICODE +-# define FMT_UNICODE !FMT_MSC_VER +-#endif +- +-#ifndef FMT_CONSTEVAL +-# if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \ +- __cplusplus > 201703L && !defined(__apple_build_version__)) || \ +- (defined(__cpp_consteval) && \ +- (!FMT_MSC_VER || _MSC_FULL_VER >= 193030704)) +-// consteval is broken in MSVC before VS2022 and Apple clang 13. +-# define FMT_CONSTEVAL consteval +-# define FMT_HAS_CONSTEVAL +-# else +-# define FMT_CONSTEVAL +-# endif +-#endif +- +-#ifndef FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +-# if defined(__cpp_nontype_template_args) && \ +- ((FMT_GCC_VERSION >= 903 && __cplusplus >= 201709L) || \ +- __cpp_nontype_template_args >= 201911L) +-# define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 1 +-# else +-# define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 0 +-# endif +-#endif +- +-// Enable minimal optimizations for more compact code in debug mode. +-FMT_GCC_PRAGMA("GCC push_options") +-#ifndef __OPTIMIZE__ +-FMT_GCC_PRAGMA("GCC optimize(\"Og\")") +-#endif +- +-FMT_BEGIN_NAMESPACE +-FMT_MODULE_EXPORT_BEGIN +- +-// Implementations of enable_if_t and other metafunctions for older systems. +-template +-using enable_if_t = typename std::enable_if::type; +-template +-using conditional_t = typename std::conditional::type; +-template using bool_constant = std::integral_constant; +-template +-using remove_reference_t = typename std::remove_reference::type; +-template +-using remove_const_t = typename std::remove_const::type; +-template +-using remove_cvref_t = typename std::remove_cv>::type; +-template struct type_identity { using type = T; }; +-template using type_identity_t = typename type_identity::type; +- +-struct monostate { +- constexpr monostate() {} +-}; +- +-// An enable_if helper to be used in template parameters which results in much +-// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed +-// to workaround a bug in MSVC 2019 (see #1140 and #1186). +-#ifdef FMT_DOC +-# define FMT_ENABLE_IF(...) +-#else +-# define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0 +-#endif +- +-FMT_BEGIN_DETAIL_NAMESPACE +- +-// Suppress "unused variable" warnings with the method described in +-// https://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/. +-// (void)var does not work on many Intel compilers. +-template FMT_CONSTEXPR void ignore_unused(const T&...) {} +- +-constexpr FMT_INLINE auto is_constant_evaluated(bool default_value = false) +- FMT_NOEXCEPT -> bool { +-#ifdef __cpp_lib_is_constant_evaluated +- ignore_unused(default_value); +- return std::is_constant_evaluated(); +-#else +- return default_value; +-#endif +-} +- +-// A function to suppress "conditional expression is constant" warnings. +-template constexpr FMT_INLINE auto const_check(T value) -> T { +- return value; +-} +- +-FMT_NORETURN FMT_API void assert_fail(const char* file, int line, +- const char* message); +- +-#ifndef FMT_ASSERT +-# ifdef NDEBUG +-// FMT_ASSERT is not empty to avoid -Werror=empty-body. +-# define FMT_ASSERT(condition, message) \ +- ::fmt::detail::ignore_unused((condition), (message)) +-# else +-# define FMT_ASSERT(condition, message) \ +- ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \ +- ? (void)0 \ +- : ::fmt::detail::assert_fail(__FILE__, __LINE__, (message))) +-# endif +-#endif +- +-#ifdef __cpp_lib_byte +-using byte = std::byte; +-#else +-enum class byte : unsigned char {}; +-#endif +- +-#if defined(FMT_USE_STRING_VIEW) +-template using std_string_view = std::basic_string_view; +-#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW) +-template +-using std_string_view = std::experimental::basic_string_view; +-#else +-template struct std_string_view {}; +-#endif +- +-#ifdef FMT_USE_INT128 +-// Do nothing. +-#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && \ +- !(FMT_CLANG_VERSION && FMT_MSC_VER) +-# define FMT_USE_INT128 1 +-using int128_t = __int128_t; +-using uint128_t = __uint128_t; +-template inline auto convert_for_visit(T value) -> T { +- return value; +-} +-#else +-# define FMT_USE_INT128 0 +-#endif +-#if !FMT_USE_INT128 +-enum class int128_t {}; +-enum class uint128_t {}; +-// Reduce template instantiations. +-template inline auto convert_for_visit(T) -> monostate { +- return {}; +-} +-#endif +- +-// Casts a nonnegative integer to unsigned. +-template +-FMT_CONSTEXPR auto to_unsigned(Int value) -> +- typename std::make_unsigned::type { +- FMT_ASSERT(value >= 0, "negative value"); +- return static_cast::type>(value); +-} +- +-FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char micro[] = "\u00B5"; +- +-constexpr auto is_utf8() -> bool { +- // Avoid buggy sign extensions in MSVC's constant evaluation mode. +- // https://developercommunity.visualstudio.com/t/C-difference-in-behavior-for-unsigned/1233612 +- using uchar = unsigned char; +- return FMT_UNICODE || (sizeof(micro) == 3 && uchar(micro[0]) == 0xC2 && +- uchar(micro[1]) == 0xB5); +-} +-FMT_END_DETAIL_NAMESPACE +- +-/** +- An implementation of ``std::basic_string_view`` for pre-C++17. It provides a +- subset of the API. ``fmt::basic_string_view`` is used for format strings even +- if ``std::string_view`` is available to prevent issues when a library is +- compiled with a different ``-std`` option than the client code (which is not +- recommended). +- */ +-template class basic_string_view { +- private: +- const Char* data_; +- size_t size_; +- +- public: +- using value_type = Char; +- using iterator = const Char*; +- +- constexpr basic_string_view() FMT_NOEXCEPT : data_(nullptr), size_(0) {} +- +- /** Constructs a string reference object from a C string and a size. */ +- constexpr basic_string_view(const Char* s, size_t count) FMT_NOEXCEPT +- : data_(s), +- size_(count) {} +- +- /** +- \rst +- Constructs a string reference object from a C string computing +- the size with ``std::char_traits::length``. +- \endrst +- */ +- FMT_CONSTEXPR_CHAR_TRAITS +- FMT_INLINE +- basic_string_view(const Char* s) +- : data_(s), +- size_(detail::const_check(std::is_same::value && +- !detail::is_constant_evaluated(true)) +- ? std::strlen(reinterpret_cast(s)) +- : std::char_traits::length(s)) {} +- +- /** Constructs a string reference from a ``std::basic_string`` object. */ +- template +- FMT_CONSTEXPR basic_string_view( +- const std::basic_string& s) FMT_NOEXCEPT +- : data_(s.data()), +- size_(s.size()) {} +- +- template >::value)> +- FMT_CONSTEXPR basic_string_view(S s) FMT_NOEXCEPT : data_(s.data()), +- size_(s.size()) {} +- +- /** Returns a pointer to the string data. */ +- constexpr auto data() const FMT_NOEXCEPT -> const Char* { return data_; } +- +- /** Returns the string size. */ +- constexpr auto size() const FMT_NOEXCEPT -> size_t { return size_; } +- +- constexpr auto begin() const FMT_NOEXCEPT -> iterator { return data_; } +- constexpr auto end() const FMT_NOEXCEPT -> iterator { return data_ + size_; } +- +- constexpr auto operator[](size_t pos) const FMT_NOEXCEPT -> const Char& { +- return data_[pos]; +- } +- +- FMT_CONSTEXPR void remove_prefix(size_t n) FMT_NOEXCEPT { +- data_ += n; +- size_ -= n; +- } +- +- // Lexicographically compare this string reference to other. +- FMT_CONSTEXPR_CHAR_TRAITS auto compare(basic_string_view other) const -> int { +- size_t str_size = size_ < other.size_ ? size_ : other.size_; +- int result = std::char_traits::compare(data_, other.data_, str_size); +- if (result == 0) +- result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); +- return result; +- } +- +- FMT_CONSTEXPR_CHAR_TRAITS friend auto operator==(basic_string_view lhs, +- basic_string_view rhs) +- -> bool { +- return lhs.compare(rhs) == 0; +- } +- friend auto operator!=(basic_string_view lhs, basic_string_view rhs) -> bool { +- return lhs.compare(rhs) != 0; +- } +- friend auto operator<(basic_string_view lhs, basic_string_view rhs) -> bool { +- return lhs.compare(rhs) < 0; +- } +- friend auto operator<=(basic_string_view lhs, basic_string_view rhs) -> bool { +- return lhs.compare(rhs) <= 0; +- } +- friend auto operator>(basic_string_view lhs, basic_string_view rhs) -> bool { +- return lhs.compare(rhs) > 0; +- } +- friend auto operator>=(basic_string_view lhs, basic_string_view rhs) -> bool { +- return lhs.compare(rhs) >= 0; +- } +-}; +- +-using string_view = basic_string_view; +- +-/** Specifies if ``T`` is a character type. Can be specialized by users. */ +-template struct is_char : std::false_type {}; +-template <> struct is_char : std::true_type {}; +- +-// Returns a string view of `s`. +-template ::value)> +-FMT_INLINE auto to_string_view(const Char* s) -> basic_string_view { +- return s; +-} +-template +-inline auto to_string_view(const std::basic_string& s) +- -> basic_string_view { +- return s; +-} +-template +-constexpr auto to_string_view(basic_string_view s) +- -> basic_string_view { +- return s; +-} +-template >::value)> +-inline auto to_string_view(detail::std_string_view s) +- -> basic_string_view { +- return s; +-} +- +-// A base class for compile-time strings. It is defined in the fmt namespace to +-// make formatting functions visible via ADL, e.g. format(FMT_STRING("{}"), 42). +-struct compile_string {}; +- +-template +-struct is_compile_string : std::is_base_of {}; +- +-template ::value)> +-constexpr auto to_string_view(const S& s) +- -> basic_string_view { +- return basic_string_view(s); +-} +- +-FMT_BEGIN_DETAIL_NAMESPACE +- +-void to_string_view(...); +-using fmt::to_string_view; +- +-// Specifies whether S is a string type convertible to fmt::basic_string_view. +-// It should be a constexpr function but MSVC 2017 fails to compile it in +-// enable_if and MSVC 2015 fails to compile it as an alias template. +-template +-struct is_string : std::is_class()))> { +-}; +- +-template struct char_t_impl {}; +-template struct char_t_impl::value>> { +- using result = decltype(to_string_view(std::declval())); +- using type = typename result::value_type; +-}; +- +-// Reports a compile-time error if S is not a valid format string. +-template ::value)> +-FMT_INLINE void check_format_string(const S&) { +-#ifdef FMT_ENFORCE_COMPILE_STRING +- static_assert(is_compile_string::value, +- "FMT_ENFORCE_COMPILE_STRING requires all format strings to use " +- "FMT_STRING."); +-#endif +-} +-template ::value)> +-void check_format_string(S); +- +-FMT_NORETURN FMT_API void throw_format_error(const char* message); +- +-struct error_handler { +- constexpr error_handler() = default; +- constexpr error_handler(const error_handler&) = default; +- +- // This function is intentionally not constexpr to give a compile-time error. +- FMT_NORETURN FMT_API void on_error(const char* message); +-}; +-FMT_END_DETAIL_NAMESPACE +- +-/** String's character type. */ +-template using char_t = typename detail::char_t_impl::type; +- +-/** +- \rst +- Parsing context consisting of a format string range being parsed and an +- argument counter for automatic indexing. +- You can use the ``format_parse_context`` type alias for ``char`` instead. +- \endrst +- */ +-template +-class basic_format_parse_context : private ErrorHandler { +- private: +- basic_string_view format_str_; +- int next_arg_id_; +- +- public: +- using char_type = Char; +- using iterator = typename basic_string_view::iterator; +- +- explicit constexpr basic_format_parse_context( +- basic_string_view format_str, ErrorHandler eh = {}, +- int next_arg_id = 0) +- : ErrorHandler(eh), format_str_(format_str), next_arg_id_(next_arg_id) {} +- +- /** +- Returns an iterator to the beginning of the format string range being +- parsed. +- */ +- constexpr auto begin() const FMT_NOEXCEPT -> iterator { +- return format_str_.begin(); +- } +- +- /** +- Returns an iterator past the end of the format string range being parsed. +- */ +- constexpr auto end() const FMT_NOEXCEPT -> iterator { +- return format_str_.end(); +- } +- +- /** Advances the begin iterator to ``it``. */ +- FMT_CONSTEXPR void advance_to(iterator it) { +- format_str_.remove_prefix(detail::to_unsigned(it - begin())); +- } +- +- /** +- Reports an error if using the manual argument indexing; otherwise returns +- the next argument index and switches to the automatic indexing. +- */ +- FMT_CONSTEXPR auto next_arg_id() -> int { +- // Don't check if the argument id is valid to avoid overhead and because it +- // will be checked during formatting anyway. +- if (next_arg_id_ >= 0) return next_arg_id_++; +- on_error("cannot switch from manual to automatic argument indexing"); +- return 0; +- } +- +- /** +- Reports an error if using the automatic argument indexing; otherwise +- switches to the manual indexing. +- */ +- FMT_CONSTEXPR void check_arg_id(int) { +- if (next_arg_id_ > 0) +- on_error("cannot switch from automatic to manual argument indexing"); +- else +- next_arg_id_ = -1; +- } +- +- FMT_CONSTEXPR void check_arg_id(basic_string_view) {} +- +- FMT_CONSTEXPR void on_error(const char* message) { +- ErrorHandler::on_error(message); +- } +- +- constexpr auto error_handler() const -> ErrorHandler { return *this; } +-}; +- +-using format_parse_context = basic_format_parse_context; +- +-template class basic_format_arg; +-template class basic_format_args; +-template class dynamic_format_arg_store; +- +-// A formatter for objects of type T. +-template +-struct formatter { +- // A deleted default constructor indicates a disabled formatter. +- formatter() = delete; +-}; +- +-// Specifies if T has an enabled formatter specialization. A type can be +-// formattable even if it doesn't have a formatter e.g. via a conversion. +-template +-using has_formatter = +- std::is_constructible>; +- +-// Checks whether T is a container with contiguous storage. +-template struct is_contiguous : std::false_type {}; +-template +-struct is_contiguous> : std::true_type {}; +- +-class appender; +- +-FMT_BEGIN_DETAIL_NAMESPACE +- +-template +-constexpr auto has_const_formatter_impl(T*) +- -> decltype(typename Context::template formatter_type().format( +- std::declval(), std::declval()), +- true) { +- return true; +-} +-template +-constexpr auto has_const_formatter_impl(...) -> bool { +- return false; +-} +-template +-constexpr auto has_const_formatter() -> bool { +- return has_const_formatter_impl(static_cast(nullptr)); +-} +- +-// Extracts a reference to the container from back_insert_iterator. +-template +-inline auto get_container(std::back_insert_iterator it) +- -> Container& { +- using bi_iterator = std::back_insert_iterator; +- struct accessor : bi_iterator { +- accessor(bi_iterator iter) : bi_iterator(iter) {} +- using bi_iterator::container; +- }; +- return *accessor(it).container; +-} +- +-template +-FMT_CONSTEXPR auto copy_str(InputIt begin, InputIt end, OutputIt out) +- -> OutputIt { +- while (begin != end) *out++ = static_cast(*begin++); +- return out; +-} +- +-template , U>::value&& is_char::value)> +-FMT_CONSTEXPR auto copy_str(T* begin, T* end, U* out) -> U* { +- if (is_constant_evaluated()) return copy_str(begin, end, out); +- auto size = to_unsigned(end - begin); +- memcpy(out, begin, size * sizeof(U)); +- return out + size; +-} +- +-/** +- \rst +- A contiguous memory buffer with an optional growing ability. It is an internal +- class and shouldn't be used directly, only via `~fmt::basic_memory_buffer`. +- \endrst +- */ +-template class buffer { +- private: +- T* ptr_; +- size_t size_; +- size_t capacity_; +- +- protected: +- // Don't initialize ptr_ since it is not accessed to save a few cycles. +- FMT_MSC_WARNING(suppress : 26495) +- buffer(size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {} +- +- FMT_CONSTEXPR20 buffer(T* p = nullptr, size_t sz = 0, +- size_t cap = 0) FMT_NOEXCEPT : ptr_(p), +- size_(sz), +- capacity_(cap) {} +- +- FMT_CONSTEXPR20 ~buffer() = default; +- buffer(buffer&&) = default; +- +- /** Sets the buffer data and capacity. */ +- FMT_CONSTEXPR void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT { +- ptr_ = buf_data; +- capacity_ = buf_capacity; +- } +- +- /** Increases the buffer capacity to hold at least *capacity* elements. */ +- virtual FMT_CONSTEXPR20 void grow(size_t capacity) = 0; +- +- public: +- using value_type = T; +- using const_reference = const T&; +- +- buffer(const buffer&) = delete; +- void operator=(const buffer&) = delete; +- +- auto begin() FMT_NOEXCEPT -> T* { return ptr_; } +- auto end() FMT_NOEXCEPT -> T* { return ptr_ + size_; } +- +- auto begin() const FMT_NOEXCEPT -> const T* { return ptr_; } +- auto end() const FMT_NOEXCEPT -> const T* { return ptr_ + size_; } +- +- /** Returns the size of this buffer. */ +- constexpr auto size() const FMT_NOEXCEPT -> size_t { return size_; } +- +- /** Returns the capacity of this buffer. */ +- constexpr auto capacity() const FMT_NOEXCEPT -> size_t { return capacity_; } +- +- /** Returns a pointer to the buffer data. */ +- FMT_CONSTEXPR auto data() FMT_NOEXCEPT -> T* { return ptr_; } +- +- /** Returns a pointer to the buffer data. */ +- FMT_CONSTEXPR auto data() const FMT_NOEXCEPT -> const T* { return ptr_; } +- +- /** Clears this buffer. */ +- void clear() { size_ = 0; } +- +- // Tries resizing the buffer to contain *count* elements. If T is a POD type +- // the new elements may not be initialized. +- FMT_CONSTEXPR20 void try_resize(size_t count) { +- try_reserve(count); +- size_ = count <= capacity_ ? count : capacity_; +- } +- +- // Tries increasing the buffer capacity to *new_capacity*. It can increase the +- // capacity by a smaller amount than requested but guarantees there is space +- // for at least one additional element either by increasing the capacity or by +- // flushing the buffer if it is full. +- FMT_CONSTEXPR20 void try_reserve(size_t new_capacity) { +- if (new_capacity > capacity_) grow(new_capacity); +- } +- +- FMT_CONSTEXPR20 void push_back(const T& value) { +- try_reserve(size_ + 1); +- ptr_[size_++] = value; +- } +- +- /** Appends data to the end of the buffer. */ +- template void append(const U* begin, const U* end); +- +- template FMT_CONSTEXPR auto operator[](I index) -> T& { +- return ptr_[index]; +- } +- template +- FMT_CONSTEXPR auto operator[](I index) const -> const T& { +- return ptr_[index]; +- } +-}; +- +-struct buffer_traits { +- explicit buffer_traits(size_t) {} +- auto count() const -> size_t { return 0; } +- auto limit(size_t size) -> size_t { return size; } +-}; +- +-class fixed_buffer_traits { +- private: +- size_t count_ = 0; +- size_t limit_; +- +- public: +- explicit fixed_buffer_traits(size_t limit) : limit_(limit) {} +- auto count() const -> size_t { return count_; } +- auto limit(size_t size) -> size_t { +- size_t n = limit_ > count_ ? limit_ - count_ : 0; +- count_ += size; +- return size < n ? size : n; +- } +-}; +- +-// A buffer that writes to an output iterator when flushed. +-template +-class iterator_buffer final : public Traits, public buffer { +- private: +- OutputIt out_; +- enum { buffer_size = 256 }; +- T data_[buffer_size]; +- +- protected: +- FMT_CONSTEXPR20 void grow(size_t) override { +- if (this->size() == buffer_size) flush(); +- } +- +- void flush() { +- auto size = this->size(); +- this->clear(); +- out_ = copy_str(data_, data_ + this->limit(size), out_); +- } +- +- public: +- explicit iterator_buffer(OutputIt out, size_t n = buffer_size) +- : Traits(n), buffer(data_, 0, buffer_size), out_(out) {} +- iterator_buffer(iterator_buffer&& other) +- : Traits(other), buffer(data_, 0, buffer_size), out_(other.out_) {} +- ~iterator_buffer() { flush(); } +- +- auto out() -> OutputIt { +- flush(); +- return out_; +- } +- auto count() const -> size_t { return Traits::count() + this->size(); } +-}; +- +-template +-class iterator_buffer final +- : public fixed_buffer_traits, +- public buffer { +- private: +- T* out_; +- enum { buffer_size = 256 }; +- T data_[buffer_size]; +- +- protected: +- FMT_CONSTEXPR20 void grow(size_t) override { +- if (this->size() == this->capacity()) flush(); +- } +- +- void flush() { +- size_t n = this->limit(this->size()); +- if (this->data() == out_) { +- out_ += n; +- this->set(data_, buffer_size); +- } +- this->clear(); +- } +- +- public: +- explicit iterator_buffer(T* out, size_t n = buffer_size) +- : fixed_buffer_traits(n), buffer(out, 0, n), out_(out) {} +- iterator_buffer(iterator_buffer&& other) +- : fixed_buffer_traits(other), +- buffer(std::move(other)), +- out_(other.out_) { +- if (this->data() != out_) { +- this->set(data_, buffer_size); +- this->clear(); +- } +- } +- ~iterator_buffer() { flush(); } +- +- auto out() -> T* { +- flush(); +- return out_; +- } +- auto count() const -> size_t { +- return fixed_buffer_traits::count() + this->size(); +- } +-}; +- +-template class iterator_buffer final : public buffer { +- protected: +- FMT_CONSTEXPR20 void grow(size_t) override {} +- +- public: +- explicit iterator_buffer(T* out, size_t = 0) : buffer(out, 0, ~size_t()) {} +- +- auto out() -> T* { return &*this->end(); } +-}; +- +-// A buffer that writes to a container with the contiguous storage. +-template +-class iterator_buffer, +- enable_if_t::value, +- typename Container::value_type>> +- final : public buffer { +- private: +- Container& container_; +- +- protected: +- FMT_CONSTEXPR20 void grow(size_t capacity) override { +- container_.resize(capacity); +- this->set(&container_[0], capacity); +- } +- +- public: +- explicit iterator_buffer(Container& c) +- : buffer(c.size()), container_(c) {} +- explicit iterator_buffer(std::back_insert_iterator out, size_t = 0) +- : iterator_buffer(get_container(out)) {} +- auto out() -> std::back_insert_iterator { +- return std::back_inserter(container_); +- } +-}; +- +-// A buffer that counts the number of code units written discarding the output. +-template class counting_buffer final : public buffer { +- private: +- enum { buffer_size = 256 }; +- T data_[buffer_size]; +- size_t count_ = 0; +- +- protected: +- FMT_CONSTEXPR20 void grow(size_t) override { +- if (this->size() != buffer_size) return; +- count_ += this->size(); +- this->clear(); +- } +- +- public: +- counting_buffer() : buffer(data_, 0, buffer_size) {} +- +- auto count() -> size_t { return count_ + this->size(); } +-}; +- +-template +-using buffer_appender = conditional_t::value, appender, +- std::back_insert_iterator>>; +- +-// Maps an output iterator to a buffer. +-template +-auto get_buffer(OutputIt out) -> iterator_buffer { +- return iterator_buffer(out); +-} +- +-template +-auto get_iterator(Buffer& buf) -> decltype(buf.out()) { +- return buf.out(); +-} +-template auto get_iterator(buffer& buf) -> buffer_appender { +- return buffer_appender(buf); +-} +- +-template +-struct fallback_formatter { +- fallback_formatter() = delete; +-}; +- +-// Specifies if T has an enabled fallback_formatter specialization. +-template +-using has_fallback_formatter = +- std::is_constructible>; +- +-struct view {}; +- +-template struct named_arg : view { +- const Char* name; +- const T& value; +- named_arg(const Char* n, const T& v) : name(n), value(v) {} +-}; +- +-template struct named_arg_info { +- const Char* name; +- int id; +-}; +- +-template +-struct arg_data { +- // args_[0].named_args points to named_args_ to avoid bloating format_args. +- // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. +- T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : +1)]; +- named_arg_info named_args_[NUM_NAMED_ARGS]; +- +- template +- arg_data(const U&... init) : args_{T(named_args_, NUM_NAMED_ARGS), init...} {} +- arg_data(const arg_data& other) = delete; +- auto args() const -> const T* { return args_ + 1; } +- auto named_args() -> named_arg_info* { return named_args_; } +-}; +- +-template +-struct arg_data { +- // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. +- T args_[NUM_ARGS != 0 ? NUM_ARGS : +1]; +- +- template +- FMT_CONSTEXPR FMT_INLINE arg_data(const U&... init) : args_{init...} {} +- FMT_CONSTEXPR FMT_INLINE auto args() const -> const T* { return args_; } +- FMT_CONSTEXPR FMT_INLINE auto named_args() -> std::nullptr_t { +- return nullptr; +- } +-}; +- +-template +-inline void init_named_args(named_arg_info*, int, int) {} +- +-template struct is_named_arg : std::false_type {}; +-template struct is_statically_named_arg : std::false_type {}; +- +-template +-struct is_named_arg> : std::true_type {}; +- +-template ::value)> +-void init_named_args(named_arg_info* named_args, int arg_count, +- int named_arg_count, const T&, const Tail&... args) { +- init_named_args(named_args, arg_count + 1, named_arg_count, args...); +-} +- +-template ::value)> +-void init_named_args(named_arg_info* named_args, int arg_count, +- int named_arg_count, const T& arg, const Tail&... args) { +- named_args[named_arg_count++] = {arg.name, arg_count}; +- init_named_args(named_args, arg_count + 1, named_arg_count, args...); +-} +- +-template +-FMT_CONSTEXPR FMT_INLINE void init_named_args(std::nullptr_t, int, int, +- const Args&...) {} +- +-template constexpr auto count() -> size_t { return B ? 1 : 0; } +-template constexpr auto count() -> size_t { +- return (B1 ? 1 : 0) + count(); +-} +- +-template constexpr auto count_named_args() -> size_t { +- return count::value...>(); +-} +- +-template +-constexpr auto count_statically_named_args() -> size_t { +- return count::value...>(); +-} +- +-enum class type { +- none_type, +- // Integer types should go first, +- int_type, +- uint_type, +- long_long_type, +- ulong_long_type, +- int128_type, +- uint128_type, +- bool_type, +- char_type, +- last_integer_type = char_type, +- // followed by floating-point types. +- float_type, +- double_type, +- long_double_type, +- last_numeric_type = long_double_type, +- cstring_type, +- string_type, +- pointer_type, +- custom_type +-}; +- +-// Maps core type T to the corresponding type enum constant. +-template +-struct type_constant : std::integral_constant {}; +- +-#define FMT_TYPE_CONSTANT(Type, constant) \ +- template \ +- struct type_constant \ +- : std::integral_constant {} +- +-FMT_TYPE_CONSTANT(int, int_type); +-FMT_TYPE_CONSTANT(unsigned, uint_type); +-FMT_TYPE_CONSTANT(long long, long_long_type); +-FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type); +-FMT_TYPE_CONSTANT(int128_t, int128_type); +-FMT_TYPE_CONSTANT(uint128_t, uint128_type); +-FMT_TYPE_CONSTANT(bool, bool_type); +-FMT_TYPE_CONSTANT(Char, char_type); +-FMT_TYPE_CONSTANT(float, float_type); +-FMT_TYPE_CONSTANT(double, double_type); +-FMT_TYPE_CONSTANT(long double, long_double_type); +-FMT_TYPE_CONSTANT(const Char*, cstring_type); +-FMT_TYPE_CONSTANT(basic_string_view, string_type); +-FMT_TYPE_CONSTANT(const void*, pointer_type); +- +-constexpr bool is_integral_type(type t) { +- return t > type::none_type && t <= type::last_integer_type; +-} +- +-constexpr bool is_arithmetic_type(type t) { +- return t > type::none_type && t <= type::last_numeric_type; +-} +- +-struct unformattable {}; +-struct unformattable_char : unformattable {}; +-struct unformattable_const : unformattable {}; +-struct unformattable_pointer : unformattable {}; +- +-template struct string_value { +- const Char* data; +- size_t size; +-}; +- +-template struct named_arg_value { +- const named_arg_info* data; +- size_t size; +-}; +- +-template struct custom_value { +- using parse_context = typename Context::parse_context_type; +- void* value; +- void (*format)(void* arg, parse_context& parse_ctx, Context& ctx); +-}; +- +-// A formatting argument value. +-template class value { +- public: +- using char_type = typename Context::char_type; +- +- union { +- monostate no_value; +- int int_value; +- unsigned uint_value; +- long long long_long_value; +- unsigned long long ulong_long_value; +- int128_t int128_value; +- uint128_t uint128_value; +- bool bool_value; +- char_type char_value; +- float float_value; +- double double_value; +- long double long_double_value; +- const void* pointer; +- string_value string; +- custom_value custom; +- named_arg_value named_args; +- }; +- +- constexpr FMT_INLINE value() : no_value() {} +- constexpr FMT_INLINE value(int val) : int_value(val) {} +- constexpr FMT_INLINE value(unsigned val) : uint_value(val) {} +- constexpr FMT_INLINE value(long long val) : long_long_value(val) {} +- constexpr FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {} +- FMT_INLINE value(int128_t val) : int128_value(val) {} +- FMT_INLINE value(uint128_t val) : uint128_value(val) {} +- constexpr FMT_INLINE value(float val) : float_value(val) {} +- constexpr FMT_INLINE value(double val) : double_value(val) {} +- FMT_INLINE value(long double val) : long_double_value(val) {} +- constexpr FMT_INLINE value(bool val) : bool_value(val) {} +- constexpr FMT_INLINE value(char_type val) : char_value(val) {} +- FMT_CONSTEXPR FMT_INLINE value(const char_type* val) { +- string.data = val; +- if (is_constant_evaluated()) string.size = {}; +- } +- FMT_CONSTEXPR FMT_INLINE value(basic_string_view val) { +- string.data = val.data(); +- string.size = val.size(); +- } +- FMT_INLINE value(const void* val) : pointer(val) {} +- FMT_INLINE value(const named_arg_info* args, size_t size) +- : named_args{args, size} {} +- +- template FMT_CONSTEXPR FMT_INLINE value(T& val) { +- using value_type = remove_cvref_t; +- custom.value = const_cast(&val); +- // Get the formatter type through the context to allow different contexts +- // have different extension points, e.g. `formatter` for `format` and +- // `printf_formatter` for `printf`. +- custom.format = format_custom_arg< +- value_type, +- conditional_t::value, +- typename Context::template formatter_type, +- fallback_formatter>>; +- } +- value(unformattable); +- value(unformattable_char); +- value(unformattable_const); +- value(unformattable_pointer); +- +- private: +- // Formats an argument of a custom type, such as a user-defined class. +- template +- static void format_custom_arg(void* arg, +- typename Context::parse_context_type& parse_ctx, +- Context& ctx) { +- auto f = Formatter(); +- parse_ctx.advance_to(f.parse(parse_ctx)); +- using qualified_type = +- conditional_t(), const T, T>; +- ctx.advance_to(f.format(*static_cast(arg), ctx)); +- } +-}; +- +-template +-FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg; +- +-// To minimize the number of types we need to deal with, long is translated +-// either to int or to long long depending on its size. +-enum { long_short = sizeof(long) == sizeof(int) }; +-using long_type = conditional_t; +-using ulong_type = conditional_t; +- +-// Maps formatting arguments to core types. +-// arg_mapper reports errors by returning unformattable instead of using +-// static_assert because it's used in the is_formattable trait. +-template struct arg_mapper { +- using char_type = typename Context::char_type; +- +- FMT_CONSTEXPR FMT_INLINE auto map(signed char val) -> int { return val; } +- FMT_CONSTEXPR FMT_INLINE auto map(unsigned char val) -> unsigned { +- return val; +- } +- FMT_CONSTEXPR FMT_INLINE auto map(short val) -> int { return val; } +- FMT_CONSTEXPR FMT_INLINE auto map(unsigned short val) -> unsigned { +- return val; +- } +- FMT_CONSTEXPR FMT_INLINE auto map(int val) -> int { return val; } +- FMT_CONSTEXPR FMT_INLINE auto map(unsigned val) -> unsigned { return val; } +- FMT_CONSTEXPR FMT_INLINE auto map(long val) -> long_type { return val; } +- FMT_CONSTEXPR FMT_INLINE auto map(unsigned long val) -> ulong_type { +- return val; +- } +- FMT_CONSTEXPR FMT_INLINE auto map(long long val) -> long long { return val; } +- FMT_CONSTEXPR FMT_INLINE auto map(unsigned long long val) +- -> unsigned long long { +- return val; +- } +- FMT_CONSTEXPR FMT_INLINE auto map(int128_t val) -> int128_t { return val; } +- FMT_CONSTEXPR FMT_INLINE auto map(uint128_t val) -> uint128_t { return val; } +- FMT_CONSTEXPR FMT_INLINE auto map(bool val) -> bool { return val; } +- +- template ::value || +- std::is_same::value)> +- FMT_CONSTEXPR FMT_INLINE auto map(T val) -> char_type { +- return val; +- } +- template ::value || +-#ifdef __cpp_char8_t +- std::is_same::value || +-#endif +- std::is_same::value || +- std::is_same::value) && +- !std::is_same::value, +- int> = 0> +- FMT_CONSTEXPR FMT_INLINE auto map(T) -> unformattable_char { +- return {}; +- } +- +- FMT_CONSTEXPR FMT_INLINE auto map(float val) -> float { return val; } +- FMT_CONSTEXPR FMT_INLINE auto map(double val) -> double { return val; } +- FMT_CONSTEXPR FMT_INLINE auto map(long double val) -> long double { +- return val; +- } +- +- FMT_CONSTEXPR FMT_INLINE auto map(char_type* val) -> const char_type* { +- return val; +- } +- FMT_CONSTEXPR FMT_INLINE auto map(const char_type* val) -> const char_type* { +- return val; +- } +- template ::value && !std::is_pointer::value && +- std::is_same>::value)> +- FMT_CONSTEXPR FMT_INLINE auto map(const T& val) +- -> basic_string_view { +- return to_string_view(val); +- } +- template ::value && !std::is_pointer::value && +- !std::is_same>::value)> +- FMT_CONSTEXPR FMT_INLINE auto map(const T&) -> unformattable_char { +- return {}; +- } +- template , T>::value && +- !is_string::value && !has_formatter::value && +- !has_fallback_formatter::value)> +- FMT_CONSTEXPR FMT_INLINE auto map(const T& val) +- -> basic_string_view { +- return basic_string_view(val); +- } +- template < +- typename T, +- FMT_ENABLE_IF( +- std::is_constructible, T>::value && +- !std::is_constructible, T>::value && +- !is_string::value && !has_formatter::value && +- !has_fallback_formatter::value)> +- FMT_CONSTEXPR FMT_INLINE auto map(const T& val) +- -> basic_string_view { +- return std_string_view(val); +- } +- +- using cstring_result = conditional_t::value, +- const char*, unformattable_pointer>; +- +- FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(const signed char* val) +- -> cstring_result { +- return map(reinterpret_cast(val)); +- } +- FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(const unsigned char* val) +- -> cstring_result { +- return map(reinterpret_cast(val)); +- } +- FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(signed char* val) +- -> cstring_result { +- return map(reinterpret_cast(val)); +- } +- FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(unsigned char* val) +- -> cstring_result { +- return map(reinterpret_cast(val)); +- } +- +- FMT_CONSTEXPR FMT_INLINE auto map(void* val) -> const void* { return val; } +- FMT_CONSTEXPR FMT_INLINE auto map(const void* val) -> const void* { +- return val; +- } +- FMT_CONSTEXPR FMT_INLINE auto map(std::nullptr_t val) -> const void* { +- return val; +- } +- +- // We use SFINAE instead of a const T* parameter to avoid conflicting with +- // the C array overload. +- template < +- typename T, +- FMT_ENABLE_IF( +- std::is_member_pointer::value || +- std::is_function::type>::value || +- (std::is_convertible::value && +- !std::is_convertible::value))> +- FMT_CONSTEXPR auto map(const T&) -> unformattable_pointer { +- return {}; +- } +- +- template ::value)> +- FMT_CONSTEXPR FMT_INLINE auto map(const T (&values)[N]) -> const T (&)[N] { +- return values; +- } +- +- template ::value&& std::is_convertible::value && +- !has_formatter::value && +- !has_fallback_formatter::value)> +- FMT_CONSTEXPR FMT_INLINE auto map(const T& val) +- -> decltype(std::declval().map( +- static_cast::type>(val))) { +- return map(static_cast::type>(val)); +- } +- +- FMT_CONSTEXPR FMT_INLINE auto map(detail::byte val) -> unsigned { +- return map(static_cast(val)); +- } +- +- template > +- struct formattable +- : bool_constant() || +- !std::is_const>::value || +- has_fallback_formatter::value> {}; +- +-#if FMT_MSC_VER != 0 && FMT_MSC_VER < 1910 +- // Workaround a bug in MSVC. +- template FMT_CONSTEXPR FMT_INLINE auto do_map(T&& val) -> T& { +- return val; +- } +-#else +- template ::value)> +- FMT_CONSTEXPR FMT_INLINE auto do_map(T&& val) -> T& { +- return val; +- } +- template ::value)> +- FMT_CONSTEXPR FMT_INLINE auto do_map(T&&) -> unformattable_const { +- return {}; +- } +-#endif +- +- template , +- FMT_ENABLE_IF(!is_string::value && !is_char::value && +- !std::is_array::value && +- (has_formatter::value || +- has_fallback_formatter::value))> +- FMT_CONSTEXPR FMT_INLINE auto map(T&& val) +- -> decltype(this->do_map(std::forward(val))) { +- return do_map(std::forward(val)); +- } +- +- template ::value)> +- FMT_CONSTEXPR FMT_INLINE auto map(const T& named_arg) +- -> decltype(std::declval().map(named_arg.value)) { +- return map(named_arg.value); +- } +- +- auto map(...) -> unformattable { return {}; } +-}; +- +-// A type constant after applying arg_mapper. +-template +-using mapped_type_constant = +- type_constant().map(std::declval())), +- typename Context::char_type>; +- +-enum { packed_arg_bits = 4 }; +-// Maximum number of arguments with packed types. +-enum { max_packed_args = 62 / packed_arg_bits }; +-enum : unsigned long long { is_unpacked_bit = 1ULL << 63 }; +-enum : unsigned long long { has_named_args_bit = 1ULL << 62 }; +- +-FMT_END_DETAIL_NAMESPACE +- +-// An output iterator that appends to a buffer. +-// It is used to reduce symbol sizes for the common case. +-class appender : public std::back_insert_iterator> { +- using base = std::back_insert_iterator>; +- +- template +- friend auto get_buffer(appender out) -> detail::buffer& { +- return detail::get_container(out); +- } +- +- public: +- using std::back_insert_iterator>::back_insert_iterator; +- appender(base it) FMT_NOEXCEPT : base(it) {} +- using _Unchecked_type = appender; // Mark iterator as checked. +- +- auto operator++() FMT_NOEXCEPT -> appender& { return *this; } +- +- auto operator++(int) FMT_NOEXCEPT -> appender { return *this; } +-}; +- +-// A formatting argument. It is a trivially copyable/constructible type to +-// allow storage in basic_memory_buffer. +-template class basic_format_arg { +- private: +- detail::value value_; +- detail::type type_; +- +- template +- friend FMT_CONSTEXPR auto detail::make_arg(const T& value) +- -> basic_format_arg; +- +- template +- friend FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis, +- const basic_format_arg& arg) +- -> decltype(vis(0)); +- +- friend class basic_format_args; +- friend class dynamic_format_arg_store; +- +- using char_type = typename Context::char_type; +- +- template +- friend struct detail::arg_data; +- +- basic_format_arg(const detail::named_arg_info* args, size_t size) +- : value_(args, size) {} +- +- public: +- class handle { +- public: +- explicit handle(detail::custom_value custom) : custom_(custom) {} +- +- void format(typename Context::parse_context_type& parse_ctx, +- Context& ctx) const { +- custom_.format(custom_.value, parse_ctx, ctx); +- } +- +- private: +- detail::custom_value custom_; +- }; +- +- constexpr basic_format_arg() : type_(detail::type::none_type) {} +- +- constexpr explicit operator bool() const FMT_NOEXCEPT { +- return type_ != detail::type::none_type; +- } +- +- auto type() const -> detail::type { return type_; } +- +- auto is_integral() const -> bool { return detail::is_integral_type(type_); } +- auto is_arithmetic() const -> bool { +- return detail::is_arithmetic_type(type_); +- } +-}; +- +-/** +- \rst +- Visits an argument dispatching to the appropriate visit method based on +- the argument type. For example, if the argument type is ``double`` then +- ``vis(value)`` will be called with the value of type ``double``. +- \endrst +- */ +-template +-FMT_CONSTEXPR FMT_INLINE auto visit_format_arg( +- Visitor&& vis, const basic_format_arg& arg) -> decltype(vis(0)) { +- switch (arg.type_) { +- case detail::type::none_type: +- break; +- case detail::type::int_type: +- return vis(arg.value_.int_value); +- case detail::type::uint_type: +- return vis(arg.value_.uint_value); +- case detail::type::long_long_type: +- return vis(arg.value_.long_long_value); +- case detail::type::ulong_long_type: +- return vis(arg.value_.ulong_long_value); +- case detail::type::int128_type: +- return vis(detail::convert_for_visit(arg.value_.int128_value)); +- case detail::type::uint128_type: +- return vis(detail::convert_for_visit(arg.value_.uint128_value)); +- case detail::type::bool_type: +- return vis(arg.value_.bool_value); +- case detail::type::char_type: +- return vis(arg.value_.char_value); +- case detail::type::float_type: +- return vis(arg.value_.float_value); +- case detail::type::double_type: +- return vis(arg.value_.double_value); +- case detail::type::long_double_type: +- return vis(arg.value_.long_double_value); +- case detail::type::cstring_type: +- return vis(arg.value_.string.data); +- case detail::type::string_type: +- using sv = basic_string_view; +- return vis(sv(arg.value_.string.data, arg.value_.string.size)); +- case detail::type::pointer_type: +- return vis(arg.value_.pointer); +- case detail::type::custom_type: +- return vis(typename basic_format_arg::handle(arg.value_.custom)); +- } +- return vis(monostate()); +-} +- +-FMT_BEGIN_DETAIL_NAMESPACE +- +-template +-auto copy_str(InputIt begin, InputIt end, appender out) -> appender { +- get_container(out).append(begin, end); +- return out; +-} +- +-#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500 +-// A workaround for gcc 4.8 to make void_t work in a SFINAE context. +-template struct void_t_impl { using type = void; }; +-template +-using void_t = typename detail::void_t_impl::type; +-#else +-template using void_t = void; +-#endif +- +-template +-struct is_output_iterator : std::false_type {}; +- +-template +-struct is_output_iterator< +- It, T, +- void_t::iterator_category, +- decltype(*std::declval() = std::declval())>> +- : std::true_type {}; +- +-template +-struct is_back_insert_iterator : std::false_type {}; +-template +-struct is_back_insert_iterator> +- : std::true_type {}; +- +-template +-struct is_contiguous_back_insert_iterator : std::false_type {}; +-template +-struct is_contiguous_back_insert_iterator> +- : is_contiguous {}; +-template <> +-struct is_contiguous_back_insert_iterator : std::true_type {}; +- +-// A type-erased reference to an std::locale to avoid heavy include. +-class locale_ref { +- private: +- const void* locale_; // A type-erased pointer to std::locale. +- +- public: +- constexpr locale_ref() : locale_(nullptr) {} +- template explicit locale_ref(const Locale& loc); +- +- explicit operator bool() const FMT_NOEXCEPT { return locale_ != nullptr; } +- +- template auto get() const -> Locale; +-}; +- +-template constexpr auto encode_types() -> unsigned long long { +- return 0; +-} +- +-template +-constexpr auto encode_types() -> unsigned long long { +- return static_cast(mapped_type_constant::value) | +- (encode_types() << packed_arg_bits); +-} +- +-template +-FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg { +- basic_format_arg arg; +- arg.type_ = mapped_type_constant::value; +- arg.value_ = arg_mapper().map(value); +- return arg; +-} +- +-// The type template parameter is there to avoid an ODR violation when using +-// a fallback formatter in one translation unit and an implicit conversion in +-// another (not recommended). +-template +-FMT_CONSTEXPR FMT_INLINE auto make_arg(T&& val) -> value { +- const auto& arg = arg_mapper().map(std::forward(val)); +- +- constexpr bool formattable_char = +- !std::is_same::value; +- static_assert(formattable_char, "Mixing character types is disallowed."); +- +- constexpr bool formattable_const = +- !std::is_same::value; +- static_assert(formattable_const, "Cannot format a const argument."); +- +- // Formatting of arbitrary pointers is disallowed. If you want to output +- // a pointer cast it to "void *" or "const void *". In particular, this +- // forbids formatting of "[const] volatile char *" which is printed as bool +- // by iostreams. +- constexpr bool formattable_pointer = +- !std::is_same::value; +- static_assert(formattable_pointer, +- "Formatting of non-void pointers is disallowed."); +- +- constexpr bool formattable = +- !std::is_same::value; +- static_assert( +- formattable, +- "Cannot format an argument. To make type T formattable provide a " +- "formatter specialization: https://fmt.dev/latest/api.html#udt"); +- return {arg}; +-} +- +-template +-inline auto make_arg(const T& value) -> basic_format_arg { +- return make_arg(value); +-} +-FMT_END_DETAIL_NAMESPACE +- +-// Formatting context. +-template class basic_format_context { +- public: +- /** The character type for the output. */ +- using char_type = Char; +- +- private: +- OutputIt out_; +- basic_format_args args_; +- detail::locale_ref loc_; +- +- public: +- using iterator = OutputIt; +- using format_arg = basic_format_arg; +- using parse_context_type = basic_format_parse_context; +- template using formatter_type = formatter; +- +- basic_format_context(basic_format_context&&) = default; +- basic_format_context(const basic_format_context&) = delete; +- void operator=(const basic_format_context&) = delete; +- /** +- Constructs a ``basic_format_context`` object. References to the arguments are +- stored in the object so make sure they have appropriate lifetimes. +- */ +- constexpr basic_format_context( +- OutputIt out, basic_format_args ctx_args, +- detail::locale_ref loc = detail::locale_ref()) +- : out_(out), args_(ctx_args), loc_(loc) {} +- +- constexpr auto arg(int id) const -> format_arg { return args_.get(id); } +- FMT_CONSTEXPR auto arg(basic_string_view name) -> format_arg { +- return args_.get(name); +- } +- FMT_CONSTEXPR auto arg_id(basic_string_view name) -> int { +- return args_.get_id(name); +- } +- auto args() const -> const basic_format_args& { +- return args_; +- } +- +- FMT_CONSTEXPR auto error_handler() -> detail::error_handler { return {}; } +- void on_error(const char* message) { error_handler().on_error(message); } +- +- // Returns an iterator to the beginning of the output range. +- FMT_CONSTEXPR auto out() -> iterator { return out_; } +- +- // Advances the begin iterator to ``it``. +- void advance_to(iterator it) { +- if (!detail::is_back_insert_iterator()) out_ = it; +- } +- +- FMT_CONSTEXPR auto locale() -> detail::locale_ref { return loc_; } +-}; +- +-template +-using buffer_context = +- basic_format_context, Char>; +-using format_context = buffer_context; +- +-// Workaround an alias issue: https://stackoverflow.com/q/62767544/471164. +-#define FMT_BUFFER_CONTEXT(Char) \ +- basic_format_context, Char> +- +-template +-using is_formattable = bool_constant< +- !std::is_base_of>().map( +- std::declval()))>::value && +- !detail::has_fallback_formatter::value>; +- +-/** +- \rst +- An array of references to arguments. It can be implicitly converted into +- `~fmt::basic_format_args` for passing into type-erased formatting functions +- such as `~fmt::vformat`. +- \endrst +- */ +-template +-class format_arg_store +-#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 +- // Workaround a GCC template argument substitution bug. +- : public basic_format_args +-#endif +-{ +- private: +- static const size_t num_args = sizeof...(Args); +- static const size_t num_named_args = detail::count_named_args(); +- static const bool is_packed = num_args <= detail::max_packed_args; +- +- using value_type = conditional_t, +- basic_format_arg>; +- +- detail::arg_data +- data_; +- +- friend class basic_format_args; +- +- static constexpr unsigned long long desc = +- (is_packed ? detail::encode_types() +- : detail::is_unpacked_bit | num_args) | +- (num_named_args != 0 +- ? static_cast(detail::has_named_args_bit) +- : 0); +- +- public: +- template +- FMT_CONSTEXPR FMT_INLINE format_arg_store(T&&... args) +- : +-#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 +- basic_format_args(*this), +-#endif +- data_{detail::make_arg< +- is_packed, Context, +- detail::mapped_type_constant, Context>::value>( +- std::forward(args))...} { +- detail::init_named_args(data_.named_args(), 0, 0, args...); +- } +-}; +- +-/** +- \rst +- Constructs a `~fmt::format_arg_store` object that contains references to +- arguments and can be implicitly converted to `~fmt::format_args`. `Context` +- can be omitted in which case it defaults to `~fmt::context`. +- See `~fmt::arg` for lifetime considerations. +- \endrst +- */ +-template +-constexpr auto make_format_args(Args&&... args) +- -> format_arg_store...> { +- return {std::forward(args)...}; +-} +- +-/** +- \rst +- Returns a named argument to be used in a formatting function. +- It should only be used in a call to a formatting function or +- `dynamic_format_arg_store::push_back`. +- +- **Example**:: +- +- fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)); +- \endrst +- */ +-template +-inline auto arg(const Char* name, const T& arg) -> detail::named_arg { +- static_assert(!detail::is_named_arg(), "nested named arguments"); +- return {name, arg}; +-} +- +-/** +- \rst +- A view of a collection of formatting arguments. To avoid lifetime issues it +- should only be used as a parameter type in type-erased functions such as +- ``vformat``:: +- +- void vlog(string_view format_str, format_args args); // OK +- format_args args = make_format_args(42); // Error: dangling reference +- \endrst +- */ +-template class basic_format_args { +- public: +- using size_type = int; +- using format_arg = basic_format_arg; +- +- private: +- // A descriptor that contains information about formatting arguments. +- // If the number of arguments is less or equal to max_packed_args then +- // argument types are passed in the descriptor. This reduces binary code size +- // per formatting function call. +- unsigned long long desc_; +- union { +- // If is_packed() returns true then argument values are stored in values_; +- // otherwise they are stored in args_. This is done to improve cache +- // locality and reduce compiled code size since storing larger objects +- // may require more code (at least on x86-64) even if the same amount of +- // data is actually copied to stack. It saves ~10% on the bloat test. +- const detail::value* values_; +- const format_arg* args_; +- }; +- +- constexpr auto is_packed() const -> bool { +- return (desc_ & detail::is_unpacked_bit) == 0; +- } +- auto has_named_args() const -> bool { +- return (desc_ & detail::has_named_args_bit) != 0; +- } +- +- FMT_CONSTEXPR auto type(int index) const -> detail::type { +- int shift = index * detail::packed_arg_bits; +- unsigned int mask = (1 << detail::packed_arg_bits) - 1; +- return static_cast((desc_ >> shift) & mask); +- } +- +- constexpr FMT_INLINE basic_format_args(unsigned long long desc, +- const detail::value* values) +- : desc_(desc), values_(values) {} +- constexpr basic_format_args(unsigned long long desc, const format_arg* args) +- : desc_(desc), args_(args) {} +- +- public: +- constexpr basic_format_args() : desc_(0), args_(nullptr) {} +- +- /** +- \rst +- Constructs a `basic_format_args` object from `~fmt::format_arg_store`. +- \endrst +- */ +- template +- constexpr FMT_INLINE basic_format_args( +- const format_arg_store& store) +- : basic_format_args(format_arg_store::desc, +- store.data_.args()) {} +- +- /** +- \rst +- Constructs a `basic_format_args` object from +- `~fmt::dynamic_format_arg_store`. +- \endrst +- */ +- constexpr FMT_INLINE basic_format_args( +- const dynamic_format_arg_store& store) +- : basic_format_args(store.get_types(), store.data()) {} +- +- /** +- \rst +- Constructs a `basic_format_args` object from a dynamic set of arguments. +- \endrst +- */ +- constexpr basic_format_args(const format_arg* args, int count) +- : basic_format_args(detail::is_unpacked_bit | detail::to_unsigned(count), +- args) {} +- +- /** Returns the argument with the specified id. */ +- FMT_CONSTEXPR auto get(int id) const -> format_arg { +- format_arg arg; +- if (!is_packed()) { +- if (id < max_size()) arg = args_[id]; +- return arg; +- } +- if (id >= detail::max_packed_args) return arg; +- arg.type_ = type(id); +- if (arg.type_ == detail::type::none_type) return arg; +- arg.value_ = values_[id]; +- return arg; +- } +- +- template +- auto get(basic_string_view name) const -> format_arg { +- int id = get_id(name); +- return id >= 0 ? get(id) : format_arg(); +- } +- +- template +- auto get_id(basic_string_view name) const -> int { +- if (!has_named_args()) return -1; +- const auto& named_args = +- (is_packed() ? values_[-1] : args_[-1].value_).named_args; +- for (size_t i = 0; i < named_args.size; ++i) { +- if (named_args.data[i].name == name) return named_args.data[i].id; +- } +- return -1; +- } +- +- auto max_size() const -> int { +- unsigned long long max_packed = detail::max_packed_args; +- return static_cast(is_packed() ? max_packed +- : desc_ & ~detail::is_unpacked_bit); +- } +-}; +- +-/** An alias to ``basic_format_args``. */ +-// A separate type would result in shorter symbols but break ABI compatibility +-// between clang and gcc on ARM (#1919). +-using format_args = basic_format_args; +- +-// We cannot use enum classes as bit fields because of a gcc bug +-// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414. +-namespace align { +-enum type { none, left, right, center, numeric }; +-} +-using align_t = align::type; +-namespace sign { +-enum type { none, minus, plus, space }; +-} +-using sign_t = sign::type; +- +-FMT_BEGIN_DETAIL_NAMESPACE +- +-// Workaround an array initialization issue in gcc 4.8. +-template struct fill_t { +- private: +- enum { max_size = 4 }; +- Char data_[max_size] = {Char(' '), Char(0), Char(0), Char(0)}; +- unsigned char size_ = 1; +- +- public: +- FMT_CONSTEXPR void operator=(basic_string_view s) { +- auto size = s.size(); +- if (size > max_size) return throw_format_error("invalid fill"); +- for (size_t i = 0; i < size; ++i) data_[i] = s[i]; +- size_ = static_cast(size); +- } +- +- constexpr auto size() const -> size_t { return size_; } +- constexpr auto data() const -> const Char* { return data_; } +- +- FMT_CONSTEXPR auto operator[](size_t index) -> Char& { return data_[index]; } +- FMT_CONSTEXPR auto operator[](size_t index) const -> const Char& { +- return data_[index]; +- } +-}; +-FMT_END_DETAIL_NAMESPACE +- +-enum class presentation_type : unsigned char { +- none, +- // Integer types should go first, +- dec, // 'd' +- oct, // 'o' +- hex_lower, // 'x' +- hex_upper, // 'X' +- bin_lower, // 'b' +- bin_upper, // 'B' +- hexfloat_lower, // 'a' +- hexfloat_upper, // 'A' +- exp_lower, // 'e' +- exp_upper, // 'E' +- fixed_lower, // 'f' +- fixed_upper, // 'F' +- general_lower, // 'g' +- general_upper, // 'G' +- chr, // 'c' +- string, // 's' +- pointer // 'p' +-}; +- +-// Format specifiers for built-in and string types. +-template struct basic_format_specs { +- int width; +- int precision; +- presentation_type type; +- align_t align : 4; +- sign_t sign : 3; +- bool alt : 1; // Alternate form ('#'). +- bool localized : 1; +- detail::fill_t fill; +- +- constexpr basic_format_specs() +- : width(0), +- precision(-1), +- type(presentation_type::none), +- align(align::none), +- sign(sign::none), +- alt(false), +- localized(false) {} +-}; +- +-using format_specs = basic_format_specs; +- +-FMT_BEGIN_DETAIL_NAMESPACE +- +-enum class arg_id_kind { none, index, name }; +- +-// An argument reference. +-template struct arg_ref { +- FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {} +- +- FMT_CONSTEXPR explicit arg_ref(int index) +- : kind(arg_id_kind::index), val(index) {} +- FMT_CONSTEXPR explicit arg_ref(basic_string_view name) +- : kind(arg_id_kind::name), val(name) {} +- +- FMT_CONSTEXPR auto operator=(int idx) -> arg_ref& { +- kind = arg_id_kind::index; +- val.index = idx; +- return *this; +- } +- +- arg_id_kind kind; +- union value { +- FMT_CONSTEXPR value(int id = 0) : index{id} {} +- FMT_CONSTEXPR value(basic_string_view n) : name(n) {} +- +- int index; +- basic_string_view name; +- } val; +-}; +- +-// Format specifiers with width and precision resolved at formatting rather +-// than parsing time to allow re-using the same parsed specifiers with +-// different sets of arguments (precompilation of format strings). +-template +-struct dynamic_format_specs : basic_format_specs { +- arg_ref width_ref; +- arg_ref precision_ref; +-}; +- +-struct auto_id {}; +- +-// A format specifier handler that sets fields in basic_format_specs. +-template class specs_setter { +- protected: +- basic_format_specs& specs_; +- +- public: +- explicit FMT_CONSTEXPR specs_setter(basic_format_specs& specs) +- : specs_(specs) {} +- +- FMT_CONSTEXPR specs_setter(const specs_setter& other) +- : specs_(other.specs_) {} +- +- FMT_CONSTEXPR void on_align(align_t align) { specs_.align = align; } +- FMT_CONSTEXPR void on_fill(basic_string_view fill) { +- specs_.fill = fill; +- } +- FMT_CONSTEXPR void on_sign(sign_t s) { specs_.sign = s; } +- FMT_CONSTEXPR void on_hash() { specs_.alt = true; } +- FMT_CONSTEXPR void on_localized() { specs_.localized = true; } +- +- FMT_CONSTEXPR void on_zero() { +- if (specs_.align == align::none) specs_.align = align::numeric; +- specs_.fill[0] = Char('0'); +- } +- +- FMT_CONSTEXPR void on_width(int width) { specs_.width = width; } +- FMT_CONSTEXPR void on_precision(int precision) { +- specs_.precision = precision; +- } +- FMT_CONSTEXPR void end_precision() {} +- +- FMT_CONSTEXPR void on_type(presentation_type type) { specs_.type = type; } +-}; +- +-// Format spec handler that saves references to arguments representing dynamic +-// width and precision to be resolved at formatting time. +-template +-class dynamic_specs_handler +- : public specs_setter { +- public: +- using char_type = typename ParseContext::char_type; +- +- FMT_CONSTEXPR dynamic_specs_handler(dynamic_format_specs& specs, +- ParseContext& ctx) +- : specs_setter(specs), specs_(specs), context_(ctx) {} +- +- FMT_CONSTEXPR dynamic_specs_handler(const dynamic_specs_handler& other) +- : specs_setter(other), +- specs_(other.specs_), +- context_(other.context_) {} +- +- template FMT_CONSTEXPR void on_dynamic_width(Id arg_id) { +- specs_.width_ref = make_arg_ref(arg_id); +- } +- +- template FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) { +- specs_.precision_ref = make_arg_ref(arg_id); +- } +- +- FMT_CONSTEXPR void on_error(const char* message) { +- context_.on_error(message); +- } +- +- private: +- dynamic_format_specs& specs_; +- ParseContext& context_; +- +- using arg_ref_type = arg_ref; +- +- FMT_CONSTEXPR auto make_arg_ref(int arg_id) -> arg_ref_type { +- context_.check_arg_id(arg_id); +- return arg_ref_type(arg_id); +- } +- +- FMT_CONSTEXPR auto make_arg_ref(auto_id) -> arg_ref_type { +- return arg_ref_type(context_.next_arg_id()); +- } +- +- FMT_CONSTEXPR auto make_arg_ref(basic_string_view arg_id) +- -> arg_ref_type { +- context_.check_arg_id(arg_id); +- basic_string_view format_str( +- context_.begin(), to_unsigned(context_.end() - context_.begin())); +- return arg_ref_type(arg_id); +- } +-}; +- +-template constexpr bool is_ascii_letter(Char c) { +- return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); +-} +- +-// Converts a character to ASCII. Returns a number > 127 on conversion failure. +-template ::value)> +-constexpr auto to_ascii(Char value) -> Char { +- return value; +-} +-template ::value)> +-constexpr auto to_ascii(Char value) -> +- typename std::underlying_type::type { +- return value; +-} +- +-template +-FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int { +- if (const_check(sizeof(Char) != 1)) return 1; +- auto lengths = +- "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4"; +- int len = lengths[static_cast(*begin) >> 3]; +- +- // Compute the pointer to the next character early so that the next +- // iteration can start working on the next character. Neither Clang +- // nor GCC figure out this reordering on their own. +- return len + !len; +-} +- +-// Return the result via the out param to workaround gcc bug 77539. +-template +-FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr& out) -> bool { +- for (out = first; out != last; ++out) { +- if (*out == value) return true; +- } +- return false; +-} +- +-template <> +-inline auto find(const char* first, const char* last, char value, +- const char*& out) -> bool { +- out = static_cast( +- std::memchr(first, value, to_unsigned(last - first))); +- return out != nullptr; +-} +- +-// Parses the range [begin, end) as an unsigned integer. This function assumes +-// that the range is non-empty and the first character is a digit. +-template +-FMT_CONSTEXPR auto parse_nonnegative_int(const Char*& begin, const Char* end, +- int error_value) noexcept -> int { +- FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', ""); +- unsigned value = 0, prev = 0; +- auto p = begin; +- do { +- prev = value; +- value = value * 10 + unsigned(*p - '0'); +- ++p; +- } while (p != end && '0' <= *p && *p <= '9'); +- auto num_digits = p - begin; +- begin = p; +- if (num_digits <= std::numeric_limits::digits10) +- return static_cast(value); +- // Check for overflow. +- const unsigned max = to_unsigned((std::numeric_limits::max)()); +- return num_digits == std::numeric_limits::digits10 + 1 && +- prev * 10ull + unsigned(p[-1] - '0') <= max +- ? static_cast(value) +- : error_value; +-} +- +-// Parses fill and alignment. +-template +-FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end, +- Handler&& handler) -> const Char* { +- FMT_ASSERT(begin != end, ""); +- auto align = align::none; +- auto p = begin + code_point_length(begin); +- if (p >= end) p = begin; +- for (;;) { +- switch (to_ascii(*p)) { +- case '<': +- align = align::left; +- break; +- case '>': +- align = align::right; +- break; +- case '^': +- align = align::center; +- break; +- default: +- break; +- } +- if (align != align::none) { +- if (p != begin) { +- auto c = *begin; +- if (c == '{') +- return handler.on_error("invalid fill character '{'"), begin; +- handler.on_fill(basic_string_view(begin, to_unsigned(p - begin))); +- begin = p + 1; +- } else +- ++begin; +- handler.on_align(align); +- break; +- } else if (p == begin) { +- break; +- } +- p = begin; +- } +- return begin; +-} +- +-template FMT_CONSTEXPR bool is_name_start(Char c) { +- return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; +-} +- +-template +-FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end, +- IDHandler&& handler) -> const Char* { +- FMT_ASSERT(begin != end, ""); +- Char c = *begin; +- if (c >= '0' && c <= '9') { +- int index = 0; +- if (c != '0') +- index = +- parse_nonnegative_int(begin, end, (std::numeric_limits::max)()); +- else +- ++begin; +- if (begin == end || (*begin != '}' && *begin != ':')) +- handler.on_error("invalid format string"); +- else +- handler(index); +- return begin; +- } +- if (!is_name_start(c)) { +- handler.on_error("invalid format string"); +- return begin; +- } +- auto it = begin; +- do { +- ++it; +- } while (it != end && (is_name_start(c = *it) || ('0' <= c && c <= '9'))); +- handler(basic_string_view(begin, to_unsigned(it - begin))); +- return it; +-} +- +-template +-FMT_CONSTEXPR FMT_INLINE auto parse_arg_id(const Char* begin, const Char* end, +- IDHandler&& handler) -> const Char* { +- Char c = *begin; +- if (c != '}' && c != ':') return do_parse_arg_id(begin, end, handler); +- handler(); +- return begin; +-} +- +-template +-FMT_CONSTEXPR auto parse_width(const Char* begin, const Char* end, +- Handler&& handler) -> const Char* { +- using detail::auto_id; +- struct width_adapter { +- Handler& handler; +- +- FMT_CONSTEXPR void operator()() { handler.on_dynamic_width(auto_id()); } +- FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_width(id); } +- FMT_CONSTEXPR void operator()(basic_string_view id) { +- handler.on_dynamic_width(id); +- } +- FMT_CONSTEXPR void on_error(const char* message) { +- if (message) handler.on_error(message); +- } +- }; +- +- FMT_ASSERT(begin != end, ""); +- if ('0' <= *begin && *begin <= '9') { +- int width = parse_nonnegative_int(begin, end, -1); +- if (width != -1) +- handler.on_width(width); +- else +- handler.on_error("number is too big"); +- } else if (*begin == '{') { +- ++begin; +- if (begin != end) begin = parse_arg_id(begin, end, width_adapter{handler}); +- if (begin == end || *begin != '}') +- return handler.on_error("invalid format string"), begin; +- ++begin; +- } +- return begin; +-} +- +-template +-FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end, +- Handler&& handler) -> const Char* { +- using detail::auto_id; +- struct precision_adapter { +- Handler& handler; +- +- FMT_CONSTEXPR void operator()() { handler.on_dynamic_precision(auto_id()); } +- FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_precision(id); } +- FMT_CONSTEXPR void operator()(basic_string_view id) { +- handler.on_dynamic_precision(id); +- } +- FMT_CONSTEXPR void on_error(const char* message) { +- if (message) handler.on_error(message); +- } +- }; +- +- ++begin; +- auto c = begin != end ? *begin : Char(); +- if ('0' <= c && c <= '9') { +- auto precision = parse_nonnegative_int(begin, end, -1); +- if (precision != -1) +- handler.on_precision(precision); +- else +- handler.on_error("number is too big"); +- } else if (c == '{') { +- ++begin; +- if (begin != end) +- begin = parse_arg_id(begin, end, precision_adapter{handler}); +- if (begin == end || *begin++ != '}') +- return handler.on_error("invalid format string"), begin; +- } else { +- return handler.on_error("missing precision specifier"), begin; +- } +- handler.end_precision(); +- return begin; +-} +- +-template +-FMT_CONSTEXPR auto parse_presentation_type(Char type) -> presentation_type { +- switch (to_ascii(type)) { +- case 'd': +- return presentation_type::dec; +- case 'o': +- return presentation_type::oct; +- case 'x': +- return presentation_type::hex_lower; +- case 'X': +- return presentation_type::hex_upper; +- case 'b': +- return presentation_type::bin_lower; +- case 'B': +- return presentation_type::bin_upper; +- case 'a': +- return presentation_type::hexfloat_lower; +- case 'A': +- return presentation_type::hexfloat_upper; +- case 'e': +- return presentation_type::exp_lower; +- case 'E': +- return presentation_type::exp_upper; +- case 'f': +- return presentation_type::fixed_lower; +- case 'F': +- return presentation_type::fixed_upper; +- case 'g': +- return presentation_type::general_lower; +- case 'G': +- return presentation_type::general_upper; +- case 'c': +- return presentation_type::chr; +- case 's': +- return presentation_type::string; +- case 'p': +- return presentation_type::pointer; +- default: +- return presentation_type::none; +- } +-} +- +-// Parses standard format specifiers and sends notifications about parsed +-// components to handler. +-template +-FMT_CONSTEXPR FMT_INLINE auto parse_format_specs(const Char* begin, +- const Char* end, +- SpecHandler&& handler) +- -> const Char* { +- if (1 < end - begin && begin[1] == '}' && is_ascii_letter(*begin) && +- *begin != 'L') { +- presentation_type type = parse_presentation_type(*begin++); +- if (type == presentation_type::none) +- handler.on_error("invalid type specifier"); +- handler.on_type(type); +- return begin; +- } +- +- if (begin == end) return begin; +- +- begin = parse_align(begin, end, handler); +- if (begin == end) return begin; +- +- // Parse sign. +- switch (to_ascii(*begin)) { +- case '+': +- handler.on_sign(sign::plus); +- ++begin; +- break; +- case '-': +- handler.on_sign(sign::minus); +- ++begin; +- break; +- case ' ': +- handler.on_sign(sign::space); +- ++begin; +- break; +- default: +- break; +- } +- if (begin == end) return begin; +- +- if (*begin == '#') { +- handler.on_hash(); +- if (++begin == end) return begin; +- } +- +- // Parse zero flag. +- if (*begin == '0') { +- handler.on_zero(); +- if (++begin == end) return begin; +- } +- +- begin = parse_width(begin, end, handler); +- if (begin == end) return begin; +- +- // Parse precision. +- if (*begin == '.') { +- begin = parse_precision(begin, end, handler); +- if (begin == end) return begin; +- } +- +- if (*begin == 'L') { +- handler.on_localized(); +- ++begin; +- } +- +- // Parse type. +- if (begin != end && *begin != '}') { +- presentation_type type = parse_presentation_type(*begin++); +- if (type == presentation_type::none) +- handler.on_error("invalid type specifier"); +- handler.on_type(type); +- } +- return begin; +-} +- +-template +-FMT_CONSTEXPR auto parse_replacement_field(const Char* begin, const Char* end, +- Handler&& handler) -> const Char* { +- struct id_adapter { +- Handler& handler; +- int arg_id; +- +- FMT_CONSTEXPR void operator()() { arg_id = handler.on_arg_id(); } +- FMT_CONSTEXPR void operator()(int id) { arg_id = handler.on_arg_id(id); } +- FMT_CONSTEXPR void operator()(basic_string_view id) { +- arg_id = handler.on_arg_id(id); +- } +- FMT_CONSTEXPR void on_error(const char* message) { +- if (message) handler.on_error(message); +- } +- }; +- +- ++begin; +- if (begin == end) return handler.on_error("invalid format string"), end; +- if (*begin == '}') { +- handler.on_replacement_field(handler.on_arg_id(), begin); +- } else if (*begin == '{') { +- handler.on_text(begin, begin + 1); +- } else { +- auto adapter = id_adapter{handler, 0}; +- begin = parse_arg_id(begin, end, adapter); +- Char c = begin != end ? *begin : Char(); +- if (c == '}') { +- handler.on_replacement_field(adapter.arg_id, begin); +- } else if (c == ':') { +- begin = handler.on_format_specs(adapter.arg_id, begin + 1, end); +- if (begin == end || *begin != '}') +- return handler.on_error("unknown format specifier"), end; +- } else { +- return handler.on_error("missing '}' in format string"), end; +- } +- } +- return begin + 1; +-} +- +-template +-FMT_CONSTEXPR FMT_INLINE void parse_format_string( +- basic_string_view format_str, Handler&& handler) { +- // Workaround a name-lookup bug in MSVC's modules implementation. +- using detail::find; +- +- auto begin = format_str.data(); +- auto end = begin + format_str.size(); +- if (end - begin < 32) { +- // Use a simple loop instead of memchr for small strings. +- const Char* p = begin; +- while (p != end) { +- auto c = *p++; +- if (c == '{') { +- handler.on_text(begin, p - 1); +- begin = p = parse_replacement_field(p - 1, end, handler); +- } else if (c == '}') { +- if (p == end || *p != '}') +- return handler.on_error("unmatched '}' in format string"); +- handler.on_text(begin, p); +- begin = ++p; +- } +- } +- handler.on_text(begin, end); +- return; +- } +- struct writer { +- FMT_CONSTEXPR void operator()(const Char* pbegin, const Char* pend) { +- if (pbegin == pend) return; +- for (;;) { +- const Char* p = nullptr; +- if (!find(pbegin, pend, Char('}'), p)) +- return handler_.on_text(pbegin, pend); +- ++p; +- if (p == pend || *p != '}') +- return handler_.on_error("unmatched '}' in format string"); +- handler_.on_text(pbegin, p); +- pbegin = p + 1; +- } +- } +- Handler& handler_; +- } write{handler}; +- while (begin != end) { +- // Doing two passes with memchr (one for '{' and another for '}') is up to +- // 2.5x faster than the naive one-pass implementation on big format strings. +- const Char* p = begin; +- if (*begin != '{' && !find(begin + 1, end, Char('{'), p)) +- return write(begin, end); +- write(begin, p); +- begin = parse_replacement_field(p, end, handler); +- } +-} +- +-template +-FMT_CONSTEXPR auto parse_format_specs(ParseContext& ctx) +- -> decltype(ctx.begin()) { +- using char_type = typename ParseContext::char_type; +- using context = buffer_context; +- using mapped_type = conditional_t< +- mapped_type_constant::value != type::custom_type, +- decltype(arg_mapper().map(std::declval())), T>; +- auto f = conditional_t::value, +- formatter, +- fallback_formatter>(); +- return f.parse(ctx); +-} +- +-// A parse context with extra argument id checks. It is only used at compile +-// time because adding checks at runtime would introduce substantial overhead +-// and would be redundant since argument ids are checked when arguments are +-// retrieved anyway. +-template +-class compile_parse_context +- : public basic_format_parse_context { +- private: +- int num_args_; +- using base = basic_format_parse_context; +- +- public: +- explicit FMT_CONSTEXPR compile_parse_context( +- basic_string_view format_str, +- int num_args = (std::numeric_limits::max)(), ErrorHandler eh = {}) +- : base(format_str, eh), num_args_(num_args) {} +- +- FMT_CONSTEXPR auto next_arg_id() -> int { +- int id = base::next_arg_id(); +- if (id >= num_args_) this->on_error("argument not found"); +- return id; +- } +- +- FMT_CONSTEXPR void check_arg_id(int id) { +- base::check_arg_id(id); +- if (id >= num_args_) this->on_error("argument not found"); +- } +- using base::check_arg_id; +-}; +- +-template +-FMT_CONSTEXPR void check_int_type_spec(presentation_type type, +- ErrorHandler&& eh) { +- if (type > presentation_type::bin_upper && type != presentation_type::chr) +- eh.on_error("invalid type specifier"); +-} +- +-// Checks char specs and returns true if the type spec is char (and not int). +-template +-FMT_CONSTEXPR auto check_char_specs(const basic_format_specs& specs, +- ErrorHandler&& eh = {}) -> bool { +- if (specs.type != presentation_type::none && +- specs.type != presentation_type::chr) { +- check_int_type_spec(specs.type, eh); +- return false; +- } +- if (specs.align == align::numeric || specs.sign != sign::none || specs.alt) +- eh.on_error("invalid format specifier for char"); +- return true; +-} +- +-// A floating-point presentation format. +-enum class float_format : unsigned char { +- general, // General: exponent notation or fixed point based on magnitude. +- exp, // Exponent notation with the default precision of 6, e.g. 1.2e-3. +- fixed, // Fixed point with the default precision of 6, e.g. 0.0012. +- hex +-}; +- +-struct float_specs { +- int precision; +- float_format format : 8; +- sign_t sign : 8; +- bool upper : 1; +- bool locale : 1; +- bool binary32 : 1; +- bool fallback : 1; +- bool showpoint : 1; +-}; +- +-template +-FMT_CONSTEXPR auto parse_float_type_spec(const basic_format_specs& specs, +- ErrorHandler&& eh = {}) +- -> float_specs { +- auto result = float_specs(); +- result.showpoint = specs.alt; +- result.locale = specs.localized; +- switch (specs.type) { +- case presentation_type::none: +- result.format = float_format::general; +- break; +- case presentation_type::general_upper: +- result.upper = true; +- FMT_FALLTHROUGH; +- case presentation_type::general_lower: +- result.format = float_format::general; +- break; +- case presentation_type::exp_upper: +- result.upper = true; +- FMT_FALLTHROUGH; +- case presentation_type::exp_lower: +- result.format = float_format::exp; +- result.showpoint |= specs.precision != 0; +- break; +- case presentation_type::fixed_upper: +- result.upper = true; +- FMT_FALLTHROUGH; +- case presentation_type::fixed_lower: +- result.format = float_format::fixed; +- result.showpoint |= specs.precision != 0; +- break; +- case presentation_type::hexfloat_upper: +- result.upper = true; +- FMT_FALLTHROUGH; +- case presentation_type::hexfloat_lower: +- result.format = float_format::hex; +- break; +- default: +- eh.on_error("invalid type specifier"); +- break; +- } +- return result; +-} +- +-template +-FMT_CONSTEXPR auto check_cstring_type_spec(presentation_type type, +- ErrorHandler&& eh = {}) -> bool { +- if (type == presentation_type::none || type == presentation_type::string) +- return true; +- if (type != presentation_type::pointer) eh.on_error("invalid type specifier"); +- return false; +-} +- +-template +-FMT_CONSTEXPR void check_string_type_spec(presentation_type type, +- ErrorHandler&& eh = {}) { +- if (type != presentation_type::none && type != presentation_type::string) +- eh.on_error("invalid type specifier"); +-} +- +-template +-FMT_CONSTEXPR void check_pointer_type_spec(presentation_type type, +- ErrorHandler&& eh) { +- if (type != presentation_type::none && type != presentation_type::pointer) +- eh.on_error("invalid type specifier"); +-} +- +-// A parse_format_specs handler that checks if specifiers are consistent with +-// the argument type. +-template class specs_checker : public Handler { +- private: +- detail::type arg_type_; +- +- FMT_CONSTEXPR void require_numeric_argument() { +- if (!is_arithmetic_type(arg_type_)) +- this->on_error("format specifier requires numeric argument"); +- } +- +- public: +- FMT_CONSTEXPR specs_checker(const Handler& handler, detail::type arg_type) +- : Handler(handler), arg_type_(arg_type) {} +- +- FMT_CONSTEXPR void on_align(align_t align) { +- if (align == align::numeric) require_numeric_argument(); +- Handler::on_align(align); +- } +- +- FMT_CONSTEXPR void on_sign(sign_t s) { +- require_numeric_argument(); +- if (is_integral_type(arg_type_) && arg_type_ != type::int_type && +- arg_type_ != type::long_long_type && arg_type_ != type::char_type) { +- this->on_error("format specifier requires signed argument"); +- } +- Handler::on_sign(s); +- } +- +- FMT_CONSTEXPR void on_hash() { +- require_numeric_argument(); +- Handler::on_hash(); +- } +- +- FMT_CONSTEXPR void on_localized() { +- require_numeric_argument(); +- Handler::on_localized(); +- } +- +- FMT_CONSTEXPR void on_zero() { +- require_numeric_argument(); +- Handler::on_zero(); +- } +- +- FMT_CONSTEXPR void end_precision() { +- if (is_integral_type(arg_type_) || arg_type_ == type::pointer_type) +- this->on_error("precision not allowed for this argument type"); +- } +-}; +- +-constexpr int invalid_arg_index = -1; +- +-#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +-template +-constexpr auto get_arg_index_by_name(basic_string_view name) -> int { +- if constexpr (detail::is_statically_named_arg()) { +- if (name == T::name) return N; +- } +- if constexpr (sizeof...(Args) > 0) +- return get_arg_index_by_name(name); +- (void)name; // Workaround an MSVC bug about "unused" parameter. +- return invalid_arg_index; +-} +-#endif +- +-template +-FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view name) -> int { +-#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +- if constexpr (sizeof...(Args) > 0) +- return get_arg_index_by_name<0, Args...>(name); +-#endif +- (void)name; +- return invalid_arg_index; +-} +- +-template +-class format_string_checker { +- private: +- using parse_context_type = compile_parse_context; +- enum { num_args = sizeof...(Args) }; +- +- // Format specifier parsing function. +- using parse_func = const Char* (*)(parse_context_type&); +- +- parse_context_type context_; +- parse_func parse_funcs_[num_args > 0 ? num_args : 1]; +- +- public: +- explicit FMT_CONSTEXPR format_string_checker( +- basic_string_view format_str, ErrorHandler eh) +- : context_(format_str, num_args, eh), +- parse_funcs_{&parse_format_specs...} {} +- +- FMT_CONSTEXPR void on_text(const Char*, const Char*) {} +- +- FMT_CONSTEXPR auto on_arg_id() -> int { return context_.next_arg_id(); } +- FMT_CONSTEXPR auto on_arg_id(int id) -> int { +- return context_.check_arg_id(id), id; +- } +- FMT_CONSTEXPR auto on_arg_id(basic_string_view id) -> int { +-#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +- auto index = get_arg_index_by_name(id); +- if (index == invalid_arg_index) on_error("named argument is not found"); +- return context_.check_arg_id(index), index; +-#else +- (void)id; +- on_error("compile-time checks for named arguments require C++20 support"); +- return 0; +-#endif +- } +- +- FMT_CONSTEXPR void on_replacement_field(int, const Char*) {} +- +- FMT_CONSTEXPR auto on_format_specs(int id, const Char* begin, const Char*) +- -> const Char* { +- context_.advance_to(context_.begin() + (begin - &*context_.begin())); +- // id >= 0 check is a workaround for gcc 10 bug (#2065). +- return id >= 0 && id < num_args ? parse_funcs_[id](context_) : begin; +- } +- +- FMT_CONSTEXPR void on_error(const char* message) { +- context_.on_error(message); +- } +-}; +- +-template ::value), int>> +-void check_format_string(S format_str) { +- FMT_CONSTEXPR auto s = to_string_view(format_str); +- using checker = format_string_checker...>; +- FMT_CONSTEXPR bool invalid_format = +- (parse_format_string(s, checker(s, {})), true); +- ignore_unused(invalid_format); +-} +- +-template +-void vformat_to( +- buffer& buf, basic_string_view fmt, +- basic_format_args)> args, +- locale_ref loc = {}); +- +-FMT_API void vprint_mojibake(std::FILE*, string_view, format_args); +-#ifndef _WIN32 +-inline void vprint_mojibake(std::FILE*, string_view, format_args) {} +-#endif +-FMT_END_DETAIL_NAMESPACE +- +-// A formatter specialization for the core types corresponding to detail::type +-// constants. +-template +-struct formatter::value != +- detail::type::custom_type>> { +- private: +- detail::dynamic_format_specs specs_; +- +- public: +- // Parses format specifiers stopping either at the end of the range or at the +- // terminating '}'. +- template +- FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { +- auto begin = ctx.begin(), end = ctx.end(); +- if (begin == end) return begin; +- using handler_type = detail::dynamic_specs_handler; +- auto type = detail::type_constant::value; +- auto checker = +- detail::specs_checker(handler_type(specs_, ctx), type); +- auto it = detail::parse_format_specs(begin, end, checker); +- auto eh = ctx.error_handler(); +- switch (type) { +- case detail::type::none_type: +- FMT_ASSERT(false, "invalid argument type"); +- break; +- case detail::type::bool_type: +- if (specs_.type == presentation_type::none || +- specs_.type == presentation_type::string) { +- break; +- } +- FMT_FALLTHROUGH; +- case detail::type::int_type: +- case detail::type::uint_type: +- case detail::type::long_long_type: +- case detail::type::ulong_long_type: +- case detail::type::int128_type: +- case detail::type::uint128_type: +- detail::check_int_type_spec(specs_.type, eh); +- break; +- case detail::type::char_type: +- detail::check_char_specs(specs_, eh); +- break; +- case detail::type::float_type: +- if (detail::const_check(FMT_USE_FLOAT)) +- detail::parse_float_type_spec(specs_, eh); +- else +- FMT_ASSERT(false, "float support disabled"); +- break; +- case detail::type::double_type: +- if (detail::const_check(FMT_USE_DOUBLE)) +- detail::parse_float_type_spec(specs_, eh); +- else +- FMT_ASSERT(false, "double support disabled"); +- break; +- case detail::type::long_double_type: +- if (detail::const_check(FMT_USE_LONG_DOUBLE)) +- detail::parse_float_type_spec(specs_, eh); +- else +- FMT_ASSERT(false, "long double support disabled"); +- break; +- case detail::type::cstring_type: +- detail::check_cstring_type_spec(specs_.type, eh); +- break; +- case detail::type::string_type: +- detail::check_string_type_spec(specs_.type, eh); +- break; +- case detail::type::pointer_type: +- detail::check_pointer_type_spec(specs_.type, eh); +- break; +- case detail::type::custom_type: +- // Custom format specifiers are checked in parse functions of +- // formatter specializations. +- break; +- } +- return it; +- } +- +- template +- FMT_CONSTEXPR auto format(const T& val, FormatContext& ctx) const +- -> decltype(ctx.out()); +-}; +- +-template struct basic_runtime { basic_string_view str; }; +- +-/** A compile-time format string. */ +-template class basic_format_string { +- private: +- basic_string_view str_; +- +- public: +- template >::value)> +- FMT_CONSTEVAL FMT_INLINE basic_format_string(const S& s) : str_(s) { +- static_assert( +- detail::count< +- (std::is_base_of>::value && +- std::is_reference::value)...>() == 0, +- "passing views as lvalues is disallowed"); +-#ifdef FMT_HAS_CONSTEVAL +- if constexpr (detail::count_named_args() == +- detail::count_statically_named_args()) { +- using checker = detail::format_string_checker...>; +- detail::parse_format_string(str_, checker(s, {})); +- } +-#else +- detail::check_format_string(s); +-#endif +- } +- basic_format_string(basic_runtime r) : str_(r.str) {} +- +- FMT_INLINE operator basic_string_view() const { return str_; } +-}; +- +-#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 +-// Workaround broken conversion on older gcc. +-template using format_string = string_view; +-template auto runtime(const S& s) -> basic_string_view> { +- return s; +-} +-#else +-template +-using format_string = basic_format_string...>; +-/** +- \rst +- Creates a runtime format string. +- +- **Example**:: +- +- // Check format string at runtime instead of compile-time. +- fmt::print(fmt::runtime("{:d}"), "I am not a number"); +- \endrst +- */ +-template auto runtime(const S& s) -> basic_runtime> { +- return {{s}}; +-} +-#endif +- +-FMT_API auto vformat(string_view fmt, format_args args) -> std::string; +- +-/** +- \rst +- Formats ``args`` according to specifications in ``fmt`` and returns the result +- as a string. +- +- **Example**:: +- +- #include +- std::string message = fmt::format("The answer is {}.", 42); +- \endrst +-*/ +-template +-FMT_NODISCARD FMT_INLINE auto format(format_string fmt, T&&... args) +- -> std::string { +- return vformat(fmt, fmt::make_format_args(args...)); +-} +- +-/** Formats a string and writes the output to ``out``. */ +-template ::value)> +-auto vformat_to(OutputIt out, string_view fmt, format_args args) -> OutputIt { +- using detail::get_buffer; +- auto&& buf = get_buffer(out); +- detail::vformat_to(buf, fmt, args, {}); +- return detail::get_iterator(buf); +-} +- +-/** +- \rst +- Formats ``args`` according to specifications in ``fmt``, writes the result to +- the output iterator ``out`` and returns the iterator past the end of the output +- range. `format_to` does not append a terminating null character. +- +- **Example**:: +- +- auto out = std::vector(); +- fmt::format_to(std::back_inserter(out), "{}", 42); +- \endrst +- */ +-template ::value)> +-FMT_INLINE auto format_to(OutputIt out, format_string fmt, T&&... args) +- -> OutputIt { +- return vformat_to(out, fmt, fmt::make_format_args(args...)); +-} +- +-template struct format_to_n_result { +- /** Iterator past the end of the output range. */ +- OutputIt out; +- /** Total (not truncated) output size. */ +- size_t size; +-}; +- +-template ::value)> +-auto vformat_to_n(OutputIt out, size_t n, string_view fmt, format_args args) +- -> format_to_n_result { +- using traits = detail::fixed_buffer_traits; +- auto buf = detail::iterator_buffer(out, n); +- detail::vformat_to(buf, fmt, args, {}); +- return {buf.out(), buf.count()}; +-} +- +-/** +- \rst +- Formats ``args`` according to specifications in ``fmt``, writes up to ``n`` +- characters of the result to the output iterator ``out`` and returns the total +- (not truncated) output size and the iterator past the end of the output range. +- `format_to_n` does not append a terminating null character. +- \endrst +- */ +-template ::value)> +-FMT_INLINE auto format_to_n(OutputIt out, size_t n, format_string fmt, +- T&&... args) -> format_to_n_result { +- return vformat_to_n(out, n, fmt, fmt::make_format_args(args...)); +-} +- +-/** Returns the number of chars in the output of ``format(fmt, args...)``. */ +-template +-FMT_NODISCARD FMT_INLINE auto formatted_size(format_string fmt, +- T&&... args) -> size_t { +- auto buf = detail::counting_buffer<>(); +- detail::vformat_to(buf, string_view(fmt), fmt::make_format_args(args...), {}); +- return buf.count(); +-} +- +-FMT_API void vprint(string_view fmt, format_args args); +-FMT_API void vprint(std::FILE* f, string_view fmt, format_args args); +- +-/** +- \rst +- Formats ``args`` according to specifications in ``fmt`` and writes the output +- to ``stdout``. +- +- **Example**:: +- +- fmt::print("Elapsed time: {0:.2f} seconds", 1.23); +- \endrst +- */ +-template +-FMT_INLINE void print(format_string fmt, T&&... args) { +- const auto& vargs = fmt::make_format_args(args...); +- return detail::is_utf8() ? vprint(fmt, vargs) +- : detail::vprint_mojibake(stdout, fmt, vargs); +-} +- +-/** +- \rst +- Formats ``args`` according to specifications in ``fmt`` and writes the +- output to the file ``f``. +- +- **Example**:: +- +- fmt::print(stderr, "Don't {}!", "panic"); +- \endrst +- */ +-template +-FMT_INLINE void print(std::FILE* f, format_string fmt, T&&... args) { +- const auto& vargs = fmt::make_format_args(args...); +- return detail::is_utf8() ? vprint(f, fmt, vargs) +- : detail::vprint_mojibake(f, fmt, vargs); +-} +- +-FMT_MODULE_EXPORT_END +-FMT_GCC_PRAGMA("GCC pop_options") +-FMT_END_NAMESPACE +- +-#ifdef FMT_HEADER_ONLY +-# include "format.h" +-#endif +-#endif // FMT_CORE_H_ +diff --git a/include/dpp/fmt/format-inl.h b/include/dpp/fmt/format-inl.h +deleted file mode 100644 +index 5902bf1..0000000 +--- a/include/dpp/fmt/format-inl.h ++++ /dev/null +@@ -1,2643 +0,0 @@ +-// Formatting library for C++ - implementation +-// +-// Copyright (c) 2012 - 2016, Victor Zverovich +-// All rights reserved. +-// +-// For the license information refer to format.h. +- +-#ifndef FMT_FORMAT_INL_H_ +-#define FMT_FORMAT_INL_H_ +- +-#include +-#include +-#include // errno +-#include +-#include +-#include +-#include // std::memmove +-#include +-#include +- +-#ifndef FMT_STATIC_THOUSANDS_SEPARATOR +-# include +-#endif +- +-#ifdef _WIN32 +-# include // _isatty +-#endif +- +-#include "format.h" +- +-FMT_BEGIN_NAMESPACE +-namespace detail { +- +-FMT_FUNC void assert_fail(const char* file, int line, const char* message) { +- // Use unchecked std::fprintf to avoid triggering another assertion when +- // writing to stderr fails +- std::fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message); +- // Chosen instead of std::abort to satisfy Clang in CUDA mode during device +- // code pass. +- std::terminate(); +-} +- +-FMT_FUNC void throw_format_error(const char* message) { +- FMT_THROW(format_error(message)); +-} +- +-#ifndef _MSC_VER +-# define FMT_SNPRINTF snprintf +-#else // _MSC_VER +-inline int fmt_snprintf(char* buffer, size_t size, const char* format, ...) { +- va_list args; +- va_start(args, format); +- int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); +- va_end(args); +- return result; +-} +-# define FMT_SNPRINTF fmt_snprintf +-#endif // _MSC_VER +- +-FMT_FUNC void format_error_code(detail::buffer& out, int error_code, +- string_view message) FMT_NOEXCEPT { +- // Report error code making sure that the output fits into +- // inline_buffer_size to avoid dynamic memory allocation and potential +- // bad_alloc. +- out.try_resize(0); +- static const char SEP[] = ": "; +- static const char ERROR_STR[] = "error "; +- // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. +- size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; +- auto abs_value = static_cast>(error_code); +- if (detail::is_negative(error_code)) { +- abs_value = 0 - abs_value; +- ++error_code_size; +- } +- error_code_size += detail::to_unsigned(detail::count_digits(abs_value)); +- auto it = buffer_appender(out); +- if (message.size() <= inline_buffer_size - error_code_size) +- format_to(it, FMT_STRING("{}{}"), message, SEP); +- format_to(it, FMT_STRING("{}{}"), ERROR_STR, error_code); +- FMT_ASSERT(out.size() <= inline_buffer_size, ""); +-} +- +-FMT_FUNC void report_error(format_func func, int error_code, +- const char* message) FMT_NOEXCEPT { +- memory_buffer full_message; +- func(full_message, error_code, message); +- // Don't use fwrite_fully because the latter may throw. +- if (std::fwrite(full_message.data(), full_message.size(), 1, stderr) > 0) +- std::fputc('\n', stderr); +-} +- +-// A wrapper around fwrite that throws on error. +-inline void fwrite_fully(const void* ptr, size_t size, size_t count, +- FILE* stream) { +- size_t written = std::fwrite(ptr, size, count, stream); +- if (written < count) FMT_THROW(system_error(errno, "cannot write to file")); +-} +- +-#ifndef FMT_STATIC_THOUSANDS_SEPARATOR +-template +-locale_ref::locale_ref(const Locale& loc) : locale_(&loc) { +- static_assert(std::is_same::value, ""); +-} +- +-template Locale locale_ref::get() const { +- static_assert(std::is_same::value, ""); +- return locale_ ? *static_cast(locale_) : std::locale(); +-} +- +-template +-FMT_FUNC auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result { +- auto& facet = std::use_facet>(loc.get()); +- auto grouping = facet.grouping(); +- auto thousands_sep = grouping.empty() ? Char() : facet.thousands_sep(); +- return {std::move(grouping), thousands_sep}; +-} +-template FMT_FUNC Char decimal_point_impl(locale_ref loc) { +- return std::use_facet>(loc.get()) +- .decimal_point(); +-} +-#else +-template +-FMT_FUNC auto thousands_sep_impl(locale_ref) -> thousands_sep_result { +- return {"\03", FMT_STATIC_THOUSANDS_SEPARATOR}; +-} +-template FMT_FUNC Char decimal_point_impl(locale_ref) { +- return '.'; +-} +-#endif +-} // namespace detail +- +-#if !FMT_MSC_VER +-FMT_API FMT_FUNC format_error::~format_error() FMT_NOEXCEPT = default; +-#endif +- +-FMT_FUNC std::system_error vsystem_error(int error_code, string_view format_str, +- format_args args) { +- auto ec = std::error_code(error_code, std::generic_category()); +- return std::system_error(ec, vformat(format_str, args)); +-} +- +-namespace detail { +- +-template <> FMT_FUNC int count_digits<4>(detail::fallback_uintptr n) { +- // fallback_uintptr is always stored in little endian. +- int i = static_cast(sizeof(void*)) - 1; +- while (i > 0 && n.value[i] == 0) --i; +- auto char_digits = std::numeric_limits::digits / 4; +- return i >= 0 ? i * char_digits + count_digits<4, unsigned>(n.value[i]) : 1; +-} +- +-// log10(2) = 0x0.4d104d427de7fbcc... +-static constexpr uint64_t log10_2_significand = 0x4d104d427de7fbcc; +- +-template struct basic_impl_data { +- // Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340. +- // These are generated by support/compute-powers.py. +- static constexpr uint64_t pow10_significands[87] = { +- 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76, +- 0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, +- 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c, +- 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5, +- 0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57, +- 0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7, +- 0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e, +- 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996, +- 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126, +- 0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053, +- 0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f, +- 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b, +- 0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06, +- 0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb, +- 0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000, +- 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984, +- 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068, +- 0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8, +- 0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758, +- 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85, +- 0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d, +- 0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25, +- 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2, +- 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a, +- 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410, +- 0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129, +- 0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85, +- 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841, +- 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b, +- }; +- +-#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 +-# pragma GCC diagnostic push +-# pragma GCC diagnostic ignored "-Wnarrowing" +-#endif +- // Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding +- // to significands above. +- static constexpr int16_t pow10_exponents[87] = { +- -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, +- -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661, +- -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, +- -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, +- -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, +- 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, +- 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, +- 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066}; +-#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 +-# pragma GCC diagnostic pop +-#endif +- +- static constexpr uint64_t power_of_10_64[20] = { +- 1, FMT_POWERS_OF_10(1ULL), FMT_POWERS_OF_10(1000000000ULL), +- 10000000000000000000ULL}; +-}; +- +-// This is a struct rather than an alias to avoid shadowing warnings in gcc. +-struct impl_data : basic_impl_data<> {}; +- +-#if __cplusplus < 201703L +-template +-constexpr uint64_t basic_impl_data::pow10_significands[]; +-template constexpr int16_t basic_impl_data::pow10_exponents[]; +-template constexpr uint64_t basic_impl_data::power_of_10_64[]; +-#endif +- +-template struct bits { +- static FMT_CONSTEXPR_DECL const int value = +- static_cast(sizeof(T) * std::numeric_limits::digits); +-}; +- +-// Returns the number of significand bits in Float excluding the implicit bit. +-template constexpr int num_significand_bits() { +- // Subtract 1 to account for an implicit most significant bit in the +- // normalized form. +- return std::numeric_limits::digits - 1; +-} +- +-// A floating-point number f * pow(2, e). +-struct fp { +- uint64_t f; +- int e; +- +- static constexpr const int num_significand_bits = bits::value; +- +- constexpr fp() : f(0), e(0) {} +- constexpr fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {} +- +- // Constructs fp from an IEEE754 floating-point number. It is a template to +- // prevent compile errors on systems where n is not IEEE754. +- template explicit FMT_CONSTEXPR fp(Float n) { assign(n); } +- +- template +- using is_supported = bool_constant; +- +- // Assigns d to this and return true iff predecessor is closer than successor. +- template ::value)> +- FMT_CONSTEXPR bool assign(Float n) { +- // Assume float is in the format [sign][exponent][significand]. +- const int num_float_significand_bits = +- detail::num_significand_bits(); +- const uint64_t implicit_bit = 1ULL << num_float_significand_bits; +- const uint64_t significand_mask = implicit_bit - 1; +- constexpr bool is_double = sizeof(Float) == sizeof(uint64_t); +- auto u = bit_cast>(n); +- f = u & significand_mask; +- const uint64_t exponent_mask = (~0ULL >> 1) & ~significand_mask; +- int biased_e = +- static_cast((u & exponent_mask) >> num_float_significand_bits); +- // The predecessor is closer if n is a normalized power of 2 (f == 0) other +- // than the smallest normalized number (biased_e > 1). +- bool is_predecessor_closer = f == 0 && biased_e > 1; +- if (biased_e != 0) +- f += implicit_bit; +- else +- biased_e = 1; // Subnormals use biased exponent 1 (min exponent). +- const int exponent_bias = std::numeric_limits::max_exponent - 1; +- e = biased_e - exponent_bias - num_float_significand_bits; +- return is_predecessor_closer; +- } +- +- template ::value)> +- bool assign(Float) { +- FMT_ASSERT(false, ""); +- return false; +- } +-}; +- +-// Normalizes the value converted from double and multiplied by (1 << SHIFT). +-template FMT_CONSTEXPR fp normalize(fp value) { +- // Handle subnormals. +- const uint64_t implicit_bit = 1ULL << num_significand_bits(); +- const auto shifted_implicit_bit = implicit_bit << SHIFT; +- while ((value.f & shifted_implicit_bit) == 0) { +- value.f <<= 1; +- --value.e; +- } +- // Subtract 1 to account for hidden bit. +- const auto offset = +- fp::num_significand_bits - num_significand_bits() - SHIFT - 1; +- value.f <<= offset; +- value.e -= offset; +- return value; +-} +- +-inline bool operator==(fp x, fp y) { return x.f == y.f && x.e == y.e; } +- +-// Computes lhs * rhs / pow(2, 64) rounded to nearest with half-up tie breaking. +-FMT_CONSTEXPR inline uint64_t multiply(uint64_t lhs, uint64_t rhs) { +-#if FMT_USE_INT128 +- auto product = static_cast<__uint128_t>(lhs) * rhs; +- auto f = static_cast(product >> 64); +- return (static_cast(product) & (1ULL << 63)) != 0 ? f + 1 : f; +-#else +- // Multiply 32-bit parts of significands. +- uint64_t mask = (1ULL << 32) - 1; +- uint64_t a = lhs >> 32, b = lhs & mask; +- uint64_t c = rhs >> 32, d = rhs & mask; +- uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d; +- // Compute mid 64-bit of result and round. +- uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31); +- return ac + (ad >> 32) + (bc >> 32) + (mid >> 32); +-#endif +-} +- +-FMT_CONSTEXPR inline fp operator*(fp x, fp y) { +- return {multiply(x.f, y.f), x.e + y.e + 64}; +-} +- +-// Returns a cached power of 10 `c_k = c_k.f * pow(2, c_k.e)` such that its +-// (binary) exponent satisfies `min_exponent <= c_k.e <= min_exponent + 28`. +-FMT_CONSTEXPR inline fp get_cached_power(int min_exponent, +- int& pow10_exponent) { +- const int shift = 32; +- const auto significand = static_cast(log10_2_significand); +- int index = static_cast( +- ((min_exponent + fp::num_significand_bits - 1) * (significand >> shift) + +- ((int64_t(1) << shift) - 1)) // ceil +- >> 32 // arithmetic shift +- ); +- // Decimal exponent of the first (smallest) cached power of 10. +- const int first_dec_exp = -348; +- // Difference between 2 consecutive decimal exponents in cached powers of 10. +- const int dec_exp_step = 8; +- index = (index - first_dec_exp - 1) / dec_exp_step + 1; +- pow10_exponent = first_dec_exp + index * dec_exp_step; +- return {impl_data::pow10_significands[index], +- impl_data::pow10_exponents[index]}; +-} +- +-// A simple accumulator to hold the sums of terms in bigint::square if uint128_t +-// is not available. +-struct accumulator { +- uint64_t lower; +- uint64_t upper; +- +- constexpr accumulator() : lower(0), upper(0) {} +- constexpr explicit operator uint32_t() const { +- return static_cast(lower); +- } +- +- FMT_CONSTEXPR void operator+=(uint64_t n) { +- lower += n; +- if (lower < n) ++upper; +- } +- FMT_CONSTEXPR void operator>>=(int shift) { +- FMT_ASSERT(shift == 32, ""); +- (void)shift; +- lower = (upper << 32) | (lower >> 32); +- upper >>= 32; +- } +-}; +- +-class bigint { +- private: +- // A bigint is stored as an array of bigits (big digits), with bigit at index +- // 0 being the least significant one. +- using bigit = uint32_t; +- using double_bigit = uint64_t; +- enum { bigits_capacity = 32 }; +- basic_memory_buffer bigits_; +- int exp_; +- +- FMT_CONSTEXPR20 bigit operator[](int index) const { +- return bigits_[to_unsigned(index)]; +- } +- FMT_CONSTEXPR20 bigit& operator[](int index) { +- return bigits_[to_unsigned(index)]; +- } +- +- static FMT_CONSTEXPR_DECL const int bigit_bits = bits::value; +- +- friend struct formatter; +- +- FMT_CONSTEXPR20 void subtract_bigits(int index, bigit other, bigit& borrow) { +- auto result = static_cast((*this)[index]) - other - borrow; +- (*this)[index] = static_cast(result); +- borrow = static_cast(result >> (bigit_bits * 2 - 1)); +- } +- +- FMT_CONSTEXPR20 void remove_leading_zeros() { +- int num_bigits = static_cast(bigits_.size()) - 1; +- while (num_bigits > 0 && (*this)[num_bigits] == 0) --num_bigits; +- bigits_.resize(to_unsigned(num_bigits + 1)); +- } +- +- // Computes *this -= other assuming aligned bigints and *this >= other. +- FMT_CONSTEXPR20 void subtract_aligned(const bigint& other) { +- FMT_ASSERT(other.exp_ >= exp_, "unaligned bigints"); +- FMT_ASSERT(compare(*this, other) >= 0, ""); +- bigit borrow = 0; +- int i = other.exp_ - exp_; +- for (size_t j = 0, n = other.bigits_.size(); j != n; ++i, ++j) +- subtract_bigits(i, other.bigits_[j], borrow); +- while (borrow > 0) subtract_bigits(i, 0, borrow); +- remove_leading_zeros(); +- } +- +- FMT_CONSTEXPR20 void multiply(uint32_t value) { +- const double_bigit wide_value = value; +- bigit carry = 0; +- for (size_t i = 0, n = bigits_.size(); i < n; ++i) { +- double_bigit result = bigits_[i] * wide_value + carry; +- bigits_[i] = static_cast(result); +- carry = static_cast(result >> bigit_bits); +- } +- if (carry != 0) bigits_.push_back(carry); +- } +- +- FMT_CONSTEXPR20 void multiply(uint64_t value) { +- const bigit mask = ~bigit(0); +- const double_bigit lower = value & mask; +- const double_bigit upper = value >> bigit_bits; +- double_bigit carry = 0; +- for (size_t i = 0, n = bigits_.size(); i < n; ++i) { +- double_bigit result = bigits_[i] * lower + (carry & mask); +- carry = +- bigits_[i] * upper + (result >> bigit_bits) + (carry >> bigit_bits); +- bigits_[i] = static_cast(result); +- } +- while (carry != 0) { +- bigits_.push_back(carry & mask); +- carry >>= bigit_bits; +- } +- } +- +- public: +- FMT_CONSTEXPR20 bigint() : exp_(0) {} +- explicit bigint(uint64_t n) { assign(n); } +- FMT_CONSTEXPR20 ~bigint() { +- FMT_ASSERT(bigits_.capacity() <= bigits_capacity, ""); +- } +- +- bigint(const bigint&) = delete; +- void operator=(const bigint&) = delete; +- +- FMT_CONSTEXPR20 void assign(const bigint& other) { +- auto size = other.bigits_.size(); +- bigits_.resize(size); +- auto data = other.bigits_.data(); +- std::copy(data, data + size, make_checked(bigits_.data(), size)); +- exp_ = other.exp_; +- } +- +- FMT_CONSTEXPR20 void assign(uint64_t n) { +- size_t num_bigits = 0; +- do { +- bigits_[num_bigits++] = n & ~bigit(0); +- n >>= bigit_bits; +- } while (n != 0); +- bigits_.resize(num_bigits); +- exp_ = 0; +- } +- +- FMT_CONSTEXPR20 int num_bigits() const { +- return static_cast(bigits_.size()) + exp_; +- } +- +- FMT_NOINLINE FMT_CONSTEXPR20 bigint& operator<<=(int shift) { +- FMT_ASSERT(shift >= 0, ""); +- exp_ += shift / bigit_bits; +- shift %= bigit_bits; +- if (shift == 0) return *this; +- bigit carry = 0; +- for (size_t i = 0, n = bigits_.size(); i < n; ++i) { +- bigit c = bigits_[i] >> (bigit_bits - shift); +- bigits_[i] = (bigits_[i] << shift) + carry; +- carry = c; +- } +- if (carry != 0) bigits_.push_back(carry); +- return *this; +- } +- +- template FMT_CONSTEXPR20 bigint& operator*=(Int value) { +- FMT_ASSERT(value > 0, ""); +- multiply(uint32_or_64_or_128_t(value)); +- return *this; +- } +- +- friend FMT_CONSTEXPR20 int compare(const bigint& lhs, const bigint& rhs) { +- int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits(); +- if (num_lhs_bigits != num_rhs_bigits) +- return num_lhs_bigits > num_rhs_bigits ? 1 : -1; +- int i = static_cast(lhs.bigits_.size()) - 1; +- int j = static_cast(rhs.bigits_.size()) - 1; +- int end = i - j; +- if (end < 0) end = 0; +- for (; i >= end; --i, --j) { +- bigit lhs_bigit = lhs[i], rhs_bigit = rhs[j]; +- if (lhs_bigit != rhs_bigit) return lhs_bigit > rhs_bigit ? 1 : -1; +- } +- if (i != j) return i > j ? 1 : -1; +- return 0; +- } +- +- // Returns compare(lhs1 + lhs2, rhs). +- friend FMT_CONSTEXPR20 int add_compare(const bigint& lhs1, const bigint& lhs2, +- const bigint& rhs) { +- int max_lhs_bigits = (std::max)(lhs1.num_bigits(), lhs2.num_bigits()); +- int num_rhs_bigits = rhs.num_bigits(); +- if (max_lhs_bigits + 1 < num_rhs_bigits) return -1; +- if (max_lhs_bigits > num_rhs_bigits) return 1; +- auto get_bigit = [](const bigint& n, int i) -> bigit { +- return i >= n.exp_ && i < n.num_bigits() ? n[i - n.exp_] : 0; +- }; +- double_bigit borrow = 0; +- int min_exp = (std::min)((std::min)(lhs1.exp_, lhs2.exp_), rhs.exp_); +- for (int i = num_rhs_bigits - 1; i >= min_exp; --i) { +- double_bigit sum = +- static_cast(get_bigit(lhs1, i)) + get_bigit(lhs2, i); +- bigit rhs_bigit = get_bigit(rhs, i); +- if (sum > rhs_bigit + borrow) return 1; +- borrow = rhs_bigit + borrow - sum; +- if (borrow > 1) return -1; +- borrow <<= bigit_bits; +- } +- return borrow != 0 ? -1 : 0; +- } +- +- // Assigns pow(10, exp) to this bigint. +- FMT_CONSTEXPR20 void assign_pow10(int exp) { +- FMT_ASSERT(exp >= 0, ""); +- if (exp == 0) return assign(1); +- // Find the top bit. +- int bitmask = 1; +- while (exp >= bitmask) bitmask <<= 1; +- bitmask >>= 1; +- // pow(10, exp) = pow(5, exp) * pow(2, exp). First compute pow(5, exp) by +- // repeated squaring and multiplication. +- assign(5); +- bitmask >>= 1; +- while (bitmask != 0) { +- square(); +- if ((exp & bitmask) != 0) *this *= 5; +- bitmask >>= 1; +- } +- *this <<= exp; // Multiply by pow(2, exp) by shifting. +- } +- +- FMT_CONSTEXPR20 void square() { +- int num_bigits = static_cast(bigits_.size()); +- int num_result_bigits = 2 * num_bigits; +- basic_memory_buffer n(std::move(bigits_)); +- bigits_.resize(to_unsigned(num_result_bigits)); +- using accumulator_t = conditional_t; +- auto sum = accumulator_t(); +- for (int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) { +- // Compute bigit at position bigit_index of the result by adding +- // cross-product terms n[i] * n[j] such that i + j == bigit_index. +- for (int i = 0, j = bigit_index; j >= 0; ++i, --j) { +- // Most terms are multiplied twice which can be optimized in the future. +- sum += static_cast(n[i]) * n[j]; +- } +- (*this)[bigit_index] = static_cast(sum); +- sum >>= bits::value; // Compute the carry. +- } +- // Do the same for the top half. +- for (int bigit_index = num_bigits; bigit_index < num_result_bigits; +- ++bigit_index) { +- for (int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;) +- sum += static_cast(n[i++]) * n[j--]; +- (*this)[bigit_index] = static_cast(sum); +- sum >>= bits::value; +- } +- remove_leading_zeros(); +- exp_ *= 2; +- } +- +- // If this bigint has a bigger exponent than other, adds trailing zero to make +- // exponents equal. This simplifies some operations such as subtraction. +- FMT_CONSTEXPR20 void align(const bigint& other) { +- int exp_difference = exp_ - other.exp_; +- if (exp_difference <= 0) return; +- int num_bigits = static_cast(bigits_.size()); +- bigits_.resize(to_unsigned(num_bigits + exp_difference)); +- for (int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j) +- bigits_[j] = bigits_[i]; +- std::uninitialized_fill_n(bigits_.data(), exp_difference, 0); +- exp_ -= exp_difference; +- } +- +- // Divides this bignum by divisor, assigning the remainder to this and +- // returning the quotient. +- FMT_CONSTEXPR20 int divmod_assign(const bigint& divisor) { +- FMT_ASSERT(this != &divisor, ""); +- if (compare(*this, divisor) < 0) return 0; +- FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0, ""); +- align(divisor); +- int quotient = 0; +- do { +- subtract_aligned(divisor); +- ++quotient; +- } while (compare(*this, divisor) >= 0); +- return quotient; +- } +-}; +- +-enum class round_direction { unknown, up, down }; +- +-// Given the divisor (normally a power of 10), the remainder = v % divisor for +-// some number v and the error, returns whether v should be rounded up, down, or +-// whether the rounding direction can't be determined due to error. +-// error should be less than divisor / 2. +-FMT_CONSTEXPR inline round_direction get_round_direction(uint64_t divisor, +- uint64_t remainder, +- uint64_t error) { +- FMT_ASSERT(remainder < divisor, ""); // divisor - remainder won't overflow. +- FMT_ASSERT(error < divisor, ""); // divisor - error won't overflow. +- FMT_ASSERT(error < divisor - error, ""); // error * 2 won't overflow. +- // Round down if (remainder + error) * 2 <= divisor. +- if (remainder <= divisor - remainder && error * 2 <= divisor - remainder * 2) +- return round_direction::down; +- // Round up if (remainder - error) * 2 >= divisor. +- if (remainder >= error && +- remainder - error >= divisor - (remainder - error)) { +- return round_direction::up; +- } +- return round_direction::unknown; +-} +- +-namespace digits { +-enum result { +- more, // Generate more digits. +- done, // Done generating digits. +- error // Digit generation cancelled due to an error. +-}; +-} +- +-struct gen_digits_handler { +- char* buf; +- int size; +- int precision; +- int exp10; +- bool fixed; +- +- FMT_CONSTEXPR digits::result on_digit(char digit, uint64_t divisor, +- uint64_t remainder, uint64_t error, +- bool integral) { +- FMT_ASSERT(remainder < divisor, ""); +- buf[size++] = digit; +- if (!integral && error >= remainder) return digits::error; +- if (size < precision) return digits::more; +- if (!integral) { +- // Check if error * 2 < divisor with overflow prevention. +- // The check is not needed for the integral part because error = 1 +- // and divisor > (1 << 32) there. +- if (error >= divisor || error >= divisor - error) return digits::error; +- } else { +- FMT_ASSERT(error == 1 && divisor > 2, ""); +- } +- auto dir = get_round_direction(divisor, remainder, error); +- if (dir != round_direction::up) +- return dir == round_direction::down ? digits::done : digits::error; +- ++buf[size - 1]; +- for (int i = size - 1; i > 0 && buf[i] > '9'; --i) { +- buf[i] = '0'; +- ++buf[i - 1]; +- } +- if (buf[0] > '9') { +- buf[0] = '1'; +- if (fixed) +- buf[size++] = '0'; +- else +- ++exp10; +- } +- return digits::done; +- } +-}; +- +-// Generates output using the Grisu digit-gen algorithm. +-// error: the size of the region (lower, upper) outside of which numbers +-// definitely do not round to value (Delta in Grisu3). +-FMT_INLINE FMT_CONSTEXPR20 digits::result grisu_gen_digits( +- fp value, uint64_t error, int& exp, gen_digits_handler& handler) { +- const fp one(1ULL << -value.e, value.e); +- // The integral part of scaled value (p1 in Grisu) = value / one. It cannot be +- // zero because it contains a product of two 64-bit numbers with MSB set (due +- // to normalization) - 1, shifted right by at most 60 bits. +- auto integral = static_cast(value.f >> -one.e); +- FMT_ASSERT(integral != 0, ""); +- FMT_ASSERT(integral == value.f >> -one.e, ""); +- // The fractional part of scaled value (p2 in Grisu) c = value % one. +- uint64_t fractional = value.f & (one.f - 1); +- exp = count_digits(integral); // kappa in Grisu. +- // Non-fixed formats require at least one digit and no precision adjustment. +- if (handler.fixed) { +- // Adjust fixed precision by exponent because it is relative to decimal +- // point. +- int precision_offset = exp + handler.exp10; +- if (precision_offset > 0 && +- handler.precision > max_value() - precision_offset) { +- FMT_THROW(format_error("number is too big")); +- } +- handler.precision += precision_offset; +- // Check if precision is satisfied just by leading zeros, e.g. +- // format("{:.2f}", 0.001) gives "0.00" without generating any digits. +- if (handler.precision <= 0) { +- if (handler.precision < 0) return digits::done; +- // Divide by 10 to prevent overflow. +- uint64_t divisor = impl_data::power_of_10_64[exp - 1] << -one.e; +- auto dir = get_round_direction(divisor, value.f / 10, error * 10); +- if (dir == round_direction::unknown) return digits::error; +- handler.buf[handler.size++] = dir == round_direction::up ? '1' : '0'; +- return digits::done; +- } +- } +- // Generate digits for the integral part. This can produce up to 10 digits. +- do { +- uint32_t digit = 0; +- auto divmod_integral = [&](uint32_t divisor) { +- digit = integral / divisor; +- integral %= divisor; +- }; +- // This optimization by Milo Yip reduces the number of integer divisions by +- // one per iteration. +- switch (exp) { +- case 10: +- divmod_integral(1000000000); +- break; +- case 9: +- divmod_integral(100000000); +- break; +- case 8: +- divmod_integral(10000000); +- break; +- case 7: +- divmod_integral(1000000); +- break; +- case 6: +- divmod_integral(100000); +- break; +- case 5: +- divmod_integral(10000); +- break; +- case 4: +- divmod_integral(1000); +- break; +- case 3: +- divmod_integral(100); +- break; +- case 2: +- divmod_integral(10); +- break; +- case 1: +- digit = integral; +- integral = 0; +- break; +- default: +- FMT_ASSERT(false, "invalid number of digits"); +- } +- --exp; +- auto remainder = (static_cast(integral) << -one.e) + fractional; +- auto result = handler.on_digit(static_cast('0' + digit), +- impl_data::power_of_10_64[exp] << -one.e, +- remainder, error, true); +- if (result != digits::more) return result; +- } while (exp > 0); +- // Generate digits for the fractional part. +- for (;;) { +- fractional *= 10; +- error *= 10; +- char digit = static_cast('0' + (fractional >> -one.e)); +- fractional &= one.f - 1; +- --exp; +- auto result = handler.on_digit(digit, one.f, fractional, error, false); +- if (result != digits::more) return result; +- } +-} +- +-// A 128-bit integer type used internally, +-struct uint128_wrapper { +- uint128_wrapper() = default; +- +-#if FMT_USE_INT128 +- uint128_t internal_; +- +- constexpr uint128_wrapper(uint64_t high, uint64_t low) FMT_NOEXCEPT +- : internal_{static_cast(low) | +- (static_cast(high) << 64)} {} +- +- constexpr uint128_wrapper(uint128_t u) : internal_{u} {} +- +- constexpr uint64_t high() const FMT_NOEXCEPT { +- return uint64_t(internal_ >> 64); +- } +- constexpr uint64_t low() const FMT_NOEXCEPT { return uint64_t(internal_); } +- +- uint128_wrapper& operator+=(uint64_t n) FMT_NOEXCEPT { +- internal_ += n; +- return *this; +- } +-#else +- uint64_t high_; +- uint64_t low_; +- +- constexpr uint128_wrapper(uint64_t high, uint64_t low) FMT_NOEXCEPT +- : high_{high}, +- low_{low} {} +- +- constexpr uint64_t high() const FMT_NOEXCEPT { return high_; } +- constexpr uint64_t low() const FMT_NOEXCEPT { return low_; } +- +- uint128_wrapper& operator+=(uint64_t n) FMT_NOEXCEPT { +-# if defined(_MSC_VER) && defined(_M_X64) +- unsigned char carry = _addcarry_u64(0, low_, n, &low_); +- _addcarry_u64(carry, high_, 0, &high_); +- return *this; +-# else +- uint64_t sum = low_ + n; +- high_ += (sum < low_ ? 1 : 0); +- low_ = sum; +- return *this; +-# endif +- } +-#endif +-}; +- +-// Implementation of Dragonbox algorithm: https://github.com/jk-jeon/dragonbox. +-namespace dragonbox { +-// Computes 128-bit result of multiplication of two 64-bit unsigned integers. +-inline uint128_wrapper umul128(uint64_t x, uint64_t y) FMT_NOEXCEPT { +-#if FMT_USE_INT128 +- return static_cast(x) * static_cast(y); +-#elif defined(_MSC_VER) && defined(_M_X64) +- uint128_wrapper result; +- result.low_ = _umul128(x, y, &result.high_); +- return result; +-#else +- const uint64_t mask = (uint64_t(1) << 32) - uint64_t(1); +- +- uint64_t a = x >> 32; +- uint64_t b = x & mask; +- uint64_t c = y >> 32; +- uint64_t d = y & mask; +- +- uint64_t ac = a * c; +- uint64_t bc = b * c; +- uint64_t ad = a * d; +- uint64_t bd = b * d; +- +- uint64_t intermediate = (bd >> 32) + (ad & mask) + (bc & mask); +- +- return {ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32), +- (intermediate << 32) + (bd & mask)}; +-#endif +-} +- +-// Computes upper 64 bits of multiplication of two 64-bit unsigned integers. +-inline uint64_t umul128_upper64(uint64_t x, uint64_t y) FMT_NOEXCEPT { +-#if FMT_USE_INT128 +- auto p = static_cast(x) * static_cast(y); +- return static_cast(p >> 64); +-#elif defined(_MSC_VER) && defined(_M_X64) +- return __umulh(x, y); +-#else +- return umul128(x, y).high(); +-#endif +-} +- +-// Computes upper 64 bits of multiplication of a 64-bit unsigned integer and a +-// 128-bit unsigned integer. +-inline uint64_t umul192_upper64(uint64_t x, uint128_wrapper y) FMT_NOEXCEPT { +- uint128_wrapper g0 = umul128(x, y.high()); +- g0 += umul128_upper64(x, y.low()); +- return g0.high(); +-} +- +-// Computes upper 32 bits of multiplication of a 32-bit unsigned integer and a +-// 64-bit unsigned integer. +-inline uint32_t umul96_upper32(uint32_t x, uint64_t y) FMT_NOEXCEPT { +- return static_cast(umul128_upper64(x, y)); +-} +- +-// Computes middle 64 bits of multiplication of a 64-bit unsigned integer and a +-// 128-bit unsigned integer. +-inline uint64_t umul192_middle64(uint64_t x, uint128_wrapper y) FMT_NOEXCEPT { +- uint64_t g01 = x * y.high(); +- uint64_t g10 = umul128_upper64(x, y.low()); +- return g01 + g10; +-} +- +-// Computes lower 64 bits of multiplication of a 32-bit unsigned integer and a +-// 64-bit unsigned integer. +-inline uint64_t umul96_lower64(uint32_t x, uint64_t y) FMT_NOEXCEPT { +- return x * y; +-} +- +-// Computes floor(log10(pow(2, e))) for e in [-1700, 1700] using the method from +-// https://fmt.dev/papers/Grisu-Exact.pdf#page=5, section 3.4. +-inline int floor_log10_pow2(int e) FMT_NOEXCEPT { +- FMT_ASSERT(e <= 1700 && e >= -1700, "too large exponent"); +- const int shift = 22; +- return (e * static_cast(log10_2_significand >> (64 - shift))) >> shift; +-} +- +-// Various fast log computations. +-inline int floor_log2_pow10(int e) FMT_NOEXCEPT { +- FMT_ASSERT(e <= 1233 && e >= -1233, "too large exponent"); +- const uint64_t log2_10_integer_part = 3; +- const uint64_t log2_10_fractional_digits = 0x5269e12f346e2bf9; +- const int shift_amount = 19; +- return (e * static_cast( +- (log2_10_integer_part << shift_amount) | +- (log2_10_fractional_digits >> (64 - shift_amount)))) >> +- shift_amount; +-} +-inline int floor_log10_pow2_minus_log10_4_over_3(int e) FMT_NOEXCEPT { +- FMT_ASSERT(e <= 1700 && e >= -1700, "too large exponent"); +- const uint64_t log10_4_over_3_fractional_digits = 0x1ffbfc2bbc780375; +- const int shift_amount = 22; +- return (e * static_cast(log10_2_significand >> (64 - shift_amount)) - +- static_cast(log10_4_over_3_fractional_digits >> +- (64 - shift_amount))) >> +- shift_amount; +-} +- +-// Returns true iff x is divisible by pow(2, exp). +-inline bool divisible_by_power_of_2(uint32_t x, int exp) FMT_NOEXCEPT { +- FMT_ASSERT(exp >= 1, ""); +- FMT_ASSERT(x != 0, ""); +-#ifdef FMT_BUILTIN_CTZ +- return FMT_BUILTIN_CTZ(x) >= exp; +-#else +- return exp < num_bits() && x == ((x >> exp) << exp); +-#endif +-} +-inline bool divisible_by_power_of_2(uint64_t x, int exp) FMT_NOEXCEPT { +- FMT_ASSERT(exp >= 1, ""); +- FMT_ASSERT(x != 0, ""); +-#ifdef FMT_BUILTIN_CTZLL +- return FMT_BUILTIN_CTZLL(x) >= exp; +-#else +- return exp < num_bits() && x == ((x >> exp) << exp); +-#endif +-} +- +-// Table entry type for divisibility test. +-template struct divtest_table_entry { +- T mod_inv; +- T max_quotient; +-}; +- +-// Returns true iff x is divisible by pow(5, exp). +-inline bool divisible_by_power_of_5(uint32_t x, int exp) FMT_NOEXCEPT { +- FMT_ASSERT(exp <= 10, "too large exponent"); +- static constexpr const divtest_table_entry divtest_table[] = { +- {0x00000001, 0xffffffff}, {0xcccccccd, 0x33333333}, +- {0xc28f5c29, 0x0a3d70a3}, {0x26e978d5, 0x020c49ba}, +- {0x3afb7e91, 0x0068db8b}, {0x0bcbe61d, 0x0014f8b5}, +- {0x68c26139, 0x000431bd}, {0xae8d46a5, 0x0000d6bf}, +- {0x22e90e21, 0x00002af3}, {0x3a2e9c6d, 0x00000897}, +- {0x3ed61f49, 0x000001b7}}; +- return x * divtest_table[exp].mod_inv <= divtest_table[exp].max_quotient; +-} +-inline bool divisible_by_power_of_5(uint64_t x, int exp) FMT_NOEXCEPT { +- FMT_ASSERT(exp <= 23, "too large exponent"); +- static constexpr const divtest_table_entry divtest_table[] = { +- {0x0000000000000001, 0xffffffffffffffff}, +- {0xcccccccccccccccd, 0x3333333333333333}, +- {0x8f5c28f5c28f5c29, 0x0a3d70a3d70a3d70}, +- {0x1cac083126e978d5, 0x020c49ba5e353f7c}, +- {0xd288ce703afb7e91, 0x0068db8bac710cb2}, +- {0x5d4e8fb00bcbe61d, 0x0014f8b588e368f0}, +- {0x790fb65668c26139, 0x000431bde82d7b63}, +- {0xe5032477ae8d46a5, 0x0000d6bf94d5e57a}, +- {0xc767074b22e90e21, 0x00002af31dc46118}, +- {0x8e47ce423a2e9c6d, 0x0000089705f4136b}, +- {0x4fa7f60d3ed61f49, 0x000001b7cdfd9d7b}, +- {0x0fee64690c913975, 0x00000057f5ff85e5}, +- {0x3662e0e1cf503eb1, 0x000000119799812d}, +- {0xa47a2cf9f6433fbd, 0x0000000384b84d09}, +- {0x54186f653140a659, 0x00000000b424dc35}, +- {0x7738164770402145, 0x0000000024075f3d}, +- {0xe4a4d1417cd9a041, 0x000000000734aca5}, +- {0xc75429d9e5c5200d, 0x000000000170ef54}, +- {0xc1773b91fac10669, 0x000000000049c977}, +- {0x26b172506559ce15, 0x00000000000ec1e4}, +- {0xd489e3a9addec2d1, 0x000000000002f394}, +- {0x90e860bb892c8d5d, 0x000000000000971d}, +- {0x502e79bf1b6f4f79, 0x0000000000001e39}, +- {0xdcd618596be30fe5, 0x000000000000060b}}; +- return x * divtest_table[exp].mod_inv <= divtest_table[exp].max_quotient; +-} +- +-// Replaces n by floor(n / pow(5, N)) returning true if and only if n is +-// divisible by pow(5, N). +-// Precondition: n <= 2 * pow(5, N + 1). +-template +-bool check_divisibility_and_divide_by_pow5(uint32_t& n) FMT_NOEXCEPT { +- static constexpr struct { +- uint32_t magic_number; +- int bits_for_comparison; +- uint32_t threshold; +- int shift_amount; +- } infos[] = {{0xcccd, 16, 0x3333, 18}, {0xa429, 8, 0x0a, 20}}; +- constexpr auto info = infos[N - 1]; +- n *= info.magic_number; +- const uint32_t comparison_mask = (1u << info.bits_for_comparison) - 1; +- bool result = (n & comparison_mask) <= info.threshold; +- n >>= info.shift_amount; +- return result; +-} +- +-// Computes floor(n / pow(10, N)) for small n and N. +-// Precondition: n <= pow(10, N + 1). +-template uint32_t small_division_by_pow10(uint32_t n) FMT_NOEXCEPT { +- static constexpr struct { +- uint32_t magic_number; +- int shift_amount; +- uint32_t divisor_times_10; +- } infos[] = {{0xcccd, 19, 100}, {0xa3d8, 22, 1000}}; +- constexpr auto info = infos[N - 1]; +- FMT_ASSERT(n <= info.divisor_times_10, "n is too large"); +- return n * info.magic_number >> info.shift_amount; +-} +- +-// Computes floor(n / 10^(kappa + 1)) (float) +-inline uint32_t divide_by_10_to_kappa_plus_1(uint32_t n) FMT_NOEXCEPT { +- return n / float_info::big_divisor; +-} +-// Computes floor(n / 10^(kappa + 1)) (double) +-inline uint64_t divide_by_10_to_kappa_plus_1(uint64_t n) FMT_NOEXCEPT { +- return umul128_upper64(n, 0x83126e978d4fdf3c) >> 9; +-} +- +-// Various subroutines using pow10 cache +-template struct cache_accessor; +- +-template <> struct cache_accessor { +- using carrier_uint = float_info::carrier_uint; +- using cache_entry_type = uint64_t; +- +- static uint64_t get_cached_power(int k) FMT_NOEXCEPT { +- FMT_ASSERT(k >= float_info::min_k && k <= float_info::max_k, +- "k is out of range"); +- static constexpr const uint64_t pow10_significands[] = { +- 0x81ceb32c4b43fcf5, 0xa2425ff75e14fc32, 0xcad2f7f5359a3b3f, +- 0xfd87b5f28300ca0e, 0x9e74d1b791e07e49, 0xc612062576589ddb, +- 0xf79687aed3eec552, 0x9abe14cd44753b53, 0xc16d9a0095928a28, +- 0xf1c90080baf72cb2, 0x971da05074da7bef, 0xbce5086492111aeb, +- 0xec1e4a7db69561a6, 0x9392ee8e921d5d08, 0xb877aa3236a4b44a, +- 0xe69594bec44de15c, 0x901d7cf73ab0acda, 0xb424dc35095cd810, +- 0xe12e13424bb40e14, 0x8cbccc096f5088cc, 0xafebff0bcb24aaff, +- 0xdbe6fecebdedd5bf, 0x89705f4136b4a598, 0xabcc77118461cefd, +- 0xd6bf94d5e57a42bd, 0x8637bd05af6c69b6, 0xa7c5ac471b478424, +- 0xd1b71758e219652c, 0x83126e978d4fdf3c, 0xa3d70a3d70a3d70b, +- 0xcccccccccccccccd, 0x8000000000000000, 0xa000000000000000, +- 0xc800000000000000, 0xfa00000000000000, 0x9c40000000000000, +- 0xc350000000000000, 0xf424000000000000, 0x9896800000000000, +- 0xbebc200000000000, 0xee6b280000000000, 0x9502f90000000000, +- 0xba43b74000000000, 0xe8d4a51000000000, 0x9184e72a00000000, +- 0xb5e620f480000000, 0xe35fa931a0000000, 0x8e1bc9bf04000000, +- 0xb1a2bc2ec5000000, 0xde0b6b3a76400000, 0x8ac7230489e80000, +- 0xad78ebc5ac620000, 0xd8d726b7177a8000, 0x878678326eac9000, +- 0xa968163f0a57b400, 0xd3c21bcecceda100, 0x84595161401484a0, +- 0xa56fa5b99019a5c8, 0xcecb8f27f4200f3a, 0x813f3978f8940984, +- 0xa18f07d736b90be5, 0xc9f2c9cd04674ede, 0xfc6f7c4045812296, +- 0x9dc5ada82b70b59d, 0xc5371912364ce305, 0xf684df56c3e01bc6, +- 0x9a130b963a6c115c, 0xc097ce7bc90715b3, 0xf0bdc21abb48db20, +- 0x96769950b50d88f4, 0xbc143fa4e250eb31, 0xeb194f8e1ae525fd, +- 0x92efd1b8d0cf37be, 0xb7abc627050305ad, 0xe596b7b0c643c719, +- 0x8f7e32ce7bea5c6f, 0xb35dbf821ae4f38b, 0xe0352f62a19e306e}; +- return pow10_significands[k - float_info::min_k]; +- } +- +- static carrier_uint compute_mul(carrier_uint u, +- const cache_entry_type& cache) FMT_NOEXCEPT { +- return umul96_upper32(u, cache); +- } +- +- static uint32_t compute_delta(const cache_entry_type& cache, +- int beta_minus_1) FMT_NOEXCEPT { +- return static_cast(cache >> (64 - 1 - beta_minus_1)); +- } +- +- static bool compute_mul_parity(carrier_uint two_f, +- const cache_entry_type& cache, +- int beta_minus_1) FMT_NOEXCEPT { +- FMT_ASSERT(beta_minus_1 >= 1, ""); +- FMT_ASSERT(beta_minus_1 < 64, ""); +- +- return ((umul96_lower64(two_f, cache) >> (64 - beta_minus_1)) & 1) != 0; +- } +- +- static carrier_uint compute_left_endpoint_for_shorter_interval_case( +- const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT { +- return static_cast( +- (cache - (cache >> (float_info::significand_bits + 2))) >> +- (64 - float_info::significand_bits - 1 - beta_minus_1)); +- } +- +- static carrier_uint compute_right_endpoint_for_shorter_interval_case( +- const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT { +- return static_cast( +- (cache + (cache >> (float_info::significand_bits + 1))) >> +- (64 - float_info::significand_bits - 1 - beta_minus_1)); +- } +- +- static carrier_uint compute_round_up_for_shorter_interval_case( +- const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT { +- return (static_cast( +- cache >> +- (64 - float_info::significand_bits - 2 - beta_minus_1)) + +- 1) / +- 2; +- } +-}; +- +-template <> struct cache_accessor { +- using carrier_uint = float_info::carrier_uint; +- using cache_entry_type = uint128_wrapper; +- +- static uint128_wrapper get_cached_power(int k) FMT_NOEXCEPT { +- FMT_ASSERT(k >= float_info::min_k && k <= float_info::max_k, +- "k is out of range"); +- +- static constexpr const uint128_wrapper pow10_significands[] = { +-#if FMT_USE_FULL_CACHE_DRAGONBOX +- {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, +- {0x9faacf3df73609b1, 0x77b191618c54e9ad}, +- {0xc795830d75038c1d, 0xd59df5b9ef6a2418}, +- {0xf97ae3d0d2446f25, 0x4b0573286b44ad1e}, +- {0x9becce62836ac577, 0x4ee367f9430aec33}, +- {0xc2e801fb244576d5, 0x229c41f793cda740}, +- {0xf3a20279ed56d48a, 0x6b43527578c11110}, +- {0x9845418c345644d6, 0x830a13896b78aaaa}, +- {0xbe5691ef416bd60c, 0x23cc986bc656d554}, +- {0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa9}, +- {0x94b3a202eb1c3f39, 0x7bf7d71432f3d6aa}, +- {0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc54}, +- {0xe858ad248f5c22c9, 0xd1b3400f8f9cff69}, +- {0x91376c36d99995be, 0x23100809b9c21fa2}, +- {0xb58547448ffffb2d, 0xabd40a0c2832a78b}, +- {0xe2e69915b3fff9f9, 0x16c90c8f323f516d}, +- {0x8dd01fad907ffc3b, 0xae3da7d97f6792e4}, +- {0xb1442798f49ffb4a, 0x99cd11cfdf41779d}, +- {0xdd95317f31c7fa1d, 0x40405643d711d584}, +- {0x8a7d3eef7f1cfc52, 0x482835ea666b2573}, +- {0xad1c8eab5ee43b66, 0xda3243650005eed0}, +- {0xd863b256369d4a40, 0x90bed43e40076a83}, +- {0x873e4f75e2224e68, 0x5a7744a6e804a292}, +- {0xa90de3535aaae202, 0x711515d0a205cb37}, +- {0xd3515c2831559a83, 0x0d5a5b44ca873e04}, +- {0x8412d9991ed58091, 0xe858790afe9486c3}, +- {0xa5178fff668ae0b6, 0x626e974dbe39a873}, +- {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, +- {0x80fa687f881c7f8e, 0x7ce66634bc9d0b9a}, +- {0xa139029f6a239f72, 0x1c1fffc1ebc44e81}, +- {0xc987434744ac874e, 0xa327ffb266b56221}, +- {0xfbe9141915d7a922, 0x4bf1ff9f0062baa9}, +- {0x9d71ac8fada6c9b5, 0x6f773fc3603db4aa}, +- {0xc4ce17b399107c22, 0xcb550fb4384d21d4}, +- {0xf6019da07f549b2b, 0x7e2a53a146606a49}, +- {0x99c102844f94e0fb, 0x2eda7444cbfc426e}, +- {0xc0314325637a1939, 0xfa911155fefb5309}, +- {0xf03d93eebc589f88, 0x793555ab7eba27cb}, +- {0x96267c7535b763b5, 0x4bc1558b2f3458df}, +- {0xbbb01b9283253ca2, 0x9eb1aaedfb016f17}, +- {0xea9c227723ee8bcb, 0x465e15a979c1cadd}, +- {0x92a1958a7675175f, 0x0bfacd89ec191eca}, +- {0xb749faed14125d36, 0xcef980ec671f667c}, +- {0xe51c79a85916f484, 0x82b7e12780e7401b}, +- {0x8f31cc0937ae58d2, 0xd1b2ecb8b0908811}, +- {0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa16}, +- {0xdfbdcece67006ac9, 0x67a791e093e1d49b}, +- {0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e1}, +- {0xaecc49914078536d, 0x58fae9f773886e19}, +- {0xda7f5bf590966848, 0xaf39a475506a899f}, +- {0x888f99797a5e012d, 0x6d8406c952429604}, +- {0xaab37fd7d8f58178, 0xc8e5087ba6d33b84}, +- {0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a65}, +- {0x855c3be0a17fcd26, 0x5cf2eea09a550680}, +- {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f}, +- {0xd0601d8efc57b08b, 0xf13b94daf124da27}, +- {0x823c12795db6ce57, 0x76c53d08d6b70859}, +- {0xa2cb1717b52481ed, 0x54768c4b0c64ca6f}, +- {0xcb7ddcdda26da268, 0xa9942f5dcf7dfd0a}, +- {0xfe5d54150b090b02, 0xd3f93b35435d7c4d}, +- {0x9efa548d26e5a6e1, 0xc47bc5014a1a6db0}, +- {0xc6b8e9b0709f109a, 0x359ab6419ca1091c}, +- {0xf867241c8cc6d4c0, 0xc30163d203c94b63}, +- {0x9b407691d7fc44f8, 0x79e0de63425dcf1e}, +- {0xc21094364dfb5636, 0x985915fc12f542e5}, +- {0xf294b943e17a2bc4, 0x3e6f5b7b17b2939e}, +- {0x979cf3ca6cec5b5a, 0xa705992ceecf9c43}, +- {0xbd8430bd08277231, 0x50c6ff782a838354}, +- {0xece53cec4a314ebd, 0xa4f8bf5635246429}, +- {0x940f4613ae5ed136, 0x871b7795e136be9a}, +- {0xb913179899f68584, 0x28e2557b59846e40}, +- {0xe757dd7ec07426e5, 0x331aeada2fe589d0}, +- {0x9096ea6f3848984f, 0x3ff0d2c85def7622}, +- {0xb4bca50b065abe63, 0x0fed077a756b53aa}, +- {0xe1ebce4dc7f16dfb, 0xd3e8495912c62895}, +- {0x8d3360f09cf6e4bd, 0x64712dd7abbbd95d}, +- {0xb080392cc4349dec, 0xbd8d794d96aacfb4}, +- {0xdca04777f541c567, 0xecf0d7a0fc5583a1}, +- {0x89e42caaf9491b60, 0xf41686c49db57245}, +- {0xac5d37d5b79b6239, 0x311c2875c522ced6}, +- {0xd77485cb25823ac7, 0x7d633293366b828c}, +- {0x86a8d39ef77164bc, 0xae5dff9c02033198}, +- {0xa8530886b54dbdeb, 0xd9f57f830283fdfd}, +- {0xd267caa862a12d66, 0xd072df63c324fd7c}, +- {0x8380dea93da4bc60, 0x4247cb9e59f71e6e}, +- {0xa46116538d0deb78, 0x52d9be85f074e609}, +- {0xcd795be870516656, 0x67902e276c921f8c}, +- {0x806bd9714632dff6, 0x00ba1cd8a3db53b7}, +- {0xa086cfcd97bf97f3, 0x80e8a40eccd228a5}, +- {0xc8a883c0fdaf7df0, 0x6122cd128006b2ce}, +- {0xfad2a4b13d1b5d6c, 0x796b805720085f82}, +- {0x9cc3a6eec6311a63, 0xcbe3303674053bb1}, +- {0xc3f490aa77bd60fc, 0xbedbfc4411068a9d}, +- {0xf4f1b4d515acb93b, 0xee92fb5515482d45}, +- {0x991711052d8bf3c5, 0x751bdd152d4d1c4b}, +- {0xbf5cd54678eef0b6, 0xd262d45a78a0635e}, +- {0xef340a98172aace4, 0x86fb897116c87c35}, +- {0x9580869f0e7aac0e, 0xd45d35e6ae3d4da1}, +- {0xbae0a846d2195712, 0x8974836059cca10a}, +- {0xe998d258869facd7, 0x2bd1a438703fc94c}, +- {0x91ff83775423cc06, 0x7b6306a34627ddd0}, +- {0xb67f6455292cbf08, 0x1a3bc84c17b1d543}, +- {0xe41f3d6a7377eeca, 0x20caba5f1d9e4a94}, +- {0x8e938662882af53e, 0x547eb47b7282ee9d}, +- {0xb23867fb2a35b28d, 0xe99e619a4f23aa44}, +- {0xdec681f9f4c31f31, 0x6405fa00e2ec94d5}, +- {0x8b3c113c38f9f37e, 0xde83bc408dd3dd05}, +- {0xae0b158b4738705e, 0x9624ab50b148d446}, +- {0xd98ddaee19068c76, 0x3badd624dd9b0958}, +- {0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d7}, +- {0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4d}, +- {0xd47487cc8470652b, 0x7647c32000696720}, +- {0x84c8d4dfd2c63f3b, 0x29ecd9f40041e074}, +- {0xa5fb0a17c777cf09, 0xf468107100525891}, +- {0xcf79cc9db955c2cc, 0x7182148d4066eeb5}, +- {0x81ac1fe293d599bf, 0xc6f14cd848405531}, +- {0xa21727db38cb002f, 0xb8ada00e5a506a7d}, +- {0xca9cf1d206fdc03b, 0xa6d90811f0e4851d}, +- {0xfd442e4688bd304a, 0x908f4a166d1da664}, +- {0x9e4a9cec15763e2e, 0x9a598e4e043287ff}, +- {0xc5dd44271ad3cdba, 0x40eff1e1853f29fe}, +- {0xf7549530e188c128, 0xd12bee59e68ef47d}, +- {0x9a94dd3e8cf578b9, 0x82bb74f8301958cf}, +- {0xc13a148e3032d6e7, 0xe36a52363c1faf02}, +- {0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac2}, +- {0x96f5600f15a7b7e5, 0x29ab103a5ef8c0ba}, +- {0xbcb2b812db11a5de, 0x7415d448f6b6f0e8}, +- {0xebdf661791d60f56, 0x111b495b3464ad22}, +- {0x936b9fcebb25c995, 0xcab10dd900beec35}, +- {0xb84687c269ef3bfb, 0x3d5d514f40eea743}, +- {0xe65829b3046b0afa, 0x0cb4a5a3112a5113}, +- {0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ac}, +- {0xb3f4e093db73a093, 0x59ed216765690f57}, +- {0xe0f218b8d25088b8, 0x306869c13ec3532d}, +- {0x8c974f7383725573, 0x1e414218c73a13fc}, +- {0xafbd2350644eeacf, 0xe5d1929ef90898fb}, +- {0xdbac6c247d62a583, 0xdf45f746b74abf3a}, +- {0x894bc396ce5da772, 0x6b8bba8c328eb784}, +- {0xab9eb47c81f5114f, 0x066ea92f3f326565}, +- {0xd686619ba27255a2, 0xc80a537b0efefebe}, +- {0x8613fd0145877585, 0xbd06742ce95f5f37}, +- {0xa798fc4196e952e7, 0x2c48113823b73705}, +- {0xd17f3b51fca3a7a0, 0xf75a15862ca504c6}, +- {0x82ef85133de648c4, 0x9a984d73dbe722fc}, +- {0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebbb}, +- {0xcc963fee10b7d1b3, 0x318df905079926a9}, +- {0xffbbcfe994e5c61f, 0xfdf17746497f7053}, +- {0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa634}, +- {0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc1}, +- {0xf9bd690a1b68637b, 0x3dfdce7aa3c673b1}, +- {0x9c1661a651213e2d, 0x06bea10ca65c084f}, +- {0xc31bfa0fe5698db8, 0x486e494fcff30a63}, +- {0xf3e2f893dec3f126, 0x5a89dba3c3efccfb}, +- {0x986ddb5c6b3a76b7, 0xf89629465a75e01d}, +- {0xbe89523386091465, 0xf6bbb397f1135824}, +- {0xee2ba6c0678b597f, 0x746aa07ded582e2d}, +- {0x94db483840b717ef, 0xa8c2a44eb4571cdd}, +- {0xba121a4650e4ddeb, 0x92f34d62616ce414}, +- {0xe896a0d7e51e1566, 0x77b020baf9c81d18}, +- {0x915e2486ef32cd60, 0x0ace1474dc1d122f}, +- {0xb5b5ada8aaff80b8, 0x0d819992132456bb}, +- {0xe3231912d5bf60e6, 0x10e1fff697ed6c6a}, +- {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2}, +- {0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb3}, +- {0xddd0467c64bce4a0, 0xac7cb3f6d05ddbdf}, +- {0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96c}, +- {0xad4ab7112eb3929d, 0x86c16c98d2c953c7}, +- {0xd89d64d57a607744, 0xe871c7bf077ba8b8}, +- {0x87625f056c7c4a8b, 0x11471cd764ad4973}, +- {0xa93af6c6c79b5d2d, 0xd598e40d3dd89bd0}, +- {0xd389b47879823479, 0x4aff1d108d4ec2c4}, +- {0x843610cb4bf160cb, 0xcedf722a585139bb}, +- {0xa54394fe1eedb8fe, 0xc2974eb4ee658829}, +- {0xce947a3da6a9273e, 0x733d226229feea33}, +- {0x811ccc668829b887, 0x0806357d5a3f5260}, +- {0xa163ff802a3426a8, 0xca07c2dcb0cf26f8}, +- {0xc9bcff6034c13052, 0xfc89b393dd02f0b6}, +- {0xfc2c3f3841f17c67, 0xbbac2078d443ace3}, +- {0x9d9ba7832936edc0, 0xd54b944b84aa4c0e}, +- {0xc5029163f384a931, 0x0a9e795e65d4df12}, +- {0xf64335bcf065d37d, 0x4d4617b5ff4a16d6}, +- {0x99ea0196163fa42e, 0x504bced1bf8e4e46}, +- {0xc06481fb9bcf8d39, 0xe45ec2862f71e1d7}, +- {0xf07da27a82c37088, 0x5d767327bb4e5a4d}, +- {0x964e858c91ba2655, 0x3a6a07f8d510f870}, +- {0xbbe226efb628afea, 0x890489f70a55368c}, +- {0xeadab0aba3b2dbe5, 0x2b45ac74ccea842f}, +- {0x92c8ae6b464fc96f, 0x3b0b8bc90012929e}, +- {0xb77ada0617e3bbcb, 0x09ce6ebb40173745}, +- {0xe55990879ddcaabd, 0xcc420a6a101d0516}, +- {0x8f57fa54c2a9eab6, 0x9fa946824a12232e}, +- {0xb32df8e9f3546564, 0x47939822dc96abfa}, +- {0xdff9772470297ebd, 0x59787e2b93bc56f8}, +- {0x8bfbea76c619ef36, 0x57eb4edb3c55b65b}, +- {0xaefae51477a06b03, 0xede622920b6b23f2}, +- {0xdab99e59958885c4, 0xe95fab368e45ecee}, +- {0x88b402f7fd75539b, 0x11dbcb0218ebb415}, +- {0xaae103b5fcd2a881, 0xd652bdc29f26a11a}, +- {0xd59944a37c0752a2, 0x4be76d3346f04960}, +- {0x857fcae62d8493a5, 0x6f70a4400c562ddc}, +- {0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb953}, +- {0xd097ad07a71f26b2, 0x7e2000a41346a7a8}, +- {0x825ecc24c873782f, 0x8ed400668c0c28c9}, +- {0xa2f67f2dfa90563b, 0x728900802f0f32fb}, +- {0xcbb41ef979346bca, 0x4f2b40a03ad2ffba}, +- {0xfea126b7d78186bc, 0xe2f610c84987bfa9}, +- {0x9f24b832e6b0f436, 0x0dd9ca7d2df4d7ca}, +- {0xc6ede63fa05d3143, 0x91503d1c79720dbc}, +- {0xf8a95fcf88747d94, 0x75a44c6397ce912b}, +- {0x9b69dbe1b548ce7c, 0xc986afbe3ee11abb}, +- {0xc24452da229b021b, 0xfbe85badce996169}, +- {0xf2d56790ab41c2a2, 0xfae27299423fb9c4}, +- {0x97c560ba6b0919a5, 0xdccd879fc967d41b}, +- {0xbdb6b8e905cb600f, 0x5400e987bbc1c921}, +- {0xed246723473e3813, 0x290123e9aab23b69}, +- {0x9436c0760c86e30b, 0xf9a0b6720aaf6522}, +- {0xb94470938fa89bce, 0xf808e40e8d5b3e6a}, +- {0xe7958cb87392c2c2, 0xb60b1d1230b20e05}, +- {0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c3}, +- {0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af4}, +- {0xe2280b6c20dd5232, 0x25c6da63c38de1b1}, +- {0x8d590723948a535f, 0x579c487e5a38ad0f}, +- {0xb0af48ec79ace837, 0x2d835a9df0c6d852}, +- {0xdcdb1b2798182244, 0xf8e431456cf88e66}, +- {0x8a08f0f8bf0f156b, 0x1b8e9ecb641b5900}, +- {0xac8b2d36eed2dac5, 0xe272467e3d222f40}, +- {0xd7adf884aa879177, 0x5b0ed81dcc6abb10}, +- {0x86ccbb52ea94baea, 0x98e947129fc2b4ea}, +- {0xa87fea27a539e9a5, 0x3f2398d747b36225}, +- {0xd29fe4b18e88640e, 0x8eec7f0d19a03aae}, +- {0x83a3eeeef9153e89, 0x1953cf68300424ad}, +- {0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd8}, +- {0xcdb02555653131b6, 0x3792f412cb06794e}, +- {0x808e17555f3ebf11, 0xe2bbd88bbee40bd1}, +- {0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec5}, +- {0xc8de047564d20a8b, 0xf245825a5a445276}, +- {0xfb158592be068d2e, 0xeed6e2f0f0d56713}, +- {0x9ced737bb6c4183d, 0x55464dd69685606c}, +- {0xc428d05aa4751e4c, 0xaa97e14c3c26b887}, +- {0xf53304714d9265df, 0xd53dd99f4b3066a9}, +- {0x993fe2c6d07b7fab, 0xe546a8038efe402a}, +- {0xbf8fdb78849a5f96, 0xde98520472bdd034}, +- {0xef73d256a5c0f77c, 0x963e66858f6d4441}, +- {0x95a8637627989aad, 0xdde7001379a44aa9}, +- {0xbb127c53b17ec159, 0x5560c018580d5d53}, +- {0xe9d71b689dde71af, 0xaab8f01e6e10b4a7}, +- {0x9226712162ab070d, 0xcab3961304ca70e9}, +- {0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d23}, +- {0xe45c10c42a2b3b05, 0x8cb89a7db77c506b}, +- {0x8eb98a7a9a5b04e3, 0x77f3608e92adb243}, +- {0xb267ed1940f1c61c, 0x55f038b237591ed4}, +- {0xdf01e85f912e37a3, 0x6b6c46dec52f6689}, +- {0x8b61313bbabce2c6, 0x2323ac4b3b3da016}, +- {0xae397d8aa96c1b77, 0xabec975e0a0d081b}, +- {0xd9c7dced53c72255, 0x96e7bd358c904a22}, +- {0x881cea14545c7575, 0x7e50d64177da2e55}, +- {0xaa242499697392d2, 0xdde50bd1d5d0b9ea}, +- {0xd4ad2dbfc3d07787, 0x955e4ec64b44e865}, +- {0x84ec3c97da624ab4, 0xbd5af13bef0b113f}, +- {0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58f}, +- {0xcfb11ead453994ba, 0x67de18eda5814af3}, +- {0x81ceb32c4b43fcf4, 0x80eacf948770ced8}, +- {0xa2425ff75e14fc31, 0xa1258379a94d028e}, +- {0xcad2f7f5359a3b3e, 0x096ee45813a04331}, +- {0xfd87b5f28300ca0d, 0x8bca9d6e188853fd}, +- {0x9e74d1b791e07e48, 0x775ea264cf55347e}, +- {0xc612062576589dda, 0x95364afe032a819e}, +- {0xf79687aed3eec551, 0x3a83ddbd83f52205}, +- {0x9abe14cd44753b52, 0xc4926a9672793543}, +- {0xc16d9a0095928a27, 0x75b7053c0f178294}, +- {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, +- {0x971da05074da7bee, 0xd3f6fc16ebca5e04}, +- {0xbce5086492111aea, 0x88f4bb1ca6bcf585}, +- {0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6}, +- {0x9392ee8e921d5d07, 0x3aff322e62439fd0}, +- {0xb877aa3236a4b449, 0x09befeb9fad487c3}, +- {0xe69594bec44de15b, 0x4c2ebe687989a9b4}, +- {0x901d7cf73ab0acd9, 0x0f9d37014bf60a11}, +- {0xb424dc35095cd80f, 0x538484c19ef38c95}, +- {0xe12e13424bb40e13, 0x2865a5f206b06fba}, +- {0x8cbccc096f5088cb, 0xf93f87b7442e45d4}, +- {0xafebff0bcb24aafe, 0xf78f69a51539d749}, +- {0xdbe6fecebdedd5be, 0xb573440e5a884d1c}, +- {0x89705f4136b4a597, 0x31680a88f8953031}, +- {0xabcc77118461cefc, 0xfdc20d2b36ba7c3e}, +- {0xd6bf94d5e57a42bc, 0x3d32907604691b4d}, +- {0x8637bd05af6c69b5, 0xa63f9a49c2c1b110}, +- {0xa7c5ac471b478423, 0x0fcf80dc33721d54}, +- {0xd1b71758e219652b, 0xd3c36113404ea4a9}, +- {0x83126e978d4fdf3b, 0x645a1cac083126ea}, +- {0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4}, +- {0xcccccccccccccccc, 0xcccccccccccccccd}, +- {0x8000000000000000, 0x0000000000000000}, +- {0xa000000000000000, 0x0000000000000000}, +- {0xc800000000000000, 0x0000000000000000}, +- {0xfa00000000000000, 0x0000000000000000}, +- {0x9c40000000000000, 0x0000000000000000}, +- {0xc350000000000000, 0x0000000000000000}, +- {0xf424000000000000, 0x0000000000000000}, +- {0x9896800000000000, 0x0000000000000000}, +- {0xbebc200000000000, 0x0000000000000000}, +- {0xee6b280000000000, 0x0000000000000000}, +- {0x9502f90000000000, 0x0000000000000000}, +- {0xba43b74000000000, 0x0000000000000000}, +- {0xe8d4a51000000000, 0x0000000000000000}, +- {0x9184e72a00000000, 0x0000000000000000}, +- {0xb5e620f480000000, 0x0000000000000000}, +- {0xe35fa931a0000000, 0x0000000000000000}, +- {0x8e1bc9bf04000000, 0x0000000000000000}, +- {0xb1a2bc2ec5000000, 0x0000000000000000}, +- {0xde0b6b3a76400000, 0x0000000000000000}, +- {0x8ac7230489e80000, 0x0000000000000000}, +- {0xad78ebc5ac620000, 0x0000000000000000}, +- {0xd8d726b7177a8000, 0x0000000000000000}, +- {0x878678326eac9000, 0x0000000000000000}, +- {0xa968163f0a57b400, 0x0000000000000000}, +- {0xd3c21bcecceda100, 0x0000000000000000}, +- {0x84595161401484a0, 0x0000000000000000}, +- {0xa56fa5b99019a5c8, 0x0000000000000000}, +- {0xcecb8f27f4200f3a, 0x0000000000000000}, +- {0x813f3978f8940984, 0x4000000000000000}, +- {0xa18f07d736b90be5, 0x5000000000000000}, +- {0xc9f2c9cd04674ede, 0xa400000000000000}, +- {0xfc6f7c4045812296, 0x4d00000000000000}, +- {0x9dc5ada82b70b59d, 0xf020000000000000}, +- {0xc5371912364ce305, 0x6c28000000000000}, +- {0xf684df56c3e01bc6, 0xc732000000000000}, +- {0x9a130b963a6c115c, 0x3c7f400000000000}, +- {0xc097ce7bc90715b3, 0x4b9f100000000000}, +- {0xf0bdc21abb48db20, 0x1e86d40000000000}, +- {0x96769950b50d88f4, 0x1314448000000000}, +- {0xbc143fa4e250eb31, 0x17d955a000000000}, +- {0xeb194f8e1ae525fd, 0x5dcfab0800000000}, +- {0x92efd1b8d0cf37be, 0x5aa1cae500000000}, +- {0xb7abc627050305ad, 0xf14a3d9e40000000}, +- {0xe596b7b0c643c719, 0x6d9ccd05d0000000}, +- {0x8f7e32ce7bea5c6f, 0xe4820023a2000000}, +- {0xb35dbf821ae4f38b, 0xdda2802c8a800000}, +- {0xe0352f62a19e306e, 0xd50b2037ad200000}, +- {0x8c213d9da502de45, 0x4526f422cc340000}, +- {0xaf298d050e4395d6, 0x9670b12b7f410000}, +- {0xdaf3f04651d47b4c, 0x3c0cdd765f114000}, +- {0x88d8762bf324cd0f, 0xa5880a69fb6ac800}, +- {0xab0e93b6efee0053, 0x8eea0d047a457a00}, +- {0xd5d238a4abe98068, 0x72a4904598d6d880}, +- {0x85a36366eb71f041, 0x47a6da2b7f864750}, +- {0xa70c3c40a64e6c51, 0x999090b65f67d924}, +- {0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d}, +- {0x82818f1281ed449f, 0xbff8f10e7a8921a4}, +- {0xa321f2d7226895c7, 0xaff72d52192b6a0d}, +- {0xcbea6f8ceb02bb39, 0x9bf4f8a69f764490}, +- {0xfee50b7025c36a08, 0x02f236d04753d5b4}, +- {0x9f4f2726179a2245, 0x01d762422c946590}, +- {0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef5}, +- {0xf8ebad2b84e0d58b, 0xd2e0898765a7deb2}, +- {0x9b934c3b330c8577, 0x63cc55f49f88eb2f}, +- {0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fb}, +- {0xf316271c7fc3908a, 0x8bef464e3945ef7a}, +- {0x97edd871cfda3a56, 0x97758bf0e3cbb5ac}, +- {0xbde94e8e43d0c8ec, 0x3d52eeed1cbea317}, +- {0xed63a231d4c4fb27, 0x4ca7aaa863ee4bdd}, +- {0x945e455f24fb1cf8, 0x8fe8caa93e74ef6a}, +- {0xb975d6b6ee39e436, 0xb3e2fd538e122b44}, +- {0xe7d34c64a9c85d44, 0x60dbbca87196b616}, +- {0x90e40fbeea1d3a4a, 0xbc8955e946fe31cd}, +- {0xb51d13aea4a488dd, 0x6babab6398bdbe41}, +- {0xe264589a4dcdab14, 0xc696963c7eed2dd1}, +- {0x8d7eb76070a08aec, 0xfc1e1de5cf543ca2}, +- {0xb0de65388cc8ada8, 0x3b25a55f43294bcb}, +- {0xdd15fe86affad912, 0x49ef0eb713f39ebe}, +- {0x8a2dbf142dfcc7ab, 0x6e3569326c784337}, +- {0xacb92ed9397bf996, 0x49c2c37f07965404}, +- {0xd7e77a8f87daf7fb, 0xdc33745ec97be906}, +- {0x86f0ac99b4e8dafd, 0x69a028bb3ded71a3}, +- {0xa8acd7c0222311bc, 0xc40832ea0d68ce0c}, +- {0xd2d80db02aabd62b, 0xf50a3fa490c30190}, +- {0x83c7088e1aab65db, 0x792667c6da79e0fa}, +- {0xa4b8cab1a1563f52, 0x577001b891185938}, +- {0xcde6fd5e09abcf26, 0xed4c0226b55e6f86}, +- {0x80b05e5ac60b6178, 0x544f8158315b05b4}, +- {0xa0dc75f1778e39d6, 0x696361ae3db1c721}, +- {0xc913936dd571c84c, 0x03bc3a19cd1e38e9}, +- {0xfb5878494ace3a5f, 0x04ab48a04065c723}, +- {0x9d174b2dcec0e47b, 0x62eb0d64283f9c76}, +- {0xc45d1df942711d9a, 0x3ba5d0bd324f8394}, +- {0xf5746577930d6500, 0xca8f44ec7ee36479}, +- {0x9968bf6abbe85f20, 0x7e998b13cf4e1ecb}, +- {0xbfc2ef456ae276e8, 0x9e3fedd8c321a67e}, +- {0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101e}, +- {0x95d04aee3b80ece5, 0xbba1f1d158724a12}, +- {0xbb445da9ca61281f, 0x2a8a6e45ae8edc97}, +- {0xea1575143cf97226, 0xf52d09d71a3293bd}, +- {0x924d692ca61be758, 0x593c2626705f9c56}, +- {0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836c}, +- {0xe498f455c38b997a, 0x0b6dfb9c0f956447}, +- {0x8edf98b59a373fec, 0x4724bd4189bd5eac}, +- {0xb2977ee300c50fe7, 0x58edec91ec2cb657}, +- {0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ed}, +- {0x8b865b215899f46c, 0xbd79e0d20082ee74}, +- {0xae67f1e9aec07187, 0xecd8590680a3aa11}, +- {0xda01ee641a708de9, 0xe80e6f4820cc9495}, +- {0x884134fe908658b2, 0x3109058d147fdcdd}, +- {0xaa51823e34a7eede, 0xbd4b46f0599fd415}, +- {0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91a}, +- {0x850fadc09923329e, 0x03e2cf6bc604ddb0}, +- {0xa6539930bf6bff45, 0x84db8346b786151c}, +- {0xcfe87f7cef46ff16, 0xe612641865679a63}, +- {0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07e}, +- {0xa26da3999aef7749, 0xe3be5e330f38f09d}, +- {0xcb090c8001ab551c, 0x5cadf5bfd3072cc5}, +- {0xfdcb4fa002162a63, 0x73d9732fc7c8f7f6}, +- {0x9e9f11c4014dda7e, 0x2867e7fddcdd9afa}, +- {0xc646d63501a1511d, 0xb281e1fd541501b8}, +- {0xf7d88bc24209a565, 0x1f225a7ca91a4226}, +- {0x9ae757596946075f, 0x3375788de9b06958}, +- {0xc1a12d2fc3978937, 0x0052d6b1641c83ae}, +- {0xf209787bb47d6b84, 0xc0678c5dbd23a49a}, +- {0x9745eb4d50ce6332, 0xf840b7ba963646e0}, +- {0xbd176620a501fbff, 0xb650e5a93bc3d898}, +- {0xec5d3fa8ce427aff, 0xa3e51f138ab4cebe}, +- {0x93ba47c980e98cdf, 0xc66f336c36b10137}, +- {0xb8a8d9bbe123f017, 0xb80b0047445d4184}, +- {0xe6d3102ad96cec1d, 0xa60dc059157491e5}, +- {0x9043ea1ac7e41392, 0x87c89837ad68db2f}, +- {0xb454e4a179dd1877, 0x29babe4598c311fb}, +- {0xe16a1dc9d8545e94, 0xf4296dd6fef3d67a}, +- {0x8ce2529e2734bb1d, 0x1899e4a65f58660c}, +- {0xb01ae745b101e9e4, 0x5ec05dcff72e7f8f}, +- {0xdc21a1171d42645d, 0x76707543f4fa1f73}, +- {0x899504ae72497eba, 0x6a06494a791c53a8}, +- {0xabfa45da0edbde69, 0x0487db9d17636892}, +- {0xd6f8d7509292d603, 0x45a9d2845d3c42b6}, +- {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b2}, +- {0xa7f26836f282b732, 0x8e6cac7768d7141e}, +- {0xd1ef0244af2364ff, 0x3207d795430cd926}, +- {0x8335616aed761f1f, 0x7f44e6bd49e807b8}, +- {0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a6}, +- {0xcd036837130890a1, 0x36dba887c37a8c0f}, +- {0x802221226be55a64, 0xc2494954da2c9789}, +- {0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6c}, +- {0xc83553c5c8965d3d, 0x6f92829494e5acc7}, +- {0xfa42a8b73abbf48c, 0xcb772339ba1f17f9}, +- {0x9c69a97284b578d7, 0xff2a760414536efb}, +- {0xc38413cf25e2d70d, 0xfef5138519684aba}, +- {0xf46518c2ef5b8cd1, 0x7eb258665fc25d69}, +- {0x98bf2f79d5993802, 0xef2f773ffbd97a61}, +- {0xbeeefb584aff8603, 0xaafb550ffacfd8fa}, +- {0xeeaaba2e5dbf6784, 0x95ba2a53f983cf38}, +- {0x952ab45cfa97a0b2, 0xdd945a747bf26183}, +- {0xba756174393d88df, 0x94f971119aeef9e4}, +- {0xe912b9d1478ceb17, 0x7a37cd5601aab85d}, +- {0x91abb422ccb812ee, 0xac62e055c10ab33a}, +- {0xb616a12b7fe617aa, 0x577b986b314d6009}, +- {0xe39c49765fdf9d94, 0xed5a7e85fda0b80b}, +- {0x8e41ade9fbebc27d, 0x14588f13be847307}, +- {0xb1d219647ae6b31c, 0x596eb2d8ae258fc8}, +- {0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bb}, +- {0x8aec23d680043bee, 0x25de7bb9480d5854}, +- {0xada72ccc20054ae9, 0xaf561aa79a10ae6a}, +- {0xd910f7ff28069da4, 0x1b2ba1518094da04}, +- {0x87aa9aff79042286, 0x90fb44d2f05d0842}, +- {0xa99541bf57452b28, 0x353a1607ac744a53}, +- {0xd3fa922f2d1675f2, 0x42889b8997915ce8}, +- {0x847c9b5d7c2e09b7, 0x69956135febada11}, +- {0xa59bc234db398c25, 0x43fab9837e699095}, +- {0xcf02b2c21207ef2e, 0x94f967e45e03f4bb}, +- {0x8161afb94b44f57d, 0x1d1be0eebac278f5}, +- {0xa1ba1ba79e1632dc, 0x6462d92a69731732}, +- {0xca28a291859bbf93, 0x7d7b8f7503cfdcfe}, +- {0xfcb2cb35e702af78, 0x5cda735244c3d43e}, +- {0x9defbf01b061adab, 0x3a0888136afa64a7}, +- {0xc56baec21c7a1916, 0x088aaa1845b8fdd0}, +- {0xf6c69a72a3989f5b, 0x8aad549e57273d45}, +- {0x9a3c2087a63f6399, 0x36ac54e2f678864b}, +- {0xc0cb28a98fcf3c7f, 0x84576a1bb416a7dd}, +- {0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d5}, +- {0x969eb7c47859e743, 0x9f644ae5a4b1b325}, +- {0xbc4665b596706114, 0x873d5d9f0dde1fee}, +- {0xeb57ff22fc0c7959, 0xa90cb506d155a7ea}, +- {0x9316ff75dd87cbd8, 0x09a7f12442d588f2}, +- {0xb7dcbf5354e9bece, 0x0c11ed6d538aeb2f}, +- {0xe5d3ef282a242e81, 0x8f1668c8a86da5fa}, +- {0x8fa475791a569d10, 0xf96e017d694487bc}, +- {0xb38d92d760ec4455, 0x37c981dcc395a9ac}, +- {0xe070f78d3927556a, 0x85bbe253f47b1417}, +- {0x8c469ab843b89562, 0x93956d7478ccec8e}, +- {0xaf58416654a6babb, 0x387ac8d1970027b2}, +- {0xdb2e51bfe9d0696a, 0x06997b05fcc0319e}, +- {0x88fcf317f22241e2, 0x441fece3bdf81f03}, +- {0xab3c2fddeeaad25a, 0xd527e81cad7626c3}, +- {0xd60b3bd56a5586f1, 0x8a71e223d8d3b074}, +- {0x85c7056562757456, 0xf6872d5667844e49}, +- {0xa738c6bebb12d16c, 0xb428f8ac016561db}, +- {0xd106f86e69d785c7, 0xe13336d701beba52}, +- {0x82a45b450226b39c, 0xecc0024661173473}, +- {0xa34d721642b06084, 0x27f002d7f95d0190}, +- {0xcc20ce9bd35c78a5, 0x31ec038df7b441f4}, +- {0xff290242c83396ce, 0x7e67047175a15271}, +- {0x9f79a169bd203e41, 0x0f0062c6e984d386}, +- {0xc75809c42c684dd1, 0x52c07b78a3e60868}, +- {0xf92e0c3537826145, 0xa7709a56ccdf8a82}, +- {0x9bbcc7a142b17ccb, 0x88a66076400bb691}, +- {0xc2abf989935ddbfe, 0x6acff893d00ea435}, +- {0xf356f7ebf83552fe, 0x0583f6b8c4124d43}, +- {0x98165af37b2153de, 0xc3727a337a8b704a}, +- {0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5c}, +- {0xeda2ee1c7064130c, 0x1162def06f79df73}, +- {0x9485d4d1c63e8be7, 0x8addcb5645ac2ba8}, +- {0xb9a74a0637ce2ee1, 0x6d953e2bd7173692}, +- {0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0437}, +- {0x910ab1d4db9914a0, 0x1d9c9892400a22a2}, +- {0xb54d5e4a127f59c8, 0x2503beb6d00cab4b}, +- {0xe2a0b5dc971f303a, 0x2e44ae64840fd61d}, +- {0x8da471a9de737e24, 0x5ceaecfed289e5d2}, +- {0xb10d8e1456105dad, 0x7425a83e872c5f47}, +- {0xdd50f1996b947518, 0xd12f124e28f77719}, +- {0x8a5296ffe33cc92f, 0x82bd6b70d99aaa6f}, +- {0xace73cbfdc0bfb7b, 0x636cc64d1001550b}, +- {0xd8210befd30efa5a, 0x3c47f7e05401aa4e}, +- {0x8714a775e3e95c78, 0x65acfaec34810a71}, +- {0xa8d9d1535ce3b396, 0x7f1839a741a14d0d}, +- {0xd31045a8341ca07c, 0x1ede48111209a050}, +- {0x83ea2b892091e44d, 0x934aed0aab460432}, +- {0xa4e4b66b68b65d60, 0xf81da84d5617853f}, +- {0xce1de40642e3f4b9, 0x36251260ab9d668e}, +- {0x80d2ae83e9ce78f3, 0xc1d72b7c6b426019}, +- {0xa1075a24e4421730, 0xb24cf65b8612f81f}, +- {0xc94930ae1d529cfc, 0xdee033f26797b627}, +- {0xfb9b7cd9a4a7443c, 0x169840ef017da3b1}, +- {0x9d412e0806e88aa5, 0x8e1f289560ee864e}, +- {0xc491798a08a2ad4e, 0xf1a6f2bab92a27e2}, +- {0xf5b5d7ec8acb58a2, 0xae10af696774b1db}, +- {0x9991a6f3d6bf1765, 0xacca6da1e0a8ef29}, +- {0xbff610b0cc6edd3f, 0x17fd090a58d32af3}, +- {0xeff394dcff8a948e, 0xddfc4b4cef07f5b0}, +- {0x95f83d0a1fb69cd9, 0x4abdaf101564f98e}, +- {0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f1}, +- {0xea53df5fd18d5513, 0x84c86189216dc5ed}, +- {0x92746b9be2f8552c, 0x32fd3cf5b4e49bb4}, +- {0xb7118682dbb66a77, 0x3fbc8c33221dc2a1}, +- {0xe4d5e82392a40515, 0x0fabaf3feaa5334a}, +- {0x8f05b1163ba6832d, 0x29cb4d87f2a7400e}, +- {0xb2c71d5bca9023f8, 0x743e20e9ef511012}, +- {0xdf78e4b2bd342cf6, 0x914da9246b255416}, +- {0x8bab8eefb6409c1a, 0x1ad089b6c2f7548e}, +- {0xae9672aba3d0c320, 0xa184ac2473b529b1}, +- {0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741e}, +- {0x8865899617fb1871, 0x7e2fa67c7a658892}, +- {0xaa7eebfb9df9de8d, 0xddbb901b98feeab7}, +- {0xd51ea6fa85785631, 0x552a74227f3ea565}, +- {0x8533285c936b35de, 0xd53a88958f87275f}, +- {0xa67ff273b8460356, 0x8a892abaf368f137}, +- {0xd01fef10a657842c, 0x2d2b7569b0432d85}, +- {0x8213f56a67f6b29b, 0x9c3b29620e29fc73}, +- {0xa298f2c501f45f42, 0x8349f3ba91b47b8f}, +- {0xcb3f2f7642717713, 0x241c70a936219a73}, +- {0xfe0efb53d30dd4d7, 0xed238cd383aa0110}, +- {0x9ec95d1463e8a506, 0xf4363804324a40aa}, +- {0xc67bb4597ce2ce48, 0xb143c6053edcd0d5}, +- {0xf81aa16fdc1b81da, 0xdd94b7868e94050a}, +- {0x9b10a4e5e9913128, 0xca7cf2b4191c8326}, +- {0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f0}, +- {0xf24a01a73cf2dccf, 0xbc633b39673c8cec}, +- {0x976e41088617ca01, 0xd5be0503e085d813}, +- {0xbd49d14aa79dbc82, 0x4b2d8644d8a74e18}, +- {0xec9c459d51852ba2, 0xddf8e7d60ed1219e}, +- {0x93e1ab8252f33b45, 0xcabb90e5c942b503}, +- {0xb8da1662e7b00a17, 0x3d6a751f3b936243}, +- {0xe7109bfba19c0c9d, 0x0cc512670a783ad4}, +- {0x906a617d450187e2, 0x27fb2b80668b24c5}, +- {0xb484f9dc9641e9da, 0xb1f9f660802dedf6}, +- {0xe1a63853bbd26451, 0x5e7873f8a0396973}, +- {0x8d07e33455637eb2, 0xdb0b487b6423e1e8}, +- {0xb049dc016abc5e5f, 0x91ce1a9a3d2cda62}, +- {0xdc5c5301c56b75f7, 0x7641a140cc7810fb}, +- {0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9d}, +- {0xac2820d9623bf429, 0x546345fa9fbdcd44}, +- {0xd732290fbacaf133, 0xa97c177947ad4095}, +- {0x867f59a9d4bed6c0, 0x49ed8eabcccc485d}, +- {0xa81f301449ee8c70, 0x5c68f256bfff5a74}, +- {0xd226fc195c6a2f8c, 0x73832eec6fff3111}, +- {0x83585d8fd9c25db7, 0xc831fd53c5ff7eab}, +- {0xa42e74f3d032f525, 0xba3e7ca8b77f5e55}, +- {0xcd3a1230c43fb26f, 0x28ce1bd2e55f35eb}, +- {0x80444b5e7aa7cf85, 0x7980d163cf5b81b3}, +- {0xa0555e361951c366, 0xd7e105bcc332621f}, +- {0xc86ab5c39fa63440, 0x8dd9472bf3fefaa7}, +- {0xfa856334878fc150, 0xb14f98f6f0feb951}, +- {0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d3}, +- {0xc3b8358109e84f07, 0x0a862f80ec4700c8}, +- {0xf4a642e14c6262c8, 0xcd27bb612758c0fa}, +- {0x98e7e9cccfbd7dbd, 0x8038d51cb897789c}, +- {0xbf21e44003acdd2c, 0xe0470a63e6bd56c3}, +- {0xeeea5d5004981478, 0x1858ccfce06cac74}, +- {0x95527a5202df0ccb, 0x0f37801e0c43ebc8}, +- {0xbaa718e68396cffd, 0xd30560258f54e6ba}, +- {0xe950df20247c83fd, 0x47c6b82ef32a2069}, +- {0x91d28b7416cdd27e, 0x4cdc331d57fa5441}, +- {0xb6472e511c81471d, 0xe0133fe4adf8e952}, +- {0xe3d8f9e563a198e5, 0x58180fddd97723a6}, +- {0x8e679c2f5e44ff8f, 0x570f09eaa7ea7648}, +- {0xb201833b35d63f73, 0x2cd2cc6551e513da}, +- {0xde81e40a034bcf4f, 0xf8077f7ea65e58d1}, +- {0x8b112e86420f6191, 0xfb04afaf27faf782}, +- {0xadd57a27d29339f6, 0x79c5db9af1f9b563}, +- {0xd94ad8b1c7380874, 0x18375281ae7822bc}, +- {0x87cec76f1c830548, 0x8f2293910d0b15b5}, +- {0xa9c2794ae3a3c69a, 0xb2eb3875504ddb22}, +- {0xd433179d9c8cb841, 0x5fa60692a46151eb}, +- {0x849feec281d7f328, 0xdbc7c41ba6bcd333}, +- {0xa5c7ea73224deff3, 0x12b9b522906c0800}, +- {0xcf39e50feae16bef, 0xd768226b34870a00}, +- {0x81842f29f2cce375, 0xe6a1158300d46640}, +- {0xa1e53af46f801c53, 0x60495ae3c1097fd0}, +- {0xca5e89b18b602368, 0x385bb19cb14bdfc4}, +- {0xfcf62c1dee382c42, 0x46729e03dd9ed7b5}, +- {0x9e19db92b4e31ba9, 0x6c07a2c26a8346d1}, +- {0xc5a05277621be293, 0xc7098b7305241885}, +- { 0xf70867153aa2db38, +- 0xb8cbee4fc66d1ea7 } +-#else +- {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, +- {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, +- {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f}, +- {0x86a8d39ef77164bc, 0xae5dff9c02033198}, +- {0xd98ddaee19068c76, 0x3badd624dd9b0958}, +- {0xafbd2350644eeacf, 0xe5d1929ef90898fb}, +- {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2}, +- {0xe55990879ddcaabd, 0xcc420a6a101d0516}, +- {0xb94470938fa89bce, 0xf808e40e8d5b3e6a}, +- {0x95a8637627989aad, 0xdde7001379a44aa9}, +- {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, +- {0xc350000000000000, 0x0000000000000000}, +- {0x9dc5ada82b70b59d, 0xf020000000000000}, +- {0xfee50b7025c36a08, 0x02f236d04753d5b4}, +- {0xcde6fd5e09abcf26, 0xed4c0226b55e6f86}, +- {0xa6539930bf6bff45, 0x84db8346b786151c}, +- {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b2}, +- {0xd910f7ff28069da4, 0x1b2ba1518094da04}, +- {0xaf58416654a6babb, 0x387ac8d1970027b2}, +- {0x8da471a9de737e24, 0x5ceaecfed289e5d2}, +- {0xe4d5e82392a40515, 0x0fabaf3feaa5334a}, +- {0xb8da1662e7b00a17, 0x3d6a751f3b936243}, +- { 0x95527a5202df0ccb, +- 0x0f37801e0c43ebc8 } +-#endif +- }; +- +-#if FMT_USE_FULL_CACHE_DRAGONBOX +- return pow10_significands[k - float_info::min_k]; +-#else +- static constexpr const uint64_t powers_of_5_64[] = { +- 0x0000000000000001, 0x0000000000000005, 0x0000000000000019, +- 0x000000000000007d, 0x0000000000000271, 0x0000000000000c35, +- 0x0000000000003d09, 0x000000000001312d, 0x000000000005f5e1, +- 0x00000000001dcd65, 0x00000000009502f9, 0x0000000002e90edd, +- 0x000000000e8d4a51, 0x0000000048c27395, 0x000000016bcc41e9, +- 0x000000071afd498d, 0x0000002386f26fc1, 0x000000b1a2bc2ec5, +- 0x000003782dace9d9, 0x00001158e460913d, 0x000056bc75e2d631, +- 0x0001b1ae4d6e2ef5, 0x000878678326eac9, 0x002a5a058fc295ed, +- 0x00d3c21bcecceda1, 0x0422ca8b0a00a425, 0x14adf4b7320334b9}; +- +- static constexpr const uint32_t pow10_recovery_errors[] = { +- 0x50001400, 0x54044100, 0x54014555, 0x55954415, 0x54115555, 0x00000001, +- 0x50000000, 0x00104000, 0x54010004, 0x05004001, 0x55555544, 0x41545555, +- 0x54040551, 0x15445545, 0x51555514, 0x10000015, 0x00101100, 0x01100015, +- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04450514, 0x45414110, +- 0x55555145, 0x50544050, 0x15040155, 0x11054140, 0x50111514, 0x11451454, +- 0x00400541, 0x00000000, 0x55555450, 0x10056551, 0x10054011, 0x55551014, +- 0x69514555, 0x05151109, 0x00155555}; +- +- static const int compression_ratio = 27; +- +- // Compute base index. +- int cache_index = (k - float_info::min_k) / compression_ratio; +- int kb = cache_index * compression_ratio + float_info::min_k; +- int offset = k - kb; +- +- // Get base cache. +- uint128_wrapper base_cache = pow10_significands[cache_index]; +- if (offset == 0) return base_cache; +- +- // Compute the required amount of bit-shift. +- int alpha = floor_log2_pow10(kb + offset) - floor_log2_pow10(kb) - offset; +- FMT_ASSERT(alpha > 0 && alpha < 64, "shifting error detected"); +- +- // Try to recover the real cache. +- uint64_t pow5 = powers_of_5_64[offset]; +- uint128_wrapper recovered_cache = umul128(base_cache.high(), pow5); +- uint128_wrapper middle_low = +- umul128(base_cache.low() - (kb < 0 ? 1u : 0u), pow5); +- +- recovered_cache += middle_low.high(); +- +- uint64_t high_to_middle = recovered_cache.high() << (64 - alpha); +- uint64_t middle_to_low = recovered_cache.low() << (64 - alpha); +- +- recovered_cache = +- uint128_wrapper{(recovered_cache.low() >> alpha) | high_to_middle, +- ((middle_low.low() >> alpha) | middle_to_low)}; +- +- if (kb < 0) recovered_cache += 1; +- +- // Get error. +- int error_idx = (k - float_info::min_k) / 16; +- uint32_t error = (pow10_recovery_errors[error_idx] >> +- ((k - float_info::min_k) % 16) * 2) & +- 0x3; +- +- // Add the error back. +- FMT_ASSERT(recovered_cache.low() + error >= recovered_cache.low(), ""); +- return {recovered_cache.high(), recovered_cache.low() + error}; +-#endif +- } +- +- static carrier_uint compute_mul(carrier_uint u, +- const cache_entry_type& cache) FMT_NOEXCEPT { +- return umul192_upper64(u, cache); +- } +- +- static uint32_t compute_delta(cache_entry_type const& cache, +- int beta_minus_1) FMT_NOEXCEPT { +- return static_cast(cache.high() >> (64 - 1 - beta_minus_1)); +- } +- +- static bool compute_mul_parity(carrier_uint two_f, +- const cache_entry_type& cache, +- int beta_minus_1) FMT_NOEXCEPT { +- FMT_ASSERT(beta_minus_1 >= 1, ""); +- FMT_ASSERT(beta_minus_1 < 64, ""); +- +- return ((umul192_middle64(two_f, cache) >> (64 - beta_minus_1)) & 1) != 0; +- } +- +- static carrier_uint compute_left_endpoint_for_shorter_interval_case( +- const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT { +- return (cache.high() - +- (cache.high() >> (float_info::significand_bits + 2))) >> +- (64 - float_info::significand_bits - 1 - beta_minus_1); +- } +- +- static carrier_uint compute_right_endpoint_for_shorter_interval_case( +- const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT { +- return (cache.high() + +- (cache.high() >> (float_info::significand_bits + 1))) >> +- (64 - float_info::significand_bits - 1 - beta_minus_1); +- } +- +- static carrier_uint compute_round_up_for_shorter_interval_case( +- const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT { +- return ((cache.high() >> +- (64 - float_info::significand_bits - 2 - beta_minus_1)) + +- 1) / +- 2; +- } +-}; +- +-// Various integer checks +-template +-bool is_left_endpoint_integer_shorter_interval(int exponent) FMT_NOEXCEPT { +- return exponent >= +- float_info< +- T>::case_shorter_interval_left_endpoint_lower_threshold && +- exponent <= +- float_info::case_shorter_interval_left_endpoint_upper_threshold; +-} +-template +-bool is_endpoint_integer(typename float_info::carrier_uint two_f, +- int exponent, int minus_k) FMT_NOEXCEPT { +- if (exponent < float_info::case_fc_pm_half_lower_threshold) return false; +- // For k >= 0. +- if (exponent <= float_info::case_fc_pm_half_upper_threshold) return true; +- // For k < 0. +- if (exponent > float_info::divisibility_check_by_5_threshold) return false; +- return divisible_by_power_of_5(two_f, minus_k); +-} +- +-template +-bool is_center_integer(typename float_info::carrier_uint two_f, int exponent, +- int minus_k) FMT_NOEXCEPT { +- // Exponent for 5 is negative. +- if (exponent > float_info::divisibility_check_by_5_threshold) return false; +- if (exponent > float_info::case_fc_upper_threshold) +- return divisible_by_power_of_5(two_f, minus_k); +- // Both exponents are nonnegative. +- if (exponent >= float_info::case_fc_lower_threshold) return true; +- // Exponent for 2 is negative. +- return divisible_by_power_of_2(two_f, minus_k - exponent + 1); +-} +- +-// Remove trailing zeros from n and return the number of zeros removed (float) +-FMT_INLINE int remove_trailing_zeros(uint32_t& n) FMT_NOEXCEPT { +-#ifdef FMT_BUILTIN_CTZ +- int t = FMT_BUILTIN_CTZ(n); +-#else +- int t = ctz(n); +-#endif +- if (t > float_info::max_trailing_zeros) +- t = float_info::max_trailing_zeros; +- +- const uint32_t mod_inv1 = 0xcccccccd; +- const uint32_t max_quotient1 = 0x33333333; +- const uint32_t mod_inv2 = 0xc28f5c29; +- const uint32_t max_quotient2 = 0x0a3d70a3; +- +- int s = 0; +- for (; s < t - 1; s += 2) { +- if (n * mod_inv2 > max_quotient2) break; +- n *= mod_inv2; +- } +- if (s < t && n * mod_inv1 <= max_quotient1) { +- n *= mod_inv1; +- ++s; +- } +- n >>= s; +- return s; +-} +- +-// Removes trailing zeros and returns the number of zeros removed (double) +-FMT_INLINE int remove_trailing_zeros(uint64_t& n) FMT_NOEXCEPT { +-#ifdef FMT_BUILTIN_CTZLL +- int t = FMT_BUILTIN_CTZLL(n); +-#else +- int t = ctzll(n); +-#endif +- if (t > float_info::max_trailing_zeros) +- t = float_info::max_trailing_zeros; +- // Divide by 10^8 and reduce to 32-bits +- // Since ret_value.significand <= (2^64 - 1) / 1000 < 10^17, +- // both of the quotient and the r should fit in 32-bits +- +- const uint32_t mod_inv1 = 0xcccccccd; +- const uint32_t max_quotient1 = 0x33333333; +- const uint64_t mod_inv8 = 0xc767074b22e90e21; +- const uint64_t max_quotient8 = 0x00002af31dc46118; +- +- // If the number is divisible by 1'0000'0000, work with the quotient +- if (t >= 8) { +- auto quotient_candidate = n * mod_inv8; +- +- if (quotient_candidate <= max_quotient8) { +- auto quotient = static_cast(quotient_candidate >> 8); +- +- int s = 8; +- for (; s < t; ++s) { +- if (quotient * mod_inv1 > max_quotient1) break; +- quotient *= mod_inv1; +- } +- quotient >>= (s - 8); +- n = quotient; +- return s; +- } +- } +- +- // Otherwise, work with the remainder +- auto quotient = static_cast(n / 100000000); +- auto remainder = static_cast(n - 100000000 * quotient); +- +- if (t == 0 || remainder * mod_inv1 > max_quotient1) { +- return 0; +- } +- remainder *= mod_inv1; +- +- if (t == 1 || remainder * mod_inv1 > max_quotient1) { +- n = (remainder >> 1) + quotient * 10000000ull; +- return 1; +- } +- remainder *= mod_inv1; +- +- if (t == 2 || remainder * mod_inv1 > max_quotient1) { +- n = (remainder >> 2) + quotient * 1000000ull; +- return 2; +- } +- remainder *= mod_inv1; +- +- if (t == 3 || remainder * mod_inv1 > max_quotient1) { +- n = (remainder >> 3) + quotient * 100000ull; +- return 3; +- } +- remainder *= mod_inv1; +- +- if (t == 4 || remainder * mod_inv1 > max_quotient1) { +- n = (remainder >> 4) + quotient * 10000ull; +- return 4; +- } +- remainder *= mod_inv1; +- +- if (t == 5 || remainder * mod_inv1 > max_quotient1) { +- n = (remainder >> 5) + quotient * 1000ull; +- return 5; +- } +- remainder *= mod_inv1; +- +- if (t == 6 || remainder * mod_inv1 > max_quotient1) { +- n = (remainder >> 6) + quotient * 100ull; +- return 6; +- } +- remainder *= mod_inv1; +- +- n = (remainder >> 7) + quotient * 10ull; +- return 7; +-} +- +-// The main algorithm for shorter interval case +-template +-FMT_INLINE decimal_fp shorter_interval_case(int exponent) FMT_NOEXCEPT { +- decimal_fp ret_value; +- // Compute k and beta +- const int minus_k = floor_log10_pow2_minus_log10_4_over_3(exponent); +- const int beta_minus_1 = exponent + floor_log2_pow10(-minus_k); +- +- // Compute xi and zi +- using cache_entry_type = typename cache_accessor::cache_entry_type; +- const cache_entry_type cache = cache_accessor::get_cached_power(-minus_k); +- +- auto xi = cache_accessor::compute_left_endpoint_for_shorter_interval_case( +- cache, beta_minus_1); +- auto zi = cache_accessor::compute_right_endpoint_for_shorter_interval_case( +- cache, beta_minus_1); +- +- // If the left endpoint is not an integer, increase it +- if (!is_left_endpoint_integer_shorter_interval(exponent)) ++xi; +- +- // Try bigger divisor +- ret_value.significand = zi / 10; +- +- // If succeed, remove trailing zeros if necessary and return +- if (ret_value.significand * 10 >= xi) { +- ret_value.exponent = minus_k + 1; +- ret_value.exponent += remove_trailing_zeros(ret_value.significand); +- return ret_value; +- } +- +- // Otherwise, compute the round-up of y +- ret_value.significand = +- cache_accessor::compute_round_up_for_shorter_interval_case( +- cache, beta_minus_1); +- ret_value.exponent = minus_k; +- +- // When tie occurs, choose one of them according to the rule +- if (exponent >= float_info::shorter_interval_tie_lower_threshold && +- exponent <= float_info::shorter_interval_tie_upper_threshold) { +- ret_value.significand = ret_value.significand % 2 == 0 +- ? ret_value.significand +- : ret_value.significand - 1; +- } else if (ret_value.significand < xi) { +- ++ret_value.significand; +- } +- return ret_value; +-} +- +-template decimal_fp to_decimal(T x) FMT_NOEXCEPT { +- // Step 1: integer promotion & Schubfach multiplier calculation. +- +- using carrier_uint = typename float_info::carrier_uint; +- using cache_entry_type = typename cache_accessor::cache_entry_type; +- auto br = bit_cast(x); +- +- // Extract significand bits and exponent bits. +- const carrier_uint significand_mask = +- (static_cast(1) << float_info::significand_bits) - 1; +- carrier_uint significand = (br & significand_mask); +- int exponent = static_cast((br & exponent_mask()) >> +- float_info::significand_bits); +- +- if (exponent != 0) { // Check if normal. +- exponent += float_info::exponent_bias - float_info::significand_bits; +- +- // Shorter interval case; proceed like Schubfach. +- if (significand == 0) return shorter_interval_case(exponent); +- +- significand |= +- (static_cast(1) << float_info::significand_bits); +- } else { +- // Subnormal case; the interval is always regular. +- if (significand == 0) return {0, 0}; +- exponent = float_info::min_exponent - float_info::significand_bits; +- } +- +- const bool include_left_endpoint = (significand % 2 == 0); +- const bool include_right_endpoint = include_left_endpoint; +- +- // Compute k and beta. +- const int minus_k = floor_log10_pow2(exponent) - float_info::kappa; +- const cache_entry_type cache = cache_accessor::get_cached_power(-minus_k); +- const int beta_minus_1 = exponent + floor_log2_pow10(-minus_k); +- +- // Compute zi and deltai +- // 10^kappa <= deltai < 10^(kappa + 1) +- const uint32_t deltai = cache_accessor::compute_delta(cache, beta_minus_1); +- const carrier_uint two_fc = significand << 1; +- const carrier_uint two_fr = two_fc | 1; +- const carrier_uint zi = +- cache_accessor::compute_mul(two_fr << beta_minus_1, cache); +- +- // Step 2: Try larger divisor; remove trailing zeros if necessary +- +- // Using an upper bound on zi, we might be able to optimize the division +- // better than the compiler; we are computing zi / big_divisor here +- decimal_fp ret_value; +- ret_value.significand = divide_by_10_to_kappa_plus_1(zi); +- uint32_t r = static_cast(zi - float_info::big_divisor * +- ret_value.significand); +- +- if (r > deltai) { +- goto small_divisor_case_label; +- } else if (r < deltai) { +- // Exclude the right endpoint if necessary +- if (r == 0 && !include_right_endpoint && +- is_endpoint_integer(two_fr, exponent, minus_k)) { +- --ret_value.significand; +- r = float_info::big_divisor; +- goto small_divisor_case_label; +- } +- } else { +- // r == deltai; compare fractional parts +- // Check conditions in the order different from the paper +- // to take advantage of short-circuiting +- const carrier_uint two_fl = two_fc - 1; +- if ((!include_left_endpoint || +- !is_endpoint_integer(two_fl, exponent, minus_k)) && +- !cache_accessor::compute_mul_parity(two_fl, cache, beta_minus_1)) { +- goto small_divisor_case_label; +- } +- } +- ret_value.exponent = minus_k + float_info::kappa + 1; +- +- // We may need to remove trailing zeros +- ret_value.exponent += remove_trailing_zeros(ret_value.significand); +- return ret_value; +- +- // Step 3: Find the significand with the smaller divisor +- +-small_divisor_case_label: +- ret_value.significand *= 10; +- ret_value.exponent = minus_k + float_info::kappa; +- +- const uint32_t mask = (1u << float_info::kappa) - 1; +- auto dist = r - (deltai / 2) + (float_info::small_divisor / 2); +- +- // Is dist divisible by 2^kappa? +- if ((dist & mask) == 0) { +- const bool approx_y_parity = +- ((dist ^ (float_info::small_divisor / 2)) & 1) != 0; +- dist >>= float_info::kappa; +- +- // Is dist divisible by 5^kappa? +- if (check_divisibility_and_divide_by_pow5::kappa>(dist)) { +- ret_value.significand += dist; +- +- // Check z^(f) >= epsilon^(f) +- // We have either yi == zi - epsiloni or yi == (zi - epsiloni) - 1, +- // where yi == zi - epsiloni if and only if z^(f) >= epsilon^(f) +- // Since there are only 2 possibilities, we only need to care about the +- // parity. Also, zi and r should have the same parity since the divisor +- // is an even number +- if (cache_accessor::compute_mul_parity(two_fc, cache, beta_minus_1) != +- approx_y_parity) { +- --ret_value.significand; +- } else { +- // If z^(f) >= epsilon^(f), we might have a tie +- // when z^(f) == epsilon^(f), or equivalently, when y is an integer +- if (is_center_integer(two_fc, exponent, minus_k)) { +- ret_value.significand = ret_value.significand % 2 == 0 +- ? ret_value.significand +- : ret_value.significand - 1; +- } +- } +- } +- // Is dist not divisible by 5^kappa? +- else { +- ret_value.significand += dist; +- } +- } +- // Is dist not divisible by 2^kappa? +- else { +- // Since we know dist is small, we might be able to optimize the division +- // better than the compiler; we are computing dist / small_divisor here +- ret_value.significand += +- small_division_by_pow10::kappa>(dist); +- } +- return ret_value; +-} +-} // namespace dragonbox +- +-// Formats a floating-point number using a variation of the Fixed-Precision +-// Positive Floating-Point Printout ((FPP)^2) algorithm by Steele & White: +-// https://fmt.dev/papers/p372-steele.pdf. +-FMT_CONSTEXPR20 inline void format_dragon(fp value, bool is_predecessor_closer, +- int num_digits, buffer& buf, +- int& exp10) { +- bigint numerator; // 2 * R in (FPP)^2. +- bigint denominator; // 2 * S in (FPP)^2. +- // lower and upper are differences between value and corresponding boundaries. +- bigint lower; // (M^- in (FPP)^2). +- bigint upper_store; // upper's value if different from lower. +- bigint* upper = nullptr; // (M^+ in (FPP)^2). +- // Shift numerator and denominator by an extra bit or two (if lower boundary +- // is closer) to make lower and upper integers. This eliminates multiplication +- // by 2 during later computations. +- int shift = is_predecessor_closer ? 2 : 1; +- uint64_t significand = value.f << shift; +- if (value.e >= 0) { +- numerator.assign(significand); +- numerator <<= value.e; +- lower.assign(1); +- lower <<= value.e; +- if (shift != 1) { +- upper_store.assign(1); +- upper_store <<= value.e + 1; +- upper = &upper_store; +- } +- denominator.assign_pow10(exp10); +- denominator <<= shift; +- } else if (exp10 < 0) { +- numerator.assign_pow10(-exp10); +- lower.assign(numerator); +- if (shift != 1) { +- upper_store.assign(numerator); +- upper_store <<= 1; +- upper = &upper_store; +- } +- numerator *= significand; +- denominator.assign(1); +- denominator <<= shift - value.e; +- } else { +- numerator.assign(significand); +- denominator.assign_pow10(exp10); +- denominator <<= shift - value.e; +- lower.assign(1); +- if (shift != 1) { +- upper_store.assign(1ULL << 1); +- upper = &upper_store; +- } +- } +- // Invariant: value == (numerator / denominator) * pow(10, exp10). +- if (num_digits < 0) { +- // Generate the shortest representation. +- if (!upper) upper = &lower; +- bool even = (value.f & 1) == 0; +- num_digits = 0; +- char* data = buf.data(); +- for (;;) { +- int digit = numerator.divmod_assign(denominator); +- bool low = compare(numerator, lower) - even < 0; // numerator <[=] lower. +- // numerator + upper >[=] pow10: +- bool high = add_compare(numerator, *upper, denominator) + even > 0; +- data[num_digits++] = static_cast('0' + digit); +- if (low || high) { +- if (!low) { +- ++data[num_digits - 1]; +- } else if (high) { +- int result = add_compare(numerator, numerator, denominator); +- // Round half to even. +- if (result > 0 || (result == 0 && (digit % 2) != 0)) +- ++data[num_digits - 1]; +- } +- buf.try_resize(to_unsigned(num_digits)); +- exp10 -= num_digits - 1; +- return; +- } +- numerator *= 10; +- lower *= 10; +- if (upper != &lower) *upper *= 10; +- } +- } +- // Generate the given number of digits. +- exp10 -= num_digits - 1; +- if (num_digits == 0) { +- denominator *= 10; +- auto digit = add_compare(numerator, numerator, denominator) > 0 ? '1' : '0'; +- buf.push_back(digit); +- return; +- } +- buf.try_resize(to_unsigned(num_digits)); +- for (int i = 0; i < num_digits - 1; ++i) { +- int digit = numerator.divmod_assign(denominator); +- buf[i] = static_cast('0' + digit); +- numerator *= 10; +- } +- int digit = numerator.divmod_assign(denominator); +- auto result = add_compare(numerator, numerator, denominator); +- if (result > 0 || (result == 0 && (digit % 2) != 0)) { +- if (digit == 9) { +- const auto overflow = '0' + 10; +- buf[num_digits - 1] = overflow; +- // Propagate the carry. +- for (int i = num_digits - 1; i > 0 && buf[i] == overflow; --i) { +- buf[i] = '0'; +- ++buf[i - 1]; +- } +- if (buf[0] == overflow) { +- buf[0] = '1'; +- ++exp10; +- } +- return; +- } +- ++digit; +- } +- buf[num_digits - 1] = static_cast('0' + digit); +-} +- +-template +-FMT_HEADER_ONLY_CONSTEXPR20 int format_float(Float value, int precision, +- float_specs specs, +- buffer& buf) { +- // float is passed as double to reduce the number of instantiations. +- static_assert(!std::is_same::value, ""); +- FMT_ASSERT(value >= 0, "value is negative"); +- +- const bool fixed = specs.format == float_format::fixed; +- if (value <= 0) { // <= instead of == to silence a warning. +- if (precision <= 0 || !fixed) { +- buf.push_back('0'); +- return 0; +- } +- buf.try_resize(to_unsigned(precision)); +- fill_n(buf.data(), precision, '0'); +- return -precision; +- } +- +- if (specs.fallback) return snprintf_float(value, precision, specs, buf); +- +- if (!is_constant_evaluated() && precision < 0) { +- // Use Dragonbox for the shortest format. +- if (specs.binary32) { +- auto dec = dragonbox::to_decimal(static_cast(value)); +- write(buffer_appender(buf), dec.significand); +- return dec.exponent; +- } +- auto dec = dragonbox::to_decimal(static_cast(value)); +- write(buffer_appender(buf), dec.significand); +- return dec.exponent; +- } +- +- int exp = 0; +- bool use_dragon = true; +- if (is_fast_float()) { +- // Use Grisu + Dragon4 for the given precision: +- // https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf. +- const int min_exp = -60; // alpha in Grisu. +- int cached_exp10 = 0; // K in Grisu. +- fp normalized = normalize(fp(value)); +- const auto cached_pow = get_cached_power( +- min_exp - (normalized.e + fp::num_significand_bits), cached_exp10); +- normalized = normalized * cached_pow; +- gen_digits_handler handler{buf.data(), 0, precision, -cached_exp10, fixed}; +- if (grisu_gen_digits(normalized, 1, exp, handler) != digits::error && +- !is_constant_evaluated()) { +- exp += handler.exp10; +- buf.try_resize(to_unsigned(handler.size)); +- use_dragon = false; +- } else { +- exp += handler.size - cached_exp10 - 1; +- precision = handler.precision; +- } +- } +- if (use_dragon) { +- auto f = fp(); +- bool is_predecessor_closer = +- specs.binary32 ? f.assign(static_cast(value)) : f.assign(value); +- // Limit precision to the maximum possible number of significant digits in +- // an IEEE754 double because we don't need to generate zeros. +- const int max_double_digits = 767; +- if (precision > max_double_digits) precision = max_double_digits; +- format_dragon(f, is_predecessor_closer, precision, buf, exp); +- } +- if (!fixed && !specs.showpoint) { +- // Remove trailing zeros. +- auto num_digits = buf.size(); +- while (num_digits > 0 && buf[num_digits - 1] == '0') { +- --num_digits; +- ++exp; +- } +- buf.try_resize(num_digits); +- } +- return exp; +-} +- +-template +-int snprintf_float(T value, int precision, float_specs specs, +- buffer& buf) { +- // Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail. +- FMT_ASSERT(buf.capacity() > buf.size(), "empty buffer"); +- static_assert(!std::is_same::value, ""); +- +- // Subtract 1 to account for the difference in precision since we use %e for +- // both general and exponent format. +- if (specs.format == float_format::general || +- specs.format == float_format::exp) +- precision = (precision >= 0 ? precision : 6) - 1; +- +- // Build the format string. +- enum { max_format_size = 7 }; // The longest format is "%#.*Le". +- char format[max_format_size]; +- char* format_ptr = format; +- *format_ptr++ = '%'; +- if (specs.showpoint && specs.format == float_format::hex) *format_ptr++ = '#'; +- if (precision >= 0) { +- *format_ptr++ = '.'; +- *format_ptr++ = '*'; +- } +- if (std::is_same()) *format_ptr++ = 'L'; +- *format_ptr++ = specs.format != float_format::hex +- ? (specs.format == float_format::fixed ? 'f' : 'e') +- : (specs.upper ? 'A' : 'a'); +- *format_ptr = '\0'; +- +- // Format using snprintf. +- auto offset = buf.size(); +- for (;;) { +- auto begin = buf.data() + offset; +- auto capacity = buf.capacity() - offset; +-#ifdef FMT_FUZZ +- if (precision > 100000) +- throw std::runtime_error( +- "fuzz mode - avoid large allocation inside snprintf"); +-#endif +- // Suppress the warning about a nonliteral format string. +- // Cannot use auto because of a bug in MinGW (#1532). +- int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF; +- int result = precision >= 0 +- ? snprintf_ptr(begin, capacity, format, precision, value) +- : snprintf_ptr(begin, capacity, format, value); +- if (result < 0) { +- // The buffer will grow exponentially. +- buf.try_reserve(buf.capacity() + 1); +- continue; +- } +- auto size = to_unsigned(result); +- // Size equal to capacity means that the last character was truncated. +- if (size >= capacity) { +- buf.try_reserve(size + offset + 1); // Add 1 for the terminating '\0'. +- continue; +- } +- auto is_digit = [](char c) { return c >= '0' && c <= '9'; }; +- if (specs.format == float_format::fixed) { +- if (precision == 0) { +- buf.try_resize(size); +- return 0; +- } +- // Find and remove the decimal point. +- auto end = begin + size, p = end; +- do { +- --p; +- } while (is_digit(*p)); +- int fraction_size = static_cast(end - p - 1); +- std::memmove(p, p + 1, to_unsigned(fraction_size)); +- buf.try_resize(size - 1); +- return -fraction_size; +- } +- if (specs.format == float_format::hex) { +- buf.try_resize(size + offset); +- return 0; +- } +- // Find and parse the exponent. +- auto end = begin + size, exp_pos = end; +- do { +- --exp_pos; +- } while (*exp_pos != 'e'); +- char sign = exp_pos[1]; +- FMT_ASSERT(sign == '+' || sign == '-', ""); +- int exp = 0; +- auto p = exp_pos + 2; // Skip 'e' and sign. +- do { +- FMT_ASSERT(is_digit(*p), ""); +- exp = exp * 10 + (*p++ - '0'); +- } while (p != end); +- if (sign == '-') exp = -exp; +- int fraction_size = 0; +- if (exp_pos != begin + 1) { +- // Remove trailing zeros. +- auto fraction_end = exp_pos - 1; +- while (*fraction_end == '0') --fraction_end; +- // Move the fractional part left to get rid of the decimal point. +- fraction_size = static_cast(fraction_end - begin - 1); +- std::memmove(begin + 1, begin + 2, to_unsigned(fraction_size)); +- } +- buf.try_resize(to_unsigned(fraction_size) + offset + 1); +- return exp - fraction_size; +- } +-} +-} // namespace detail +- +-template <> struct formatter { +- FMT_CONSTEXPR format_parse_context::iterator parse( +- format_parse_context& ctx) { +- return ctx.begin(); +- } +- +- format_context::iterator format(const detail::bigint& n, +- format_context& ctx) { +- auto out = ctx.out(); +- bool first = true; +- for (auto i = n.bigits_.size(); i > 0; --i) { +- auto value = n.bigits_[i - 1u]; +- if (first) { +- out = format_to(out, FMT_STRING("{:x}"), value); +- first = false; +- continue; +- } +- out = format_to(out, FMT_STRING("{:08x}"), value); +- } +- if (n.exp_ > 0) +- out = format_to(out, FMT_STRING("p{}"), +- n.exp_ * detail::bigint::bigit_bits); +- return out; +- } +-}; +- +-FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) { +- for_each_codepoint(s, [this](uint32_t cp, string_view) { +- if (cp == invalid_code_point) FMT_THROW(std::runtime_error("invalid utf8")); +- if (cp <= 0xFFFF) { +- buffer_.push_back(static_cast(cp)); +- } else { +- cp -= 0x10000; +- buffer_.push_back(static_cast(0xD800 + (cp >> 10))); +- buffer_.push_back(static_cast(0xDC00 + (cp & 0x3FF))); +- } +- return true; +- }); +- buffer_.push_back(0); +-} +- +-FMT_FUNC void format_system_error(detail::buffer& out, int error_code, +- const char* message) FMT_NOEXCEPT { +- FMT_TRY { +- auto ec = std::error_code(error_code, std::generic_category()); +- write(std::back_inserter(out), std::system_error(ec, message).what()); +- return; +- } +- FMT_CATCH(...) {} +- format_error_code(out, error_code, message); +-} +- +-FMT_FUNC void report_system_error(int error_code, +- const char* message) FMT_NOEXCEPT { +- report_error(format_system_error, error_code, message); +-} +- +-// DEPRECATED! +-// This function is defined here and not inline for ABI compatibility. +-FMT_FUNC void detail::error_handler::on_error(const char* message) { +- throw_format_error(message); +-} +- +-FMT_FUNC std::string vformat(string_view fmt, format_args args) { +- // Don't optimize the "{}" case to keep the binary size small and because it +- // can be better optimized in fmt::format anyway. +- auto buffer = memory_buffer(); +- detail::vformat_to(buffer, fmt, args); +- return to_string(buffer); +-} +- +-#ifdef _WIN32 +-namespace detail { +-using dword = conditional_t; +-extern "C" __declspec(dllimport) int __stdcall WriteConsoleW( // +- void*, const void*, dword, dword*, void*); +-} // namespace detail +-#endif +- +-namespace detail { +-FMT_FUNC void print(std::FILE* f, string_view text) { +-#ifdef _WIN32 +- auto fd = _fileno(f); +- if (_isatty(fd)) { +- detail::utf8_to_utf16 u16(string_view(text.data(), text.size())); +- auto written = detail::dword(); +- if (detail::WriteConsoleW(reinterpret_cast(_get_osfhandle(fd)), +- u16.c_str(), static_cast(u16.size()), +- &written, nullptr)) { +- return; +- } +- // Fallback to fwrite on failure. It can happen if the output has been +- // redirected to NUL. +- } +-#endif +- detail::fwrite_fully(text.data(), 1, text.size(), f); +-} +-} // namespace detail +- +-FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) { +- memory_buffer buffer; +- detail::vformat_to(buffer, format_str, args); +- detail::print(f, {buffer.data(), buffer.size()}); +-} +- +-#ifdef _WIN32 +-// Print assuming legacy (non-Unicode) encoding. +-FMT_FUNC void detail::vprint_mojibake(std::FILE* f, string_view format_str, +- format_args args) { +- memory_buffer buffer; +- detail::vformat_to(buffer, format_str, +- basic_format_args>(args)); +- fwrite_fully(buffer.data(), 1, buffer.size(), f); +-} +-#endif +- +-FMT_FUNC void vprint(string_view format_str, format_args args) { +- vprint(stdout, format_str, args); +-} +- +-FMT_END_NAMESPACE +- +-#endif // FMT_FORMAT_INL_H_ +diff --git a/include/dpp/fmt/format.h b/include/dpp/fmt/format.h +deleted file mode 100644 +index ee69651..0000000 +--- a/include/dpp/fmt/format.h ++++ /dev/null +@@ -1,3104 +0,0 @@ +-/* +- Formatting library for C++ +- +- Copyright (c) 2012 - present, Victor Zverovich +- +- Permission is hereby granted, free of charge, to any person obtaining +- a copy of this software and associated documentation files (the +- "Software"), to deal in the Software without restriction, including +- without limitation the rights to use, copy, modify, merge, publish, +- distribute, sublicense, and/or sell copies of the Software, and to +- permit persons to whom the Software is furnished to do so, subject to +- the following conditions: +- +- The above copyright notice and this permission notice shall be +- included in all copies or substantial portions of the Software. +- +- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +- +- --- Optional exception to the license --- +- +- As an exception, if, as a result of your compiling your source code, portions +- of this Software are embedded into a machine-executable object form of such +- source code, you may redistribute such embedded portions in such object form +- without including the above copyright and permission notices. +- */ +- +-#ifndef FMT_FORMAT_H_ +-#define FMT_FORMAT_H_ +- +-#include // std::signbit +-#include // uint32_t +-#include // std::numeric_limits +-#include // std::uninitialized_copy +-#include // std::runtime_error +-#include // std::system_error +-#include // std::swap +- +-#ifdef __cpp_lib_bit_cast +-# include // std::bitcast +-#endif +- +-#include "core.h" +- +-#if FMT_GCC_VERSION +-# define FMT_GCC_VISIBILITY_HIDDEN __attribute__((visibility("hidden"))) +-#else +-# define FMT_GCC_VISIBILITY_HIDDEN +-#endif +- +-#ifdef __NVCC__ +-# define FMT_CUDA_VERSION (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__) +-#else +-# define FMT_CUDA_VERSION 0 +-#endif +- +-#ifdef __has_builtin +-# define FMT_HAS_BUILTIN(x) __has_builtin(x) +-#else +-# define FMT_HAS_BUILTIN(x) 0 +-#endif +- +-#if FMT_GCC_VERSION || FMT_CLANG_VERSION +-# define FMT_NOINLINE __attribute__((noinline)) +-#else +-# define FMT_NOINLINE +-#endif +- +-#if FMT_MSC_VER +-# define FMT_MSC_DEFAULT = default +-#else +-# define FMT_MSC_DEFAULT +-#endif +- +-#ifndef FMT_THROW +-# if FMT_EXCEPTIONS +-# if FMT_MSC_VER || FMT_NVCC +-FMT_BEGIN_NAMESPACE +-namespace detail { +-template inline void do_throw(const Exception& x) { +- // Silence unreachable code warnings in MSVC and NVCC because these +- // are nearly impossible to fix in a generic code. +- volatile bool b = true; +- if (b) throw x; +-} +-} // namespace detail +-FMT_END_NAMESPACE +-# define FMT_THROW(x) detail::do_throw(x) +-# else +-# define FMT_THROW(x) throw x +-# endif +-# else +-# define FMT_THROW(x) \ +- do { \ +- FMT_ASSERT(false, (x).what()); \ +- } while (false) +-# endif +-#endif +- +-#if FMT_EXCEPTIONS +-# define FMT_TRY try +-# define FMT_CATCH(x) catch (x) +-#else +-# define FMT_TRY if (true) +-# define FMT_CATCH(x) if (false) +-#endif +- +-#ifndef FMT_MAYBE_UNUSED +-# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) +-# define FMT_MAYBE_UNUSED [[maybe_unused]] +-# else +-# define FMT_MAYBE_UNUSED +-# endif +-#endif +- +-// Workaround broken [[deprecated]] in the Intel, PGI and NVCC compilers. +-#if FMT_ICC_VERSION || defined(__PGI) || FMT_NVCC +-# define FMT_DEPRECATED_ALIAS +-#else +-# define FMT_DEPRECATED_ALIAS FMT_DEPRECATED +-#endif +- +-#ifndef FMT_USE_USER_DEFINED_LITERALS +-// EDG based compilers (Intel, NVIDIA, Elbrus, etc), GCC and MSVC support UDLs. +-# if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \ +- FMT_MSC_VER >= 1900) && \ +- (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= /* UDL feature */ 480) +-# define FMT_USE_USER_DEFINED_LITERALS 1 +-# else +-# define FMT_USE_USER_DEFINED_LITERALS 0 +-# endif +-#endif +- +-// Defining FMT_REDUCE_INT_INSTANTIATIONS to 1, will reduce the number of +-// integer formatter template instantiations to just one by only using the +-// largest integer type. This results in a reduction in binary size but will +-// cause a decrease in integer formatting performance. +-#if !defined(FMT_REDUCE_INT_INSTANTIATIONS) +-# define FMT_REDUCE_INT_INSTANTIATIONS 0 +-#endif +- +-// __builtin_clz is broken in clang with Microsoft CodeGen: +-// https://github.com/fmtlib/fmt/issues/519. +-#if !FMT_MSC_VER +-# if FMT_HAS_BUILTIN(__builtin_clz) || FMT_GCC_VERSION || FMT_ICC_VERSION +-# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) +-# endif +-# if FMT_HAS_BUILTIN(__builtin_clzll) || FMT_GCC_VERSION || FMT_ICC_VERSION +-# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) +-# endif +-#endif +- +-// __builtin_ctz is broken in Intel Compiler Classic on Windows: +-// https://github.com/fmtlib/fmt/issues/2510. +-#ifndef __ICL +-# if FMT_HAS_BUILTIN(__builtin_ctz) || FMT_GCC_VERSION || FMT_ICC_VERSION +-# define FMT_BUILTIN_CTZ(n) __builtin_ctz(n) +-# endif +-# if FMT_HAS_BUILTIN(__builtin_ctzll) || FMT_GCC_VERSION || FMT_ICC_VERSION +-# define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n) +-# endif +-#endif +- +-#if FMT_MSC_VER +-# include // _BitScanReverse[64], _BitScanForward[64], _umul128 +-#endif +- +-// Some compilers masquerade as both MSVC and GCC-likes or otherwise support +-// __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the +-// MSVC intrinsics if the clz and clzll builtins are not available. +-#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(FMT_BUILTIN_CTZLL) +-FMT_BEGIN_NAMESPACE +-namespace detail { +-// Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning. +-# if !defined(__clang__) +-# pragma intrinsic(_BitScanForward) +-# pragma intrinsic(_BitScanReverse) +-# if defined(_WIN64) +-# pragma intrinsic(_BitScanForward64) +-# pragma intrinsic(_BitScanReverse64) +-# endif +-# endif +- +-inline auto clz(uint32_t x) -> int { +- unsigned long r = 0; +- _BitScanReverse(&r, x); +- FMT_ASSERT(x != 0, ""); +- // Static analysis complains about using uninitialized data +- // "r", but the only way that can happen is if "x" is 0, +- // which the callers guarantee to not happen. +- FMT_MSC_WARNING(suppress : 6102) +- return 31 ^ static_cast(r); +-} +-# define FMT_BUILTIN_CLZ(n) detail::clz(n) +- +-inline auto clzll(uint64_t x) -> int { +- unsigned long r = 0; +-# ifdef _WIN64 +- _BitScanReverse64(&r, x); +-# else +- // Scan the high 32 bits. +- if (_BitScanReverse(&r, static_cast(x >> 32))) return 63 ^ (r + 32); +- // Scan the low 32 bits. +- _BitScanReverse(&r, static_cast(x)); +-# endif +- FMT_ASSERT(x != 0, ""); +- FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. +- return 63 ^ static_cast(r); +-} +-# define FMT_BUILTIN_CLZLL(n) detail::clzll(n) +- +-inline auto ctz(uint32_t x) -> int { +- unsigned long r = 0; +- _BitScanForward(&r, x); +- FMT_ASSERT(x != 0, ""); +- FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. +- return static_cast(r); +-} +-# define FMT_BUILTIN_CTZ(n) detail::ctz(n) +- +-inline auto ctzll(uint64_t x) -> int { +- unsigned long r = 0; +- FMT_ASSERT(x != 0, ""); +- FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. +-# ifdef _WIN64 +- _BitScanForward64(&r, x); +-# else +- // Scan the low 32 bits. +- if (_BitScanForward(&r, static_cast(x))) return static_cast(r); +- // Scan the high 32 bits. +- _BitScanForward(&r, static_cast(x >> 32)); +- r += 32; +-# endif +- return static_cast(r); +-} +-# define FMT_BUILTIN_CTZLL(n) detail::ctzll(n) +-} // namespace detail +-FMT_END_NAMESPACE +-#endif +- +-#ifdef FMT_HEADER_ONLY +-# define FMT_HEADER_ONLY_CONSTEXPR20 FMT_CONSTEXPR20 +-#else +-# define FMT_HEADER_ONLY_CONSTEXPR20 +-#endif +- +-FMT_BEGIN_NAMESPACE +-namespace detail { +- +-template class formatbuf : public Streambuf { +- private: +- using char_type = typename Streambuf::char_type; +- using streamsize = decltype(std::declval().sputn(nullptr, 0)); +- using int_type = typename Streambuf::int_type; +- using traits_type = typename Streambuf::traits_type; +- +- buffer& buffer_; +- +- public: +- explicit formatbuf(buffer& buf) : buffer_(buf) {} +- +- protected: +- // The put area is always empty. This makes the implementation simpler and has +- // the advantage that the streambuf and the buffer are always in sync and +- // sputc never writes into uninitialized memory. A disadvantage is that each +- // call to sputc always results in a (virtual) call to overflow. There is no +- // disadvantage here for sputn since this always results in a call to xsputn. +- +- auto overflow(int_type ch) -> int_type override { +- if (!traits_type::eq_int_type(ch, traits_type::eof())) +- buffer_.push_back(static_cast(ch)); +- return ch; +- } +- +- auto xsputn(const char_type* s, streamsize count) -> streamsize override { +- buffer_.append(s, s + count); +- return count; +- } +-}; +- +-// Implementation of std::bit_cast for pre-C++20. +-template +-FMT_CONSTEXPR20 auto bit_cast(const From& from) -> To { +- static_assert(sizeof(To) == sizeof(From), "size mismatch"); +-#ifdef __cpp_lib_bit_cast +- if (is_constant_evaluated()) return std::bit_cast(from); +-#endif +- auto to = To(); +- std::memcpy(&to, &from, sizeof(to)); +- return to; +-} +- +-inline auto is_big_endian() -> bool { +-#ifdef _WIN32 +- return false; +-#elif defined(__BIG_ENDIAN__) +- return true; +-#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) +- return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__; +-#else +- struct bytes { +- char data[sizeof(int)]; +- }; +- return bit_cast(1).data[0] == 0; +-#endif +-} +- +-// A fallback implementation of uintptr_t for systems that lack it. +-struct fallback_uintptr { +- unsigned char value[sizeof(void*)]; +- +- fallback_uintptr() = default; +- explicit fallback_uintptr(const void* p) { +- *this = bit_cast(p); +- if (const_check(is_big_endian())) { +- for (size_t i = 0, j = sizeof(void*) - 1; i < j; ++i, --j) +- std::swap(value[i], value[j]); +- } +- } +-}; +-#ifdef UINTPTR_MAX +-using uintptr_t = ::uintptr_t; +-inline auto to_uintptr(const void* p) -> uintptr_t { +- return bit_cast(p); +-} +-#else +-using uintptr_t = fallback_uintptr; +-inline auto to_uintptr(const void* p) -> fallback_uintptr { +- return fallback_uintptr(p); +-} +-#endif +- +-// Returns the largest possible value for type T. Same as +-// std::numeric_limits::max() but shorter and not affected by the max macro. +-template constexpr auto max_value() -> T { +- return (std::numeric_limits::max)(); +-} +-template constexpr auto num_bits() -> int { +- return std::numeric_limits::digits; +-} +-// std::numeric_limits::digits may return 0 for 128-bit ints. +-template <> constexpr auto num_bits() -> int { return 128; } +-template <> constexpr auto num_bits() -> int { return 128; } +-template <> constexpr auto num_bits() -> int { +- return static_cast(sizeof(void*) * +- std::numeric_limits::digits); +-} +- +-FMT_INLINE void assume(bool condition) { +- (void)condition; +-#if FMT_HAS_BUILTIN(__builtin_assume) +- __builtin_assume(condition); +-#endif +-} +- +-// An approximation of iterator_t for pre-C++20 systems. +-template +-using iterator_t = decltype(std::begin(std::declval())); +-template using sentinel_t = decltype(std::end(std::declval())); +- +-// A workaround for std::string not having mutable data() until C++17. +-template +-inline auto get_data(std::basic_string& s) -> Char* { +- return &s[0]; +-} +-template +-inline auto get_data(Container& c) -> typename Container::value_type* { +- return c.data(); +-} +- +-#if defined(_SECURE_SCL) && _SECURE_SCL +-// Make a checked iterator to avoid MSVC warnings. +-template using checked_ptr = stdext::checked_array_iterator; +-template +-constexpr auto make_checked(T* p, size_t size) -> checked_ptr { +- return {p, size}; +-} +-#else +-template using checked_ptr = T*; +-template constexpr auto make_checked(T* p, size_t) -> T* { +- return p; +-} +-#endif +- +-// Attempts to reserve space for n extra characters in the output range. +-// Returns a pointer to the reserved range or a reference to it. +-template ::value)> +-#if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION +-__attribute__((no_sanitize("undefined"))) +-#endif +-inline auto +-reserve(std::back_insert_iterator it, size_t n) +- -> checked_ptr { +- Container& c = get_container(it); +- size_t size = c.size(); +- c.resize(size + n); +- return make_checked(get_data(c) + size, n); +-} +- +-template +-inline auto reserve(buffer_appender it, size_t n) -> buffer_appender { +- buffer& buf = get_container(it); +- buf.try_reserve(buf.size() + n); +- return it; +-} +- +-template +-constexpr auto reserve(Iterator& it, size_t) -> Iterator& { +- return it; +-} +- +-template +-using reserve_iterator = +- remove_reference_t(), 0))>; +- +-template +-constexpr auto to_pointer(OutputIt, size_t) -> T* { +- return nullptr; +-} +-template auto to_pointer(buffer_appender it, size_t n) -> T* { +- buffer& buf = get_container(it); +- auto size = buf.size(); +- if (buf.capacity() < size + n) return nullptr; +- buf.try_resize(size + n); +- return buf.data() + size; +-} +- +-template ::value)> +-inline auto base_iterator(std::back_insert_iterator& it, +- checked_ptr) +- -> std::back_insert_iterator { +- return it; +-} +- +-template +-constexpr auto base_iterator(Iterator, Iterator it) -> Iterator { +- return it; +-} +- +-// is spectacularly slow to compile in C++20 so use a simple fill_n +-// instead (#1998). +-template +-FMT_CONSTEXPR auto fill_n(OutputIt out, Size count, const T& value) +- -> OutputIt { +- for (Size i = 0; i < count; ++i) *out++ = value; +- return out; +-} +-template +-FMT_CONSTEXPR20 auto fill_n(T* out, Size count, char value) -> T* { +- if (is_constant_evaluated()) { +- return fill_n(out, count, value); +- } +- std::memset(out, value, to_unsigned(count)); +- return out + count; +-} +- +-#ifdef __cpp_char8_t +-using char8_type = char8_t; +-#else +-enum char8_type : unsigned char {}; +-#endif +- +-template +-FMT_CONSTEXPR FMT_NOINLINE auto copy_str_noinline(InputIt begin, InputIt end, +- OutputIt out) -> OutputIt { +- return copy_str(begin, end, out); +-} +- +-// A public domain branchless UTF-8 decoder by Christopher Wellons: +-// https://github.com/skeeto/branchless-utf8 +-/* Decode the next character, c, from s, reporting errors in e. +- * +- * Since this is a branchless decoder, four bytes will be read from the +- * buffer regardless of the actual length of the next character. This +- * means the buffer _must_ have at least three bytes of zero padding +- * following the end of the data stream. +- * +- * Errors are reported in e, which will be non-zero if the parsed +- * character was somehow invalid: invalid byte sequence, non-canonical +- * encoding, or a surrogate half. +- * +- * The function returns a pointer to the next character. When an error +- * occurs, this pointer will be a guess that depends on the particular +- * error, but it will always advance at least one byte. +- */ +-FMT_CONSTEXPR inline auto utf8_decode(const char* s, uint32_t* c, int* e) +- -> const char* { +- constexpr const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07}; +- constexpr const uint32_t mins[] = {4194304, 0, 128, 2048, 65536}; +- constexpr const int shiftc[] = {0, 18, 12, 6, 0}; +- constexpr const int shifte[] = {0, 6, 4, 2, 0}; +- +- int len = code_point_length(s); +- const char* next = s + len; +- +- // Assume a four-byte character and load four bytes. Unused bits are +- // shifted out. +- *c = uint32_t(s[0] & masks[len]) << 18; +- *c |= uint32_t(s[1] & 0x3f) << 12; +- *c |= uint32_t(s[2] & 0x3f) << 6; +- *c |= uint32_t(s[3] & 0x3f) << 0; +- *c >>= shiftc[len]; +- +- // Accumulate the various error conditions. +- using uchar = unsigned char; +- *e = (*c < mins[len]) << 6; // non-canonical encoding +- *e |= ((*c >> 11) == 0x1b) << 7; // surrogate half? +- *e |= (*c > 0x10FFFF) << 8; // out of range? +- *e |= (uchar(s[1]) & 0xc0) >> 2; +- *e |= (uchar(s[2]) & 0xc0) >> 4; +- *e |= uchar(s[3]) >> 6; +- *e ^= 0x2a; // top two bits of each tail byte correct? +- *e >>= shifte[len]; +- +- return next; +-} +- +-constexpr uint32_t invalid_code_point = ~uint32_t(); +- +-// Invokes f(cp, sv) for every code point cp in s with sv being the string view +-// corresponding to the code point. cp is invalid_code_point on error. +-template +-FMT_CONSTEXPR void for_each_codepoint(string_view s, F f) { +- auto decode = [f](const char* buf_ptr, const char* ptr) { +- auto cp = uint32_t(); +- auto error = 0; +- auto end = utf8_decode(buf_ptr, &cp, &error); +- bool result = f(error ? invalid_code_point : cp, +- string_view(ptr, to_unsigned(end - buf_ptr))); +- return result ? end : nullptr; +- }; +- auto p = s.data(); +- const size_t block_size = 4; // utf8_decode always reads blocks of 4 chars. +- if (s.size() >= block_size) { +- for (auto end = p + s.size() - block_size + 1; p < end;) { +- p = decode(p, p); +- if (!p) return; +- } +- } +- if (auto num_chars_left = s.data() + s.size() - p) { +- char buf[2 * block_size - 1] = {}; +- copy_str(p, p + num_chars_left, buf); +- const char* buf_ptr = buf; +- do { +- auto end = decode(buf_ptr, p); +- if (!end) return; +- p += end - buf_ptr; +- buf_ptr = end; +- } while (buf_ptr - buf < num_chars_left); +- } +-} +- +-template +-inline auto compute_width(basic_string_view s) -> size_t { +- return s.size(); +-} +- +-// Computes approximate display width of a UTF-8 string. +-FMT_CONSTEXPR inline size_t compute_width(string_view s) { +- size_t num_code_points = 0; +- // It is not a lambda for compatibility with C++14. +- struct count_code_points { +- size_t* count; +- FMT_CONSTEXPR auto operator()(uint32_t cp, string_view) const -> bool { +- *count += detail::to_unsigned( +- 1 + +- (cp >= 0x1100 && +- (cp <= 0x115f || // Hangul Jamo init. consonants +- cp == 0x2329 || // LEFT-POINTING ANGLE BRACKET +- cp == 0x232a || // RIGHT-POINTING ANGLE BRACKET +- // CJK ... Yi except IDEOGRAPHIC HALF FILL SPACE: +- (cp >= 0x2e80 && cp <= 0xa4cf && cp != 0x303f) || +- (cp >= 0xac00 && cp <= 0xd7a3) || // Hangul Syllables +- (cp >= 0xf900 && cp <= 0xfaff) || // CJK Compatibility Ideographs +- (cp >= 0xfe10 && cp <= 0xfe19) || // Vertical Forms +- (cp >= 0xfe30 && cp <= 0xfe6f) || // CJK Compatibility Forms +- (cp >= 0xff00 && cp <= 0xff60) || // Fullwidth Forms +- (cp >= 0xffe0 && cp <= 0xffe6) || // Fullwidth Forms +- (cp >= 0x20000 && cp <= 0x2fffd) || // CJK +- (cp >= 0x30000 && cp <= 0x3fffd) || +- // Miscellaneous Symbols and Pictographs + Emoticons: +- (cp >= 0x1f300 && cp <= 0x1f64f) || +- // Supplemental Symbols and Pictographs: +- (cp >= 0x1f900 && cp <= 0x1f9ff)))); +- return true; +- } +- }; +- for_each_codepoint(s, count_code_points{&num_code_points}); +- return num_code_points; +-} +- +-inline auto compute_width(basic_string_view s) -> size_t { +- return compute_width(basic_string_view( +- reinterpret_cast(s.data()), s.size())); +-} +- +-template +-inline auto code_point_index(basic_string_view s, size_t n) -> size_t { +- size_t size = s.size(); +- return n < size ? n : size; +-} +- +-// Calculates the index of the nth code point in a UTF-8 string. +-inline auto code_point_index(basic_string_view s, size_t n) +- -> size_t { +- const char8_type* data = s.data(); +- size_t num_code_points = 0; +- for (size_t i = 0, size = s.size(); i != size; ++i) { +- if ((data[i] & 0xc0) != 0x80 && ++num_code_points > n) return i; +- } +- return s.size(); +-} +- +-template ::value> +-struct is_fast_float : bool_constant::is_iec559 && +- sizeof(T) <= sizeof(double)> {}; +-template struct is_fast_float : std::false_type {}; +- +-#ifndef FMT_USE_FULL_CACHE_DRAGONBOX +-# define FMT_USE_FULL_CACHE_DRAGONBOX 0 +-#endif +- +-template +-template +-void buffer::append(const U* begin, const U* end) { +- while (begin != end) { +- auto count = to_unsigned(end - begin); +- try_reserve(size_ + count); +- auto free_cap = capacity_ - size_; +- if (free_cap < count) count = free_cap; +- std::uninitialized_copy_n(begin, count, make_checked(ptr_ + size_, count)); +- size_ += count; +- begin += count; +- } +-} +- +-template +-struct is_locale : std::false_type {}; +-template +-struct is_locale> : std::true_type {}; +-} // namespace detail +- +-FMT_MODULE_EXPORT_BEGIN +- +-// The number of characters to store in the basic_memory_buffer object itself +-// to avoid dynamic memory allocation. +-enum { inline_buffer_size = 500 }; +- +-/** +- \rst +- A dynamically growing memory buffer for trivially copyable/constructible types +- with the first ``SIZE`` elements stored in the object itself. +- +- You can use the ``memory_buffer`` type alias for ``char`` instead. +- +- **Example**:: +- +- auto out = fmt::memory_buffer(); +- format_to(std::back_inserter(out), "The answer is {}.", 42); +- +- This will append the following output to the ``out`` object: +- +- .. code-block:: none +- +- The answer is 42. +- +- The output can be converted to an ``std::string`` with ``to_string(out)``. +- \endrst +- */ +-template > +-class basic_memory_buffer final : public detail::buffer { +- private: +- T store_[SIZE]; +- +- // Don't inherit from Allocator avoid generating type_info for it. +- Allocator alloc_; +- +- // Deallocate memory allocated by the buffer. +- FMT_CONSTEXPR20 void deallocate() { +- T* data = this->data(); +- if (data != store_) alloc_.deallocate(data, this->capacity()); +- } +- +- protected: +- FMT_CONSTEXPR20 void grow(size_t size) override; +- +- public: +- using value_type = T; +- using const_reference = const T&; +- +- FMT_CONSTEXPR20 explicit basic_memory_buffer( +- const Allocator& alloc = Allocator()) +- : alloc_(alloc) { +- this->set(store_, SIZE); +- if (detail::is_constant_evaluated()) { +- detail::fill_n(store_, SIZE, T{}); +- } +- } +- FMT_CONSTEXPR20 ~basic_memory_buffer() { deallocate(); } +- +- private: +- // Move data from other to this buffer. +- FMT_CONSTEXPR20 void move(basic_memory_buffer& other) { +- alloc_ = std::move(other.alloc_); +- T* data = other.data(); +- size_t size = other.size(), capacity = other.capacity(); +- if (data == other.store_) { +- this->set(store_, capacity); +- if (detail::is_constant_evaluated()) { +- detail::copy_str(other.store_, other.store_ + size, +- detail::make_checked(store_, capacity)); +- } else { +- std::uninitialized_copy(other.store_, other.store_ + size, +- detail::make_checked(store_, capacity)); +- } +- } else { +- this->set(data, capacity); +- // Set pointer to the inline array so that delete is not called +- // when deallocating. +- other.set(other.store_, 0); +- } +- this->resize(size); +- } +- +- public: +- /** +- \rst +- Constructs a :class:`fmt::basic_memory_buffer` object moving the content +- of the other object to it. +- \endrst +- */ +- FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer&& other) +- FMT_NOEXCEPT { +- move(other); +- } +- +- /** +- \rst +- Moves the content of the other ``basic_memory_buffer`` object to this one. +- \endrst +- */ +- auto operator=(basic_memory_buffer&& other) FMT_NOEXCEPT +- -> basic_memory_buffer& { +- FMT_ASSERT(this != &other, ""); +- deallocate(); +- move(other); +- return *this; +- } +- +- // Returns a copy of the allocator associated with this buffer. +- auto get_allocator() const -> Allocator { return alloc_; } +- +- /** +- Resizes the buffer to contain *count* elements. If T is a POD type new +- elements may not be initialized. +- */ +- FMT_CONSTEXPR20 void resize(size_t count) { this->try_resize(count); } +- +- /** Increases the buffer capacity to *new_capacity*. */ +- void reserve(size_t new_capacity) { this->try_reserve(new_capacity); } +- +- // Directly append data into the buffer +- using detail::buffer::append; +- template +- void append(const ContiguousRange& range) { +- append(range.data(), range.data() + range.size()); +- } +-}; +- +-template +-FMT_CONSTEXPR20 void basic_memory_buffer::grow( +- size_t size) { +-#ifdef FMT_FUZZ +- if (size > 5000) throw std::runtime_error("fuzz mode - won't grow that much"); +-#endif +- const size_t max_size = std::allocator_traits::max_size(alloc_); +- size_t old_capacity = this->capacity(); +- size_t new_capacity = old_capacity + old_capacity / 2; +- if (size > new_capacity) +- new_capacity = size; +- else if (new_capacity > max_size) +- new_capacity = size > max_size ? size : max_size; +- T* old_data = this->data(); +- T* new_data = +- std::allocator_traits::allocate(alloc_, new_capacity); +- // The following code doesn't throw, so the raw pointer above doesn't leak. +- std::uninitialized_copy(old_data, old_data + this->size(), +- detail::make_checked(new_data, new_capacity)); +- this->set(new_data, new_capacity); +- // deallocate must not throw according to the standard, but even if it does, +- // the buffer already uses the new storage and will deallocate it in +- // destructor. +- if (old_data != store_) alloc_.deallocate(old_data, old_capacity); +-} +- +-using memory_buffer = basic_memory_buffer; +- +-template +-struct is_contiguous> : std::true_type { +-}; +- +-namespace detail { +-FMT_API void print(std::FILE*, string_view); +-} +- +-/** A formatting error such as invalid format string. */ +-FMT_CLASS_API +-class FMT_API format_error : public std::runtime_error { +- public: +- explicit format_error(const char* message) : std::runtime_error(message) {} +- explicit format_error(const std::string& message) +- : std::runtime_error(message) {} +- format_error(const format_error&) = default; +- format_error& operator=(const format_error&) = default; +- format_error(format_error&&) = default; +- format_error& operator=(format_error&&) = default; +- ~format_error() FMT_NOEXCEPT override FMT_MSC_DEFAULT; +-}; +- +-/** +- \rst +- Constructs a `~fmt::format_arg_store` object that contains references +- to arguments and can be implicitly converted to `~fmt::format_args`. +- If ``fmt`` is a compile-time string then `make_args_checked` checks +- its validity at compile time. +- \endrst +- */ +-template > +-FMT_INLINE auto make_args_checked(const S& fmt, +- const remove_reference_t&... args) +- -> format_arg_store, remove_reference_t...> { +- static_assert( +- detail::count<( +- std::is_base_of>::value && +- std::is_reference::value)...>() == 0, +- "passing views as lvalues is disallowed"); +- detail::check_format_string(fmt); +- return {args...}; +-} +- +-// compile-time support +-namespace detail_exported { +-#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +-template struct fixed_string { +- constexpr fixed_string(const Char (&str)[N]) { +- detail::copy_str(static_cast(str), +- str + N, data); +- } +- Char data[N]{}; +-}; +-#endif +- +-// Converts a compile-time string to basic_string_view. +-template +-constexpr auto compile_string_to_view(const Char (&s)[N]) +- -> basic_string_view { +- // Remove trailing NUL character if needed. Won't be present if this is used +- // with a raw character array (i.e. not defined as a string). +- return {s, N - (std::char_traits::to_int_type(s[N - 1]) == 0 ? 1 : 0)}; +-} +-template +-constexpr auto compile_string_to_view(detail::std_string_view s) +- -> basic_string_view { +- return {s.data(), s.size()}; +-} +-} // namespace detail_exported +- +-FMT_BEGIN_DETAIL_NAMESPACE +- +-template struct is_integral : std::is_integral {}; +-template <> struct is_integral : std::true_type {}; +-template <> struct is_integral : std::true_type {}; +- +-template +-using is_signed = +- std::integral_constant::is_signed || +- std::is_same::value>; +- +-// Returns true if value is negative, false otherwise. +-// Same as `value < 0` but doesn't produce warnings if T is an unsigned type. +-template ::value)> +-FMT_CONSTEXPR auto is_negative(T value) -> bool { +- return value < 0; +-} +-template ::value)> +-FMT_CONSTEXPR auto is_negative(T) -> bool { +- return false; +-} +- +-template ::value)> +-FMT_CONSTEXPR auto is_supported_floating_point(T) -> uint16_t { +- return (std::is_same::value && FMT_USE_FLOAT) || +- (std::is_same::value && FMT_USE_DOUBLE) || +- (std::is_same::value && FMT_USE_LONG_DOUBLE); +-} +- +-// Smallest of uint32_t, uint64_t, uint128_t that is large enough to +-// represent all values of an integral type T. +-template +-using uint32_or_64_or_128_t = +- conditional_t() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS, +- uint32_t, +- conditional_t() <= 64, uint64_t, uint128_t>>; +-template +-using uint64_or_128_t = conditional_t() <= 64, uint64_t, uint128_t>; +- +-#define FMT_POWERS_OF_10(factor) \ +- factor * 10, (factor)*100, (factor)*1000, (factor)*10000, (factor)*100000, \ +- (factor)*1000000, (factor)*10000000, (factor)*100000000, \ +- (factor)*1000000000 +- +-// Converts value in the range [0, 100) to a string. +-constexpr const char* digits2(size_t value) { +- // GCC generates slightly better code when value is pointer-size. +- return &"0001020304050607080910111213141516171819" +- "2021222324252627282930313233343536373839" +- "4041424344454647484950515253545556575859" +- "6061626364656667686970717273747576777879" +- "8081828384858687888990919293949596979899"[value * 2]; +-} +- +-// Sign is a template parameter to workaround a bug in gcc 4.8. +-template constexpr Char sign(Sign s) { +-#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 604 +- static_assert(std::is_same::value, ""); +-#endif +- return static_cast("\0-+ "[s]); +-} +- +-template FMT_CONSTEXPR auto count_digits_fallback(T n) -> int { +- int count = 1; +- for (;;) { +- // Integer division is slow so do it for a group of four digits instead +- // of for every digit. The idea comes from the talk by Alexandrescu +- // "Three Optimization Tips for C++". See speed-test for a comparison. +- if (n < 10) return count; +- if (n < 100) return count + 1; +- if (n < 1000) return count + 2; +- if (n < 10000) return count + 3; +- n /= 10000u; +- count += 4; +- } +-} +-#if FMT_USE_INT128 +-FMT_CONSTEXPR inline auto count_digits(uint128_t n) -> int { +- return count_digits_fallback(n); +-} +-#endif +- +-#ifdef FMT_BUILTIN_CLZLL +-// It is a separate function rather than a part of count_digits to workaround +-// the lack of static constexpr in constexpr functions. +-inline auto do_count_digits(uint64_t n) -> int { +- // This has comparable performance to the version by Kendall Willets +- // (https://github.com/fmtlib/format-benchmark/blob/master/digits10) +- // but uses smaller tables. +- // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)). +- static constexpr uint8_t bsr2log10[] = { +- 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, +- 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, +- 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, +- 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20}; +- auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63]; +- static constexpr const uint64_t zero_or_powers_of_10[] = { +- 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL), +- 10000000000000000000ULL}; +- return t - (n < zero_or_powers_of_10[t]); +-} +-#endif +- +-// Returns the number of decimal digits in n. Leading zeros are not counted +-// except for n == 0 in which case count_digits returns 1. +-FMT_CONSTEXPR20 inline auto count_digits(uint64_t n) -> int { +-#ifdef FMT_BUILTIN_CLZLL +- if (!is_constant_evaluated()) { +- return do_count_digits(n); +- } +-#endif +- return count_digits_fallback(n); +-} +- +-// Counts the number of digits in n. BITS = log2(radix). +-template +-FMT_CONSTEXPR auto count_digits(UInt n) -> int { +-#ifdef FMT_BUILTIN_CLZ +- if (num_bits() == 32) +- return (FMT_BUILTIN_CLZ(static_cast(n) | 1) ^ 31) / BITS + 1; +-#endif +- // Lambda avoids unreachable code warnings from NVHPC. +- return [](UInt m) { +- int num_digits = 0; +- do { +- ++num_digits; +- } while ((m >>= BITS) != 0); +- return num_digits; +- }(n); +-} +- +-template <> auto count_digits<4>(detail::fallback_uintptr n) -> int; +- +-#ifdef FMT_BUILTIN_CLZ +-// It is a separate function rather than a part of count_digits to workaround +-// the lack of static constexpr in constexpr functions. +-FMT_INLINE auto do_count_digits(uint32_t n) -> int { +-// An optimization by Kendall Willets from https://bit.ly/3uOIQrB. +-// This increments the upper 32 bits (log10(T) - 1) when >= T is added. +-# define FMT_INC(T) (((sizeof(# T) - 1ull) << 32) - T) +- static constexpr uint64_t table[] = { +- FMT_INC(0), FMT_INC(0), FMT_INC(0), // 8 +- FMT_INC(10), FMT_INC(10), FMT_INC(10), // 64 +- FMT_INC(100), FMT_INC(100), FMT_INC(100), // 512 +- FMT_INC(1000), FMT_INC(1000), FMT_INC(1000), // 4096 +- FMT_INC(10000), FMT_INC(10000), FMT_INC(10000), // 32k +- FMT_INC(100000), FMT_INC(100000), FMT_INC(100000), // 256k +- FMT_INC(1000000), FMT_INC(1000000), FMT_INC(1000000), // 2048k +- FMT_INC(10000000), FMT_INC(10000000), FMT_INC(10000000), // 16M +- FMT_INC(100000000), FMT_INC(100000000), FMT_INC(100000000), // 128M +- FMT_INC(1000000000), FMT_INC(1000000000), FMT_INC(1000000000), // 1024M +- FMT_INC(1000000000), FMT_INC(1000000000) // 4B +- }; +- auto inc = table[FMT_BUILTIN_CLZ(n | 1) ^ 31]; +- return static_cast((n + inc) >> 32); +-} +-#endif +- +-// Optional version of count_digits for better performance on 32-bit platforms. +-FMT_CONSTEXPR20 inline auto count_digits(uint32_t n) -> int { +-#ifdef FMT_BUILTIN_CLZ +- if (!is_constant_evaluated()) { +- return do_count_digits(n); +- } +-#endif +- return count_digits_fallback(n); +-} +- +-template constexpr auto digits10() FMT_NOEXCEPT -> int { +- return std::numeric_limits::digits10; +-} +-template <> constexpr auto digits10() FMT_NOEXCEPT -> int { +- return 38; +-} +-template <> constexpr auto digits10() FMT_NOEXCEPT -> int { +- return 38; +-} +- +-template struct thousands_sep_result { +- std::string grouping; +- Char thousands_sep; +-}; +- +-template +-FMT_API auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result; +-template +-inline auto thousands_sep(locale_ref loc) -> thousands_sep_result { +- auto result = thousands_sep_impl(loc); +- return {result.grouping, Char(result.thousands_sep)}; +-} +-template <> +-inline auto thousands_sep(locale_ref loc) -> thousands_sep_result { +- return thousands_sep_impl(loc); +-} +- +-template +-FMT_API auto decimal_point_impl(locale_ref loc) -> Char; +-template inline auto decimal_point(locale_ref loc) -> Char { +- return Char(decimal_point_impl(loc)); +-} +-template <> inline auto decimal_point(locale_ref loc) -> wchar_t { +- return decimal_point_impl(loc); +-} +- +-// Compares two characters for equality. +-template auto equal2(const Char* lhs, const char* rhs) -> bool { +- return lhs[0] == Char(rhs[0]) && lhs[1] == Char(rhs[1]); +-} +-inline auto equal2(const char* lhs, const char* rhs) -> bool { +- return memcmp(lhs, rhs, 2) == 0; +-} +- +-// Copies two characters from src to dst. +-template +-FMT_CONSTEXPR20 FMT_INLINE void copy2(Char* dst, const char* src) { +- if (!is_constant_evaluated() && sizeof(Char) == sizeof(char)) { +- memcpy(dst, src, 2); +- return; +- } +- *dst++ = static_cast(*src++); +- *dst = static_cast(*src); +-} +- +-template struct format_decimal_result { +- Iterator begin; +- Iterator end; +-}; +- +-// Formats a decimal unsigned integer value writing into out pointing to a +-// buffer of specified size. The caller must ensure that the buffer is large +-// enough. +-template +-FMT_CONSTEXPR20 auto format_decimal(Char* out, UInt value, int size) +- -> format_decimal_result { +- FMT_ASSERT(size >= count_digits(value), "invalid digit count"); +- out += size; +- Char* end = out; +- while (value >= 100) { +- // Integer division is slow so do it for a group of two digits instead +- // of for every digit. The idea comes from the talk by Alexandrescu +- // "Three Optimization Tips for C++". See speed-test for a comparison. +- out -= 2; +- copy2(out, digits2(static_cast(value % 100))); +- value /= 100; +- } +- if (value < 10) { +- *--out = static_cast('0' + value); +- return {out, end}; +- } +- out -= 2; +- copy2(out, digits2(static_cast(value))); +- return {out, end}; +-} +- +-template >::value)> +-inline auto format_decimal(Iterator out, UInt value, int size) +- -> format_decimal_result { +- // Buffer is large enough to hold all digits (digits10 + 1). +- Char buffer[digits10() + 1]; +- auto end = format_decimal(buffer, value, size).end; +- return {out, detail::copy_str_noinline(buffer, end, out)}; +-} +- +-template +-FMT_CONSTEXPR auto format_uint(Char* buffer, UInt value, int num_digits, +- bool upper = false) -> Char* { +- buffer += num_digits; +- Char* end = buffer; +- do { +- const char* digits = upper ? "0123456789ABCDEF" : "0123456789abcdef"; +- unsigned digit = (value & ((1 << BASE_BITS) - 1)); +- *--buffer = static_cast(BASE_BITS < 4 ? static_cast('0' + digit) +- : digits[digit]); +- } while ((value >>= BASE_BITS) != 0); +- return end; +-} +- +-template +-auto format_uint(Char* buffer, detail::fallback_uintptr n, int num_digits, +- bool = false) -> Char* { +- auto char_digits = std::numeric_limits::digits / 4; +- int start = (num_digits + char_digits - 1) / char_digits - 1; +- if (int start_digits = num_digits % char_digits) { +- unsigned value = n.value[start--]; +- buffer = format_uint(buffer, value, start_digits); +- } +- for (; start >= 0; --start) { +- unsigned value = n.value[start]; +- buffer += char_digits; +- auto p = buffer; +- for (int i = 0; i < char_digits; ++i) { +- unsigned digit = (value & ((1 << BASE_BITS) - 1)); +- *--p = static_cast("0123456789abcdef"[digit]); +- value >>= BASE_BITS; +- } +- } +- return buffer; +-} +- +-template +-inline auto format_uint(It out, UInt value, int num_digits, bool upper = false) +- -> It { +- if (auto ptr = to_pointer(out, to_unsigned(num_digits))) { +- format_uint(ptr, value, num_digits, upper); +- return out; +- } +- // Buffer should be large enough to hold all digits (digits / BASE_BITS + 1). +- char buffer[num_bits() / BASE_BITS + 1]; +- format_uint(buffer, value, num_digits, upper); +- return detail::copy_str_noinline(buffer, buffer + num_digits, out); +-} +- +-// A converter from UTF-8 to UTF-16. +-class utf8_to_utf16 { +- private: +- basic_memory_buffer buffer_; +- +- public: +- FMT_API explicit utf8_to_utf16(string_view s); +- operator basic_string_view() const { return {&buffer_[0], size()}; } +- auto size() const -> size_t { return buffer_.size() - 1; } +- auto c_str() const -> const wchar_t* { return &buffer_[0]; } +- auto str() const -> std::wstring { return {&buffer_[0], size()}; } +-}; +- +-namespace dragonbox { +- +-// Type-specific information that Dragonbox uses. +-template struct float_info; +- +-template <> struct float_info { +- using carrier_uint = uint32_t; +- static const int significand_bits = 23; +- static const int exponent_bits = 8; +- static const int min_exponent = -126; +- static const int max_exponent = 127; +- static const int exponent_bias = -127; +- static const int decimal_digits = 9; +- static const int kappa = 1; +- static const int big_divisor = 100; +- static const int small_divisor = 10; +- static const int min_k = -31; +- static const int max_k = 46; +- static const int cache_bits = 64; +- static const int divisibility_check_by_5_threshold = 39; +- static const int case_fc_pm_half_lower_threshold = -1; +- static const int case_fc_pm_half_upper_threshold = 6; +- static const int case_fc_lower_threshold = -2; +- static const int case_fc_upper_threshold = 6; +- static const int case_shorter_interval_left_endpoint_lower_threshold = 2; +- static const int case_shorter_interval_left_endpoint_upper_threshold = 3; +- static const int shorter_interval_tie_lower_threshold = -35; +- static const int shorter_interval_tie_upper_threshold = -35; +- static const int max_trailing_zeros = 7; +-}; +- +-template <> struct float_info { +- using carrier_uint = uint64_t; +- static const int significand_bits = 52; +- static const int exponent_bits = 11; +- static const int min_exponent = -1022; +- static const int max_exponent = 1023; +- static const int exponent_bias = -1023; +- static const int decimal_digits = 17; +- static const int kappa = 2; +- static const int big_divisor = 1000; +- static const int small_divisor = 100; +- static const int min_k = -292; +- static const int max_k = 326; +- static const int cache_bits = 128; +- static const int divisibility_check_by_5_threshold = 86; +- static const int case_fc_pm_half_lower_threshold = -2; +- static const int case_fc_pm_half_upper_threshold = 9; +- static const int case_fc_lower_threshold = -4; +- static const int case_fc_upper_threshold = 9; +- static const int case_shorter_interval_left_endpoint_lower_threshold = 2; +- static const int case_shorter_interval_left_endpoint_upper_threshold = 3; +- static const int shorter_interval_tie_lower_threshold = -77; +- static const int shorter_interval_tie_upper_threshold = -77; +- static const int max_trailing_zeros = 16; +-}; +- +-template struct decimal_fp { +- using significand_type = typename float_info::carrier_uint; +- significand_type significand; +- int exponent; +-}; +- +-template +-FMT_API auto to_decimal(T x) FMT_NOEXCEPT -> decimal_fp; +-} // namespace dragonbox +- +-template +-constexpr auto exponent_mask() -> +- typename dragonbox::float_info::carrier_uint { +- using uint = typename dragonbox::float_info::carrier_uint; +- return ((uint(1) << dragonbox::float_info::exponent_bits) - 1) +- << dragonbox::float_info::significand_bits; +-} +- +-// Writes the exponent exp in the form "[+-]d{2,3}" to buffer. +-template +-FMT_CONSTEXPR auto write_exponent(int exp, It it) -> It { +- FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range"); +- if (exp < 0) { +- *it++ = static_cast('-'); +- exp = -exp; +- } else { +- *it++ = static_cast('+'); +- } +- if (exp >= 100) { +- const char* top = digits2(to_unsigned(exp / 100)); +- if (exp >= 1000) *it++ = static_cast(top[0]); +- *it++ = static_cast(top[1]); +- exp %= 100; +- } +- const char* d = digits2(to_unsigned(exp)); +- *it++ = static_cast(d[0]); +- *it++ = static_cast(d[1]); +- return it; +-} +- +-template +-FMT_HEADER_ONLY_CONSTEXPR20 auto format_float(T value, int precision, +- float_specs specs, +- buffer& buf) -> int; +- +-// Formats a floating-point number with snprintf. +-template +-auto snprintf_float(T value, int precision, float_specs specs, +- buffer& buf) -> int; +- +-template constexpr auto promote_float(T value) -> T { +- return value; +-} +-constexpr auto promote_float(float value) -> double { +- return static_cast(value); +-} +- +-template +-FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, +- const fill_t& fill) -> OutputIt { +- auto fill_size = fill.size(); +- if (fill_size == 1) return detail::fill_n(it, n, fill[0]); +- auto data = fill.data(); +- for (size_t i = 0; i < n; ++i) +- it = copy_str(data, data + fill_size, it); +- return it; +-} +- +-// Writes the output of f, padded according to format specifications in specs. +-// size: output size in code units. +-// width: output display width in (terminal) column positions. +-template +-FMT_CONSTEXPR auto write_padded(OutputIt out, +- const basic_format_specs& specs, +- size_t size, size_t width, F&& f) -> OutputIt { +- static_assert(align == align::left || align == align::right, ""); +- unsigned spec_width = to_unsigned(specs.width); +- size_t padding = spec_width > width ? spec_width - width : 0; +- // Shifts are encoded as string literals because static constexpr is not +- // supported in constexpr functions. +- auto* shifts = align == align::left ? "\x1f\x1f\x00\x01" : "\x00\x1f\x00\x01"; +- size_t left_padding = padding >> shifts[specs.align]; +- size_t right_padding = padding - left_padding; +- auto it = reserve(out, size + padding * specs.fill.size()); +- if (left_padding != 0) it = fill(it, left_padding, specs.fill); +- it = f(it); +- if (right_padding != 0) it = fill(it, right_padding, specs.fill); +- return base_iterator(out, it); +-} +- +-template +-constexpr auto write_padded(OutputIt out, const basic_format_specs& specs, +- size_t size, F&& f) -> OutputIt { +- return write_padded(out, specs, size, size, f); +-} +- +-template +-FMT_CONSTEXPR auto write_bytes(OutputIt out, string_view bytes, +- const basic_format_specs& specs) +- -> OutputIt { +- return write_padded( +- out, specs, bytes.size(), [bytes](reserve_iterator it) { +- const char* data = bytes.data(); +- return copy_str(data, data + bytes.size(), it); +- }); +-} +- +-template +-auto write_ptr(OutputIt out, UIntPtr value, +- const basic_format_specs* specs) -> OutputIt { +- int num_digits = count_digits<4>(value); +- auto size = to_unsigned(num_digits) + size_t(2); +- auto write = [=](reserve_iterator it) { +- *it++ = static_cast('0'); +- *it++ = static_cast('x'); +- return format_uint<4, Char>(it, value, num_digits); +- }; +- return specs ? write_padded(out, *specs, size, write) +- : base_iterator(out, write(reserve(out, size))); +-} +- +-template +-FMT_CONSTEXPR auto write_char(OutputIt out, Char value, +- const basic_format_specs& specs) +- -> OutputIt { +- return write_padded(out, specs, 1, [=](reserve_iterator it) { +- *it++ = value; +- return it; +- }); +-} +-template +-FMT_CONSTEXPR auto write(OutputIt out, Char value, +- const basic_format_specs& specs, +- locale_ref loc = {}) -> OutputIt { +- return check_char_specs(specs) +- ? write_char(out, value, specs) +- : write(out, static_cast(value), specs, loc); +-} +- +-// Data for write_int that doesn't depend on output iterator type. It is used to +-// avoid template code bloat. +-template struct write_int_data { +- size_t size; +- size_t padding; +- +- FMT_CONSTEXPR write_int_data(int num_digits, unsigned prefix, +- const basic_format_specs& specs) +- : size((prefix >> 24) + to_unsigned(num_digits)), padding(0) { +- if (specs.align == align::numeric) { +- auto width = to_unsigned(specs.width); +- if (width > size) { +- padding = width - size; +- size = width; +- } +- } else if (specs.precision > num_digits) { +- size = (prefix >> 24) + to_unsigned(specs.precision); +- padding = to_unsigned(specs.precision - num_digits); +- } +- } +-}; +- +-// Writes an integer in the format +-// +-// where are written by write_digits(it). +-// prefix contains chars in three lower bytes and the size in the fourth byte. +-template +-FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, int num_digits, +- unsigned prefix, +- const basic_format_specs& specs, +- W write_digits) -> OutputIt { +- // Slightly faster check for specs.width == 0 && specs.precision == -1. +- if ((specs.width | (specs.precision + 1)) == 0) { +- auto it = reserve(out, to_unsigned(num_digits) + (prefix >> 24)); +- if (prefix != 0) { +- for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) +- *it++ = static_cast(p & 0xff); +- } +- return base_iterator(out, write_digits(it)); +- } +- auto data = write_int_data(num_digits, prefix, specs); +- return write_padded( +- out, specs, data.size, [=](reserve_iterator it) { +- for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) +- *it++ = static_cast(p & 0xff); +- it = detail::fill_n(it, data.padding, static_cast('0')); +- return write_digits(it); +- }); +-} +- +-template class digit_grouping { +- private: +- thousands_sep_result sep_; +- +- struct next_state { +- std::string::const_iterator group; +- int pos; +- }; +- next_state initial_state() const { return {sep_.grouping.begin(), 0}; } +- +- // Returns the next digit group separator position. +- int next(next_state& state) const { +- if (!sep_.thousands_sep) return max_value(); +- if (state.group == sep_.grouping.end()) +- return state.pos += sep_.grouping.back(); +- if (*state.group <= 0 || *state.group == max_value()) +- return max_value(); +- state.pos += *state.group++; +- return state.pos; +- } +- +- public: +- explicit digit_grouping(locale_ref loc, bool localized = true) { +- if (localized) +- sep_ = thousands_sep(loc); +- else +- sep_.thousands_sep = Char(); +- } +- explicit digit_grouping(thousands_sep_result sep) : sep_(sep) {} +- +- Char separator() const { return sep_.thousands_sep; } +- +- int count_separators(int num_digits) const { +- int count = 0; +- auto state = initial_state(); +- while (num_digits > next(state)) ++count; +- return count; +- } +- +- // Applies grouping to digits and write the output to out. +- template +- Out apply(Out out, basic_string_view digits) const { +- auto num_digits = static_cast(digits.size()); +- auto separators = basic_memory_buffer(); +- separators.push_back(0); +- auto state = initial_state(); +- while (int i = next(state)) { +- if (i >= num_digits) break; +- separators.push_back(i); +- } +- for (int i = 0, sep_index = static_cast(separators.size() - 1); +- i < num_digits; ++i) { +- if (num_digits - i == separators[sep_index]) { +- *out++ = separator(); +- --sep_index; +- } +- *out++ = static_cast(digits[to_unsigned(i)]); +- } +- return out; +- } +-}; +- +-template +-auto write_int_localized(OutputIt out, UInt value, unsigned prefix, +- const basic_format_specs& specs, +- const digit_grouping& grouping) -> OutputIt { +- static_assert(std::is_same, UInt>::value, ""); +- int num_digits = count_digits(value); +- char digits[40]; +- format_decimal(digits, value, num_digits); +- unsigned size = to_unsigned((prefix != 0 ? 1 : 0) + num_digits + +- grouping.count_separators(num_digits)); +- return write_padded( +- out, specs, size, size, [&](reserve_iterator it) { +- if (prefix != 0) *it++ = static_cast(prefix); +- return grouping.apply(it, string_view(digits, to_unsigned(num_digits))); +- }); +-} +- +-template +-auto write_int_localized(OutputIt& out, UInt value, unsigned prefix, +- const basic_format_specs& specs, locale_ref loc) +- -> bool { +- auto grouping = digit_grouping(loc); +- out = write_int_localized(out, value, prefix, specs, grouping); +- return true; +-} +- +-FMT_CONSTEXPR inline void prefix_append(unsigned& prefix, unsigned value) { +- prefix |= prefix != 0 ? value << 8 : value; +- prefix += (1u + (value > 0xff ? 1 : 0)) << 24; +-} +- +-template struct write_int_arg { +- UInt abs_value; +- unsigned prefix; +-}; +- +-template +-FMT_CONSTEXPR auto make_write_int_arg(T value, sign_t sign) +- -> write_int_arg> { +- auto prefix = 0u; +- auto abs_value = static_cast>(value); +- if (is_negative(value)) { +- prefix = 0x01000000 | '-'; +- abs_value = 0 - abs_value; +- } else { +- constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+', +- 0x1000000u | ' '}; +- prefix = prefixes[sign]; +- } +- return {abs_value, prefix}; +-} +- +-template +-FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg arg, +- const basic_format_specs& specs, +- locale_ref loc) -> OutputIt { +- static_assert(std::is_same>::value, ""); +- auto abs_value = arg.abs_value; +- auto prefix = arg.prefix; +- switch (specs.type) { +- case presentation_type::none: +- case presentation_type::dec: { +- if (specs.localized && +- write_int_localized(out, static_cast>(abs_value), +- prefix, specs, loc)) { +- return out; +- } +- auto num_digits = count_digits(abs_value); +- return write_int( +- out, num_digits, prefix, specs, [=](reserve_iterator it) { +- return format_decimal(it, abs_value, num_digits).end; +- }); +- } +- case presentation_type::hex_lower: +- case presentation_type::hex_upper: { +- bool upper = specs.type == presentation_type::hex_upper; +- if (specs.alt) +- prefix_append(prefix, unsigned(upper ? 'X' : 'x') << 8 | '0'); +- int num_digits = count_digits<4>(abs_value); +- return write_int( +- out, num_digits, prefix, specs, [=](reserve_iterator it) { +- return format_uint<4, Char>(it, abs_value, num_digits, upper); +- }); +- } +- case presentation_type::bin_lower: +- case presentation_type::bin_upper: { +- bool upper = specs.type == presentation_type::bin_upper; +- if (specs.alt) +- prefix_append(prefix, unsigned(upper ? 'B' : 'b') << 8 | '0'); +- int num_digits = count_digits<1>(abs_value); +- return write_int(out, num_digits, prefix, specs, +- [=](reserve_iterator it) { +- return format_uint<1, Char>(it, abs_value, num_digits); +- }); +- } +- case presentation_type::oct: { +- int num_digits = count_digits<3>(abs_value); +- // Octal prefix '0' is counted as a digit, so only add it if precision +- // is not greater than the number of digits. +- if (specs.alt && specs.precision <= num_digits && abs_value != 0) +- prefix_append(prefix, '0'); +- return write_int(out, num_digits, prefix, specs, +- [=](reserve_iterator it) { +- return format_uint<3, Char>(it, abs_value, num_digits); +- }); +- } +- case presentation_type::chr: +- return write_char(out, static_cast(abs_value), specs); +- default: +- throw_format_error("invalid type specifier"); +- } +- return out; +-} +-template +-FMT_CONSTEXPR FMT_NOINLINE auto write_int_noinline( +- OutputIt out, write_int_arg arg, const basic_format_specs& specs, +- locale_ref loc) -> OutputIt { +- return write_int(out, arg, specs, loc); +-} +-template ::value && +- !std::is_same::value && +- std::is_same>::value)> +-FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value, +- const basic_format_specs& specs, +- locale_ref loc) -> OutputIt { +- return write_int_noinline(out, make_write_int_arg(value, specs.sign), specs, +- loc); +-} +-// An inlined version of write used in format string compilation. +-template ::value && +- !std::is_same::value && +- !std::is_same>::value)> +-FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value, +- const basic_format_specs& specs, +- locale_ref loc) -> OutputIt { +- return write_int(out, make_write_int_arg(value, specs.sign), specs, loc); +-} +- +-template +-FMT_CONSTEXPR auto write(OutputIt out, basic_string_view s, +- const basic_format_specs& specs) -> OutputIt { +- auto data = s.data(); +- auto size = s.size(); +- if (specs.precision >= 0 && to_unsigned(specs.precision) < size) +- size = code_point_index(s, to_unsigned(specs.precision)); +- auto width = +- specs.width != 0 ? compute_width(basic_string_view(data, size)) : 0; +- return write_padded(out, specs, size, width, +- [=](reserve_iterator it) { +- return copy_str(data, data + size, it); +- }); +-} +-template +-FMT_CONSTEXPR auto write(OutputIt out, +- basic_string_view> s, +- const basic_format_specs& specs, locale_ref) +- -> OutputIt { +- check_string_type_spec(specs.type); +- return write(out, s, specs); +-} +-template +-FMT_CONSTEXPR auto write(OutputIt out, const Char* s, +- const basic_format_specs& specs, locale_ref) +- -> OutputIt { +- return check_cstring_type_spec(specs.type) +- ? write(out, basic_string_view(s), specs, {}) +- : write_ptr(out, to_uintptr(s), &specs); +-} +- +-template +-FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isinf, +- basic_format_specs specs, +- const float_specs& fspecs) -> OutputIt { +- auto str = +- isinf ? (fspecs.upper ? "INF" : "inf") : (fspecs.upper ? "NAN" : "nan"); +- constexpr size_t str_size = 3; +- auto sign = fspecs.sign; +- auto size = str_size + (sign ? 1 : 0); +- // Replace '0'-padding with space for non-finite values. +- const bool is_zero_fill = +- specs.fill.size() == 1 && *specs.fill.data() == static_cast('0'); +- if (is_zero_fill) specs.fill[0] = static_cast(' '); +- return write_padded(out, specs, size, [=](reserve_iterator it) { +- if (sign) *it++ = detail::sign(sign); +- return copy_str(str, str + str_size, it); +- }); +-} +- +-// A decimal floating-point number significand * pow(10, exp). +-struct big_decimal_fp { +- const char* significand; +- int significand_size; +- int exponent; +-}; +- +-constexpr auto get_significand_size(const big_decimal_fp& fp) -> int { +- return fp.significand_size; +-} +-template +-inline auto get_significand_size(const dragonbox::decimal_fp& fp) -> int { +- return count_digits(fp.significand); +-} +- +-template +-constexpr auto write_significand(OutputIt out, const char* significand, +- int significand_size) -> OutputIt { +- return copy_str(significand, significand + significand_size, out); +-} +-template +-inline auto write_significand(OutputIt out, UInt significand, +- int significand_size) -> OutputIt { +- return format_decimal(out, significand, significand_size).end; +-} +-template +-FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, +- int significand_size, int exponent, +- const Grouping& grouping) -> OutputIt { +- if (!grouping.separator()) { +- out = write_significand(out, significand, significand_size); +- return detail::fill_n(out, exponent, static_cast('0')); +- } +- auto buffer = memory_buffer(); +- write_significand(appender(buffer), significand, significand_size); +- detail::fill_n(appender(buffer), exponent, '0'); +- return grouping.apply(out, string_view(buffer.data(), buffer.size())); +-} +- +-template ::value)> +-inline auto write_significand(Char* out, UInt significand, int significand_size, +- int integral_size, Char decimal_point) -> Char* { +- if (!decimal_point) +- return format_decimal(out, significand, significand_size).end; +- out += significand_size + 1; +- Char* end = out; +- int floating_size = significand_size - integral_size; +- for (int i = floating_size / 2; i > 0; --i) { +- out -= 2; +- copy2(out, digits2(significand % 100)); +- significand /= 100; +- } +- if (floating_size % 2 != 0) { +- *--out = static_cast('0' + significand % 10); +- significand /= 10; +- } +- *--out = decimal_point; +- format_decimal(out - integral_size, significand, integral_size); +- return end; +-} +- +-template >::value)> +-inline auto write_significand(OutputIt out, UInt significand, +- int significand_size, int integral_size, +- Char decimal_point) -> OutputIt { +- // Buffer is large enough to hold digits (digits10 + 1) and a decimal point. +- Char buffer[digits10() + 2]; +- auto end = write_significand(buffer, significand, significand_size, +- integral_size, decimal_point); +- return detail::copy_str_noinline(buffer, end, out); +-} +- +-template +-FMT_CONSTEXPR auto write_significand(OutputIt out, const char* significand, +- int significand_size, int integral_size, +- Char decimal_point) -> OutputIt { +- out = detail::copy_str_noinline(significand, +- significand + integral_size, out); +- if (!decimal_point) return out; +- *out++ = decimal_point; +- return detail::copy_str_noinline(significand + integral_size, +- significand + significand_size, out); +-} +- +-template +-FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, +- int significand_size, int integral_size, +- Char decimal_point, +- const Grouping& grouping) -> OutputIt { +- if (!grouping.separator()) { +- return write_significand(out, significand, significand_size, integral_size, +- decimal_point); +- } +- auto buffer = basic_memory_buffer(); +- write_significand(buffer_appender(buffer), significand, +- significand_size, integral_size, decimal_point); +- grouping.apply( +- out, basic_string_view(buffer.data(), to_unsigned(integral_size))); +- return detail::copy_str_noinline(buffer.data() + integral_size, +- buffer.end(), out); +-} +- +-template > +-FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& fp, +- const basic_format_specs& specs, +- float_specs fspecs, locale_ref loc) +- -> OutputIt { +- auto significand = fp.significand; +- int significand_size = get_significand_size(fp); +- constexpr Char zero = static_cast('0'); +- auto sign = fspecs.sign; +- size_t size = to_unsigned(significand_size) + (sign ? 1 : 0); +- using iterator = reserve_iterator; +- +- Char decimal_point = +- fspecs.locale ? detail::decimal_point(loc) : static_cast('.'); +- +- int output_exp = fp.exponent + significand_size - 1; +- auto use_exp_format = [=]() { +- if (fspecs.format == float_format::exp) return true; +- if (fspecs.format != float_format::general) return false; +- // Use the fixed notation if the exponent is in [exp_lower, exp_upper), +- // e.g. 0.0001 instead of 1e-04. Otherwise use the exponent notation. +- const int exp_lower = -4, exp_upper = 16; +- return output_exp < exp_lower || +- output_exp >= (fspecs.precision > 0 ? fspecs.precision : exp_upper); +- }; +- if (use_exp_format()) { +- int num_zeros = 0; +- if (fspecs.showpoint) { +- num_zeros = fspecs.precision - significand_size; +- if (num_zeros < 0) num_zeros = 0; +- size += to_unsigned(num_zeros); +- } else if (significand_size == 1) { +- decimal_point = Char(); +- } +- auto abs_output_exp = output_exp >= 0 ? output_exp : -output_exp; +- int exp_digits = 2; +- if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3; +- +- size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits); +- char exp_char = fspecs.upper ? 'E' : 'e'; +- auto write = [=](iterator it) { +- if (sign) *it++ = detail::sign(sign); +- // Insert a decimal point after the first digit and add an exponent. +- it = write_significand(it, significand, significand_size, 1, +- decimal_point); +- if (num_zeros > 0) it = detail::fill_n(it, num_zeros, zero); +- *it++ = static_cast(exp_char); +- return write_exponent(output_exp, it); +- }; +- return specs.width > 0 ? write_padded(out, specs, size, write) +- : base_iterator(out, write(reserve(out, size))); +- } +- +- int exp = fp.exponent + significand_size; +- if (fp.exponent >= 0) { +- // 1234e5 -> 123400000[.0+] +- size += to_unsigned(fp.exponent); +- int num_zeros = fspecs.precision - exp; +-#ifdef FMT_FUZZ +- if (num_zeros > 5000) +- throw std::runtime_error("fuzz mode - avoiding excessive cpu use"); +-#endif +- if (fspecs.showpoint) { +- if (num_zeros <= 0 && fspecs.format != float_format::fixed) num_zeros = 1; +- if (num_zeros > 0) size += to_unsigned(num_zeros) + 1; +- } +- auto grouping = Grouping(loc, fspecs.locale); +- size += to_unsigned(grouping.count_separators(significand_size)); +- return write_padded(out, specs, size, [&](iterator it) { +- if (sign) *it++ = detail::sign(sign); +- it = write_significand(it, significand, significand_size, +- fp.exponent, grouping); +- if (!fspecs.showpoint) return it; +- *it++ = decimal_point; +- return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; +- }); +- } else if (exp > 0) { +- // 1234e-2 -> 12.34[0+] +- int num_zeros = fspecs.showpoint ? fspecs.precision - significand_size : 0; +- size += 1 + to_unsigned(num_zeros > 0 ? num_zeros : 0); +- auto grouping = Grouping(loc, fspecs.locale); +- size += to_unsigned(grouping.count_separators(significand_size)); +- return write_padded(out, specs, size, [&](iterator it) { +- if (sign) *it++ = detail::sign(sign); +- it = write_significand(it, significand, significand_size, exp, +- decimal_point, grouping); +- return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; +- }); +- } +- // 1234e-6 -> 0.001234 +- int num_zeros = -exp; +- if (significand_size == 0 && fspecs.precision >= 0 && +- fspecs.precision < num_zeros) { +- num_zeros = fspecs.precision; +- } +- bool pointy = num_zeros != 0 || significand_size != 0 || fspecs.showpoint; +- size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros); +- return write_padded(out, specs, size, [&](iterator it) { +- if (sign) *it++ = detail::sign(sign); +- *it++ = zero; +- if (!pointy) return it; +- *it++ = decimal_point; +- it = detail::fill_n(it, num_zeros, zero); +- return write_significand(it, significand, significand_size); +- }); +-} +- +-template class fallback_digit_grouping { +- public: +- constexpr fallback_digit_grouping(locale_ref, bool) {} +- +- constexpr Char separator() const { return Char(); } +- +- constexpr int count_separators(int) const { return 0; } +- +- template +- constexpr Out apply(Out out, basic_string_view) const { +- return out; +- } +-}; +- +-template +-FMT_CONSTEXPR20 auto write_float(OutputIt out, const DecimalFP& fp, +- const basic_format_specs& specs, +- float_specs fspecs, locale_ref loc) +- -> OutputIt { +- if (is_constant_evaluated()) { +- return do_write_float>(out, fp, specs, fspecs, +- loc); +- } else { +- return do_write_float(out, fp, specs, fspecs, loc); +- } +-} +- +-template ::value)> +-FMT_CONSTEXPR20 bool isinf(T value) { +- if (is_constant_evaluated()) { +-#if defined(__cpp_if_constexpr) +- if constexpr (std::numeric_limits::is_iec559) { +- auto bits = detail::bit_cast(static_cast(value)); +- constexpr auto significand_bits = +- dragonbox::float_info::significand_bits; +- return (bits & exponent_mask()) && +- !(bits & ((uint64_t(1) << significand_bits) - 1)); +- } +-#endif +- } +- return std::isinf(value); +-} +- +-template ::value)> +-FMT_CONSTEXPR20 bool isfinite(T value) { +- if (is_constant_evaluated()) { +-#if defined(__cpp_if_constexpr) +- if constexpr (std::numeric_limits::is_iec559) { +- auto bits = detail::bit_cast(static_cast(value)); +- return (bits & exponent_mask()) != exponent_mask(); +- } +-#endif +- } +- return std::isfinite(value); +-} +- +-template ::value)> +-FMT_INLINE FMT_CONSTEXPR bool signbit(T value) { +- if (is_constant_evaluated()) { +-#ifdef __cpp_if_constexpr +- if constexpr (std::numeric_limits::is_iec559) { +- auto bits = detail::bit_cast(static_cast(value)); +- return (bits & (uint64_t(1) << (num_bits() - 1))) != 0; +- } +-#endif +- } +- return std::signbit(value); +-} +- +-template ::value)> +-FMT_CONSTEXPR20 auto write(OutputIt out, T value, +- basic_format_specs specs, locale_ref loc = {}) +- -> OutputIt { +- if (const_check(!is_supported_floating_point(value))) return out; +- float_specs fspecs = parse_float_type_spec(specs); +- fspecs.sign = specs.sign; +- if (detail::signbit(value)) { // value < 0 is false for NaN so use signbit. +- fspecs.sign = sign::minus; +- value = -value; +- } else if (fspecs.sign == sign::minus) { +- fspecs.sign = sign::none; +- } +- +- if (!detail::isfinite(value)) +- return write_nonfinite(out, detail::isinf(value), specs, fspecs); +- +- if (specs.align == align::numeric && fspecs.sign) { +- auto it = reserve(out, 1); +- *it++ = detail::sign(fspecs.sign); +- out = base_iterator(out, it); +- fspecs.sign = sign::none; +- if (specs.width != 0) --specs.width; +- } +- +- memory_buffer buffer; +- if (fspecs.format == float_format::hex) { +- if (fspecs.sign) buffer.push_back(detail::sign(fspecs.sign)); +- snprintf_float(promote_float(value), specs.precision, fspecs, buffer); +- return write_bytes(out, {buffer.data(), buffer.size()}, +- specs); +- } +- int precision = specs.precision >= 0 || specs.type == presentation_type::none +- ? specs.precision +- : 6; +- if (fspecs.format == float_format::exp) { +- if (precision == max_value()) +- throw_format_error("number is too big"); +- else +- ++precision; +- } +- if (const_check(std::is_same())) fspecs.binary32 = true; +- if (!is_fast_float()) fspecs.fallback = true; +- int exp = format_float(promote_float(value), precision, fspecs, buffer); +- fspecs.precision = precision; +- auto fp = big_decimal_fp{buffer.data(), static_cast(buffer.size()), exp}; +- return write_float(out, fp, specs, fspecs, loc); +-} +- +-template ::value)> +-FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt { +- if (is_constant_evaluated()) { +- return write(out, value, basic_format_specs()); +- } +- +- if (const_check(!is_supported_floating_point(value))) return out; +- +- using floaty = conditional_t::value, double, T>; +- using uint = typename dragonbox::float_info::carrier_uint; +- auto bits = bit_cast(value); +- +- auto fspecs = float_specs(); +- if (detail::signbit(value)) { +- fspecs.sign = sign::minus; +- value = -value; +- } +- +- constexpr auto specs = basic_format_specs(); +- uint mask = exponent_mask(); +- if ((bits & mask) == mask) +- return write_nonfinite(out, std::isinf(value), specs, fspecs); +- +- auto dec = dragonbox::to_decimal(static_cast(value)); +- return write_float(out, dec, specs, fspecs, {}); +-} +- +-template ::value && +- !is_fast_float::value)> +-inline auto write(OutputIt out, T value) -> OutputIt { +- return write(out, value, basic_format_specs()); +-} +- +-template +-auto write(OutputIt out, monostate, basic_format_specs = {}, +- locale_ref = {}) -> OutputIt { +- FMT_ASSERT(false, ""); +- return out; +-} +- +-template +-FMT_CONSTEXPR auto write(OutputIt out, basic_string_view value) +- -> OutputIt { +- auto it = reserve(out, value.size()); +- it = copy_str_noinline(value.begin(), value.end(), it); +- return base_iterator(out, it); +-} +- +-template ::value)> +-constexpr auto write(OutputIt out, const T& value) -> OutputIt { +- return write(out, to_string_view(value)); +-} +- +-template ::value && +- !std::is_same::value && +- !std::is_same::value)> +-FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { +- auto abs_value = static_cast>(value); +- bool negative = is_negative(value); +- // Don't do -abs_value since it trips unsigned-integer-overflow sanitizer. +- if (negative) abs_value = ~abs_value + 1; +- int num_digits = count_digits(abs_value); +- auto size = (negative ? 1 : 0) + static_cast(num_digits); +- auto it = reserve(out, size); +- if (auto ptr = to_pointer(it, size)) { +- if (negative) *ptr++ = static_cast('-'); +- format_decimal(ptr, abs_value, num_digits); +- return out; +- } +- if (negative) *it++ = static_cast('-'); +- it = format_decimal(it, abs_value, num_digits).end; +- return base_iterator(out, it); +-} +- +-// FMT_ENABLE_IF() condition separated to workaround an MSVC bug. +-template < +- typename Char, typename OutputIt, typename T, +- bool check = +- std::is_enum::value && !std::is_same::value && +- mapped_type_constant>::value != +- type::custom_type, +- FMT_ENABLE_IF(check)> +-FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { +- return write( +- out, static_cast::type>(value)); +-} +- +-template ::value)> +-FMT_CONSTEXPR auto write(OutputIt out, T value, +- const basic_format_specs& specs = {}, +- locale_ref = {}) -> OutputIt { +- return specs.type != presentation_type::none && +- specs.type != presentation_type::string +- ? write(out, value ? 1 : 0, specs, {}) +- : write_bytes(out, value ? "true" : "false", specs); +-} +- +-template +-FMT_CONSTEXPR auto write(OutputIt out, Char value) -> OutputIt { +- auto it = reserve(out, 1); +- *it++ = value; +- return base_iterator(out, it); +-} +- +-template +-FMT_CONSTEXPR_CHAR_TRAITS auto write(OutputIt out, const Char* value) +- -> OutputIt { +- if (!value) { +- throw_format_error("string pointer is null"); +- } else { +- out = write(out, basic_string_view(value)); +- } +- return out; +-} +- +-template ::value)> +-auto write(OutputIt out, const T* value, +- const basic_format_specs& specs = {}, locale_ref = {}) +- -> OutputIt { +- check_pointer_type_spec(specs.type, error_handler()); +- return write_ptr(out, to_uintptr(value), &specs); +-} +- +-// A write overload that handles implicit conversions. +-template > +-FMT_CONSTEXPR auto write(OutputIt out, const T& value) -> enable_if_t< +- std::is_class::value && !is_string::value && +- !std::is_same::value && +- !std::is_same().map(value))>::value, +- OutputIt> { +- return write(out, arg_mapper().map(value)); +-} +- +-template > +-FMT_CONSTEXPR auto write(OutputIt out, const T& value) +- -> enable_if_t::value == type::custom_type, +- OutputIt> { +- using formatter_type = +- conditional_t::value, +- typename Context::template formatter_type, +- fallback_formatter>; +- auto ctx = Context(out, {}, {}); +- return formatter_type().format(value, ctx); +-} +- +-// An argument visitor that formats the argument and writes it via the output +-// iterator. It's a class and not a generic lambda for compatibility with C++11. +-template struct default_arg_formatter { +- using iterator = buffer_appender; +- using context = buffer_context; +- +- iterator out; +- basic_format_args args; +- locale_ref loc; +- +- template auto operator()(T value) -> iterator { +- return write(out, value); +- } +- auto operator()(typename basic_format_arg::handle h) -> iterator { +- basic_format_parse_context parse_ctx({}); +- context format_ctx(out, args, loc); +- h.format(parse_ctx, format_ctx); +- return format_ctx.out(); +- } +-}; +- +-template struct arg_formatter { +- using iterator = buffer_appender; +- using context = buffer_context; +- +- iterator out; +- const basic_format_specs& specs; +- locale_ref locale; +- +- template +- FMT_CONSTEXPR FMT_INLINE auto operator()(T value) -> iterator { +- return detail::write(out, value, specs, locale); +- } +- auto operator()(typename basic_format_arg::handle) -> iterator { +- // User-defined types are handled separately because they require access +- // to the parse context. +- return out; +- } +-}; +- +-template struct custom_formatter { +- basic_format_parse_context& parse_ctx; +- buffer_context& ctx; +- +- void operator()( +- typename basic_format_arg>::handle h) const { +- h.format(parse_ctx, ctx); +- } +- template void operator()(T) const {} +-}; +- +-template +-using is_integer = +- bool_constant::value && !std::is_same::value && +- !std::is_same::value && +- !std::is_same::value>; +- +-template class width_checker { +- public: +- explicit FMT_CONSTEXPR width_checker(ErrorHandler& eh) : handler_(eh) {} +- +- template ::value)> +- FMT_CONSTEXPR auto operator()(T value) -> unsigned long long { +- if (is_negative(value)) handler_.on_error("negative width"); +- return static_cast(value); +- } +- +- template ::value)> +- FMT_CONSTEXPR auto operator()(T) -> unsigned long long { +- handler_.on_error("width is not integer"); +- return 0; +- } +- +- private: +- ErrorHandler& handler_; +-}; +- +-template class precision_checker { +- public: +- explicit FMT_CONSTEXPR precision_checker(ErrorHandler& eh) : handler_(eh) {} +- +- template ::value)> +- FMT_CONSTEXPR auto operator()(T value) -> unsigned long long { +- if (is_negative(value)) handler_.on_error("negative precision"); +- return static_cast(value); +- } +- +- template ::value)> +- FMT_CONSTEXPR auto operator()(T) -> unsigned long long { +- handler_.on_error("precision is not integer"); +- return 0; +- } +- +- private: +- ErrorHandler& handler_; +-}; +- +-template