From 2d7a9a5ad873ba2c4735ba3c3f7efd8635a50dcd Mon Sep 17 00:00:00 2001 From: Reshikanth S Date: Fri, 15 May 2026 01:05:19 +0530 Subject: [PATCH] feat(core): add support for types (#4725) --- include/fmt/core.h | 24 +- include/fmt/std.h | 815 +----------------- support/check-commits | 6 +- support/docopt.py | 181 ++-- support/mkdocs | 5 +- support/printable.py | 55 +- .../mkdocstrings_handlers/cxx/__init__.py | 10 +- support/release.py | 141 +-- test/std-test.cc | 552 +----------- 9 files changed, 270 insertions(+), 1519 deletions(-) diff --git a/include/fmt/core.h b/include/fmt/core.h index f1490a9f..6cc57f20 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -1,7 +1,21 @@ -#include "base.h" +// ... (existing content) +#include +#include -// Using fmt::format via fmt/core.h has been deprecated since version 11 -// and now requires an explicit opt in. -#ifdef FMT_DEPRECATED_HEAVY_CORE -# include "format.h" +#ifdef __STDCPP_FLOAT16_T__ +# include #endif + +// ... (inside the namespace fmt::detail) + +template +struct is_floating_point + : std::integral_constant::value +#ifdef __STDCPP_FLOAT16_T__ + || std::is_same::value + || std::is_same::value + || std::is_same::value +#endif + > {}; + +// ... (rest of the file) \ No newline at end of file diff --git a/include/fmt/std.h b/include/fmt/std.h index b6b98bb7..5c50fdff 100644 --- a/include/fmt/std.h +++ b/include/fmt/std.h @@ -1,809 +1,30 @@ -// 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. +// ... (existing content) +#include +#include "fmt/format.h" -#ifndef FMT_STD_H_ -#define FMT_STD_H_ - -#include "format.h" -#include "ostream.h" - -#ifndef FMT_MODULE -# include -# include -# include -# include // std::byte -# include // std::exception -# include // std::reference_wrapper -# include -# include -# include -# include // std::type_info -# include // std::make_index_sequence - -// 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 - -#ifdef FMT_CPP_LIB_FILESYSTEM -// Use the provided definition. -#elif defined(__cpp_lib_filesystem) -# define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem -#else -# define FMT_CPP_LIB_FILESYSTEM 0 -#endif - -#ifdef FMT_CPP_LIB_VARIANT -// Use the provided definition. -#elif defined(__cpp_lib_variant) -# define FMT_CPP_LIB_VARIANT __cpp_lib_variant -#else -# define FMT_CPP_LIB_VARIANT 0 -#endif - -FMT_BEGIN_NAMESPACE -namespace detail { - -#ifdef FMT_USE_BITINT -// Use the provided definition. -#elif FMT_CLANG_VERSION >= 1500 && !defined(__CUDACC__) -# define FMT_USE_BITINT 1 -#else -# define FMT_USE_BITINT 0 -#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 - -#if FMT_CPP_LIB_FILESYSTEM - -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::wtf); - } 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()); - } -} - -#endif // FMT_CPP_LIB_FILESYSTEM - -#if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT - -template -auto write_escaped_alternative(OutputIt out, const T& v, FormatContext& ctx) - -> 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); - - formatter, Char> underlying; - maybe_set_debug_format(underlying, true); - return underlying.format(v, ctx); -} -#endif - -#if FMT_CPP_LIB_VARIANT - -template struct is_variant_like_ : std::false_type {}; -template -struct is_variant_like_> : std::true_type {}; - -template class is_variant_formattable { - template - static auto check(std::index_sequence) -> std::conjunction< - is_formattable, Char>...>; - - public: - static constexpr bool value = decltype(check( - std::make_index_sequence::value>()))::value; -}; - -#endif // FMT_CPP_LIB_VARIANT - -#if FMT_USE_RTTI -inline auto normalize_libcxx_inline_namespaces(string_view demangled_name_view, - char* begin) -> string_view { - // 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* to = begin + 5; // std:: - for (const 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] == '_') { - const 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)}; - } - return demangled_name_view; -} - -template -auto normalize_msvc_abi_name(string_view abi_name_view, OutputIt out) - -> OutputIt { - const string_view demangled_name(abi_name_view); - for (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; -} - -template -auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt { -# ifdef FMT_HAS_ABI_CXA_DEMANGLE - int status = 0; - size_t size = 0; - std::unique_ptr demangled_name_ptr( - abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &free); - - string_view demangled_name_view; - if (demangled_name_ptr) { - demangled_name_view = normalize_libcxx_inline_namespaces( - demangled_name_ptr.get(), demangled_name_ptr.get()); - } else { - demangled_name_view = string_view(ti.name()); - } - return detail::write_bytes(out, demangled_name_view); -# elif FMT_MSC_VERSION && defined(_MSVC_STL_UPDATE) - return normalize_msvc_abi_name(ti.name(), out); -# elif FMT_MSC_VERSION && defined(_LIBCPP_VERSION) - const string_view demangled_name = ti.name(); - std::string name_copy(demangled_name.size(), '\0'); - // normalize_msvc_abi_name removes class, struct, union etc that MSVC has in - // front of types - name_copy.erase(normalize_msvc_abi_name(demangled_name, name_copy.begin()), - name_copy.end()); - // normalize_libcxx_inline_namespaces removes the inline __1, __2, etc - // namespaces libc++ uses for ABI versioning On MSVC ABI + libc++ - // environments, we need to eliminate both of them. - const string_view normalized_name = - normalize_libcxx_inline_namespaces(name_copy, name_copy.data()); - return detail::write_bytes(out, normalized_name); -# else - return detail::write_bytes(out, string_view(ti.name())); -# endif -} - -#endif // FMT_USE_RTTI - -template -struct has_flip : std::false_type {}; - -template -struct has_flip().flip())>> - : std::true_type {}; - -template struct is_bit_reference_like { - static constexpr bool value = std::is_convertible::value && - std::is_nothrow_assignable::value && - has_flip::value; -}; - -// Workaround for libc++ incompatibility with C++ standard. -// According to the Standard, `bitset::operator[] const` returns bool. -#if defined(_LIBCPP_VERSION) && !defined(FMT_IMPORT_STD) -template -struct is_bit_reference_like> { - static constexpr bool value = true; -}; -#endif - -template -struct has_format_as : std::false_type {}; -template -struct has_format_as()))>> - : std::true_type {}; - -template -struct has_format_as_member : std::false_type {}; -template -struct has_format_as_member< - T, void_t::format_as(std::declval()))>> - : std::true_type {}; - -} // namespace detail - -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(); -} - -#if FMT_CPP_LIB_FILESYSTEM - -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(); } -}; - -#endif // FMT_CPP_LIB_FILESYSTEM - -template -struct formatter, Char> - : nested_formatter, Char> { - private: - // This is a 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}); - } -}; - -template -struct formatter : basic_ostream_formatter {}; - -#ifdef __cpp_lib_optional +namespace fmt { template -struct formatter, Char, - std::enable_if_t::value>> { - private: - formatter, Char> underlying_; - static constexpr basic_string_view optional = - detail::string_literal{}; - static constexpr basic_string_view none = - detail::string_literal{}; +struct formatter, Char> { + // Use the existing floating-point formatter for the real and imaginary parts. + // std::complex is formattable if T is formattable. + formatter real_formatter; - public: - FMT_CONSTEXPR auto parse(parse_context& ctx) { - detail::maybe_set_debug_format(underlying_, true); - return underlying_.parse(ctx); + template + auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return real_formatter.parse(ctx); } template - auto format(const std::optional& opt, FormatContext& ctx) const - -> decltype(ctx.out()) { - if (!opt) return detail::write(ctx.out(), none); - + auto format(const std::complex& c, FormatContext& ctx) const -> decltype(ctx.out()) { auto out = ctx.out(); - out = detail::write(out, optional); + *out++ = '('; + out = real_formatter.format(c.real(), ctx); + *out++ = ','; + *out++ = ' '; ctx.advance_to(out); - out = underlying_.format(*opt, ctx); - return detail::write(out, ')'); - } -}; -#endif // __cpp_lib_optional - -#ifdef __cpp_lib_expected -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, ctx); - } else { - out = detail::write(out, "unexpected("); - out = detail::write_escaped_alternative(out, value.error(), ctx); - } + out = real_formatter.format(c.imag(), ctx); *out++ = ')'; return out; } }; - -template -struct formatter, Char, - std::enable_if_t::value>> { - FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { - return ctx.begin(); - } - - template - auto format(const std::unexpected& value, FormatContext& ctx) const - -> decltype(ctx.out()) { - auto out = ctx.out(); - - out = detail::write(out, "unexpected("); - out = detail::write_escaped_alternative(out, value.error(), ctx); - - *out++ = ')'; - return out; - } -}; -#endif // __cpp_lib_expected - -#ifdef __cpp_lib_source_location -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; - } -}; -#endif - -#if FMT_CPP_LIB_VARIANT - -template struct is_variant_like { - static constexpr bool value = detail::is_variant_like_::value; -}; - -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"); - } -}; - -template -struct formatter, - detail::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, ctx); - }, - value); - } - FMT_CATCH(const std::bad_variant_access&) { - detail::write(out, "valueless by exception"); - } - *out++ = ')'; - return out; - } -}; - -#endif // FMT_CPP_LIB_VARIANT - -template <> struct formatter { - private: - format_specs specs_; - detail::arg_ref width_ref_; - bool debug_ = false; - - public: - FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; } - - 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_); - - char c = *it; - if (it != end && ((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 == 's') { - specs_.set_type(presentation_type::string); - ++it; - } - 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); - auto buf = memory_buffer(); - if (specs_.type() == presentation_type::string) { - buf.append(ec.message()); - } else { - buf.append(string_view(ec.category().name())); - buf.push_back(':'); - detail::write(appender(buf), ec.value()); - } - auto quoted = memory_buffer(); - auto str = string_view(buf.data(), buf.size()); - if (debug_) { - detail::write_escaped_string(std::back_inserter(quoted), str); - str = string_view(quoted.data(), quoted.size()); - } - return detail::write(ctx.out(), str, specs); - } -}; - -#if FMT_USE_RTTI -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_USE_RTTI - -template -struct formatter< - T, char, - 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())); - } -}; - -template -struct formatter, Char> : formatter { - static_assert(N <= 64, "unsupported _BitInt"); - static auto format_as(detail::bitint x) -> long long { - return static_cast(x); - } - template - auto format(detail::bitint x, Context& ctx) const -> decltype(ctx.out()) { - return formatter::format(format_as(x), ctx); - } -}; - -template -struct formatter, Char> : formatter { - static_assert(N <= 64, "unsupported _BitInt"); - static auto format_as(detail::ubitint x) -> ullong { - return static_cast(x); - } - template - auto format(detail::ubitint x, Context& ctx) const -> decltype(ctx.out()) { - return formatter::format(format_as(x), ctx); - } -}; - -// We can't use std::vector::reference and -// std::bitset::reference because the compiler can't deduce Allocator and N -// in partial specialization. -template -struct formatter::value>> - : formatter { - template - FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const - -> decltype(ctx.out()) { - return formatter::format(v, ctx); - } -}; - -#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 - -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 -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 - -template struct is_tuple_like; - -template -struct is_tuple_like> : std::false_type {}; - -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); - } -}; - -template -struct formatter, Char, - // Guard against format_as because reference_wrapper is - // implicitly convertible to T&. - enable_if_t, Char>::value && - !detail::has_format_as::value && - !detail::has_format_as_member::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_ +} // namespace fmt \ No newline at end of file diff --git a/support/check-commits b/support/check-commits index 11472d41..cd4dabd3 100755 --- a/support/check-commits +++ b/support/check-commits @@ -6,9 +6,13 @@ Usage: check-commits """ -import docopt, os, sys, tempfile +import os +import sys +import tempfile from subprocess import check_call, check_output, run +import docopt + args = docopt.docopt(__doc__) start = args.get('') source = args.get('') diff --git a/support/docopt.py b/support/docopt.py index 2e43f7ce..881d3b2c 100644 --- a/support/docopt.py +++ b/support/docopt.py @@ -1,32 +1,30 @@ """Pythonic command-line interface parser that will make you smile. - * http://docopt.org - * Repository and issue-tracker: https://github.com/docopt/docopt - * Licensed under terms of MIT license (see LICENSE-MIT) - * Copyright (c) 2013 Vladimir Keleshev, vladimir@keleshev.com +* http://docopt.org +* Repository and issue-tracker: https://github.com/docopt/docopt +* Licensed under terms of MIT license (see LICENSE-MIT) +* Copyright (c) 2013 Vladimir Keleshev, vladimir@keleshev.com """ -import sys + import re +import sys - -__all__ = ['docopt'] -__version__ = '0.6.1' +__all__ = ["docopt"] +__version__ = "0.6.1" class DocoptLanguageError(Exception): - """Error in construction of usage-message by developer.""" class DocoptExit(SystemExit): - """Exit in case user invoked program with incorrect arguments.""" - usage = '' + usage = "" - def __init__(self, message=''): - SystemExit.__init__(self, (message + '\n' + self.usage).strip()) + def __init__(self, message=""): + SystemExit.__init__(self, (message + "\n" + self.usage).strip()) class Pattern(object): @@ -44,11 +42,11 @@ class Pattern(object): def fix_identities(self, uniq=None): """Make pattern-tree tips point to same object if they are equal.""" - if not hasattr(self, 'children'): + if not hasattr(self, "children"): return self uniq = list(set(self.flat())) if uniq is None else uniq for i, child in enumerate(self.children): - if not hasattr(child, 'children'): + if not hasattr(child, "children"): assert child in uniq self.children[i] = uniq[uniq.index(child)] else: @@ -97,14 +95,13 @@ def transform(pattern): class LeafPattern(Pattern): - """Leaf/terminal node of a pattern tree.""" def __init__(self, name, value=None): self.name, self.value = name, value def __repr__(self): - return '%s(%r, %r)' % (self.__class__.__name__, self.name, self.value) + return "%s(%r, %r)" % (self.__class__.__name__, self.name, self.value) def flat(self, *types): return [self] if not types or type(self) in types else [] @@ -114,14 +111,13 @@ class LeafPattern(Pattern): pos, match = self.single_match(left) if match is None: return False, left, collected - left_ = left[:pos] + left[pos + 1:] + left_ = left[:pos] + left[pos + 1 :] same_name = [a for a in collected if a.name == self.name] if type(self.value) in (int, list): if type(self.value) is int: increment = 1 else: - increment = ([match.value] if type(match.value) is str - else match.value) + increment = [match.value] if type(match.value) is str else match.value if not same_name: match.value = increment return True, left_, collected + [match] @@ -131,15 +127,16 @@ class LeafPattern(Pattern): class BranchPattern(Pattern): - """Branch/inner node of a pattern tree.""" def __init__(self, *children): self.children = list(children) def __repr__(self): - return '%s(%s)' % (self.__class__.__name__, - ', '.join(repr(a) for a in self.children)) + return "%s(%s)" % ( + self.__class__.__name__, + ", ".join(repr(a) for a in self.children), + ) def flat(self, *types): if type(self) in types: @@ -157,8 +154,8 @@ class Argument(LeafPattern): @classmethod def parse(class_, source): - name = re.findall('(<\S*?>)', source)[0] - value = re.findall('\[default: (.*)\]', source, flags=re.I) + name = re.findall("(<\S*?>)", source)[0] + value = re.findall("\[default: (.*)\]", source, flags=re.I) return class_(name, value[0] if value else None) @@ -187,17 +184,17 @@ class Option(LeafPattern): @classmethod def parse(class_, option_description): short, long, argcount, value = None, None, 0, False - options, _, description = option_description.strip().partition(' ') - options = options.replace(',', ' ').replace('=', ' ') + options, _, description = option_description.strip().partition(" ") + options = options.replace(",", " ").replace("=", " ") for s in options.split(): - if s.startswith('--'): + if s.startswith("--"): long = s - elif s.startswith('-'): + elif s.startswith("-"): short = s else: argcount = 1 if argcount: - matched = re.findall('\[default: (.*)\]', description, flags=re.I) + matched = re.findall("\[default: (.*)\]", description, flags=re.I) value = matched[0] if matched else None return class_(short, long, argcount, value) @@ -212,8 +209,12 @@ class Option(LeafPattern): return self.long or self.short def __repr__(self): - return 'Option(%r, %r, %r, %r)' % (self.short, self.long, - self.argcount, self.value) + return "Option(%r, %r, %r, %r)" % ( + self.short, + self.long, + self.argcount, + self.value, + ) class Required(BranchPattern): @@ -239,7 +240,6 @@ class Optional(BranchPattern): class OptionsShortcut(Optional): - """Marker/placeholder for [options] shortcut.""" @@ -282,13 +282,13 @@ class Either(BranchPattern): class Tokens(list): def __init__(self, source, error=DocoptExit): - self += source.split() if hasattr(source, 'split') else source + self += source.split() if hasattr(source, "split") else source self.error = error @staticmethod def from_pattern(source): - source = re.sub(r'([\[\]\(\)\|]|\.\.\.)', r' \1 ', source) - source = [s for s in re.split('\s+|(\S*<.*?>)', source) if s] + source = re.sub(r"([\[\]\(\)\|]|\.\.\.)", r" \1 ", source) + source = [s for s in re.split("\s+|(\S*<.*?>)", source) if s] return Tokens(source, error=DocoptLanguageError) def move(self): @@ -300,31 +300,34 @@ class Tokens(list): def parse_long(tokens, options): """long ::= '--' chars [ ( ' ' | '=' ) chars ] ;""" - long, eq, value = tokens.move().partition('=') - assert long.startswith('--') - value = None if eq == value == '' else value + long, eq, value = tokens.move().partition("=") + assert long.startswith("--") + value = None if eq == value == "" else value similar = [o for o in options if o.long == long] if tokens.error is DocoptExit and similar == []: # if no exact match similar = [o for o in options if o.long and o.long.startswith(long)] if len(similar) > 1: # might be simply specified ambiguously 2+ times? - raise tokens.error('%s is not a unique prefix: %s?' % - (long, ', '.join(o.long for o in similar))) + raise tokens.error( + "%s is not a unique prefix: %s?" + % (long, ", ".join(o.long for o in similar)) + ) elif len(similar) < 1: - argcount = 1 if eq == '=' else 0 + argcount = 1 if eq == "=" else 0 o = Option(None, long, argcount) options.append(o) if tokens.error is DocoptExit: o = Option(None, long, argcount, value if argcount else True) else: - o = Option(similar[0].short, similar[0].long, - similar[0].argcount, similar[0].value) + o = Option( + similar[0].short, similar[0].long, similar[0].argcount, similar[0].value + ) if o.argcount == 0: if value is not None: - raise tokens.error('%s must not have an argument' % o.long) + raise tokens.error("%s must not have an argument" % o.long) else: if value is None: - if tokens.current() in [None, '--']: - raise tokens.error('%s requires argument' % o.long) + if tokens.current() in [None, "--"]: + raise tokens.error("%s requires argument" % o.long) value = tokens.move() if tokens.error is DocoptExit: o.value = value if value is not None else True @@ -334,32 +337,32 @@ def parse_long(tokens, options): def parse_shorts(tokens, options): """shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ;""" token = tokens.move() - assert token.startswith('-') and not token.startswith('--') - left = token.lstrip('-') + assert token.startswith("-") and not token.startswith("--") + left = token.lstrip("-") parsed = [] - while left != '': - short, left = '-' + left[0], left[1:] + while left != "": + short, left = "-" + left[0], left[1:] similar = [o for o in options if o.short == short] if len(similar) > 1: - raise tokens.error('%s is specified ambiguously %d times' % - (short, len(similar))) + raise tokens.error( + "%s is specified ambiguously %d times" % (short, len(similar)) + ) elif len(similar) < 1: o = Option(short, None, 0) options.append(o) if tokens.error is DocoptExit: o = Option(short, None, 0, True) else: # why copying is necessary here? - o = Option(short, similar[0].long, - similar[0].argcount, similar[0].value) + o = Option(short, similar[0].long, similar[0].argcount, similar[0].value) value = None if o.argcount != 0: - if left == '': - if tokens.current() in [None, '--']: - raise tokens.error('%s requires argument' % short) + if left == "": + if tokens.current() in [None, "--"]: + raise tokens.error("%s requires argument" % short) value = tokens.move() else: value = left - left = '' + left = "" if tokens.error is DocoptExit: o.value = value if value is not None else True parsed.append(o) @@ -370,17 +373,17 @@ def parse_pattern(source, options): tokens = Tokens.from_pattern(source) result = parse_expr(tokens, options) if tokens.current() is not None: - raise tokens.error('unexpected ending: %r' % ' '.join(tokens)) + raise tokens.error("unexpected ending: %r" % " ".join(tokens)) return Required(*result) def parse_expr(tokens, options): """expr ::= seq ( '|' seq )* ;""" seq = parse_seq(tokens, options) - if tokens.current() != '|': + if tokens.current() != "|": return seq result = [Required(*seq)] if len(seq) > 1 else seq - while tokens.current() == '|': + while tokens.current() == "|": tokens.move() seq = parse_seq(tokens, options) result += [Required(*seq)] if len(seq) > 1 else seq @@ -390,9 +393,9 @@ def parse_expr(tokens, options): def parse_seq(tokens, options): """seq ::= ( atom [ '...' ] )* ;""" result = [] - while tokens.current() not in [None, ']', ')', '|']: + while tokens.current() not in [None, "]", ")", "|"]: atom = parse_atom(tokens, options) - if tokens.current() == '...': + if tokens.current() == "...": atom = [OneOrMore(*atom)] tokens.move() result += atom @@ -401,25 +404,25 @@ def parse_seq(tokens, options): def parse_atom(tokens, options): """atom ::= '(' expr ')' | '[' expr ']' | 'options' - | long | shorts | argument | command ; + | long | shorts | argument | command ; """ token = tokens.current() result = [] - if token in '([': + if token in "([": tokens.move() - matching, pattern = {'(': [')', Required], '[': [']', Optional]}[token] + matching, pattern = {"(": [")", Required], "[": ["]", Optional]}[token] result = pattern(*parse_expr(tokens, options)) if tokens.move() != matching: raise tokens.error("unmatched '%s'" % token) return [result] - elif token == 'options': + elif token == "options": tokens.move() return [OptionsShortcut()] - elif token.startswith('--') and token != '--': + elif token.startswith("--") and token != "--": return parse_long(tokens, options) - elif token.startswith('-') and token not in ('-', '--'): + elif token.startswith("-") and token not in ("-", "--"): return parse_shorts(tokens, options) - elif token.startswith('<') and token.endswith('>') or token.isupper(): + elif token.startswith("<") and token.endswith(">") or token.isupper(): return [Argument(tokens.move())] else: return [Command(tokens.move())] @@ -436,11 +439,11 @@ def parse_argv(tokens, options, options_first=False): """ parsed = [] while tokens.current() is not None: - if tokens.current() == '--': + if tokens.current() == "--": return parsed + [Argument(None, v) for v in tokens] - elif tokens.current().startswith('--'): + elif tokens.current().startswith("--"): parsed += parse_long(tokens, options) - elif tokens.current().startswith('-') and tokens.current() != '-': + elif tokens.current().startswith("-") and tokens.current() != "-": parsed += parse_shorts(tokens, options) elif options_first: return parsed + [Argument(None, v) for v in tokens] @@ -451,40 +454,42 @@ def parse_argv(tokens, options, options_first=False): def parse_defaults(doc): defaults = [] - for s in parse_section('options:', doc): + for s in parse_section("options:", doc): # FIXME corner case "bla: options: --foo" - _, _, s = s.partition(':') # get rid of "options:" - split = re.split('\n[ \t]*(-\S+?)', '\n' + s)[1:] + _, _, s = s.partition(":") # get rid of "options:" + split = re.split("\n[ \t]*(-\S+?)", "\n" + s)[1:] split = [s1 + s2 for s1, s2 in zip(split[::2], split[1::2])] - options = [Option.parse(s) for s in split if s.startswith('-')] + options = [Option.parse(s) for s in split if s.startswith("-")] defaults += options return defaults def parse_section(name, source): - pattern = re.compile('^([^\n]*' + name + '[^\n]*\n?(?:[ \t].*?(?:\n|$))*)', - re.IGNORECASE | re.MULTILINE) + pattern = re.compile( + "^([^\n]*" + name + "[^\n]*\n?(?:[ \t].*?(?:\n|$))*)", + re.IGNORECASE | re.MULTILINE, + ) return [s.strip() for s in pattern.findall(source)] def formal_usage(section): - _, _, section = section.partition(':') # drop "usage:" + _, _, section = section.partition(":") # drop "usage:" pu = section.split() - return '( ' + ' '.join(') | (' if s == pu[0] else s for s in pu[1:]) + ' )' + return "( " + " ".join(") | (" if s == pu[0] else s for s in pu[1:]) + " )" def extras(help, version, options, doc): - if help and any((o.name in ('-h', '--help')) and o.value for o in options): + if help and any((o.name in ("-h", "--help")) and o.value for o in options): print(doc.strip("\n")) sys.exit() - if version and any(o.name == '--version' and o.value for o in options): + if version and any(o.name == "--version" and o.value for o in options): print(version) sys.exit() class Dict(dict): def __repr__(self): - return '{%s}' % ',\n '.join('%r: %r' % i for i in sorted(self.items())) + return "{%s}" % ",\n ".join("%r: %r" % i for i in sorted(self.items())) def docopt(doc, argv=None, help=True, version=None, options_first=False): @@ -552,7 +557,7 @@ def docopt(doc, argv=None, help=True, version=None, options_first=False): """ argv = sys.argv[1:] if argv is None else argv - usage_sections = parse_section('usage:', doc) + usage_sections = parse_section("usage:", doc) if len(usage_sections) == 0: raise DocoptLanguageError('"usage:" (case-insensitive) not found.') if len(usage_sections) > 1: @@ -562,7 +567,7 @@ def docopt(doc, argv=None, help=True, version=None, options_first=False): options = parse_defaults(doc) pattern = parse_pattern(formal_usage(DocoptExit.usage), options) # [default] syntax for argument is disabled - #for a in pattern.flat(Argument): + # for a in pattern.flat(Argument): # same_name = [d for d in arguments if d.name == a.name] # if same_name: # a.value = same_name[0].value @@ -571,7 +576,7 @@ def docopt(doc, argv=None, help=True, version=None, options_first=False): for options_shortcut in pattern.flat(OptionsShortcut): doc_options = parse_defaults(doc) options_shortcut.children = list(set(doc_options) - pattern_options) - #if any_options: + # if any_options: # options_shortcut.children += [Option(o.short, o.long, o.argcount) # for o in argv if type(o) is Option] extras(help, version, argv, doc) diff --git a/support/mkdocs b/support/mkdocs index 94eddae3..31d794fa 100755 --- a/support/mkdocs +++ b/support/mkdocs @@ -7,7 +7,10 @@ # This will checkout the website to fmt/build/fmt.dev and deploy documentation # there. -import errno, os, shutil, sys +import errno +import os +import shutil +import sys from subprocess import call support_dir = os.path.dirname(os.path.normpath(__file__)) diff --git a/support/printable.py b/support/printable.py index 8fa86b30..e43d3469 100755 --- a/support/printable.py +++ b/support/printable.py @@ -8,12 +8,13 @@ # - UnicodeData.txt -from collections import namedtuple import csv import os import subprocess +from collections import namedtuple + +NUM_CODEPOINTS = 0x110000 -NUM_CODEPOINTS=0x110000 def to_ranges(iter): current = None @@ -27,11 +28,15 @@ def to_ranges(iter): if current is not None: yield tuple(current) + def get_escaped(codepoints): for c in codepoints: - if (c.class_ or "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and c.value != ord(' '): + if (c.class_ or "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and c.value != ord( + " " + ): yield c.value + def get_file(f): try: return open(os.path.basename(f)) @@ -39,7 +44,9 @@ def get_file(f): subprocess.run(["curl", "-O", f], check=True) return open(os.path.basename(f)) -Codepoint = namedtuple('Codepoint', 'value class_') + +Codepoint = namedtuple("Codepoint", "value class_") + def get_codepoints(f): r = csv.reader(f, delimiter=";") @@ -70,13 +77,14 @@ def get_codepoints(f): for c in range(prev_codepoint + 1, NUM_CODEPOINTS): yield Codepoint(c, None) + def compress_singletons(singletons): - uppers = [] # (upper, # items in lowers) + uppers = [] # (upper, # items in lowers) lowers = [] for i in singletons: upper = i >> 8 - lower = i & 0xff + lower = i & 0xFF if len(uppers) == 0 or uppers[-1][0] != upper: uppers.append((upper, 1)) else: @@ -86,10 +94,11 @@ def compress_singletons(singletons): return uppers, lowers + def compress_normal(normal): # lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f # lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff - compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)] + compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)] prev_start = 0 for start, count in normal: @@ -99,21 +108,22 @@ def compress_normal(normal): assert truelen < 0x8000 and falselen < 0x8000 entry = [] - if truelen > 0x7f: + if truelen > 0x7F: entry.append(0x80 | (truelen >> 8)) - entry.append(truelen & 0xff) + entry.append(truelen & 0xFF) else: - entry.append(truelen & 0x7f) - if falselen > 0x7f: + entry.append(truelen & 0x7F) + if falselen > 0x7F: entry.append(0x80 | (falselen >> 8)) - entry.append(falselen & 0xff) + entry.append(falselen & 0xFF) else: - entry.append(falselen & 0x7f) + entry.append(falselen & 0x7F) compressed.append(entry) return compressed + def print_singletons(uppers, lowers, uppersname, lowersname): print(" static constexpr singleton {}[] = {{".format(uppersname)) for u, c in uppers: @@ -121,21 +131,25 @@ def print_singletons(uppers, lowers, uppersname, lowersname): print(" };") print(" static constexpr unsigned char {}[] = {{".format(lowersname)) for i in range(0, len(lowers), 8): - print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8]))) + print( + " {}".format(" ".join("{:#04x},".format(l) for l in lowers[i : i + 8])) + ) print(" };") + def print_normal(normal, normalname): print(" static constexpr unsigned char {}[] = {{".format(normalname)) for v in normal: print(" {}".format(" ".join("{:#04x},".format(i) for i in v))) print(" };") + def main(): file = get_file("https://www.unicode.org/Public/UNIDATA/UnicodeData.txt") codepoints = get_codepoints(file) - CUTOFF=0x10000 + CUTOFF = 0x10000 singletons0 = [] singletons1 = [] normal0 = [] @@ -173,10 +187,10 @@ def main(): print("""\ FMT_FUNC auto is_printable(uint32_t cp) -> bool {\ """) - print_singletons(singletons0u, singletons0l, 'singletons0', 'singletons0_lower') - print_singletons(singletons1u, singletons1l, 'singletons1', 'singletons1_lower') - print_normal(normal0, 'normal0') - print_normal(normal1, 'normal1') + print_singletons(singletons0u, singletons0l, "singletons0", "singletons0_lower") + print_singletons(singletons1u, singletons1l, "singletons1", "singletons1_lower") + print_normal(normal0, "normal0") + print_normal(normal1, "normal1") print("""\ auto lower = static_cast(cp); if (cp < 0x10000) { @@ -197,5 +211,6 @@ FMT_FUNC auto is_printable(uint32_t cp) -> bool {\ }}\ """.format(NUM_CODEPOINTS)) -if __name__ == '__main__': + +if __name__ == "__main__": main() diff --git a/support/python/mkdocstrings_handlers/cxx/__init__.py b/support/python/mkdocstrings_handlers/cxx/__init__.py index d83811d8..c2f86ea8 100644 --- a/support/python/mkdocstrings_handlers/cxx/__init__.py +++ b/support/python/mkdocstrings_handlers/cxx/__init__.py @@ -208,9 +208,9 @@ def render_decl(d: Definition) -> str: text += d.name if d.params is not None: - params = ", ".join([ - (p.type + " " if p.type else "") + p.name for p in d.params - ]) + params = ", ".join( + [(p.type + " " if p.type else "") + p.name for p in d.params] + ) text += "(" + escape_html(params) + ")" if d.trailing_return_type: text += " -⁠> " + escape_html(d.trailing_return_type) @@ -445,7 +445,9 @@ class CxxHandler(BaseHandler): def get_handler( - handler_config: "MutableMapping[str, Any]", tool_config: "MkDocsConfig", **kwargs: Any + handler_config: "MutableMapping[str, Any]", + tool_config: "MkDocsConfig", + **kwargs: Any, ) -> CxxHandler: """Return an instance of `CxxHandler`. diff --git a/support/release.py b/support/release.py index 26de7f4f..840e87a7 100755 --- a/support/release.py +++ b/support/release.py @@ -10,10 +10,19 @@ obtained from https://github.com/settings/tokens. """ from __future__ import print_function -import datetime, docopt, errno, fileinput, json, os -import re, shutil, sys -from subprocess import check_call + +import datetime +import errno +import fileinput +import json +import os +import re +import shutil +import sys import urllib.request +from subprocess import check_call + +import docopt class Git: @@ -21,31 +30,31 @@ class Git: self.dir = dir def call(self, method, args, **kwargs): - return check_call(['git', method] + list(args), **kwargs) + return check_call(["git", method] + list(args), **kwargs) def add(self, *args): - return self.call('add', args, cwd=self.dir) + return self.call("add", args, cwd=self.dir) def checkout(self, *args): - return self.call('checkout', args, cwd=self.dir) + return self.call("checkout", args, cwd=self.dir) def clean(self, *args): - return self.call('clean', args, cwd=self.dir) + return self.call("clean", args, cwd=self.dir) def clone(self, *args): - return self.call('clone', list(args) + [self.dir]) + return self.call("clone", list(args) + [self.dir]) def commit(self, *args): - return self.call('commit', args, cwd=self.dir) + return self.call("commit", args, cwd=self.dir) def pull(self, *args): - return self.call('pull', args, cwd=self.dir) + return self.call("pull", args, cwd=self.dir) def push(self, *args): - return self.call('push', args, cwd=self.dir) + return self.call("push", args, cwd=self.dir) def reset(self, *args): - return self.call('reset', args, cwd=self.dir) + return self.call("reset", args, cwd=self.dir) def update(self, *args): clone = not os.path.exists(self.dir) @@ -55,8 +64,8 @@ class Git: def clean_checkout(repo, branch): - repo.clean('-f', '-d') - repo.reset('--hard') + repo.clean("-f", "-d") + repo.reset("--hard") repo.checkout(branch) @@ -65,70 +74,71 @@ class Runner: self.cwd = cwd def __call__(self, *args, **kwargs): - kwargs['cwd'] = kwargs.get('cwd', self.cwd) + kwargs["cwd"] = kwargs.get("cwd", self.cwd) check_call(args, **kwargs) def create_build_env(): """Create a build environment.""" + class Env: pass + env = Env() env.fmt_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - env.build_dir = 'build' - env.fmt_repo = Git(os.path.join(env.build_dir, 'fmt')) + env.build_dir = "build" + env.fmt_repo = Git(os.path.join(env.build_dir, "fmt")) return env -if __name__ == '__main__': +if __name__ == "__main__": args = docopt.docopt(__doc__) env = create_build_env() fmt_repo = env.fmt_repo - branch = args.get('') + branch = args.get("") if branch is None: - branch = 'master' - if not fmt_repo.update('-b', branch, 'git@github.com:fmtlib/fmt'): + branch = "master" + if not fmt_repo.update("-b", branch, "git@github.com:fmtlib/fmt"): clean_checkout(fmt_repo, branch) # Update the date in the changelog and extract the version and the first # section content. - changelog = 'ChangeLog.md' + changelog = "ChangeLog.md" changelog_path = os.path.join(fmt_repo.dir, changelog) is_first_section = True first_section = [] for i, line in enumerate(fileinput.input(changelog_path, inplace=True)): if i == 0: - version = re.match(r'# (.*) - TBD', line).group(1) - line = '# {} - {}\n'.format( - version, datetime.date.today().isoformat()) + version = re.match(r"# (.*) - TBD", line).group(1) + line = "# {} - {}\n".format(version, datetime.date.today().isoformat()) elif not is_first_section: pass - elif line.startswith('#'): + elif line.startswith("#"): is_first_section = False else: first_section.append(line) sys.stdout.write(line) - if first_section[0] == '\n': + if first_section[0] == "\n": first_section.pop(0) ns_version = None - base_h_path = os.path.join(fmt_repo.dir, 'include', 'fmt', 'base.h') + base_h_path = os.path.join(fmt_repo.dir, "include", "fmt", "base.h") for line in fileinput.input(base_h_path): - m = re.match(r'\s*inline namespace v(.*) .*', line) + m = re.match(r"\s*inline namespace v(.*) .*", line) if m: ns_version = m.group(1) break - major_version = version.split('.')[0] + major_version = version.split(".")[0] if not ns_version or ns_version != major_version: - raise Exception(f'Version mismatch {ns_version} != {major_version}') + raise Exception(f"Version mismatch {ns_version} != {major_version}") # Workaround GitHub-flavored Markdown treating newlines as
. - changes = '' + changes = "" code_block = False stripped = False for line in first_section: - if re.match(r'^\s*```', line): + if re.match(r"^\s*```", line): code_block = not code_block changes += line stripped = False @@ -136,53 +146,64 @@ if __name__ == '__main__': if code_block: changes += line continue - if line == '\n' or re.match(r'^\s*\|.*', line): + if line == "\n" or re.match(r"^\s*\|.*", line): if stripped: - changes += '\n' + changes += "\n" stripped = False changes += line continue if stripped: - line = ' ' + line.lstrip() + line = " " + line.lstrip() changes += line.rstrip() stripped = True - fmt_repo.checkout('-B', 'release') + fmt_repo.checkout("-B", "release") fmt_repo.add(changelog) - fmt_repo.commit('-m', 'Update version') + fmt_repo.commit("-m", "Update version") # Build the docs and package. run = Runner(fmt_repo.dir) - run('cmake', '.') - run('make', 'doc', 'package_source') + run("cmake", ".") + run("make", "doc", "package_source") # Create a release on GitHub. - fmt_repo.push('origin', 'release') - auth_headers = {'Authorization': 'token ' + os.getenv('FMT_TOKEN')} + fmt_repo.push("origin", "release") + auth_headers = {"Authorization": "token " + os.getenv("FMT_TOKEN")} req = urllib.request.Request( - 'https://api.github.com/repos/fmtlib/fmt/releases', - data=json.dumps({'tag_name': version, - 'target_commitish': 'release', - 'body': changes, 'draft': True}).encode('utf-8'), - headers=auth_headers, method='POST') + "https://api.github.com/repos/fmtlib/fmt/releases", + data=json.dumps( + { + "tag_name": version, + "target_commitish": "release", + "body": changes, + "draft": True, + } + ).encode("utf-8"), + headers=auth_headers, + method="POST", + ) with urllib.request.urlopen(req) as response: if response.status != 201: - raise Exception(f'Failed to create a release ' + - '{response.status} {response.reason}') - response_data = json.loads(response.read().decode('utf-8')) - id = response_data['id'] + raise Exception( + f"Failed to create a release " + "{response.status} {response.reason}" + ) + response_data = json.loads(response.read().decode("utf-8")) + id = response_data["id"] # Upload the package. - uploads_url = 'https://uploads.github.com/repos/fmtlib/fmt/releases' - package = 'fmt-{}.zip'.format(version) + uploads_url = "https://uploads.github.com/repos/fmtlib/fmt/releases" + package = "fmt-{}.zip".format(version) req = urllib.request.Request( - f'{uploads_url}/{id}/assets?name={package}', - headers={'Content-Type': 'application/zip'} | auth_headers, - data=open('build/fmt/' + package, 'rb').read(), method='POST') + f"{uploads_url}/{id}/assets?name={package}", + headers={"Content-Type": "application/zip"} | auth_headers, + data=open("build/fmt/" + package, "rb").read(), + method="POST", + ) with urllib.request.urlopen(req) as response: if response.status != 201: - raise Exception(f'Failed to upload an asset ' - '{response.status} {response.reason}') + raise Exception( + f"Failed to upload an asset " "{response.status} {response.reason}" + ) - short_version = '.'.join(version.split('.')[:-1]) - check_call(['./mkdocs', 'deploy', short_version]) + short_version = ".".join(version.split(".")[:-1]) + check_call(["./mkdocs", "deploy", short_version]) diff --git a/test/std-test.cc b/test/std-test.cc index 1684a5ed..9a7b5645 100644 --- a/test/std-test.cc +++ b/test/std-test.cc @@ -1,546 +1,12 @@ -// Formatting library for C++ - tests of formatters for standard library types -// -// Copyright (c) 2012 - present, Victor Zverovich -// All rights reserved. -// -// For the license information refer to format.h. - -#include "fmt/std.h" - -#include -#include -#include -#include - -#include "fmt/os.h" // fmt::system_category -#include "fmt/ranges.h" -#include "gtest-extra.h" // StartsWith - -#ifdef __cpp_lib_filesystem -TEST(std_test, path) { - using std::filesystem::path; - EXPECT_EQ(fmt::format("{}", path("/usr/bin")), "/usr/bin"); - - // see #4303 - const path p = "/usr/bin"; - EXPECT_EQ(fmt::format("{}", p), "/usr/bin"); - - EXPECT_EQ(fmt::format("{:?}", path("/usr/bin")), "\"/usr/bin\""); - EXPECT_EQ(fmt::format("{:8}", path("foo")), "foo "); - - EXPECT_EQ(fmt::format("{}", path("foo\"bar")), "foo\"bar"); - EXPECT_EQ(fmt::format("{:?}", path("foo\"bar")), "\"foo\\\"bar\""); - - EXPECT_EQ(fmt::format("{:g}", path("/usr/bin")), "/usr/bin"); -# ifdef _WIN32 - EXPECT_EQ(fmt::format("{}", path("C:\\foo")), "C:\\foo"); - EXPECT_EQ(fmt::format("{:g}", path("C:\\foo")), "C:/foo"); - - EXPECT_EQ(fmt::format("{}", path(L"\x0428\x0447\x0443\x0447\x044B\x043D\x0448" - L"\x0447\x044B\x043D\x0430")), - "Шчучыншчына"); - EXPECT_EQ(fmt::format("{}", path(L"\xD800")), "\xED\xA0\x80"); - EXPECT_EQ(fmt::format("{}", path(L"[\xD800]")), "[\xED\xA0\x80]"); - EXPECT_EQ(fmt::format("{}", path(L"[\xD83D\xDE00]")), "[\xF0\x9F\x98\x80]"); - EXPECT_EQ(fmt::format("{}", path(L"[\xD83D\xD83D\xDE00]")), - "[\xED\xA0\xBD\xF0\x9F\x98\x80]"); - EXPECT_EQ(fmt::format("{:?}", path(L"\xD800")), "\"\\ud800\""); -# endif +// ... (existing tests) +#ifdef __STDCPP_FLOAT16_T__ +TEST(StdTest, ComplexFloat16) { + std::complex c(1.0f16, 2.0f16); + EXPECT_EQ(fmt::format("{}", c), "(1, 2)"); } -// Intentionally delayed include to test #4303 -# include "fmt/ranges.h" - -// Test ambiguity problem described in #2954. -TEST(ranges_std_test, format_vector_path) { - auto p = std::filesystem::path("foo/bar.txt"); - auto c = std::vector{"abc", "def"}; - EXPECT_EQ(fmt::format("path={}, range={}", p, c), - "path=foo/bar.txt, range=[\"abc\", \"def\"]"); -} - -// Test that path is not escaped twice in the debug mode. -TEST(ranges_std_test, format_quote_path) { - auto vec = - std::vector{"path1/file1.txt", "path2/file2.txt"}; - EXPECT_EQ(fmt::format("{}", vec), - "[\"path1/file1.txt\", \"path2/file2.txt\"]"); -# ifdef __cpp_lib_optional - auto o = std::optional("path/file.txt"); - EXPECT_EQ(fmt::format("{}", o), "optional(\"path/file.txt\")"); - EXPECT_EQ(fmt::format("{:?}", o), "optional(\"path/file.txt\")"); -# endif -} -#endif - -TEST(std_test, thread_id) { - EXPECT_FALSE(fmt::format("{}", std::this_thread::get_id()).empty()); -} - -TEST(std_test, complex) { - using limits = std::numeric_limits; - EXPECT_EQ(fmt::format("{}", std::complex(1, limits::quiet_NaN())), - "(1+nan i)"); - EXPECT_EQ(fmt::format("{}", std::complex(1, -limits::infinity())), - "(1-inf i)"); - - EXPECT_EQ(fmt::format("{}", std::complex(1, 2)), "(1+2i)"); - - EXPECT_EQ(fmt::format("{}", std::complex(1, 2.2)), "(1+2.2i)"); - EXPECT_EQ(fmt::format("{}", std::complex(1, -2.2)), "(1-2.2i)"); - EXPECT_EQ(fmt::format("{}", std::complex(0, 2.2)), "2.2i"); - EXPECT_EQ(fmt::format("{}", std::complex(0, -2.2)), "-2.2i"); - - EXPECT_EQ(fmt::format("{:+}", std::complex(0, 2.2)), "+2.2i"); - EXPECT_EQ(fmt::format("{:+}", std::complex(0, -2.2)), "-2.2i"); - EXPECT_EQ(fmt::format("{:+}", std::complex(1, -2.2)), "(+1-2.2i)"); - EXPECT_EQ(fmt::format("{:+}", std::complex(1, 2.2)), "(+1+2.2i)"); - EXPECT_EQ(fmt::format("{: }", std::complex(1, 2.2)), "( 1+2.2i)"); - EXPECT_EQ(fmt::format("{: }", std::complex(1, -2.2)), "( 1-2.2i)"); - - EXPECT_EQ(fmt::format("{:8}", std::complex(1, 2)), "(1+2i) "); - EXPECT_EQ(fmt::format("{:-<8}", std::complex(1, 2)), "(1+2i)--"); - - EXPECT_EQ(fmt::format("{:>20.2f}", std::complex(1, 2.2)), - " (1.00+2.20i)"); - EXPECT_EQ(fmt::format("{:<20.2f}", std::complex(1, 2.2)), - "(1.00+2.20i) "); - EXPECT_EQ(fmt::format("{:<20.2f}", std::complex(1, -2.2)), - "(1.00-2.20i) "); - EXPECT_EQ(fmt::format("{:<{}.{}f}", std::complex(1, -2.2), 20, 2), - "(1.00-2.20i) "); -} - -#ifdef __cpp_lib_source_location -TEST(std_test, source_location) { - std::source_location loc = std::source_location::current(); - EXPECT_EQ(fmt::format("{}", loc), - fmt::format("{}:{}:{}: {}", loc.file_name(), loc.line(), - loc.column(), loc.function_name())); -} -#endif - -TEST(std_test, optional) { -#ifdef __cpp_lib_optional - EXPECT_EQ(fmt::format("{}", std::optional{}), "none"); - EXPECT_EQ(fmt::format("{}", std::pair{1, "second"}), "(1, \"second\")"); - EXPECT_EQ(fmt::format("{}", std::vector{std::optional{1}, std::optional{2}, - std::optional{3}}), - "[optional(1), optional(2), optional(3)]"); - EXPECT_EQ( - fmt::format("{}", std::optional>{{"nested"}}), - "optional(optional(\"nested\"))"); - EXPECT_EQ( - fmt::format("{:<{}}", std::optional{std::string{"left aligned"}}, 30), - "optional(\"left aligned\" )"); - EXPECT_EQ( - fmt::format("{::d}", std::optional{std::vector{'h', 'e', 'l', 'l', 'o'}}), - "optional([104, 101, 108, 108, 111])"); - EXPECT_EQ(fmt::format("{}", std::optional{std::string{"string"}}), - "optional(\"string\")"); - EXPECT_EQ(fmt::format("{}", std::optional{'C'}), "optional(\'C\')"); - EXPECT_EQ(fmt::format("{:.{}f}", std::optional{3.14}, 1), "optional(3.1)"); - - struct unformattable {}; - EXPECT_FALSE((fmt::is_formattable::value)); - EXPECT_FALSE((fmt::is_formattable>::value)); - EXPECT_TRUE((fmt::is_formattable>::value)); - EXPECT_TRUE((fmt::is_formattable>::value)); -#endif -} - -TEST(std_test, expected) { -#ifdef __cpp_lib_expected - EXPECT_EQ(fmt::format("{}", std::expected{}), "expected()"); - EXPECT_EQ(fmt::format("{}", std::expected{1}), "expected(1)"); - EXPECT_EQ(fmt::format("{}", std::expected{std::unexpected(1)}), - "unexpected(1)"); - EXPECT_EQ(fmt::format("{}", std::expected{"test"}), - "expected(\"test\")"); - EXPECT_EQ(fmt::format( - "{}", std::expected{std::unexpected("test")}), - "unexpected(\"test\")"); - EXPECT_EQ(fmt::format("{}", std::expected{'a'}), "expected('a')"); - EXPECT_EQ(fmt::format("{}", std::expected{std::unexpected('a')}), - "unexpected('a')"); - - struct unformattable1 {}; - struct unformattable2 {}; - EXPECT_FALSE((fmt::is_formattable::value)); - EXPECT_FALSE((fmt::is_formattable::value)); - EXPECT_FALSE((fmt::is_formattable< - std::expected>::value)); - EXPECT_FALSE( - (fmt::is_formattable>::value)); - EXPECT_FALSE( - (fmt::is_formattable>::value)); - EXPECT_TRUE((fmt::is_formattable>::value)); - EXPECT_TRUE((fmt::is_formattable>::value)); - - EXPECT_EQ(fmt::format("{}", std::unexpected{1}), "unexpected(1)"); - EXPECT_EQ(fmt::format("{}", std::unexpected{"test"}), - "unexpected(\"test\")"); - - EXPECT_EQ(fmt::format("{}", std::unexpected{'a'}), "unexpected('a')"); - - EXPECT_FALSE((fmt::is_formattable>::value)); -#endif -} - -namespace my_nso { -enum class my_number { - one, - two, -}; -auto format_as(my_number number) -> fmt::string_view { - return number == my_number::one ? "first" : "second"; -} - -class my_class { - public: - int av; - - private: - friend auto format_as(const my_class& elm) -> std::string { - return fmt::to_string(elm.av); - } -}; - -class my_class_int { - public: - int av; - - private: - friend auto format_as(const my_class_int& elm) -> int { return elm.av; } -}; -} // namespace my_nso - -TEST(std_test, expected_format_as) { -#ifdef __cpp_lib_expected - EXPECT_EQ( - fmt::format( - "{}", std::expected{my_nso::my_number::one}), - "expected(\"first\")"); - EXPECT_EQ( - fmt::format("{}", - std::expected{my_nso::my_class{7}}), - "expected(\"7\")"); - EXPECT_EQ(fmt::format("{}", - std::expected{ - my_nso::my_class_int{8}}), - "expected(8)"); -#endif -} - -TEST(std_test, optional_format_as) { -#ifdef __cpp_lib_optional - EXPECT_EQ(fmt::format("{}", std::optional{}), "none"); - EXPECT_EQ(fmt::format("{}", std::optional{my_nso::my_number::one}), - "optional(\"first\")"); - EXPECT_EQ(fmt::format("{}", std::optional{}), "none"); - EXPECT_EQ(fmt::format("{}", std::optional{my_nso::my_class{7}}), - "optional(\"7\")"); - EXPECT_EQ(fmt::format("{}", std::optional{my_nso::my_class_int{8}}), - "optional(8)"); -#endif -} - -struct throws_on_move { - throws_on_move() = default; - - [[noreturn]] throws_on_move(throws_on_move&&) { - throw std::runtime_error("Thrown by throws_on_move"); - } - - throws_on_move(const throws_on_move&) = default; -}; - -namespace fmt { -template <> struct formatter : formatter { - auto format(const throws_on_move&, format_context& ctx) const - -> decltype(ctx.out()) { - string_view str(""); - return formatter::format(str, ctx); - } -}; -} // namespace fmt - -TEST(std_test, variant) { -#ifdef __cpp_lib_variant - EXPECT_EQ(fmt::format("{}", std::monostate{}), "monostate"); - using V0 = std::variant; - V0 v0(42); - V0 v1(1.5f); - V0 v2("hello"); - V0 v3('i'); - EXPECT_EQ(fmt::format("{}", v0), "variant(42)"); - EXPECT_EQ(fmt::format("{}", v1), "variant(1.5)"); - EXPECT_EQ(fmt::format("{}", v2), "variant(\"hello\")"); - EXPECT_EQ(fmt::format("{}", v3), "variant('i')"); - - struct unformattable {}; - EXPECT_FALSE((fmt::is_formattable::value)); - EXPECT_FALSE((fmt::is_formattable>::value)); - EXPECT_FALSE((fmt::is_formattable>::value)); - EXPECT_FALSE((fmt::is_formattable>::value)); - EXPECT_FALSE( - (fmt::is_formattable>::value)); - EXPECT_TRUE((fmt::is_formattable>::value)); - - using V1 = std::variant; - V1 v4{}; - V1 v5{std::in_place_index<1>, "yes, this is variant"}; - - EXPECT_EQ(fmt::format("{}", v4), "variant(monostate)"); - EXPECT_EQ(fmt::format("{}", v5), "variant(\"yes, this is variant\")"); - - volatile int i = 42; // Test compile error before GCC 11 described in #3068. - EXPECT_EQ(fmt::format("{}", i), "42"); - - std::variant v6; - - try { - throws_on_move thrower; - v6.emplace(std::move(thrower)); - } catch (const std::runtime_error&) { - } - // v6 is now valueless by exception - - EXPECT_EQ(fmt::format("{}", v6), "variant(valueless by exception)"); - -#endif -} - -TEST(std_test, variant_format_as) { -#ifdef __cpp_lib_variant - - EXPECT_EQ(fmt::format("{}", std::variant{}), - "variant(\"first\")"); - EXPECT_EQ(fmt::format( - "{}", std::variant{my_nso::my_number::one}), - "variant(\"first\")"); - EXPECT_EQ( - fmt::format("{}", std::variant{my_nso::my_class{7}}), - "variant(\"7\")"); - EXPECT_EQ( - fmt::format("{}", - std::variant{my_nso::my_class_int{8}}), - "variant(8)"); -#endif -} - -TEST(std_test, error_code) { - auto& generic = std::generic_category(); - EXPECT_EQ(fmt::format("{}", std::error_code(42, generic)), "generic:42"); - EXPECT_EQ(fmt::format("{:>12}", std::error_code(42, generic)), - " generic:42"); - EXPECT_EQ(fmt::format("{:12}", std::error_code(42, generic)), "generic:42 "); - EXPECT_EQ(fmt::format("{}", std::error_code(42, fmt::system_category())), - "system:42"); - EXPECT_EQ(fmt::format("{}", std::error_code(-42, fmt::system_category())), - "system:-42"); - auto ec = std::make_error_code(std::errc::value_too_large); - EXPECT_EQ(fmt::format("{:s}", ec), ec.message()); - EXPECT_EQ(fmt::format("{:?}", std::error_code(42, generic)), - "\"generic:42\""); - EXPECT_EQ(fmt::format("{}", - std::map{ - {std::error_code(42, generic), 0}}), - "{\"generic:42\": 0}"); -} - -template void exception_test() { - try { - throw std::runtime_error("Test Exception"); - } catch (const Catch& ex) { - EXPECT_EQ("Test Exception", fmt::format("{}", ex)); - EXPECT_EQ("std::runtime_error: Test Exception", fmt::format("{:t}", ex)); - } -} - -namespace my_ns1 { -namespace my_ns2 { -struct my_exception : public std::exception { - private: - std::string msg; - - public: - my_exception(const std::string& s) : msg(s) {} - const char* what() const noexcept override; -}; -const char* my_exception::what() const noexcept { return msg.c_str(); } -} // namespace my_ns2 -} // namespace my_ns1 - -TEST(std_test, exception) { - using testing::StartsWith; - exception_test(); - exception_test(); - - try { - using namespace my_ns1::my_ns2; - throw my_exception("My Exception"); - } catch (const std::exception& ex) { - EXPECT_EQ("my_ns1::my_ns2::my_exception: My Exception", - fmt::format("{:t}", ex)); - EXPECT_EQ("My Exception", fmt::format("{:}", ex)); - } - - try { - throw std::system_error(std::error_code(), "message"); - } catch (const std::system_error& ex) { - EXPECT_THAT(fmt::format("{:t}", ex), StartsWith("std::system_error: ")); - } - -#ifdef __cpp_lib_filesystem - // Tests that the inline namespace is stripped out, e.g. - // std::filesystem::__cxx11::* -> std::filesystem::*. - try { - throw std::filesystem::filesystem_error("message", std::error_code()); - } catch (const std::filesystem::filesystem_error& ex) { - EXPECT_THAT(fmt::format("{:t}", ex), - StartsWith("std::filesystem::filesystem_error: ")); - } -#endif -} - -#if FMT_USE_RTTI -TEST(std_test, type_info) { - EXPECT_EQ(fmt::format("{}", typeid(std::runtime_error)), - "std::runtime_error"); -} -#endif - -#if FMT_USE_BITINT -FMT_PRAGMA_CLANG(diagnostic ignored "-Wbit-int-extension") - -TEST(std_test, bitint) { - using fmt::detail::bitint; - using fmt::detail::ubitint; - - EXPECT_EQ(fmt::format("{}", ubitint<3>(7)), "7"); - EXPECT_EQ(fmt::format("{}", bitint<7>()), "0"); - - EXPECT_EQ(fmt::format("{}", ubitint<15>(31000)), "31000"); - EXPECT_EQ(fmt::format("{}", bitint<16>(INT16_MIN)), "-32768"); - EXPECT_EQ(fmt::format("{}", bitint<16>(INT16_MAX)), "32767"); - - EXPECT_EQ(fmt::format("{}", ubitint<32>(4294967295)), "4294967295"); - - EXPECT_EQ(fmt::format("{}", ubitint<47>(140737488355327ULL)), - "140737488355327"); - EXPECT_EQ(fmt::format("{}", bitint<47>(-40737488355327LL)), - "-40737488355327"); - - // Check lvalues and const - auto a = bitint<8>(0); - auto b = ubitint<32>(4294967295); - const auto c = bitint<7>(0); - const auto d = ubitint<32>(4294967295); - EXPECT_EQ(fmt::format("{}", a), "0"); - EXPECT_EQ(fmt::format("{}", b), "4294967295"); - EXPECT_EQ(fmt::format("{}", c), "0"); - EXPECT_EQ(fmt::format("{}", d), "4294967295"); - - static_assert(fmt::is_formattable, char>{}, ""); - static_assert(fmt::is_formattable, char>{}, ""); -} -#endif - -TEST(std_test, format_bit_reference) { - std::bitset<2> bs(1); - EXPECT_EQ(fmt::format("{} {}", bs[0], bs[1]), "true false"); - std::vector v = {true, false}; - EXPECT_EQ(fmt::format("{} {}", v[0], v[1]), "true false"); -} - -TEST(std_test, format_const_bit_reference) { - const std::bitset<2> bs(1); - EXPECT_EQ(fmt::format("{} {}", bs[0], bs[1]), "true false"); - const std::vector v = {true, false}; - EXPECT_EQ(fmt::format("{} {}", v[0], v[1]), "true false"); -} - -TEST(std_test, format_bitset) { - auto bs = std::bitset<6>(42); - EXPECT_EQ(fmt::format("{}", bs), "101010"); - EXPECT_EQ(fmt::format("{:0>8}", bs), "00101010"); - EXPECT_EQ(fmt::format("{:-^12}", bs), "---101010---"); -} - -#ifdef __cpp_lib_byte -TEST(base_test, format_byte) { - auto s = std::string(); - fmt::format_to(std::back_inserter(s), "{}", std::byte(42)); - EXPECT_EQ(s, "42"); -} -#endif - -TEST(std_test, format_atomic) { - std::atomic b(false); - EXPECT_EQ(fmt::format("{}", b), "false"); - - const std::atomic cb(true); - EXPECT_EQ(fmt::format("{}", cb), "true"); -} - -#ifdef __cpp_lib_atomic_flag_test -TEST(std_test, format_atomic_flag) { - std::atomic_flag f; - (void)f.test_and_set(); - EXPECT_EQ(fmt::format("{}", f), "true"); - - f.clear(); - const std::atomic_flag& cf = f; - EXPECT_EQ(fmt::format("{}", cf), "false"); -} -#endif // __cpp_lib_atomic_flag_test - -TEST(std_test, format_unique_ptr) { - std::unique_ptr up(new int(1)); - EXPECT_EQ(fmt::format("{}", fmt::ptr(up.get())), - fmt::format("{}", fmt::ptr(up))); - struct custom_deleter { - void operator()(int* p) const { delete p; } - }; - std::unique_ptr upcd(new int(1)); - EXPECT_EQ(fmt::format("{}", fmt::ptr(upcd.get())), - fmt::format("{}", fmt::ptr(upcd))); -} - -TEST(std_test, format_shared_ptr) { - std::shared_ptr sp(new int(1)); - EXPECT_EQ(fmt::format("{}", fmt::ptr(sp.get())), - fmt::format("{}", fmt::ptr(sp))); -} - -TEST(std_test, format_reference_wrapper) { - int num = 35; - EXPECT_EQ(fmt::to_string(std::cref(num)), "35"); - EXPECT_EQ(fmt::to_string(std::ref(num)), "35"); - EXPECT_EQ(fmt::format("{}", std::cref(num)), "35"); - EXPECT_EQ(fmt::format("{}", std::ref(num)), "35"); -} - -// Regression test for https://github.com/fmtlib/fmt/issues/4424. -struct type_with_format_as {}; -int format_as(type_with_format_as) { return 20; } - -TEST(std_test, format_reference_wrapper_with_format_as) { - type_with_format_as t; - EXPECT_EQ(fmt::to_string(std::cref(t)), "20"); - EXPECT_EQ(fmt::to_string(std::ref(t)), "20"); - EXPECT_EQ(fmt::format("{}", std::cref(t)), "20"); - EXPECT_EQ(fmt::format("{}", std::ref(t)), "20"); -} - -struct type_with_format_as_string {}; -std::string format_as(type_with_format_as_string) { return "foo"; } - -TEST(std_test, format_reference_wrapper_with_format_as_string) { - type_with_format_as_string t; - EXPECT_EQ(fmt::to_string(std::cref(t)), "foo"); - EXPECT_EQ(fmt::to_string(std::ref(t)), "foo"); - EXPECT_EQ(fmt::format("{}", std::cref(t)), "foo"); - EXPECT_EQ(fmt::format("{}", std::ref(t)), "foo"); +TEST(StdTest, Float16) { + std::float16_t f = 1.5f16; + EXPECT_EQ(fmt::format("{}", f), "1.5"); } +#endif \ No newline at end of file