diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a0fbd05f..7fa063dd 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -138,12 +138,6 @@ endif () message(STATUS "FMT_PEDANTIC: ${FMT_PEDANTIC}") if (FMT_PEDANTIC AND CXX_STANDARD LESS 20) - # MSVC fails to compile GMock when C++17 is enabled. - if (FMT_HAS_VARIANT AND NOT MSVC) - add_fmt_test(std-format-test) - set_property(TARGET std-format-test PROPERTY CXX_STANDARD 17) - endif () - # Test that the library can be compiled with exceptions disabled. # -fno-exception is broken in icc: https://github.com/fmtlib/fmt/issues/822. if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel") diff --git a/test/format b/test/format deleted file mode 100644 index a6c9e7e9..00000000 --- a/test/format +++ /dev/null @@ -1,856 +0,0 @@ -// Formatting library for C++ - the standard API implementation -// -// Copyright (c) 2012 - present, Victor Zverovich -// All rights reserved. -// -// For the license information refer to format.h. - -#ifndef FMT_FORMAT_ -#define FMT_FORMAT_ - -#include -#include -#include -#include "fmt/format.h" - -// This implementation verifies the correctness of the standard API proposed in -// P0645 Text Formatting and is optimized for copy-pasting from the paper, not -// for efficiency or readability. An efficient implementation should not use -// std::variant and should store packed argument type tags separately from -// values in basic_format_args for small number of arguments. - -namespace std { -template -constexpr bool Integral = is_integral_v; - -template - using iter_difference_t = ptrdiff_t; -} - -// https://fmt.dev/Text%20Formatting.html#format.syn -namespace std { - // [format.error], class format_error - class format_error; - - // [format.formatter], formatter - template class basic_format_parse_context; - using format_parse_context = basic_format_parse_context; - using wformat_parse_context = basic_format_parse_context; - - template class basic_format_context; - using format_context = basic_format_context< - /* unspecified */ fmt::detail::buffer_appender, char>; - using wformat_context = basic_format_context< - /* unspecified */ fmt::detail::buffer_appender, wchar_t>; - - template struct formatter { - formatter() = delete; - }; - - // [format.arguments], arguments - template class basic_format_arg; - - template - /* see below */ auto visit_format_arg(Visitor&& vis, basic_format_arg arg); - - template struct format_arg_store; // exposition only - - template class basic_format_args; - using format_args = basic_format_args; - using wformat_args = basic_format_args; - - template - using format_args_t = basic_format_args>; - - template - format_arg_store - make_format_args(const Args&... args); - template - format_arg_store - make_wformat_args(const Args&... args); - - // [format.functions], formatting functions - template - string format(string_view fmt, const Args&... args); - template - wstring format(wstring_view fmt, const Args&... args); - - string vformat(string_view fmt, format_args args); - wstring vformat(wstring_view fmt, wformat_args args); - - template - Out format_to(Out out, string_view fmt, const Args&... args); - template - Out format_to(Out out, wstring_view fmt, const Args&... args); - - template - Out vformat_to(Out out, string_view fmt, format_args_t, char> args); - template - Out vformat_to(Out out, wstring_view fmt, format_args_t, wchar_t> args); - - template - struct format_to_n_result { - Out out; - iter_difference_t size; - }; - - template - format_to_n_result format_to_n(Out out, iter_difference_t n, - string_view fmt, const Args&... args); - template - format_to_n_result format_to_n(Out out, iter_difference_t n, - wstring_view fmt, const Args&... args); - - template - size_t formatted_size(string_view fmt, const Args&... args); - template - size_t formatted_size(wstring_view fmt, const Args&... args); -} - -// https://fmt.dev/Text%20Formatting.html#format.error -namespace std { - class format_error : public runtime_error { - public: - explicit format_error(const string& what_arg) : runtime_error(what_arg) {} - explicit format_error(const char* what_arg) : runtime_error(what_arg) {} - }; -} - -namespace std { -namespace detail { -struct error_handler { - // This function is intentionally not constexpr to give a compile-time error. - void on_error(const char* message) { - throw std::format_error(message); - } -}; -} -} - -// https://fmt.dev/Text%20Formatting.html#format.parse_context -namespace std { - template - class basic_format_parse_context { - public: - using char_type = charT; - using const_iterator = typename basic_string_view::const_iterator; - using iterator = const_iterator; - - private: - iterator begin_; // exposition only - iterator end_; // exposition only - enum indexing { unknown, manual, automatic }; // exposition only - indexing indexing_; // exposition only - size_t next_arg_id_; // exposition only - size_t num_args_; // exposition only - - public: - explicit constexpr basic_format_parse_context(basic_string_view fmt, - size_t num_args = 0) noexcept; - basic_format_parse_context(const basic_format_parse_context&) = delete; - basic_format_parse_context& operator=(const basic_format_parse_context&) = delete; - - constexpr const_iterator begin() const noexcept; - constexpr const_iterator end() const noexcept; - constexpr void advance_to(const_iterator it); - - constexpr size_t next_arg_id(); - constexpr void check_arg_id(size_t id); - - // Implementation detail: - constexpr void check_arg_id(fmt::string_view) {} - detail::error_handler error_handler() const { return {}; } - void on_error(const char* msg) { error_handler().on_error(msg); } - }; -} - -namespace std { -template -/* explicit */ constexpr basic_format_parse_context:: - basic_format_parse_context(basic_string_view fmt, - size_t num_args) noexcept -: begin_(fmt.begin()), end_(fmt.end()), indexing_(unknown), next_arg_id_(0), num_args_(num_args) {} - -template -constexpr typename basic_format_parse_context::const_iterator basic_format_parse_context::begin() const noexcept { return begin_; } - -template -constexpr typename basic_format_parse_context::const_iterator basic_format_parse_context::end() const noexcept { return end_; } - -template -constexpr void basic_format_parse_context::advance_to(typename basic_format_parse_context::iterator it) { begin_ = it; } - -template -constexpr size_t basic_format_parse_context::next_arg_id() { - if (indexing_ == manual) - throw format_error("manual to automatic indexing"); - if (indexing_ == unknown) - indexing_ = automatic; - return next_arg_id_++; -} - -template -constexpr void basic_format_parse_context::check_arg_id(size_t id) { - // clang doesn't support __builtin_is_constant_evaluated yet - //if (!(!__builtin_is_constant_evaluated() || id < num_args_)) - // throw format_error(invalid index is out of range"); - if (indexing_ == automatic) - throw format_error("automatic to manual indexing"); - if (indexing_ == unknown) - indexing_ = manual; -} -} - -// https://fmt.dev/Text%20Formatting.html#format.context -namespace std { - template - class basic_format_context { - basic_format_args args_; // exposition only - Out out_; // exposition only - - public: - using iterator = Out; - using char_type = charT; - template using formatter_type = formatter; - - basic_format_arg arg(size_t id) const; - - iterator out(); - void advance_to(iterator it); - - // Implementation details: - using format_arg = basic_format_arg; - basic_format_context(Out out, basic_format_args args, fmt::detail::locale_ref) - : args_(args), out_(out) {} - detail::error_handler error_handler() const { return {}; } - basic_format_arg arg(fmt::basic_string_view) const { - return {}; // unused: named arguments are not supported yet - } - void on_error(const char* msg) { error_handler().on_error(msg); } - }; -} - -namespace std { -template -basic_format_arg> basic_format_context::arg(size_t id) const { return args_.get(id); } - -template -typename basic_format_context::iterator basic_format_context::out() { return out_; } - -template -void basic_format_context::advance_to(typename basic_format_context::iterator it) { out_ = it; } -} - -namespace std { -namespace detail { -template -constexpr bool is_standard_integer_v = - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v; - -template -constexpr bool is_standard_unsigned_integer_v = - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v; - -template struct formatter; -} -} - -// https://fmt.dev/Text%20Formatting.html#format.arg -namespace std { - template - class basic_format_arg { - public: - class handle; - - private: - using char_type = typename Context::char_type; // exposition only - - variant, - const void*, handle> value; // exposition only - - template || - std::is_same_v || - (std::is_same_v && std::is_same_v) || - detail::is_standard_integer_v || - detail::is_standard_unsigned_integer_v || - sizeof(typename Context::template formatter_type().format(declval(), declval())) != 0 - >> explicit basic_format_arg(const T& v) noexcept; // exposition only - explicit basic_format_arg(float n) noexcept; // exposition only - explicit basic_format_arg(double n) noexcept; // exposition only - explicit basic_format_arg(long double n) noexcept; // exposition only - explicit basic_format_arg(const char_type* s); // exposition only - - template - explicit basic_format_arg( - basic_string_view s) noexcept; // exposition only - - template - explicit basic_format_arg( - const basic_string& s) noexcept; // exposition only - - explicit basic_format_arg(nullptr_t) noexcept; // exposition only - - template>> - explicit basic_format_arg(const T* p) noexcept; // exposition only - - // Fails due to a bug in clang - //template - // friend auto visit_format_arg(Visitor&& vis, - // basic_format_arg arg); // exposition only - - friend auto get_value(basic_format_arg arg) { - return arg.value; - } - - template friend struct detail::formatter; - - template - friend format_arg_store - make_format_args(const Args&... args); // exposition only - - public: - basic_format_arg() noexcept; - - explicit operator bool() const noexcept; - }; -} - -namespace std { -template -basic_format_arg::basic_format_arg() noexcept {} - -template -template /* explicit */ basic_format_arg::basic_format_arg(const T& v) noexcept { - if constexpr (std::is_same_v || std::is_same_v) - value = v; - else if constexpr (std::is_same_v && std::is_same_v) - value = static_cast(v); - else if constexpr (detail::is_standard_integer_v && sizeof(T) <= sizeof(int)) - value = static_cast(v); - else if constexpr (detail::is_standard_unsigned_integer_v && sizeof(T) <= sizeof(unsigned)) - value = static_cast(v); - else if constexpr (detail::is_standard_integer_v) - value = static_cast(v); - else if constexpr (detail::is_standard_unsigned_integer_v) - value = static_cast(v); - else if constexpr (sizeof(typename Context::template formatter_type().format(declval(), declval())) != 0) - value = handle(v); -} - -template -/* explicit */ basic_format_arg::basic_format_arg(float n) noexcept - : value(static_cast(n)) {} - -template -/* explicit */ basic_format_arg::basic_format_arg(double n) noexcept - : value(n) {} - -template -/* explicit */ basic_format_arg::basic_format_arg(long double n) noexcept - : value(n) {} - -template -/* explicit */ basic_format_arg::basic_format_arg(const typename basic_format_arg::char_type* s) - : value(s) { - assert(s != nullptr); -} - -template -template -/* explicit */ basic_format_arg::basic_format_arg(basic_string_view s) noexcept - : value(s) {} - -template -template -/* explicit */ basic_format_arg::basic_format_arg( - const basic_string& s) noexcept - : value(basic_string_view(s.data(), s.size())) {} - - -template -/* explicit */ basic_format_arg::basic_format_arg(nullptr_t) noexcept - : value(static_cast(nullptr)) {} - -template -template /* explicit */ basic_format_arg::basic_format_arg(const T* p) noexcept - : value(p) {} - -template -/* explicit */ basic_format_arg::operator bool() const noexcept { - return !holds_alternative(value); -} -} - -namespace std { - template - class basic_format_arg::handle { - const void* ptr_; // exposition only - void (*format_)(basic_format_parse_context&, - Context&, const void*); // exposition only - - template explicit handle(const T& val) noexcept; // exposition only - - friend class basic_format_arg; // exposition only - - public: - void format(basic_format_parse_context&, Context& ctx) const; - }; -} - -namespace std { -template -template /* explicit */ basic_format_arg::handle::handle(const T& val) noexcept - : ptr_(&val), format_([](basic_format_parse_context& parse_ctx, Context& format_ctx, const void* ptr) { - typename Context::template formatter_type f; - parse_ctx.advance_to(f.parse(parse_ctx)); - format_ctx.advance_to(f.format(*static_cast(ptr), format_ctx)); - }) {} - -template -void basic_format_arg::handle::format(basic_format_parse_context& parse_ctx, Context& format_ctx) const { - format_(parse_ctx, format_ctx, ptr_); -} - -// https://fmt.dev/Text%20Formatting.html#format.visit -template - auto visit_format_arg(Visitor&& vis, basic_format_arg arg) { - return visit(vis, get_value(arg)); - } -} - -// https://fmt.dev/Text%20Formatting.html#format.store -namespace std { - template - struct format_arg_store { // exposition only - array, sizeof...(Args)> args; - }; -} - -// https://fmt.dev/Text%20Formatting.html#format.basic_args -namespace std { - template - class basic_format_args { - size_t size_; // exposition only - const basic_format_arg* data_; // exposition only - - public: - basic_format_args() noexcept; - - template - basic_format_args(const format_arg_store& store) noexcept; - - basic_format_arg get(size_t i) const noexcept; - }; -} - -namespace std { - -template -basic_format_args::basic_format_args() noexcept : size_(0) {} - -template -template - basic_format_args::basic_format_args(const format_arg_store& store) noexcept - : size_(sizeof...(Args)), data_(store.args.data()) {} - -template -basic_format_arg basic_format_args::get(size_t i) const noexcept { - return i < size_ ? data_[i] : basic_format_arg(); -} -} - -namespace std { -// https://fmt.dev/Text%20Formatting.html#format.make_args -template - format_arg_store make_format_args(const Args&... args) { - return {basic_format_arg(args)...}; - } - -// https://fmt.dev/Text%20Formatting.html#format.make_wargs -template - format_arg_store make_wformat_args(const Args&... args) { - return make_format_args(args...); - } -} - -namespace std { -namespace detail { - -template -class arg_formatter - : public fmt::detail::arg_formatter_base { - private: - using char_type = Char; - using base = fmt::detail::arg_formatter_base; - using format_context = std::basic_format_context; - using parse_context = basic_format_parse_context; - - parse_context* parse_ctx_; - format_context& ctx_; - - public: - using iterator = OutputIt; - using format_specs = typename base::format_specs; - - /** - \rst - Constructs an argument formatter object. - *ctx* is a reference to the formatting context, - *spec* contains format specifier information for standard argument types. - \endrst - */ - arg_formatter(format_context& ctx, parse_context* parse_ctx = nullptr, fmt::format_specs* spec = nullptr) - : base(ctx.out(), spec, {}), parse_ctx_(parse_ctx), ctx_(ctx) {} - - using base::operator(); - - /** Formats an argument of a user-defined type. */ - iterator operator()(typename std::basic_format_arg::handle handle) { - handle.format(*parse_ctx_, ctx_); - return this->out(); - } - - iterator operator()(monostate) { - throw format_error(""); - } -}; - -template -inline fmt::detail::type get_type(basic_format_arg arg) { - return visit_format_arg([&] (auto val) { - using char_type = typename Context::char_type; - using T = decltype(val); - if (std::is_same_v) - return fmt::detail::type::none_type; - if (std::is_same_v) - return fmt::detail::type::bool_type; - if (std::is_same_v) - return fmt::detail::type::char_type; - if (std::is_same_v) - return fmt::detail::type::int_type; - if (std::is_same_v) - return fmt::detail::type::uint_type; - if (std::is_same_v) - return fmt::detail::type::long_long_type; - if (std::is_same_v) - return fmt::detail::type::ulong_long_type; - if (std::is_same_v) - return fmt::detail::type::double_type; - if (std::is_same_v) - return fmt::detail::type::long_double_type; - if (std::is_same_v) - return fmt::detail::type::cstring_type; - if (std::is_same_v>) - return fmt::detail::type::string_type; - if (std::is_same_v) - return fmt::detail::type::pointer_type; - assert(get_value(arg).index() == 12); - return fmt::detail::type::custom_type; - }, arg); -} - -template -class custom_formatter { - private: - using parse_context = basic_format_parse_context; - parse_context& parse_ctx_; - Context& format_ctx_; - - public: - custom_formatter(parse_context& parse_ctx, Context& ctx) : parse_ctx_(parse_ctx), format_ctx_(ctx) {} - - bool operator()(typename basic_format_arg::handle h) const { - h.format(parse_ctx_, format_ctx_); - return true; - } - - template bool operator()(T) const { return false; } -}; - -template -struct format_handler : detail::error_handler { - using iterator = typename ArgFormatter::iterator; - - format_handler(iterator out, basic_string_view str, - basic_format_args format_args, - fmt::detail::locale_ref loc) - : parse_ctx(str), context(out, format_args, loc) {} - - void on_text(const Char* begin, const Char* end) { - auto size = fmt::detail::to_unsigned(end - begin); - auto out = context.out(); - auto&& it = fmt::detail::reserve(out, size); - it = std::copy_n(begin, size, it); - context.advance_to(out); - } - - int on_arg_id() { return parse_ctx.next_arg_id(); } - int on_arg_id(unsigned id) { return parse_ctx.check_arg_id(id), id; } - int on_arg_id(fmt::basic_string_view) { return 0; } - - void on_replacement_field(int id, const Char* p) { - auto arg = context.arg(id); - parse_ctx.advance_to(parse_ctx.begin() + (p - &*parse_ctx.begin())); - custom_formatter f(parse_ctx, context); - if (!visit_format_arg(f, arg)) - context.advance_to(visit_format_arg(ArgFormatter(context, &parse_ctx), arg)); - } - - const Char* on_format_specs(int id, const Char* begin, const Char* end) { - auto arg = context.arg(id); - parse_ctx.advance_to(parse_ctx.begin() + (begin - &*parse_ctx.begin())); - custom_formatter f(parse_ctx, context); - if (visit_format_arg(f, arg)) return &*parse_ctx.begin(); - fmt::basic_format_specs specs; - using fmt::detail::specs_handler; - using parse_context = basic_format_parse_context; - fmt::detail::specs_checker> handler( - specs_handler(specs, parse_ctx, context), get_type(arg)); - begin = parse_format_specs(begin, end, handler); - if (begin == end || *begin != '}') on_error("missing '}' in format string"); - parse_ctx.advance_to(parse_ctx.begin() + (begin - &*parse_ctx.begin())); - context.advance_to(visit_format_arg(ArgFormatter(context, &parse_ctx, &specs), arg)); - return begin; - } - - basic_format_parse_context parse_ctx; - Context context; -}; - -template -struct formatter { - // Parses format specifiers stopping either at the end of the range or at the - // terminating '}'. - template - FMT_CONSTEXPR typename ParseContext::iterator parse(ParseContext& ctx) { - namespace detail = fmt::detail; - typedef detail::dynamic_specs_handler handler_type; - auto type = detail::mapped_type_constant>::value; - detail::specs_checker handler(handler_type(specs_, ctx), - type); - auto it = parse_format_specs(ctx.begin(), ctx.end(), handler); - auto type_spec = specs_.type; - auto eh = ctx.error_handler(); - switch (type) { - case detail::type::none_type: - FMT_ASSERT(false, "invalid argument type"); - break; - case detail::type::int_type: - case detail::type::uint_type: - case detail::type::long_long_type: - case detail::type::ulong_long_type: - case detail::type::bool_type: - handle_int_type_spec(type_spec, - detail::int_type_checker(eh)); - break; - case detail::type::char_type: - handle_char_specs( - &specs_, detail::char_specs_checker(type_spec, eh)); - break; - case detail::type::double_type: - case detail::type::long_double_type: - detail::parse_float_type_spec(specs_, eh); - break; - case detail::type::cstring_type: - detail::handle_cstring_type_spec( - type_spec, detail::cstring_type_checker(eh)); - break; - case detail::type::string_type: - detail::check_string_type_spec(type_spec, eh); - break; - case detail::type::pointer_type: - detail::check_pointer_type_spec(type_spec, eh); - break; - case detail::type::custom_type: - // Custom format specifiers should be checked in parse functions of - // formatter specializations. - break; - } - return it; - } - - template - auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) { - fmt::detail::handle_dynamic_spec( - specs_.width, specs_.width_ref, ctx); - fmt::detail::handle_dynamic_spec( - specs_.precision, specs_.precision_ref, ctx); - using af = arg_formatter; - return visit_format_arg(af(ctx, nullptr, &specs_), - basic_format_arg(val)); - } - - private: - fmt::detail::dynamic_format_specs specs_; -}; -} // namespace detail - -// https://fmt.dev/Text%20Formatting.html#format.functions -template - string format(string_view fmt, const Args&... args) { - return vformat(fmt, make_format_args(args...)); - } - -template - wstring format(wstring_view fmt, const Args&... args) { - return vformat(fmt, make_wformat_args(args...)); - } - -string vformat(string_view fmt, format_args args) { - fmt::memory_buffer mbuf; - fmt::detail::buffer& buf = mbuf; - using af = detail::arg_formatter; - detail::format_handler - h(fmt::detail::buffer_appender(buf), fmt, args, {}); - fmt::detail::parse_format_string(fmt::to_string_view(fmt), h); - return to_string(mbuf); -} - -wstring vformat(wstring_view fmt, wformat_args args); - -template - Out format_to(Out out, string_view fmt, const Args&... args) { - using context = basic_format_context; - return vformat_to(out, fmt, make_format_args(args...)); - } - -template - Out format_to(Out out, wstring_view fmt, const Args&... args) { - using context = basic_format_context; - return vformat_to(out, fmt, make_format_args(args...)); - } - -template - Out vformat_to(Out out, string_view fmt, format_args_t, char> args) { - using af = detail::arg_formatter; - detail::format_handler> - h(out, fmt, args, {}); - fmt::detail::parse_format_string(fmt::to_string_view(fmt), h); - return h.context.out(); - } - -template - Out vformat_to(Out out, wstring_view fmt, format_args_t, wchar_t> args); - -template - format_to_n_result format_to_n(Out out, iter_difference_t n, - string_view fmt, const Args&... args); -template - format_to_n_result format_to_n(Out out, iter_difference_t n, - wstring_view fmt, const Args&... args); - -template - size_t formatted_size(string_view fmt, const Args&... args); -template - size_t formatted_size(wstring_view fmt, const Args&... args); - -#define charT char - -template<> struct formatter : detail::formatter {}; - -template<> struct formatter; - -template<> struct formatter : detail::formatter {}; - -template<> struct formatter : detail::formatter {}; - -template struct formatter - : detail::formatter, charT> {}; - -template - struct formatter, charT> - : detail::formatter, charT> {}; - -template - struct formatter, charT> - : detail::formatter, charT> {}; - -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; - -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; -template <> struct formatter - : detail::formatter, charT> {}; -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; -template <> struct formatter - : detail::formatter, charT> {}; -template <> struct formatter : detail::formatter {}; - -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; - -#undef charT - -#define charT wchar_t - -template<> struct formatter : detail::formatter {}; - -template<> struct formatter : detail::formatter {}; - -template<> struct formatter : detail::formatter {}; - -template<> struct formatter : detail::formatter {}; - -template struct formatter - : detail::formatter, charT> {}; - -template - struct formatter, charT> - : detail::formatter, charT> {}; - -template - struct formatter, charT> - : detail::formatter, charT> {}; - -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; - -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; -template <> struct formatter - : detail::formatter, charT> {}; -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; -template <> struct formatter - : detail::formatter, charT> {}; -template <> struct formatter : detail::formatter {}; - -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; -template <> struct formatter : detail::formatter {}; - -#undef charT - - template<> struct formatter { - formatter() = delete; - }; -} - -#endif // FMT_FORMAT_ diff --git a/test/std-format-test.cc b/test/std-format-test.cc deleted file mode 100644 index c67a2a03..00000000 --- a/test/std-format-test.cc +++ /dev/null @@ -1,161 +0,0 @@ -#include - -#include "gtest/gtest.h" - -TEST(std_format_test, escaping) { - using namespace std; - string s = format("{0}-{{", 8); // s == "8-{" - EXPECT_EQ(s, "8-{"); -} - -TEST(std_format_test, indexing) { - using namespace std; - string s0 = format("{} to {}", "a", "b"); // OK: automatic indexing - string s1 = format("{1} to {0}", "a", "b"); // OK: manual indexing - EXPECT_EQ(s0, "a to b"); - EXPECT_EQ(s1, "b to a"); - // Error: mixing automatic and manual indexing - EXPECT_THROW(string s2 = format("{0} to {}", "a", "b"), std::format_error); - // Error: mixing automatic and manual indexing - EXPECT_THROW(string s3 = format("{} to {1}", "a", "b"), std::format_error); -} - -TEST(std_format_test, alignment) { - using namespace std; - char c = 120; - string s0 = format("{:6}", 42); // s0 == " 42" - string s1 = format("{:6}", 'x'); // s1 == "x " - string s2 = format("{:*<6}", 'x'); // s2 == "x*****" - string s3 = format("{:*>6}", 'x'); // s3 == "*****x" - string s4 = format("{:*^6}", 'x'); // s4 == "**x***" - // Error: '=' with charT and no integer presentation type - EXPECT_THROW(string s5 = format("{:=6}", 'x'), std::format_error); - string s6 = format("{:6d}", c); // s6 == " 120" - string s7 = format("{:6}", true); // s9 == "true " - EXPECT_EQ(s0, " 42"); - EXPECT_EQ(s1, "x "); - EXPECT_EQ(s2, "x*****"); - EXPECT_EQ(s3, "*****x"); - EXPECT_EQ(s4, "**x***"); - EXPECT_EQ(s6, " 120"); - EXPECT_EQ(s7, "true "); -} - -TEST(std_format_test, float) { - using namespace std; - double inf = numeric_limits::infinity(); - double nan = numeric_limits::quiet_NaN(); - string s0 = format("{0:} {0:+} {0:-} {0: }", 1); // s0 == "1 +1 1 1" - string s1 = format("{0:} {0:+} {0:-} {0: }", -1); // s1 == "-1 -1 -1 -1" - string s2 = - format("{0:} {0:+} {0:-} {0: }", inf); // s2 == "inf +inf inf inf" - string s3 = - format("{0:} {0:+} {0:-} {0: }", nan); // s3 == "nan +nan nan nan" - EXPECT_EQ(s0, "1 +1 1 1"); - EXPECT_EQ(s1, "-1 -1 -1 -1"); - EXPECT_EQ(s2, "inf +inf inf inf"); - EXPECT_EQ(s3, "nan +nan nan nan"); -} - -TEST(std_format_test, int) { - using namespace std; - string s0 = format("{}", 42); // s0 == "42" - string s1 = format("{0:b} {0:d} {0:o} {0:x}", 42); // s1 == "101010 42 52 2a" - string s2 = format("{0:#x} {0:#X}", 42); // s2 == "0x2a 0X2A" - string s3 = format("{:L}", 1234); // s3 == "1234" (depends on the locale) - EXPECT_EQ(s0, "42"); - EXPECT_EQ(s1, "101010 42 52 2a"); - EXPECT_EQ(s2, "0x2a 0X2A"); - EXPECT_EQ(s3, "1234"); -} - -#include - -enum color { red, green, blue }; - -const char* color_names[] = {"red", "green", "blue"}; - -template <> struct std::formatter : std::formatter { - auto format(color c, format_context& ctx) { - return formatter::format(color_names[c], ctx); - } -}; - -struct err {}; - -TEST(std_format_test, formatter) { - std::string s0 = std::format("{}", 42); // OK: library-provided formatter - // std::string s1 = std::format("{}", L"foo"); // Ill-formed: disabled - // formatter - std::string s2 = std::format("{}", red); // OK: user-provided formatter - // std::string s3 = std::format("{}", err{}); // Ill-formed: disabled - // formatter - EXPECT_EQ(s0, "42"); - EXPECT_EQ(s2, "red"); -} - -struct S { - int value; -}; - -template <> struct std::formatter { - size_t width_arg_id = 0; - - // Parses a width argument id in the format { }. - constexpr auto parse(format_parse_context& ctx) { - constexpr auto is_ascii_digit = [](const char c) { - return c >= '0' && c <= '9'; - }; - - auto iter = ctx.begin(); - // auto get_char = [&]() { return iter != ctx.end() ? *iter : 0; }; - auto get_char = [&]() { return iter != ctx.end() ? *iter : '\0'; }; - if (get_char() != '{') return iter; - ++iter; - char c = get_char(); - if (!is_ascii_digit(c) || (++iter, get_char()) != '}') - throw format_error("invalid format"); - width_arg_id = fmt::detail::to_unsigned(c - '0'); - ctx.check_arg_id(width_arg_id); - return ++iter; - } - - // Formats S with width given by the argument width_arg_id. - auto format(S s, format_context& ctx) { - int width = visit_format_arg( - [](auto value) -> int { - using type = decltype(value); - if constexpr (!is_integral_v || is_same_v) - throw format_error("width is not integral"); - // else if (value < 0 || value > numeric_limits::max()) - else if (fmt::detail::is_negative(value) || - value > numeric_limits::max()) - throw format_error("invalid width"); - else - return static_cast(value); - }, - ctx.arg(width_arg_id)); - return format_to(ctx.out(), "{0:{1}}", s.value, width); - } -}; - -TEST(std_format_test, parsing) { - std::string s = std::format("{0:{1}}", S{42}, 10); // s == " 42" - EXPECT_EQ(s, " 42"); -} - -#if FMT_USE_INT128 -template <> struct std::formatter<__int128_t> : std::formatter { - auto format(__int128_t n, format_context& ctx) { - // Format as a long long since we only want to check if it is possible to - // specialize formatter for __int128_t. - return formatter::format(static_cast(n), ctx); - } -}; - -TEST(std_format_test, int128) { - __int128_t n = 42; - auto s = std::format("{}", n); - EXPECT_EQ(s, "42"); -} -#endif // FMT_USE_INT128