From f4a3463df15d27ee4bac71f4e7582b30e2517489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maksymilian=20Wilczy=C5=84ski?= Date: Wed, 7 May 2025 18:47:04 +0200 Subject: [PATCH] Initial commit --- .gitignore | 4 + fmt.lib | Bin 0 -> 669868 bytes include/fmt/args.h | 220 ++ include/fmt/base.h | 2958 ++++++++++++++++++++++++++ include/fmt/chrono.h | 2338 +++++++++++++++++++++ include/fmt/color.h | 610 ++++++ include/fmt/compile.h | 551 +++++ include/fmt/core.h | 5 + include/fmt/format-inl.h | 1949 ++++++++++++++++++ include/fmt/format.h | 4232 ++++++++++++++++++++++++++++++++++++++ include/fmt/os.h | 427 ++++ include/fmt/ostream.h | 166 ++ include/fmt/printf.h | 633 ++++++ include/fmt/ranges.h | 848 ++++++++ include/fmt/std.h | 726 +++++++ include/fmt/xchar.h | 373 ++++ uno.cpp | 223 ++ uno.sln | 31 + uno.vcxproj | 159 ++ uno.vcxproj.filters | 22 + 20 files changed, 16475 insertions(+) create mode 100644 .gitignore create mode 100644 fmt.lib create mode 100644 include/fmt/args.h create mode 100644 include/fmt/base.h create mode 100644 include/fmt/chrono.h create mode 100644 include/fmt/color.h create mode 100644 include/fmt/compile.h create mode 100644 include/fmt/core.h create mode 100644 include/fmt/format-inl.h create mode 100644 include/fmt/format.h create mode 100644 include/fmt/os.h create mode 100644 include/fmt/ostream.h create mode 100644 include/fmt/printf.h create mode 100644 include/fmt/ranges.h create mode 100644 include/fmt/std.h create mode 100644 include/fmt/xchar.h create mode 100644 uno.cpp create mode 100644 uno.sln create mode 100644 uno.vcxproj create mode 100644 uno.vcxproj.filters diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..66a176d --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +x64/ +uno/ +.vs/ +*.vcxproj.user diff --git a/fmt.lib b/fmt.lib new file mode 100644 index 0000000000000000000000000000000000000000..5a23adbc02d0e5f64e16cbeef638f4e367ec09c9 GIT binary patch literal 669868 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≫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

Ni#!f#`vzdxnBsGZ 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 hT6yu)1iii2JC=e*d3~e2erp=v zPpCgF1 h7L=PG@_qBuz1MoHn%F|4y#A-WUar~l2cb^36g0}~J5a$MTd1X0GhWar z>U&Ubox=AxggVGl&?xE$P;P|X@W5Rj6Y3XBL8IEnkD%y3_E_>4N{+L49|#t<6i^#>@PA98M@ zkMFqDG~aJrVZESHG5iyhi{YhLZ})~!zgP+y<@J~M;#}U{@NL5Y?=@@<6AfsT*Wb#E z$7P|;vJ^DRizom3`7fb9vJ^CmS^^Z$H#j%@Z}iJ|LPgdzIfO=0OM-Hv!|L1aQ!3Q4 zmV!o6y+FCvd*V$k?+)|Pc*9cAsAwz&%0+(G=;gN+Dzui#AvDTsX;8sYPpBg;1&yMX z0p+gc{a0$(K&ZDZ1&yMXRpnao$IlNr$d{{ZZIeT2RJoSZ<(l>9NTF`E6g0|fc~HTt zQmD{6#tRxntpLi+MVI{Y(wRctWGQGAwIV1Njdy;&Y`#$CeT^41idqSj>*uQ;Txaru zzK^=yQqZVqtPIN4@`9IE`G-*3t!uoXQC_`41*0L<<(7g*QLBLJL+zb@C^~P+i{BS& zqxFmzG>Tf)=a8VHhu=JJC7~{|6f}xj4OD+3xChu{{H)ZwzHRhf-*`czqQUP5mDA~4 zynI4Ps5(nQqrCcn3PwYyYb*tgqSgSl7Uhm>`uNC}M+^0%rJzyNn%;|`q8Embs}O3} z4NSS9QPf(Xg7d?_d^Aq66f`OtYlCuaW8~61Zz9ywmV!okt>Y=qA+J*^eLGxoLz6>j zlviI*(GNvO?{oALLe*Fb8s)Vvs9?GN_T`#mDQJ|}ddlmt<*scI>PAaJqrBEvUIV{A z{n=A}x!$uBG|Fp(3@@PuZ)BnYjq=)1d98L^^x&(#*VUGSMtN5_ z!5%=U)iyC+&?ssPP;Sn~_c(+)&{EJSsy`^VQ!(#@`u&9Z+)~h}IopE^}@8s!xN6>J+qO}7*@iVA}Ywhf`~wiGmqDgj0R!RO6aKifg5mA5cCghsWEQc$jK zoY%DN5JLsq1~kem0?LiBwLhgUJK5LQUe*g56~i)6u5IkIaq}xe{bDI-lo!8wQ_r!5 zI-|cS7c`2h0Oev>@j~x2g(}<9P|zr<5|q2X9zX1q=Y@LHQqZUvR)KPJwry8R9Brsz z453k8JAiW67w@xO?%Ux(TbUd}qhh!tC>KLMsVme|mV!ok?F6crS_aqj372hk$2{+~ z*4D-g8s)XK@*1(x!S4zcw-hwWYZp+#HZRnTmV!o6)u3E`U3tn&?+NvnrJzw%jiqr65buQk3{^=Y9Vu@p4QYY$L7kK)fh$rU!9 zn2MW4K<#lnWZ=HA#7K429auQqU-`y+FAb zuJ_&8ON2VxQqU-`y_MJPXMew$P_J1E8s+s5UoQFqF%)W@GE**Sl-EAWYuK1)_Y`WP zrJzw>`+ACF$ZOaNAH%aP1GdWv(%_X31^-crygul+!|Hoxm-^=J3?UcJgqxu8*A zG37O9cGV|B9bhSFlvf=nS6_)`%D)xr9ZNx@yyD91*WNFmAk>HolS62fS3-H!{T*IO zsCz91jq*w=ua|zGJ5Q*sD~%U4$}0tmV@N*~t@+X65uwht6g0|fvhw=vn5Fg*YWXVT z1W0*d=X_PYD%kIofpmZhLkUiHfBjZI%%Rj5xb1 BACxQCDW^3=g&Mzu$ssh# zYpU{^zT2!dgnGd9K;1LP^@DAx}Eb?&v}gxY10p`cM-bClO|gM4On*JqJ+)~geucJW)qaoBamV!o6{{l6T za>stD^`=}U)DM<|Mp4Ir;u!Mhxf?b)L#RQ+Ou3*@)Ulx4TJQI#rrssgiI##!MdLV7 zE*gA}NT`o31LK9ARqyO|t9qr6T~Ui@sJc%5n~Xq4B9%8S>qOZZy;%u>)OualG) z?~4l6d$`FVG|KB_P}@+{xkWwP>*O!@^IoNvf<}3rqP(8jX2vQ)HCPH7<#j5kV2cv! zDoa75sMA2XJqO;m5$a=0L8GYCLAgDL-ZwYxFI4~CO*EiU)ES^$i{f44**+RcOF^Te zaV99&qB!zGy=Wolw_V3L52gPKMWE-fO*)#tRzd zb#8{2P{&#d8s&AKr}$dt)y)px>laHwqrA@d6#Y=d@B9>M(@`de&?v79K)L$jD`iRV zHNsNRD6b1Myo5T&QqU-`i$J+MK0Ff5@gvcrmV!okU97x#Bob=vJxsZvQC^pT3SKEf z)msW0MO_LiI1&kUzonp2)I3nZkw~b%dzu_Vqo~V3^`pAte&g5u*E(vbk9>orpi$Ad z9F)6K4tVm@=|au76g0}~3Q)ml2=%+Api$J7pmw9&aYSBteBRnZ4H|9A1&yMv0_9Gp zpY_4=R||ETrJzyN)u3EE)JeCM_URS<#nC% z;*m(a-nJAp%IkXN#n)GnujP`lCWp`{uN#yX_lH7FuoN`P>qh0peeW#qb&#c?QC>G? zcnS51rJzw>H)nXw@Lqe2Gv$ItdEJuXCDgr^f<}4Wn&EY*_u68-@q$Kq-In1c)Tx$& zMtRNm6g7GDy;a`p4@*I#yl(dt{eZq#sLdys973bK?f}Ir4*pEtuyoT=zCRpgDQJ|} zoyv>HFQFc=6g0}~E>Qi*hjTb6^~9AzZ8y>65E|umxAMAUqs_Jy>LN=)qrC0`x1&yK}0_E<1l|R4hH$n~B$57Cy zJ3bGC;_-w(JI-9@SwjWy_&}q)9s%Y0UVh_5f8P$*-`99Sqhk0dDA)Ins@^*y)IOGi zMtMC3%I(06TH~0>LS0}fXq4CE%4>8HYRx+11&yMf2jyz{z5bW= z5$Y04L8GXDgW|il{8{S73m+D$G;X}0QPc~b;&%W3wAS7l`vk=D6f}51*0L;Z&oN*XU{6!o&FI2td$ReP#X%cTqjjp_mZ z3(EBy8+~)sw}uM#0MIC}S3q$z_%rT+`nys-hUZ!@XjBYe^%VV3w9oNl&k*WeOF^T& zUIXQN?D=&mOo&ux8#y2?_}D6cm_1?x+wZKfD6XcYA(s9=2w zb*rVIQPf+Y+ z_k{I=M#b=5P_E7Y^uXz>2(`lgCWp`{ulGO&V<^<_mV!o6?}G})P^eQZ1&yLU@D#Vh zzB}B1l2C713K|u|4?(#Yw$z?^p`n5?ghqLN1j?NiNv(Xtg2}!eZamdQ0~!^>k3qQ@ z@_8GfuCNp|%IgzQ!59j))imP;jiNpU6^x-!H(LrCMSTX!t-qc)x9oJGcA0LxpiwdW z+?R_Z|6=)F&l)NiLui!O7mDJ3W2%qgW7Z2A6~iw*ML!fR_~rL%p*CtTIfO=eEdb^A z%>Vk|_W!=bd(E;GG|KBM<#qj%w_GRG`<8-6d3~+C&i#Ff?XLD-!x~Kvp;2DnD6iW# zKKwDEZnG3L%IjNCapXszxLnOO-iu!S#lI|qMtS|uQ}ja-e{Y~r*INo2<@Ft?enc?! z=?h=IBh-!u7%ym)*Z0b+?*}`sBh)jNf<}4$0Lsk)ZkT*`y-<5M8!u>-*N@6;r%}7D zA=HF(D1%Bh$77#`GOyr5BDKP#`NRvP`0P#;+e8s+s%hSz1@Yxh>; z1 hReA9)mQeF81 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 BNqN=x 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 literal 0 HcmV?d00001 diff --git a/include/fmt/args.h b/include/fmt/args.h new file mode 100644 index 0000000..3ff4788 --- /dev/null +++ b/include/fmt/args.h @@ -0,0 +1,220 @@ +// Formatting library for C++ - dynamic argument lists +// +// 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_ + +#ifndef FMT_MODULE +# include // std::reference_wrapper +# include // std::unique_ptr +# include +#endif + +#include "format.h" // std_string_view + +FMT_BEGIN_NAMESPACE +namespace detail { + +template struct is_reference_wrapper : std::false_type {}; +template +struct is_reference_wrapper> : std::true_type {}; + +template auto unwrap(const T& v) -> const T& { return v; } +template +auto unwrap(const std::reference_wrapper& v) -> const T& { + return static_cast(v); +} + +// node is defined outside dynamic_arg_list to workaround a C2504 bug in MSVC +// 2022 (v17.10.0). +// +// 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 node is made a fake template. +template struct node { + virtual ~node() = default; + std::unique_ptr> next; +}; + +class dynamic_arg_list { + 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 auto push(const Arg& arg) -> const T& { + 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 + +/** + * A dynamic list of formatting arguments with storage. + * + * It can be implicitly converted into `fmt::basic_format_args` for passing + * into type-erased formatting functions such as `fmt::vformat`. + */ +template class dynamic_format_arg_store { + 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_t = conditional_t< + std::is_convertible>::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; + + auto data() const -> const basic_format_arg* { + return named_info_.empty() ? data_.data() : data_.data() + 1; + } + + template void emplace_arg(const T& arg) { + data_.emplace_back(arg); + } + + template + void emplace_arg(const detail::named_arg& arg) { + if (named_info_.empty()) + data_.insert(data_.begin(), basic_format_arg(nullptr, 0)); + data_.emplace_back(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] = {named_info_.data(), named_info_.size()}; + guard.release(); + } + + public: + constexpr dynamic_format_arg_store() = default; + + operator basic_format_args() const { + return basic_format_args(data(), static_cast(data_.size()), + !named_info_.empty()); + } + + /** + * 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); + */ + 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)); + } + + /** + * 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" + */ + 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_ = {}; + } + + /// Reserves space to store at least `new_cap` arguments including + /// `new_cap_named` named arguments. + 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); + } + + /// Returns the number of elements in the store. + size_t size() const noexcept { return data_.size(); } +}; + +FMT_END_NAMESPACE + +#endif // FMT_ARGS_H_ diff --git a/include/fmt/base.h b/include/fmt/base.h new file mode 100644 index 0000000..c1d09c6 --- /dev/null +++ b/include/fmt/base.h @@ -0,0 +1,2958 @@ +// Formatting library for C++ - the base API for char/UTF-8 +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_BASE_H_ +#define FMT_BASE_H_ + +#if defined(FMT_IMPORT_STD) && !defined(FMT_MODULE) +# define FMT_MODULE +#endif + +#ifndef FMT_MODULE +# include // CHAR_BIT +# include // FILE +# include // memcmp + +# include // std::enable_if +#endif + +// The fmt library version in the form major * 10000 + minor * 100 + patch. +#define FMT_VERSION 110102 + +// Detect compiler versions. +#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) +# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#else +# define FMT_GCC_VERSION 0 +#endif +#if defined(__ICL) +# define FMT_ICC_VERSION __ICL +#elif defined(__INTEL_COMPILER) +# define FMT_ICC_VERSION __INTEL_COMPILER +#else +# define FMT_ICC_VERSION 0 +#endif +#if defined(_MSC_VER) +# define FMT_MSC_VERSION _MSC_VER +#else +# define FMT_MSC_VERSION 0 +#endif + +// Detect standard library versions. +#ifdef _GLIBCXX_RELEASE +# define FMT_GLIBCXX_RELEASE _GLIBCXX_RELEASE +#else +# define FMT_GLIBCXX_RELEASE 0 +#endif +#ifdef _LIBCPP_VERSION +# define FMT_LIBCPP_VERSION _LIBCPP_VERSION +#else +# define FMT_LIBCPP_VERSION 0 +#endif + +#ifdef _MSVC_LANG +# define FMT_CPLUSPLUS _MSVC_LANG +#else +# define FMT_CPLUSPLUS __cplusplus +#endif + +// Detect __has_*. +#ifdef __has_feature +# define FMT_HAS_FEATURE(x) __has_feature(x) +#else +# define FMT_HAS_FEATURE(x) 0 +#endif +#ifdef __has_include +# define FMT_HAS_INCLUDE(x) __has_include(x) +#else +# define FMT_HAS_INCLUDE(x) 0 +#endif +#ifdef __has_builtin +# define FMT_HAS_BUILTIN(x) __has_builtin(x) +#else +# define FMT_HAS_BUILTIN(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 + +#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)) + +// Detect C++14 relaxed constexpr. +#ifdef FMT_USE_CONSTEXPR +// Use the provided definition. +#elif FMT_GCC_VERSION >= 600 && FMT_CPLUSPLUS >= 201402L +// GCC only allows throw in constexpr since version 6: +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67371. +# define FMT_USE_CONSTEXPR 1 +#elif FMT_ICC_VERSION +# define FMT_USE_CONSTEXPR 0 // https://github.com/fmtlib/fmt/issues/1628 +#elif FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VERSION >= 1912 +# define FMT_USE_CONSTEXPR 1 +#else +# define FMT_USE_CONSTEXPR 0 +#endif +#if FMT_USE_CONSTEXPR +# define FMT_CONSTEXPR constexpr +#else +# define FMT_CONSTEXPR +#endif + +// Detect consteval, C++20 constexpr extensions and std::is_constant_evaluated. +#if !defined(__cpp_lib_is_constant_evaluated) +# define FMT_USE_CONSTEVAL 0 +#elif FMT_CPLUSPLUS < 201709L +# define FMT_USE_CONSTEVAL 0 +#elif FMT_GLIBCXX_RELEASE && FMT_GLIBCXX_RELEASE < 10 +# define FMT_USE_CONSTEVAL 0 +#elif FMT_LIBCPP_VERSION && FMT_LIBCPP_VERSION < 10000 +# define FMT_USE_CONSTEVAL 0 +#elif defined(__apple_build_version__) && __apple_build_version__ < 14000029L +# define FMT_USE_CONSTEVAL 0 // consteval is broken in Apple clang < 14. +#elif FMT_MSC_VERSION && FMT_MSC_VERSION < 1929 +# define FMT_USE_CONSTEVAL 0 // consteval is broken in MSVC VS2019 < 16.10. +#elif defined(__cpp_consteval) +# define FMT_USE_CONSTEVAL 1 +#elif FMT_GCC_VERSION >= 1002 || FMT_CLANG_VERSION >= 1101 +# define FMT_USE_CONSTEVAL 1 +#else +# define FMT_USE_CONSTEVAL 0 +#endif +#if FMT_USE_CONSTEVAL +# define FMT_CONSTEVAL consteval +# define FMT_CONSTEXPR20 constexpr +#else +# define FMT_CONSTEVAL +# define FMT_CONSTEXPR20 +#endif + +// Check if exceptions are disabled. +#ifdef FMT_USE_EXCEPTIONS +// Use the provided definition. +#elif defined(__GNUC__) && !defined(__EXCEPTIONS) +# define FMT_USE_EXCEPTIONS 0 +#elif defined(__clang__) && !defined(__cpp_exceptions) +# define FMT_USE_EXCEPTIONS 0 +#elif FMT_MSC_VERSION && !_HAS_EXCEPTIONS +# define FMT_USE_EXCEPTIONS 0 +#else +# define FMT_USE_EXCEPTIONS 1 +#endif +#if FMT_USE_EXCEPTIONS +# define FMT_TRY try +# define FMT_CATCH(x) catch (x) +#else +# define FMT_TRY if (true) +# define FMT_CATCH(x) if (false) +#endif + +#ifdef FMT_NO_UNIQUE_ADDRESS +// Use the provided definition. +#elif FMT_CPLUSPLUS < 202002L +// Not supported. +#elif FMT_HAS_CPP_ATTRIBUTE(no_unique_address) +# define FMT_NO_UNIQUE_ADDRESS [[no_unique_address]] +// VS2019 v16.10 and later except clang-cl (https://reviews.llvm.org/D110485). +#elif FMT_MSC_VERSION >= 1929 && !FMT_CLANG_VERSION +# define FMT_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] +#endif +#ifndef FMT_NO_UNIQUE_ADDRESS +# define FMT_NO_UNIQUE_ADDRESS +#endif + +#if FMT_HAS_CPP17_ATTRIBUTE(fallthrough) +# define FMT_FALLTHROUGH [[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 + +// Disable [[noreturn]] on MSVC/NVCC because of bogus unreachable code warnings. +#if FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VERSION && !defined(__NVCC__) +# define FMT_NORETURN [[noreturn]] +#else +# define FMT_NORETURN +#endif + +#ifdef FMT_NODISCARD +// Use the provided definition. +#elif FMT_HAS_CPP17_ATTRIBUTE(nodiscard) +# define FMT_NODISCARD [[nodiscard]] +#else +# define FMT_NODISCARD +#endif + +#ifdef FMT_DEPRECATED +// Use the provided definition. +#elif FMT_HAS_CPP14_ATTRIBUTE(deprecated) +# define FMT_DEPRECATED [[deprecated]] +#else +# define FMT_DEPRECATED /* deprecated */ +#endif + +#ifdef FMT_ALWAYS_INLINE +// Use the provided definition. +#elif FMT_GCC_VERSION || FMT_CLANG_VERSION +# define FMT_ALWAYS_INLINE inline __attribute__((always_inline)) +#else +# define FMT_ALWAYS_INLINE inline +#endif +// A version of FMT_ALWAYS_INLINE to prevent code bloat in debug mode. +#ifdef NDEBUG +# define FMT_INLINE FMT_ALWAYS_INLINE +#else +# define FMT_INLINE inline +#endif + +#if FMT_GCC_VERSION || FMT_CLANG_VERSION +# define FMT_VISIBILITY(value) __attribute__((visibility(value))) +#else +# define FMT_VISIBILITY(value) +#endif + +// Detect pragmas. +#define FMT_PRAGMA_IMPL(x) _Pragma(#x) +#if FMT_GCC_VERSION >= 504 && !defined(__NVCOMPILER) +// Workaround a _Pragma bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59884 +// and an nvhpc warning: https://github.com/fmtlib/fmt/pull/2582. +# define FMT_PRAGMA_GCC(x) FMT_PRAGMA_IMPL(GCC x) +#else +# define FMT_PRAGMA_GCC(x) +#endif +#if FMT_CLANG_VERSION +# define FMT_PRAGMA_CLANG(x) FMT_PRAGMA_IMPL(clang x) +#else +# define FMT_PRAGMA_CLANG(x) +#endif +#if FMT_MSC_VERSION +# define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__)) +#else +# define FMT_MSC_WARNING(...) +#endif + +#ifndef FMT_BEGIN_NAMESPACE +# define FMT_BEGIN_NAMESPACE \ + namespace fmt { \ + inline namespace v11 { +# define FMT_END_NAMESPACE \ + } \ + } +#endif + +#ifndef FMT_EXPORT +# define FMT_EXPORT +# define FMT_BEGIN_EXPORT +# define FMT_END_EXPORT +#endif + +#ifdef _WIN32 +# define FMT_WIN32 1 +#else +# define FMT_WIN32 0 +#endif + +#if !defined(FMT_HEADER_ONLY) && FMT_WIN32 +# if defined(FMT_LIB_EXPORT) +# define FMT_API __declspec(dllexport) +# elif defined(FMT_SHARED) +# define FMT_API __declspec(dllimport) +# endif +#elif defined(FMT_LIB_EXPORT) || defined(FMT_SHARED) +# define FMT_API FMT_VISIBILITY("default") +#endif +#ifndef FMT_API +# define FMT_API +#endif + +#ifndef FMT_OPTIMIZE_SIZE +# define FMT_OPTIMIZE_SIZE 0 +#endif + +// FMT_BUILTIN_TYPE=0 may result in smaller library size at the cost of higher +// per-call binary size by passing built-in types through the extension API. +#ifndef FMT_BUILTIN_TYPES +# define FMT_BUILTIN_TYPES 1 +#endif + +#define FMT_APPLY_VARIADIC(expr) \ + using ignore = int[]; \ + (void)ignore { 0, (expr, 0)... } + +// Enable minimal optimizations for more compact code in debug mode. +FMT_PRAGMA_GCC(push_options) +#if !defined(__OPTIMIZE__) && !defined(__CUDACC__) +FMT_PRAGMA_GCC(optimize("Og")) +#endif +FMT_PRAGMA_CLANG(diagnostic push) + +FMT_BEGIN_NAMESPACE + +// 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 +using make_unsigned_t = typename std::make_unsigned::type; +template +using underlying_t = typename std::underlying_type::type; +template using decay_t = typename std::decay::type; +using nullptr_t = decltype(nullptr); + +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500 +// A workaround for gcc 4.9 to make void_t work in a SFINAE context. +template struct void_t_impl { + using type = void; +}; +template using void_t = typename void_t_impl::type; +#else +template using void_t = void; +#endif + +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(...) fmt::enable_if_t<(__VA_ARGS__), int> = 0 +#endif + +template constexpr auto min_of(T a, T b) -> T { + return a < b ? a : b; +} +template constexpr auto max_of(T a, T b) -> T { + return a > b ? a : b; +} + +namespace detail { +// Suppresses "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 auto is_constant_evaluated(bool default_value = false) noexcept + -> bool { +// Workaround for incompatibility between clang 14 and libstdc++ consteval-based +// std::is_constant_evaluated: https://github.com/fmtlib/fmt/issues/3247. +#if FMT_CPLUSPLUS >= 202002L && FMT_GLIBCXX_RELEASE >= 12 && \ + (FMT_CLANG_VERSION >= 1400 && FMT_CLANG_VERSION < 1500) + ignore_unused(default_value); + return __builtin_is_constant_evaluated(); +#elif defined(__cpp_lib_is_constant_evaluated) + ignore_unused(default_value); + return std::is_constant_evaluated(); +#else + return default_value; +#endif +} + +// Suppresses "conditional expression is constant" warnings. +template FMT_ALWAYS_INLINE constexpr auto const_check(T val) -> T { + return val; +} + +FMT_NORETURN FMT_API void assert_fail(const char* file, int line, + const char* message); + +#if defined(FMT_ASSERT) +// Use the provided definition. +#elif defined(NDEBUG) +// FMT_ASSERT is not empty to avoid -Wempty-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 + +#ifdef FMT_USE_INT128 +// Use the provided definition. +#elif defined(__SIZEOF_INT128__) && !defined(__NVCC__) && \ + !(FMT_CLANG_VERSION && FMT_MSC_VERSION) +# define FMT_USE_INT128 1 +using int128_opt = __int128_t; // An optional native 128-bit integer. +using uint128_opt = __uint128_t; +inline auto map(int128_opt x) -> int128_opt { return x; } +inline auto map(uint128_opt x) -> uint128_opt { return x; } +#else +# define FMT_USE_INT128 0 +#endif +#if !FMT_USE_INT128 +enum class int128_opt {}; +enum class uint128_opt {}; +// Reduce template instantiations. +inline auto map(int128_opt) -> monostate { return {}; } +inline auto map(uint128_opt) -> monostate { return {}; } +#endif + +#ifndef FMT_USE_BITINT +# define FMT_USE_BITINT (FMT_CLANG_VERSION >= 1500) +#endif + +#if FMT_USE_BITINT +FMT_PRAGMA_CLANG(diagnostic ignored "-Wbit-int-extension") +template using bitint = _BitInt(N); +template using ubitint = unsigned _BitInt(N); +#else +template struct bitint {}; +template struct ubitint {}; +#endif // FMT_USE_BITINT + +// Casts a nonnegative integer to unsigned. +template +FMT_CONSTEXPR auto to_unsigned(Int value) -> make_unsigned_t { + FMT_ASSERT(std::is_unsigned::value || value >= 0, "negative value"); + return static_cast>(value); +} + +template +using unsigned_char = conditional_t; + +// A heuristic to detect std::string and std::[experimental::]string_view. +// It is mainly used to avoid dependency on <[experimental/]string_view>. +template +struct is_std_string_like : std::false_type {}; +template +struct is_std_string_like().find_first_of( + typename T::value_type(), 0))>> + : std::is_convertible().data()), + const typename T::value_type*> {}; + +// Check if the literal encoding is UTF-8. +enum { is_utf8_enabled = "\u00A7"[1] == '\xA7' }; +enum { use_utf8 = !FMT_WIN32 || is_utf8_enabled }; + +#ifndef FMT_UNICODE +# define FMT_UNICODE 1 +#endif + +static_assert(!FMT_UNICODE || use_utf8, + "Unicode support requires compiling with /utf-8"); + +template constexpr const char* narrow(const T*) { return nullptr; } +constexpr FMT_ALWAYS_INLINE const char* narrow(const char* s) { return s; } + +template +FMT_CONSTEXPR auto compare(const Char* s1, const Char* s2, std::size_t n) + -> int { + if (!is_constant_evaluated() && sizeof(Char) == 1) return memcmp(s1, s2, n); + for (; n != 0; ++s1, ++s2, --n) { + if (*s1 < *s2) return -1; + if (*s1 > *s2) return 1; + } + return 0; +} + +namespace adl { +using namespace std; + +template +auto invoke_back_inserter() + -> decltype(back_inserter(std::declval())); +} // namespace adl + +template +struct is_back_insert_iterator : std::false_type {}; + +template +struct is_back_insert_iterator< + It, bool_constant()), + It>::value>> : std::true_type {}; + +// Extracts a reference to the container from *insert_iterator. +template +inline FMT_CONSTEXPR20 auto get_container(OutputIt it) -> + typename OutputIt::container_type& { + struct accessor : OutputIt { + FMT_CONSTEXPR20 accessor(OutputIt base) : OutputIt(base) {} + using OutputIt::container; + }; + return *accessor(it).container; +} +} // namespace detail + +// Parsing-related public API and forward declarations. +FMT_BEGIN_EXPORT + +/** + * 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::basic_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() 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) noexcept + : data_(s), size_(count) {} + + constexpr basic_string_view(nullptr_t) = delete; + + /// Constructs a string reference object from a C string. +#if FMT_GCC_VERSION + FMT_ALWAYS_INLINE +#endif + FMT_CONSTEXPR20 basic_string_view(const Char* s) : data_(s) { +#if FMT_HAS_BUILTIN(__buitin_strlen) || FMT_GCC_VERSION || FMT_CLANG_VERSION + if (std::is_same::value) { + size_ = __builtin_strlen(detail::narrow(s)); + return; + } +#endif + size_t len = 0; + while (*s++) ++len; + size_ = len; + } + + /// Constructs a string reference from a `std::basic_string` or a + /// `std::basic_string_view` object. + template ::value&& std::is_same< + typename S::value_type, Char>::value)> + FMT_CONSTEXPR basic_string_view(const S& s) noexcept + : data_(s.data()), size_(s.size()) {} + + /// Returns a pointer to the string data. + constexpr auto data() const noexcept -> const Char* { return data_; } + + /// Returns the string size. + constexpr auto size() const noexcept -> size_t { return size_; } + + constexpr auto begin() const noexcept -> iterator { return data_; } + constexpr auto end() const noexcept -> iterator { return data_ + size_; } + + constexpr auto operator[](size_t pos) const noexcept -> const Char& { + return data_[pos]; + } + + FMT_CONSTEXPR void remove_prefix(size_t n) noexcept { + data_ += n; + size_ -= n; + } + + FMT_CONSTEXPR auto starts_with(basic_string_view sv) const noexcept + -> bool { + return size_ >= sv.size_ && detail::compare(data_, sv.data_, sv.size_) == 0; + } + FMT_CONSTEXPR auto starts_with(Char c) const noexcept -> bool { + return size_ >= 1 && *data_ == c; + } + FMT_CONSTEXPR auto starts_with(const Char* s) const -> bool { + return starts_with(basic_string_view(s)); + } + + // Lexicographically compare this string reference to other. + FMT_CONSTEXPR auto compare(basic_string_view other) const -> int { + int result = + detail::compare(data_, other.data_, min_of(size_, other.size_)); + if (result != 0) return result; + return size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); + } + + FMT_CONSTEXPR 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 an extended character type. Can be specialized by users. +template struct is_xchar : std::false_type {}; +template <> struct is_xchar : std::true_type {}; +template <> struct is_xchar : std::true_type {}; +template <> struct is_xchar : std::true_type {}; +#ifdef __cpp_char8_t +template <> struct is_xchar : std::true_type {}; +#endif + +// DEPRECATED! Will be replaced with an alias to prevent specializations. +template struct is_char : is_xchar {}; +template <> struct is_char : std::true_type {}; + +template class basic_appender; +using appender = basic_appender; + +// Checks whether T is a container with contiguous storage. +template struct is_contiguous : std::false_type {}; + +class context; +template class generic_context; +template class parse_context; + +// Longer aliases for C++20 compatibility. +template using basic_format_parse_context = parse_context; +using format_parse_context = parse_context; +template +using basic_format_context = + conditional_t::value, context, + generic_context>; +using format_context = context; + +template +using buffered_context = + conditional_t::value, context, + generic_context, Char>>; + +template class basic_format_arg; +template class 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; + +// A formatter for objects of type T. +template +struct formatter { + // A deleted default constructor indicates a disabled formatter. + formatter() = delete; +}; + +/// Reports a format error at compile time or, via a `format_error` exception, +/// at runtime. +// This function is intentionally not constexpr to give a compile-time error. +FMT_NORETURN FMT_API void report_error(const char* message); + +enum class presentation_type : unsigned char { + // Common specifiers: + none = 0, + debug = 1, // '?' + string = 2, // 's' (string, bool) + + // Integral, bool and character specifiers: + dec = 3, // 'd' + hex, // 'x' or 'X' + oct, // 'o' + bin, // 'b' or 'B' + chr, // 'c' + + // String and pointer specifiers: + pointer = 3, // 'p' + + // Floating-point specifiers: + exp = 1, // 'e' or 'E' (1 since there is no FP debug presentation) + fixed, // 'f' or 'F' + general, // 'g' or 'G' + hexfloat // 'a' or 'A' +}; + +enum class align { none, left, right, center, numeric }; +enum class sign { none, minus, plus, space }; +enum class arg_id_kind { none, index, name }; + +// Basic format specifiers for built-in and string types. +class basic_specs { + private: + // Data is arranged as follows: + // + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |type |align| w | p | s |u|#|L| f | unused | + // +-----+-----+---+---+---+-+-+-+-----+---------------------------+ + // + // w - dynamic width info + // p - dynamic precision info + // s - sign + // u - uppercase (e.g. 'X' for 'x') + // # - alternate form ('#') + // L - localized + // f - fill size + // + // Bitfields are not used because of compiler bugs such as gcc bug 61414. + enum : unsigned { + type_mask = 0x00007, + align_mask = 0x00038, + width_mask = 0x000C0, + precision_mask = 0x00300, + sign_mask = 0x00C00, + uppercase_mask = 0x01000, + alternate_mask = 0x02000, + localized_mask = 0x04000, + fill_size_mask = 0x38000, + + align_shift = 3, + width_shift = 6, + precision_shift = 8, + sign_shift = 10, + fill_size_shift = 15, + + max_fill_size = 4 + }; + + size_t data_ = 1 << fill_size_shift; + + // Character (code unit) type is erased to prevent template bloat. + char fill_data_[max_fill_size] = {' '}; + + FMT_CONSTEXPR void set_fill_size(size_t size) { + data_ = (data_ & ~fill_size_mask) | (size << fill_size_shift); + } + + public: + constexpr auto type() const -> presentation_type { + return static_cast(data_ & type_mask); + } + FMT_CONSTEXPR void set_type(presentation_type t) { + data_ = (data_ & ~type_mask) | static_cast(t); + } + + constexpr auto align() const -> align { + return static_cast((data_ & align_mask) >> align_shift); + } + FMT_CONSTEXPR void set_align(fmt::align a) { + data_ = (data_ & ~align_mask) | (static_cast(a) << align_shift); + } + + constexpr auto dynamic_width() const -> arg_id_kind { + return static_cast((data_ & width_mask) >> width_shift); + } + FMT_CONSTEXPR void set_dynamic_width(arg_id_kind w) { + data_ = (data_ & ~width_mask) | (static_cast(w) << width_shift); + } + + FMT_CONSTEXPR auto dynamic_precision() const -> arg_id_kind { + return static_cast((data_ & precision_mask) >> + precision_shift); + } + FMT_CONSTEXPR void set_dynamic_precision(arg_id_kind p) { + data_ = (data_ & ~precision_mask) | + (static_cast(p) << precision_shift); + } + + constexpr bool dynamic() const { + return (data_ & (width_mask | precision_mask)) != 0; + } + + constexpr auto sign() const -> sign { + return static_cast((data_ & sign_mask) >> sign_shift); + } + FMT_CONSTEXPR void set_sign(fmt::sign s) { + data_ = (data_ & ~sign_mask) | (static_cast(s) << sign_shift); + } + + constexpr auto upper() const -> bool { return (data_ & uppercase_mask) != 0; } + FMT_CONSTEXPR void set_upper() { data_ |= uppercase_mask; } + + constexpr auto alt() const -> bool { return (data_ & alternate_mask) != 0; } + FMT_CONSTEXPR void set_alt() { data_ |= alternate_mask; } + FMT_CONSTEXPR void clear_alt() { data_ &= ~alternate_mask; } + + constexpr auto localized() const -> bool { + return (data_ & localized_mask) != 0; + } + FMT_CONSTEXPR void set_localized() { data_ |= localized_mask; } + + constexpr auto fill_size() const -> size_t { + return (data_ & fill_size_mask) >> fill_size_shift; + } + + template ::value)> + constexpr auto fill() const -> const Char* { + return fill_data_; + } + template ::value)> + constexpr auto fill() const -> const Char* { + return nullptr; + } + + template constexpr auto fill_unit() const -> Char { + using uchar = unsigned char; + return static_cast(static_cast(fill_data_[0]) | + (static_cast(fill_data_[1]) << 8) | + (static_cast(fill_data_[2]) << 16)); + } + + FMT_CONSTEXPR void set_fill(char c) { + fill_data_[0] = c; + set_fill_size(1); + } + + template + FMT_CONSTEXPR void set_fill(basic_string_view s) { + auto size = s.size(); + set_fill_size(size); + if (size == 1) { + unsigned uchar = static_cast>(s[0]); + fill_data_[0] = static_cast(uchar); + fill_data_[1] = static_cast(uchar >> 8); + fill_data_[2] = static_cast(uchar >> 16); + return; + } + FMT_ASSERT(size <= max_fill_size, "invalid fill"); + for (size_t i = 0; i < size; ++i) + fill_data_[i & 3] = static_cast(s[i]); + } + + FMT_CONSTEXPR void copy_fill_from(const basic_specs& specs) { + set_fill_size(specs.fill_size()); + for (size_t i = 0; i < max_fill_size; ++i) + fill_data_[i] = specs.fill_data_[i]; + } +}; + +// Format specifiers for built-in and string types. +struct format_specs : basic_specs { + int width; + int precision; + + constexpr format_specs() : width(0), precision(-1) {} +}; + +/** + * Parsing context consisting of a format string range being parsed and an + * argument counter for automatic indexing. + */ +template class parse_context { + private: + basic_string_view fmt_; + int next_arg_id_; + + enum { use_constexpr_cast = !FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200 }; + + FMT_CONSTEXPR void do_check_arg_id(int arg_id); + + public: + using char_type = Char; + using iterator = const Char*; + + constexpr explicit parse_context(basic_string_view fmt, + int next_arg_id = 0) + : fmt_(fmt), next_arg_id_(next_arg_id) {} + + /// Returns an iterator to the beginning of the format string range being + /// parsed. + constexpr auto begin() const noexcept -> iterator { return fmt_.begin(); } + + /// Returns an iterator past the end of the format string range being parsed. + constexpr auto end() const noexcept -> iterator { return fmt_.end(); } + + /// Advances the begin iterator to `it`. + FMT_CONSTEXPR void advance_to(iterator it) { + fmt_.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 { + if (next_arg_id_ < 0) { + report_error("cannot switch from manual to automatic argument indexing"); + return 0; + } + int id = next_arg_id_++; + do_check_arg_id(id); + return id; + } + + /// Reports an error if using the automatic argument indexing; otherwise + /// switches to the manual indexing. + FMT_CONSTEXPR void check_arg_id(int id) { + if (next_arg_id_ > 0) { + report_error("cannot switch from automatic to manual argument indexing"); + return; + } + next_arg_id_ = -1; + do_check_arg_id(id); + } + FMT_CONSTEXPR void check_arg_id(basic_string_view) { + next_arg_id_ = -1; + } + FMT_CONSTEXPR void check_dynamic_spec(int arg_id); +}; + +FMT_END_EXPORT + +namespace detail { + +// Constructs fmt::basic_string_view from types implicitly convertible +// to it, deducing Char. Explicitly convertible types such as the ones returned +// from FMT_STRING are intentionally excluded. +template ::value)> +constexpr auto to_string_view(const Char* s) -> basic_string_view { + return s; +} +template ::value)> +constexpr auto to_string_view(const T& s) + -> basic_string_view { + return s; +} +template +constexpr auto to_string_view(basic_string_view s) + -> basic_string_view { + return s; +} + +template +struct has_to_string_view : std::false_type {}; +// detail:: is intentional since to_string_view is not an extension point. +template +struct has_to_string_view< + T, void_t()))>> + : std::true_type {}; + +/// String's character (code unit) type. detail:: is intentional to prevent ADL. +template ()))> +using char_t = typename V::value_type; + +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_opt, int128_type); +FMT_TYPE_CONSTANT(uint128_opt, 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 auto is_integral_type(type t) -> bool { + return t > type::none_type && t <= type::last_integer_type; +} +constexpr auto is_arithmetic_type(type t) -> bool { + return t > type::none_type && t <= type::last_numeric_type; +} + +constexpr auto set(type rhs) -> int { return 1 << static_cast(rhs); } +constexpr auto in(type t, int set) -> bool { + return ((set >> static_cast(t)) & 1) != 0; +} + +// Bitsets of types. +enum { + sint_set = + set(type::int_type) | set(type::long_long_type) | set(type::int128_type), + uint_set = set(type::uint_type) | set(type::ulong_long_type) | + set(type::uint128_type), + bool_set = set(type::bool_type), + char_set = set(type::char_type), + float_set = set(type::float_type) | set(type::double_type) | + set(type::long_double_type), + string_set = set(type::string_type), + cstring_set = set(type::cstring_type), + pointer_set = set(type::pointer_type) +}; + +struct view {}; + +template struct named_arg; +template struct is_named_arg : std::false_type {}; +template struct is_static_named_arg : std::false_type {}; + +template +struct is_named_arg> : std::true_type {}; + +template struct named_arg : view { + const Char* name; + const T& value; + + named_arg(const Char* n, const T& v) : name(n), value(v) {} + static_assert(!is_named_arg::value, "nested named arguments"); +}; + +template constexpr auto count() -> int { return B ? 1 : 0; } +template constexpr auto count() -> int { + return (B1 ? 1 : 0) + count(); +} + +template constexpr auto count_named_args() -> int { + return count::value...>(); +} +template constexpr auto count_static_named_args() -> int { + return count::value...>(); +} + +template struct named_arg_info { + const Char* name; + int id; +}; + +template ::value)> +void init_named_arg(named_arg_info*, int& arg_index, int&, const T&) { + ++arg_index; +} +template ::value)> +void init_named_arg(named_arg_info* named_args, int& arg_index, + int& named_arg_index, const T& arg) { + named_args[named_arg_index++] = {arg.name, arg_index++}; +} + +template ::value)> +FMT_CONSTEXPR void init_static_named_arg(named_arg_info*, int& arg_index, + int&) { + ++arg_index; +} +template ::value)> +FMT_CONSTEXPR void init_static_named_arg(named_arg_info* named_args, + int& arg_index, int& named_arg_index) { + named_args[named_arg_index++] = {T::name, arg_index++}; +} + +// 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; + +template +using format_as_result = + remove_cvref_t()))>; +template +using format_as_member_result = + remove_cvref_t::format_as(std::declval()))>; + +template +struct use_format_as : std::false_type {}; +// format_as member is only used to avoid injection into the std namespace. +template +struct use_format_as_member : std::false_type {}; + +// Only map owning types because mapping views can be unsafe. +template +struct use_format_as< + T, bool_constant>::value>> + : std::true_type {}; +template +struct use_format_as_member< + T, bool_constant>::value>> + : std::true_type {}; + +template > +using use_formatter = + bool_constant<(std::is_class::value || std::is_enum::value || + std::is_union::value || std::is_array::value) && + !has_to_string_view::value && !is_named_arg::value && + !use_format_as::value && !use_format_as_member::value>; + +template > +auto has_formatter_impl(T* p, buffered_context* ctx = nullptr) + -> decltype(formatter().format(*p, *ctx), std::true_type()); +template auto has_formatter_impl(...) -> std::false_type; + +// T can be const-qualified to check if it is const-formattable. +template constexpr auto has_formatter() -> bool { + return decltype(has_formatter_impl(static_cast(nullptr)))::value; +} + +// Maps formatting argument types to natively supported types or user-defined +// types with formatters. Returns void on errors to be SFINAE-friendly. +template struct type_mapper { + static auto map(signed char) -> int; + static auto map(unsigned char) -> unsigned; + static auto map(short) -> int; + static auto map(unsigned short) -> unsigned; + static auto map(int) -> int; + static auto map(unsigned) -> unsigned; + static auto map(long) -> long_type; + static auto map(unsigned long) -> ulong_type; + static auto map(long long) -> long long; + static auto map(unsigned long long) -> unsigned long long; + static auto map(int128_opt) -> int128_opt; + static auto map(uint128_opt) -> uint128_opt; + static auto map(bool) -> bool; + + template + static auto map(bitint) -> conditional_t; + template + static auto map(ubitint) + -> conditional_t; + + template ::value)> + static auto map(T) -> conditional_t< + std::is_same::value || std::is_same::value, Char, void>; + + static auto map(float) -> float; + static auto map(double) -> double; + static auto map(long double) -> long double; + + static auto map(Char*) -> const Char*; + static auto map(const Char*) -> const Char*; + template , + FMT_ENABLE_IF(!std::is_pointer::value)> + static auto map(const T&) -> conditional_t::value, + basic_string_view, void>; + + static auto map(void*) -> const void*; + static auto map(const void*) -> const void*; + static auto map(volatile void*) -> const void*; + static auto map(const volatile void*) -> const void*; + static auto map(nullptr_t) -> const void*; + template ::value || + std::is_member_pointer::value)> + static auto map(const T&) -> void; + + template ::value)> + static auto map(const T& x) -> decltype(map(format_as(x))); + template ::value)> + static auto map(const T& x) -> decltype(map(formatter::format_as(x))); + + template ::value)> + static auto map(T&) -> conditional_t(), T&, void>; + + template ::value)> + static auto map(const T& named_arg) -> decltype(map(named_arg.value)); +}; + +// detail:: is used to workaround a bug in MSVC 2017. +template +using mapped_t = decltype(detail::type_mapper::map(std::declval())); + +// A type constant after applying type_mapper. +template +using mapped_type_constant = type_constant, Char>; + +template ::value> +using stored_type_constant = std::integral_constant< + type, Context::builtin_types || TYPE == type::int_type ? TYPE + : type::custom_type>; +// A parse context with extra data used only in compile-time checks. +template +class compile_parse_context : public parse_context { + private: + int num_args_; + const type* types_; + using base = parse_context; + + public: + FMT_CONSTEXPR explicit compile_parse_context(basic_string_view fmt, + int num_args, const type* types, + int next_arg_id = 0) + : base(fmt, next_arg_id), num_args_(num_args), types_(types) {} + + constexpr auto num_args() const -> int { return num_args_; } + constexpr auto arg_type(int id) const -> type { return types_[id]; } + + FMT_CONSTEXPR auto next_arg_id() -> int { + int id = base::next_arg_id(); + if (id >= num_args_) report_error("argument not found"); + return id; + } + + FMT_CONSTEXPR void check_arg_id(int id) { + base::check_arg_id(id); + if (id >= num_args_) report_error("argument not found"); + } + using base::check_arg_id; + + FMT_CONSTEXPR void check_dynamic_spec(int arg_id) { + ignore_unused(arg_id); + if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id])) + report_error("width/precision is not integer"); + } +}; + +// An argument reference. +template union arg_ref { + FMT_CONSTEXPR arg_ref(int idx = 0) : index(idx) {} + FMT_CONSTEXPR arg_ref(basic_string_view n) : name(n) {} + + int index; + basic_string_view name; +}; + +// Format specifiers with width and precision resolved at formatting rather +// than parsing time to allow reusing the same parsed specifiers with +// different sets of arguments (precompilation of format strings). +template struct dynamic_format_specs : format_specs { + arg_ref width_ref; + arg_ref precision_ref; +}; + +// Converts a character to ASCII. Returns '\0' on conversion failure. +template ::value)> +constexpr auto to_ascii(Char c) -> char { + return c <= 0xff ? static_cast(c) : '\0'; +} + +// Returns the number of code units in a code point or 1 on error. +template +FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int { + if (const_check(sizeof(Char) != 1)) return 1; + auto c = static_cast(*begin); + return static_cast((0x3a55000000000000ull >> (2 * (c >> 3))) & 3) + 1; +} + +// 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; + int digits10 = static_cast(sizeof(int) * CHAR_BIT * 3 / 10); + if (num_digits <= digits10) return static_cast(value); + // Check for overflow. + unsigned max = INT_MAX; + return num_digits == digits10 + 1 && + prev * 10ull + unsigned(p[-1] - '0') <= max + ? static_cast(value) + : error_value; +} + +FMT_CONSTEXPR inline auto parse_align(char c) -> align { + switch (c) { + case '<': return align::left; + case '>': return align::right; + case '^': return align::center; + } + return align::none; +} + +template constexpr auto is_name_start(Char c) -> bool { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '_'; +} + +template +FMT_CONSTEXPR auto parse_arg_id(const Char* begin, const Char* end, + Handler&& handler) -> const Char* { + Char c = *begin; + if (c >= '0' && c <= '9') { + int index = 0; + if (c != '0') + index = parse_nonnegative_int(begin, end, INT_MAX); + else + ++begin; + if (begin == end || (*begin != '}' && *begin != ':')) + report_error("invalid format string"); + else + handler.on_index(index); + return begin; + } + if (FMT_OPTIMIZE_SIZE > 1 || !is_name_start(c)) { + report_error("invalid format string"); + return begin; + } + auto it = begin; + do { + ++it; + } while (it != end && (is_name_start(*it) || ('0' <= *it && *it <= '9'))); + handler.on_name({begin, to_unsigned(it - begin)}); + return it; +} + +template struct dynamic_spec_handler { + parse_context& ctx; + arg_ref& ref; + arg_id_kind& kind; + + FMT_CONSTEXPR void on_index(int id) { + ref = id; + kind = arg_id_kind::index; + ctx.check_arg_id(id); + ctx.check_dynamic_spec(id); + } + FMT_CONSTEXPR void on_name(basic_string_view id) { + ref = id; + kind = arg_id_kind::name; + ctx.check_arg_id(id); + } +}; + +template struct parse_dynamic_spec_result { + const Char* end; + arg_id_kind kind; +}; + +// Parses integer | "{" [arg_id] "}". +template +FMT_CONSTEXPR auto parse_dynamic_spec(const Char* begin, const Char* end, + int& value, arg_ref& ref, + parse_context& ctx) + -> parse_dynamic_spec_result { + FMT_ASSERT(begin != end, ""); + auto kind = arg_id_kind::none; + if ('0' <= *begin && *begin <= '9') { + int val = parse_nonnegative_int(begin, end, -1); + if (val == -1) report_error("number is too big"); + value = val; + } else { + if (*begin == '{') { + ++begin; + if (begin != end) { + Char c = *begin; + if (c == '}' || c == ':') { + int id = ctx.next_arg_id(); + ref = id; + kind = arg_id_kind::index; + ctx.check_dynamic_spec(id); + } else { + begin = parse_arg_id(begin, end, + dynamic_spec_handler{ctx, ref, kind}); + } + } + if (begin != end && *begin == '}') return {++begin, kind}; + } + report_error("invalid format string"); + } + return {begin, kind}; +} + +template +FMT_CONSTEXPR auto parse_width(const Char* begin, const Char* end, + format_specs& specs, arg_ref& width_ref, + parse_context& ctx) -> const Char* { + auto result = parse_dynamic_spec(begin, end, specs.width, width_ref, ctx); + specs.set_dynamic_width(result.kind); + return result.end; +} + +template +FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end, + format_specs& specs, + arg_ref& precision_ref, + parse_context& ctx) -> const Char* { + ++begin; + if (begin == end) { + report_error("invalid precision"); + return begin; + } + auto result = + parse_dynamic_spec(begin, end, specs.precision, precision_ref, ctx); + specs.set_dynamic_precision(result.kind); + return result.end; +} + +enum class state { start, align, sign, hash, zero, width, precision, locale }; + +// Parses standard format specifiers. +template +FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end, + dynamic_format_specs& specs, + parse_context& ctx, type arg_type) + -> const Char* { + auto c = '\0'; + if (end - begin > 1) { + auto next = to_ascii(begin[1]); + c = parse_align(next) == align::none ? to_ascii(*begin) : '\0'; + } else { + if (begin == end) return begin; + c = to_ascii(*begin); + } + + struct { + state current_state = state::start; + FMT_CONSTEXPR void operator()(state s, bool valid = true) { + if (current_state >= s || !valid) + report_error("invalid format specifier"); + current_state = s; + } + } enter_state; + + using pres = presentation_type; + constexpr auto integral_set = sint_set | uint_set | bool_set | char_set; + struct { + const Char*& begin; + format_specs& specs; + type arg_type; + + FMT_CONSTEXPR auto operator()(pres pres_type, int set) -> const Char* { + if (!in(arg_type, set)) report_error("invalid format specifier"); + specs.set_type(pres_type); + return begin + 1; + } + } parse_presentation_type{begin, specs, arg_type}; + + for (;;) { + switch (c) { + case '<': + case '>': + case '^': + enter_state(state::align); + specs.set_align(parse_align(c)); + ++begin; + break; + case '+': + case ' ': + specs.set_sign(c == ' ' ? sign::space : sign::plus); + FMT_FALLTHROUGH; + case '-': + enter_state(state::sign, in(arg_type, sint_set | float_set)); + ++begin; + break; + case '#': + enter_state(state::hash, is_arithmetic_type(arg_type)); + specs.set_alt(); + ++begin; + break; + case '0': + enter_state(state::zero); + if (!is_arithmetic_type(arg_type)) + report_error("format specifier requires numeric argument"); + if (specs.align() == align::none) { + // Ignore 0 if align is specified for compatibility with std::format. + specs.set_align(align::numeric); + specs.set_fill('0'); + } + ++begin; + break; + // clang-format off + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': case '{': + // clang-format on + enter_state(state::width); + begin = parse_width(begin, end, specs, specs.width_ref, ctx); + break; + case '.': + enter_state(state::precision, + in(arg_type, float_set | string_set | cstring_set)); + begin = parse_precision(begin, end, specs, specs.precision_ref, ctx); + break; + case 'L': + enter_state(state::locale, is_arithmetic_type(arg_type)); + specs.set_localized(); + ++begin; + break; + case 'd': return parse_presentation_type(pres::dec, integral_set); + case 'X': specs.set_upper(); FMT_FALLTHROUGH; + case 'x': return parse_presentation_type(pres::hex, integral_set); + case 'o': return parse_presentation_type(pres::oct, integral_set); + case 'B': specs.set_upper(); FMT_FALLTHROUGH; + case 'b': return parse_presentation_type(pres::bin, integral_set); + case 'E': specs.set_upper(); FMT_FALLTHROUGH; + case 'e': return parse_presentation_type(pres::exp, float_set); + case 'F': specs.set_upper(); FMT_FALLTHROUGH; + case 'f': return parse_presentation_type(pres::fixed, float_set); + case 'G': specs.set_upper(); FMT_FALLTHROUGH; + case 'g': return parse_presentation_type(pres::general, float_set); + case 'A': specs.set_upper(); FMT_FALLTHROUGH; + case 'a': return parse_presentation_type(pres::hexfloat, float_set); + case 'c': + if (arg_type == type::bool_type) report_error("invalid format specifier"); + return parse_presentation_type(pres::chr, integral_set); + case 's': + return parse_presentation_type(pres::string, + bool_set | string_set | cstring_set); + case 'p': + return parse_presentation_type(pres::pointer, pointer_set | cstring_set); + case '?': + return parse_presentation_type(pres::debug, + char_set | string_set | cstring_set); + case '}': return begin; + default: { + if (*begin == '}') return begin; + // Parse fill and alignment. + auto fill_end = begin + code_point_length(begin); + if (end - fill_end <= 0) { + report_error("invalid format specifier"); + return begin; + } + if (*begin == '{') { + report_error("invalid fill character '{'"); + return begin; + } + auto alignment = parse_align(to_ascii(*fill_end)); + enter_state(state::align, alignment != align::none); + specs.set_fill( + basic_string_view(begin, to_unsigned(fill_end - begin))); + specs.set_align(alignment); + begin = fill_end + 1; + } + } + if (begin == end) return begin; + c = to_ascii(*begin); + } +} + +template +FMT_CONSTEXPR FMT_INLINE auto parse_replacement_field(const Char* begin, + const Char* end, + Handler&& handler) + -> const Char* { + ++begin; + if (begin == end) { + handler.on_error("invalid format string"); + return end; + } + int arg_id = 0; + switch (*begin) { + case '}': + handler.on_replacement_field(handler.on_arg_id(), begin); + return begin + 1; + case '{': handler.on_text(begin, begin + 1); return begin + 1; + case ':': arg_id = handler.on_arg_id(); break; + default: { + struct id_adapter { + Handler& handler; + int arg_id; + + FMT_CONSTEXPR void on_index(int id) { arg_id = handler.on_arg_id(id); } + FMT_CONSTEXPR void on_name(basic_string_view id) { + arg_id = handler.on_arg_id(id); + } + } adapter = {handler, 0}; + begin = parse_arg_id(begin, end, adapter); + arg_id = adapter.arg_id; + Char c = begin != end ? *begin : Char(); + if (c == '}') { + handler.on_replacement_field(arg_id, begin); + return begin + 1; + } + if (c != ':') { + handler.on_error("missing '}' in format string"); + return end; + } + break; + } + } + begin = handler.on_format_specs(arg_id, begin + 1, end); + if (begin == end || *begin != '}') + return handler.on_error("unknown format specifier"), end; + return begin + 1; +} + +template +FMT_CONSTEXPR void parse_format_string(basic_string_view fmt, + Handler&& handler) { + auto begin = fmt.data(), end = begin + fmt.size(); + auto 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); +} + +// Checks char specs and returns true iff the presentation type is char-like. +FMT_CONSTEXPR inline auto check_char_specs(const format_specs& specs) -> bool { + auto type = specs.type(); + if (type != presentation_type::none && type != presentation_type::chr && + type != presentation_type::debug) { + return false; + } + if (specs.align() == align::numeric || specs.sign() != sign::none || + specs.alt()) { + report_error("invalid format specifier for char"); + } + return true; +} + +// A base class for compile-time strings. +struct compile_string {}; + +template +FMT_VISIBILITY("hidden") // Suppress an ld warning on macOS (#3769). +FMT_CONSTEXPR auto invoke_parse(parse_context& ctx) -> const Char* { + using mapped_type = remove_cvref_t>; + constexpr bool formattable = + std::is_constructible>::value; + if (!formattable) return ctx.begin(); // Error is reported in the value ctor. + using formatted_type = conditional_t; + return formatter().parse(ctx); +} + +template struct arg_pack {}; + +template +class format_string_checker { + private: + type types_[max_of(1, NUM_ARGS)]; + named_arg_info named_args_[max_of(1, NUM_NAMED_ARGS)]; + compile_parse_context context_; + + using parse_func = auto (*)(parse_context&) -> const Char*; + parse_func parse_funcs_[max_of(1, NUM_ARGS)]; + + public: + template + FMT_CONSTEXPR explicit format_string_checker(basic_string_view fmt, + arg_pack) + : types_{mapped_type_constant::value...}, + named_args_{}, + context_(fmt, NUM_ARGS, types_), + parse_funcs_{&invoke_parse...} { + int arg_index = 0, named_arg_index = 0; + FMT_APPLY_VARIADIC( + init_static_named_arg(named_args_, arg_index, named_arg_index)); + ignore_unused(arg_index, named_arg_index); + } + + 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 { + context_.check_arg_id(id); + return id; + } + FMT_CONSTEXPR auto on_arg_id(basic_string_view id) -> int { + for (int i = 0; i < NUM_NAMED_ARGS; ++i) { + if (named_args_[i].name == id) return named_args_[i].id; + } + if (!DYNAMIC_NAMES) on_error("argument not found"); + return -1; + } + + FMT_CONSTEXPR void on_replacement_field(int id, const Char* begin) { + on_format_specs(id, begin, begin); // Call parse() on empty specs. + } + + FMT_CONSTEXPR auto on_format_specs(int id, const Char* begin, const Char* end) + -> const Char* { + context_.advance_to(begin); + if (id >= 0 && id < NUM_ARGS) return parse_funcs_[id](context_); + while (begin != end && *begin != '}') ++begin; + return begin; + } + + FMT_NORETURN FMT_CONSTEXPR void on_error(const char* message) { + report_error(message); + } +}; + +/// A contiguous memory buffer with an optional growing ability. It is an +/// internal class and shouldn't be used directly, only via `memory_buffer`. +template class buffer { + private: + T* ptr_; + size_t size_; + size_t capacity_; + + using grow_fun = void (*)(buffer& buf, size_t capacity); + grow_fun grow_; + + protected: + // Don't initialize ptr_ since it is not accessed to save a few cycles. + FMT_MSC_WARNING(suppress : 26495) + FMT_CONSTEXPR buffer(grow_fun grow, size_t sz) noexcept + : size_(sz), capacity_(sz), grow_(grow) {} + + constexpr buffer(grow_fun grow, T* p = nullptr, size_t sz = 0, + size_t cap = 0) noexcept + : ptr_(p), size_(sz), capacity_(cap), grow_(grow) {} + + FMT_CONSTEXPR20 ~buffer() = default; + buffer(buffer&&) = default; + + /// Sets the buffer data and capacity. + FMT_CONSTEXPR void set(T* buf_data, size_t buf_capacity) noexcept { + ptr_ = buf_data; + capacity_ = buf_capacity; + } + + public: + using value_type = T; + using const_reference = const T&; + + buffer(const buffer&) = delete; + void operator=(const buffer&) = delete; + + auto begin() noexcept -> T* { return ptr_; } + auto end() noexcept -> T* { return ptr_ + size_; } + + auto begin() const noexcept -> const T* { return ptr_; } + auto end() const noexcept -> const T* { return ptr_ + size_; } + + /// Returns the size of this buffer. + constexpr auto size() const noexcept -> size_t { return size_; } + + /// Returns the capacity of this buffer. + constexpr auto capacity() const noexcept -> size_t { return capacity_; } + + /// Returns a pointer to the buffer data (not null-terminated). + FMT_CONSTEXPR auto data() noexcept -> T* { return ptr_; } + FMT_CONSTEXPR auto data() const noexcept -> const T* { return ptr_; } + + /// Clears this buffer. + FMT_CONSTEXPR 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_CONSTEXPR void try_resize(size_t count) { + try_reserve(count); + size_ = min_of(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_CONSTEXPR void try_reserve(size_t new_capacity) { + if (new_capacity > capacity_) grow_(*this, new_capacity); + } + + FMT_CONSTEXPR void push_back(const T& value) { + try_reserve(size_ + 1); + ptr_[size_++] = value; + } + + /// Appends data to the end of the buffer. + template +// Workaround for MSVC2019 to fix error C2893: Failed to specialize function +// template 'void fmt::v11::detail::buffer::append(const U *,const U *)'. +#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1940 + FMT_CONSTEXPR20 +#endif + void + 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; + // A loop is faster than memcpy on small sizes. + T* out = ptr_ + size_; + for (size_t i = 0; i < count; ++i) out[i] = begin[i]; + size_ += count; + begin += count; + } + } + + template FMT_CONSTEXPR auto operator[](Idx index) -> T& { + return ptr_[index]; + } + template + FMT_CONSTEXPR auto operator[](Idx index) const -> const T& { + return ptr_[index]; + } +}; + +struct buffer_traits { + constexpr explicit buffer_traits(size_t) {} + constexpr auto count() const -> size_t { return 0; } + constexpr auto limit(size_t size) const -> size_t { return size; } +}; + +class fixed_buffer_traits { + private: + size_t count_ = 0; + size_t limit_; + + public: + constexpr explicit fixed_buffer_traits(size_t limit) : limit_(limit) {} + constexpr auto count() const -> size_t { return count_; } + FMT_CONSTEXPR auto limit(size_t size) -> size_t { + size_t n = limit_ > count_ ? limit_ - count_ : 0; + count_ += size; + return min_of(size, n); + } +}; + +// A buffer that writes to an output iterator when flushed. +template +class iterator_buffer : public Traits, public buffer { + private: + OutputIt out_; + enum { buffer_size = 256 }; + T data_[buffer_size]; + + static FMT_CONSTEXPR void grow(buffer& buf, size_t) { + if (buf.size() == buffer_size) static_cast(buf).flush(); + } + + void flush() { + auto size = this->size(); + this->clear(); + const T* begin = data_; + const T* end = begin + this->limit(size); + while (begin != end) *out_++ = *begin++; + } + + public: + explicit iterator_buffer(OutputIt out, size_t n = buffer_size) + : Traits(n), buffer(grow, data_, 0, buffer_size), out_(out) {} + iterator_buffer(iterator_buffer&& other) noexcept + : Traits(other), + buffer(grow, data_, 0, buffer_size), + out_(other.out_) {} + ~iterator_buffer() { + // Don't crash if flush fails during unwinding. + FMT_TRY { flush(); } + FMT_CATCH(...) {} + } + + auto out() -> OutputIt { + flush(); + return out_; + } + auto count() const -> size_t { return Traits::count() + this->size(); } +}; + +template +class iterator_buffer : public fixed_buffer_traits, + public buffer { + private: + T* out_; + enum { buffer_size = 256 }; + T data_[buffer_size]; + + static FMT_CONSTEXPR void grow(buffer& buf, size_t) { + if (buf.size() == buf.capacity()) + static_cast(buf).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(grow, out, 0, n), out_(out) {} + iterator_buffer(iterator_buffer&& other) noexcept + : fixed_buffer_traits(other), + buffer(static_cast(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 : public buffer { + public: + explicit iterator_buffer(T* out, size_t = 0) + : buffer([](buffer&, size_t) {}, out, 0, ~size_t()) {} + + auto out() -> T* { return &*this->end(); } +}; + +template +class container_buffer : public buffer { + private: + using value_type = typename Container::value_type; + + static FMT_CONSTEXPR void grow(buffer& buf, size_t capacity) { + auto& self = static_cast(buf); + self.container.resize(capacity); + self.set(&self.container[0], capacity); + } + + public: + Container& container; + + explicit container_buffer(Container& c) + : buffer(grow, c.size()), container(c) {} +}; + +// A buffer that writes to a container with the contiguous storage. +template +class iterator_buffer< + OutputIt, + enable_if_t::value && + is_contiguous::value, + typename OutputIt::container_type::value_type>> + : public container_buffer { + private: + using base = container_buffer; + + public: + explicit iterator_buffer(typename OutputIt::container_type& c) : base(c) {} + explicit iterator_buffer(OutputIt out, size_t = 0) + : base(get_container(out)) {} + + auto out() -> OutputIt { return OutputIt(this->container); } +}; + +// A buffer that counts the number of code units written discarding the output. +template class counting_buffer : public buffer { + private: + enum { buffer_size = 256 }; + T data_[buffer_size]; + size_t count_ = 0; + + static FMT_CONSTEXPR void grow(buffer& buf, size_t) { + if (buf.size() != buffer_size) return; + static_cast(buf).count_ += buf.size(); + buf.clear(); + } + + public: + FMT_CONSTEXPR counting_buffer() : buffer(grow, data_, 0, buffer_size) {} + + constexpr auto count() const noexcept -> size_t { + return count_ + this->size(); + } +}; + +template +struct is_back_insert_iterator> : std::true_type {}; + +template +struct has_back_insert_iterator_container_append : std::false_type {}; +template +struct has_back_insert_iterator_container_append< + OutputIt, InputIt, + void_t()) + .append(std::declval(), + std::declval()))>> : std::true_type {}; + +// An optimized version of std::copy with the output value type (T). +template ::value&& + has_back_insert_iterator_container_append< + OutputIt, InputIt>::value)> +FMT_CONSTEXPR20 auto copy(InputIt begin, InputIt end, OutputIt out) + -> OutputIt { + get_container(out).append(begin, end); + return out; +} + +template ::value && + !has_back_insert_iterator_container_append< + OutputIt, InputIt>::value)> +FMT_CONSTEXPR20 auto copy(InputIt begin, InputIt end, OutputIt out) + -> OutputIt { + auto& c = get_container(out); + c.insert(c.end(), begin, end); + return out; +} + +template ::value)> +FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt { + while (begin != end) *out++ = static_cast(*begin++); + return out; +} + +template +FMT_CONSTEXPR auto copy(basic_string_view s, OutputIt out) -> OutputIt { + return copy(s.begin(), s.end(), out); +} + +template +struct is_buffer_appender : std::false_type {}; +template +struct is_buffer_appender< + It, bool_constant< + is_back_insert_iterator::value && + std::is_base_of, + typename It::container_type>::value>> + : std::true_type {}; + +// Maps an output iterator to a buffer. +template ::value)> +auto get_buffer(OutputIt out) -> iterator_buffer { + return iterator_buffer(out); +} +template ::value)> +auto get_buffer(OutputIt out) -> buffer& { + return get_container(out); +} + +template +auto get_iterator(Buf& buf, OutputIt) -> decltype(buf.out()) { + return buf.out(); +} +template +auto get_iterator(buffer&, OutputIt out) -> OutputIt { + return out; +} + +// This type is intentionally undefined, only used for errors. +template struct type_is_unformattable_for; + +template struct string_value { + const Char* data; + size_t size; + auto str() const -> basic_string_view { return {data, size}; } +}; + +template struct custom_value { + using char_type = typename Context::char_type; + void* value; + void (*format)(void* arg, parse_context& parse_ctx, Context& ctx); +}; + +template struct named_arg_value { + const named_arg_info* data; + size_t size; +}; + +struct custom_tag {}; + +#if !FMT_BUILTIN_TYPES +# define FMT_BUILTIN , monostate +#else +# define FMT_BUILTIN +#endif + +// 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_opt int128_value; + uint128_opt 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(signed char x) : int_value(x) {} + constexpr FMT_INLINE value(unsigned char x FMT_BUILTIN) : uint_value(x) {} + constexpr FMT_INLINE value(signed short x) : int_value(x) {} + constexpr FMT_INLINE value(unsigned short x FMT_BUILTIN) : uint_value(x) {} + constexpr FMT_INLINE value(int x) : int_value(x) {} + constexpr FMT_INLINE value(unsigned x FMT_BUILTIN) : uint_value(x) {} + FMT_CONSTEXPR FMT_INLINE value(long x FMT_BUILTIN) : value(long_type(x)) {} + FMT_CONSTEXPR FMT_INLINE value(unsigned long x FMT_BUILTIN) + : value(ulong_type(x)) {} + constexpr FMT_INLINE value(long long x FMT_BUILTIN) : long_long_value(x) {} + constexpr FMT_INLINE value(unsigned long long x FMT_BUILTIN) + : ulong_long_value(x) {} + FMT_INLINE value(int128_opt x FMT_BUILTIN) : int128_value(x) {} + FMT_INLINE value(uint128_opt x FMT_BUILTIN) : uint128_value(x) {} + constexpr FMT_INLINE value(bool x FMT_BUILTIN) : bool_value(x) {} + + template + constexpr FMT_INLINE value(bitint x FMT_BUILTIN) : long_long_value(x) { + static_assert(N <= 64, "unsupported _BitInt"); + } + template + constexpr FMT_INLINE value(ubitint x FMT_BUILTIN) : ulong_long_value(x) { + static_assert(N <= 64, "unsupported _BitInt"); + } + + template ::value)> + constexpr FMT_INLINE value(T x FMT_BUILTIN) : char_value(x) { + static_assert( + std::is_same::value || std::is_same::value, + "mixing character types is disallowed"); + } + + constexpr FMT_INLINE value(float x FMT_BUILTIN) : float_value(x) {} + constexpr FMT_INLINE value(double x FMT_BUILTIN) : double_value(x) {} + FMT_INLINE value(long double x FMT_BUILTIN) : long_double_value(x) {} + + FMT_CONSTEXPR FMT_INLINE value(char_type* x FMT_BUILTIN) { + string.data = x; + if (is_constant_evaluated()) string.size = 0; + } + FMT_CONSTEXPR FMT_INLINE value(const char_type* x FMT_BUILTIN) { + string.data = x; + if (is_constant_evaluated()) string.size = 0; + } + template , + FMT_ENABLE_IF(!std::is_pointer::value)> + FMT_CONSTEXPR value(const T& x FMT_BUILTIN) { + static_assert(std::is_same::value, + "mixing character types is disallowed"); + auto sv = to_string_view(x); + string.data = sv.data(); + string.size = sv.size(); + } + FMT_INLINE value(void* x FMT_BUILTIN) : pointer(x) {} + FMT_INLINE value(const void* x FMT_BUILTIN) : pointer(x) {} + FMT_INLINE value(volatile void* x FMT_BUILTIN) + : pointer(const_cast(x)) {} + FMT_INLINE value(const volatile void* x FMT_BUILTIN) + : pointer(const_cast(x)) {} + FMT_INLINE value(nullptr_t) : pointer(nullptr) {} + + template ::value || + std::is_member_pointer::value)> + value(const T&) { + // Formatting of arbitrary pointers is disallowed. If you want to format a + // pointer cast it to `void*` or `const void*`. In particular, this forbids + // formatting of `[const] volatile char*` printed as bool by iostreams. + static_assert(sizeof(T) == 0, + "formatting of non-void pointers is disallowed"); + } + + template ::value)> + value(const T& x) : value(format_as(x)) {} + template ::value)> + value(const T& x) : value(formatter::format_as(x)) {} + + template ::value)> + value(const T& named_arg) : value(named_arg.value) {} + + template ::value || !FMT_BUILTIN_TYPES)> + FMT_CONSTEXPR20 FMT_INLINE value(T& x) : value(x, custom_tag()) {} + + FMT_ALWAYS_INLINE value(const named_arg_info* args, size_t size) + : named_args{args, size} {} + + private: + template ())> + FMT_CONSTEXPR value(T& x, custom_tag) { + using value_type = remove_const_t; + // T may overload operator& e.g. std::vector::reference in libc++. + if (!is_constant_evaluated()) { + custom.value = + const_cast(&reinterpret_cast(x)); + } else { + custom.value = nullptr; +#if defined(__cpp_if_constexpr) + if constexpr (std::is_same*>::value) + custom.value = const_cast(&x); +#endif + } + custom.format = format_custom>; + } + + template ())> + FMT_CONSTEXPR value(const T&, custom_tag) { + // Cannot format an argument; to make type T formattable provide a + // formatter specialization: https://fmt.dev/latest/api.html#udt. + type_is_unformattable_for _; + } + + // Formats an argument of a custom type, such as a user-defined class. + template + static void format_custom(void* arg, parse_context& parse_ctx, + Context& ctx) { + auto f = Formatter(); + parse_ctx.advance_to(f.parse(parse_ctx)); + using qualified_type = + conditional_t(), const T, T>; + // format must be const for compatibility with std::format and compilation. + const auto& cf = f; + ctx.advance_to(cf.format(*static_cast(arg), ctx)); + } +}; + +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 }; + +template +struct is_output_iterator : std::false_type {}; + +template <> struct is_output_iterator : std::true_type {}; + +template +struct is_output_iterator< + It, T, + void_t&>()++ = std::declval())>> + : std::true_type {}; + +#ifndef FMT_USE_LOCALE +# define FMT_USE_LOCALE (FMT_OPTIMIZE_SIZE <= 1) +#endif + +// A type-erased reference to an std::locale to avoid a heavy include. +struct locale_ref { +#if FMT_USE_LOCALE + private: + const void* locale_; // A type-erased pointer to std::locale. + + public: + constexpr locale_ref() : locale_(nullptr) {} + template locale_ref(const Locale& loc); + + inline explicit operator bool() const noexcept { return locale_ != nullptr; } +#endif // FMT_USE_LOCALE + + 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(stored_type_constant::value) | + (encode_types() << packed_arg_bits); +} + +template +constexpr auto make_descriptor() -> unsigned long long { + return NUM_ARGS <= max_packed_args ? encode_types() + : is_unpacked_bit | NUM_ARGS; +} + +template +using arg_t = conditional_t, + basic_format_arg>; + +template +struct named_arg_store { + // args_[0].named_args points to named_args to avoid bloating format_args. + arg_t args[1 + NUM_ARGS]; + named_arg_info named_args[NUM_NAMED_ARGS]; + + template + FMT_CONSTEXPR FMT_ALWAYS_INLINE named_arg_store(T&... values) + : args{{named_args, NUM_NAMED_ARGS}, values...} { + int arg_index = 0, named_arg_index = 0; + FMT_APPLY_VARIADIC( + init_named_arg(named_args, arg_index, named_arg_index, values)); + } + + named_arg_store(named_arg_store&& rhs) { + args[0] = {named_args, NUM_NAMED_ARGS}; + for (size_t i = 1; i < sizeof(args) / sizeof(*args); ++i) + args[i] = rhs.args[i]; + for (size_t i = 0; i < NUM_NAMED_ARGS; ++i) + named_args[i] = rhs.named_args[i]; + } + + named_arg_store(const named_arg_store& rhs) = delete; + named_arg_store& operator=(const named_arg_store& rhs) = delete; + named_arg_store& operator=(named_arg_store&& rhs) = delete; + operator const arg_t*() const { return args + 1; } +}; + +// An array of references to arguments. It can be implicitly converted to +// `basic_format_args` for passing into type-erased formatting functions +// such as `vformat`. It is a plain struct to reduce binary size in debug mode. +template +struct format_arg_store { + // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. + using type = + conditional_t[max_of(1, NUM_ARGS)], + named_arg_store>; + type args; +}; + +// TYPE can be different from type_constant, e.g. for __float128. +template struct native_formatter { + private: + dynamic_format_specs specs_; + + public: + using nonlocking = void; + + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + if (ctx.begin() == ctx.end() || *ctx.begin() == '}') return ctx.begin(); + auto end = parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, TYPE); + if (const_check(TYPE == type::char_type)) check_char_specs(specs_); + return end; + } + + template + FMT_CONSTEXPR void set_debug_format(bool set = true) { + specs_.set_type(set ? presentation_type::debug : presentation_type::none); + } + + FMT_PRAGMA_CLANG(diagnostic ignored "-Wundefined-inline") + template + FMT_CONSTEXPR auto format(const T& val, FormatContext& ctx) const + -> decltype(ctx.out()); +}; + +template +struct locking + : bool_constant::value == type::custom_type> {}; +template +struct locking>::nonlocking>> + : std::false_type {}; + +template FMT_CONSTEXPR inline auto is_locking() -> bool { + return locking::value; +} +template +FMT_CONSTEXPR inline auto is_locking() -> bool { + return locking::value || is_locking(); +} + +FMT_API void vformat_to(buffer& buf, string_view fmt, format_args args, + locale_ref loc = {}); + +#if FMT_WIN32 +FMT_API void vprint_mojibake(FILE*, string_view, format_args, bool); +#else // format_args is passed by reference since it is defined later. +inline void vprint_mojibake(FILE*, string_view, const format_args&, bool) {} +#endif +} // namespace detail + +// The main public API. + +template +FMT_CONSTEXPR void parse_context::do_check_arg_id(int arg_id) { + // Argument id is only checked at compile time during parsing because + // formatting has its own validation. + if (detail::is_constant_evaluated() && use_constexpr_cast) { + auto ctx = static_cast*>(this); + if (arg_id >= ctx->num_args()) report_error("argument not found"); + } +} + +template +FMT_CONSTEXPR void parse_context::check_dynamic_spec(int arg_id) { + using detail::compile_parse_context; + if (detail::is_constant_evaluated() && use_constexpr_cast) + static_cast*>(this)->check_dynamic_spec(arg_id); +} + +FMT_BEGIN_EXPORT + +// An output iterator that appends to a buffer. It is used instead of +// back_insert_iterator to reduce symbol sizes and avoid dependency. +template class basic_appender { + protected: + detail::buffer* container; + + public: + using container_type = detail::buffer; + + FMT_CONSTEXPR basic_appender(detail::buffer& buf) : container(&buf) {} + + FMT_CONSTEXPR20 auto operator=(T c) -> basic_appender& { + container->push_back(c); + return *this; + } + FMT_CONSTEXPR20 auto operator*() -> basic_appender& { return *this; } + FMT_CONSTEXPR20 auto operator++() -> basic_appender& { return *this; } + FMT_CONSTEXPR20 auto operator++(int) -> basic_appender { return *this; } +}; + +// A formatting argument. Context is a template parameter for the compiled API +// where output can be unbuffered. +template class basic_format_arg { + private: + detail::value value_; + detail::type type_; + + friend class basic_format_args; + + using char_type = typename Context::char_type; + + public: + class handle { + private: + detail::custom_value custom_; + + public: + explicit handle(detail::custom_value custom) : custom_(custom) {} + + void format(parse_context& parse_ctx, Context& ctx) const { + custom_.format(custom_.value, parse_ctx, ctx); + } + }; + + constexpr basic_format_arg() : type_(detail::type::none_type) {} + basic_format_arg(const detail::named_arg_info* args, size_t size) + : value_(args, size) {} + template + basic_format_arg(T&& val) + : value_(val), type_(detail::stored_type_constant::value) {} + + constexpr explicit operator bool() const noexcept { + return type_ != detail::type::none_type; + } + auto type() const -> detail::type { return type_; } + + /** + * 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`. + */ + template + FMT_CONSTEXPR FMT_INLINE auto visit(Visitor&& vis) const -> decltype(vis(0)) { + using detail::map; + switch (type_) { + case detail::type::none_type: break; + case detail::type::int_type: return vis(value_.int_value); + case detail::type::uint_type: return vis(value_.uint_value); + case detail::type::long_long_type: return vis(value_.long_long_value); + case detail::type::ulong_long_type: return vis(value_.ulong_long_value); + case detail::type::int128_type: return vis(map(value_.int128_value)); + case detail::type::uint128_type: return vis(map(value_.uint128_value)); + case detail::type::bool_type: return vis(value_.bool_value); + case detail::type::char_type: return vis(value_.char_value); + case detail::type::float_type: return vis(value_.float_value); + case detail::type::double_type: return vis(value_.double_value); + case detail::type::long_double_type: return vis(value_.long_double_value); + case detail::type::cstring_type: return vis(value_.string.data); + case detail::type::string_type: return vis(value_.string.str()); + case detail::type::pointer_type: return vis(value_.pointer); + case detail::type::custom_type: return vis(handle(value_.custom)); + } + return vis(monostate()); + } + + auto format_custom(const char_type* parse_begin, + parse_context& parse_ctx, Context& ctx) + -> bool { + if (type_ != detail::type::custom_type) return false; + parse_ctx.advance_to(parse_begin); + value_.custom.format(value_.custom.value, parse_ctx, ctx); + return true; + } +}; + +/** + * 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(fmt::string_view fmt, fmt::format_args args); // OK + * fmt::format_args args = fmt::make_format_args(); // Dangling reference + */ +template class basic_format_args { + 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 basic_format_arg* args_; + }; + + constexpr auto is_packed() const -> bool { + return (desc_ & detail::is_unpacked_bit) == 0; + } + constexpr 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 mask = (1 << detail::packed_arg_bits) - 1; + return static_cast((desc_ >> shift) & mask); + } + + template + using store = + detail::format_arg_store; + + public: + using format_arg = basic_format_arg; + + constexpr basic_format_args() : desc_(0), args_(nullptr) {} + + /// Constructs a `basic_format_args` object from `format_arg_store`. + template + constexpr FMT_ALWAYS_INLINE basic_format_args( + const store& s) + : desc_(DESC | (NUM_NAMED_ARGS != 0 ? +detail::has_named_args_bit : 0)), + values_(s.args) {} + + template detail::max_packed_args)> + constexpr basic_format_args(const store& s) + : desc_(DESC | (NUM_NAMED_ARGS != 0 ? +detail::has_named_args_bit : 0)), + args_(s.args) {} + + /// Constructs a `basic_format_args` object from a dynamic list of arguments. + constexpr basic_format_args(const format_arg* args, int count, + bool has_named = false) + : desc_(detail::is_unpacked_bit | detail::to_unsigned(count) | + (has_named ? +detail::has_named_args_bit : 0)), + args_(args) {} + + /// Returns the argument with the specified id. + FMT_CONSTEXPR auto get(int id) const -> format_arg { + auto arg = format_arg(); + if (!is_packed()) { + if (id < max_size()) arg = args_[id]; + return arg; + } + if (static_cast(id) >= detail::max_packed_args) return arg; + arg.type_ = type(id); + if (arg.type_ != detail::type::none_type) 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 + FMT_CONSTEXPR 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); + } +}; + +// A formatting context. +class context { + private: + appender out_; + format_args args_; + FMT_NO_UNIQUE_ADDRESS detail::locale_ref loc_; + + public: + /// The character type for the output. + using char_type = char; + + using iterator = appender; + using format_arg = basic_format_arg; + using parse_context_type FMT_DEPRECATED = parse_context<>; + template using formatter_type FMT_DEPRECATED = formatter; + enum { builtin_types = FMT_BUILTIN_TYPES }; + + /// Constructs a `context` object. References to the arguments are stored + /// in the object so make sure they have appropriate lifetimes. + FMT_CONSTEXPR context(iterator out, format_args args, + detail::locale_ref loc = {}) + : out_(out), args_(args), loc_(loc) {} + context(context&&) = default; + context(const context&) = delete; + void operator=(const context&) = delete; + + FMT_CONSTEXPR auto arg(int id) const -> format_arg { return args_.get(id); } + inline auto arg(string_view name) const -> format_arg { + return args_.get(name); + } + FMT_CONSTEXPR auto arg_id(string_view name) const -> int { + return args_.get_id(name); + } + + // Returns an iterator to the beginning of the output range. + FMT_CONSTEXPR auto out() const -> iterator { return out_; } + + // Advances the begin iterator to `it`. + FMT_CONSTEXPR void advance_to(iterator) {} + + FMT_CONSTEXPR auto locale() const -> detail::locale_ref { return loc_; } +}; + +template struct runtime_format_string { + basic_string_view str; +}; + +/** + * 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"); + */ +inline auto runtime(string_view s) -> runtime_format_string<> { return {{s}}; } + +/// A compile-time format string. Use `format_string` in the public API to +/// prevent type deduction. +template struct fstring { + private: + static constexpr int num_static_named_args = + detail::count_static_named_args(); + + using checker = detail::format_string_checker< + char, static_cast(sizeof...(T)), num_static_named_args, + num_static_named_args != detail::count_named_args()>; + + using arg_pack = detail::arg_pack; + + public: + string_view str; + using t = fstring; + + // Reports a compile-time error if S is not a valid format string for T. + template + FMT_CONSTEVAL FMT_ALWAYS_INLINE fstring(const char (&s)[N]) : str(s, N - 1) { + using namespace detail; + static_assert(count<(std::is_base_of>::value && + std::is_reference::value)...>() == 0, + "passing views as lvalues is disallowed"); + if (FMT_USE_CONSTEVAL) parse_format_string(s, checker(s, arg_pack())); +#ifdef FMT_ENFORCE_COMPILE_STRING + static_assert( + FMT_USE_CONSTEVAL && sizeof(s) != 0, + "FMT_ENFORCE_COMPILE_STRING requires format strings to use FMT_STRING"); +#endif + } + template ::value)> + FMT_CONSTEVAL FMT_ALWAYS_INLINE fstring(const S& s) : str(s) { + auto sv = string_view(str); + if (FMT_USE_CONSTEVAL) + detail::parse_format_string(sv, checker(sv, arg_pack())); +#ifdef FMT_ENFORCE_COMPILE_STRING + static_assert( + FMT_USE_CONSTEVAL && sizeof(s) != 0, + "FMT_ENFORCE_COMPILE_STRING requires format strings to use FMT_STRING"); +#endif + } + template ::value&& + std::is_same::value)> + FMT_ALWAYS_INLINE fstring(const S&) : str(S()) { + FMT_CONSTEXPR auto sv = string_view(S()); + FMT_CONSTEXPR int ignore = + (parse_format_string(sv, checker(sv, arg_pack())), 0); + detail::ignore_unused(ignore); + } + fstring(runtime_format_string<> fmt) : str(fmt.str) {} + + // Returning by reference generates better code in debug mode. + FMT_ALWAYS_INLINE operator const string_view&() const { return str; } + auto get() const -> string_view { return str; } +}; + +template using format_string = typename fstring::t; + +template +using is_formattable = bool_constant::value, int*, T>, Char>, + void>::value>; +#ifdef __cpp_concepts +template +concept formattable = is_formattable, Char>::value; +#endif + +template +using has_formatter FMT_DEPRECATED = std::is_constructible>; + +// A formatter specialization for natively supported types. +template +struct formatter::value != + detail::type::custom_type>> + : detail::native_formatter::value> { +}; + +/** + * Constructs an object that stores references to arguments and can be + * implicitly converted to `format_args`. `Context` can be omitted in which case + * it defaults to `context`. See `arg` for lifetime considerations. + */ +// Take arguments by lvalue references to avoid some lifetime issues, e.g. +// auto args = make_format_args(std::string()); +template (), + unsigned long long DESC = detail::make_descriptor()> +constexpr FMT_ALWAYS_INLINE auto make_format_args(T&... args) + -> detail::format_arg_store { + // Suppress warnings for pathological types convertible to detail::value. + FMT_PRAGMA_GCC(diagnostic ignored "-Wconversion") + return {{args...}}; +} + +template +using vargs = + detail::format_arg_store(), + detail::make_descriptor()>; + +/** + * Returns a named argument to be used in a formatting function. + * It should only be used in a call to a formatting function. + * + * **Example**: + * + * fmt::print("The answer is {answer}.", fmt::arg("answer", 42)); + */ +template +inline auto arg(const Char* name, const T& arg) -> detail::named_arg { + return {name, arg}; +} + +/// Formats a string and writes the output to `out`. +template , + char>::value)> +auto vformat_to(OutputIt&& out, string_view fmt, format_args args) + -> remove_cvref_t { + auto&& buf = detail::get_buffer(out); + detail::vformat_to(buf, fmt, args, {}); + return detail::get_iterator(buf, out); +} + +/** + * 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); + */ +template , + char>::value)> +FMT_INLINE auto format_to(OutputIt&& out, format_string fmt, T&&... args) + -> remove_cvref_t { + return vformat_to(out, fmt.str, vargs{{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()}; +} + +/** + * 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. + */ +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.str, vargs{{args...}}); +} + +struct format_to_result { + /// Pointer to just after the last successful write in the array. + char* out; + /// Specifies if the output was truncated. + bool truncated; + + FMT_CONSTEXPR operator char*() const { + // Report truncation to prevent silent data loss. + if (truncated) report_error("output is truncated"); + return out; + } +}; + +template +auto vformat_to(char (&out)[N], string_view fmt, format_args args) + -> format_to_result { + auto result = vformat_to_n(out, N, fmt, args); + return {result.out, result.size > N}; +} + +template +FMT_INLINE auto format_to(char (&out)[N], format_string fmt, T&&... args) + -> format_to_result { + auto result = vformat_to_n(out, N, fmt.str, vargs{{args...}}); + return {result.out, result.size > N}; +} + +/// 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, fmt.str, vargs{{args...}}, {}); + return buf.count(); +} + +FMT_API void vprint(string_view fmt, format_args args); +FMT_API void vprint(FILE* f, string_view fmt, format_args args); +FMT_API void vprintln(FILE* f, string_view fmt, format_args args); +FMT_API void vprint_buffered(FILE* f, string_view fmt, format_args args); + +/** + * Formats `args` according to specifications in `fmt` and writes the output + * to `stdout`. + * + * **Example**: + * + * fmt::print("The answer is {}.", 42); + */ +template +FMT_INLINE void print(format_string fmt, T&&... args) { + vargs va = {{args...}}; + if (detail::const_check(!detail::use_utf8)) + return detail::vprint_mojibake(stdout, fmt.str, va, false); + return detail::is_locking() ? vprint_buffered(stdout, fmt.str, va) + : vprint(fmt.str, va); +} + +/** + * Formats `args` according to specifications in `fmt` and writes the + * output to the file `f`. + * + * **Example**: + * + * fmt::print(stderr, "Don't {}!", "panic"); + */ +template +FMT_INLINE void print(FILE* f, format_string fmt, T&&... args) { + vargs va = {{args...}}; + if (detail::const_check(!detail::use_utf8)) + return detail::vprint_mojibake(f, fmt.str, va, false); + return detail::is_locking() ? vprint_buffered(f, fmt.str, va) + : vprint(f, fmt.str, va); +} + +/// Formats `args` according to specifications in `fmt` and writes the output +/// to the file `f` followed by a newline. +template +FMT_INLINE void println(FILE* f, format_string fmt, T&&... args) { + vargs va = {{args...}}; + return detail::const_check(detail::use_utf8) + ? vprintln(f, fmt.str, va) + : detail::vprint_mojibake(f, fmt.str, va, true); +} + +/// Formats `args` according to specifications in `fmt` and writes the output +/// to `stdout` followed by a newline. +template +FMT_INLINE void println(format_string fmt, T&&... args) { + return fmt::println(stdout, fmt, static_cast(args)...); +} + +FMT_END_EXPORT +FMT_PRAGMA_CLANG(diagnostic pop) +FMT_PRAGMA_GCC(pop_options) +FMT_END_NAMESPACE + +#ifdef FMT_HEADER_ONLY +# include "format.h" +#endif +#endif // FMT_BASE_H_ diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h new file mode 100644 index 0000000..50c777c --- /dev/null +++ b/include/fmt/chrono.h @@ -0,0 +1,2338 @@ +// 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_ + +#ifndef FMT_MODULE +# include +# include +# include // std::isfinite +# include // std::memcpy +# include +# include +# include +# include +# include +#endif + +#include "format.h" + +namespace fmt_detail { +struct time_zone { + template + auto to_sys(T) + -> std::chrono::time_point { + return {}; + } +}; +template inline auto current_zone(T...) -> time_zone* { + return nullptr; +} + +template inline void _tzset(T...) {} +} // namespace fmt_detail + +FMT_BEGIN_NAMESPACE + +// 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 auto lossless_integral_conversion(const From from, int& ec) + -> To { + 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 auto lossless_integral_conversion(const From from, int& ec) + -> To { + 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 auto lossless_integral_conversion(const From from, int& ec) + -> To { + 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 auto safe_float_conversion(const From from, int& ec) -> To { + 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 auto safe_float_conversion(const From from, int& ec) -> To { + ec = 0; + static_assert(std::is_floating_point::value, "From must be floating"); + return from; +} + +/// Safe duration_cast between floating point durations +template ::value), + FMT_ENABLE_IF(std::is_floating_point::value)> +auto safe_duration_cast(std::chrono::duration from, + int& ec) -> To { + 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 + +namespace detail { + +// Check if std::chrono::utc_time is available. +#ifdef FMT_USE_UTC_TIME +// Use the provided definition. +#elif defined(__cpp_lib_chrono) +# define FMT_USE_UTC_TIME (__cpp_lib_chrono >= 201907L) +#else +# define FMT_USE_UTC_TIME 0 +#endif +#if FMT_USE_UTC_TIME +using utc_clock = std::chrono::utc_clock; +#else +struct utc_clock { + template void to_sys(T); +}; +#endif + +// Check if std::chrono::local_time is available. +#ifdef FMT_USE_LOCAL_TIME +// Use the provided definition. +#elif defined(__cpp_lib_chrono) +# define FMT_USE_LOCAL_TIME (__cpp_lib_chrono >= 201907L) +#else +# define FMT_USE_LOCAL_TIME 0 +#endif +#if FMT_USE_LOCAL_TIME +using local_t = std::chrono::local_t; +#else +struct local_t {}; +#endif + +} // namespace detail + +template +using sys_time = std::chrono::time_point; + +template +using utc_time = std::chrono::time_point; + +template +using local_time = std::chrono::time_point; + +namespace detail { + +// Prevents expansion of a preceding token as a function-style macro. +// Usage: f FMT_NOMACRO() +#define FMT_NOMACRO + +template struct null {}; +inline auto localtime_r FMT_NOMACRO(...) -> null<> { return null<>(); } +inline auto localtime_s(...) -> null<> { return null<>(); } +inline auto gmtime_r(...) -> null<> { return null<>(); } +inline auto gmtime_s(...) -> null<> { return null<>(); } + +// It is defined here and not in ostream.h because the latter has expensive +// includes. +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; + } +}; + +inline auto get_classic_locale() -> const std::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 +void write_codecvt(codecvt_result& out, string_view in, + const std::locale& loc) { + FMT_PRAGMA_CLANG(diagnostic push) + FMT_PRAGMA_CLANG(diagnostic ignored "-Wdeprecated") + auto& f = std::use_facet>(loc); + FMT_PRAGMA_CLANG(diagnostic pop) + auto mb = std::mbstate_t(); + const char* from_next = nullptr; + auto result = f.in(mb, in.begin(), in.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 (const_check(detail::use_utf8) && loc != get_classic_locale()) { + // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and + // gcc-4. +#if FMT_MSC_VERSION != 0 || \ + (defined(__GLIBCXX__) && \ + (!defined(_GLIBCXX_USE_DUAL_ABI) || _GLIBCXX_USE_DUAL_ABI == 0)) + // 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 u = + to_utf8>(); + if (!u.convert({unit.buf, to_unsigned(unit.end - unit.buf)})) + FMT_THROW(format_error("failed to format time")); + return copy(u.c_str(), u.c_str() + u.size(), out); + } + return copy(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(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); + 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 get_iterator(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); +} + +template +struct is_same_arithmetic_type + : public std::integral_constant::value && + std::is_integral::value) || + (std::is_floating_point::value && + std::is_floating_point::value)> { +}; + +FMT_NORETURN inline void throw_duration_error() { + FMT_THROW(format_error("cannot format duration")); +} + +// Cast one integral duration to another with an overflow check. +template ::value&& + std::is_integral::value)> +auto duration_cast(std::chrono::duration from) -> To { +#if !FMT_SAFE_DURATION_CAST + return std::chrono::duration_cast(from); +#else + // The conversion factor: to.count() == factor * from.count(). + using factor = std::ratio_divide; + + using common_rep = typename std::common_type::type; + + int ec = 0; + auto count = safe_duration_cast::lossless_integral_conversion( + from.count(), ec); + if (ec) throw_duration_error(); + + // Multiply from.count() by factor and check for overflow. + if (const_check(factor::num != 1)) { + if (count > max_value() / factor::num) throw_duration_error(); + const auto min = (std::numeric_limits::min)() / factor::num; + if (const_check(!std::is_unsigned::value) && count < min) + throw_duration_error(); + count *= factor::num; + } + if (const_check(factor::den != 1)) count /= factor::den; + auto to = + To(safe_duration_cast::lossless_integral_conversion( + count, ec)); + if (ec) throw_duration_error(); + return to; +#endif +} + +template ::value&& + std::is_floating_point::value)> +auto duration_cast(std::chrono::duration from) -> To { +#if FMT_SAFE_DURATION_CAST + // Throwing version of safe_duration_cast is only available for + // integer to integer or float to float casts. + int ec; + To to = safe_duration_cast::safe_duration_cast(from, ec); + if (ec) throw_duration_error(); + return to; +#else + // Standard duration cast, may overflow. + return std::chrono::duration_cast(from); +#endif +} + +template < + typename To, typename FromRep, typename FromPeriod, + FMT_ENABLE_IF(!is_same_arithmetic_type::value)> +auto duration_cast(std::chrono::duration from) -> To { + // Mixed integer <-> float cast is not supported by safe_duration_cast. + return std::chrono::duration_cast(from); +} + +template +auto to_time_t(sys_time time_point) -> std::time_t { + // Cannot use std::chrono::system_clock::to_time_t since this would first + // require a cast to std::chrono::system_clock::time_point, which could + // overflow. + return detail::duration_cast>( + time_point.time_since_epoch()) + .count(); +} + +// Workaround a bug in libstdc++ which sets __cpp_lib_chrono to 201907 without +// providing current_zone(): https://github.com/fmtlib/fmt/issues/4160. +template FMT_CONSTEXPR auto has_current_zone() -> bool { + using namespace std::chrono; + using namespace fmt_detail; + return !std::is_same::value; +} +} // namespace detail + +FMT_BEGIN_EXPORT + +/** + * 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 auto localtime(std::time_t time) -> std::tm { + struct dispatcher { + std::time_t time_; + std::tm tm_; + + inline dispatcher(std::time_t t) : time_(t) {} + + inline auto run() -> bool { + using namespace fmt::detail; + return handle(localtime_r(&time_, &tm_)); + } + + inline auto handle(std::tm* tm) -> bool { return tm != nullptr; } + + inline auto handle(detail::null<>) -> bool { + using namespace fmt::detail; + return fallback(localtime_s(&tm_, &time_)); + } + + inline auto fallback(int res) -> bool { return res == 0; } + +#if !FMT_MSC_VERSION + inline auto fallback(detail::null<>) -> bool { + 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_; +} + +#if FMT_USE_LOCAL_TIME +template ())> +inline auto localtime(std::chrono::local_time time) -> std::tm { + using namespace std::chrono; + using namespace fmt_detail; + return localtime(detail::to_time_t(current_zone()->to_sys(time))); +} +#endif + +/** + * 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 auto gmtime(std::time_t time) -> std::tm { + struct dispatcher { + std::time_t time_; + std::tm tm_; + + inline dispatcher(std::time_t t) : time_(t) {} + + inline auto run() -> bool { + using namespace fmt::detail; + return handle(gmtime_r(&time_, &tm_)); + } + + inline auto handle(std::tm* tm) -> bool { return tm != nullptr; } + + inline auto handle(detail::null<>) -> bool { + using namespace fmt::detail; + return fallback(gmtime_s(&tm_, &time_)); + } + + inline auto fallback(int res) -> bool { return res == 0; } + +#if !FMT_MSC_VERSION + inline auto fallback(detail::null<>) -> bool { + std::tm* tm = std::gmtime(&time_); + if (tm) tm_ = *tm; + return tm != nullptr; + } +#endif + }; + auto gt = dispatcher(time); + // Too big time values may be unsupported. + if (!gt.run()) FMT_THROW(format_error("time_t value out of range")); + return gt.tm_; +} + +template +inline auto gmtime(sys_time time_point) -> std::tm { + return gmtime(detail::to_time_t(time_point)); +} + +namespace detail { + +// 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]; + std::memcpy(tmp, &digits, len); + std::reverse_copy(tmp, tmp + len, buf); + } else { + std::memcpy(buf, &digits, len); + } +} + +template +FMT_CONSTEXPR inline auto get_units() -> const char* { + 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 detail::use_utf8 ? "µs" : "us"; + 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 "min"; + if (std::is_same>::value) return "h"; + if (std::is_same>::value) return "d"; + return nullptr; +} + +enum class numeric_system { + standard, + // Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale. + alternative +}; + +// Glibc extensions for formatting numeric values. +enum class pad_type { + // Pad a numeric result string with zeros (the default). + zero, + // Do not pad a numeric result string. + none, + // Pad a numeric result string with spaces. + space, +}; + +template +auto write_padding(OutputIt out, pad_type pad, int width) -> OutputIt { + if (pad == pad_type::none) return out; + return detail::fill_n(out, width, pad == pad_type::space ? ' ' : '0'); +} + +template +auto write_padding(OutputIt out, pad_type pad) -> OutputIt { + if (pad != pad_type::none) *out++ = pad == pad_type::space ? ' ' : '0'; + return out; +} + +// Parses a put_time-like format string and invokes handler actions. +template +FMT_CONSTEXPR auto parse_chrono_format(const Char* begin, const Char* end, + Handler&& handler) -> const Char* { + if (begin == end || *begin == '}') return begin; + if (*begin != '%') FMT_THROW(format_error("invalid format")); + auto ptr = begin; + while (ptr != end) { + pad_type pad = pad_type::zero; + 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 '_': + pad = pad_type::space; + ++ptr; + break; + case '-': + pad = pad_type::none; + ++ptr; + break; + } + 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, pad); 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, pad); break; + // Day of the year/month: + case 'U': + handler.on_dec0_week_of_year(numeric_system::standard, pad); + break; + case 'W': + handler.on_dec1_week_of_year(numeric_system::standard, pad); + break; + case 'V': handler.on_iso_week_of_year(numeric_system::standard, pad); break; + case 'j': handler.on_day_of_year(pad); break; + case 'd': handler.on_day_of_month(numeric_system::standard, pad); break; + case 'e': + handler.on_day_of_month(numeric_system::standard, pad_type::space); + break; + // Hour, minute, second: + case 'H': handler.on_24_hour(numeric_system::standard, pad); break; + case 'I': handler.on_12_hour(numeric_system::standard, pad); break; + case 'M': handler.on_minute(numeric_system::standard, pad); break; + case 'S': handler.on_second(numeric_system::standard, pad); 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(numeric_system::standard); 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, pad); 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; + case 'z': handler.on_utc_offset(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, pad); break; + case 'U': + handler.on_dec0_week_of_year(numeric_system::alternative, pad); + break; + case 'W': + handler.on_dec1_week_of_year(numeric_system::alternative, pad); + break; + case 'V': + handler.on_iso_week_of_year(numeric_system::alternative, pad); + break; + case 'd': + handler.on_day_of_month(numeric_system::alternative, pad); + break; + case 'e': + handler.on_day_of_month(numeric_system::alternative, pad_type::space); + 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, pad); break; + case 'I': handler.on_12_hour(numeric_system::alternative, pad); break; + case 'M': handler.on_minute(numeric_system::alternative, pad); break; + case 'S': handler.on_second(numeric_system::alternative, pad); break; + case 'z': handler.on_utc_offset(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, pad_type) { 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, pad_type) { unsupported(); } + FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system, pad_type) { + unsupported(); + } + FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system, pad_type) { + unsupported(); + } + FMT_CONSTEXPR void on_iso_week_of_year(numeric_system, pad_type) { + unsupported(); + } + FMT_CONSTEXPR void on_day_of_year(pad_type) { unsupported(); } + FMT_CONSTEXPR void on_day_of_month(numeric_system, pad_type) { + 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(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_tz_name() { unsupported(); } +}; + +struct tm_format_checker : null_chrono_spec_handler { + FMT_NORETURN inline 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, pad_type) {} + 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, pad_type) {} + FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_iso_week_of_year(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_day_of_year(pad_type) {} + FMT_CONSTEXPR void on_day_of_month(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_minute(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_second(numeric_system, pad_type) {} + 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(numeric_system) {} + FMT_CONSTEXPR void on_tz_name() {} +}; + +inline auto tm_wday_full_name(int wday) -> const char* { + static constexpr const char* full_name_list[] = { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday"}; + return wday >= 0 && wday <= 6 ? full_name_list[wday] : "?"; +} +inline auto tm_wday_short_name(int wday) -> const char* { + static constexpr const char* short_name_list[] = {"Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat"}; + return wday >= 0 && wday <= 6 ? short_name_list[wday] : "???"; +} + +inline auto tm_mon_full_name(int mon) -> const char* { + 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 auto tm_mon_short_name(int mon) -> const char* { + 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 {}; + +inline void tzset_once() { + static bool init = []() { + using namespace fmt_detail; + _tzset(); + return false; + }(); + ignore_unused(init); +} + +// Converts value to Int and checks that it's in the range [0, upper). +template ::value)> +inline auto to_nonnegative_int(T value, Int upper) -> Int { + if (!std::is_unsigned::value && + (value < 0 || to_unsigned(value) > to_unsigned(upper))) { + FMT_THROW(fmt::format_error("chrono value is out of range")); + } + return static_cast(value); +} +template ::value)> +inline auto to_nonnegative_int(T value, Int upper) -> Int { + auto int_value = static_cast(value); + if (int_value < 0 || value > static_cast(upper)) + FMT_THROW(format_error("invalid value")); + return int_value; +} + +constexpr auto pow10(std::uint32_t n) -> long long { + return n == 0 ? 1 : 10 * pow10(n - 1); +} + +// Counts 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. +template () / 10)> +struct count_fractional_digits { + static constexpr int value = + Num % Den == 0 ? N : count_fractional_digits::value; +}; + +// Base case that doesn't instantiate any more templates +// in order to avoid overflow. +template +struct count_fractional_digits { + static constexpr int value = (Num % Den == 0) ? N : 6; +}; + +// Format subseconds which are given as an integer type with an appropriate +// number of digits. +template +void write_fractional_seconds(OutputIt& out, Duration d, int precision = -1) { + constexpr auto num_fractional_digits = + count_fractional_digits::value; + + using subsecond_precision = std::chrono::duration< + typename std::common_type::type, + std::ratio<1, pow10(num_fractional_digits)>>; + + const auto fractional = d - detail::duration_cast(d); + const auto subseconds = + std::chrono::treat_as_floating_point< + typename subsecond_precision::rep>::value + ? fractional.count() + : detail::duration_cast(fractional).count(); + auto n = static_cast>(subseconds); + const int num_digits = count_digits(n); + + int leading_zeroes = (std::max)(0, num_fractional_digits - num_digits); + if (precision < 0) { + FMT_ASSERT(!std::is_floating_point::value, ""); + if (std::ratio_less::value) { + *out++ = '.'; + out = detail::fill_n(out, leading_zeroes, '0'); + out = format_decimal(out, n, num_digits); + } + } else if (precision > 0) { + *out++ = '.'; + leading_zeroes = min_of(leading_zeroes, precision); + int remaining = precision - leading_zeroes; + out = detail::fill_n(out, leading_zeroes, '0'); + if (remaining < num_digits) { + int num_truncated_digits = num_digits - remaining; + n /= to_unsigned(pow10(to_unsigned(num_truncated_digits))); + if (n != 0) out = format_decimal(out, n, remaining); + return; + } + if (n != 0) { + out = format_decimal(out, n, num_digits); + remaining -= num_digits; + } + out = detail::fill_n(out, remaining, '0'); + } +} + +// Format subseconds which are given as a floating point type with an +// appropriate number of digits. We cannot pass the Duration here, as we +// explicitly need to pass the Rep value in the chrono_formatter. +template +void write_floating_seconds(memory_buffer& buf, Duration duration, + int num_fractional_digits = -1) { + using rep = typename Duration::rep; + FMT_ASSERT(std::is_floating_point::value, ""); + + auto val = duration.count(); + + if (num_fractional_digits < 0) { + // For `std::round` with fallback to `round`: + // On some toolchains `std::round` is not available (e.g. GCC 6). + using namespace std; + num_fractional_digits = + count_fractional_digits::value; + if (num_fractional_digits < 6 && static_cast(round(val)) != val) + num_fractional_digits = 6; + } + + fmt::format_to(std::back_inserter(buf), FMT_STRING("{:.{}f}"), + std::fmod(val * static_cast(Duration::period::num) / + static_cast(Duration::period::den), + static_cast(60)), + num_fractional_digits); +} + +template +class tm_writer { + private: + static constexpr int days_per_week = 7; + + const std::locale& loc_; + const bool is_classic_; + OutputIt out_; + const Duration* subsecs_; + 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. + 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 write2(int value, pad_type pad) { + unsigned int v = to_unsigned(value) % 100; + if (v >= 10) { + const char* d = digits2(v); + *out_++ = *d++; + *out_++ = *d; + } else { + out_ = detail::write_padding(out_, pad); + *out_++ = static_cast('0' + v); + } + } + + void write_year_extended(long long year, pad_type pad) { + // At least 4 characters. + int width = 4; + bool negative = year < 0; + if (negative) { + year = 0 - year; + --width; + } + uint32_or_64_or_128_t n = to_unsigned(year); + const int num_digits = count_digits(n); + if (negative && pad == pad_type::zero) *out_++ = '-'; + if (width > num_digits) { + out_ = detail::write_padding(out_, pad, width - num_digits); + } + if (negative && pad != pad_type::zero) *out_++ = '-'; + out_ = format_decimal(out_, n, num_digits); + } + void write_year(long long year, pad_type pad) { + write_year_extended(year, pad); + } + + void write_utc_offset(long long offset, numeric_system ns) { + if (offset < 0) { + *out_++ = '-'; + offset = -offset; + } else { + *out_++ = '+'; + } + offset /= 60; + write2(static_cast(offset / 60)); + if (ns != numeric_system::standard) *out_++ = ':'; + write2(static_cast(offset % 60)); + } + + template ::value)> + void format_utc_offset_impl(const T& tm, numeric_system ns) { + write_utc_offset(tm.tm_gmtoff, ns); + } + template ::value)> + void format_utc_offset_impl(const T& tm, numeric_system ns) { +#if defined(_WIN32) && defined(_UCRT) + tzset_once(); + long offset = 0; + _get_timezone(&offset); + if (tm.tm_isdst) { + long dstbias = 0; + _get_dstbias(&dstbias); + offset += dstbias; + } + write_utc_offset(-offset, ns); +#else + if (ns == numeric_system::standard) return format_localized('z'); + + // Extract timezone offset from timezone conversion functions. + std::tm gtm = tm; + std::time_t gt = std::mktime(>m); + std::tm ltm = gmtime(gt); + std::time_t lt = std::mktime(<m); + long long offset = gt - lt; + write_utc_offset(offset, ns); +#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, + const Duration* subsecs = nullptr) + : loc_(loc), + is_classic_(loc_ == get_classic_locale()), + out_(out), + subsecs_(subsecs), + tm_(tm) {} + + auto out() const -> OutputIt { return out_; } + + FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { + out_ = copy(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(numeric_system::standard, pad_type::space); + *out_++ = ' '; + on_iso_time(); + *out_++ = ' '; + on_year(numeric_system::standard, pad_type::space); + } 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(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) { + write2digits(buf, static_cast(year / 100)); + } else { + offset = 4; + write_year_extended(year, pad_type::zero); + year = 0; + } + write_digit2_separated(buf + 2, static_cast(year % 100), + to_unsigned(tm_mon() + 1), to_unsigned(tm_mday()), + '-'); + out_ = copy(std::begin(buf) + offset, std::end(buf), out_); + } + + void on_utc_offset(numeric_system ns) { format_utc_offset_impl(tm_, ns); } + void on_tz_name() { format_tz_name_impl(tm_); } + + void on_year(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write_year(tm_year(), pad); + 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, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_mon() + 1, pad); + format_localized('m', 'O'); + } + + void on_dec0_week_of_year(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week, + pad); + format_localized('U', 'O'); + } + void on_dec1_week_of_year(numeric_system ns, pad_type pad) { + 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, + pad); + } else { + format_localized('W', 'O'); + } + } + void on_iso_week_of_year(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_iso_week_of_year(), pad); + format_localized('V', 'O'); + } + + void on_iso_week_based_year() { + write_year(tm_iso_week_year(), pad_type::zero); + } + void on_iso_week_based_short_year() { + write2(split_year_lower(tm_iso_week_year())); + } + + void on_day_of_year(pad_type pad) { + auto yday = tm_yday() + 1; + auto digit1 = yday / 100; + if (digit1 != 0) { + write1(digit1); + } else { + out_ = detail::write_padding(out_, pad); + } + write2(yday % 100, pad); + } + + void on_day_of_month(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_mday(), pad); + format_localized('d', 'O'); + } + + void on_24_hour(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_hour(), pad); + format_localized('H', 'O'); + } + void on_12_hour(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_hour12(), pad); + format_localized('I', 'O'); + } + void on_minute(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_min(), pad); + format_localized('M', 'O'); + } + + void on_second(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) { + write2(tm_sec(), pad); + if (subsecs_) { + if (std::is_floating_point::value) { + auto buf = memory_buffer(); + write_floating_seconds(buf, *subsecs_); + if (buf.size() > 1) { + // Remove the leading "0", write something like ".123". + out_ = copy(buf.begin() + 1, buf.end(), out_); + } + } else { + write_fractional_seconds(out_, *subsecs_); + } + } + } else { + // Currently no formatting of subseconds when a locale is set. + 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(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() { + on_24_hour_time(); + *out_++ = ':'; + on_second(numeric_system::standard, pad_type::zero); + } + + 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 { + bool has_precision_integral = false; + + FMT_NORETURN inline void unsupported() { FMT_THROW(format_error("no date")); } + + template + FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + FMT_CONSTEXPR void on_day_of_year(pad_type) {} + FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_minute(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_second(numeric_system, pad_type) {} + 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() const { + if (has_precision_integral) + FMT_THROW(format_error("precision not allowed for this argument type")); + } + FMT_CONSTEXPR void on_duration_unit() {} +}; + +template ::value&& has_isfinite::value)> +inline auto isfinite(T) -> bool { + return true; +} + +template ::value)> +inline auto mod(T x, int y) -> T { + return x % static_cast(y); +} +template ::value)> +inline auto mod(T x, int y) -> T { + 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; +}; + +template ::value)> +inline auto get_milliseconds(std::chrono::duration d) + -> std::chrono::duration { + // 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 = detail::duration_cast(d); + const auto d_as_whole_seconds = + detail::duration_cast(d_as_common); + // this conversion should be nonproblematic + const auto diff = d_as_common - d_as_whole_seconds; + const auto ms = + detail::duration_cast>(diff); + return ms; +#else + auto s = detail::duration_cast(d); + return detail::duration_cast(d - s); +#endif +} + +template ::value)> +auto format_duration_value(OutputIt out, Rep val, int) -> OutputIt { + return write(out, val); +} + +template ::value)> +auto format_duration_value(OutputIt out, Rep val, int precision) -> OutputIt { + auto specs = format_specs(); + specs.precision = precision; + specs.set_type(precision >= 0 ? presentation_type::fixed + : presentation_type::general); + return write(out, val, specs); +} + +template +auto copy_unit(string_view unit, OutputIt out, Char) -> OutputIt { + return copy(unit.begin(), unit.end(), out); +} + +template +auto copy_unit(string_view unit, OutputIt out, wchar_t) -> OutputIt { + // 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 copy(u.c_str(), u.c_str() + u.size(), out); +} + +template +auto format_duration_unit(OutputIt out) -> OutputIt { + 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: + inline get_locale(bool localized, locale_ref loc) : has_locale_(localized) { + if (localized) + ::new (&locale_) std::locale(loc.template get()); + } + inline ~get_locale() { + if (has_locale_) locale_.~locale(); + } + inline 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. + // might need checked conversion (rep!=Rep) + s = detail::duration_cast(std::chrono::duration(val)); + } + + // returns true if nan or inf, writes to out. + auto handle_nan_inf() -> bool { + 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; + } + + auto days() const -> Rep { return static_cast(s.count() / 86400); } + auto hour() const -> Rep { + return static_cast(mod((s.count() / 3600), 24)); + } + + auto hour12() const -> Rep { + Rep hour = static_cast(mod((s.count() / 3600), 12)); + return hour <= 0 ? 12 : hour; + } + + auto minute() const -> Rep { + return static_cast(mod((s.count() / 60), 60)); + } + auto second() const -> Rep { return static_cast(mod(s.count(), 60)); } + + auto time() const -> std::tm { + 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, pad_type pad = pad_type::zero) { + 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 = detail::write_padding(out, pad, width - num_digits); + } + out = format_decimal(out, n, num_digits); + } + + 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) { + 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(numeric_system) {} + void on_tz_name() {} + void on_year(numeric_system, pad_type) {} + 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, pad_type) {} + void on_dec0_week_of_year(numeric_system, pad_type) {} + void on_dec1_week_of_year(numeric_system, pad_type) {} + void on_iso_week_of_year(numeric_system, pad_type) {} + void on_day_of_month(numeric_system, pad_type) {} + + void on_day_of_year(pad_type) { + if (handle_nan_inf()) return; + write(days(), 0); + } + + void on_24_hour(numeric_system ns, pad_type pad) { + if (handle_nan_inf()) return; + + if (ns == numeric_system::standard) return write(hour(), 2, pad); + auto time = tm(); + time.tm_hour = to_nonnegative_int(hour(), 24); + format_tm(time, &tm_writer_type::on_24_hour, ns, pad); + } + + void on_12_hour(numeric_system ns, pad_type pad) { + if (handle_nan_inf()) return; + + if (ns == numeric_system::standard) return write(hour12(), 2, pad); + auto time = tm(); + time.tm_hour = to_nonnegative_int(hour12(), 12); + format_tm(time, &tm_writer_type::on_12_hour, ns, pad); + } + + void on_minute(numeric_system ns, pad_type pad) { + if (handle_nan_inf()) return; + + if (ns == numeric_system::standard) return write(minute(), 2, pad); + auto time = tm(); + time.tm_min = to_nonnegative_int(minute(), 60); + format_tm(time, &tm_writer_type::on_minute, ns, pad); + } + + void on_second(numeric_system ns, pad_type pad) { + if (handle_nan_inf()) return; + + if (ns == numeric_system::standard) { + if (std::is_floating_point::value) { + auto buf = memory_buffer(); + write_floating_seconds(buf, std::chrono::duration(val), + precision); + if (negative) *out++ = '-'; + if (buf.size() < 2 || buf[1] == '.') { + out = detail::write_padding(out, pad); + } + out = copy(buf.begin(), buf.end(), out); + } else { + write(second(), 2, pad); + write_fractional_seconds( + out, std::chrono::duration(val), precision); + } + return; + } + auto time = tm(); + time.tm_sec = to_nonnegative_int(second(), 60); + format_tm(time, &tm_writer_type::on_second, ns, pad); + } + + 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, pad_type::zero); + } + + 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); + } +}; + +} // namespace detail + +#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907 +using weekday = std::chrono::weekday; +using day = std::chrono::day; +using month = std::chrono::month; +using year = std::chrono::year; +using year_month_day = std::chrono::year_month_day; +#else +// A fallback version of weekday. +class weekday { + private: + unsigned char value_; + + public: + weekday() = default; + constexpr explicit weekday(unsigned wd) noexcept + : value_(static_cast(wd != 7 ? wd : 0)) {} + constexpr auto c_encoding() const noexcept -> unsigned { return value_; } +}; + +class day { + private: + unsigned char value_; + + public: + day() = default; + constexpr explicit day(unsigned d) noexcept + : value_(static_cast(d)) {} + constexpr explicit operator unsigned() const noexcept { return value_; } +}; + +class month { + private: + unsigned char value_; + + public: + month() = default; + constexpr explicit month(unsigned m) noexcept + : value_(static_cast(m)) {} + constexpr explicit operator unsigned() const noexcept { return value_; } +}; + +class year { + private: + int value_; + + public: + year() = default; + constexpr explicit year(int y) noexcept : value_(y) {} + constexpr explicit operator int() const noexcept { return value_; } +}; + +class year_month_day { + private: + fmt::year year_; + fmt::month month_; + fmt::day day_; + + public: + year_month_day() = default; + constexpr year_month_day(const year& y, const month& m, const day& d) noexcept + : year_(y), month_(m), day_(d) {} + constexpr auto year() const noexcept -> fmt::year { return year_; } + constexpr auto month() const noexcept -> fmt::month { return month_; } + constexpr auto day() const noexcept -> fmt::day { return day_; } +}; +#endif + +template +struct formatter : private formatter { + private: + bool localized_ = false; + bool use_tm_formatter_ = false; + + public: + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + auto it = ctx.begin(), end = ctx.end(); + if (it != end && *it == 'L') { + ++it; + localized_ = true; + return it; + } + use_tm_formatter_ = it != end && *it != '}'; + return use_tm_formatter_ ? formatter::parse(ctx) : it; + } + + template + auto format(weekday wd, FormatContext& ctx) const -> decltype(ctx.out()) { + auto time = std::tm(); + time.tm_wday = static_cast(wd.c_encoding()); + if (use_tm_formatter_) return formatter::format(time, ctx); + 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 : private formatter { + private: + bool use_tm_formatter_ = false; + + public: + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + auto it = ctx.begin(), end = ctx.end(); + use_tm_formatter_ = it != end && *it != '}'; + return use_tm_formatter_ ? formatter::parse(ctx) : it; + } + + template + auto format(day d, FormatContext& ctx) const -> decltype(ctx.out()) { + auto time = std::tm(); + time.tm_mday = static_cast(static_cast(d)); + if (use_tm_formatter_) return formatter::format(time, ctx); + detail::get_locale loc(false, ctx.locale()); + auto w = detail::tm_writer(loc, ctx.out(), time); + w.on_day_of_month(detail::numeric_system::standard, detail::pad_type::zero); + return w.out(); + } +}; + +template +struct formatter : private formatter { + private: + bool localized_ = false; + bool use_tm_formatter_ = false; + + public: + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + auto it = ctx.begin(), end = ctx.end(); + if (it != end && *it == 'L') { + ++it; + localized_ = true; + return it; + } + use_tm_formatter_ = it != end && *it != '}'; + return use_tm_formatter_ ? formatter::parse(ctx) : it; + } + + template + auto format(month m, FormatContext& ctx) const -> decltype(ctx.out()) { + auto time = std::tm(); + time.tm_mon = static_cast(static_cast(m)) - 1; + if (use_tm_formatter_) return formatter::format(time, ctx); + detail::get_locale loc(localized_, ctx.locale()); + auto w = detail::tm_writer(loc, ctx.out(), time); + w.on_abbr_month(); + return w.out(); + } +}; + +template +struct formatter : private formatter { + private: + bool use_tm_formatter_ = false; + + public: + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + auto it = ctx.begin(), end = ctx.end(); + use_tm_formatter_ = it != end && *it != '}'; + return use_tm_formatter_ ? formatter::parse(ctx) : it; + } + + template + auto format(year y, FormatContext& ctx) const -> decltype(ctx.out()) { + auto time = std::tm(); + time.tm_year = static_cast(y) - 1900; + if (use_tm_formatter_) return formatter::format(time, ctx); + detail::get_locale loc(false, ctx.locale()); + auto w = detail::tm_writer(loc, ctx.out(), time); + w.on_year(detail::numeric_system::standard, detail::pad_type::zero); + return w.out(); + } +}; + +template +struct formatter : private formatter { + private: + bool use_tm_formatter_ = false; + + public: + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + auto it = ctx.begin(), end = ctx.end(); + use_tm_formatter_ = it != end && *it != '}'; + return use_tm_formatter_ ? formatter::parse(ctx) : it; + } + + template + auto format(year_month_day val, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto time = std::tm(); + time.tm_year = static_cast(val.year()) - 1900; + time.tm_mon = static_cast(static_cast(val.month())) - 1; + time.tm_mday = static_cast(static_cast(val.day())); + if (use_tm_formatter_) return formatter::format(time, ctx); + detail::get_locale loc(true, ctx.locale()); + auto w = detail::tm_writer(loc, ctx.out(), time); + w.on_iso_date(); + return w.out(); + } +}; + +template +struct formatter, Char> { + private: + format_specs specs_; + detail::arg_ref width_ref_; + detail::arg_ref precision_ref_; + bool localized_ = false; + basic_string_view fmt_; + + public: + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + auto it = ctx.begin(), end = ctx.end(); + if (it == end || *it == '}') return it; + + it = detail::parse_align(it, end, specs_); + if (it == end) return it; + + Char c = *it; + if ((c >= '0' && c <= '9') || c == '{') { + it = detail::parse_width(it, end, specs_, width_ref_, ctx); + if (it == end) return it; + } + + auto checker = detail::chrono_format_checker(); + if (*it == '.') { + checker.has_precision_integral = !std::is_floating_point::value; + it = detail::parse_precision(it, end, specs_, precision_ref_, ctx); + } + if (it != end && *it == 'L') { + localized_ = true; + ++it; + } + end = detail::parse_chrono_format(it, end, checker); + fmt_ = {it, detail::to_unsigned(end - it)}; + return end; + } + + template + auto format(std::chrono::duration d, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto specs = specs_; + auto precision = specs.precision; + specs.precision = -1; + auto begin = fmt_.begin(), end = fmt_.end(); + // As a possible future optimization, we could avoid extra copying if width + // is not specified. + auto buf = basic_memory_buffer(); + auto out = basic_appender(buf); + detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_, + ctx); + detail::handle_dynamic_spec(specs.dynamic_precision(), precision, + precision_ref_, ctx); + if (begin == end || *begin == '}') { + out = detail::format_duration_value(out, d.count(), precision); + detail::format_duration_unit(out); + } else { + using chrono_formatter = + detail::chrono_formatter; + auto f = chrono_formatter(ctx, out, d); + f.precision = precision; + f.localized = localized_; + detail::parse_chrono_format(begin, end, f); + } + return detail::write( + ctx.out(), basic_string_view(buf.data(), buf.size()), specs); + } +}; + +template struct formatter { + private: + format_specs specs_; + detail::arg_ref width_ref_; + + protected: + basic_string_view fmt_; + + template + auto do_format(const std::tm& tm, FormatContext& ctx, + const Duration* subsecs) const -> decltype(ctx.out()) { + auto specs = specs_; + auto buf = basic_memory_buffer(); + auto out = basic_appender(buf); + detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_, + ctx); + + auto loc_ref = ctx.locale(); + detail::get_locale loc(static_cast(loc_ref), loc_ref); + auto w = + detail::tm_writer(loc, out, tm, subsecs); + detail::parse_chrono_format(fmt_.begin(), fmt_.end(), w); + return detail::write( + ctx.out(), basic_string_view(buf.data(), buf.size()), specs); + } + + public: + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + auto it = ctx.begin(), end = ctx.end(); + if (it == end || *it == '}') return it; + + it = detail::parse_align(it, end, specs_); + if (it == end) return it; + + Char c = *it; + if ((c >= '0' && c <= '9') || c == '{') { + it = detail::parse_width(it, end, specs_, width_ref_, ctx); + if (it == end) return it; + } + + end = detail::parse_chrono_format(it, end, detail::tm_format_checker()); + // Replace the default format string only if the new spec is not empty. + if (end != it) fmt_ = {it, detail::to_unsigned(end - it)}; + return end; + } + + template + auto format(const std::tm& tm, FormatContext& ctx) const + -> decltype(ctx.out()) { + return do_format(tm, ctx, nullptr); + } +}; + +template +struct formatter, Char> : formatter { + FMT_CONSTEXPR formatter() { + this->fmt_ = detail::string_literal(); + } + + template + auto format(sys_time val, FormatContext& ctx) const + -> decltype(ctx.out()) { + std::tm tm = gmtime(val); + using period = typename Duration::period; + if (detail::const_check( + period::num == 1 && period::den == 1 && + !std::is_floating_point::value)) { + return formatter::format(tm, ctx); + } + Duration epoch = val.time_since_epoch(); + Duration subsecs = detail::duration_cast( + epoch - detail::duration_cast(epoch)); + if (subsecs.count() < 0) { + auto second = detail::duration_cast(std::chrono::seconds(1)); + if (tm.tm_sec != 0) + --tm.tm_sec; + else + tm = gmtime(val - second); + subsecs += detail::duration_cast(std::chrono::seconds(1)); + } + return formatter::do_format(tm, ctx, &subsecs); + } +}; + +template +struct formatter, Char> + : formatter, Char> { + template + auto format(utc_time val, FormatContext& ctx) const + -> decltype(ctx.out()) { + return formatter, Char>::format( + detail::utc_clock::to_sys(val), ctx); + } +}; + +template +struct formatter, Char> : formatter { + FMT_CONSTEXPR formatter() { + this->fmt_ = detail::string_literal(); + } + + template + auto format(local_time val, FormatContext& ctx) const + -> decltype(ctx.out()) { + using period = typename Duration::period; + if (period::num == 1 && period::den == 1 && + !std::is_floating_point::value) { + return formatter::format(localtime(val), ctx); + } + auto epoch = val.time_since_epoch(); + auto subsecs = detail::duration_cast( + epoch - detail::duration_cast(epoch)); + return formatter::do_format(localtime(val), ctx, &subsecs); + } +}; + +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_CHRONO_H_ diff --git a/include/fmt/color.h b/include/fmt/color.h new file mode 100644 index 0000000..2faaf3a --- /dev/null +++ b/include/fmt/color.h @@ -0,0 +1,610 @@ +// 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" + +FMT_BEGIN_NAMESPACE +FMT_BEGIN_EXPORT + +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; +}; + +namespace detail { + +// color is a struct of either a rgb color or a terminal color. +struct color_type { + FMT_CONSTEXPR color_type() noexcept : is_rgb(), value{} {} + FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} { + value.rgb_color = static_cast(rgb_color); + } + FMT_CONSTEXPR color_type(rgb rgb_color) 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) 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; +}; +} // namespace detail + +/// A text style consisting of foreground and background colors and emphasis. +class text_style { + public: + FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept + : set_foreground_color(), set_background_color(), ems(em) {} + + FMT_CONSTEXPR auto operator|=(const text_style& rhs) -> text_style& { + 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) + report_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) + report_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 auto operator|(text_style lhs, const text_style& rhs) + -> text_style { + return lhs |= rhs; + } + + FMT_CONSTEXPR auto has_foreground() const noexcept -> bool { + return set_foreground_color; + } + FMT_CONSTEXPR auto has_background() const noexcept -> bool { + return set_background_color; + } + FMT_CONSTEXPR auto has_emphasis() const noexcept -> bool { + return static_cast(ems) != 0; + } + FMT_CONSTEXPR auto get_foreground() const noexcept -> detail::color_type { + FMT_ASSERT(has_foreground(), "no foreground specified for this style"); + return foreground_color; + } + FMT_CONSTEXPR auto get_background() const noexcept -> detail::color_type { + FMT_ASSERT(has_background(), "no background specified for this style"); + return background_color; + } + FMT_CONSTEXPR auto get_emphasis() const noexcept -> emphasis { + 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) 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; + } + } + + friend FMT_CONSTEXPR auto fg(detail::color_type foreground) noexcept + -> text_style; + + friend FMT_CONSTEXPR auto bg(detail::color_type background) noexcept + -> text_style; + + 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 auto fg(detail::color_type foreground) noexcept + -> text_style { + return text_style(true, foreground); +} + +/// Creates a text style from the background color. +FMT_CONSTEXPR inline auto bg(detail::color_type background) noexcept + -> text_style { + return text_style(false, background); +} + +FMT_CONSTEXPR inline auto operator|(emphasis lhs, emphasis rhs) noexcept + -> text_style { + return text_style(lhs) | rhs; +} + +namespace detail { + +template struct ansi_color_escape { + FMT_CONSTEXPR ansi_color_escape(color_type text_color, + const char* esc) 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) 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 noexcept { return buffer; } + + FMT_CONSTEXPR auto begin() const noexcept -> const Char* { return buffer; } + FMT_CONSTEXPR20 auto end() const noexcept -> const Char* { + return buffer + basic_string_view(buffer).size(); + } + + 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) 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 auto has_emphasis(emphasis em, emphasis mask) noexcept + -> bool { + return static_cast(em) & static_cast(mask); + } +}; + +template +FMT_CONSTEXPR auto make_foreground_color(color_type foreground) noexcept + -> ansi_color_escape { + return ansi_color_escape(foreground, "\x1b[38;2;"); +} + +template +FMT_CONSTEXPR auto make_background_color(color_type background) noexcept + -> ansi_color_escape { + return ansi_color_escape(background, "\x1b[48;2;"); +} + +template +FMT_CONSTEXPR auto make_emphasis(emphasis em) noexcept + -> ansi_color_escape { + return ansi_color_escape(em); +} + +template inline void reset_color(buffer& buffer) { + auto reset_color = string_view("\x1b[0m"); + buffer.append(reset_color.begin(), reset_color.end()); +} + +template struct styled_arg : view { + const T& value; + text_style style; + styled_arg(const T& v, text_style s) : value(v), style(s) {} +}; + +template +void vformat_to(buffer& buf, const text_style& ts, + basic_string_view fmt, + basic_format_args> args) { + bool has_style = false; + if (ts.has_emphasis()) { + has_style = true; + auto emphasis = make_emphasis(ts.get_emphasis()); + buf.append(emphasis.begin(), emphasis.end()); + } + if (ts.has_foreground()) { + has_style = true; + auto foreground = make_foreground_color(ts.get_foreground()); + buf.append(foreground.begin(), foreground.end()); + } + if (ts.has_background()) { + has_style = true; + auto background = make_background_color(ts.get_background()); + buf.append(background.begin(), background.end()); + } + vformat_to(buf, fmt, args); + if (has_style) reset_color(buf); +} +} // namespace detail + +inline void vprint(FILE* f, const text_style& ts, string_view fmt, + format_args args) { + auto buf = memory_buffer(); + detail::vformat_to(buf, ts, fmt, args); + print(f, FMT_STRING("{}"), string_view(buf.begin(), buf.size())); +} + +/** + * 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); + */ +template +void print(FILE* f, const text_style& ts, format_string fmt, + T&&... args) { + vprint(f, ts, fmt.str, vargs{{args...}}); +} + +/** + * 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); + */ +template +void print(const text_style& ts, format_string fmt, T&&... args) { + return print(stdout, ts, fmt, std::forward(args)...); +} + +inline auto vformat(const text_style& ts, string_view fmt, format_args args) + -> std::string { + auto buf = memory_buffer(); + detail::vformat_to(buf, ts, fmt, args); + return fmt::to_string(buf); +} + +/** + * 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); + * ``` + */ +template +inline auto format(const text_style& ts, format_string fmt, T&&... args) + -> std::string { + return fmt::vformat(ts, fmt.str, vargs{{args...}}); +} + +/// Formats a string with the given text_style and writes the output to `out`. +template ::value)> +auto vformat_to(OutputIt out, const text_style& ts, string_view fmt, + format_args args) -> OutputIt { + auto&& buf = detail::get_buffer(out); + detail::vformat_to(buf, ts, fmt, args); + return detail::get_iterator(buf, out); +} + +/** + * 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); + */ +template ::value)> +inline auto format_to(OutputIt out, const text_style& ts, + format_string fmt, T&&... args) -> OutputIt { + return vformat_to(out, ts, fmt.str, vargs{{args...}}); +} + +template +struct formatter, Char> : formatter { + template + auto format(const detail::styled_arg& arg, FormatContext& ctx) const + -> decltype(ctx.out()) { + const auto& ts = arg.style; + auto out = ctx.out(); + + bool has_style = false; + if (ts.has_emphasis()) { + has_style = true; + auto emphasis = detail::make_emphasis(ts.get_emphasis()); + out = detail::copy(emphasis.begin(), emphasis.end(), out); + } + if (ts.has_foreground()) { + has_style = true; + auto foreground = + detail::make_foreground_color(ts.get_foreground()); + out = detail::copy(foreground.begin(), foreground.end(), out); + } + if (ts.has_background()) { + has_style = true; + auto background = + detail::make_background_color(ts.get_background()); + out = detail::copy(background.begin(), background.end(), out); + } + out = formatter::format(arg.value, ctx); + if (has_style) { + auto reset_color = string_view("\x1b[0m"); + out = detail::copy(reset_color.begin(), reset_color.end(), out); + } + return out; + } +}; + +/** + * Returns an argument that will be formatted using ANSI escape sequences, + * to be used in a formatting function. + * + * **Example**: + * + * fmt::print("Elapsed time: {0:.2f} seconds", + * fmt::styled(1.23, fmt::fg(fmt::color::green) | + * fmt::bg(fmt::color::blue))); + */ +template +FMT_CONSTEXPR auto styled(const T& value, text_style ts) + -> detail::styled_arg> { + return detail::styled_arg>{value, ts}; +} + +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_COLOR_H_ diff --git a/include/fmt/compile.h b/include/fmt/compile.h new file mode 100644 index 0000000..68b451c --- /dev/null +++ b/include/fmt/compile.h @@ -0,0 +1,551 @@ +// 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_ + +#ifndef FMT_MODULE +# include // std::back_inserter +#endif + +#include "format.h" + +FMT_BEGIN_NAMESPACE + +// A compile-time string which is compiled into fast formatting code. +FMT_EXPORT class compiled_string {}; + +namespace detail { + +template +struct is_compiled_string : std::is_base_of {}; + +/** + * 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); + */ +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) +# define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::compiled_string) +#else +# define FMT_COMPILE(s) FMT_STRING(s) +#endif + +#if FMT_USE_NONTYPE_TEMPLATE_ARGS +template Str> +struct udl_compiled_string : compiled_string { + using char_type = Char; + constexpr explicit operator basic_string_view() const { + return {Str.data, N - 1}; + } +}; +#endif + +template +auto first(const T& value, const Tail&...) -> const T& { + 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...); +} + +# if FMT_USE_NONTYPE_TEMPLATE_ARGS +template +constexpr auto get_arg_index_by_name(basic_string_view name) -> int { + if constexpr (is_static_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 -1; +} +# endif + +template +FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view name) -> int { +# if FMT_USE_NONTYPE_TEMPLATE_ARGS + if constexpr (sizeof...(Args) > 0) + return get_arg_index_by_name<0, Args...>(name); +# endif + (void)name; + return -1; +} + +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 { + *out++ = value; + return out; + } +}; + +// 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 { + const T& arg = get_arg_checked(args...); + if constexpr (std::is_convertible>::value) { + auto s = basic_string_view(arg); + return copy(s.begin(), s.end(), out); + } else { + return write(out, arg); + } + } +}; + +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 fmt); + +template +constexpr auto parse_tail(T head, S fmt) { + if constexpr (POS != basic_string_view(fmt).size()) { + constexpr auto tail = compile_format_string(fmt); + 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; +}; + +enum { 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 = + compile_parse_context(str, max_value(), nullptr, next_arg_id); + auto f = formatter(); + auto end = f.parse(ctx); + return {f, pos + fmt::detail::to_unsigned(end - str.data()), + next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()}; +} + +template struct arg_id_handler { + arg_id_kind kind; + arg_ref arg_id; + + constexpr int on_auto() { + FMT_ASSERT(false, "handler cannot be used with automatic indexing"); + return 0; + } + constexpr int on_index(int id) { + kind = arg_id_kind::index; + arg_id = arg_ref(id); + return 0; + } + constexpr int on_name(basic_string_view id) { + kind = arg_id_kind::name; + arg_id = arg_ref(id); + return 0; + } +}; + +template struct parse_arg_id_result { + arg_id_kind kind; + 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_id_kind::none, arg_ref{}}; + auto arg_id_end = parse_arg_id(begin, end, handler); + return parse_arg_id_result{handler.kind, 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 fmt) { + using char_type = typename S::char_type; + constexpr auto str = basic_string_view(fmt); + constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type(); + if constexpr (c == '}') { + return parse_tail( + field::type, ARG_INDEX>(), fmt); + } else if constexpr (c != ':') { + FMT_THROW(format_error("expected ':'")); + } else { + constexpr auto result = parse_specs::type>( + str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID); + if constexpr (result.end >= str.size() || str[result.end] != '}') { + FMT_THROW(format_error("expected '}'")); + return 0; + } else { + return parse_tail( + spec_field::type, ARG_INDEX>{ + result.fmt}, + fmt); + } + } +} + +// Compiles a non-empty format string and returns the compiled representation +// or unknown_format() on unrecognized input. +template +constexpr auto compile_format_string(S fmt) { + using char_type = typename S::char_type; + constexpr auto str = basic_string_view(fmt); + 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), fmt); + } 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>(fmt); + } 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.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.index; + return parse_replacement_field_then_tail, + Args, arg_id_end_pos, + arg_index, manual_indexing_id>( + fmt); + } else if constexpr (arg_id_result.kind == arg_id_kind::name) { + constexpr auto arg_index = + get_arg_index_by_name(arg_id_result.arg_id.name, Args{}); + if constexpr (arg_index >= 0) { + 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>(fmt); + } else if constexpr (c == '}') { + return parse_tail( + runtime_named_field{arg_id_result.arg_id.name}, fmt); + } 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), fmt); + } else { + constexpr auto end = parse_text(str, POS + 1); + if constexpr (end - POS > 1) { + return parse_tail(make_text(str, POS, end - POS), fmt); + } else { + return parse_tail(code_unit{str[POS]}, fmt); + } + } +} + +template ::value)> +constexpr auto compile(S fmt) { + constexpr auto str = basic_string_view(fmt); + if constexpr (str.size() == 0) { + return detail::make_text(str, 0, 0); + } else { + constexpr auto result = + detail::compile_format_string, 0, 0>(fmt); + return result; + } +} +#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) +} // namespace detail + +FMT_BEGIN_EXPORT + +#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 fmt::format( + static_cast>(S()), + std::forward(args)...); + } else { + return fmt::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 fmt::format_to( + out, static_cast>(S()), + std::forward(args)...); + } else { + return fmt::format_to(out, compiled, std::forward(args)...); + } +} +#endif + +template ::value)> +auto format_to_n(OutputIt out, size_t n, const S& fmt, Args&&... args) + -> format_to_n_result { + using traits = detail::fixed_buffer_traits; + auto buf = detail::iterator_buffer(out, n); + fmt::format_to(std::back_inserter(buf), fmt, std::forward(args)...); + return {buf.out(), buf.count()}; +} + +template ::value)> +FMT_CONSTEXPR20 auto formatted_size(const S& fmt, const Args&... args) + -> size_t { + auto buf = detail::counting_buffer<>(); + fmt::format_to(appender(buf), fmt, args...); + return buf.count(); +} + +template ::value)> +void print(std::FILE* f, const S& fmt, const Args&... args) { + auto buf = memory_buffer(); + fmt::format_to(appender(buf), fmt, args...); + detail::print(f, {buf.data(), buf.size()}); +} + +template ::value)> +void print(const S& fmt, const Args&... args) { + print(stdout, fmt, args...); +} + +#if FMT_USE_NONTYPE_TEMPLATE_ARGS +inline namespace literals { +template constexpr auto operator""_cf() { + using char_t = remove_cvref_t; + return detail::udl_compiled_string(); +} +} // namespace literals +#endif + +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_COMPILE_H_ diff --git a/include/fmt/core.h b/include/fmt/core.h new file mode 100644 index 0000000..8ca735f --- /dev/null +++ b/include/fmt/core.h @@ -0,0 +1,5 @@ +// This file is only provided for compatibility and may be removed in future +// versions. Use fmt/base.h if you don't need fmt::format and fmt/format.h +// otherwise. + +#include "format.h" diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h new file mode 100644 index 0000000..a5b79db --- /dev/null +++ b/include/fmt/format-inl.h @@ -0,0 +1,1949 @@ +// 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_ + +#ifndef FMT_MODULE +# include +# include // errno +# include +# include +# include +#endif + +#if defined(_WIN32) && !defined(FMT_USE_WRITE_CONSOLE) +# include // _isatty +#endif + +#include "format.h" + +#if FMT_USE_LOCALE +# include +#endif + +#ifndef FMT_FUNC +# define FMT_FUNC +#endif + +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. + fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message); + abort(); +} + +FMT_FUNC void format_error_code(detail::buffer& out, int error_code, + string_view message) 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 = appender(out); + if (message.size() <= inline_buffer_size - error_code_size) + fmt::format_to(it, FMT_STRING("{}{}"), message, SEP); + fmt::format_to(it, FMT_STRING("{}{}"), ERROR_STR, error_code); + FMT_ASSERT(out.size() <= inline_buffer_size, ""); +} + +FMT_FUNC void do_report_error(format_func func, int error_code, + const char* message) noexcept { + memory_buffer full_message; + func(full_message, error_code, message); + // Don't use fwrite_all 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_all(const void* ptr, size_t count, FILE* stream) { + size_t written = std::fwrite(ptr, 1, count, stream); + if (written < count) + FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); +} + +#if FMT_USE_LOCALE +using std::locale; +using std::numpunct; +using std::use_facet; + +template +locale_ref::locale_ref(const Locale& loc) : locale_(&loc) { + static_assert(std::is_same::value, ""); +} +#else +struct locale {}; +template struct numpunct { + auto grouping() const -> std::string { return "\03"; } + auto thousands_sep() const -> Char { return ','; } + auto decimal_point() const -> Char { return '.'; } +}; +template Facet use_facet(locale) { return {}; } +#endif // FMT_USE_LOCALE + +template auto locale_ref::get() const -> Locale { + static_assert(std::is_same::value, ""); +#if FMT_USE_LOCALE + if (locale_) return *static_cast(locale_); +#endif + return locale(); +} + +template +FMT_FUNC auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result { + auto&& facet = 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 auto decimal_point_impl(locale_ref loc) -> Char { + return use_facet>(loc.get()).decimal_point(); +} + +#if FMT_USE_LOCALE +FMT_FUNC auto write_loc(appender out, loc_value value, + const format_specs& specs, locale_ref loc) -> bool { + auto locale = loc.get(); + // We cannot use the num_put facet because it may produce output in + // a wrong encoding. + using facet = format_facet; + if (std::has_facet(locale)) + return use_facet(locale).put(out, value, specs); + return facet(locale).put(out, value, specs); +} +#endif +} // namespace detail + +FMT_FUNC void report_error(const char* message) { +#if FMT_USE_EXCEPTIONS + // Use FMT_THROW instead of throw to avoid bogus unreachable code warnings + // from MSVC. + FMT_THROW(format_error(message)); +#else + fputs(message, stderr); + abort(); +#endif +} + +template typename Locale::id format_facet::id; + +template format_facet::format_facet(Locale& loc) { + auto& np = detail::use_facet>(loc); + grouping_ = np.grouping(); + if (!grouping_.empty()) separator_ = std::string(1, np.thousands_sep()); +} + +#if FMT_USE_LOCALE +template <> +FMT_API FMT_FUNC auto format_facet::do_put( + appender out, loc_value val, const format_specs& specs) const -> bool { + return val.visit( + detail::loc_writer<>{out, specs, separator_, grouping_, decimal_point_}); +} +#endif + +FMT_FUNC auto vsystem_error(int error_code, string_view fmt, format_args args) + -> std::system_error { + auto ec = std::error_code(error_code, std::generic_category()); + return std::system_error(ec, vformat(fmt, args)); +} + +namespace detail { + +template +inline auto operator==(basic_fp x, basic_fp y) -> bool { + return x.f == y.f && x.e == y.e; +} + +// Compilers should be able to optimize this into the ror instruction. +FMT_CONSTEXPR inline auto rotr(uint32_t n, uint32_t r) noexcept -> uint32_t { + r &= 31; + return (n >> r) | (n << (32 - r)); +} +FMT_CONSTEXPR inline auto rotr(uint64_t n, uint32_t r) noexcept -> uint64_t { + r &= 63; + return (n >> r) | (n << (64 - r)); +} + +// Implementation of Dragonbox algorithm: https://github.com/jk-jeon/dragonbox. +namespace dragonbox { +// Computes upper 64 bits of multiplication of a 32-bit unsigned integer and a +// 64-bit unsigned integer. +inline auto umul96_upper64(uint32_t x, uint64_t y) noexcept -> uint64_t { + return umul128_upper64(static_cast(x) << 32, y); +} + +// Computes lower 128 bits of multiplication of a 64-bit unsigned integer and a +// 128-bit unsigned integer. +inline auto umul192_lower128(uint64_t x, uint128_fallback y) noexcept + -> uint128_fallback { + uint64_t high = x * y.high(); + uint128_fallback high_low = umul128(x, y.low()); + return {high + high_low.high(), high_low.low()}; +} + +// Computes lower 64 bits of multiplication of a 32-bit unsigned integer and a +// 64-bit unsigned integer. +inline auto umul96_lower64(uint32_t x, uint64_t y) noexcept -> uint64_t { + return x * y; +} + +// Various fast log computations. +inline auto floor_log10_pow2_minus_log10_4_over_3(int e) noexcept -> int { + FMT_ASSERT(e <= 2936 && e >= -2985, "too large exponent"); + return (e * 631305 - 261663) >> 21; +} + +FMT_INLINE_VARIABLE constexpr struct { + uint32_t divisor; + int shift_amount; +} div_small_pow10_infos[] = {{10, 16}, {100, 16}}; + +// Replaces n by floor(n / pow(10, N)) returning true if and only if n is +// divisible by pow(10, N). +// Precondition: n <= pow(10, N + 1). +template +auto check_divisibility_and_divide_by_pow10(uint32_t& n) noexcept -> bool { + // The numbers below are chosen such that: + // 1. floor(n/d) = floor(nm / 2^k) where d=10 or d=100, + // 2. nm mod 2^k < m if and only if n is divisible by d, + // where m is magic_number, k is shift_amount + // and d is divisor. + // + // Item 1 is a common technique of replacing division by a constant with + // multiplication, see e.g. "Division by Invariant Integers Using + // Multiplication" by Granlund and Montgomery (1994). magic_number (m) is set + // to ceil(2^k/d) for large enough k. + // The idea for item 2 originates from Schubfach. + constexpr auto info = div_small_pow10_infos[N - 1]; + FMT_ASSERT(n <= info.divisor * 10, "n is too large"); + constexpr uint32_t magic_number = + (1u << info.shift_amount) / info.divisor + 1; + n *= magic_number; + const uint32_t comparison_mask = (1u << info.shift_amount) - 1; + bool result = (n & comparison_mask) < magic_number; + n >>= info.shift_amount; + return result; +} + +// Computes floor(n / pow(10, N)) for small n and N. +// Precondition: n <= pow(10, N + 1). +template auto small_division_by_pow10(uint32_t n) noexcept -> uint32_t { + constexpr auto info = div_small_pow10_infos[N - 1]; + FMT_ASSERT(n <= info.divisor * 10, "n is too large"); + constexpr uint32_t magic_number = + (1u << info.shift_amount) / info.divisor + 1; + return (n * magic_number) >> info.shift_amount; +} + +// Computes floor(n / 10^(kappa + 1)) (float) +inline auto divide_by_10_to_kappa_plus_1(uint32_t n) noexcept -> uint32_t { + // 1374389535 = ceil(2^37/100) + return static_cast((static_cast(n) * 1374389535) >> 37); +} +// Computes floor(n / 10^(kappa + 1)) (double) +inline auto divide_by_10_to_kappa_plus_1(uint64_t n) noexcept -> uint64_t { + // 2361183241434822607 = ceil(2^(64+7)/1000) + return umul128_upper64(n, 2361183241434822607ull) >> 7; +} + +// 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 auto get_cached_power(int k) noexcept -> uint64_t { + 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, 0x813f3978f8940985, + 0xa18f07d736b90be6, 0xc9f2c9cd04674edf, 0xfc6f7c4045812297, + 0x9dc5ada82b70b59e, 0xc5371912364ce306, 0xf684df56c3e01bc7, + 0x9a130b963a6c115d, 0xc097ce7bc90715b4, 0xf0bdc21abb48db21, + 0x96769950b50d88f5, 0xbc143fa4e250eb32, 0xeb194f8e1ae525fe, + 0x92efd1b8d0cf37bf, 0xb7abc627050305ae, 0xe596b7b0c643c71a, + 0x8f7e32ce7bea5c70, 0xb35dbf821ae4f38c, 0xe0352f62a19e306f}; + return pow10_significands[k - float_info::min_k]; + } + + struct compute_mul_result { + carrier_uint result; + bool is_integer; + }; + struct compute_mul_parity_result { + bool parity; + bool is_integer; + }; + + static auto compute_mul(carrier_uint u, + const cache_entry_type& cache) noexcept + -> compute_mul_result { + auto r = umul96_upper64(u, cache); + return {static_cast(r >> 32), + static_cast(r) == 0}; + } + + static auto compute_delta(const cache_entry_type& cache, int beta) noexcept + -> uint32_t { + return static_cast(cache >> (64 - 1 - beta)); + } + + static auto compute_mul_parity(carrier_uint two_f, + const cache_entry_type& cache, + int beta) noexcept + -> compute_mul_parity_result { + FMT_ASSERT(beta >= 1, ""); + FMT_ASSERT(beta < 64, ""); + + auto r = umul96_lower64(two_f, cache); + return {((r >> (64 - beta)) & 1) != 0, + static_cast(r >> (32 - beta)) == 0}; + } + + static auto compute_left_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return static_cast( + (cache - (cache >> (num_significand_bits() + 2))) >> + (64 - num_significand_bits() - 1 - beta)); + } + + static auto compute_right_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return static_cast( + (cache + (cache >> (num_significand_bits() + 1))) >> + (64 - num_significand_bits() - 1 - beta)); + } + + static auto compute_round_up_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return (static_cast( + cache >> (64 - num_significand_bits() - 2 - beta)) + + 1) / + 2; + } +}; + +template <> struct cache_accessor { + using carrier_uint = float_info::carrier_uint; + using cache_entry_type = uint128_fallback; + + static auto get_cached_power(int k) noexcept -> uint128_fallback { + FMT_ASSERT(k >= float_info::min_k && k <= float_info::max_k, + "k is out of range"); + + static constexpr const uint128_fallback 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, 0xbff8f10e7a8921a5}, + {0xa321f2d7226895c7, 0xaff72d52192b6a0e}, + {0xcbea6f8ceb02bb39, 0x9bf4f8a69f764491}, + {0xfee50b7025c36a08, 0x02f236d04753d5b5}, + {0x9f4f2726179a2245, 0x01d762422c946591}, + {0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef6}, + {0xf8ebad2b84e0d58b, 0xd2e0898765a7deb3}, + {0x9b934c3b330c8577, 0x63cc55f49f88eb30}, + {0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fc}, + {0xf316271c7fc3908a, 0x8bef464e3945ef7b}, + {0x97edd871cfda3a56, 0x97758bf0e3cbb5ad}, + {0xbde94e8e43d0c8ec, 0x3d52eeed1cbea318}, + {0xed63a231d4c4fb27, 0x4ca7aaa863ee4bde}, + {0x945e455f24fb1cf8, 0x8fe8caa93e74ef6b}, + {0xb975d6b6ee39e436, 0xb3e2fd538e122b45}, + {0xe7d34c64a9c85d44, 0x60dbbca87196b617}, + {0x90e40fbeea1d3a4a, 0xbc8955e946fe31ce}, + {0xb51d13aea4a488dd, 0x6babab6398bdbe42}, + {0xe264589a4dcdab14, 0xc696963c7eed2dd2}, + {0x8d7eb76070a08aec, 0xfc1e1de5cf543ca3}, + {0xb0de65388cc8ada8, 0x3b25a55f43294bcc}, + {0xdd15fe86affad912, 0x49ef0eb713f39ebf}, + {0x8a2dbf142dfcc7ab, 0x6e3569326c784338}, + {0xacb92ed9397bf996, 0x49c2c37f07965405}, + {0xd7e77a8f87daf7fb, 0xdc33745ec97be907}, + {0x86f0ac99b4e8dafd, 0x69a028bb3ded71a4}, + {0xa8acd7c0222311bc, 0xc40832ea0d68ce0d}, + {0xd2d80db02aabd62b, 0xf50a3fa490c30191}, + {0x83c7088e1aab65db, 0x792667c6da79e0fb}, + {0xa4b8cab1a1563f52, 0x577001b891185939}, + {0xcde6fd5e09abcf26, 0xed4c0226b55e6f87}, + {0x80b05e5ac60b6178, 0x544f8158315b05b5}, + {0xa0dc75f1778e39d6, 0x696361ae3db1c722}, + {0xc913936dd571c84c, 0x03bc3a19cd1e38ea}, + {0xfb5878494ace3a5f, 0x04ab48a04065c724}, + {0x9d174b2dcec0e47b, 0x62eb0d64283f9c77}, + {0xc45d1df942711d9a, 0x3ba5d0bd324f8395}, + {0xf5746577930d6500, 0xca8f44ec7ee3647a}, + {0x9968bf6abbe85f20, 0x7e998b13cf4e1ecc}, + {0xbfc2ef456ae276e8, 0x9e3fedd8c321a67f}, + {0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101f}, + {0x95d04aee3b80ece5, 0xbba1f1d158724a13}, + {0xbb445da9ca61281f, 0x2a8a6e45ae8edc98}, + {0xea1575143cf97226, 0xf52d09d71a3293be}, + {0x924d692ca61be758, 0x593c2626705f9c57}, + {0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836d}, + {0xe498f455c38b997a, 0x0b6dfb9c0f956448}, + {0x8edf98b59a373fec, 0x4724bd4189bd5ead}, + {0xb2977ee300c50fe7, 0x58edec91ec2cb658}, + {0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ee}, + {0x8b865b215899f46c, 0xbd79e0d20082ee75}, + {0xae67f1e9aec07187, 0xecd8590680a3aa12}, + {0xda01ee641a708de9, 0xe80e6f4820cc9496}, + {0x884134fe908658b2, 0x3109058d147fdcde}, + {0xaa51823e34a7eede, 0xbd4b46f0599fd416}, + {0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91b}, + {0x850fadc09923329e, 0x03e2cf6bc604ddb1}, + {0xa6539930bf6bff45, 0x84db8346b786151d}, + {0xcfe87f7cef46ff16, 0xe612641865679a64}, + {0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07f}, + {0xa26da3999aef7749, 0xe3be5e330f38f09e}, + {0xcb090c8001ab551c, 0x5cadf5bfd3072cc6}, + {0xfdcb4fa002162a63, 0x73d9732fc7c8f7f7}, + {0x9e9f11c4014dda7e, 0x2867e7fddcdd9afb}, + {0xc646d63501a1511d, 0xb281e1fd541501b9}, + {0xf7d88bc24209a565, 0x1f225a7ca91a4227}, + {0x9ae757596946075f, 0x3375788de9b06959}, + {0xc1a12d2fc3978937, 0x0052d6b1641c83af}, + {0xf209787bb47d6b84, 0xc0678c5dbd23a49b}, + {0x9745eb4d50ce6332, 0xf840b7ba963646e1}, + {0xbd176620a501fbff, 0xb650e5a93bc3d899}, + {0xec5d3fa8ce427aff, 0xa3e51f138ab4cebf}, + {0x93ba47c980e98cdf, 0xc66f336c36b10138}, + {0xb8a8d9bbe123f017, 0xb80b0047445d4185}, + {0xe6d3102ad96cec1d, 0xa60dc059157491e6}, + {0x9043ea1ac7e41392, 0x87c89837ad68db30}, + {0xb454e4a179dd1877, 0x29babe4598c311fc}, + {0xe16a1dc9d8545e94, 0xf4296dd6fef3d67b}, + {0x8ce2529e2734bb1d, 0x1899e4a65f58660d}, + {0xb01ae745b101e9e4, 0x5ec05dcff72e7f90}, + {0xdc21a1171d42645d, 0x76707543f4fa1f74}, + {0x899504ae72497eba, 0x6a06494a791c53a9}, + {0xabfa45da0edbde69, 0x0487db9d17636893}, + {0xd6f8d7509292d603, 0x45a9d2845d3c42b7}, + {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b3}, + {0xa7f26836f282b732, 0x8e6cac7768d7141f}, + {0xd1ef0244af2364ff, 0x3207d795430cd927}, + {0x8335616aed761f1f, 0x7f44e6bd49e807b9}, + {0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a7}, + {0xcd036837130890a1, 0x36dba887c37a8c10}, + {0x802221226be55a64, 0xc2494954da2c978a}, + {0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6d}, + {0xc83553c5c8965d3d, 0x6f92829494e5acc8}, + {0xfa42a8b73abbf48c, 0xcb772339ba1f17fa}, + {0x9c69a97284b578d7, 0xff2a760414536efc}, + {0xc38413cf25e2d70d, 0xfef5138519684abb}, + {0xf46518c2ef5b8cd1, 0x7eb258665fc25d6a}, + {0x98bf2f79d5993802, 0xef2f773ffbd97a62}, + {0xbeeefb584aff8603, 0xaafb550ffacfd8fb}, + {0xeeaaba2e5dbf6784, 0x95ba2a53f983cf39}, + {0x952ab45cfa97a0b2, 0xdd945a747bf26184}, + {0xba756174393d88df, 0x94f971119aeef9e5}, + {0xe912b9d1478ceb17, 0x7a37cd5601aab85e}, + {0x91abb422ccb812ee, 0xac62e055c10ab33b}, + {0xb616a12b7fe617aa, 0x577b986b314d600a}, + {0xe39c49765fdf9d94, 0xed5a7e85fda0b80c}, + {0x8e41ade9fbebc27d, 0x14588f13be847308}, + {0xb1d219647ae6b31c, 0x596eb2d8ae258fc9}, + {0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bc}, + {0x8aec23d680043bee, 0x25de7bb9480d5855}, + {0xada72ccc20054ae9, 0xaf561aa79a10ae6b}, + {0xd910f7ff28069da4, 0x1b2ba1518094da05}, + {0x87aa9aff79042286, 0x90fb44d2f05d0843}, + {0xa99541bf57452b28, 0x353a1607ac744a54}, + {0xd3fa922f2d1675f2, 0x42889b8997915ce9}, + {0x847c9b5d7c2e09b7, 0x69956135febada12}, + {0xa59bc234db398c25, 0x43fab9837e699096}, + {0xcf02b2c21207ef2e, 0x94f967e45e03f4bc}, + {0x8161afb94b44f57d, 0x1d1be0eebac278f6}, + {0xa1ba1ba79e1632dc, 0x6462d92a69731733}, + {0xca28a291859bbf93, 0x7d7b8f7503cfdcff}, + {0xfcb2cb35e702af78, 0x5cda735244c3d43f}, + {0x9defbf01b061adab, 0x3a0888136afa64a8}, + {0xc56baec21c7a1916, 0x088aaa1845b8fdd1}, + {0xf6c69a72a3989f5b, 0x8aad549e57273d46}, + {0x9a3c2087a63f6399, 0x36ac54e2f678864c}, + {0xc0cb28a98fcf3c7f, 0x84576a1bb416a7de}, + {0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d6}, + {0x969eb7c47859e743, 0x9f644ae5a4b1b326}, + {0xbc4665b596706114, 0x873d5d9f0dde1fef}, + {0xeb57ff22fc0c7959, 0xa90cb506d155a7eb}, + {0x9316ff75dd87cbd8, 0x09a7f12442d588f3}, + {0xb7dcbf5354e9bece, 0x0c11ed6d538aeb30}, + {0xe5d3ef282a242e81, 0x8f1668c8a86da5fb}, + {0x8fa475791a569d10, 0xf96e017d694487bd}, + {0xb38d92d760ec4455, 0x37c981dcc395a9ad}, + {0xe070f78d3927556a, 0x85bbe253f47b1418}, + {0x8c469ab843b89562, 0x93956d7478ccec8f}, + {0xaf58416654a6babb, 0x387ac8d1970027b3}, + {0xdb2e51bfe9d0696a, 0x06997b05fcc0319f}, + {0x88fcf317f22241e2, 0x441fece3bdf81f04}, + {0xab3c2fddeeaad25a, 0xd527e81cad7626c4}, + {0xd60b3bd56a5586f1, 0x8a71e223d8d3b075}, + {0x85c7056562757456, 0xf6872d5667844e4a}, + {0xa738c6bebb12d16c, 0xb428f8ac016561dc}, + {0xd106f86e69d785c7, 0xe13336d701beba53}, + {0x82a45b450226b39c, 0xecc0024661173474}, + {0xa34d721642b06084, 0x27f002d7f95d0191}, + {0xcc20ce9bd35c78a5, 0x31ec038df7b441f5}, + {0xff290242c83396ce, 0x7e67047175a15272}, + {0x9f79a169bd203e41, 0x0f0062c6e984d387}, + {0xc75809c42c684dd1, 0x52c07b78a3e60869}, + {0xf92e0c3537826145, 0xa7709a56ccdf8a83}, + {0x9bbcc7a142b17ccb, 0x88a66076400bb692}, + {0xc2abf989935ddbfe, 0x6acff893d00ea436}, + {0xf356f7ebf83552fe, 0x0583f6b8c4124d44}, + {0x98165af37b2153de, 0xc3727a337a8b704b}, + {0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5d}, + {0xeda2ee1c7064130c, 0x1162def06f79df74}, + {0x9485d4d1c63e8be7, 0x8addcb5645ac2ba9}, + {0xb9a74a0637ce2ee1, 0x6d953e2bd7173693}, + {0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0438}, + {0x910ab1d4db9914a0, 0x1d9c9892400a22a3}, + {0xb54d5e4a127f59c8, 0x2503beb6d00cab4c}, + {0xe2a0b5dc971f303a, 0x2e44ae64840fd61e}, + {0x8da471a9de737e24, 0x5ceaecfed289e5d3}, + {0xb10d8e1456105dad, 0x7425a83e872c5f48}, + {0xdd50f1996b947518, 0xd12f124e28f7771a}, + {0x8a5296ffe33cc92f, 0x82bd6b70d99aaa70}, + {0xace73cbfdc0bfb7b, 0x636cc64d1001550c}, + {0xd8210befd30efa5a, 0x3c47f7e05401aa4f}, + {0x8714a775e3e95c78, 0x65acfaec34810a72}, + {0xa8d9d1535ce3b396, 0x7f1839a741a14d0e}, + {0xd31045a8341ca07c, 0x1ede48111209a051}, + {0x83ea2b892091e44d, 0x934aed0aab460433}, + {0xa4e4b66b68b65d60, 0xf81da84d56178540}, + {0xce1de40642e3f4b9, 0x36251260ab9d668f}, + {0x80d2ae83e9ce78f3, 0xc1d72b7c6b42601a}, + {0xa1075a24e4421730, 0xb24cf65b8612f820}, + {0xc94930ae1d529cfc, 0xdee033f26797b628}, + {0xfb9b7cd9a4a7443c, 0x169840ef017da3b2}, + {0x9d412e0806e88aa5, 0x8e1f289560ee864f}, + {0xc491798a08a2ad4e, 0xf1a6f2bab92a27e3}, + {0xf5b5d7ec8acb58a2, 0xae10af696774b1dc}, + {0x9991a6f3d6bf1765, 0xacca6da1e0a8ef2a}, + {0xbff610b0cc6edd3f, 0x17fd090a58d32af4}, + {0xeff394dcff8a948e, 0xddfc4b4cef07f5b1}, + {0x95f83d0a1fb69cd9, 0x4abdaf101564f98f}, + {0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f2}, + {0xea53df5fd18d5513, 0x84c86189216dc5ee}, + {0x92746b9be2f8552c, 0x32fd3cf5b4e49bb5}, + {0xb7118682dbb66a77, 0x3fbc8c33221dc2a2}, + {0xe4d5e82392a40515, 0x0fabaf3feaa5334b}, + {0x8f05b1163ba6832d, 0x29cb4d87f2a7400f}, + {0xb2c71d5bca9023f8, 0x743e20e9ef511013}, + {0xdf78e4b2bd342cf6, 0x914da9246b255417}, + {0x8bab8eefb6409c1a, 0x1ad089b6c2f7548f}, + {0xae9672aba3d0c320, 0xa184ac2473b529b2}, + {0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741f}, + {0x8865899617fb1871, 0x7e2fa67c7a658893}, + {0xaa7eebfb9df9de8d, 0xddbb901b98feeab8}, + {0xd51ea6fa85785631, 0x552a74227f3ea566}, + {0x8533285c936b35de, 0xd53a88958f872760}, + {0xa67ff273b8460356, 0x8a892abaf368f138}, + {0xd01fef10a657842c, 0x2d2b7569b0432d86}, + {0x8213f56a67f6b29b, 0x9c3b29620e29fc74}, + {0xa298f2c501f45f42, 0x8349f3ba91b47b90}, + {0xcb3f2f7642717713, 0x241c70a936219a74}, + {0xfe0efb53d30dd4d7, 0xed238cd383aa0111}, + {0x9ec95d1463e8a506, 0xf4363804324a40ab}, + {0xc67bb4597ce2ce48, 0xb143c6053edcd0d6}, + {0xf81aa16fdc1b81da, 0xdd94b7868e94050b}, + {0x9b10a4e5e9913128, 0xca7cf2b4191c8327}, + {0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f1}, + {0xf24a01a73cf2dccf, 0xbc633b39673c8ced}, + {0x976e41088617ca01, 0xd5be0503e085d814}, + {0xbd49d14aa79dbc82, 0x4b2d8644d8a74e19}, + {0xec9c459d51852ba2, 0xddf8e7d60ed1219f}, + {0x93e1ab8252f33b45, 0xcabb90e5c942b504}, + {0xb8da1662e7b00a17, 0x3d6a751f3b936244}, + {0xe7109bfba19c0c9d, 0x0cc512670a783ad5}, + {0x906a617d450187e2, 0x27fb2b80668b24c6}, + {0xb484f9dc9641e9da, 0xb1f9f660802dedf7}, + {0xe1a63853bbd26451, 0x5e7873f8a0396974}, + {0x8d07e33455637eb2, 0xdb0b487b6423e1e9}, + {0xb049dc016abc5e5f, 0x91ce1a9a3d2cda63}, + {0xdc5c5301c56b75f7, 0x7641a140cc7810fc}, + {0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9e}, + {0xac2820d9623bf429, 0x546345fa9fbdcd45}, + {0xd732290fbacaf133, 0xa97c177947ad4096}, + {0x867f59a9d4bed6c0, 0x49ed8eabcccc485e}, + {0xa81f301449ee8c70, 0x5c68f256bfff5a75}, + {0xd226fc195c6a2f8c, 0x73832eec6fff3112}, + {0x83585d8fd9c25db7, 0xc831fd53c5ff7eac}, + {0xa42e74f3d032f525, 0xba3e7ca8b77f5e56}, + {0xcd3a1230c43fb26f, 0x28ce1bd2e55f35ec}, + {0x80444b5e7aa7cf85, 0x7980d163cf5b81b4}, + {0xa0555e361951c366, 0xd7e105bcc3326220}, + {0xc86ab5c39fa63440, 0x8dd9472bf3fefaa8}, + {0xfa856334878fc150, 0xb14f98f6f0feb952}, + {0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d4}, + {0xc3b8358109e84f07, 0x0a862f80ec4700c9}, + {0xf4a642e14c6262c8, 0xcd27bb612758c0fb}, + {0x98e7e9cccfbd7dbd, 0x8038d51cb897789d}, + {0xbf21e44003acdd2c, 0xe0470a63e6bd56c4}, + {0xeeea5d5004981478, 0x1858ccfce06cac75}, + {0x95527a5202df0ccb, 0x0f37801e0c43ebc9}, + {0xbaa718e68396cffd, 0xd30560258f54e6bb}, + {0xe950df20247c83fd, 0x47c6b82ef32a206a}, + {0x91d28b7416cdd27e, 0x4cdc331d57fa5442}, + {0xb6472e511c81471d, 0xe0133fe4adf8e953}, + {0xe3d8f9e563a198e5, 0x58180fddd97723a7}, + {0x8e679c2f5e44ff8f, 0x570f09eaa7ea7649}, + {0xb201833b35d63f73, 0x2cd2cc6551e513db}, + {0xde81e40a034bcf4f, 0xf8077f7ea65e58d2}, + {0x8b112e86420f6191, 0xfb04afaf27faf783}, + {0xadd57a27d29339f6, 0x79c5db9af1f9b564}, + {0xd94ad8b1c7380874, 0x18375281ae7822bd}, + {0x87cec76f1c830548, 0x8f2293910d0b15b6}, + {0xa9c2794ae3a3c69a, 0xb2eb3875504ddb23}, + {0xd433179d9c8cb841, 0x5fa60692a46151ec}, + {0x849feec281d7f328, 0xdbc7c41ba6bcd334}, + {0xa5c7ea73224deff3, 0x12b9b522906c0801}, + {0xcf39e50feae16bef, 0xd768226b34870a01}, + {0x81842f29f2cce375, 0xe6a1158300d46641}, + {0xa1e53af46f801c53, 0x60495ae3c1097fd1}, + {0xca5e89b18b602368, 0x385bb19cb14bdfc5}, + {0xfcf62c1dee382c42, 0x46729e03dd9ed7b6}, + {0x9e19db92b4e31ba9, 0x6c07a2c26a8346d2}, + {0xc5a05277621be293, 0xc7098b7305241886}, + {0xf70867153aa2db38, 0xb8cbee4fc66d1ea8}, + {0x9a65406d44a5c903, 0x737f74f1dc043329}, + {0xc0fe908895cf3b44, 0x505f522e53053ff3}, + {0xf13e34aabb430a15, 0x647726b9e7c68ff0}, + {0x96c6e0eab509e64d, 0x5eca783430dc19f6}, + {0xbc789925624c5fe0, 0xb67d16413d132073}, + {0xeb96bf6ebadf77d8, 0xe41c5bd18c57e890}, + {0x933e37a534cbaae7, 0x8e91b962f7b6f15a}, + {0xb80dc58e81fe95a1, 0x723627bbb5a4adb1}, + {0xe61136f2227e3b09, 0xcec3b1aaa30dd91d}, + {0x8fcac257558ee4e6, 0x213a4f0aa5e8a7b2}, + {0xb3bd72ed2af29e1f, 0xa988e2cd4f62d19e}, + {0xe0accfa875af45a7, 0x93eb1b80a33b8606}, + {0x8c6c01c9498d8b88, 0xbc72f130660533c4}, + {0xaf87023b9bf0ee6a, 0xeb8fad7c7f8680b5}, + {0xdb68c2ca82ed2a05, 0xa67398db9f6820e2}, +#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, 0x02f236d04753d5b5}, + {0xcde6fd5e09abcf26, 0xed4c0226b55e6f87}, + {0xa6539930bf6bff45, 0x84db8346b786151d}, + {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b3}, + {0xd910f7ff28069da4, 0x1b2ba1518094da05}, + {0xaf58416654a6babb, 0x387ac8d1970027b3}, + {0x8da471a9de737e24, 0x5ceaecfed289e5d3}, + {0xe4d5e82392a40515, 0x0fabaf3feaa5334b}, + {0xb8da1662e7b00a17, 0x3d6a751f3b936244}, + {0x95527a5202df0ccb, 0x0f37801e0c43ebc9}, + {0xf13e34aabb430a15, 0x647726b9e7c68ff0} +#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 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_fallback 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_fallback recovered_cache = umul128(base_cache.high(), pow5); + uint128_fallback middle_low = umul128(base_cache.low(), 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_fallback{(recovered_cache.low() >> alpha) | high_to_middle, + ((middle_low.low() >> alpha) | middle_to_low)}; + FMT_ASSERT(recovered_cache.low() + 1 != 0, ""); + return {recovered_cache.high(), recovered_cache.low() + 1}; +#endif + } + + struct compute_mul_result { + carrier_uint result; + bool is_integer; + }; + struct compute_mul_parity_result { + bool parity; + bool is_integer; + }; + + static auto compute_mul(carrier_uint u, + const cache_entry_type& cache) noexcept + -> compute_mul_result { + auto r = umul192_upper128(u, cache); + return {r.high(), r.low() == 0}; + } + + static auto compute_delta(cache_entry_type const& cache, int beta) noexcept + -> uint32_t { + return static_cast(cache.high() >> (64 - 1 - beta)); + } + + static auto compute_mul_parity(carrier_uint two_f, + const cache_entry_type& cache, + int beta) noexcept + -> compute_mul_parity_result { + FMT_ASSERT(beta >= 1, ""); + FMT_ASSERT(beta < 64, ""); + + auto r = umul192_lower128(two_f, cache); + return {((r.high() >> (64 - beta)) & 1) != 0, + ((r.high() << beta) | (r.low() >> (64 - beta))) == 0}; + } + + static auto compute_left_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return (cache.high() - + (cache.high() >> (num_significand_bits() + 2))) >> + (64 - num_significand_bits() - 1 - beta); + } + + static auto compute_right_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return (cache.high() + + (cache.high() >> (num_significand_bits() + 1))) >> + (64 - num_significand_bits() - 1 - beta); + } + + static auto compute_round_up_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return ((cache.high() >> (64 - num_significand_bits() - 2 - beta)) + + 1) / + 2; + } +}; + +FMT_FUNC auto get_cached_power(int k) noexcept -> uint128_fallback { + return cache_accessor::get_cached_power(k); +} + +// Various integer checks +template +auto is_left_endpoint_integer_shorter_interval(int exponent) noexcept -> bool { + const int case_shorter_interval_left_endpoint_lower_threshold = 2; + const int case_shorter_interval_left_endpoint_upper_threshold = 3; + return exponent >= case_shorter_interval_left_endpoint_lower_threshold && + exponent <= case_shorter_interval_left_endpoint_upper_threshold; +} + +// Remove trailing zeros from n and return the number of zeros removed (float) +FMT_INLINE int remove_trailing_zeros(uint32_t& n, int s = 0) noexcept { + FMT_ASSERT(n != 0, ""); + // Modular inverse of 5 (mod 2^32): (mod_inv_5 * 5) mod 2^32 = 1. + constexpr uint32_t mod_inv_5 = 0xcccccccd; + constexpr uint32_t mod_inv_25 = 0xc28f5c29; // = mod_inv_5 * mod_inv_5 + + while (true) { + auto q = rotr(n * mod_inv_25, 2); + if (q > max_value() / 100) break; + n = q; + s += 2; + } + auto q = rotr(n * mod_inv_5, 1); + if (q <= max_value() / 10) { + n = q; + s |= 1; + } + return s; +} + +// Removes trailing zeros and returns the number of zeros removed (double) +FMT_INLINE int remove_trailing_zeros(uint64_t& n) noexcept { + FMT_ASSERT(n != 0, ""); + + // This magic number is ceil(2^90 / 10^8). + constexpr uint64_t magic_number = 12379400392853802749ull; + auto nm = umul128(n, magic_number); + + // Is n is divisible by 10^8? + if ((nm.high() & ((1ull << (90 - 64)) - 1)) == 0 && nm.low() < magic_number) { + // If yes, work with the quotient... + auto n32 = static_cast(nm.high() >> (90 - 64)); + // ... and use the 32 bit variant of the function + int s = remove_trailing_zeros(n32, 8); + n = n32; + return s; + } + + // If n is not divisible by 10^8, work with n itself. + constexpr uint64_t mod_inv_5 = 0xcccccccccccccccd; + constexpr uint64_t mod_inv_25 = 0x8f5c28f5c28f5c29; // mod_inv_5 * mod_inv_5 + + int s = 0; + while (true) { + auto q = rotr(n * mod_inv_25, 2); + if (q > max_value() / 100) break; + n = q; + s += 2; + } + auto q = rotr(n * mod_inv_5, 1); + if (q <= max_value() / 10) { + n = q; + s |= 1; + } + + return s; +} + +// The main algorithm for shorter interval case +template +FMT_INLINE decimal_fp shorter_interval_case(int exponent) 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 = 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); + auto zi = cache_accessor::compute_right_endpoint_for_shorter_interval_case( + cache, beta); + + // 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); + 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 auto to_decimal(T x) noexcept -> decimal_fp { + // 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) << num_significand_bits()) - 1; + carrier_uint significand = (br & significand_mask); + int exponent = + static_cast((br & exponent_mask()) >> num_significand_bits()); + + if (exponent != 0) { // Check if normal. + exponent -= exponent_bias() + num_significand_bits(); + + // Shorter interval case; proceed like Schubfach. + // In fact, when exponent == 1 and significand == 0, the interval is + // regular. However, it can be shown that the end-results are anyway same. + if (significand == 0) return shorter_interval_case(exponent); + + significand |= (static_cast(1) << num_significand_bits()); + } else { + // Subnormal case; the interval is always regular. + if (significand == 0) return {0, 0}; + exponent = + std::numeric_limits::min_exponent - num_significand_bits() - 1; + } + + 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 = 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); + const carrier_uint two_fc = significand << 1; + + // For the case of binary32, the result of integer check is not correct for + // 29711844 * 2^-82 + // = 6.1442653300000000008655037797566933477355632930994033813476... * 10^-18 + // and 29711844 * 2^-81 + // = 1.2288530660000000001731007559513386695471126586198806762695... * 10^-17, + // and they are the unique counterexamples. However, since 29711844 is even, + // this does not cause any problem for the endpoints calculations; it can only + // cause a problem when we need to perform integer check for the center. + // Fortunately, with these inputs, that branch is never executed, so we are + // fine. + const typename cache_accessor::compute_mul_result z_mul = + cache_accessor::compute_mul((two_fc | 1) << beta, 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(z_mul.result); + uint32_t r = static_cast(z_mul.result - float_info::big_divisor * + ret_value.significand); + + if (r < deltai) { + // Exclude the right endpoint if necessary. + if (r == 0 && (z_mul.is_integer & !include_right_endpoint)) { + --ret_value.significand; + r = float_info::big_divisor; + goto small_divisor_case_label; + } + } else if (r > deltai) { + goto small_divisor_case_label; + } else { + // r == deltai; compare fractional parts. + const typename cache_accessor::compute_mul_parity_result x_mul = + cache_accessor::compute_mul_parity(two_fc - 1, cache, beta); + + if (!(x_mul.parity | (x_mul.is_integer & include_left_endpoint))) + 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; + + uint32_t dist = r - (deltai / 2) + (float_info::small_divisor / 2); + const bool approx_y_parity = + ((dist ^ (float_info::small_divisor / 2)) & 1) != 0; + + // Is dist divisible by 10^kappa? + const bool divisible_by_small_divisor = + check_divisibility_and_divide_by_pow10::kappa>(dist); + + // Add dist / 10^kappa to the significand. + ret_value.significand += dist; + + if (!divisible_by_small_divisor) return ret_value; + + // 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. + const auto y_mul = cache_accessor::compute_mul_parity(two_fc, cache, beta); + + // If z^(f) >= epsilon^(f), we might have a tie when z^(f) == epsilon^(f), + // or equivalently, when y is an integer. + if (y_mul.parity != approx_y_parity) + --ret_value.significand; + else if (y_mul.is_integer & (ret_value.significand % 2 != 0)) + --ret_value.significand; + return ret_value; +} +} // namespace dragonbox +} // namespace detail + +template <> struct formatter { + FMT_CONSTEXPR auto parse(format_parse_context& ctx) + -> format_parse_context::iterator { + return ctx.begin(); + } + + auto format(const detail::bigint& n, format_context& ctx) const + -> format_context::iterator { + 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 = fmt::format_to(out, FMT_STRING("{:x}"), value); + first = false; + continue; + } + out = fmt::format_to(out, FMT_STRING("{:08x}"), value); + } + if (n.exp_ > 0) + out = fmt::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) noexcept { + FMT_TRY { + auto ec = std::error_code(error_code, std::generic_category()); + detail::write(appender(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) noexcept { + do_report_error(format_system_error, error_code, message); +} + +FMT_FUNC auto vformat(string_view fmt, format_args args) -> std::string { + // 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); +} + +namespace detail { + +FMT_FUNC void vformat_to(buffer& buf, string_view fmt, format_args args, + locale_ref loc) { + auto out = appender(buf); + if (fmt.size() == 2 && equal2(fmt.data(), "{}")) + return args.get(0).visit(default_arg_formatter{out}); + parse_format_string( + fmt, format_handler{parse_context(fmt), {out, args, loc}}); +} + +template struct span { + T* data; + size_t size; +}; + +template auto flockfile(F* f) -> decltype(_lock_file(f)) { + _lock_file(f); +} +template auto funlockfile(F* f) -> decltype(_unlock_file(f)) { + _unlock_file(f); +} + +#ifndef getc_unlocked +template auto getc_unlocked(F* f) -> decltype(_fgetc_nolock(f)) { + return _fgetc_nolock(f); +} +#endif + +template +struct has_flockfile : std::false_type {}; + +template +struct has_flockfile()))>> + : std::true_type {}; + +// A FILE wrapper. F is FILE defined as a template parameter to make system API +// detection work. +template class file_base { + public: + F* file_; + + public: + file_base(F* file) : file_(file) {} + operator F*() const { return file_; } + + // Reads a code unit from the stream. + auto get() -> int { + int result = getc_unlocked(file_); + if (result == EOF && ferror(file_) != 0) + FMT_THROW(system_error(errno, FMT_STRING("getc failed"))); + return result; + } + + // Puts the code unit back into the stream buffer. + void unget(char c) { + if (ungetc(c, file_) == EOF) + FMT_THROW(system_error(errno, FMT_STRING("ungetc failed"))); + } + + void flush() { fflush(this->file_); } +}; + +// A FILE wrapper for glibc. +template class glibc_file : public file_base { + private: + enum { + line_buffered = 0x200, // _IO_LINE_BUF + unbuffered = 2 // _IO_UNBUFFERED + }; + + public: + using file_base::file_base; + + auto is_buffered() const -> bool { + return (this->file_->_flags & unbuffered) == 0; + } + + void init_buffer() { + if (this->file_->_IO_write_ptr) return; + // Force buffer initialization by placing and removing a char in a buffer. + assume(this->file_->_IO_write_ptr >= this->file_->_IO_write_end); + putc_unlocked(0, this->file_); + --this->file_->_IO_write_ptr; + } + + // Returns the file's read buffer. + auto get_read_buffer() const -> span { + auto ptr = this->file_->_IO_read_ptr; + return {ptr, to_unsigned(this->file_->_IO_read_end - ptr)}; + } + + // Returns the file's write buffer. + auto get_write_buffer() const -> span { + auto ptr = this->file_->_IO_write_ptr; + return {ptr, to_unsigned(this->file_->_IO_buf_end - ptr)}; + } + + void advance_write_buffer(size_t size) { this->file_->_IO_write_ptr += size; } + + bool needs_flush() const { + if ((this->file_->_flags & line_buffered) == 0) return false; + char* end = this->file_->_IO_write_end; + return memchr(end, '\n', to_unsigned(this->file_->_IO_write_ptr - end)); + } + + void flush() { fflush_unlocked(this->file_); } +}; + +// A FILE wrapper for Apple's libc. +template class apple_file : public file_base { + private: + enum { + line_buffered = 1, // __SNBF + unbuffered = 2 // __SLBF + }; + + public: + using file_base::file_base; + + auto is_buffered() const -> bool { + return (this->file_->_flags & unbuffered) == 0; + } + + void init_buffer() { + if (this->file_->_p) return; + // Force buffer initialization by placing and removing a char in a buffer. + putc_unlocked(0, this->file_); + --this->file_->_p; + ++this->file_->_w; + } + + auto get_read_buffer() const -> span { + return {reinterpret_cast(this->file_->_p), + to_unsigned(this->file_->_r)}; + } + + auto get_write_buffer() const -> span { + return {reinterpret_cast(this->file_->_p), + to_unsigned(this->file_->_bf._base + this->file_->_bf._size - + this->file_->_p)}; + } + + void advance_write_buffer(size_t size) { + this->file_->_p += size; + this->file_->_w -= size; + } + + bool needs_flush() const { + if ((this->file_->_flags & line_buffered) == 0) return false; + return memchr(this->file_->_p + this->file_->_w, '\n', + to_unsigned(-this->file_->_w)); + } +}; + +// A fallback FILE wrapper. +template class fallback_file : public file_base { + private: + char next_; // The next unconsumed character in the buffer. + bool has_next_ = false; + + public: + using file_base::file_base; + + auto is_buffered() const -> bool { return false; } + auto needs_flush() const -> bool { return false; } + void init_buffer() {} + + auto get_read_buffer() const -> span { + return {&next_, has_next_ ? 1u : 0u}; + } + + auto get_write_buffer() const -> span { return {nullptr, 0}; } + + void advance_write_buffer(size_t) {} + + auto get() -> int { + has_next_ = false; + return file_base::get(); + } + + void unget(char c) { + file_base::unget(c); + next_ = c; + has_next_ = true; + } +}; + +#ifndef FMT_USE_FALLBACK_FILE +# define FMT_USE_FALLBACK_FILE 0 +#endif + +template +auto get_file(F* f, int) -> apple_file { + return f; +} +template +inline auto get_file(F* f, int) -> glibc_file { + return f; +} + +inline auto get_file(FILE* f, ...) -> fallback_file { return f; } + +using file_ref = decltype(get_file(static_cast(nullptr), 0)); + +template +class file_print_buffer : public buffer { + public: + explicit file_print_buffer(F*) : buffer(nullptr, size_t()) {} +}; + +template +class file_print_buffer::value>> + : public buffer { + private: + file_ref file_; + + static void grow(buffer& base, size_t) { + auto& self = static_cast(base); + self.file_.advance_write_buffer(self.size()); + if (self.file_.get_write_buffer().size == 0) self.file_.flush(); + auto buf = self.file_.get_write_buffer(); + FMT_ASSERT(buf.size > 0, ""); + self.set(buf.data, buf.size); + self.clear(); + } + + public: + explicit file_print_buffer(F* f) : buffer(grow, size_t()), file_(f) { + flockfile(f); + file_.init_buffer(); + auto buf = file_.get_write_buffer(); + set(buf.data, buf.size); + } + ~file_print_buffer() { + file_.advance_write_buffer(size()); + bool flush = file_.needs_flush(); + F* f = file_; // Make funlockfile depend on the template parameter F + funlockfile(f); // for the system API detection to work. + if (flush) fflush(file_); + } +}; + +#if !defined(_WIN32) || defined(FMT_USE_WRITE_CONSOLE) +FMT_FUNC auto write_console(int, string_view) -> bool { return false; } +#else +using dword = conditional_t; +extern "C" __declspec(dllimport) int __stdcall WriteConsoleW( // + void*, const void*, dword, dword*, void*); + +FMT_FUNC bool write_console(int fd, string_view text) { + auto u16 = utf8_to_utf16(text); + return WriteConsoleW(reinterpret_cast(_get_osfhandle(fd)), u16.c_str(), + static_cast(u16.size()), nullptr, nullptr) != 0; +} +#endif + +#ifdef _WIN32 +// Print assuming legacy (non-Unicode) encoding. +FMT_FUNC void vprint_mojibake(std::FILE* f, string_view fmt, format_args args, + bool newline) { + auto buffer = memory_buffer(); + detail::vformat_to(buffer, fmt, args); + if (newline) buffer.push_back('\n'); + fwrite_all(buffer.data(), buffer.size(), f); +} +#endif + +FMT_FUNC void print(std::FILE* f, string_view text) { +#if defined(_WIN32) && !defined(FMT_USE_WRITE_CONSOLE) + int fd = _fileno(f); + if (_isatty(fd)) { + std::fflush(f); + if (write_console(fd, text)) return; + } +#endif + fwrite_all(text.data(), text.size(), f); +} +} // namespace detail + +FMT_FUNC void vprint_buffered(std::FILE* f, string_view fmt, format_args args) { + auto buffer = memory_buffer(); + detail::vformat_to(buffer, fmt, args); + detail::print(f, {buffer.data(), buffer.size()}); +} + +FMT_FUNC void vprint(std::FILE* f, string_view fmt, format_args args) { + if (!detail::file_ref(f).is_buffered() || !detail::has_flockfile<>()) + return vprint_buffered(f, fmt, args); + auto&& buffer = detail::file_print_buffer<>(f); + return detail::vformat_to(buffer, fmt, args); +} + +FMT_FUNC void vprintln(std::FILE* f, string_view fmt, format_args args) { + auto buffer = memory_buffer(); + detail::vformat_to(buffer, fmt, args); + buffer.push_back('\n'); + detail::print(f, {buffer.data(), buffer.size()}); +} + +FMT_FUNC void vprint(string_view fmt, format_args args) { + vprint(stdout, fmt, args); +} + +namespace detail { + +struct singleton { + unsigned char upper; + unsigned char lower_count; +}; + +inline auto is_printable(uint16_t x, const singleton* singletons, + size_t singletons_size, + const unsigned char* singleton_lowers, + const unsigned char* normal, size_t normal_size) + -> bool { + auto upper = x >> 8; + auto lower_start = 0; + for (size_t i = 0; i < singletons_size; ++i) { + auto s = singletons[i]; + auto lower_end = lower_start + s.lower_count; + if (upper < s.upper) break; + if (upper == s.upper) { + for (auto j = lower_start; j < lower_end; ++j) { + if (singleton_lowers[j] == (x & 0xff)) return false; + } + } + lower_start = lower_end; + } + + auto xsigned = static_cast(x); + auto current = true; + for (size_t i = 0; i < normal_size; ++i) { + auto v = static_cast(normal[i]); + auto len = (v & 0x80) != 0 ? (v & 0x7f) << 8 | normal[++i] : v; + xsigned -= len; + if (xsigned < 0) break; + current = !current; + } + return current; +} + +// This code is generated by support/printable.py. +FMT_FUNC auto is_printable(uint32_t cp) -> bool { + static constexpr singleton singletons0[] = { + {0x00, 1}, {0x03, 5}, {0x05, 6}, {0x06, 3}, {0x07, 6}, {0x08, 8}, + {0x09, 17}, {0x0a, 28}, {0x0b, 25}, {0x0c, 20}, {0x0d, 16}, {0x0e, 13}, + {0x0f, 4}, {0x10, 3}, {0x12, 18}, {0x13, 9}, {0x16, 1}, {0x17, 5}, + {0x18, 2}, {0x19, 3}, {0x1a, 7}, {0x1c, 2}, {0x1d, 1}, {0x1f, 22}, + {0x20, 3}, {0x2b, 3}, {0x2c, 2}, {0x2d, 11}, {0x2e, 1}, {0x30, 3}, + {0x31, 2}, {0x32, 1}, {0xa7, 2}, {0xa9, 2}, {0xaa, 4}, {0xab, 8}, + {0xfa, 2}, {0xfb, 5}, {0xfd, 4}, {0xfe, 3}, {0xff, 9}, + }; + static constexpr unsigned char singletons0_lower[] = { + 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, 0x58, 0x8b, 0x8c, 0x90, + 0x1c, 0x1d, 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f, + 0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, 0x92, 0xa9, 0xb1, + 0xba, 0xbb, 0xc5, 0xc6, 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04, + 0x11, 0x12, 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, 0x5d, + 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf, + 0xe4, 0xe5, 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, + 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, + 0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, 0x8d, + 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x0d, + 0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, + 0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6, 0xbe, 0xbf, 0xc5, 0xc7, + 0xce, 0xcf, 0xda, 0xdb, 0x48, 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, + 0x4e, 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, 0xb1, 0xb6, 0xb7, + 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, + 0xfe, 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e, + 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, 0xaf, 0xbb, 0xbc, 0xfa, 0x16, + 0x17, 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, 0x7e, + 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f, + 0x74, 0x75, 0x96, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf, + 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, 0x30, 0x8f, 0x1f, 0xc0, + 0xc1, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27, + 0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, 0x91, + 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, + 0xfe, 0xff, + }; + static constexpr singleton singletons1[] = { + {0x00, 6}, {0x01, 1}, {0x03, 1}, {0x04, 2}, {0x08, 8}, {0x09, 2}, + {0x0a, 5}, {0x0b, 2}, {0x0e, 4}, {0x10, 1}, {0x11, 2}, {0x12, 5}, + {0x13, 17}, {0x14, 1}, {0x15, 2}, {0x17, 2}, {0x19, 13}, {0x1c, 5}, + {0x1d, 8}, {0x24, 1}, {0x6a, 3}, {0x6b, 2}, {0xbc, 2}, {0xd1, 2}, + {0xd4, 12}, {0xd5, 9}, {0xd6, 2}, {0xd7, 2}, {0xda, 1}, {0xe0, 5}, + {0xe1, 2}, {0xe8, 2}, {0xee, 32}, {0xf0, 4}, {0xf8, 2}, {0xf9, 2}, + {0xfa, 2}, {0xfb, 1}, + }; + static constexpr unsigned char singletons1_lower[] = { + 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, 0x9e, 0x9f, 0x06, 0x07, + 0x09, 0x36, 0x3d, 0x3e, 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x36, + 0x37, 0x56, 0x57, 0x7f, 0xaa, 0xae, 0xaf, 0xbd, 0x35, 0xe0, 0x12, 0x87, + 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, + 0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5c, 0xb6, 0xb7, 0x1b, + 0x1c, 0x07, 0x08, 0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8, 0xa9, + 0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66, + 0x69, 0x8f, 0x92, 0x6f, 0x5f, 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, + 0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc, + 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, + 0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, 0x3f, 0xc5, 0xc6, + 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c, + 0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, + 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0, + 0xae, 0xaf, 0x79, 0xcc, 0x6e, 0x6f, 0x93, + }; + static constexpr unsigned char normal0[] = { + 0x00, 0x20, 0x5f, 0x22, 0x82, 0xdf, 0x04, 0x82, 0x44, 0x08, 0x1b, 0x04, + 0x06, 0x11, 0x81, 0xac, 0x0e, 0x80, 0xab, 0x35, 0x28, 0x0b, 0x80, 0xe0, + 0x03, 0x19, 0x08, 0x01, 0x04, 0x2f, 0x04, 0x34, 0x04, 0x07, 0x03, 0x01, + 0x07, 0x06, 0x07, 0x11, 0x0a, 0x50, 0x0f, 0x12, 0x07, 0x55, 0x07, 0x03, + 0x04, 0x1c, 0x0a, 0x09, 0x03, 0x08, 0x03, 0x07, 0x03, 0x02, 0x03, 0x03, + 0x03, 0x0c, 0x04, 0x05, 0x03, 0x0b, 0x06, 0x01, 0x0e, 0x15, 0x05, 0x3a, + 0x03, 0x11, 0x07, 0x06, 0x05, 0x10, 0x07, 0x57, 0x07, 0x02, 0x07, 0x15, + 0x0d, 0x50, 0x04, 0x43, 0x03, 0x2d, 0x03, 0x01, 0x04, 0x11, 0x06, 0x0f, + 0x0c, 0x3a, 0x04, 0x1d, 0x25, 0x5f, 0x20, 0x6d, 0x04, 0x6a, 0x25, 0x80, + 0xc8, 0x05, 0x82, 0xb0, 0x03, 0x1a, 0x06, 0x82, 0xfd, 0x03, 0x59, 0x07, + 0x15, 0x0b, 0x17, 0x09, 0x14, 0x0c, 0x14, 0x0c, 0x6a, 0x06, 0x0a, 0x06, + 0x1a, 0x06, 0x59, 0x07, 0x2b, 0x05, 0x46, 0x0a, 0x2c, 0x04, 0x0c, 0x04, + 0x01, 0x03, 0x31, 0x0b, 0x2c, 0x04, 0x1a, 0x06, 0x0b, 0x03, 0x80, 0xac, + 0x06, 0x0a, 0x06, 0x21, 0x3f, 0x4c, 0x04, 0x2d, 0x03, 0x74, 0x08, 0x3c, + 0x03, 0x0f, 0x03, 0x3c, 0x07, 0x38, 0x08, 0x2b, 0x05, 0x82, 0xff, 0x11, + 0x18, 0x08, 0x2f, 0x11, 0x2d, 0x03, 0x20, 0x10, 0x21, 0x0f, 0x80, 0x8c, + 0x04, 0x82, 0x97, 0x19, 0x0b, 0x15, 0x88, 0x94, 0x05, 0x2f, 0x05, 0x3b, + 0x07, 0x02, 0x0e, 0x18, 0x09, 0x80, 0xb3, 0x2d, 0x74, 0x0c, 0x80, 0xd6, + 0x1a, 0x0c, 0x05, 0x80, 0xff, 0x05, 0x80, 0xdf, 0x0c, 0xee, 0x0d, 0x03, + 0x84, 0x8d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, 0x80, + 0xcb, 0x2a, 0x38, 0x03, 0x0a, 0x06, 0x38, 0x08, 0x46, 0x08, 0x0c, 0x06, + 0x74, 0x0b, 0x1e, 0x03, 0x5a, 0x04, 0x59, 0x09, 0x80, 0x83, 0x18, 0x1c, + 0x0a, 0x16, 0x09, 0x4c, 0x04, 0x80, 0x8a, 0x06, 0xab, 0xa4, 0x0c, 0x17, + 0x04, 0x31, 0xa1, 0x04, 0x81, 0xda, 0x26, 0x07, 0x0c, 0x05, 0x05, 0x80, + 0xa5, 0x11, 0x81, 0x6d, 0x10, 0x78, 0x28, 0x2a, 0x06, 0x4c, 0x04, 0x80, + 0x8d, 0x04, 0x80, 0xbe, 0x03, 0x1b, 0x03, 0x0f, 0x0d, + }; + static constexpr unsigned char normal1[] = { + 0x5e, 0x22, 0x7b, 0x05, 0x03, 0x04, 0x2d, 0x03, 0x66, 0x03, 0x01, 0x2f, + 0x2e, 0x80, 0x82, 0x1d, 0x03, 0x31, 0x0f, 0x1c, 0x04, 0x24, 0x09, 0x1e, + 0x05, 0x2b, 0x05, 0x44, 0x04, 0x0e, 0x2a, 0x80, 0xaa, 0x06, 0x24, 0x04, + 0x24, 0x04, 0x28, 0x08, 0x34, 0x0b, 0x01, 0x80, 0x90, 0x81, 0x37, 0x09, + 0x16, 0x0a, 0x08, 0x80, 0x98, 0x39, 0x03, 0x63, 0x08, 0x09, 0x30, 0x16, + 0x05, 0x21, 0x03, 0x1b, 0x05, 0x01, 0x40, 0x38, 0x04, 0x4b, 0x05, 0x2f, + 0x04, 0x0a, 0x07, 0x09, 0x07, 0x40, 0x20, 0x27, 0x04, 0x0c, 0x09, 0x36, + 0x03, 0x3a, 0x05, 0x1a, 0x07, 0x04, 0x0c, 0x07, 0x50, 0x49, 0x37, 0x33, + 0x0d, 0x33, 0x07, 0x2e, 0x08, 0x0a, 0x81, 0x26, 0x52, 0x4e, 0x28, 0x08, + 0x2a, 0x56, 0x1c, 0x14, 0x17, 0x09, 0x4e, 0x04, 0x1e, 0x0f, 0x43, 0x0e, + 0x19, 0x07, 0x0a, 0x06, 0x48, 0x08, 0x27, 0x09, 0x75, 0x0b, 0x3f, 0x41, + 0x2a, 0x06, 0x3b, 0x05, 0x0a, 0x06, 0x51, 0x06, 0x01, 0x05, 0x10, 0x03, + 0x05, 0x80, 0x8b, 0x62, 0x1e, 0x48, 0x08, 0x0a, 0x80, 0xa6, 0x5e, 0x22, + 0x45, 0x0b, 0x0a, 0x06, 0x0d, 0x13, 0x39, 0x07, 0x0a, 0x36, 0x2c, 0x04, + 0x10, 0x80, 0xc0, 0x3c, 0x64, 0x53, 0x0c, 0x48, 0x09, 0x0a, 0x46, 0x45, + 0x1b, 0x48, 0x08, 0x53, 0x1d, 0x39, 0x81, 0x07, 0x46, 0x0a, 0x1d, 0x03, + 0x47, 0x49, 0x37, 0x03, 0x0e, 0x08, 0x0a, 0x06, 0x39, 0x07, 0x0a, 0x81, + 0x36, 0x19, 0x80, 0xb7, 0x01, 0x0f, 0x32, 0x0d, 0x83, 0x9b, 0x66, 0x75, + 0x0b, 0x80, 0xc4, 0x8a, 0xbc, 0x84, 0x2f, 0x8f, 0xd1, 0x82, 0x47, 0xa1, + 0xb9, 0x82, 0x39, 0x07, 0x2a, 0x04, 0x02, 0x60, 0x26, 0x0a, 0x46, 0x0a, + 0x28, 0x05, 0x13, 0x82, 0xb0, 0x5b, 0x65, 0x4b, 0x04, 0x39, 0x07, 0x11, + 0x40, 0x05, 0x0b, 0x02, 0x0e, 0x97, 0xf8, 0x08, 0x84, 0xd6, 0x2a, 0x09, + 0xa2, 0xf7, 0x81, 0x1f, 0x31, 0x03, 0x11, 0x04, 0x08, 0x81, 0x8c, 0x89, + 0x04, 0x6b, 0x05, 0x0d, 0x03, 0x09, 0x07, 0x10, 0x93, 0x60, 0x80, 0xf6, + 0x0a, 0x73, 0x08, 0x6e, 0x17, 0x46, 0x80, 0x9a, 0x14, 0x0c, 0x57, 0x09, + 0x19, 0x80, 0x87, 0x81, 0x47, 0x03, 0x85, 0x42, 0x0f, 0x15, 0x85, 0x50, + 0x2b, 0x80, 0xd5, 0x2d, 0x03, 0x1a, 0x04, 0x02, 0x81, 0x70, 0x3a, 0x05, + 0x01, 0x85, 0x00, 0x80, 0xd7, 0x29, 0x4c, 0x04, 0x0a, 0x04, 0x02, 0x83, + 0x11, 0x44, 0x4c, 0x3d, 0x80, 0xc2, 0x3c, 0x06, 0x01, 0x04, 0x55, 0x05, + 0x1b, 0x34, 0x02, 0x81, 0x0e, 0x2c, 0x04, 0x64, 0x0c, 0x56, 0x0a, 0x80, + 0xae, 0x38, 0x1d, 0x0d, 0x2c, 0x04, 0x09, 0x07, 0x02, 0x0e, 0x06, 0x80, + 0x9a, 0x83, 0xd8, 0x08, 0x0d, 0x03, 0x0d, 0x03, 0x74, 0x0c, 0x59, 0x07, + 0x0c, 0x14, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, 0x22, 0x4e, + 0x81, 0x54, 0x0c, 0x15, 0x03, 0x03, 0x05, 0x07, 0x09, 0x19, 0x07, 0x07, + 0x09, 0x03, 0x0d, 0x07, 0x29, 0x80, 0xcb, 0x25, 0x0a, 0x84, 0x06, + }; + auto lower = static_cast(cp); + if (cp < 0x10000) { + return is_printable(lower, singletons0, + sizeof(singletons0) / sizeof(*singletons0), + singletons0_lower, normal0, sizeof(normal0)); + } + if (cp < 0x20000) { + return is_printable(lower, singletons1, + sizeof(singletons1) / sizeof(*singletons1), + singletons1_lower, normal1, sizeof(normal1)); + } + if (0x2a6de <= cp && cp < 0x2a700) return false; + if (0x2b735 <= cp && cp < 0x2b740) return false; + if (0x2b81e <= cp && cp < 0x2b820) return false; + if (0x2cea2 <= cp && cp < 0x2ceb0) return false; + if (0x2ebe1 <= cp && cp < 0x2f800) return false; + if (0x2fa1e <= cp && cp < 0x30000) return false; + if (0x3134b <= cp && cp < 0xe0100) return false; + if (0xe01f0 <= cp && cp < 0x110000) return false; + return cp < 0x110000; +} + +} // namespace detail + +FMT_END_NAMESPACE + +#endif // FMT_FORMAT_INL_H_ diff --git a/include/fmt/format.h b/include/fmt/format.h new file mode 100644 index 0000000..92a1d5b --- /dev/null +++ b/include/fmt/format.h @@ -0,0 +1,4232 @@ +/* + 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_ + +#ifndef _LIBCPP_REMOVE_TRANSITIVE_INCLUDES +# define _LIBCPP_REMOVE_TRANSITIVE_INCLUDES +# define FMT_REMOVE_TRANSITIVE_INCLUDES +#endif + +#include "base.h" + +#ifndef FMT_MODULE +# include // std::signbit +# include // std::byte +# include // uint32_t +# include // std::memcpy +# include // std::numeric_limits +# include // std::bad_alloc +# if defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI) +// Workaround for pre gcc 5 libstdc++. +# include // std::allocator_traits +# endif +# include // std::runtime_error +# include // std::string +# include // std::system_error + +// Check FMT_CPLUSPLUS to avoid a warning in MSVC. +# if FMT_HAS_INCLUDE() && FMT_CPLUSPLUS > 201703L +# include // std::bit_cast +# endif + +// libc++ supports string_view in pre-c++17. +# if FMT_HAS_INCLUDE() && \ + (FMT_CPLUSPLUS >= 201703L || defined(_LIBCPP_VERSION)) +# include +# define FMT_USE_STRING_VIEW +# endif + +# if FMT_MSC_VERSION +# include // _BitScanReverse[64], _umul128 +# endif +#endif // FMT_MODULE + +#if defined(FMT_USE_NONTYPE_TEMPLATE_ARGS) +// Use the provided definition. +#elif defined(__NVCOMPILER) +# define FMT_USE_NONTYPE_TEMPLATE_ARGS 0 +#elif FMT_GCC_VERSION >= 903 && FMT_CPLUSPLUS >= 201709L +# define FMT_USE_NONTYPE_TEMPLATE_ARGS 1 +#elif defined(__cpp_nontype_template_args) && \ + __cpp_nontype_template_args >= 201911L +# define FMT_USE_NONTYPE_TEMPLATE_ARGS 1 +#elif FMT_CLANG_VERSION >= 1200 && FMT_CPLUSPLUS >= 202002L +# define FMT_USE_NONTYPE_TEMPLATE_ARGS 1 +#else +# define FMT_USE_NONTYPE_TEMPLATE_ARGS 0 +#endif + +#if defined __cpp_inline_variables && __cpp_inline_variables >= 201606L +# define FMT_INLINE_VARIABLE inline +#else +# define FMT_INLINE_VARIABLE +#endif + +// Check if RTTI is disabled. +#ifdef FMT_USE_RTTI +// Use the provided definition. +#elif defined(__GXX_RTTI) || FMT_HAS_FEATURE(cxx_rtti) || defined(_CPPRTTI) || \ + defined(__INTEL_RTTI__) || defined(__RTTI) +// __RTTI is for EDG compilers. _CPPRTTI is for MSVC. +# define FMT_USE_RTTI 1 +#else +# define FMT_USE_RTTI 0 +#endif + +// Visibility when compiled as a shared library/object. +#if defined(FMT_LIB_EXPORT) || defined(FMT_SHARED) +# define FMT_SO_VISIBILITY(value) FMT_VISIBILITY(value) +#else +# define FMT_SO_VISIBILITY(value) +#endif + +#if FMT_GCC_VERSION || FMT_CLANG_VERSION +# define FMT_NOINLINE __attribute__((noinline)) +#else +# define FMT_NOINLINE +#endif + +namespace std { +template struct iterator_traits> { + using iterator_category = output_iterator_tag; + using value_type = T; + using difference_type = + decltype(static_cast(nullptr) - static_cast(nullptr)); + using pointer = void; + using reference = void; +}; +} // namespace std + +#ifndef FMT_THROW +# if FMT_USE_EXCEPTIONS +# if FMT_MSC_VERSION || defined(__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) \ + ::fmt::detail::assert_fail(__FILE__, __LINE__, (x).what()) +# endif // FMT_USE_EXCEPTIONS +#endif // FMT_THROW + +// 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 + +FMT_BEGIN_NAMESPACE + +template +struct is_contiguous> + : std::true_type {}; + +namespace detail { + +// __builtin_clz is broken in clang with Microsoft codegen: +// https://github.com/fmtlib/fmt/issues/519. +#if !FMT_MSC_VERSION +# 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 + +// Some compilers masquerade as both MSVC and GCC but 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_VERSION && !defined(FMT_BUILTIN_CLZLL) +// Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning. +# ifndef __clang__ +# pragma intrinsic(_BitScanReverse) +# ifdef _WIN64 +# pragma intrinsic(_BitScanReverse64) +# endif +# endif + +inline auto clz(uint32_t x) -> int { + FMT_ASSERT(x != 0, ""); + FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. + unsigned long r = 0; + _BitScanReverse(&r, x); + return 31 ^ static_cast(r); +} +# define FMT_BUILTIN_CLZ(n) detail::clz(n) + +inline auto clzll(uint64_t x) -> int { + FMT_ASSERT(x != 0, ""); + FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. + unsigned long r = 0; +# ifdef _WIN64 + _BitScanReverse64(&r, x); +# else + // Scan the high 32 bits. + if (_BitScanReverse(&r, static_cast(x >> 32))) + return 63 ^ static_cast(r + 32); + // Scan the low 32 bits. + _BitScanReverse(&r, static_cast(x)); +# endif + return 63 ^ static_cast(r); +} +# define FMT_BUILTIN_CLZLL(n) detail::clzll(n) +#endif // FMT_MSC_VERSION && !defined(FMT_BUILTIN_CLZLL) + +FMT_CONSTEXPR inline void abort_fuzzing_if(bool condition) { + ignore_unused(condition); +#ifdef FMT_FUZZ + if (condition) throw std::runtime_error("fuzzing limit reached"); +#endif +} + +#if defined(FMT_USE_STRING_VIEW) +template using std_string_view = std::basic_string_view; +#else +template struct std_string_view {}; +#endif + +template struct string_literal { + static constexpr Char value[sizeof...(C)] = {C...}; + constexpr operator basic_string_view() const { + return {value, sizeof...(C)}; + } +}; +#if FMT_CPLUSPLUS < 201703L +template +constexpr Char string_literal::value[sizeof...(C)]; +#endif + +// Implementation of std::bit_cast for pre-C++20. +template +FMT_CONSTEXPR20 auto bit_cast(const From& from) -> To { +#ifdef __cpp_lib_bit_cast + if (is_constant_evaluated()) return std::bit_cast(from); +#endif + auto to = To(); + // The cast suppresses a bogus -Wclass-memaccess on GCC. + std::memcpy(static_cast(&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 +} + +class uint128_fallback { + private: + uint64_t lo_, hi_; + + public: + constexpr uint128_fallback(uint64_t hi, uint64_t lo) : lo_(lo), hi_(hi) {} + constexpr uint128_fallback(uint64_t value = 0) : lo_(value), hi_(0) {} + + constexpr auto high() const noexcept -> uint64_t { return hi_; } + constexpr auto low() const noexcept -> uint64_t { return lo_; } + + template ::value)> + constexpr explicit operator T() const { + return static_cast(lo_); + } + + friend constexpr auto operator==(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> bool { + return lhs.hi_ == rhs.hi_ && lhs.lo_ == rhs.lo_; + } + friend constexpr auto operator!=(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> bool { + return !(lhs == rhs); + } + friend constexpr auto operator>(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> bool { + return lhs.hi_ != rhs.hi_ ? lhs.hi_ > rhs.hi_ : lhs.lo_ > rhs.lo_; + } + friend constexpr auto operator|(const uint128_fallback& lhs, + const uint128_fallback& rhs) + -> uint128_fallback { + return {lhs.hi_ | rhs.hi_, lhs.lo_ | rhs.lo_}; + } + friend constexpr auto operator&(const uint128_fallback& lhs, + const uint128_fallback& rhs) + -> uint128_fallback { + return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_}; + } + friend constexpr auto operator~(const uint128_fallback& n) + -> uint128_fallback { + return {~n.hi_, ~n.lo_}; + } + friend FMT_CONSTEXPR auto operator+(const uint128_fallback& lhs, + const uint128_fallback& rhs) + -> uint128_fallback { + auto result = uint128_fallback(lhs); + result += rhs; + return result; + } + friend FMT_CONSTEXPR auto operator*(const uint128_fallback& lhs, uint32_t rhs) + -> uint128_fallback { + FMT_ASSERT(lhs.hi_ == 0, ""); + uint64_t hi = (lhs.lo_ >> 32) * rhs; + uint64_t lo = (lhs.lo_ & ~uint32_t()) * rhs; + uint64_t new_lo = (hi << 32) + lo; + return {(hi >> 32) + (new_lo < lo ? 1 : 0), new_lo}; + } + friend constexpr auto operator-(const uint128_fallback& lhs, uint64_t rhs) + -> uint128_fallback { + return {lhs.hi_ - (lhs.lo_ < rhs ? 1 : 0), lhs.lo_ - rhs}; + } + FMT_CONSTEXPR auto operator>>(int shift) const -> uint128_fallback { + if (shift == 64) return {0, hi_}; + if (shift > 64) return uint128_fallback(0, hi_) >> (shift - 64); + return {hi_ >> shift, (hi_ << (64 - shift)) | (lo_ >> shift)}; + } + FMT_CONSTEXPR auto operator<<(int shift) const -> uint128_fallback { + if (shift == 64) return {lo_, 0}; + if (shift > 64) return uint128_fallback(lo_, 0) << (shift - 64); + return {hi_ << shift | (lo_ >> (64 - shift)), (lo_ << shift)}; + } + FMT_CONSTEXPR auto operator>>=(int shift) -> uint128_fallback& { + return *this = *this >> shift; + } + FMT_CONSTEXPR void operator+=(uint128_fallback n) { + uint64_t new_lo = lo_ + n.lo_; + uint64_t new_hi = hi_ + n.hi_ + (new_lo < lo_ ? 1 : 0); + FMT_ASSERT(new_hi >= hi_, ""); + lo_ = new_lo; + hi_ = new_hi; + } + FMT_CONSTEXPR void operator&=(uint128_fallback n) { + lo_ &= n.lo_; + hi_ &= n.hi_; + } + + FMT_CONSTEXPR20 auto operator+=(uint64_t n) noexcept -> uint128_fallback& { + if (is_constant_evaluated()) { + lo_ += n; + hi_ += (lo_ < n ? 1 : 0); + return *this; + } +#if FMT_HAS_BUILTIN(__builtin_addcll) && !defined(__ibmxl__) + unsigned long long carry; + lo_ = __builtin_addcll(lo_, n, 0, &carry); + hi_ += carry; +#elif FMT_HAS_BUILTIN(__builtin_ia32_addcarryx_u64) && !defined(__ibmxl__) + unsigned long long result; + auto carry = __builtin_ia32_addcarryx_u64(0, lo_, n, &result); + lo_ = result; + hi_ += carry; +#elif defined(_MSC_VER) && defined(_M_X64) + auto carry = _addcarry_u64(0, lo_, n, &lo_); + _addcarry_u64(carry, hi_, 0, &hi_); +#else + lo_ += n; + hi_ += (lo_ < n ? 1 : 0); +#endif + return *this; + } +}; + +using uint128_t = conditional_t; + +#ifdef UINTPTR_MAX +using uintptr_t = ::uintptr_t; +#else +using uintptr_t = uint128_t; +#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 128; } + +// A heterogeneous bit_cast used for converting 96-bit long double to uint128_t +// and 128-bit pointers to uint128_fallback. +template sizeof(From))> +inline auto bit_cast(const From& from) -> To { + constexpr auto size = static_cast(sizeof(From) / sizeof(unsigned short)); + struct data_t { + unsigned short value[static_cast(size)]; + } data = bit_cast(from); + auto result = To(); + if (const_check(is_big_endian())) { + for (int i = 0; i < size; ++i) + result = (result << num_bits()) | data.value[i]; + } else { + for (int i = size - 1; i >= 0; --i) + result = (result << num_bits()) | data.value[i]; + } + return result; +} + +template +FMT_CONSTEXPR20 inline auto countl_zero_fallback(UInt n) -> int { + int lz = 0; + constexpr UInt msb_mask = static_cast(1) << (num_bits() - 1); + for (; (n & msb_mask) == 0; n <<= 1) lz++; + return lz; +} + +FMT_CONSTEXPR20 inline auto countl_zero(uint32_t n) -> int { +#ifdef FMT_BUILTIN_CLZ + if (!is_constant_evaluated()) return FMT_BUILTIN_CLZ(n); +#endif + return countl_zero_fallback(n); +} + +FMT_CONSTEXPR20 inline auto countl_zero(uint64_t n) -> int { +#ifdef FMT_BUILTIN_CLZLL + if (!is_constant_evaluated()) return FMT_BUILTIN_CLZLL(n); +#endif + return countl_zero_fallback(n); +} + +FMT_INLINE void assume(bool condition) { + (void)condition; +#if FMT_HAS_BUILTIN(__builtin_assume) && !FMT_ICC_VERSION + __builtin_assume(condition); +#elif FMT_GCC_VERSION + if (!condition) __builtin_unreachable(); +#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&& + is_contiguous::value)> +#if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION +__attribute__((no_sanitize("undefined"))) +#endif +FMT_CONSTEXPR20 inline auto +reserve(OutputIt it, size_t n) -> typename OutputIt::value_type* { + auto& c = get_container(it); + size_t size = c.size(); + c.resize(size + n); + return &c[size]; +} + +template +FMT_CONSTEXPR20 inline auto reserve(basic_appender it, size_t n) + -> basic_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 +FMT_CONSTEXPR20 auto to_pointer(basic_appender it, size_t n) -> T* { + buffer& buf = get_container(it); + buf.try_reserve(buf.size() + n); + auto size = buf.size(); + if (buf.capacity() < size + n) return nullptr; + buf.try_resize(size + n); + return buf.data() + size; +} + +template ::value&& + is_contiguous::value)> +inline auto base_iterator(OutputIt it, + typename OutputIt::container_type::value_type*) + -> OutputIt { + 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; +} + +template +FMT_CONSTEXPR FMT_NOINLINE auto copy_noinline(InputIt begin, InputIt end, + OutputIt out) -> OutputIt { + return copy(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 = "\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" + [static_cast(*s) >> 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. + const char* next = s + len + !len; + + using uchar = unsigned char; + + // Assume a four-byte character and load four bytes. Unused bits are + // shifted out. + *c = uint32_t(uchar(s[0]) & masks[len]) << 18; + *c |= uint32_t(uchar(s[1]) & 0x3f) << 12; + *c |= uint32_t(uchar(s[2]) & 0x3f) << 6; + *c |= uint32_t(uchar(s[3]) & 0x3f) << 0; + *c >>= shiftc[len]; + + // Accumulate the various error conditions. + *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 FMT_INLINE_VARIABLE 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, error ? 1 : to_unsigned(end - buf_ptr))); + return result ? (error ? buf_ptr + 1 : 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; + } + } + auto num_chars_left = to_unsigned(s.data() + s.size() - p); + if (num_chars_left == 0) return; + + // Suppress bogus -Wstringop-overflow. + if (FMT_GCC_VERSION) num_chars_left &= 3; + char buf[2 * block_size - 1] = {}; + copy(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 auto compute_width(string_view s) -> size_t { + 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 += 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; + } + }; + // We could avoid branches by using utf8_decode directly. + for_each_codepoint(s, count_code_points{&num_code_points}); + return num_code_points; +} + +template +inline auto code_point_index(basic_string_view s, size_t n) -> size_t { + return min_of(n, s.size()); +} + +// Calculates the index of the nth code point in a UTF-8 string. +inline auto code_point_index(string_view s, size_t n) -> size_t { + size_t result = s.size(); + const char* begin = s.begin(); + for_each_codepoint(s, [begin, &n, &result](uint32_t, string_view sv) { + if (n != 0) { + --n; + return true; + } + result = to_unsigned(sv.begin() - begin); + return false; + }); + return result; +} + +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>; + +template +using is_integer = + bool_constant::value && !std::is_same::value && + !std::is_same::value && + !std::is_same::value>; + +#if defined(FMT_USE_FLOAT128) +// Use the provided definition. +#elif FMT_CLANG_VERSION && FMT_HAS_INCLUDE() +# define FMT_USE_FLOAT128 1 +#elif FMT_GCC_VERSION && defined(_GLIBCXX_USE_FLOAT128) && \ + !defined(__STRICT_ANSI__) +# define FMT_USE_FLOAT128 1 +#else +# define FMT_USE_FLOAT128 0 +#endif +#if FMT_USE_FLOAT128 +using float128 = __float128; +#else +struct float128 {}; +#endif + +template using is_float128 = std::is_same; + +template +using is_floating_point = + bool_constant::value || is_float128::value>; + +template ::value> +struct is_fast_float : bool_constant::is_iec559 && + sizeof(T) <= sizeof(double)> {}; +template struct is_fast_float : std::false_type {}; + +template +using is_double_double = bool_constant::digits == 106>; + +#ifndef FMT_USE_FULL_CACHE_DRAGONBOX +# define FMT_USE_FULL_CACHE_DRAGONBOX 0 +#endif + +// An allocator that uses malloc/free to allow removing dependency on the C++ +// standard libary runtime. +template struct allocator { + using value_type = T; + + T* allocate(size_t n) { + FMT_ASSERT(n <= max_value() / sizeof(T), ""); + T* p = static_cast(malloc(n * sizeof(T))); + if (!p) FMT_THROW(std::bad_alloc()); + return p; + } + + void deallocate(T* p, size_t) { free(p); } +}; + +} // namespace detail + +FMT_BEGIN_EXPORT + +// The number of characters to store in the basic_memory_buffer object itself +// to avoid dynamic memory allocation. +enum { inline_buffer_size = 500 }; + +/** + * A dynamically growing memory buffer for trivially copyable/constructible + * types with the first `SIZE` elements stored in the object itself. Most + * commonly used via the `memory_buffer` alias for `char`. + * + * **Example**: + * + * auto out = fmt::memory_buffer(); + * fmt::format_to(std::back_inserter(out), "The answer is {}.", 42); + * + * This will append "The answer is 42." to `out`. The buffer content can be + * converted to `std::string` with `to_string(out)`. + */ +template > +class basic_memory_buffer : public detail::buffer { + private: + T store_[SIZE]; + + // Don't inherit from Allocator to avoid generating type_info for it. + FMT_NO_UNIQUE_ADDRESS Allocator alloc_; + + // Deallocate memory allocated by the buffer. + FMT_CONSTEXPR20 void deallocate() { + T* data = this->data(); + if (data != store_) alloc_.deallocate(data, this->capacity()); + } + + static FMT_CONSTEXPR20 void grow(detail::buffer& buf, size_t size) { + detail::abort_fuzzing_if(size > 5000); + auto& self = static_cast(buf); + const size_t max_size = + std::allocator_traits::max_size(self.alloc_); + size_t old_capacity = buf.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 = max_of(size, max_size); + T* old_data = buf.data(); + T* new_data = self.alloc_.allocate(new_capacity); + // Suppress a bogus -Wstringop-overflow in gcc 13.1 (#3481). + detail::assume(buf.size() <= new_capacity); + // The following code doesn't throw, so the raw pointer above doesn't leak. + memcpy(new_data, old_data, buf.size() * sizeof(T)); + self.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 != self.store_) self.alloc_.deallocate(old_data, old_capacity); + } + + public: + using value_type = T; + using const_reference = const T&; + + FMT_CONSTEXPR explicit basic_memory_buffer( + const Allocator& alloc = Allocator()) + : detail::buffer(grow), 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); + detail::copy(other.store_, other.store_ + size, store_); + } else { + this->set(data, capacity); + // Set pointer to the inline array so that delete is not called + // when deallocating. + other.set(other.store_, 0); + other.clear(); + } + this->resize(size); + } + + public: + /// Constructs a `basic_memory_buffer` object moving the content of the other + /// object to it. + FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer&& other) noexcept + : detail::buffer(grow) { + move(other); + } + + /// Moves the content of the other `basic_memory_buffer` object to this one. + auto operator=(basic_memory_buffer&& other) 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_CONSTEXPR 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); } + + using detail::buffer::append; + template + FMT_CONSTEXPR20 void append(const ContiguousRange& range) { + append(range.data(), range.data() + range.size()); + } +}; + +using memory_buffer = basic_memory_buffer; + +template +FMT_NODISCARD auto to_string(const basic_memory_buffer& buf) + -> std::string { + auto size = buf.size(); + detail::assume(size < std::string().max_size()); + return {buf.data(), size}; +} + +// A writer to a buffered stream. It doesn't own the underlying stream. +class writer { + private: + detail::buffer* buf_; + + // We cannot create a file buffer in advance because any write to a FILE may + // invalidate it. + FILE* file_; + + public: + inline writer(FILE* f) : buf_(nullptr), file_(f) {} + inline writer(detail::buffer& buf) : buf_(&buf) {} + + /// Formats `args` according to specifications in `fmt` and writes the + /// output to the file. + template void print(format_string fmt, T&&... args) { + if (buf_) + fmt::format_to(appender(*buf_), fmt, std::forward(args)...); + else + fmt::print(file_, fmt, std::forward(args)...); + } +}; + +class string_buffer { + private: + std::string str_; + detail::container_buffer buf_; + + public: + inline string_buffer() : buf_(str_) {} + + inline operator writer() { return buf_; } + inline std::string& str() { return str_; } +}; + +template +struct is_contiguous> : std::true_type { +}; + +// Suppress a misleading warning in older versions of clang. +FMT_PRAGMA_CLANG(diagnostic ignored "-Wweak-vtables") + +/// An error reported from a formatting function. +class FMT_SO_VISIBILITY("default") format_error : public std::runtime_error { + public: + using std::runtime_error::runtime_error; +}; + +class loc_value; + +FMT_END_EXPORT +namespace detail { +FMT_API auto write_console(int fd, string_view text) -> bool; +FMT_API void print(FILE*, string_view); +} // namespace detail + +namespace detail { +template struct fixed_string { + FMT_CONSTEXPR20 fixed_string(const Char (&s)[N]) { + detail::copy(static_cast(s), s + N, + data); + } + Char data[N] = {}; +}; + +// Converts a compile-time string to basic_string_view. +FMT_EXPORT 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)}; +} +FMT_EXPORT template +constexpr auto compile_string_to_view(basic_string_view s) + -> basic_string_view { + return s; +} + +// 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)> +constexpr auto is_negative(T value) -> bool { + return value < 0; +} +template ::value)> +constexpr auto is_negative(T) -> bool { + return false; +} + +// 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. +// GCC generates slightly better code when value is pointer-size. +inline auto digits2(size_t value) -> const char* { + // Align data since unaligned access may be slower when crossing a + // hardware-specific boundary. + alignas(2) static const char data[] = + "0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"; + return &data[value * 2]; +} + +template constexpr auto getsign(sign s) -> Char { + return static_cast(((' ' << 24) | ('+' << 16) | ('-' << 8)) >> + (static_cast(s) * 8)); +} + +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_opt 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() && !FMT_OPTIMIZE_SIZE) 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 (!is_constant_evaluated() && 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); +} + +#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() && !FMT_OPTIMIZE_SIZE) return do_count_digits(n); +#endif + return count_digits_fallback(n); +} + +template constexpr auto digits10() noexcept -> int { + return std::numeric_limits::digits10; +} +template <> constexpr auto digits10() noexcept -> int { return 38; } +template <> constexpr auto digits10() 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); +} + +#ifndef FMT_HEADER_ONLY +FMT_BEGIN_EXPORT +extern template FMT_API auto thousands_sep_impl(locale_ref) + -> thousands_sep_result; +extern template FMT_API auto thousands_sep_impl(locale_ref) + -> thousands_sep_result; +extern template FMT_API auto decimal_point_impl(locale_ref) -> char; +extern template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t; +FMT_END_EXPORT +#endif // FMT_HEADER_ONLY + +// 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; +} + +// Writes a two-digit value to out. +template +FMT_CONSTEXPR20 FMT_INLINE void write2digits(Char* out, size_t value) { + if (!is_constant_evaluated() && std::is_same::value && + !FMT_OPTIMIZE_SIZE) { + memcpy(out, digits2(value), 2); + return; + } + *out++ = static_cast('0' + value / 10); + *out = static_cast('0' + value % 10); +} + +// Formats a decimal unsigned integer value writing to out pointing to a buffer +// of specified size. The caller must ensure that the buffer is large enough. +template +FMT_CONSTEXPR20 auto do_format_decimal(Char* out, UInt value, int size) + -> Char* { + FMT_ASSERT(size >= count_digits(value), "invalid digit count"); + unsigned n = to_unsigned(size); + 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. + n -= 2; + write2digits(out + n, static_cast(value % 100)); + value /= 100; + } + if (value >= 10) { + n -= 2; + write2digits(out + n, static_cast(value)); + } else { + out[--n] = static_cast('0' + value); + } + return out + n; +} + +template +FMT_CONSTEXPR FMT_INLINE auto format_decimal(Char* out, UInt value, + int num_digits) -> Char* { + do_format_decimal(out, value, num_digits); + return out + num_digits; +} + +template ::value)> +FMT_CONSTEXPR auto format_decimal(OutputIt out, UInt value, int num_digits) + -> OutputIt { + if (auto ptr = to_pointer(out, to_unsigned(num_digits))) { + do_format_decimal(ptr, value, num_digits); + return out; + } + // Buffer is large enough to hold all digits (digits10 + 1). + char buffer[digits10() + 1]; + if (is_constant_evaluated()) fill_n(buffer, sizeof(buffer), '\0'); + do_format_decimal(buffer, value, num_digits); + return copy_noinline(buffer, buffer + num_digits, out); +} + +template +FMT_CONSTEXPR auto do_format_base2e(int base_bits, Char* out, UInt value, + int size, bool upper = false) -> Char* { + out += size; + do { + const char* digits = upper ? "0123456789ABCDEF" : "0123456789abcdef"; + unsigned digit = static_cast(value & ((1 << base_bits) - 1)); + *--out = static_cast(base_bits < 4 ? static_cast('0' + digit) + : digits[digit]); + } while ((value >>= base_bits) != 0); + return out; +} + +// Formats an unsigned integer in the power of two base (binary, octal, hex). +template +FMT_CONSTEXPR auto format_base2e(int base_bits, Char* out, UInt value, + int num_digits, bool upper = false) -> Char* { + do_format_base2e(base_bits, out, value, num_digits, upper); + return out + num_digits; +} + +template ::value)> +FMT_CONSTEXPR inline auto format_base2e(int base_bits, OutputIt out, UInt value, + int num_digits, bool upper = false) + -> OutputIt { + if (auto ptr = to_pointer(out, to_unsigned(num_digits))) { + format_base2e(base_bits, ptr, value, num_digits, upper); + return out; + } + // Make buffer large enough for any base. + char buffer[num_bits()]; + if (is_constant_evaluated()) fill_n(buffer, sizeof(buffer), '\0'); + format_base2e(base_bits, buffer, value, num_digits, upper); + return detail::copy_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); + inline operator basic_string_view() const { + return {&buffer_[0], size()}; + } + inline auto size() const -> size_t { return buffer_.size() - 1; } + inline auto c_str() const -> const wchar_t* { return &buffer_[0]; } + inline auto str() const -> std::wstring { return {&buffer_[0], size()}; } +}; + +enum class to_utf8_error_policy { abort, replace }; + +// A converter from UTF-16/UTF-32 (host endian) to UTF-8. +template class to_utf8 { + private: + Buffer buffer_; + + public: + to_utf8() {} + explicit to_utf8(basic_string_view s, + to_utf8_error_policy policy = to_utf8_error_policy::abort) { + static_assert(sizeof(WChar) == 2 || sizeof(WChar) == 4, + "Expect utf16 or utf32"); + if (!convert(s, policy)) + FMT_THROW(std::runtime_error(sizeof(WChar) == 2 ? "invalid utf16" + : "invalid utf32")); + } + operator string_view() const { return string_view(&buffer_[0], size()); } + auto size() const -> size_t { return buffer_.size() - 1; } + auto c_str() const -> const char* { return &buffer_[0]; } + auto str() const -> std::string { return std::string(&buffer_[0], size()); } + + // Performs conversion returning a bool instead of throwing exception on + // conversion error. This method may still throw in case of memory allocation + // error. + auto convert(basic_string_view s, + to_utf8_error_policy policy = to_utf8_error_policy::abort) + -> bool { + if (!convert(buffer_, s, policy)) return false; + buffer_.push_back(0); + return true; + } + static auto convert(Buffer& buf, basic_string_view s, + to_utf8_error_policy policy = to_utf8_error_policy::abort) + -> bool { + for (auto p = s.begin(); p != s.end(); ++p) { + uint32_t c = static_cast(*p); + if (sizeof(WChar) == 2 && c >= 0xd800 && c <= 0xdfff) { + // Handle a surrogate pair. + ++p; + if (p == s.end() || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) { + if (policy == to_utf8_error_policy::abort) return false; + buf.append(string_view("\xEF\xBF\xBD")); + --p; + continue; + } else { + 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 { + return false; + } + } + return true; + } +}; + +// Computes 128-bit result of multiplication of two 64-bit unsigned integers. +inline auto umul128(uint64_t x, uint64_t y) noexcept -> uint128_fallback { +#if FMT_USE_INT128 + auto p = static_cast(x) * static_cast(y); + return {static_cast(p >> 64), static_cast(p)}; +#elif defined(_MSC_VER) && defined(_M_X64) + auto hi = uint64_t(); + auto lo = _umul128(x, y, &hi); + return {hi, lo}; +#else + const uint64_t mask = static_cast(max_value()); + + 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 +} + +namespace dragonbox { +// Computes floor(log10(pow(2, e))) for e in [-2620, 2620] using the method from +// https://fmt.dev/papers/Dragonbox.pdf#page=28, section 6.1. +inline auto floor_log10_pow2(int e) noexcept -> int { + FMT_ASSERT(e <= 2620 && e >= -2620, "too large exponent"); + static_assert((-1 >> 1) == -1, "right shift is not arithmetic"); + return (e * 315653) >> 20; +} + +inline auto floor_log2_pow10(int e) noexcept -> int { + FMT_ASSERT(e <= 1233 && e >= -1233, "too large exponent"); + return (e * 1741647) >> 19; +} + +// Computes upper 64 bits of multiplication of two 64-bit unsigned integers. +inline auto umul128_upper64(uint64_t x, uint64_t y) noexcept -> uint64_t { +#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 128 bits of multiplication of a 64-bit unsigned integer and a +// 128-bit unsigned integer. +inline auto umul192_upper128(uint64_t x, uint128_fallback y) noexcept + -> uint128_fallback { + uint128_fallback r = umul128(x, y.high()); + r += umul128_upper64(x, y.low()); + return r; +} + +FMT_API auto get_cached_power(int k) noexcept -> uint128_fallback; + +// Type-specific information that Dragonbox uses. +template struct float_info; + +template <> struct float_info { + using carrier_uint = uint32_t; + static const int exponent_bits = 8; + 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 shorter_interval_tie_lower_threshold = -35; + static const int shorter_interval_tie_upper_threshold = -35; +}; + +template <> struct float_info { + using carrier_uint = uint64_t; + static const int exponent_bits = 11; + 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 = 341; + static const int shorter_interval_tie_lower_threshold = -77; + static const int shorter_interval_tie_upper_threshold = -77; +}; + +// An 80- or 128-bit floating point number. +template +struct float_info::digits == 64 || + std::numeric_limits::digits == 113 || + is_float128::value>> { + using carrier_uint = detail::uint128_t; + static const int exponent_bits = 15; +}; + +// A double-double floating point number. +template +struct float_info::value>> { + using carrier_uint = detail::uint128_t; +}; + +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) noexcept -> decimal_fp; +} // namespace dragonbox + +// Returns true iff Float has the implicit bit which is not stored. +template constexpr auto has_implicit_bit() -> bool { + // An 80-bit FP number has a 64-bit significand an no implicit bit. + return std::numeric_limits::digits != 64; +} + +// Returns the number of significand bits stored in Float. The implicit bit is +// not counted since it is not stored. +template constexpr auto num_significand_bits() -> int { + // std::numeric_limits may not support __float128. + return is_float128() ? 112 + : (std::numeric_limits::digits - + (has_implicit_bit() ? 1 : 0)); +} + +template +constexpr auto exponent_mask() -> + typename dragonbox::float_info::carrier_uint { + using float_uint = typename dragonbox::float_info::carrier_uint; + return ((float_uint(1) << dragonbox::float_info::exponent_bits) - 1) + << num_significand_bits(); +} +template constexpr auto exponent_bias() -> int { + // std::numeric_limits may not support __float128. + return is_float128() ? 16383 + : std::numeric_limits::max_exponent - 1; +} + +// Writes the exponent exp in the form "[+-]d{2,3}" to buffer. +template +FMT_CONSTEXPR auto write_exponent(int exp, OutputIt out) -> OutputIt { + FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range"); + if (exp < 0) { + *out++ = static_cast('-'); + exp = -exp; + } else { + *out++ = static_cast('+'); + } + auto uexp = static_cast(exp); + if (is_constant_evaluated()) { + if (uexp < 10) *out++ = '0'; + return format_decimal(out, uexp, count_digits(uexp)); + } + if (uexp >= 100u) { + const char* top = digits2(uexp / 100); + if (uexp >= 1000u) *out++ = static_cast(top[0]); + *out++ = static_cast(top[1]); + uexp %= 100; + } + const char* d = digits2(uexp); + *out++ = static_cast(d[0]); + *out++ = static_cast(d[1]); + return out; +} + +// A floating-point number f * pow(2, e) where F is an unsigned type. +template struct basic_fp { + F f; + int e; + + static constexpr const int num_significand_bits = + static_cast(sizeof(F) * num_bits()); + + constexpr basic_fp() : f(0), e(0) {} + constexpr basic_fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {} + + // Constructs fp from an IEEE754 floating-point number. + template FMT_CONSTEXPR basic_fp(Float n) { assign(n); } + + // Assigns n to this and return true iff predecessor is closer than successor. + template ::value)> + FMT_CONSTEXPR auto assign(Float n) -> bool { + static_assert(std::numeric_limits::digits <= 113, "unsupported FP"); + // Assume Float is in the format [sign][exponent][significand]. + using carrier_uint = typename dragonbox::float_info::carrier_uint; + const auto num_float_significand_bits = + detail::num_significand_bits(); + const auto implicit_bit = carrier_uint(1) << num_float_significand_bits; + const auto significand_mask = implicit_bit - 1; + auto u = bit_cast(n); + f = static_cast(u & significand_mask); + auto 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). + auto is_predecessor_closer = f == 0 && biased_e > 1; + if (biased_e == 0) + biased_e = 1; // Subnormals use biased exponent 1 (min exponent). + else if (has_implicit_bit()) + f += static_cast(implicit_bit); + e = biased_e - exponent_bias() - num_float_significand_bits; + if (!has_implicit_bit()) ++e; + return is_predecessor_closer; + } + + template ::value)> + FMT_CONSTEXPR auto assign(Float n) -> bool { + static_assert(std::numeric_limits::is_iec559, "unsupported FP"); + return assign(static_cast(n)); + } +}; + +using fp = basic_fp; + +// Normalizes the value converted from double and multiplied by (1 << SHIFT). +template +FMT_CONSTEXPR auto normalize(basic_fp value) -> basic_fp { + // Handle subnormals. + const auto implicit_bit = F(1) << 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 = basic_fp::num_significand_bits - + num_significand_bits() - SHIFT - 1; + value.f <<= offset; + value.e -= offset; + return value; +} + +// Computes lhs * rhs / pow(2, 64) rounded to nearest with half-up tie breaking. +FMT_CONSTEXPR inline auto multiply(uint64_t lhs, uint64_t rhs) -> uint64_t { +#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 auto operator*(fp x, fp y) -> fp { + return {multiply(x.f, y.f), x.e + y.e + 64}; +} + +template () == num_bits()> +using convert_float_result = + conditional_t::value || doublish, double, T>; + +template +constexpr auto convert_float(T value) -> convert_float_result { + return static_cast>(value); +} + +template +FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, + const basic_specs& specs) -> OutputIt { + auto fill_size = specs.fill_size(); + if (fill_size == 1) return detail::fill_n(it, n, specs.fill_unit()); + if (const Char* data = specs.fill()) { + for (size_t i = 0; i < n; ++i) it = copy(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 format_specs& specs, + size_t size, size_t width, F&& f) -> OutputIt { + static_assert(default_align == align::left || default_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 = + default_align == align::left ? "\x1f\x1f\x00\x01" : "\x00\x1f\x00\x01"; + size_t left_padding = padding >> shifts[static_cast(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); + it = f(it); + if (right_padding != 0) it = fill(it, right_padding, specs); + return base_iterator(out, it); +} + +template +constexpr auto write_padded(OutputIt out, const 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 format_specs& specs = {}) -> OutputIt { + return write_padded( + out, specs, bytes.size(), [bytes](reserve_iterator it) { + const char* data = bytes.data(); + return copy(data, data + bytes.size(), it); + }); +} + +template +auto write_ptr(OutputIt out, UIntPtr value, const 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_base2e(4, it, value, num_digits); + }; + return specs ? write_padded(out, *specs, size, write) + : base_iterator(out, write(reserve(out, size))); +} + +// Returns true iff the code point cp is printable. +FMT_API auto is_printable(uint32_t cp) -> bool; + +inline auto needs_escape(uint32_t cp) -> bool { + if (cp < 0x20 || cp == 0x7f || cp == '"' || cp == '\\') return true; + if (const_check(FMT_OPTIMIZE_SIZE > 1)) return false; + return !is_printable(cp); +} + +template struct find_escape_result { + const Char* begin; + const Char* end; + uint32_t cp; +}; + +template +auto find_escape(const Char* begin, const Char* end) + -> find_escape_result { + for (; begin != end; ++begin) { + uint32_t cp = static_cast>(*begin); + if (const_check(sizeof(Char) == 1) && cp >= 0x80) continue; + if (needs_escape(cp)) return {begin, begin + 1, cp}; + } + return {begin, nullptr, 0}; +} + +inline auto find_escape(const char* begin, const char* end) + -> find_escape_result { + if (const_check(!use_utf8)) return find_escape(begin, end); + auto result = find_escape_result{end, nullptr, 0}; + for_each_codepoint(string_view(begin, to_unsigned(end - begin)), + [&](uint32_t cp, string_view sv) { + if (needs_escape(cp)) { + result = {sv.begin(), sv.end(), cp}; + return false; + } + return true; + }); + return result; +} + +template +auto write_codepoint(OutputIt out, char prefix, uint32_t cp) -> OutputIt { + *out++ = static_cast('\\'); + *out++ = static_cast(prefix); + Char buf[width]; + fill_n(buf, width, static_cast('0')); + format_base2e(4, buf, cp, width); + return copy(buf, buf + width, out); +} + +template +auto write_escaped_cp(OutputIt out, const find_escape_result& escape) + -> OutputIt { + auto c = static_cast(escape.cp); + switch (escape.cp) { + case '\n': + *out++ = static_cast('\\'); + c = static_cast('n'); + break; + case '\r': + *out++ = static_cast('\\'); + c = static_cast('r'); + break; + case '\t': + *out++ = static_cast('\\'); + c = static_cast('t'); + break; + case '"': FMT_FALLTHROUGH; + case '\'': FMT_FALLTHROUGH; + case '\\': *out++ = static_cast('\\'); break; + default: + if (escape.cp < 0x100) return write_codepoint<2, Char>(out, 'x', escape.cp); + if (escape.cp < 0x10000) + return write_codepoint<4, Char>(out, 'u', escape.cp); + if (escape.cp < 0x110000) + return write_codepoint<8, Char>(out, 'U', escape.cp); + for (Char escape_char : basic_string_view( + escape.begin, to_unsigned(escape.end - escape.begin))) { + out = write_codepoint<2, Char>(out, 'x', + static_cast(escape_char) & 0xFF); + } + return out; + } + *out++ = c; + return out; +} + +template +auto write_escaped_string(OutputIt out, basic_string_view str) + -> OutputIt { + *out++ = static_cast('"'); + auto begin = str.begin(), end = str.end(); + do { + auto escape = find_escape(begin, end); + out = copy(begin, escape.begin, out); + begin = escape.end; + if (!begin) break; + out = write_escaped_cp(out, escape); + } while (begin != end); + *out++ = static_cast('"'); + return out; +} + +template +auto write_escaped_char(OutputIt out, Char v) -> OutputIt { + Char v_array[1] = {v}; + *out++ = static_cast('\''); + if ((needs_escape(static_cast(v)) && v != static_cast('"')) || + v == static_cast('\'')) { + out = write_escaped_cp(out, + find_escape_result{v_array, v_array + 1, + static_cast(v)}); + } else { + *out++ = v; + } + *out++ = static_cast('\''); + return out; +} + +template +FMT_CONSTEXPR auto write_char(OutputIt out, Char value, + const format_specs& specs) -> OutputIt { + bool is_debug = specs.type() == presentation_type::debug; + return write_padded(out, specs, 1, [=](reserve_iterator it) { + if (is_debug) return write_escaped_char(it, value); + *it++ = value; + return it; + }); +} +template +FMT_CONSTEXPR auto write(OutputIt out, Char value, const format_specs& specs, + locale_ref loc = {}) -> OutputIt { + // char is formatted as unsigned char for consistency across platforms. + using unsigned_type = + conditional_t::value, unsigned char, unsigned>; + return check_char_specs(specs) + ? write_char(out, value, specs) + : write(out, static_cast(value), specs, loc); +} + +template class digit_grouping { + private: + std::string grouping_; + std::basic_string thousands_sep_; + + struct next_state { + std::string::const_iterator group; + int pos; + }; + auto initial_state() const -> next_state { return {grouping_.begin(), 0}; } + + // Returns the next digit group separator position. + auto next(next_state& state) const -> int { + if (thousands_sep_.empty()) return max_value(); + if (state.group == grouping_.end()) return state.pos += grouping_.back(); + if (*state.group <= 0 || *state.group == max_value()) + return max_value(); + state.pos += *state.group++; + return state.pos; + } + + public: + template ::value)> + explicit digit_grouping(Locale loc, bool localized = true) { + if (!localized) return; + auto sep = thousands_sep(loc); + grouping_ = sep.grouping; + if (sep.thousands_sep) thousands_sep_.assign(1, sep.thousands_sep); + } + digit_grouping(std::string grouping, std::basic_string sep) + : grouping_(std::move(grouping)), thousands_sep_(std::move(sep)) {} + + auto has_separator() const -> bool { return !thousands_sep_.empty(); } + + auto count_separators(int num_digits) const -> int { + 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 + auto apply(Out out, basic_string_view digits) const -> Out { + 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 = copy(thousands_sep_.data(), + thousands_sep_.data() + thousands_sep_.size(), out); + --sep_index; + } + *out++ = static_cast(digits[to_unsigned(i)]); + } + return out; + } +}; + +FMT_CONSTEXPR inline void prefix_append(unsigned& prefix, unsigned value) { + prefix |= prefix != 0 ? value << 8 : value; + prefix += (1u + (value > 0xff ? 1 : 0)) << 24; +} + +// Writes a decimal integer with digit grouping. +template +auto write_int(OutputIt out, UInt value, unsigned prefix, + const format_specs& specs, const digit_grouping& grouping) + -> OutputIt { + static_assert(std::is_same, UInt>::value, ""); + int num_digits = 0; + auto buffer = memory_buffer(); + switch (specs.type()) { + default: FMT_ASSERT(false, ""); FMT_FALLTHROUGH; + case presentation_type::none: + case presentation_type::dec: + num_digits = count_digits(value); + format_decimal(appender(buffer), value, num_digits); + break; + case presentation_type::hex: + if (specs.alt()) + prefix_append(prefix, unsigned(specs.upper() ? 'X' : 'x') << 8 | '0'); + num_digits = count_digits<4>(value); + format_base2e(4, appender(buffer), value, num_digits, specs.upper()); + break; + case presentation_type::oct: + num_digits = count_digits<3>(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 && value != 0) + prefix_append(prefix, '0'); + format_base2e(3, appender(buffer), value, num_digits); + break; + case presentation_type::bin: + if (specs.alt()) + prefix_append(prefix, unsigned(specs.upper() ? 'B' : 'b') << 8 | '0'); + num_digits = count_digits<1>(value); + format_base2e(1, appender(buffer), value, num_digits); + break; + case presentation_type::chr: + return write_char(out, static_cast(value), specs); + } + + unsigned size = (prefix != 0 ? prefix >> 24 : 0) + to_unsigned(num_digits) + + to_unsigned(grouping.count_separators(num_digits)); + return write_padded( + out, specs, size, size, [&](reserve_iterator it) { + for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) + *it++ = static_cast(p & 0xff); + return grouping.apply(it, string_view(buffer.data(), buffer.size())); + }); +} + +#if FMT_USE_LOCALE +// Writes a localized value. +FMT_API auto write_loc(appender out, loc_value value, const format_specs& specs, + locale_ref loc) -> bool; +#endif +template +inline auto write_loc(OutputIt, const loc_value&, const format_specs&, + locale_ref) -> bool { + return false; +} + +template struct write_int_arg { + UInt abs_value; + unsigned prefix; +}; + +template +FMT_CONSTEXPR auto make_write_int_arg(T value, sign s) + -> 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[static_cast(s)]; + } + return {abs_value, prefix}; +} + +template struct loc_writer { + basic_appender out; + const format_specs& specs; + std::basic_string sep; + std::string grouping; + std::basic_string decimal_point; + + template ::value)> + auto operator()(T value) -> bool { + auto arg = make_write_int_arg(value, specs.sign()); + write_int(out, static_cast>(arg.abs_value), arg.prefix, + specs, digit_grouping(grouping, sep)); + return true; + } + + template ::value)> + auto operator()(T) -> bool { + return false; + } +}; + +// Size and padding computation separate from write_int to avoid template bloat. +struct size_padding { + unsigned size; + unsigned padding; + + FMT_CONSTEXPR size_padding(int num_digits, unsigned prefix, + const 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); + } + } +}; + +template +FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg arg, + const format_specs& specs) -> OutputIt { + static_assert(std::is_same>::value, ""); + + constexpr int buffer_size = num_bits(); + char buffer[buffer_size]; + if (is_constant_evaluated()) fill_n(buffer, buffer_size, '\0'); + const char* begin = nullptr; + const char* end = buffer + buffer_size; + + auto abs_value = arg.abs_value; + auto prefix = arg.prefix; + switch (specs.type()) { + default: FMT_ASSERT(false, ""); FMT_FALLTHROUGH; + case presentation_type::none: + case presentation_type::dec: + begin = do_format_decimal(buffer, abs_value, buffer_size); + break; + case presentation_type::hex: + begin = do_format_base2e(4, buffer, abs_value, buffer_size, specs.upper()); + if (specs.alt()) + prefix_append(prefix, unsigned(specs.upper() ? 'X' : 'x') << 8 | '0'); + break; + case presentation_type::oct: { + begin = do_format_base2e(3, buffer, abs_value, buffer_size); + // Octal prefix '0' is counted as a digit, so only add it if precision + // is not greater than the number of digits. + auto num_digits = end - begin; + if (specs.alt() && specs.precision <= num_digits && abs_value != 0) + prefix_append(prefix, '0'); + break; + } + case presentation_type::bin: + begin = do_format_base2e(1, buffer, abs_value, buffer_size); + if (specs.alt()) + prefix_append(prefix, unsigned(specs.upper() ? 'B' : 'b') << 8 | '0'); + break; + case presentation_type::chr: + return write_char(out, static_cast(abs_value), specs); + } + + // Write an integer in the format + // + // prefix contains chars in three lower bytes and the size in the fourth byte. + int num_digits = static_cast(end - begin); + // 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)); + for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) + *it++ = static_cast(p & 0xff); + return base_iterator(out, copy(begin, end, it)); + } + auto sp = size_padding(num_digits, prefix, specs); + unsigned padding = sp.padding; + return write_padded( + out, specs, sp.size, [=](reserve_iterator it) { + for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) + *it++ = static_cast(p & 0xff); + it = detail::fill_n(it, padding, static_cast('0')); + return copy(begin, end, it); + }); +} + +template +FMT_CONSTEXPR FMT_NOINLINE auto write_int_noinline(OutputIt out, + write_int_arg arg, + const format_specs& specs) + -> OutputIt { + return write_int(out, arg, specs); +} + +template ::value && + !std::is_same::value && + !std::is_same::value)> +FMT_CONSTEXPR FMT_INLINE auto write(basic_appender out, T value, + const format_specs& specs, locale_ref loc) + -> basic_appender { + if (specs.localized() && write_loc(out, value, specs, loc)) return out; + return write_int_noinline(out, make_write_int_arg(value, specs.sign()), + specs); +} + +// An inlined version of write used in format string compilation. +template ::value && + !std::is_same::value && + !std::is_same::value && + !std::is_same>::value)> +FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value, + const format_specs& specs, locale_ref loc) + -> OutputIt { + if (specs.localized() && write_loc(out, value, specs, loc)) return out; + return write_int(out, make_write_int_arg(value, specs.sign()), specs); +} + +template +FMT_CONSTEXPR auto write(OutputIt out, basic_string_view s, + const 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)); + + bool is_debug = specs.type() == presentation_type::debug; + if (is_debug) { + auto buf = counting_buffer(); + write_escaped_string(basic_appender(buf), s); + size = buf.count(); + } + + size_t width = 0; + if (specs.width != 0) { + width = + is_debug ? size : compute_width(basic_string_view(data, size)); + } + return write_padded( + out, specs, size, width, [=](reserve_iterator it) { + return is_debug ? write_escaped_string(it, s) + : copy(data, data + size, it); + }); +} +template +FMT_CONSTEXPR auto write(OutputIt out, basic_string_view s, + const format_specs& specs, locale_ref) -> OutputIt { + return write(out, s, specs); +} +template +FMT_CONSTEXPR auto write(OutputIt out, const Char* s, const format_specs& specs, + locale_ref) -> OutputIt { + if (specs.type() == presentation_type::pointer) + return write_ptr(out, bit_cast(s), &specs); + if (!s) report_error("string pointer is null"); + return write(out, basic_string_view(s), specs, {}); +} + +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); + if (auto ptr = to_pointer(out, size)) { + if (negative) *ptr++ = static_cast('-'); + format_decimal(ptr, abs_value, num_digits); + return out; + } + if (negative) *out++ = static_cast('-'); + return format_decimal(out, abs_value, num_digits); +} + +template +FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end, + format_specs& specs) -> const Char* { + FMT_ASSERT(begin != end, ""); + auto alignment = align::none; + auto p = begin + code_point_length(begin); + if (end - p <= 0) p = begin; + for (;;) { + switch (to_ascii(*p)) { + case '<': alignment = align::left; break; + case '>': alignment = align::right; break; + case '^': alignment = align::center; break; + } + if (alignment != align::none) { + if (p != begin) { + auto c = *begin; + if (c == '}') return begin; + if (c == '{') { + report_error("invalid fill character '{'"); + return begin; + } + specs.set_fill(basic_string_view(begin, to_unsigned(p - begin))); + begin = p + 1; + } else { + ++begin; + } + break; + } else if (p == begin) { + break; + } + p = begin; + } + specs.set_align(alignment); + return begin; +} + +template +FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isnan, + format_specs specs, sign s) -> OutputIt { + auto str = + isnan ? (specs.upper() ? "NAN" : "nan") : (specs.upper() ? "INF" : "inf"); + constexpr size_t str_size = 3; + auto size = str_size + (s != sign::none ? 1 : 0); + // Replace '0'-padding with space for non-finite values. + const bool is_zero_fill = + specs.fill_size() == 1 && specs.fill_unit() == '0'; + if (is_zero_fill) specs.set_fill(' '); + return write_padded(out, specs, size, + [=](reserve_iterator it) { + if (s != sign::none) + *it++ = detail::getsign(s); + return copy(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& f) -> int { + return f.significand_size; +} +template +inline auto get_significand_size(const dragonbox::decimal_fp& f) -> int { + return count_digits(f.significand); +} + +template +constexpr auto write_significand(OutputIt out, const char* significand, + int significand_size) -> OutputIt { + return copy(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); +} +template +FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, + int significand_size, int exponent, + const Grouping& grouping) -> OutputIt { + if (!grouping.has_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); + 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; + write2digits(out, static_cast(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_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_noinline(significand, significand + integral_size, + out); + if (!decimal_point) return out; + *out++ = decimal_point; + return detail::copy_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.has_separator()) { + return write_significand(out, significand, significand_size, integral_size, + decimal_point); + } + auto buffer = basic_memory_buffer(); + write_significand(basic_appender(buffer), significand, significand_size, + integral_size, decimal_point); + grouping.apply( + out, basic_string_view(buffer.data(), to_unsigned(integral_size))); + return detail::copy_noinline(buffer.data() + integral_size, + buffer.end(), out); +} + +template > +FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f, + const format_specs& specs, sign s, + locale_ref loc) -> OutputIt { + auto significand = f.significand; + int significand_size = get_significand_size(f); + const Char zero = static_cast('0'); + size_t size = to_unsigned(significand_size) + (s != sign::none ? 1 : 0); + using iterator = reserve_iterator; + + Char decimal_point = specs.localized() ? detail::decimal_point(loc) + : static_cast('.'); + + int output_exp = f.exponent + significand_size - 1; + auto use_exp_format = [=]() { + if (specs.type() == presentation_type::exp) return true; + if (specs.type() == presentation_type::fixed) 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 >= (specs.precision > 0 ? specs.precision : exp_upper); + }; + if (use_exp_format()) { + int num_zeros = 0; + if (specs.alt()) { + num_zeros = specs.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 = specs.upper() ? 'E' : 'e'; + auto write = [=](iterator it) { + if (s != sign::none) *it++ = detail::getsign(s); + // 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 = f.exponent + significand_size; + if (f.exponent >= 0) { + // 1234e5 -> 123400000[.0+] + size += to_unsigned(f.exponent); + int num_zeros = specs.precision - exp; + abort_fuzzing_if(num_zeros > 5000); + if (specs.alt()) { + ++size; + if (num_zeros <= 0 && specs.type() != presentation_type::fixed) + num_zeros = 0; + if (num_zeros > 0) size += to_unsigned(num_zeros); + } + auto grouping = Grouping(loc, specs.localized()); + size += to_unsigned(grouping.count_separators(exp)); + return write_padded(out, specs, size, [&](iterator it) { + if (s != sign::none) *it++ = detail::getsign(s); + it = write_significand(it, significand, significand_size, + f.exponent, grouping); + if (!specs.alt()) 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 = specs.alt() ? specs.precision - significand_size : 0; + size += 1 + static_cast(max_of(num_zeros, 0)); + auto grouping = Grouping(loc, specs.localized()); + size += to_unsigned(grouping.count_separators(exp)); + return write_padded(out, specs, size, [&](iterator it) { + if (s != sign::none) *it++ = detail::getsign(s); + 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 && specs.precision >= 0 && + specs.precision < num_zeros) { + num_zeros = specs.precision; + } + bool pointy = num_zeros != 0 || significand_size != 0 || specs.alt(); + size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros); + return write_padded(out, specs, size, [&](iterator it) { + if (s != sign::none) *it++ = detail::getsign(s); + *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 auto has_separator() const -> bool { return false; } + + constexpr auto count_separators(int) const -> int { return 0; } + + template + constexpr auto apply(Out out, basic_string_view) const -> Out { + return out; + } +}; + +template +FMT_CONSTEXPR20 auto write_float(OutputIt out, const DecimalFP& f, + const format_specs& specs, sign s, + locale_ref loc) -> OutputIt { + if (is_constant_evaluated()) { + return do_write_float>(out, f, specs, s, loc); + } else { + return do_write_float(out, f, specs, s, loc); + } +} + +template constexpr auto isnan(T value) -> bool { + return value != value; // std::isnan doesn't support __float128. +} + +template +struct has_isfinite : std::false_type {}; + +template +struct has_isfinite> + : std::true_type {}; + +template ::value&& + has_isfinite::value)> +FMT_CONSTEXPR20 auto isfinite(T value) -> bool { + constexpr T inf = T(std::numeric_limits::infinity()); + if (is_constant_evaluated()) + return !detail::isnan(value) && value < inf && value > -inf; + return std::isfinite(value); +} +template ::value)> +FMT_CONSTEXPR auto isfinite(T value) -> bool { + T inf = T(std::numeric_limits::infinity()); + // std::isfinite doesn't support __float128. + return !detail::isnan(value) && value < inf && value > -inf; +} + +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 >> (num_bits() - 1)) != 0; + } +#endif + } + return std::signbit(static_cast(value)); +} + +inline FMT_CONSTEXPR20 void adjust_precision(int& precision, int exp10) { + // Adjust fixed precision by exponent because it is relative to decimal + // point. + if (exp10 > 0 && precision > max_value() - exp10) + FMT_THROW(format_error("number is too big")); + precision += exp10; +} + +class bigint { + private: + // A bigint is a number in the form bigit_[N - 1] ... bigit_[0] * 32^exp_. + using bigit = uint32_t; // A big digit. + using double_bigit = uint64_t; + enum { bigit_bits = num_bits() }; + enum { bigits_capacity = 32 }; + basic_memory_buffer bigits_; + int exp_; + + friend struct formatter; + + FMT_CONSTEXPR auto get_bigit(int i) const -> bigit { + return i >= exp_ && i < num_bigits() ? bigits_[i - exp_] : 0; + } + + FMT_CONSTEXPR void subtract_bigits(int index, bigit other, bigit& borrow) { + auto result = double_bigit(bigits_[index]) - other - borrow; + bigits_[index] = static_cast(result); + borrow = static_cast(result >> (bigit_bits * 2 - 1)); + } + + FMT_CONSTEXPR void remove_leading_zeros() { + int num_bigits = static_cast(bigits_.size()) - 1; + while (num_bigits > 0 && bigits_[num_bigits] == 0) --num_bigits; + bigits_.resize(to_unsigned(num_bigits + 1)); + } + + // Computes *this -= other assuming aligned bigints and *this >= other. + FMT_CONSTEXPR 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); + if (borrow != 0) subtract_bigits(i, 0, borrow); + FMT_ASSERT(borrow == 0, ""); + remove_leading_zeros(); + } + + FMT_CONSTEXPR void multiply(uint32_t value) { + bigit carry = 0; + const double_bigit wide_value = value; + 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); + } + + template ::value || + std::is_same::value)> + FMT_CONSTEXPR void multiply(UInt value) { + using half_uint = + conditional_t::value, uint64_t, uint32_t>; + const int shift = num_bits() - bigit_bits; + const UInt lower = static_cast(value); + const UInt upper = value >> num_bits(); + UInt carry = 0; + for (size_t i = 0, n = bigits_.size(); i < n; ++i) { + UInt result = lower * bigits_[i] + static_cast(carry); + carry = (upper * bigits_[i] << shift) + (result >> bigit_bits) + + (carry >> bigit_bits); + bigits_[i] = static_cast(result); + } + while (carry != 0) { + bigits_.push_back(static_cast(carry)); + carry >>= bigit_bits; + } + } + + template ::value || + std::is_same::value)> + FMT_CONSTEXPR void assign(UInt n) { + size_t num_bigits = 0; + do { + bigits_[num_bigits++] = static_cast(n); + n >>= bigit_bits; + } while (n != 0); + bigits_.resize(num_bigits); + exp_ = 0; + } + + public: + FMT_CONSTEXPR bigint() : exp_(0) {} + explicit bigint(uint64_t n) { assign(n); } + + bigint(const bigint&) = delete; + void operator=(const bigint&) = delete; + + FMT_CONSTEXPR void assign(const bigint& other) { + auto size = other.bigits_.size(); + bigits_.resize(size); + auto data = other.bigits_.data(); + copy(data, data + size, bigits_.data()); + exp_ = other.exp_; + } + + template FMT_CONSTEXPR void operator=(Int n) { + FMT_ASSERT(n > 0, ""); + assign(uint64_or_128_t(n)); + } + + FMT_CONSTEXPR auto num_bigits() const -> int { + return static_cast(bigits_.size()) + exp_; + } + + FMT_CONSTEXPR auto operator<<=(int shift) -> bigint& { + 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_CONSTEXPR auto operator*=(Int value) -> bigint& { + FMT_ASSERT(value > 0, ""); + multiply(uint32_or_64_or_128_t(value)); + return *this; + } + + friend FMT_CONSTEXPR auto compare(const bigint& b1, const bigint& b2) -> int { + int num_bigits1 = b1.num_bigits(), num_bigits2 = b2.num_bigits(); + if (num_bigits1 != num_bigits2) return num_bigits1 > num_bigits2 ? 1 : -1; + int i = static_cast(b1.bigits_.size()) - 1; + int j = static_cast(b2.bigits_.size()) - 1; + int end = i - j; + if (end < 0) end = 0; + for (; i >= end; --i, --j) { + bigit b1_bigit = b1.bigits_[i], b2_bigit = b2.bigits_[j]; + if (b1_bigit != b2_bigit) return b1_bigit > b2_bigit ? 1 : -1; + } + if (i != j) return i > j ? 1 : -1; + return 0; + } + + // Returns compare(lhs1 + lhs2, rhs). + friend FMT_CONSTEXPR auto add_compare(const bigint& lhs1, const bigint& lhs2, + const bigint& rhs) -> int { + int max_lhs_bigits = max_of(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; + double_bigit borrow = 0; + int min_exp = min_of(min_of(lhs1.exp_, lhs2.exp_), rhs.exp_); + for (int i = num_rhs_bigits - 1; i >= min_exp; --i) { + double_bigit sum = double_bigit(lhs1.get_bigit(i)) + lhs2.get_bigit(i); + bigit rhs_bigit = rhs.get_bigit(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 *this = 1; + int bitmask = 1 << (num_bits() - + countl_zero(static_cast(exp)) - 1); + // pow(10, exp) = pow(5, exp) * pow(2, exp). First compute pow(5, exp) by + // repeated squaring and multiplication. + *this = 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)); + auto sum = uint128_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 += double_bigit(n[i]) * n[j]; + } + bigits_[bigit_index] = static_cast(sum); + sum >>= num_bits(); // 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 += double_bigit(n[i++]) * n[j--]; + bigits_[bigit_index] = static_cast(sum); + sum >>= num_bits(); + } + 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_CONSTEXPR 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]; + memset(bigits_.data(), 0, to_unsigned(exp_difference) * sizeof(bigit)); + exp_ -= exp_difference; + } + + // Divides this bignum by divisor, assigning the remainder to this and + // returning the quotient. + FMT_CONSTEXPR auto divmod_assign(const bigint& divisor) -> int { + 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; + } +}; + +// format_dragon flags. +enum dragon { + predecessor_closer = 1, + fixup = 2, // Run fixup to correct exp10 which can be off by one. + fixed = 4, +}; + +// 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(basic_fp value, + unsigned flags, 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. + bool is_predecessor_closer = (flags & dragon::predecessor_closer) != 0; + int shift = is_predecessor_closer ? 2 : 1; + if (value.e >= 0) { + numerator = value.f; + numerator <<= value.e + shift; + lower = 1; + lower <<= value.e; + if (is_predecessor_closer) { + upper_store = 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 (is_predecessor_closer) { + upper_store.assign(numerator); + upper_store <<= 1; + upper = &upper_store; + } + numerator *= value.f; + numerator <<= shift; + denominator = 1; + denominator <<= shift - value.e; + } else { + numerator = value.f; + numerator <<= shift; + denominator.assign_pow10(exp10); + denominator <<= shift - value.e; + lower = 1; + if (is_predecessor_closer) { + upper_store = 1ULL << 1; + upper = &upper_store; + } + } + int even = static_cast((value.f & 1) == 0); + if (!upper) upper = &lower; + bool shortest = num_digits < 0; + if ((flags & dragon::fixup) != 0) { + if (add_compare(numerator, *upper, denominator) + even <= 0) { + --exp10; + numerator *= 10; + if (num_digits < 0) { + lower *= 10; + if (upper != &lower) *upper *= 10; + } + } + if ((flags & dragon::fixed) != 0) adjust_precision(num_digits, exp10 + 1); + } + // Invariant: value == (numerator / denominator) * pow(10, exp10). + if (shortest) { + // Generate the shortest representation. + 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) { + auto digit = '0'; + if (num_digits == 0) { + denominator *= 10; + 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'; + if ((flags & dragon::fixed) != 0) + buf.push_back('0'); + else + ++exp10; + } + return; + } + ++digit; + } + buf[num_digits - 1] = static_cast('0' + digit); +} + +// Formats a floating-point number using the hexfloat format. +template ::value)> +FMT_CONSTEXPR20 void format_hexfloat(Float value, format_specs specs, + buffer& buf) { + // float is passed as double to reduce the number of instantiations and to + // simplify implementation. + static_assert(!std::is_same::value, ""); + + using info = dragonbox::float_info; + + // Assume Float is in the format [sign][exponent][significand]. + using carrier_uint = typename info::carrier_uint; + + const auto num_float_significand_bits = detail::num_significand_bits(); + + basic_fp f(value); + f.e += num_float_significand_bits; + if (!has_implicit_bit()) --f.e; + + const auto num_fraction_bits = + num_float_significand_bits + (has_implicit_bit() ? 1 : 0); + const auto num_xdigits = (num_fraction_bits + 3) / 4; + + const auto leading_shift = ((num_xdigits - 1) * 4); + const auto leading_mask = carrier_uint(0xF) << leading_shift; + const auto leading_xdigit = + static_cast((f.f & leading_mask) >> leading_shift); + if (leading_xdigit > 1) f.e -= (32 - countl_zero(leading_xdigit) - 1); + + int print_xdigits = num_xdigits - 1; + if (specs.precision >= 0 && print_xdigits > specs.precision) { + const int shift = ((print_xdigits - specs.precision - 1) * 4); + const auto mask = carrier_uint(0xF) << shift; + const auto v = static_cast((f.f & mask) >> shift); + + if (v >= 8) { + const auto inc = carrier_uint(1) << (shift + 4); + f.f += inc; + f.f &= ~(inc - 1); + } + + // Check long double overflow + if (!has_implicit_bit()) { + const auto implicit_bit = carrier_uint(1) << num_float_significand_bits; + if ((f.f & implicit_bit) == implicit_bit) { + f.f >>= 4; + f.e += 4; + } + } + + print_xdigits = specs.precision; + } + + char xdigits[num_bits() / 4]; + detail::fill_n(xdigits, sizeof(xdigits), '0'); + format_base2e(4, xdigits, f.f, num_xdigits, specs.upper()); + + // Remove zero tail + while (print_xdigits > 0 && xdigits[print_xdigits] == '0') --print_xdigits; + + buf.push_back('0'); + buf.push_back(specs.upper() ? 'X' : 'x'); + buf.push_back(xdigits[0]); + if (specs.alt() || print_xdigits > 0 || print_xdigits < specs.precision) + buf.push_back('.'); + buf.append(xdigits + 1, xdigits + 1 + print_xdigits); + for (; print_xdigits < specs.precision; ++print_xdigits) buf.push_back('0'); + + buf.push_back(specs.upper() ? 'P' : 'p'); + + uint32_t abs_e; + if (f.e < 0) { + buf.push_back('-'); + abs_e = static_cast(-f.e); + } else { + buf.push_back('+'); + abs_e = static_cast(f.e); + } + format_decimal(appender(buf), abs_e, detail::count_digits(abs_e)); +} + +template ::value)> +FMT_CONSTEXPR20 void format_hexfloat(Float value, format_specs specs, + buffer& buf) { + format_hexfloat(static_cast(value), specs, buf); +} + +constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t { + // For checking rounding thresholds. + // The kth entry is chosen to be the smallest integer such that the + // upper 32-bits of 10^(k+1) times it is strictly bigger than 5 * 10^k. + // It is equal to ceil(2^31 + 2^32/10^(k + 1)). + // These are stored in a string literal because we cannot have static arrays + // in constexpr functions and non-static ones are poorly optimized. + return U"\x9999999a\x828f5c29\x80418938\x80068db9\x8000a7c6\x800010c7" + U"\x800001ae\x8000002b"[index]; +} + +template +FMT_CONSTEXPR20 auto format_float(Float value, int precision, + const format_specs& specs, bool binary32, + buffer& buf) -> int { + // float is passed as double to reduce the number of instantiations. + static_assert(!std::is_same::value, ""); + auto converted_value = convert_float(value); + + const bool fixed = specs.type() == presentation_type::fixed; + if (value == 0) { + if (precision <= 0 || !fixed) { + buf.push_back('0'); + return 0; + } + buf.try_resize(to_unsigned(precision)); + fill_n(buf.data(), precision, '0'); + return -precision; + } + + int exp = 0; + bool use_dragon = true; + unsigned dragon_flags = 0; + if (!is_fast_float() || is_constant_evaluated()) { + const auto inv_log2_10 = 0.3010299956639812; // 1 / log2(10) + using info = dragonbox::float_info; + const auto f = basic_fp(converted_value); + // Compute exp, an approximate power of 10, such that + // 10^(exp - 1) <= value < 10^exp or 10^exp <= value < 10^(exp + 1). + // This is based on log10(value) == log2(value) / log2(10) and approximation + // of log2(value) by e + num_fraction_bits idea from double-conversion. + auto e = (f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10; + exp = static_cast(e); + if (e > exp) ++exp; // Compute ceil. + dragon_flags = dragon::fixup; + } else { + // Extract significand bits and exponent bits. + using info = dragonbox::float_info; + auto br = bit_cast(static_cast(value)); + + const uint64_t significand_mask = + (static_cast(1) << num_significand_bits()) - 1; + uint64_t significand = (br & significand_mask); + int exponent = static_cast((br & exponent_mask()) >> + num_significand_bits()); + + if (exponent != 0) { // Check if normal. + exponent -= exponent_bias() + num_significand_bits(); + significand |= + (static_cast(1) << num_significand_bits()); + significand <<= 1; + } else { + // Normalize subnormal inputs. + FMT_ASSERT(significand != 0, "zeros should not appear here"); + int shift = countl_zero(significand); + FMT_ASSERT(shift >= num_bits() - num_significand_bits(), + ""); + shift -= (num_bits() - num_significand_bits() - 2); + exponent = (std::numeric_limits::min_exponent - + num_significand_bits()) - + shift; + significand <<= shift; + } + + // Compute the first several nonzero decimal significand digits. + // We call the number we get the first segment. + const int k = info::kappa - dragonbox::floor_log10_pow2(exponent); + exp = -k; + const int beta = exponent + dragonbox::floor_log2_pow10(k); + uint64_t first_segment; + bool has_more_segments; + int digits_in_the_first_segment; + { + const auto r = dragonbox::umul192_upper128( + significand << beta, dragonbox::get_cached_power(k)); + first_segment = r.high(); + has_more_segments = r.low() != 0; + + // The first segment can have 18 ~ 19 digits. + if (first_segment >= 1000000000000000000ULL) { + digits_in_the_first_segment = 19; + } else { + // When it is of 18-digits, we align it to 19-digits by adding a bogus + // zero at the end. + digits_in_the_first_segment = 18; + first_segment *= 10; + } + } + + // Compute the actual number of decimal digits to print. + if (fixed) adjust_precision(precision, exp + digits_in_the_first_segment); + + // Use Dragon4 only when there might be not enough digits in the first + // segment. + if (digits_in_the_first_segment > precision) { + use_dragon = false; + + if (precision <= 0) { + exp += digits_in_the_first_segment; + + if (precision < 0) { + // Nothing to do, since all we have are just leading zeros. + buf.try_resize(0); + } else { + // We may need to round-up. + buf.try_resize(1); + if ((first_segment | static_cast(has_more_segments)) > + 5000000000000000000ULL) { + buf[0] = '1'; + } else { + buf[0] = '0'; + } + } + } // precision <= 0 + else { + exp += digits_in_the_first_segment - precision; + + // When precision > 0, we divide the first segment into three + // subsegments, each with 9, 9, and 0 ~ 1 digits so that each fits + // in 32-bits which usually allows faster calculation than in + // 64-bits. Since some compiler (e.g. MSVC) doesn't know how to optimize + // division-by-constant for large 64-bit divisors, we do it here + // manually. The magic number 7922816251426433760 below is equal to + // ceil(2^(64+32) / 10^10). + const uint32_t first_subsegment = static_cast( + dragonbox::umul128_upper64(first_segment, 7922816251426433760ULL) >> + 32); + const uint64_t second_third_subsegments = + first_segment - first_subsegment * 10000000000ULL; + + uint64_t prod; + uint32_t digits; + bool should_round_up; + int number_of_digits_to_print = min_of(precision, 9); + + // Print a 9-digits subsegment, either the first or the second. + auto print_subsegment = [&](uint32_t subsegment, char* buffer) { + int number_of_digits_printed = 0; + + // If we want to print an odd number of digits from the subsegment, + if ((number_of_digits_to_print & 1) != 0) { + // Convert to 64-bit fixed-point fractional form with 1-digit + // integer part. The magic number 720575941 is a good enough + // approximation of 2^(32 + 24) / 10^8; see + // https://jk-jeon.github.io/posts/2022/12/fixed-precision-formatting/#fixed-length-case + // for details. + prod = ((subsegment * static_cast(720575941)) >> 24) + 1; + digits = static_cast(prod >> 32); + *buffer = static_cast('0' + digits); + number_of_digits_printed++; + } + // If we want to print an even number of digits from the + // first_subsegment, + else { + // Convert to 64-bit fixed-point fractional form with 2-digits + // integer part. The magic number 450359963 is a good enough + // approximation of 2^(32 + 20) / 10^7; see + // https://jk-jeon.github.io/posts/2022/12/fixed-precision-formatting/#fixed-length-case + // for details. + prod = ((subsegment * static_cast(450359963)) >> 20) + 1; + digits = static_cast(prod >> 32); + write2digits(buffer, digits); + number_of_digits_printed += 2; + } + + // Print all digit pairs. + while (number_of_digits_printed < number_of_digits_to_print) { + prod = static_cast(prod) * static_cast(100); + digits = static_cast(prod >> 32); + write2digits(buffer + number_of_digits_printed, digits); + number_of_digits_printed += 2; + } + }; + + // Print first subsegment. + print_subsegment(first_subsegment, buf.data()); + + // Perform rounding if the first subsegment is the last subsegment to + // print. + if (precision <= 9) { + // Rounding inside the subsegment. + // We round-up if: + // - either the fractional part is strictly larger than 1/2, or + // - the fractional part is exactly 1/2 and the last digit is odd. + // We rely on the following observations: + // - If fractional_part >= threshold, then the fractional part is + // strictly larger than 1/2. + // - If the MSB of fractional_part is set, then the fractional part + // must be at least 1/2. + // - When the MSB of fractional_part is set, either + // second_third_subsegments being nonzero or has_more_segments + // being true means there are further digits not printed, so the + // fractional part is strictly larger than 1/2. + if (precision < 9) { + uint32_t fractional_part = static_cast(prod); + should_round_up = + fractional_part >= fractional_part_rounding_thresholds( + 8 - number_of_digits_to_print) || + ((fractional_part >> 31) & + ((digits & 1) | (second_third_subsegments != 0) | + has_more_segments)) != 0; + } + // Rounding at the subsegment boundary. + // In this case, the fractional part is at least 1/2 if and only if + // second_third_subsegments >= 5000000000ULL, and is strictly larger + // than 1/2 if we further have either second_third_subsegments > + // 5000000000ULL or has_more_segments == true. + else { + should_round_up = second_third_subsegments > 5000000000ULL || + (second_third_subsegments == 5000000000ULL && + ((digits & 1) != 0 || has_more_segments)); + } + } + // Otherwise, print the second subsegment. + else { + // Compilers are not aware of how to leverage the maximum value of + // second_third_subsegments to find out a better magic number which + // allows us to eliminate an additional shift. 1844674407370955162 = + // ceil(2^64/10) < ceil(2^64*(10^9/(10^10 - 1))). + const uint32_t second_subsegment = + static_cast(dragonbox::umul128_upper64( + second_third_subsegments, 1844674407370955162ULL)); + const uint32_t third_subsegment = + static_cast(second_third_subsegments) - + second_subsegment * 10; + + number_of_digits_to_print = precision - 9; + print_subsegment(second_subsegment, buf.data() + 9); + + // Rounding inside the subsegment. + if (precision < 18) { + // The condition third_subsegment != 0 implies that the segment was + // of 19 digits, so in this case the third segment should be + // consisting of a genuine digit from the input. + uint32_t fractional_part = static_cast(prod); + should_round_up = + fractional_part >= fractional_part_rounding_thresholds( + 8 - number_of_digits_to_print) || + ((fractional_part >> 31) & + ((digits & 1) | (third_subsegment != 0) | + has_more_segments)) != 0; + } + // Rounding at the subsegment boundary. + else { + // In this case, the segment must be of 19 digits, thus + // the third subsegment should be consisting of a genuine digit from + // the input. + should_round_up = third_subsegment > 5 || + (third_subsegment == 5 && + ((digits & 1) != 0 || has_more_segments)); + } + } + + // Round-up if necessary. + if (should_round_up) { + ++buf[precision - 1]; + for (int i = precision - 1; i > 0 && buf[i] > '9'; --i) { + buf[i] = '0'; + ++buf[i - 1]; + } + if (buf[0] > '9') { + buf[0] = '1'; + if (fixed) + buf[precision++] = '0'; + else + ++exp; + } + } + buf.try_resize(to_unsigned(precision)); + } + } // if (digits_in_the_first_segment > precision) + else { + // Adjust the exponent for its use in Dragon4. + exp += digits_in_the_first_segment - 1; + } + } + if (use_dragon) { + auto f = basic_fp(); + bool is_predecessor_closer = binary32 ? f.assign(static_cast(value)) + : f.assign(converted_value); + if (is_predecessor_closer) dragon_flags |= dragon::predecessor_closer; + if (fixed) dragon_flags |= dragon::fixed; + // 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, dragon_flags, precision, buf, exp); + } + if (!fixed && !specs.alt()) { + // 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 +FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, format_specs specs, + locale_ref loc) -> OutputIt { + // Use signbit because value < 0 is false for NaN. + sign s = detail::signbit(value) ? sign::minus : specs.sign(); + + if (!detail::isfinite(value)) + return write_nonfinite(out, detail::isnan(value), specs, s); + + if (specs.align() == align::numeric && s != sign::none) { + *out++ = detail::getsign(s); + s = sign::none; + if (specs.width != 0) --specs.width; + } + + int precision = specs.precision; + if (precision < 0) { + if (specs.type() != presentation_type::none) { + precision = 6; + } else if (is_fast_float::value && !is_constant_evaluated()) { + // Use Dragonbox for the shortest format. + using floaty = conditional_t= sizeof(double), double, float>; + auto dec = dragonbox::to_decimal(static_cast(value)); + return write_float(out, dec, specs, s, loc); + } + } + + memory_buffer buffer; + if (specs.type() == presentation_type::hexfloat) { + if (s != sign::none) buffer.push_back(detail::getsign(s)); + format_hexfloat(convert_float(value), specs, buffer); + return write_bytes(out, {buffer.data(), buffer.size()}, + specs); + } + + if (specs.type() == presentation_type::exp) { + if (precision == max_value()) + report_error("number is too big"); + else + ++precision; + if (specs.precision != 0) specs.set_alt(); + } else if (specs.type() == presentation_type::fixed) { + if (specs.precision != 0) specs.set_alt(); + } else if (precision == 0) { + precision = 1; + } + int exp = format_float(convert_float(value), precision, specs, + std::is_same(), buffer); + + specs.precision = precision; + auto f = big_decimal_fp{buffer.data(), static_cast(buffer.size()), exp}; + return write_float(out, f, specs, s, loc); +} + +template ::value)> +FMT_CONSTEXPR20 auto write(OutputIt out, T value, format_specs specs, + locale_ref loc = {}) -> OutputIt { + return specs.localized() && write_loc(out, value, specs, loc) + ? out + : write_float(out, value, specs, loc); +} + +template ::value)> +FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt { + if (is_constant_evaluated()) return write(out, value, format_specs()); + + auto s = detail::signbit(value) ? sign::minus : sign::none; + + constexpr auto specs = format_specs(); + using floaty = conditional_t= sizeof(double), double, float>; + using floaty_uint = typename dragonbox::float_info::carrier_uint; + floaty_uint mask = exponent_mask(); + if ((bit_cast(value) & mask) == mask) + return write_nonfinite(out, std::isnan(value), specs, s); + + auto dec = dragonbox::to_decimal(static_cast(value)); + return write_float(out, dec, specs, s, {}); +} + +template ::value && + !is_fast_float::value)> +inline auto write(OutputIt out, T value) -> OutputIt { + return write(out, value, format_specs()); +} + +template +auto write(OutputIt out, monostate, format_specs = {}, locale_ref = {}) + -> OutputIt { + FMT_ASSERT(false, ""); + return out; +} + +template +FMT_CONSTEXPR auto write(OutputIt out, basic_string_view value) + -> OutputIt { + return copy_noinline(value.begin(), value.end(), out); +} + +template ::value)> +constexpr auto write(OutputIt out, const T& value) -> OutputIt { + return write(out, to_string_view(value)); +} + +// 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>(value)); +} + +template ::value)> +FMT_CONSTEXPR auto write(OutputIt out, T value, const 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_CONSTEXPR20 auto write(OutputIt out, const Char* value) -> OutputIt { + if (value) return write(out, basic_string_view(value)); + report_error("string pointer is null"); + return out; +} + +template ::value)> +auto write(OutputIt out, const T* value, const format_specs& specs = {}, + locale_ref = {}) -> OutputIt { + return write_ptr(out, bit_cast(value), &specs); +} + +template ::value == + type::custom_type && + !std::is_fundamental::value)> +FMT_CONSTEXPR auto write(OutputIt out, const T& value) -> OutputIt { + auto f = formatter(); + auto parse_ctx = parse_context({}); + f.parse(parse_ctx); + auto ctx = basic_format_context(out, {}, {}); + return f.format(value, ctx); +} + +template +using is_builtin = + bool_constant::value || FMT_BUILTIN_TYPES>; + +// 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 context = buffered_context; + + basic_appender out; + + void operator()(monostate) { report_error("argument not found"); } + + template ::value)> + void operator()(T value) { + write(out, value); + } + + template ::value)> + void operator()(T) { + FMT_ASSERT(false, ""); + } + + void operator()(typename basic_format_arg::handle h) { + // Use a null locale since the default format must be unlocalized. + auto parse_ctx = parse_context({}); + auto format_ctx = context(out, {}, {}); + h.format(parse_ctx, format_ctx); + } +}; + +template struct arg_formatter { + basic_appender out; + const format_specs& specs; + FMT_NO_UNIQUE_ADDRESS locale_ref locale; + + template ::value)> + FMT_CONSTEXPR FMT_INLINE void operator()(T value) { + detail::write(out, value, specs, locale); + } + + template ::value)> + void operator()(T) { + FMT_ASSERT(false, ""); + } + + void operator()(typename basic_format_arg>::handle) { + // User-defined types are handled separately because they require access + // to the parse context. + } +}; + +struct dynamic_spec_getter { + template ::value)> + FMT_CONSTEXPR auto operator()(T value) -> unsigned long long { + return is_negative(value) ? ~0ull : static_cast(value); + } + + template ::value)> + FMT_CONSTEXPR auto operator()(T) -> unsigned long long { + report_error("width/precision is not integer"); + return 0; + } +}; + +template +FMT_CONSTEXPR auto get_arg(Context& ctx, ID id) -> basic_format_arg { + auto arg = ctx.arg(id); + if (!arg) report_error("argument not found"); + return arg; +} + +template +FMT_CONSTEXPR int get_dynamic_spec( + arg_id_kind kind, const arg_ref& ref, + Context& ctx) { + FMT_ASSERT(kind != arg_id_kind::none, ""); + auto arg = + kind == arg_id_kind::index ? ctx.arg(ref.index) : ctx.arg(ref.name); + if (!arg) report_error("argument not found"); + unsigned long long value = arg.visit(dynamic_spec_getter()); + if (value > to_unsigned(max_value())) + report_error("width/precision is out of range"); + return static_cast(value); +} + +template +FMT_CONSTEXPR void handle_dynamic_spec( + arg_id_kind kind, int& value, + const arg_ref& ref, Context& ctx) { + if (kind != arg_id_kind::none) value = get_dynamic_spec(kind, ref, ctx); +} + +#if FMT_USE_NONTYPE_TEMPLATE_ARGS +template Str> +struct static_named_arg : view { + static constexpr auto name = Str.data; + + const T& value; + static_named_arg(const T& v) : value(v) {} +}; + +template Str> +struct is_named_arg> : std::true_type {}; + +template Str> +struct is_static_named_arg> : std::true_type { +}; + +template Str> +struct udl_arg { + template auto operator=(T&& value) const { + return static_named_arg(std::forward(value)); + } +}; +#else +template struct udl_arg { + const Char* str; + + template auto operator=(T&& value) const -> named_arg { + return {str, std::forward(value)}; + } +}; +#endif // FMT_USE_NONTYPE_TEMPLATE_ARGS + +template struct format_handler { + parse_context parse_ctx; + buffered_context ctx; + + void on_text(const Char* begin, const Char* end) { + copy_noinline(begin, end, ctx.out()); + } + + FMT_CONSTEXPR auto on_arg_id() -> int { return parse_ctx.next_arg_id(); } + FMT_CONSTEXPR auto on_arg_id(int id) -> int { + parse_ctx.check_arg_id(id); + return id; + } + FMT_CONSTEXPR auto on_arg_id(basic_string_view id) -> int { + parse_ctx.check_arg_id(id); + int arg_id = ctx.arg_id(id); + if (arg_id < 0) report_error("argument not found"); + return arg_id; + } + + FMT_INLINE void on_replacement_field(int id, const Char*) { + ctx.arg(id).visit(default_arg_formatter{ctx.out()}); + } + + auto on_format_specs(int id, const Char* begin, const Char* end) + -> const Char* { + auto arg = get_arg(ctx, id); + // Not using a visitor for custom types gives better codegen. + if (arg.format_custom(begin, parse_ctx, ctx)) return parse_ctx.begin(); + + auto specs = dynamic_format_specs(); + begin = parse_format_specs(begin, end, specs, parse_ctx, arg.type()); + if (specs.dynamic()) { + handle_dynamic_spec(specs.dynamic_width(), specs.width, specs.width_ref, + ctx); + handle_dynamic_spec(specs.dynamic_precision(), specs.precision, + specs.precision_ref, ctx); + } + + arg.visit(arg_formatter{ctx.out(), specs, ctx.locale()}); + return begin; + } + + FMT_NORETURN void on_error(const char* message) { report_error(message); } +}; + +using format_func = void (*)(detail::buffer&, int, const char*); +FMT_API void do_report_error(format_func func, int error_code, + const char* message) noexcept; + +FMT_API void format_error_code(buffer& out, int error_code, + string_view message) noexcept; + +template +template +FMT_CONSTEXPR auto native_formatter::format( + const T& val, FormatContext& ctx) const -> decltype(ctx.out()) { + if (!specs_.dynamic()) + return write(ctx.out(), val, specs_, ctx.locale()); + auto specs = format_specs(specs_); + handle_dynamic_spec(specs.dynamic_width(), specs.width, specs_.width_ref, + ctx); + handle_dynamic_spec(specs.dynamic_precision(), specs.precision, + specs_.precision_ref, ctx); + return write(ctx.out(), val, specs, ctx.locale()); +} + +// DEPRECATED! https://github.com/fmtlib/fmt/issues/4292. +template +struct is_locale : std::false_type {}; +template +struct is_locale> : std::true_type {}; + +// DEPRECATED! +template struct vformat_args { + using type = basic_format_args>; +}; +template <> struct vformat_args { + using type = format_args; +}; + +template +void vformat_to(buffer& buf, basic_string_view fmt, + typename vformat_args::type args, locale_ref loc = {}) { + auto out = basic_appender(buf); + parse_format_string( + fmt, format_handler{parse_context(fmt), {out, args, loc}}); +} +} // namespace detail + +FMT_BEGIN_EXPORT + +// A generic formatting context with custom output iterator and character +// (code unit) support. Char is the format string code unit type which can be +// different from OutputIt::value_type. +template class generic_context { + private: + OutputIt out_; + basic_format_args args_; + detail::locale_ref loc_; + + public: + using char_type = Char; + using iterator = OutputIt; + using parse_context_type FMT_DEPRECATED = parse_context; + template + using formatter_type FMT_DEPRECATED = formatter; + enum { builtin_types = FMT_BUILTIN_TYPES }; + + constexpr generic_context(OutputIt out, + basic_format_args args, + detail::locale_ref loc = {}) + : out_(out), args_(args), loc_(loc) {} + generic_context(generic_context&&) = default; + generic_context(const generic_context&) = delete; + void operator=(const generic_context&) = delete; + + constexpr auto arg(int id) const -> basic_format_arg { + return args_.get(id); + } + auto arg(basic_string_view name) const + -> basic_format_arg { + return args_.get(name); + } + constexpr auto arg_id(basic_string_view name) const -> int { + return args_.get_id(name); + } + + constexpr auto out() const -> iterator { return out_; } + + void advance_to(iterator it) { + if (!detail::is_back_insert_iterator()) out_ = it; + } + + constexpr auto locale() const -> detail::locale_ref { return loc_; } +}; + +class loc_value { + private: + basic_format_arg value_; + + public: + template ::value)> + loc_value(T value) : value_(value) {} + + template ::value)> + loc_value(T) {} + + template auto visit(Visitor&& vis) -> decltype(vis(0)) { + return value_.visit(vis); + } +}; + +// A locale facet that formats values in UTF-8. +// It is parameterized on the locale to avoid the heavy include. +template class format_facet : public Locale::facet { + private: + std::string separator_; + std::string grouping_; + std::string decimal_point_; + + protected: + virtual auto do_put(appender out, loc_value val, + const format_specs& specs) const -> bool; + + public: + static FMT_API typename Locale::id id; + + explicit format_facet(Locale& loc); + explicit format_facet(string_view sep = "", std::string grouping = "\3", + std::string decimal_point = ".") + : separator_(sep.data(), sep.size()), + grouping_(grouping), + decimal_point_(decimal_point) {} + + auto put(appender out, loc_value val, const format_specs& specs) const + -> bool { + return do_put(out, val, specs); + } +}; + +#define FMT_FORMAT_AS(Type, Base) \ + template \ + struct formatter : formatter { \ + template \ + FMT_CONSTEXPR auto format(Type value, FormatContext& ctx) const \ + -> decltype(ctx.out()) { \ + return formatter::format(value, ctx); \ + } \ + } + +FMT_FORMAT_AS(signed char, int); +FMT_FORMAT_AS(unsigned char, unsigned); +FMT_FORMAT_AS(short, int); +FMT_FORMAT_AS(unsigned short, unsigned); +FMT_FORMAT_AS(long, detail::long_type); +FMT_FORMAT_AS(unsigned long, detail::ulong_type); +FMT_FORMAT_AS(Char*, const Char*); +FMT_FORMAT_AS(detail::std_string_view, basic_string_view); +FMT_FORMAT_AS(std::nullptr_t, const void*); +FMT_FORMAT_AS(void*, const void*); + +template +struct formatter : formatter, Char> {}; + +template +class formatter, Char> + : public formatter, Char> {}; + +template +struct formatter, Char> : formatter {}; +template +struct formatter, Char> + : formatter {}; + +template +struct formatter + : detail::native_formatter {}; + +template +struct formatter>> + : formatter, Char> { + template + FMT_CONSTEXPR auto format(const T& value, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto&& val = format_as(value); // Make an lvalue reference for format. + return formatter, Char>::format(val, ctx); + } +}; + +/** + * Converts `p` to `const void*` for pointer formatting. + * + * **Example**: + * + * auto s = fmt::format("{}", fmt::ptr(p)); + */ +template auto ptr(T p) -> const void* { + static_assert(std::is_pointer::value, ""); + return detail::bit_cast(p); +} + +/** + * Converts `e` to the underlying type. + * + * **Example**: + * + * enum class color { red, green, blue }; + * auto s = fmt::format("{}", fmt::underlying(color::red)); // s == "0" + */ +template +constexpr auto underlying(Enum e) noexcept -> underlying_t { + return static_cast>(e); +} + +namespace enums { +template ::value)> +constexpr auto format_as(Enum e) noexcept -> underlying_t { + return static_cast>(e); +} +} // namespace enums + +#ifdef __cpp_lib_byte +template <> struct formatter : formatter { + static auto format_as(std::byte b) -> unsigned char { + return static_cast(b); + } + template + auto format(std::byte b, Context& ctx) const -> decltype(ctx.out()) { + return formatter::format(format_as(b), ctx); + } +}; +#endif + +struct bytes { + string_view data; + + inline explicit bytes(string_view s) : data(s) {} +}; + +template <> struct formatter { + private: + detail::dynamic_format_specs<> specs_; + + public: + FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* { + return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, + detail::type::string_type); + } + + template + auto format(bytes b, FormatContext& ctx) const -> decltype(ctx.out()) { + auto specs = specs_; + detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, + specs.width_ref, ctx); + detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision, + specs.precision_ref, ctx); + return detail::write_bytes(ctx.out(), b.data, specs); + } +}; + +// group_digits_view is not derived from view because it copies the argument. +template struct group_digits_view { + T value; +}; + +/** + * Returns a view that formats an integer value using ',' as a + * locale-independent thousands separator. + * + * **Example**: + * + * fmt::print("{}", fmt::group_digits(12345)); + * // Output: "12,345" + */ +template auto group_digits(T value) -> group_digits_view { + return {value}; +} + +template struct formatter> : formatter { + private: + detail::dynamic_format_specs<> specs_; + + public: + FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* { + return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, + detail::type::int_type); + } + + template + auto format(group_digits_view view, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto specs = specs_; + detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, + specs.width_ref, ctx); + detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision, + specs.precision_ref, ctx); + auto arg = detail::make_write_int_arg(view.value, specs.sign()); + return detail::write_int( + ctx.out(), static_cast>(arg.abs_value), + arg.prefix, specs, detail::digit_grouping("\3", ",")); + } +}; + +template struct nested_view { + const formatter* fmt; + const T* value; +}; + +template +struct formatter, Char> { + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + return ctx.begin(); + } + template + auto format(nested_view view, FormatContext& ctx) const + -> decltype(ctx.out()) { + return view.fmt->format(*view.value, ctx); + } +}; + +template struct nested_formatter { + private: + basic_specs specs_; + int width_; + formatter formatter_; + + public: + constexpr nested_formatter() : width_(0) {} + + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + auto it = ctx.begin(), end = ctx.end(); + if (it == end) return it; + auto specs = format_specs(); + it = detail::parse_align(it, end, specs); + specs_ = specs; + Char c = *it; + auto width_ref = detail::arg_ref(); + if ((c >= '0' && c <= '9') || c == '{') { + it = detail::parse_width(it, end, specs, width_ref, ctx); + width_ = specs.width; + } + ctx.advance_to(it); + return formatter_.parse(ctx); + } + + template + auto write_padded(FormatContext& ctx, F write) const -> decltype(ctx.out()) { + if (width_ == 0) return write(ctx.out()); + auto buf = basic_memory_buffer(); + write(basic_appender(buf)); + auto specs = format_specs(); + specs.width = width_; + specs.copy_fill_from(specs_); + specs.set_align(specs_.align()); + return detail::write( + ctx.out(), basic_string_view(buf.data(), buf.size()), specs); + } + + auto nested(const T& value) const -> nested_view { + return nested_view{&formatter_, &value}; + } +}; + +inline namespace literals { +#if FMT_USE_NONTYPE_TEMPLATE_ARGS +template constexpr auto operator""_a() { + using char_t = remove_cvref_t; + return detail::udl_arg(); +} +#else +/** + * User-defined literal equivalent of `fmt::arg`. + * + * **Example**: + * + * using namespace fmt::literals; + * fmt::print("The answer is {answer}.", "answer"_a=42); + */ +constexpr auto operator""_a(const char* s, size_t) -> detail::udl_arg { + return {s}; +} +#endif // FMT_USE_NONTYPE_TEMPLATE_ARGS +} // namespace literals + +/// A fast integer formatter. +class format_int { + private: + // Buffer should be large enough to hold all digits (digits10 + 1), + // a sign and a null character. + enum { buffer_size = std::numeric_limits::digits10 + 3 }; + mutable char buffer_[buffer_size]; + char* str_; + + template + FMT_CONSTEXPR20 auto format_unsigned(UInt value) -> char* { + auto n = static_cast>(value); + return detail::do_format_decimal(buffer_, n, buffer_size - 1); + } + + template + FMT_CONSTEXPR20 auto format_signed(Int value) -> char* { + auto abs_value = static_cast>(value); + bool negative = value < 0; + if (negative) abs_value = 0 - abs_value; + auto begin = format_unsigned(abs_value); + if (negative) *--begin = '-'; + return begin; + } + + public: + FMT_CONSTEXPR20 explicit format_int(int value) : str_(format_signed(value)) {} + FMT_CONSTEXPR20 explicit format_int(long value) + : str_(format_signed(value)) {} + FMT_CONSTEXPR20 explicit format_int(long long value) + : str_(format_signed(value)) {} + FMT_CONSTEXPR20 explicit format_int(unsigned value) + : str_(format_unsigned(value)) {} + FMT_CONSTEXPR20 explicit format_int(unsigned long value) + : str_(format_unsigned(value)) {} + FMT_CONSTEXPR20 explicit format_int(unsigned long long value) + : str_(format_unsigned(value)) {} + + /// Returns the number of characters written to the output buffer. + FMT_CONSTEXPR20 auto size() const -> size_t { + return detail::to_unsigned(buffer_ - str_ + buffer_size - 1); + } + + /// Returns a pointer to the output buffer content. No terminating null + /// character is appended. + FMT_CONSTEXPR20 auto data() const -> const char* { return str_; } + + /// Returns a pointer to the output buffer content with terminating null + /// character appended. + FMT_CONSTEXPR20 auto c_str() const -> const char* { + buffer_[buffer_size - 1] = '\0'; + return str_; + } + + /// Returns the content of the output buffer as an `std::string`. + inline auto str() const -> std::string { return {str_, size()}; } +}; + +#define FMT_STRING_IMPL(s, base) \ + [] { \ + /* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \ + /* Use a macro-like name to avoid shadowing warnings. */ \ + struct FMT_VISIBILITY("hidden") FMT_COMPILE_STRING : base { \ + using char_type = fmt::remove_cvref_t; \ + constexpr explicit operator fmt::basic_string_view() const { \ + return fmt::detail::compile_string_to_view(s); \ + } \ + }; \ + using FMT_STRING_VIEW = \ + fmt::basic_string_view; \ + fmt::detail::ignore_unused(FMT_STRING_VIEW(FMT_COMPILE_STRING())); \ + return FMT_COMPILE_STRING(); \ + }() + +/** + * Constructs a legacy compile-time format string from a string literal `s`. + * + * **Example**: + * + * // A compile-time error because 'd' is an invalid specifier for strings. + * std::string s = fmt::format(FMT_STRING("{:d}"), "foo"); + */ +#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::detail::compile_string) + +FMT_API auto vsystem_error(int error_code, string_view fmt, format_args args) + -> std::system_error; + +/** + * Constructs `std::system_error` with a message formatted with + * `fmt::format(fmt, args...)`. + * `error_code` is a system error code as given by `errno`. + * + * **Example**: + * + * // This throws std::system_error with the description + * // cannot open file 'madeup': No such file or directory + * // or similar (system message may vary). + * const char* filename = "madeup"; + * FILE* file = fopen(filename, "r"); + * if (!file) + * throw fmt::system_error(errno, "cannot open file '{}'", filename); + */ +template +auto system_error(int error_code, format_string fmt, T&&... args) + -> std::system_error { + return vsystem_error(error_code, fmt.str, vargs{{args...}}); +} + +/** + * Formats an error message for an error returned by an operating system or a + * language runtime, for example a file opening error, and writes it to `out`. + * The format is the same as the one used by `std::system_error(ec, message)` + * where `ec` is `std::error_code(error_code, std::generic_category())`. + * It is implementation-defined but normally looks like: + * + * : + * + * where `` is the passed message and `` is the system + * message corresponding to the error code. + * `error_code` is a system error code as given by `errno`. + */ +FMT_API void format_system_error(detail::buffer& out, int error_code, + const char* message) noexcept; + +// Reports a system error without throwing an exception. +// Can be used to report errors from destructors. +FMT_API void report_system_error(int error_code, const char* message) noexcept; + +template ::value)> +inline auto vformat(const Locale& loc, string_view fmt, format_args args) + -> std::string { + auto buf = memory_buffer(); + detail::vformat_to(buf, fmt, args, detail::locale_ref(loc)); + return {buf.data(), buf.size()}; +} + +template ::value)> +FMT_INLINE auto format(const Locale& loc, format_string fmt, T&&... args) + -> std::string { + return vformat(loc, fmt.str, vargs{{args...}}); +} + +template ::value)> +auto vformat_to(OutputIt out, const Locale& loc, string_view fmt, + format_args args) -> OutputIt { + auto&& buf = detail::get_buffer(out); + detail::vformat_to(buf, fmt, args, detail::locale_ref(loc)); + return detail::get_iterator(buf, out); +} + +template ::value&& + detail::is_locale::value)> +FMT_INLINE auto format_to(OutputIt out, const Locale& loc, + format_string fmt, T&&... args) -> OutputIt { + return fmt::vformat_to(out, loc, fmt.str, vargs{{args...}}); +} + +template ::value)> +FMT_NODISCARD FMT_INLINE auto formatted_size(const Locale& loc, + format_string fmt, + T&&... args) -> size_t { + auto buf = detail::counting_buffer<>(); + detail::vformat_to(buf, fmt.str, vargs{{args...}}, + detail::locale_ref(loc)); + return buf.count(); +} + +FMT_API auto vformat(string_view fmt, format_args args) -> std::string; + +/** + * 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); + */ +template +FMT_NODISCARD FMT_INLINE auto format(format_string fmt, T&&... args) + -> std::string { + return vformat(fmt.str, vargs{{args...}}); +} + +/** + * Converts `value` to `std::string` using the default format for type `T`. + * + * **Example**: + * + * std::string answer = fmt::to_string(42); + */ +template ::value)> +FMT_NODISCARD auto to_string(T value) -> std::string { + // The buffer should be large enough to store the number including the sign + // or "false" for bool. + char buffer[max_of(detail::digits10() + 2, 5)]; + return {buffer, detail::write(buffer, value)}; +} + +template ::value)> +FMT_NODISCARD auto to_string(const T& value) -> std::string { + return to_string(format_as(value)); +} + +template ::value && + !detail::use_format_as::value)> +FMT_NODISCARD auto to_string(const T& value) -> std::string { + auto buffer = memory_buffer(); + detail::write(appender(buffer), value); + return {buffer.data(), buffer.size()}; +} + +FMT_END_EXPORT +FMT_END_NAMESPACE + +#ifdef FMT_HEADER_ONLY +# define FMT_FUNC inline +# include "format-inl.h" +#endif + +// Restore _LIBCPP_REMOVE_TRANSITIVE_INCLUDES. +#ifdef FMT_REMOVE_TRANSITIVE_INCLUDES +# undef _LIBCPP_REMOVE_TRANSITIVE_INCLUDES +#endif + +#endif // FMT_FORMAT_H_ diff --git a/include/fmt/os.h b/include/fmt/os.h new file mode 100644 index 0000000..b2cc5e4 --- /dev/null +++ b/include/fmt/os.h @@ -0,0 +1,427 @@ +// Formatting library for C++ - optional OS-specific functionality +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_OS_H_ +#define FMT_OS_H_ + +#include "format.h" + +#ifndef FMT_MODULE +# include +# include +# include +# include // std::system_error + +# if FMT_HAS_INCLUDE() +# include // LC_NUMERIC_MASK on macOS +# endif +#endif // FMT_MODULE + +#ifndef FMT_USE_FCNTL +// UWP doesn't provide _pipe. +# if FMT_HAS_INCLUDE("winapifamily.h") +# include +# endif +# if (FMT_HAS_INCLUDE() || defined(__APPLE__) || \ + defined(__linux__)) && \ + (!defined(WINAPI_FAMILY) || \ + (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) +# include // for O_RDONLY +# define FMT_USE_FCNTL 1 +# else +# define FMT_USE_FCNTL 0 +# endif +#endif + +#ifndef FMT_POSIX +# if defined(_WIN32) && !defined(__MINGW32__) +// Fix warnings about deprecated symbols. +# define FMT_POSIX(call) _##call +# else +# define FMT_POSIX(call) call +# endif +#endif + +// Calls to system functions are wrapped in FMT_SYSTEM for testability. +#ifdef FMT_SYSTEM +# define FMT_HAS_SYSTEM +# define FMT_POSIX_CALL(call) FMT_SYSTEM(call) +#else +# define FMT_SYSTEM(call) ::call +# ifdef _WIN32 +// Fix warnings about deprecated symbols. +# define FMT_POSIX_CALL(call) ::_##call +# else +# define FMT_POSIX_CALL(call) ::call +# endif +#endif + +// Retries the expression while it evaluates to error_result and errno +// equals to EINTR. +#ifndef _WIN32 +# define FMT_RETRY_VAL(result, expression, error_result) \ + do { \ + (result) = (expression); \ + } while ((result) == (error_result) && errno == EINTR) +#else +# define FMT_RETRY_VAL(result, expression, error_result) result = (expression) +#endif + +#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) + +FMT_BEGIN_NAMESPACE +FMT_BEGIN_EXPORT + +/** + * A reference to a null-terminated string. It can be constructed from a C + * string or `std::string`. + * + * You can use one of the following type aliases for common character types: + * + * +---------------+-----------------------------+ + * | Type | Definition | + * +===============+=============================+ + * | cstring_view | basic_cstring_view | + * +---------------+-----------------------------+ + * | wcstring_view | basic_cstring_view | + * +---------------+-----------------------------+ + * + * This class is most useful as a parameter type for functions that wrap C APIs. + */ +template class basic_cstring_view { + private: + const Char* data_; + + public: + /// Constructs a string reference object from a C string. + basic_cstring_view(const Char* s) : data_(s) {} + + /// Constructs a string reference from an `std::string` object. + basic_cstring_view(const std::basic_string& s) : data_(s.c_str()) {} + + /// Returns the pointer to a C string. + auto c_str() const -> const Char* { return data_; } +}; + +using cstring_view = basic_cstring_view; +using wcstring_view = basic_cstring_view; + +#ifdef _WIN32 +FMT_API const std::error_category& system_category() noexcept; + +namespace detail { +FMT_API void format_windows_error(buffer& out, int error_code, + const char* message) noexcept; +} + +FMT_API std::system_error vwindows_error(int error_code, string_view fmt, + format_args args); + +/** + * Constructs a `std::system_error` object with the description of the form + * + * : + * + * where `` is the formatted message and `` is the + * system message corresponding to the error code. + * `error_code` is a Windows error code as given by `GetLastError`. + * If `error_code` is not a valid error code such as -1, the system message + * will look like "error -1". + * + * **Example**: + * + * // This throws a system_error with the description + * // cannot open file 'madeup': The system cannot find the file + * specified. + * // or similar (system message may vary). + * const char *filename = "madeup"; + * LPOFSTRUCT of = LPOFSTRUCT(); + * HFILE file = OpenFile(filename, &of, OF_READ); + * if (file == HFILE_ERROR) { + * throw fmt::windows_error(GetLastError(), + * "cannot open file '{}'", filename); + * } + */ +template +auto windows_error(int error_code, string_view message, const T&... args) + -> std::system_error { + return vwindows_error(error_code, message, vargs{{args...}}); +} + +// Reports a Windows error without throwing an exception. +// Can be used to report errors from destructors. +FMT_API void report_windows_error(int error_code, const char* message) noexcept; +#else +inline auto system_category() noexcept -> const std::error_category& { + return std::system_category(); +} +#endif // _WIN32 + +// std::system is not available on some platforms such as iOS (#2248). +#ifdef __OSX__ +template > +void say(const S& fmt, Args&&... args) { + std::system(format("say \"{}\"", format(fmt, args...)).c_str()); +} +#endif + +// A buffered file. +class buffered_file { + private: + FILE* file_; + + friend class file; + + inline explicit buffered_file(FILE* f) : file_(f) {} + + public: + buffered_file(const buffered_file&) = delete; + void operator=(const buffered_file&) = delete; + + // Constructs a buffered_file object which doesn't represent any file. + inline buffered_file() noexcept : file_(nullptr) {} + + // Destroys the object closing the file it represents if any. + FMT_API ~buffered_file() noexcept; + + public: + inline buffered_file(buffered_file&& other) noexcept : file_(other.file_) { + other.file_ = nullptr; + } + + inline auto operator=(buffered_file&& other) -> buffered_file& { + close(); + file_ = other.file_; + other.file_ = nullptr; + return *this; + } + + // Opens a file. + FMT_API buffered_file(cstring_view filename, cstring_view mode); + + // Closes the file. + FMT_API void close(); + + // Returns the pointer to a FILE object representing this file. + inline auto get() const noexcept -> FILE* { return file_; } + + FMT_API auto descriptor() const -> int; + + template + inline void print(string_view fmt, const T&... args) { + fmt::vargs vargs = {{args...}}; + detail::is_locking() ? fmt::vprint_buffered(file_, fmt, vargs) + : fmt::vprint(file_, fmt, vargs); + } +}; + +#if FMT_USE_FCNTL + +// A file. Closed file is represented by a file object with descriptor -1. +// Methods that are not declared with noexcept may throw +// fmt::system_error in case of failure. Note that some errors such as +// closing the file multiple times will cause a crash on Windows rather +// than an exception. You can get standard behavior by overriding the +// invalid parameter handler with _set_invalid_parameter_handler. +class FMT_API file { + private: + int fd_; // File descriptor. + + // Constructs a file object with a given descriptor. + explicit file(int fd) : fd_(fd) {} + + friend struct pipe; + + public: + // Possible values for the oflag argument to the constructor. + enum { + RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. + WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. + RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing. + CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist. + APPEND = FMT_POSIX(O_APPEND), // Open in append mode. + TRUNC = FMT_POSIX(O_TRUNC) // Truncate the content of the file. + }; + + // Constructs a file object which doesn't represent any file. + inline file() noexcept : fd_(-1) {} + + // Opens a file and constructs a file object representing this file. + file(cstring_view path, int oflag); + + public: + file(const file&) = delete; + void operator=(const file&) = delete; + + inline file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; } + + // Move assignment is not noexcept because close may throw. + inline auto operator=(file&& other) -> file& { + close(); + fd_ = other.fd_; + other.fd_ = -1; + return *this; + } + + // Destroys the object closing the file it represents if any. + ~file() noexcept; + + // Returns the file descriptor. + inline auto descriptor() const noexcept -> int { return fd_; } + + // Closes the file. + void close(); + + // Returns the file size. The size has signed type for consistency with + // stat::st_size. + auto size() const -> long long; + + // Attempts to read count bytes from the file into the specified buffer. + auto read(void* buffer, size_t count) -> size_t; + + // Attempts to write count bytes from the specified buffer to the file. + auto write(const void* buffer, size_t count) -> size_t; + + // Duplicates a file descriptor with the dup function and returns + // the duplicate as a file object. + static auto dup(int fd) -> file; + + // Makes fd be the copy of this file descriptor, closing fd first if + // necessary. + void dup2(int fd); + + // Makes fd be the copy of this file descriptor, closing fd first if + // necessary. + void dup2(int fd, std::error_code& ec) noexcept; + + // Creates a buffered_file object associated with this file and detaches + // this file object from the file. + auto fdopen(const char* mode) -> buffered_file; + +# if defined(_WIN32) && !defined(__MINGW32__) + // Opens a file and constructs a file object representing this file by + // wcstring_view filename. Windows only. + static file open_windows_file(wcstring_view path, int oflag); +# endif +}; + +struct FMT_API pipe { + file read_end; + file write_end; + + // Creates a pipe setting up read_end and write_end file objects for reading + // and writing respectively. + pipe(); +}; + +// Returns the memory page size. +auto getpagesize() -> long; + +namespace detail { + +struct buffer_size { + constexpr buffer_size() = default; + size_t value = 0; + FMT_CONSTEXPR auto operator=(size_t val) const -> buffer_size { + auto bs = buffer_size(); + bs.value = val; + return bs; + } +}; + +struct ostream_params { + int oflag = file::WRONLY | file::CREATE | file::TRUNC; + size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768; + + constexpr ostream_params() {} + + template + ostream_params(T... params, int new_oflag) : ostream_params(params...) { + oflag = new_oflag; + } + + template + ostream_params(T... params, detail::buffer_size bs) + : ostream_params(params...) { + this->buffer_size = bs.value; + } + +// Intel has a bug that results in failure to deduce a constructor +// for empty parameter packs. +# if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000 + ostream_params(int new_oflag) : oflag(new_oflag) {} + ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {} +# endif +}; + +} // namespace detail + +FMT_INLINE_VARIABLE constexpr auto buffer_size = detail::buffer_size(); + +/// A fast buffered output stream for writing from a single thread. Writing from +/// multiple threads without external synchronization may result in a data race. +class FMT_API ostream : private detail::buffer { + private: + file file_; + + ostream(cstring_view path, const detail::ostream_params& params); + + static void grow(buffer& buf, size_t); + + public: + ostream(ostream&& other) noexcept; + ~ostream(); + + operator writer() { + detail::buffer& buf = *this; + return buf; + } + + inline void flush() { + if (size() == 0) return; + file_.write(data(), size() * sizeof(data()[0])); + clear(); + } + + template + friend auto output_file(cstring_view path, T... params) -> ostream; + + inline void close() { + flush(); + file_.close(); + } + + /// Formats `args` according to specifications in `fmt` and writes the + /// output to the file. + template void print(format_string fmt, T&&... args) { + vformat_to(appender(*this), fmt.str, vargs{{args...}}); + } +}; + +/** + * Opens a file for writing. Supported parameters passed in `params`: + * + * - ``: Flags passed to [open]( + * https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html) + * (`file::WRONLY | file::CREATE | file::TRUNC` by default) + * - `buffer_size=`: Output buffer size + * + * **Example**: + * + * auto out = fmt::output_file("guide.txt"); + * out.print("Don't {}", "Panic"); + */ +template +inline auto output_file(cstring_view path, T... params) -> ostream { + return {path, detail::ostream_params(params...)}; +} +#endif // FMT_USE_FCNTL + +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_OS_H_ diff --git a/include/fmt/ostream.h b/include/fmt/ostream.h new file mode 100644 index 0000000..5d893c9 --- /dev/null +++ b/include/fmt/ostream.h @@ -0,0 +1,166 @@ +// Formatting library for C++ - std::ostream support +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_OSTREAM_H_ +#define FMT_OSTREAM_H_ + +#ifndef FMT_MODULE +# include // std::filebuf +#endif + +#ifdef _WIN32 +# ifdef __GLIBCXX__ +# include +# include +# endif +# include +#endif + +#include "chrono.h" // formatbuf + +#ifdef _MSVC_STL_UPDATE +# define FMT_MSVC_STL_UPDATE _MSVC_STL_UPDATE +#elif defined(_MSC_VER) && _MSC_VER < 1912 // VS 15.5 +# define FMT_MSVC_STL_UPDATE _MSVC_LANG +#else +# define FMT_MSVC_STL_UPDATE 0 +#endif + +FMT_BEGIN_NAMESPACE +namespace detail { + +// Generate a unique explicit instantion in every translation unit using a tag +// type in an anonymous namespace. +namespace { +struct file_access_tag {}; +} // namespace +template +class file_access { + friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; } +}; + +#if FMT_MSVC_STL_UPDATE +template class file_access; +auto get_file(std::filebuf&) -> FILE*; +#endif + +// Write the content of buf to os. +// It is a separate function rather than a part of vprint to simplify testing. +template +void write_buffer(std::basic_ostream& os, buffer& buf) { + const Char* buf_data = buf.data(); + using unsigned_streamsize = make_unsigned_t; + unsigned_streamsize size = buf.size(); + unsigned_streamsize max_size = to_unsigned(max_value()); + do { + unsigned_streamsize n = size <= max_size ? size : max_size; + os.write(buf_data, static_cast(n)); + buf_data += n; + size -= n; + } while (size != 0); +} + +template struct streamed_view { + const T& value; +}; +} // namespace detail + +// Formats an object of type T that has an overloaded ostream operator<<. +template +struct basic_ostream_formatter : formatter, Char> { + void set_debug_format() = delete; + + template + auto format(const T& value, Context& ctx) const -> decltype(ctx.out()) { + auto buffer = basic_memory_buffer(); + auto&& formatbuf = detail::formatbuf>(buffer); + auto&& output = std::basic_ostream(&formatbuf); + output.imbue(std::locale::classic()); // The default is always unlocalized. + output << value; + output.exceptions(std::ios_base::failbit | std::ios_base::badbit); + return formatter, Char>::format( + {buffer.data(), buffer.size()}, ctx); + } +}; + +using ostream_formatter = basic_ostream_formatter; + +template +struct formatter, Char> + : basic_ostream_formatter { + template + auto format(detail::streamed_view view, Context& ctx) const + -> decltype(ctx.out()) { + return basic_ostream_formatter::format(view.value, ctx); + } +}; + +/** + * Returns a view that formats `value` via an ostream `operator<<`. + * + * **Example**: + * + * fmt::print("Current thread id: {}\n", + * fmt::streamed(std::this_thread::get_id())); + */ +template +constexpr auto streamed(const T& value) -> detail::streamed_view { + return {value}; +} + +inline void vprint(std::ostream& os, string_view fmt, format_args args) { + auto buffer = memory_buffer(); + detail::vformat_to(buffer, fmt, args); + FILE* f = nullptr; +#if FMT_MSVC_STL_UPDATE && FMT_USE_RTTI + if (auto* buf = dynamic_cast(os.rdbuf())) + f = detail::get_file(*buf); +#elif defined(_WIN32) && defined(__GLIBCXX__) && FMT_USE_RTTI + auto* rdbuf = os.rdbuf(); + if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf*>(rdbuf)) + f = sfbuf->file(); + else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf*>(rdbuf)) + f = fbuf->file(); +#endif +#ifdef _WIN32 + if (f) { + int fd = _fileno(f); + if (_isatty(fd)) { + os.flush(); + if (detail::write_console(fd, {buffer.data(), buffer.size()})) return; + } + } +#endif + detail::ignore_unused(f); + detail::write_buffer(os, buffer); +} + +/** + * Prints formatted data to the stream `os`. + * + * **Example**: + * + * fmt::print(cerr, "Don't {}!", "panic"); + */ +FMT_EXPORT template +void print(std::ostream& os, format_string fmt, T&&... args) { + fmt::vargs vargs = {{args...}}; + if (detail::use_utf8) return vprint(os, fmt.str, vargs); + auto buffer = memory_buffer(); + detail::vformat_to(buffer, fmt.str, vargs); + detail::write_buffer(os, buffer); +} + +FMT_EXPORT template +void println(std::ostream& os, format_string fmt, T&&... args) { + fmt::print(os, "{}\n", fmt::format(fmt, std::forward(args)...)); +} + +FMT_END_NAMESPACE + +#endif // FMT_OSTREAM_H_ diff --git a/include/fmt/printf.h b/include/fmt/printf.h new file mode 100644 index 0000000..e726840 --- /dev/null +++ b/include/fmt/printf.h @@ -0,0 +1,633 @@ +// Formatting library for C++ - legacy printf implementation +// +// Copyright (c) 2012 - 2016, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_PRINTF_H_ +#define FMT_PRINTF_H_ + +#ifndef FMT_MODULE +# include // std::max +# include // std::numeric_limits +#endif + +#include "format.h" + +FMT_BEGIN_NAMESPACE +FMT_BEGIN_EXPORT + +template struct printf_formatter { + printf_formatter() = delete; +}; + +template class basic_printf_context { + private: + basic_appender out_; + basic_format_args args_; + + static_assert(std::is_same::value || + std::is_same::value, + "Unsupported code unit type."); + + public: + using char_type = Char; + using parse_context_type = parse_context; + template using formatter_type = printf_formatter; + enum { builtin_types = 1 }; + + /// Constructs a `printf_context` object. References to the arguments are + /// stored in the context object so make sure they have appropriate lifetimes. + basic_printf_context(basic_appender out, + basic_format_args args) + : out_(out), args_(args) {} + + auto out() -> basic_appender { return out_; } + void advance_to(basic_appender) {} + + auto locale() -> detail::locale_ref { return {}; } + + auto arg(int id) const -> basic_format_arg { + return args_.get(id); + } +}; + +namespace detail { + +// 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(memchr(first, value, to_unsigned(last - first))); + return out != nullptr; +} + +// Checks if a value fits in int - used to avoid warnings about comparing +// signed and unsigned integers. +template struct int_checker { + template static auto fits_in_int(T value) -> bool { + unsigned max = to_unsigned(max_value()); + return value <= max; + } + inline static auto fits_in_int(bool) -> bool { return true; } +}; + +template <> struct int_checker { + template static auto fits_in_int(T value) -> bool { + return value >= (std::numeric_limits::min)() && + value <= max_value(); + } + inline static auto fits_in_int(int) -> bool { return true; } +}; + +struct printf_precision_handler { + template ::value)> + auto operator()(T value) -> int { + if (!int_checker::is_signed>::fits_in_int(value)) + report_error("number is too big"); + return (std::max)(static_cast(value), 0); + } + + template ::value)> + auto operator()(T) -> int { + report_error("precision is not integer"); + return 0; + } +}; + +// An argument visitor that returns true iff arg is a zero integer. +struct is_zero_int { + template ::value)> + auto operator()(T value) -> bool { + return value == 0; + } + + template ::value)> + auto operator()(T) -> bool { + return false; + } +}; + +template struct make_unsigned_or_bool : std::make_unsigned {}; + +template <> struct make_unsigned_or_bool { + using type = bool; +}; + +template class arg_converter { + private: + using char_type = typename Context::char_type; + + basic_format_arg& arg_; + char_type type_; + + public: + arg_converter(basic_format_arg& arg, char_type type) + : arg_(arg), type_(type) {} + + void operator()(bool value) { + if (type_ != 's') operator()(value); + } + + template ::value)> + void operator()(U value) { + bool is_signed = type_ == 'd' || type_ == 'i'; + using target_type = conditional_t::value, U, T>; + if (const_check(sizeof(target_type) <= sizeof(int))) { + // Extra casts are used to silence warnings. + using unsigned_type = typename make_unsigned_or_bool::type; + if (is_signed) + arg_ = static_cast(static_cast(value)); + else + arg_ = static_cast(static_cast(value)); + } else { + // glibc's printf doesn't sign extend arguments of smaller types: + // std::printf("%lld", -42); // prints "4294967254" + // but we don't have to do the same because it's a UB. + if (is_signed) + arg_ = static_cast(value); + else + arg_ = static_cast::type>(value); + } + } + + template ::value)> + void operator()(U) {} // No conversion needed for non-integral types. +}; + +// Converts an integer argument to T for printf, if T is an integral type. +// If T is void, the argument is converted to corresponding signed or unsigned +// type depending on the type specifier: 'd' and 'i' - signed, other - +// unsigned). +template +void convert_arg(basic_format_arg& arg, Char type) { + arg.visit(arg_converter(arg, type)); +} + +// Converts an integer argument to char for printf. +template class char_converter { + private: + basic_format_arg& arg_; + + public: + explicit char_converter(basic_format_arg& arg) : arg_(arg) {} + + template ::value)> + void operator()(T value) { + arg_ = static_cast(value); + } + + template ::value)> + void operator()(T) {} // No conversion needed for non-integral types. +}; + +// An argument visitor that return a pointer to a C string if argument is a +// string or null otherwise. +template struct get_cstring { + template auto operator()(T) -> const Char* { return nullptr; } + auto operator()(const Char* s) -> const Char* { return s; } +}; + +// Checks if an argument is a valid printf width specifier and sets +// left alignment if it is negative. +class printf_width_handler { + private: + format_specs& specs_; + + public: + inline explicit printf_width_handler(format_specs& specs) : specs_(specs) {} + + template ::value)> + auto operator()(T value) -> unsigned { + auto width = static_cast>(value); + if (detail::is_negative(value)) { + specs_.set_align(align::left); + width = 0 - width; + } + unsigned int_max = to_unsigned(max_value()); + if (width > int_max) report_error("number is too big"); + return static_cast(width); + } + + template ::value)> + auto operator()(T) -> unsigned { + report_error("width is not integer"); + return 0; + } +}; + +// Workaround for a bug with the XL compiler when initializing +// printf_arg_formatter's base class. +template +auto make_arg_formatter(basic_appender iter, format_specs& s) + -> arg_formatter { + return {iter, s, locale_ref()}; +} + +// The `printf` argument formatter. +template +class printf_arg_formatter : public arg_formatter { + private: + using base = arg_formatter; + using context_type = basic_printf_context; + + context_type& context_; + + void write_null_pointer(bool is_string = false) { + auto s = this->specs; + s.set_type(presentation_type::none); + write_bytes(this->out, is_string ? "(null)" : "(nil)", s); + } + + template void write(T value) { + detail::write(this->out, value, this->specs, this->locale); + } + + public: + printf_arg_formatter(basic_appender iter, format_specs& s, + context_type& ctx) + : base(make_arg_formatter(iter, s)), context_(ctx) {} + + void operator()(monostate value) { write(value); } + + template ::value)> + void operator()(T value) { + // MSVC2013 fails to compile separate overloads for bool and Char so use + // std::is_same instead. + if (!std::is_same::value) { + write(value); + return; + } + format_specs s = this->specs; + if (s.type() != presentation_type::none && + s.type() != presentation_type::chr) { + return (*this)(static_cast(value)); + } + s.set_sign(sign::none); + s.clear_alt(); + s.set_fill(' '); // Ignore '0' flag for char types. + // align::numeric needs to be overwritten here since the '0' flag is + // ignored for non-numeric types + if (s.align() == align::none || s.align() == align::numeric) + s.set_align(align::right); + detail::write(this->out, static_cast(value), s); + } + + template ::value)> + void operator()(T value) { + write(value); + } + + void operator()(const char* value) { + if (value) + write(value); + else + write_null_pointer(this->specs.type() != presentation_type::pointer); + } + + void operator()(const wchar_t* value) { + if (value) + write(value); + else + write_null_pointer(this->specs.type() != presentation_type::pointer); + } + + void operator()(basic_string_view value) { write(value); } + + void operator()(const void* value) { + if (value) + write(value); + else + write_null_pointer(); + } + + void operator()(typename basic_format_arg::handle handle) { + auto parse_ctx = parse_context({}); + handle.format(parse_ctx, context_); + } +}; + +template +void parse_flags(format_specs& specs, const Char*& it, const Char* end) { + for (; it != end; ++it) { + switch (*it) { + case '-': specs.set_align(align::left); break; + case '+': specs.set_sign(sign::plus); break; + case '0': specs.set_fill('0'); break; + case ' ': + if (specs.sign() != sign::plus) specs.set_sign(sign::space); + break; + case '#': specs.set_alt(); break; + default: return; + } + } +} + +template +auto parse_header(const Char*& it, const Char* end, format_specs& specs, + GetArg get_arg) -> int { + int arg_index = -1; + Char c = *it; + if (c >= '0' && c <= '9') { + // Parse an argument index (if followed by '$') or a width possibly + // preceded with '0' flag(s). + int value = parse_nonnegative_int(it, end, -1); + if (it != end && *it == '$') { // value is an argument index + ++it; + arg_index = value != -1 ? value : max_value(); + } else { + if (c == '0') specs.set_fill('0'); + if (value != 0) { + // Nonzero value means that we parsed width and don't need to + // parse it or flags again, so return now. + if (value == -1) report_error("number is too big"); + specs.width = value; + return arg_index; + } + } + } + parse_flags(specs, it, end); + // Parse width. + if (it != end) { + if (*it >= '0' && *it <= '9') { + specs.width = parse_nonnegative_int(it, end, -1); + if (specs.width == -1) report_error("number is too big"); + } else if (*it == '*') { + ++it; + specs.width = static_cast( + get_arg(-1).visit(detail::printf_width_handler(specs))); + } + } + return arg_index; +} + +inline auto parse_printf_presentation_type(char c, type t, bool& upper) + -> presentation_type { + using pt = presentation_type; + constexpr auto integral_set = sint_set | uint_set | bool_set | char_set; + switch (c) { + case 'd': return in(t, integral_set) ? pt::dec : pt::none; + case 'o': return in(t, integral_set) ? pt::oct : pt::none; + case 'X': upper = true; FMT_FALLTHROUGH; + case 'x': return in(t, integral_set) ? pt::hex : pt::none; + case 'E': upper = true; FMT_FALLTHROUGH; + case 'e': return in(t, float_set) ? pt::exp : pt::none; + case 'F': upper = true; FMT_FALLTHROUGH; + case 'f': return in(t, float_set) ? pt::fixed : pt::none; + case 'G': upper = true; FMT_FALLTHROUGH; + case 'g': return in(t, float_set) ? pt::general : pt::none; + case 'A': upper = true; FMT_FALLTHROUGH; + case 'a': return in(t, float_set) ? pt::hexfloat : pt::none; + case 'c': return in(t, integral_set) ? pt::chr : pt::none; + case 's': return in(t, string_set | cstring_set) ? pt::string : pt::none; + case 'p': return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none; + default: return pt::none; + } +} + +template +void vprintf(buffer& buf, basic_string_view format, + basic_format_args args) { + using iterator = basic_appender; + auto out = iterator(buf); + auto context = basic_printf_context(out, args); + auto parse_ctx = parse_context(format); + + // Returns the argument with specified index or, if arg_index is -1, the next + // argument. + auto get_arg = [&](int arg_index) { + if (arg_index < 0) + arg_index = parse_ctx.next_arg_id(); + else + parse_ctx.check_arg_id(--arg_index); + return detail::get_arg(context, arg_index); + }; + + const Char* start = parse_ctx.begin(); + const Char* end = parse_ctx.end(); + auto it = start; + while (it != end) { + if (!find(it, end, '%', it)) { + it = end; // find leaves it == nullptr if it doesn't find '%'. + break; + } + Char c = *it++; + if (it != end && *it == c) { + write(out, basic_string_view(start, to_unsigned(it - start))); + start = ++it; + continue; + } + write(out, basic_string_view(start, to_unsigned(it - 1 - start))); + + auto specs = format_specs(); + specs.set_align(align::right); + + // Parse argument index, flags and width. + int arg_index = parse_header(it, end, specs, get_arg); + if (arg_index == 0) report_error("argument not found"); + + // Parse precision. + if (it != end && *it == '.') { + ++it; + c = it != end ? *it : 0; + if ('0' <= c && c <= '9') { + specs.precision = parse_nonnegative_int(it, end, 0); + } else if (c == '*') { + ++it; + specs.precision = + static_cast(get_arg(-1).visit(printf_precision_handler())); + } else { + specs.precision = 0; + } + } + + auto arg = get_arg(arg_index); + // For d, i, o, u, x, and X conversion specifiers, if a precision is + // specified, the '0' flag is ignored + if (specs.precision >= 0 && is_integral_type(arg.type())) { + // Ignore '0' for non-numeric types or if '-' present. + specs.set_fill(' '); + } + if (specs.precision >= 0 && arg.type() == type::cstring_type) { + auto str = arg.visit(get_cstring()); + auto str_end = str + specs.precision; + auto nul = std::find(str, str_end, Char()); + auto sv = basic_string_view( + str, to_unsigned(nul != str_end ? nul - str : specs.precision)); + arg = sv; + } + if (specs.alt() && arg.visit(is_zero_int())) specs.clear_alt(); + if (specs.fill_unit() == '0') { + if (is_arithmetic_type(arg.type()) && specs.align() != align::left) { + specs.set_align(align::numeric); + } else { + // Ignore '0' flag for non-numeric types or if '-' flag is also present. + specs.set_fill(' '); + } + } + + // Parse length and convert the argument to the required type. + c = it != end ? *it++ : 0; + Char t = it != end ? *it : 0; + switch (c) { + case 'h': + if (t == 'h') { + ++it; + t = it != end ? *it : 0; + convert_arg(arg, t); + } else { + convert_arg(arg, t); + } + break; + case 'l': + if (t == 'l') { + ++it; + t = it != end ? *it : 0; + convert_arg(arg, t); + } else { + convert_arg(arg, t); + } + break; + case 'j': convert_arg(arg, t); break; + case 'z': convert_arg(arg, t); break; + case 't': convert_arg(arg, t); break; + case 'L': + // printf produces garbage when 'L' is omitted for long double, no + // need to do the same. + break; + default: --it; convert_arg(arg, c); + } + + // Parse type. + if (it == end) report_error("invalid format string"); + char type = static_cast(*it++); + if (is_integral_type(arg.type())) { + // Normalize type. + switch (type) { + case 'i': + case 'u': type = 'd'; break; + case 'c': + arg.visit(char_converter>(arg)); + break; + } + } + bool upper = false; + specs.set_type(parse_printf_presentation_type(type, arg.type(), upper)); + if (specs.type() == presentation_type::none) + report_error("invalid format specifier"); + if (upper) specs.set_upper(); + + start = it; + + // Format argument. + arg.visit(printf_arg_formatter(out, specs, context)); + } + write(out, basic_string_view(start, to_unsigned(it - start))); +} +} // namespace detail + +using printf_context = basic_printf_context; +using wprintf_context = basic_printf_context; + +using printf_args = basic_format_args; +using wprintf_args = basic_format_args; + +/// Constructs an `format_arg_store` object that contains references to +/// arguments and can be implicitly converted to `printf_args`. +template +inline auto make_printf_args(T&... args) + -> decltype(fmt::make_format_args>(args...)) { + return fmt::make_format_args>(args...); +} + +template struct vprintf_args { + using type = basic_format_args>; +}; + +template +inline auto vsprintf(basic_string_view fmt, + typename vprintf_args::type args) + -> std::basic_string { + auto buf = basic_memory_buffer(); + detail::vprintf(buf, fmt, args); + return {buf.data(), buf.size()}; +} + +/** + * Formats `args` according to specifications in `fmt` and returns the result + * as as string. + * + * **Example**: + * + * std::string message = fmt::sprintf("The answer is %d", 42); + */ +template > +inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string { + return vsprintf(detail::to_string_view(fmt), + fmt::make_format_args>(args...)); +} + +template +inline auto vfprintf(std::FILE* f, basic_string_view fmt, + typename vprintf_args::type args) -> int { + auto buf = basic_memory_buffer(); + detail::vprintf(buf, fmt, args); + size_t size = buf.size(); + return std::fwrite(buf.data(), sizeof(Char), size, f) < size + ? -1 + : static_cast(size); +} + +/** + * Formats `args` according to specifications in `fmt` and writes the output + * to `f`. + * + * **Example**: + * + * fmt::fprintf(stderr, "Don't %s!", "panic"); + */ +template > +inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int { + return vfprintf(f, detail::to_string_view(fmt), + make_printf_args(args...)); +} + +template +FMT_DEPRECATED inline auto vprintf(basic_string_view fmt, + typename vprintf_args::type args) + -> int { + return vfprintf(stdout, fmt, args); +} + +/** + * Formats `args` according to specifications in `fmt` and writes the output + * to `stdout`. + * + * **Example**: + * + * fmt::printf("Elapsed time: %.2f seconds", 1.23); + */ +template +inline auto printf(string_view fmt, const T&... args) -> int { + return vfprintf(stdout, fmt, make_printf_args(args...)); +} +template +FMT_DEPRECATED inline auto printf(basic_string_view fmt, + const T&... args) -> int { + return vfprintf(stdout, fmt, make_printf_args(args...)); +} + +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_PRINTF_H_ diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h new file mode 100644 index 0000000..118d24f --- /dev/null +++ b/include/fmt/ranges.h @@ -0,0 +1,848 @@ +// Formatting library for C++ - range and tuple support +// +// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_RANGES_H_ +#define FMT_RANGES_H_ + +#ifndef FMT_MODULE +# include +# include +# include +# include +# include +# include +#endif + +#include "format.h" + +FMT_BEGIN_NAMESPACE + +FMT_EXPORT +enum class range_format { disabled, map, set, sequence, string, debug_string }; + +namespace detail { + +template class is_map { + template static auto check(U*) -> typename U::mapped_type; + template static void check(...); + + public: + static constexpr const bool value = + !std::is_void(nullptr))>::value; +}; + +template class is_set { + template static auto check(U*) -> typename U::key_type; + template static void check(...); + + public: + static constexpr const bool value = + !std::is_void(nullptr))>::value && !is_map::value; +}; + +// C array overload +template +auto range_begin(const T (&arr)[N]) -> const T* { + return arr; +} +template +auto range_end(const T (&arr)[N]) -> const T* { + return arr + N; +} + +template +struct has_member_fn_begin_end_t : std::false_type {}; + +template +struct has_member_fn_begin_end_t().begin()), + decltype(std::declval().end())>> + : std::true_type {}; + +// Member function overloads. +template +auto range_begin(T&& rng) -> decltype(static_cast(rng).begin()) { + return static_cast(rng).begin(); +} +template +auto range_end(T&& rng) -> decltype(static_cast(rng).end()) { + return static_cast(rng).end(); +} + +// ADL overloads. Only participate in overload resolution if member functions +// are not found. +template +auto range_begin(T&& rng) + -> enable_if_t::value, + decltype(begin(static_cast(rng)))> { + return begin(static_cast(rng)); +} +template +auto range_end(T&& rng) -> enable_if_t::value, + decltype(end(static_cast(rng)))> { + return end(static_cast(rng)); +} + +template +struct has_const_begin_end : std::false_type {}; +template +struct has_mutable_begin_end : std::false_type {}; + +template +struct has_const_begin_end< + T, void_t&>())), + decltype(detail::range_end( + std::declval&>()))>> + : std::true_type {}; + +template +struct has_mutable_begin_end< + T, void_t())), + decltype(detail::range_end(std::declval())), + // the extra int here is because older versions of MSVC don't + // SFINAE properly unless there are distinct types + int>> : std::true_type {}; + +template struct is_range_ : std::false_type {}; +template +struct is_range_ + : std::integral_constant::value || + has_mutable_begin_end::value)> {}; + +// tuple_size and tuple_element check. +template class is_tuple_like_ { + template ::type> + static auto check(U* p) -> decltype(std::tuple_size::value, 0); + template static void check(...); + + public: + static constexpr const bool value = + !std::is_void(nullptr))>::value; +}; + +// Check for integer_sequence +#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900 +template +using integer_sequence = std::integer_sequence; +template using index_sequence = std::index_sequence; +template using make_index_sequence = std::make_index_sequence; +#else +template struct integer_sequence { + using value_type = T; + + static FMT_CONSTEXPR auto size() -> size_t { return sizeof...(N); } +}; + +template using index_sequence = integer_sequence; + +template +struct make_integer_sequence : make_integer_sequence {}; +template +struct make_integer_sequence : integer_sequence {}; + +template +using make_index_sequence = make_integer_sequence; +#endif + +template +using tuple_index_sequence = make_index_sequence::value>; + +template ::value> +class is_tuple_formattable_ { + public: + static constexpr const bool value = false; +}; +template class is_tuple_formattable_ { + template + static auto all_true(index_sequence, + integer_sequence= 0)...>) -> std::true_type; + static auto all_true(...) -> std::false_type; + + template + static auto check(index_sequence) -> decltype(all_true( + index_sequence{}, + integer_sequence::type, + C>::value)...>{})); + + public: + static constexpr const bool value = + decltype(check(tuple_index_sequence{}))::value; +}; + +template +FMT_CONSTEXPR void for_each(index_sequence, Tuple&& t, F&& f) { + using std::get; + // Using a free function get(Tuple) now. + const int unused[] = {0, ((void)f(get(t)), 0)...}; + ignore_unused(unused); +} + +template +FMT_CONSTEXPR void for_each(Tuple&& t, F&& f) { + for_each(tuple_index_sequence>(), + std::forward(t), std::forward(f)); +} + +template +void for_each2(index_sequence, Tuple1&& t1, Tuple2&& t2, F&& f) { + using std::get; + const int unused[] = {0, ((void)f(get(t1), get(t2)), 0)...}; + ignore_unused(unused); +} + +template +void for_each2(Tuple1&& t1, Tuple2&& t2, F&& f) { + for_each2(tuple_index_sequence>(), + std::forward(t1), std::forward(t2), + std::forward(f)); +} + +namespace tuple { +// Workaround a bug in MSVC 2019 (v140). +template +using result_t = std::tuple, Char>...>; + +using std::get; +template +auto get_formatters(index_sequence) + -> result_t(std::declval()))...>; +} // namespace tuple + +#if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920 +// Older MSVC doesn't get the reference type correctly for arrays. +template struct range_reference_type_impl { + using type = decltype(*detail::range_begin(std::declval())); +}; + +template struct range_reference_type_impl { + using type = T&; +}; + +template +using range_reference_type = typename range_reference_type_impl::type; +#else +template +using range_reference_type = + decltype(*detail::range_begin(std::declval())); +#endif + +// We don't use the Range's value_type for anything, but we do need the Range's +// reference type, with cv-ref stripped. +template +using uncvref_type = remove_cvref_t>; + +template +FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set) + -> decltype(f.set_debug_format(set)) { + f.set_debug_format(set); +} +template +FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {} + +template +struct range_format_kind_ + : std::integral_constant, T>::value + ? range_format::disabled + : is_map::value ? range_format::map + : is_set::value ? range_format::set + : range_format::sequence> {}; + +template +using range_format_constant = std::integral_constant; + +// These are not generic lambdas for compatibility with C++11. +template struct parse_empty_specs { + template FMT_CONSTEXPR void operator()(Formatter& f) { + f.parse(ctx); + detail::maybe_set_debug_format(f, true); + } + parse_context& ctx; +}; +template struct format_tuple_element { + using char_type = typename FormatContext::char_type; + + template + void operator()(const formatter& f, const T& v) { + if (i > 0) ctx.advance_to(detail::copy(separator, ctx.out())); + ctx.advance_to(f.format(v, ctx)); + ++i; + } + + int i; + FormatContext& ctx; + basic_string_view separator; +}; + +} // namespace detail + +template struct is_tuple_like { + static constexpr const bool value = + detail::is_tuple_like_::value && !detail::is_range_::value; +}; + +template struct is_tuple_formattable { + static constexpr const bool value = + detail::is_tuple_formattable_::value; +}; + +template +struct formatter::value && + fmt::is_tuple_formattable::value>> { + private: + decltype(detail::tuple::get_formatters( + detail::tuple_index_sequence())) formatters_; + + basic_string_view separator_ = detail::string_literal{}; + basic_string_view opening_bracket_ = + detail::string_literal{}; + basic_string_view closing_bracket_ = + detail::string_literal{}; + + public: + FMT_CONSTEXPR formatter() {} + + FMT_CONSTEXPR void set_separator(basic_string_view sep) { + separator_ = sep; + } + + FMT_CONSTEXPR void set_brackets(basic_string_view open, + basic_string_view close) { + opening_bracket_ = open; + closing_bracket_ = close; + } + + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + auto it = ctx.begin(); + auto end = ctx.end(); + if (it != end && detail::to_ascii(*it) == 'n') { + ++it; + set_brackets({}, {}); + set_separator({}); + } + if (it != end && *it != '}') report_error("invalid format specifier"); + ctx.advance_to(it); + detail::for_each(formatters_, detail::parse_empty_specs{ctx}); + return it; + } + + template + auto format(const Tuple& value, FormatContext& ctx) const + -> decltype(ctx.out()) { + ctx.advance_to(detail::copy(opening_bracket_, ctx.out())); + detail::for_each2( + formatters_, value, + detail::format_tuple_element{0, ctx, separator_}); + return detail::copy(closing_bracket_, ctx.out()); + } +}; + +template struct is_range { + static constexpr const bool value = + detail::is_range_::value && !detail::has_to_string_view::value; +}; + +namespace detail { + +template +using range_formatter_type = formatter, Char>; + +template +using maybe_const_range = + conditional_t::value, const R, R>; + +template +struct is_formattable_delayed + : is_formattable>, Char> {}; +} // namespace detail + +template struct conjunction : std::true_type {}; +template struct conjunction

: P {}; +template +struct conjunction + : conditional_t, P1> {}; + +template +struct range_formatter; + +template +struct range_formatter< + T, Char, + enable_if_t>, + is_formattable>::value>> { + private: + detail::range_formatter_type underlying_; + basic_string_view separator_ = detail::string_literal{}; + basic_string_view opening_bracket_ = + detail::string_literal{}; + basic_string_view closing_bracket_ = + detail::string_literal{}; + bool is_debug = false; + + template ::value)> + auto write_debug_string(Output& out, It it, Sentinel end) const -> Output { + auto buf = basic_memory_buffer(); + for (; it != end; ++it) buf.push_back(*it); + auto specs = format_specs(); + specs.set_type(presentation_type::debug); + return detail::write( + out, basic_string_view(buf.data(), buf.size()), specs); + } + + template ::value)> + auto write_debug_string(Output& out, It, Sentinel) const -> Output { + return out; + } + + public: + FMT_CONSTEXPR range_formatter() {} + + FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type& { + return underlying_; + } + + FMT_CONSTEXPR void set_separator(basic_string_view sep) { + separator_ = sep; + } + + FMT_CONSTEXPR void set_brackets(basic_string_view open, + basic_string_view close) { + opening_bracket_ = open; + closing_bracket_ = close; + } + + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + auto it = ctx.begin(); + auto end = ctx.end(); + detail::maybe_set_debug_format(underlying_, true); + if (it == end) return underlying_.parse(ctx); + + switch (detail::to_ascii(*it)) { + case 'n': + set_brackets({}, {}); + ++it; + break; + case '?': + is_debug = true; + set_brackets({}, {}); + ++it; + if (it == end || *it != 's') report_error("invalid format specifier"); + FMT_FALLTHROUGH; + case 's': + if (!std::is_same::value) + report_error("invalid format specifier"); + if (!is_debug) { + set_brackets(detail::string_literal{}, + detail::string_literal{}); + set_separator({}); + detail::maybe_set_debug_format(underlying_, false); + } + ++it; + return it; + } + + if (it != end && *it != '}') { + if (*it != ':') report_error("invalid format specifier"); + detail::maybe_set_debug_format(underlying_, false); + ++it; + } + + ctx.advance_to(it); + return underlying_.parse(ctx); + } + + template + auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) { + auto out = ctx.out(); + auto it = detail::range_begin(range); + auto end = detail::range_end(range); + if (is_debug) return write_debug_string(out, std::move(it), end); + + out = detail::copy(opening_bracket_, out); + int i = 0; + for (; it != end; ++it) { + if (i > 0) out = detail::copy(separator_, out); + ctx.advance_to(out); + auto&& item = *it; // Need an lvalue + out = underlying_.format(item, ctx); + ++i; + } + out = detail::copy(closing_bracket_, out); + return out; + } +}; + +FMT_EXPORT +template +struct range_format_kind + : conditional_t< + is_range::value, detail::range_format_kind_, + std::integral_constant> {}; + +template +struct formatter< + R, Char, + enable_if_t::value != range_format::disabled && + range_format_kind::value != range_format::map && + range_format_kind::value != range_format::string && + range_format_kind::value != range_format::debug_string>, + detail::is_formattable_delayed>::value>> { + private: + using range_type = detail::maybe_const_range; + range_formatter, Char> range_formatter_; + + public: + using nonlocking = void; + + FMT_CONSTEXPR formatter() { + if (detail::const_check(range_format_kind::value != + range_format::set)) + return; + range_formatter_.set_brackets(detail::string_literal{}, + detail::string_literal{}); + } + + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + return range_formatter_.parse(ctx); + } + + template + auto format(range_type& range, FormatContext& ctx) const + -> decltype(ctx.out()) { + return range_formatter_.format(range, ctx); + } +}; + +// A map formatter. +template +struct formatter< + R, Char, + enable_if_t::value == range_format::map>> { + private: + using map_type = detail::maybe_const_range; + using element_type = detail::uncvref_type; + + decltype(detail::tuple::get_formatters( + detail::tuple_index_sequence())) formatters_; + bool no_delimiters_ = false; + + public: + FMT_CONSTEXPR formatter() {} + + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + auto it = ctx.begin(); + auto end = ctx.end(); + if (it != end) { + if (detail::to_ascii(*it) == 'n') { + no_delimiters_ = true; + ++it; + } + if (it != end && *it != '}') { + if (*it != ':') report_error("invalid format specifier"); + ++it; + } + ctx.advance_to(it); + } + detail::for_each(formatters_, detail::parse_empty_specs{ctx}); + return it; + } + + template + auto format(map_type& map, FormatContext& ctx) const -> decltype(ctx.out()) { + auto out = ctx.out(); + basic_string_view open = detail::string_literal{}; + if (!no_delimiters_) out = detail::copy(open, out); + int i = 0; + basic_string_view sep = detail::string_literal{}; + for (auto&& value : map) { + if (i > 0) out = detail::copy(sep, out); + ctx.advance_to(out); + detail::for_each2(formatters_, value, + detail::format_tuple_element{ + 0, ctx, detail::string_literal{}}); + ++i; + } + basic_string_view close = detail::string_literal{}; + if (!no_delimiters_) out = detail::copy(close, out); + return out; + } +}; + +// A (debug_)string formatter. +template +struct formatter< + R, Char, + enable_if_t::value == range_format::string || + range_format_kind::value == + range_format::debug_string>> { + private: + using range_type = detail::maybe_const_range; + using string_type = + conditional_t, + decltype(detail::range_begin(std::declval())), + decltype(detail::range_end(std::declval()))>::value, + detail::std_string_view, std::basic_string>; + + formatter underlying_; + + public: + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + return underlying_.parse(ctx); + } + + template + auto format(range_type& range, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto out = ctx.out(); + if (detail::const_check(range_format_kind::value == + range_format::debug_string)) + *out++ = '"'; + out = underlying_.format( + string_type{detail::range_begin(range), detail::range_end(range)}, ctx); + if (detail::const_check(range_format_kind::value == + range_format::debug_string)) + *out++ = '"'; + return out; + } +}; + +template +struct join_view : detail::view { + It begin; + Sentinel end; + basic_string_view sep; + + join_view(It b, Sentinel e, basic_string_view s) + : begin(std::move(b)), end(e), sep(s) {} +}; + +template +struct formatter, Char> { + private: + using value_type = +#ifdef __cpp_lib_ranges + std::iter_value_t; +#else + typename std::iterator_traits::value_type; +#endif + formatter, Char> value_formatter_; + + using view = conditional_t::value, + const join_view, + join_view>; + + public: + using nonlocking = void; + + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + return value_formatter_.parse(ctx); + } + + template + auto format(view& value, FormatContext& ctx) const -> decltype(ctx.out()) { + using iter = + conditional_t::value, It, It&>; + iter it = value.begin; + auto out = ctx.out(); + if (it == value.end) return out; + out = value_formatter_.format(*it, ctx); + ++it; + while (it != value.end) { + out = detail::copy(value.sep.begin(), value.sep.end(), out); + ctx.advance_to(out); + out = value_formatter_.format(*it, ctx); + ++it; + } + return out; + } +}; + +template struct tuple_join_view : detail::view { + const Tuple& tuple; + basic_string_view sep; + + tuple_join_view(const Tuple& t, basic_string_view s) + : tuple(t), sep{s} {} +}; + +// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers +// support in tuple_join. It is disabled by default because of issues with +// the dynamic width and precision. +#ifndef FMT_TUPLE_JOIN_SPECIFIERS +# define FMT_TUPLE_JOIN_SPECIFIERS 0 +#endif + +template +struct formatter, Char, + enable_if_t::value>> { + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + return do_parse(ctx, std::tuple_size()); + } + + template + auto format(const tuple_join_view& value, + FormatContext& ctx) const -> typename FormatContext::iterator { + return do_format(value, ctx, std::tuple_size()); + } + + private: + decltype(detail::tuple::get_formatters( + detail::tuple_index_sequence())) formatters_; + + FMT_CONSTEXPR auto do_parse(parse_context& ctx, + std::integral_constant) + -> const Char* { + return ctx.begin(); + } + + template + FMT_CONSTEXPR auto do_parse(parse_context& ctx, + std::integral_constant) + -> const Char* { + auto end = ctx.begin(); +#if FMT_TUPLE_JOIN_SPECIFIERS + end = std::get::value - N>(formatters_).parse(ctx); + if (N > 1) { + auto end1 = do_parse(ctx, std::integral_constant()); + if (end != end1) + report_error("incompatible format specs for tuple elements"); + } +#endif + return end; + } + + template + auto do_format(const tuple_join_view&, FormatContext& ctx, + std::integral_constant) const -> + typename FormatContext::iterator { + return ctx.out(); + } + + template + auto do_format(const tuple_join_view& value, FormatContext& ctx, + std::integral_constant) const -> + typename FormatContext::iterator { + using std::get; + auto out = + std::get::value - N>(formatters_) + .format(get::value - N>(value.tuple), ctx); + if (N <= 1) return out; + out = detail::copy(value.sep, out); + ctx.advance_to(out); + return do_format(value, ctx, std::integral_constant()); + } +}; + +namespace detail { +// Check if T has an interface like a container adaptor (e.g. std::stack, +// std::queue, std::priority_queue). +template class is_container_adaptor_like { + template static auto check(U* p) -> typename U::container_type; + template static void check(...); + + public: + static constexpr const bool value = + !std::is_void(nullptr))>::value; +}; + +template struct all { + const Container& c; + auto begin() const -> typename Container::const_iterator { return c.begin(); } + auto end() const -> typename Container::const_iterator { return c.end(); } +}; +} // namespace detail + +template +struct formatter< + T, Char, + enable_if_t, + bool_constant::value == + range_format::disabled>>::value>> + : formatter, Char> { + using all = detail::all; + template + auto format(const T& t, FormatContext& ctx) const -> decltype(ctx.out()) { + struct getter : T { + static auto get(const T& t) -> all { + return {t.*(&getter::c)}; // Access c through the derived class. + } + }; + return formatter::format(getter::get(t), ctx); + } +}; + +FMT_BEGIN_EXPORT + +/// Returns a view that formats the iterator range `[begin, end)` with elements +/// separated by `sep`. +template +auto join(It begin, Sentinel end, string_view sep) -> join_view { + return {std::move(begin), end, sep}; +} + +/** + * Returns a view that formats `range` with elements separated by `sep`. + * + * **Example**: + * + * auto v = std::vector{1, 2, 3}; + * fmt::print("{}", fmt::join(v, ", ")); + * // Output: 1, 2, 3 + * + * `fmt::join` applies passed format specifiers to the range elements: + * + * fmt::print("{:02}", fmt::join(v, ", ")); + * // Output: 01, 02, 03 + */ +template ::value)> +auto join(Range&& r, string_view sep) + -> join_view { + return {detail::range_begin(r), detail::range_end(r), sep}; +} + +/** + * Returns an object that formats `std::tuple` with elements separated by `sep`. + * + * **Example**: + * + * auto t = std::tuple{1, 'a'}; + * fmt::print("{}", fmt::join(t, ", ")); + * // Output: 1, a + */ +template ::value)> +FMT_CONSTEXPR auto join(const Tuple& tuple, string_view sep) + -> tuple_join_view { + return {tuple, sep}; +} + +/** + * Returns an object that formats `std::initializer_list` with elements + * separated by `sep`. + * + * **Example**: + * + * fmt::print("{}", fmt::join({1, 2, 3}, ", ")); + * // Output: "1, 2, 3" + */ +template +auto join(std::initializer_list list, string_view sep) + -> join_view { + return join(std::begin(list), std::end(list), sep); +} + +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_RANGES_H_ diff --git a/include/fmt/std.h b/include/fmt/std.h new file mode 100644 index 0000000..54eb2c2 --- /dev/null +++ b/include/fmt/std.h @@ -0,0 +1,726 @@ +// Formatting library for C++ - formatters for standard library types +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_STD_H_ +#define FMT_STD_H_ + +#include "format.h" +#include "ostream.h" + +#ifndef FMT_MODULE +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +// Check FMT_CPLUSPLUS to suppress a bogus warning in MSVC. +# if FMT_CPLUSPLUS >= 201703L +# if FMT_HAS_INCLUDE() && \ + (!defined(FMT_CPP_LIB_FILESYSTEM) || FMT_CPP_LIB_FILESYSTEM != 0) +# include +# endif +# if FMT_HAS_INCLUDE() +# include +# endif +# if FMT_HAS_INCLUDE() +# include +# endif +# endif +// Use > instead of >= in the version check because may be +// available after C++17 but before C++20 is marked as implemented. +# if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE() +# include +# endif +# if FMT_CPLUSPLUS > 202002L && FMT_HAS_INCLUDE() +# include +# endif +#endif // FMT_MODULE + +#if FMT_HAS_INCLUDE() +# include +#endif + +// GCC 4 does not support FMT_HAS_INCLUDE. +#if FMT_HAS_INCLUDE() || defined(__GLIBCXX__) +# include +// Android NDK with gabi++ library on some architectures does not implement +// abi::__cxa_demangle(). +# ifndef __GABIXX_CXXABI_H__ +# define FMT_HAS_ABI_CXA_DEMANGLE +# endif +#endif + +// For older Xcode versions, __cpp_lib_xxx flags are inaccurately defined. +#ifndef FMT_CPP_LIB_FILESYSTEM +# ifdef __cpp_lib_filesystem +# define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem +# else +# define FMT_CPP_LIB_FILESYSTEM 0 +# endif +#endif + +#ifndef FMT_CPP_LIB_VARIANT +# ifdef __cpp_lib_variant +# define FMT_CPP_LIB_VARIANT __cpp_lib_variant +# else +# define FMT_CPP_LIB_VARIANT 0 +# endif +#endif + +#if FMT_CPP_LIB_FILESYSTEM +FMT_BEGIN_NAMESPACE + +namespace detail { + +template +auto get_path_string(const std::filesystem::path& p, + const std::basic_string& native) { + if constexpr (std::is_same_v && std::is_same_v) + return to_utf8(native, to_utf8_error_policy::replace); + else + return p.string(); +} + +template +void write_escaped_path(basic_memory_buffer& quoted, + const std::filesystem::path& p, + const std::basic_string& native) { + if constexpr (std::is_same_v && + std::is_same_v) { + auto buf = basic_memory_buffer(); + write_escaped_string(std::back_inserter(buf), native); + bool valid = to_utf8::convert(quoted, {buf.data(), buf.size()}); + FMT_ASSERT(valid, "invalid utf16"); + } else if constexpr (std::is_same_v) { + write_escaped_string( + std::back_inserter(quoted), native); + } else { + write_escaped_string(std::back_inserter(quoted), p.string()); + } +} + +} // namespace detail + +FMT_EXPORT +template struct formatter { + private: + format_specs specs_; + detail::arg_ref width_ref_; + bool debug_ = false; + char path_type_ = 0; + + public: + FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; } + + FMT_CONSTEXPR auto parse(parse_context& ctx) { + auto it = ctx.begin(), end = ctx.end(); + if (it == end) return it; + + it = detail::parse_align(it, end, specs_); + if (it == end) return it; + + Char c = *it; + if ((c >= '0' && c <= '9') || c == '{') + it = detail::parse_width(it, end, specs_, width_ref_, ctx); + if (it != end && *it == '?') { + debug_ = true; + ++it; + } + if (it != end && (*it == 'g')) path_type_ = detail::to_ascii(*it++); + return it; + } + + template + auto format(const std::filesystem::path& p, FormatContext& ctx) const { + auto specs = specs_; + auto path_string = + !path_type_ ? p.native() + : p.generic_string(); + + detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_, + ctx); + if (!debug_) { + auto s = detail::get_path_string(p, path_string); + return detail::write(ctx.out(), basic_string_view(s), specs); + } + auto quoted = basic_memory_buffer(); + detail::write_escaped_path(quoted, p, path_string); + return detail::write(ctx.out(), + basic_string_view(quoted.data(), quoted.size()), + specs); + } +}; + +class path : public std::filesystem::path { + public: + auto display_string() const -> std::string { + const std::filesystem::path& base = *this; + return fmt::format(FMT_STRING("{}"), base); + } + auto system_string() const -> std::string { return string(); } + + auto generic_display_string() const -> std::string { + const std::filesystem::path& base = *this; + return fmt::format(FMT_STRING("{:g}"), base); + } + auto generic_system_string() const -> std::string { return generic_string(); } +}; + +FMT_END_NAMESPACE +#endif // FMT_CPP_LIB_FILESYSTEM + +FMT_BEGIN_NAMESPACE +FMT_EXPORT +template +struct formatter, Char> + : nested_formatter, Char> { + private: + // Functor because C++11 doesn't support generic lambdas. + struct writer { + const std::bitset& bs; + + template + FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt { + for (auto pos = N; pos > 0; --pos) { + out = detail::write(out, bs[pos - 1] ? Char('1') : Char('0')); + } + + return out; + } + }; + + public: + template + auto format(const std::bitset& bs, FormatContext& ctx) const + -> decltype(ctx.out()) { + return this->write_padded(ctx, writer{bs}); + } +}; + +FMT_EXPORT +template +struct formatter : basic_ostream_formatter {}; +FMT_END_NAMESPACE + +#ifdef __cpp_lib_optional +FMT_BEGIN_NAMESPACE +FMT_EXPORT +template +struct formatter, Char, + std::enable_if_t::value>> { + private: + formatter underlying_; + static constexpr basic_string_view optional = + detail::string_literal{}; + static constexpr basic_string_view none = + detail::string_literal{}; + + template + FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set) + -> decltype(u.set_debug_format(set)) { + u.set_debug_format(set); + } + + template + FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {} + + public: + FMT_CONSTEXPR auto parse(parse_context& ctx) { + maybe_set_debug_format(underlying_, true); + return underlying_.parse(ctx); + } + + template + auto format(const std::optional& opt, FormatContext& ctx) const + -> decltype(ctx.out()) { + if (!opt) return detail::write(ctx.out(), none); + + auto out = ctx.out(); + out = detail::write(out, optional); + ctx.advance_to(out); + out = underlying_.format(*opt, ctx); + return detail::write(out, ')'); + } +}; +FMT_END_NAMESPACE +#endif // __cpp_lib_optional + +#if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT + +FMT_BEGIN_NAMESPACE +namespace detail { + +template +auto write_escaped_alternative(OutputIt out, const T& v) -> OutputIt { + if constexpr (has_to_string_view::value) + return write_escaped_string(out, detail::to_string_view(v)); + if constexpr (std::is_same_v) return write_escaped_char(out, v); + return write(out, v); +} + +} // namespace detail + +FMT_END_NAMESPACE +#endif + +#ifdef __cpp_lib_expected +FMT_BEGIN_NAMESPACE + +FMT_EXPORT +template +struct formatter, Char, + std::enable_if_t<(std::is_void::value || + is_formattable::value) && + is_formattable::value>> { + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + return ctx.begin(); + } + + template + auto format(const std::expected& value, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto out = ctx.out(); + + if (value.has_value()) { + out = detail::write(out, "expected("); + if constexpr (!std::is_void::value) + out = detail::write_escaped_alternative(out, *value); + } else { + out = detail::write(out, "unexpected("); + out = detail::write_escaped_alternative(out, value.error()); + } + *out++ = ')'; + return out; + } +}; +FMT_END_NAMESPACE +#endif // __cpp_lib_expected + +#ifdef __cpp_lib_source_location +FMT_BEGIN_NAMESPACE +FMT_EXPORT +template <> struct formatter { + FMT_CONSTEXPR auto parse(parse_context<>& ctx) { return ctx.begin(); } + + template + auto format(const std::source_location& loc, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto out = ctx.out(); + out = detail::write(out, loc.file_name()); + out = detail::write(out, ':'); + out = detail::write(out, loc.line()); + out = detail::write(out, ':'); + out = detail::write(out, loc.column()); + out = detail::write(out, ": "); + out = detail::write(out, loc.function_name()); + return out; + } +}; +FMT_END_NAMESPACE +#endif + +#if FMT_CPP_LIB_VARIANT +FMT_BEGIN_NAMESPACE +namespace detail { + +template +using variant_index_sequence = + std::make_index_sequence::value>; + +template struct is_variant_like_ : std::false_type {}; +template +struct is_variant_like_> : std::true_type {}; + +// formattable element check. +template class is_variant_formattable_ { + template + static std::conjunction< + is_formattable, C>...> + check(std::index_sequence); + + public: + static constexpr const bool value = + decltype(check(variant_index_sequence{}))::value; +}; + +} // namespace detail + +template struct is_variant_like { + static constexpr const bool value = detail::is_variant_like_::value; +}; + +template struct is_variant_formattable { + static constexpr const bool value = + detail::is_variant_formattable_::value; +}; + +FMT_EXPORT +template struct formatter { + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + return ctx.begin(); + } + + template + auto format(const std::monostate&, FormatContext& ctx) const + -> decltype(ctx.out()) { + return detail::write(ctx.out(), "monostate"); + } +}; + +FMT_EXPORT +template +struct formatter< + Variant, Char, + std::enable_if_t, is_variant_formattable>>> { + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + return ctx.begin(); + } + + template + auto format(const Variant& value, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto out = ctx.out(); + + out = detail::write(out, "variant("); + FMT_TRY { + std::visit( + [&](const auto& v) { + out = detail::write_escaped_alternative(out, v); + }, + value); + } + FMT_CATCH(const std::bad_variant_access&) { + detail::write(out, "valueless by exception"); + } + *out++ = ')'; + return out; + } +}; +FMT_END_NAMESPACE +#endif // FMT_CPP_LIB_VARIANT + +FMT_BEGIN_NAMESPACE +FMT_EXPORT +template <> struct formatter { + private: + format_specs specs_; + detail::arg_ref width_ref_; + + public: + FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* { + auto it = ctx.begin(), end = ctx.end(); + if (it == end) return it; + + it = detail::parse_align(it, end, specs_); + if (it == end) return it; + + char c = *it; + if ((c >= '0' && c <= '9') || c == '{') + it = detail::parse_width(it, end, specs_, width_ref_, ctx); + return it; + } + + template + FMT_CONSTEXPR20 auto format(const std::error_code& ec, + FormatContext& ctx) const -> decltype(ctx.out()) { + auto specs = specs_; + detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_, + ctx); + memory_buffer buf; + buf.append(string_view(ec.category().name())); + buf.push_back(':'); + detail::write(appender(buf), ec.value()); + return detail::write(ctx.out(), string_view(buf.data(), buf.size()), + specs); + } +}; + +#if FMT_USE_RTTI +namespace detail { + +template +auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt { +# ifdef FMT_HAS_ABI_CXA_DEMANGLE + int status = 0; + std::size_t size = 0; + std::unique_ptr demangled_name_ptr( + abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free); + + string_view demangled_name_view; + if (demangled_name_ptr) { + demangled_name_view = demangled_name_ptr.get(); + + // Normalization of stdlib inline namespace names. + // libc++ inline namespaces. + // std::__1::* -> std::* + // std::__1::__fs::* -> std::* + // libstdc++ inline namespaces. + // std::__cxx11::* -> std::* + // std::filesystem::__cxx11::* -> std::filesystem::* + if (demangled_name_view.starts_with("std::")) { + char* begin = demangled_name_ptr.get(); + char* to = begin + 5; // std:: + for (char *from = to, *end = begin + demangled_name_view.size(); + from < end;) { + // This is safe, because demangled_name is NUL-terminated. + if (from[0] == '_' && from[1] == '_') { + char* next = from + 1; + while (next < end && *next != ':') next++; + if (next[0] == ':' && next[1] == ':') { + from = next + 2; + continue; + } + } + *to++ = *from++; + } + demangled_name_view = {begin, detail::to_unsigned(to - begin)}; + } + } else { + demangled_name_view = string_view(ti.name()); + } + return detail::write_bytes(out, demangled_name_view); +# elif FMT_MSC_VERSION + const string_view demangled_name(ti.name()); + for (std::size_t i = 0; i < demangled_name.size(); ++i) { + auto sub = demangled_name; + sub.remove_prefix(i); + if (sub.starts_with("enum ")) { + i += 4; + continue; + } + if (sub.starts_with("class ") || sub.starts_with("union ")) { + i += 5; + continue; + } + if (sub.starts_with("struct ")) { + i += 6; + continue; + } + if (*sub.begin() != ' ') *out++ = *sub.begin(); + } + return out; +# else + return detail::write_bytes(out, string_view(ti.name())); +# endif +} + +} // namespace detail + +FMT_EXPORT +template +struct formatter { + public: + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + return ctx.begin(); + } + + template + auto format(const std::type_info& ti, Context& ctx) const + -> decltype(ctx.out()) { + return detail::write_demangled_name(ctx.out(), ti); + } +}; +#endif + +FMT_EXPORT +template +struct formatter< + T, Char, // DEPRECATED! Mixing code unit types. + typename std::enable_if::value>::type> { + private: + bool with_typename_ = false; + + public: + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + auto it = ctx.begin(); + auto end = ctx.end(); + if (it == end || *it == '}') return it; + if (*it == 't') { + ++it; + with_typename_ = FMT_USE_RTTI != 0; + } + return it; + } + + template + auto format(const std::exception& ex, Context& ctx) const + -> decltype(ctx.out()) { + auto out = ctx.out(); +#if FMT_USE_RTTI + if (with_typename_) { + out = detail::write_demangled_name(out, typeid(ex)); + *out++ = ':'; + *out++ = ' '; + } +#endif + return detail::write_bytes(out, string_view(ex.what())); + } +}; + +namespace detail { + +template +struct has_flip : std::false_type {}; + +template +struct has_flip().flip())>> + : std::true_type {}; + +template struct is_bit_reference_like { + static constexpr const bool value = + std::is_convertible::value && + std::is_nothrow_assignable::value && has_flip::value; +}; + +#ifdef _LIBCPP_VERSION + +// Workaround for libc++ incompatibility with C++ standard. +// According to the Standard, `bitset::operator[] const` returns bool. +template +struct is_bit_reference_like> { + static constexpr const bool value = true; +}; + +#endif + +} // namespace detail + +// We can't use std::vector::reference and +// std::bitset::reference because the compiler can't deduce Allocator and N +// in partial specialization. +FMT_EXPORT +template +struct formatter::value>> + : formatter { + template + FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const + -> decltype(ctx.out()) { + return formatter::format(v, ctx); + } +}; + +template +auto ptr(const std::unique_ptr& p) -> const void* { + return p.get(); +} +template auto ptr(const std::shared_ptr& p) -> const void* { + return p.get(); +} + +FMT_EXPORT +template +struct formatter, Char, + enable_if_t::value>> + : formatter { + template + auto format(const std::atomic& v, FormatContext& ctx) const + -> decltype(ctx.out()) { + return formatter::format(v.load(), ctx); + } +}; + +#ifdef __cpp_lib_atomic_flag_test +FMT_EXPORT +template +struct formatter : formatter { + template + auto format(const std::atomic_flag& v, FormatContext& ctx) const + -> decltype(ctx.out()) { + return formatter::format(v.test(), ctx); + } +}; +#endif // __cpp_lib_atomic_flag_test + +FMT_EXPORT +template struct formatter, Char> { + private: + detail::dynamic_format_specs specs_; + + template + FMT_CONSTEXPR auto do_format(const std::complex& c, + detail::dynamic_format_specs& specs, + FormatContext& ctx, OutputIt out) const + -> OutputIt { + if (c.real() != 0) { + *out++ = Char('('); + out = detail::write(out, c.real(), specs, ctx.locale()); + specs.set_sign(sign::plus); + out = detail::write(out, c.imag(), specs, ctx.locale()); + if (!detail::isfinite(c.imag())) *out++ = Char(' '); + *out++ = Char('i'); + *out++ = Char(')'); + return out; + } + out = detail::write(out, c.imag(), specs, ctx.locale()); + if (!detail::isfinite(c.imag())) *out++ = Char(' '); + *out++ = Char('i'); + return out; + } + + public: + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + if (ctx.begin() == ctx.end() || *ctx.begin() == '}') return ctx.begin(); + return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, + detail::type_constant::value); + } + + template + auto format(const std::complex& c, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto specs = specs_; + if (specs.dynamic()) { + detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, + specs.width_ref, ctx); + detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision, + specs.precision_ref, ctx); + } + + if (specs.width == 0) return do_format(c, specs, ctx, ctx.out()); + auto buf = basic_memory_buffer(); + + auto outer_specs = format_specs(); + outer_specs.width = specs.width; + outer_specs.copy_fill_from(specs); + outer_specs.set_align(specs.align()); + + specs.width = 0; + specs.set_fill({}); + specs.set_align(align::none); + + do_format(c, specs, ctx, basic_appender(buf)); + return detail::write(ctx.out(), + basic_string_view(buf.data(), buf.size()), + outer_specs); + } +}; + +FMT_EXPORT +template +struct formatter, Char, + enable_if_t, Char>::value>> + : formatter, Char> { + template + auto format(std::reference_wrapper ref, FormatContext& ctx) const + -> decltype(ctx.out()) { + return formatter, Char>::format(ref.get(), ctx); + } +}; + +FMT_END_NAMESPACE +#endif // FMT_STD_H_ diff --git a/include/fmt/xchar.h b/include/fmt/xchar.h new file mode 100644 index 0000000..9f7f889 --- /dev/null +++ b/include/fmt/xchar.h @@ -0,0 +1,373 @@ +// Formatting library for C++ - optional wchar_t and exotic character support +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_XCHAR_H_ +#define FMT_XCHAR_H_ + +#include "color.h" +#include "format.h" +#include "ostream.h" +#include "ranges.h" + +#ifndef FMT_MODULE +# include +# if FMT_USE_LOCALE +# include +# endif +#endif + +FMT_BEGIN_NAMESPACE +namespace detail { + +template +using is_exotic_char = bool_constant::value>; + +template struct format_string_char {}; + +template +struct format_string_char< + S, void_t())))>> { + using type = char_t; +}; + +template +struct format_string_char< + S, enable_if_t::value>> { + using type = typename S::char_type; +}; + +template +using format_string_char_t = typename format_string_char::type; + +inline auto write_loc(basic_appender out, loc_value value, + const format_specs& specs, locale_ref loc) -> bool { +#if FMT_USE_LOCALE + auto& numpunct = + std::use_facet>(loc.get()); + auto separator = std::wstring(); + auto grouping = numpunct.grouping(); + if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep()); + return value.visit(loc_writer{out, specs, separator, grouping, {}}); +#endif + return false; +} +} // namespace detail + +FMT_BEGIN_EXPORT + +using wstring_view = basic_string_view; +using wformat_parse_context = parse_context; +using wformat_context = buffered_context; +using wformat_args = basic_format_args; +using wmemory_buffer = basic_memory_buffer; + +template struct basic_fstring { + private: + basic_string_view str_; + + static constexpr int num_static_named_args = + detail::count_static_named_args(); + + using checker = detail::format_string_checker< + Char, static_cast(sizeof...(T)), num_static_named_args, + num_static_named_args != detail::count_named_args()>; + + using arg_pack = detail::arg_pack; + + public: + using t = basic_fstring; + + template >::value)> + FMT_CONSTEVAL FMT_ALWAYS_INLINE basic_fstring(const S& s) : str_(s) { + if (FMT_USE_CONSTEVAL) + detail::parse_format_string(s, checker(s, arg_pack())); + } + template ::value&& + std::is_same::value)> + FMT_ALWAYS_INLINE basic_fstring(const S&) : str_(S()) { + FMT_CONSTEXPR auto sv = basic_string_view(S()); + FMT_CONSTEXPR int ignore = + (parse_format_string(sv, checker(sv, arg_pack())), 0); + detail::ignore_unused(ignore); + } + basic_fstring(runtime_format_string fmt) : str_(fmt.str) {} + + operator basic_string_view() const { return str_; } + auto get() const -> basic_string_view { return str_; } +}; + +template +using basic_format_string = basic_fstring; + +template +using wformat_string = typename basic_format_string::t; +inline auto runtime(wstring_view s) -> runtime_format_string { + return {{s}}; +} + +template <> struct is_char : std::true_type {}; +template <> struct is_char : std::true_type {}; +template <> struct is_char : std::true_type {}; + +#ifdef __cpp_char8_t +template <> struct is_char : bool_constant {}; +#endif + +template +constexpr auto make_wformat_args(T&... args) + -> decltype(fmt::make_format_args(args...)) { + return fmt::make_format_args(args...); +} + +#if !FMT_USE_NONTYPE_TEMPLATE_ARGS +inline namespace literals { +inline auto operator""_a(const wchar_t* s, size_t) -> detail::udl_arg { + return {s}; +} +} // namespace literals +#endif + +template +auto join(It begin, Sentinel end, wstring_view sep) + -> join_view { + return {begin, end, sep}; +} + +template ::value)> +auto join(Range&& range, wstring_view sep) + -> join_view { + return join(std::begin(range), std::end(range), sep); +} + +template +auto join(std::initializer_list list, wstring_view sep) + -> join_view { + return join(std::begin(list), std::end(list), sep); +} + +template ::value)> +auto join(const Tuple& tuple, basic_string_view sep) + -> tuple_join_view { + return {tuple, sep}; +} + +template ::value)> +auto vformat(basic_string_view fmt, + typename detail::vformat_args::type args) + -> std::basic_string { + auto buf = basic_memory_buffer(); + detail::vformat_to(buf, fmt, args); + return {buf.data(), buf.size()}; +} + +template +auto format(wformat_string fmt, T&&... args) -> std::wstring { + return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...)); +} + +template +auto format_to(OutputIt out, wformat_string fmt, T&&... args) + -> OutputIt { + return vformat_to(out, fmt::wstring_view(fmt), + fmt::make_wformat_args(args...)); +} + +// Pass char_t as a default template parameter instead of using +// std::basic_string> to reduce the symbol size. +template , + FMT_ENABLE_IF(!std::is_same::value && + !std::is_same::value)> +auto format(const S& fmt, T&&... args) -> std::basic_string { + return vformat(detail::to_string_view(fmt), + fmt::make_format_args>(args...)); +} + +template , + FMT_ENABLE_IF(detail::is_locale::value&& + detail::is_exotic_char::value)> +inline auto vformat(const Locale& loc, const S& fmt, + typename detail::vformat_args::type args) + -> std::basic_string { + auto buf = basic_memory_buffer(); + detail::vformat_to(buf, detail::to_string_view(fmt), args, + detail::locale_ref(loc)); + return {buf.data(), buf.size()}; +} + +template , + FMT_ENABLE_IF(detail::is_locale::value&& + detail::is_exotic_char::value)> +inline auto format(const Locale& loc, const S& fmt, T&&... args) + -> std::basic_string { + return vformat(loc, detail::to_string_view(fmt), + fmt::make_format_args>(args...)); +} + +template , + FMT_ENABLE_IF(detail::is_output_iterator::value&& + detail::is_exotic_char::value)> +auto vformat_to(OutputIt out, const S& fmt, + typename detail::vformat_args::type args) -> OutputIt { + auto&& buf = detail::get_buffer(out); + detail::vformat_to(buf, detail::to_string_view(fmt), args); + return detail::get_iterator(buf, out); +} + +template , + FMT_ENABLE_IF(detail::is_output_iterator::value && + !std::is_same::value && + !std::is_same::value)> +inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt { + return vformat_to(out, detail::to_string_view(fmt), + fmt::make_format_args>(args...)); +} + +template , + FMT_ENABLE_IF(detail::is_output_iterator::value&& + detail::is_locale::value&& + detail::is_exotic_char::value)> +inline auto vformat_to(OutputIt out, const Locale& loc, const S& fmt, + typename detail::vformat_args::type args) + -> OutputIt { + auto&& buf = detail::get_buffer(out); + vformat_to(buf, detail::to_string_view(fmt), args, detail::locale_ref(loc)); + return detail::get_iterator(buf, out); +} + +template , + bool enable = detail::is_output_iterator::value && + detail::is_locale::value && + detail::is_exotic_char::value> +inline auto format_to(OutputIt out, const Locale& loc, const S& fmt, + T&&... args) -> + typename std::enable_if::type { + return vformat_to(out, loc, detail::to_string_view(fmt), + fmt::make_format_args>(args...)); +} + +template ::value&& + detail::is_exotic_char::value)> +inline auto vformat_to_n(OutputIt out, size_t n, basic_string_view fmt, + typename detail::vformat_args::type 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()}; +} + +template , + FMT_ENABLE_IF(detail::is_output_iterator::value&& + detail::is_exotic_char::value)> +inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args) + -> format_to_n_result { + return vformat_to_n(out, n, fmt::basic_string_view(fmt), + fmt::make_format_args>(args...)); +} + +template , + FMT_ENABLE_IF(detail::is_exotic_char::value)> +inline auto formatted_size(const S& fmt, T&&... args) -> size_t { + auto buf = detail::counting_buffer(); + detail::vformat_to(buf, detail::to_string_view(fmt), + fmt::make_format_args>(args...)); + return buf.count(); +} + +inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) { + auto buf = wmemory_buffer(); + detail::vformat_to(buf, fmt, args); + buf.push_back(L'\0'); + if (std::fputws(buf.data(), f) == -1) + FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); +} + +inline void vprint(wstring_view fmt, wformat_args args) { + vprint(stdout, fmt, args); +} + +template +void print(std::FILE* f, wformat_string fmt, T&&... args) { + return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...)); +} + +template void print(wformat_string fmt, T&&... args) { + return vprint(wstring_view(fmt), fmt::make_wformat_args(args...)); +} + +template +void println(std::FILE* f, wformat_string fmt, T&&... args) { + return print(f, L"{}\n", fmt::format(fmt, std::forward(args)...)); +} + +template void println(wformat_string fmt, T&&... args) { + return print(L"{}\n", fmt::format(fmt, std::forward(args)...)); +} + +inline auto vformat(const text_style& ts, wstring_view fmt, wformat_args args) + -> std::wstring { + auto buf = wmemory_buffer(); + detail::vformat_to(buf, ts, fmt, args); + return {buf.data(), buf.size()}; +} + +template +inline auto format(const text_style& ts, wformat_string fmt, T&&... args) + -> std::wstring { + return fmt::vformat(ts, fmt, fmt::make_wformat_args(args...)); +} + +template +FMT_DEPRECATED void print(std::FILE* f, const text_style& ts, + wformat_string fmt, const T&... args) { + vprint(f, ts, fmt, fmt::make_wformat_args(args...)); +} + +template +FMT_DEPRECATED void print(const text_style& ts, wformat_string fmt, + const T&... args) { + return print(stdout, ts, fmt, args...); +} + +inline void vprint(std::wostream& os, wstring_view fmt, wformat_args args) { + auto buffer = basic_memory_buffer(); + detail::vformat_to(buffer, fmt, args); + detail::write_buffer(os, buffer); +} + +template +void print(std::wostream& os, wformat_string fmt, T&&... args) { + vprint(os, fmt, fmt::make_format_args>(args...)); +} + +template +void println(std::wostream& os, wformat_string fmt, T&&... args) { + print(os, L"{}\n", fmt::format(fmt, std::forward(args)...)); +} + +/// Converts `value` to `std::wstring` using the default format for type `T`. +template inline auto to_wstring(const T& value) -> std::wstring { + return format(FMT_STRING(L"{}"), value); +} +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_XCHAR_H_ diff --git a/uno.cpp b/uno.cpp new file mode 100644 index 0000000..e190468 --- /dev/null +++ b/uno.cpp @@ -0,0 +1,223 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +enum class Color { Red, Green, Blue, Yellow }; + +std::string colorToString(Color c) { + switch (c) { + case Color::Red: return "Red"; + case Color::Green: return "Green"; + case Color::Blue: return "Blue"; + case Color::Yellow: return "Yellow"; + default: return "Unknown"; + } +} + +struct Card { + Color color; + int number; + + void print() const { + fmt::color fmt_color; + switch (color) { + case Color::Red: fmt_color = fmt::color::red; break; + case Color::Green: fmt_color = fmt::color::green; break; + case Color::Blue: fmt_color = fmt::color::blue; break; + case Color::Yellow: fmt_color = fmt::color::yellow; break; + } + fmt::print(fmt::fg(fmt_color), "[{} {}] ", colorToString(color), number); + } + + bool matches(const Card& other) const { + return color == other.color || number == other.number; + } +}; + +std::vector createDeck() { + std::vector deck; + for (int c = 0; c < 4; ++c) { + for (int n = 0; n <= 9; ++n) { + // Two of each card (except 0 which appears once) + deck.push_back({ static_cast(c), n }); + if (n != 0) deck.push_back({ static_cast(c), n }); + } + } + std::shuffle(deck.begin(), deck.end(), std::mt19937{ std::random_device{}() }); + return deck; +} + +Card drawCard(std::vector& deck) { + if (deck.empty()) throw std::runtime_error("Deck is empty!"); + Card c = deck.back(); + deck.pop_back(); + return c; +} + +void printHand(const std::vector& hand) { + for (size_t i = 0; i < hand.size(); ++i) { + fmt::print("[{}] ", i); + hand[i].print(); + fmt::print("\n"); + } +} + +bool hasPlayableCard(const std::vector& hand, const Card& topCard) { + for (const auto& card : hand) { + if (card.matches(topCard)) return true; + } + return false; +} + +void clearScreen() { +#ifdef _WIN32 + std::system("cls"); +#else + std::system("clear"); +#endif +} + +std::string rightAlign(std::string text, size_t width = 50) { + if (text.length() >= width) return text; + return std::string(width - text.length(), ' ') + text; +} + +int main() { + auto deck = createDeck(); + std::vector playerHand, aiHand; + + for (int i = 0; i < 7; ++i) { + playerHand.push_back(drawCard(deck)); + aiHand.push_back(drawCard(deck)); + } + + Card topCard = drawCard(deck); + bool playerTurn = true; + + while (true) { + clearScreen(); + + // Prepare UNO! labels if needed + std::string playerUno = (playerHand.size() == 1) ? rightAlign(fmt::format(fmt::emphasis::bold, "YOU: UNO!")) : ""; + std::string aiUno = (aiHand.size() == 1) ? rightAlign(fmt::format(fmt::emphasis::bold, "AI: UNO!")) : ""; + + // Print top card and UNO! indicator + fmt::print("Top card: "); + topCard.print(); + if (!playerUno.empty()) fmt::print("{}", playerUno); + if (!aiUno.empty()) fmt::print("{}", aiUno); + fmt::print("\n"); + + fmt::print("AI has {} card(s).\n\n", aiHand.size()); + + if (playerHand.empty()) { + fmt::print(fmt::fg(fmt::color::green), "You win!\n"); + break; + } + + if (aiHand.empty()) { + fmt::print(fmt::fg(fmt::color::red), "AI wins!\n"); + break; + } + + if (deck.empty()) { + fmt::print(fmt::fg(fmt::color::gray), "Deck is empty! Reshuffling...\n"); + deck = createDeck(); // not perfect, doesn’t exclude cards in play + } + + if (playerTurn) { + fmt::print(fmt::fg(fmt::color::cyan), "Your turn:\n"); + printHand(playerHand); + + if (!hasPlayableCard(playerHand, topCard)) { + fmt::print("No playable card. Press 'd' to draw: "); + char input; + std::cin >> input; + if (input == 'd' || input == 'D') { + playerHand.push_back(drawCard(deck)); + Card drawn = drawCard(deck); + playerHand.push_back(drawn); + fmt::print("You drew: "); + drawn.print(); + fmt::print("\nPress Enter to continue..."); + std::cin.ignore(std::numeric_limits::max(), '\n'); + std::cin.get(); + playerTurn = false; + continue; + } + } + else { + while (true) { + fmt::print("Choose card index to play or 'd' to draw: "); + std::string input; + std::cin >> input; + + if (input == "d" || input == "D") { + playerHand.push_back(drawCard(deck)); + fmt::print("You drew a card. "); + fmt::print("Press Enter to continue..."); + std::cin.ignore(std::numeric_limits::max(), '\n'); + std::cin.get(); + playerTurn = false; + break; + } + + try { + int choice = std::stoi(input); + if (choice >= 0 && choice < static_cast(playerHand.size())) { + if (playerHand[choice].matches(topCard)) { + topCard = playerHand[choice]; + playerHand.erase(playerHand.begin() + choice); + playerTurn = false; + break; + } + else { + fmt::print("Invalid move. You must match color or number.\n"); + } + } + else { + fmt::print("Invalid index.\n"); + } + } + catch (...) { + fmt::print("Invalid input.\n"); + } + } + } + } + else { + fmt::print(fmt::fg(fmt::color::yellow), "AI's turn...\n"); + bool played = false; + for (size_t i = 0; i < aiHand.size(); ++i) { + if (aiHand[i].matches(topCard)) { + topCard = aiHand[i]; + aiHand.erase(aiHand.begin() + i); + fmt::print("AI played: "); + topCard.print(); + fmt::print("\n"); + played = true; + break; + } + } + + if (!played) { + aiHand.push_back(drawCard(deck)); + fmt::print("AI drew a card.\n"); + } + + fmt::print("Press Enter to continue..."); + if (played) + std::cin.ignore(std::numeric_limits::max(), '\n'); + std::cin.get(); + + playerTurn = true; + } + } + + return 0; +} diff --git a/uno.sln b/uno.sln new file mode 100644 index 0000000..c21fe43 --- /dev/null +++ b/uno.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35913.81 d17.13 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uno", "uno.vcxproj", "{C48A49B2-1EF7-4BC6-A812-9EFAEC06C419}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C48A49B2-1EF7-4BC6-A812-9EFAEC06C419}.Debug|x64.ActiveCfg = Debug|x64 + {C48A49B2-1EF7-4BC6-A812-9EFAEC06C419}.Debug|x64.Build.0 = Debug|x64 + {C48A49B2-1EF7-4BC6-A812-9EFAEC06C419}.Debug|x86.ActiveCfg = Debug|Win32 + {C48A49B2-1EF7-4BC6-A812-9EFAEC06C419}.Debug|x86.Build.0 = Debug|Win32 + {C48A49B2-1EF7-4BC6-A812-9EFAEC06C419}.Release|x64.ActiveCfg = Release|x64 + {C48A49B2-1EF7-4BC6-A812-9EFAEC06C419}.Release|x64.Build.0 = Release|x64 + {C48A49B2-1EF7-4BC6-A812-9EFAEC06C419}.Release|x86.ActiveCfg = Release|Win32 + {C48A49B2-1EF7-4BC6-A812-9EFAEC06C419}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {CE804B6D-3BCA-4AA5-B1BA-45F67EAB2FC8} + EndGlobalSection +EndGlobal diff --git a/uno.vcxproj b/uno.vcxproj new file mode 100644 index 0000000..1ad6195 --- /dev/null +++ b/uno.vcxproj @@ -0,0 +1,159 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {c48a49b2-1ef7-4bc6-a812-9efaec06c419} + uno + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + include;%(AdditionalIncludeDirectories) + stdcpp23 + /utf-8 %(AdditionalOptions) + MultiThreadedDebug + + + Console + true + fmt.lib;%(AdditionalDependencies) + /utf-8 %(AdditionalOptions) + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + include;%(AdditionalIncludeDirectories) + stdcpp23 + /source-charset:utf-8 /execution-charset:utf-8 %(AdditionalOptions) + MultiThreaded + + + Console + true + true + true + fmt.lib;%(AdditionalDependencies) + /utf-8 %(AdditionalOptions) + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + include;%(AdditionalIncludeDirectories) + stdcpp23 + /utf-8 %(AdditionalOptions) + MultiThreadedDebug + + + Console + true + fmt.lib;%(AdditionalDependencies) + /utf-8 %(AdditionalOptions) + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + include;%(AdditionalIncludeDirectories) + stdcpp23 + /source-charset:utf-8 /execution-charset:utf-8 %(AdditionalOptions) + MultiThreaded + + + Console + true + true + true + fmt.lib;%(AdditionalDependencies) + /utf-8 %(AdditionalOptions) + + + + + + + + + \ No newline at end of file diff --git a/uno.vcxproj.filters b/uno.vcxproj.filters new file mode 100644 index 0000000..8bf3aee --- /dev/null +++ b/uno.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file