diff --git a/include/fmt/core.h b/include/fmt/core.h index c060ed7c..d82948b7 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -11,7 +11,7 @@ #include // std::byte #include // std::FILE #include // std::strlen -#include // std::back_insert_iterator +#include // DEPRECATED! #include // std::numeric_limits #include #include @@ -1099,16 +1099,27 @@ using has_formatter = // An output iterator that appends to a buffer. // It is used to reduce symbol sizes for the common case. -class appender : public std::back_insert_iterator> { - using base = std::back_insert_iterator>; +class appender { + private: + detail::buffer* buffer_; + + friend auto get_container(appender app) -> detail::buffer& { + return *app.buffer_; + } public: - using std::back_insert_iterator>::back_insert_iterator; - appender(base it) noexcept : base(it) {} + using difference_type = ptrdiff_t; FMT_UNCHECKED_ITERATOR(appender); - auto operator++() noexcept -> appender& { return *this; } - auto operator++(int) noexcept -> appender { return *this; } + appender(detail::buffer& buf) : buffer_(&buf) {} + + auto operator=(char c) -> appender& { + buffer_->push_back(c); + return *this; + } + auto operator*() -> appender& {return *this;} + auto operator++() -> appender& { return *this; } + auto operator++(int) -> appender { return *this; } }; namespace detail { @@ -1545,6 +1556,8 @@ template using void_t = void; template struct is_output_iterator : std::false_type {}; +template <> struct is_output_iterator : std::true_type {}; + template struct is_output_iterator< It, T, diff --git a/include/fmt/format.h b/include/fmt/format.h index 997020b9..9aa51f19 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -262,6 +262,14 @@ inline auto ctzll(uint64_t x) -> int { FMT_END_NAMESPACE #endif +namespace std { +template <> +struct iterator_traits { + using value_type = void; + using iterator_category = std::output_iterator_tag; +}; +} + FMT_BEGIN_NAMESPACE namespace detail { diff --git a/test/core-test.cc b/test/core-test.cc index db2cbc39..3c811ce9 100644 --- a/test/core-test.cc +++ b/test/core-test.cc @@ -11,7 +11,6 @@ #include "fmt/core.h" -#include // std::copy_n #include // INT_MAX #include // std::strlen #include // std::equal_to @@ -33,6 +32,11 @@ using testing::Return; # error core-test includes format.h #endif +fmt::appender copy(fmt::string_view s, fmt::appender out) { + for (char c : s) *out++ = c; + return out; +} + TEST(string_view_test, value_type) { static_assert(std::is_same::value, ""); } @@ -102,16 +106,6 @@ TEST(core_test, is_output_iterator) { } TEST(core_test, buffer_appender) { - // back_insert_iterator is not default-constructible before C++20, so - // buffer_appender can only be default-constructible when back_insert_iterator - // is. - static_assert( - std::is_default_constructible< - std::back_insert_iterator>>::value == - std::is_default_constructible< - fmt::detail::buffer_appender>::value, - ""); - #ifdef __cpp_lib_ranges static_assert(std::output_iterator, char>); #endif @@ -297,8 +291,7 @@ template struct formatter { } auto format(test_struct, format_context& ctx) const -> decltype(ctx.out()) { - auto test = string_view("test"); - return std::copy_n(test.data(), test.size(), ctx.out()); + return copy("test", ctx.out()); } }; FMT_END_NAMESPACE @@ -619,8 +612,7 @@ template <> struct formatter { auto format(const const_formattable&, format_context& ctx) -> decltype(ctx.out()) { - auto test = string_view("test"); - return std::copy_n(test.data(), test.size(), ctx.out()); + return copy("test", ctx.out()); } }; @@ -631,8 +623,7 @@ template <> struct formatter { auto format(nonconst_formattable&, format_context& ctx) -> decltype(ctx.out()) { - auto test = string_view("test"); - return std::copy_n(test.data(), test.size(), ctx.out()); + return copy("test", ctx.out()); } }; FMT_END_NAMESPACE @@ -653,8 +644,7 @@ template <> struct formatter { auto format(convertible_to_pointer_formattable, format_context& ctx) const -> decltype(ctx.out()) { - auto test = string_view("test"); - return std::copy_n(test.data(), test.size(), ctx.out()); + return copy("test", ctx.out()); } }; FMT_END_NAMESPACE @@ -732,7 +722,7 @@ template <> struct formatter { } auto format(convertible_to_int, format_context& ctx) const -> decltype(ctx.out()) { - return std::copy_n("foo", 3, ctx.out()); + return copy("foo", ctx.out()); } }; @@ -742,7 +732,7 @@ template <> struct formatter { } auto format(convertible_to_cstring, format_context& ctx) const -> decltype(ctx.out()) { - return std::copy_n("bar", 3, ctx.out()); + return copy("bar", ctx.out()); } }; FMT_END_NAMESPACE @@ -853,8 +843,7 @@ template <> struct formatter { } auto format(its_a_trap, format_context& ctx) const -> decltype(ctx.out()) { - auto s = string_view("42"); - return std::copy(s.begin(), s.end(), ctx.out()); + return copy("42", ctx.out()); } }; FMT_END_NAMESPACE