Decouple appender from back_insert_iterator
This commit is contained in:
parent
242bcaec04
commit
c9d233c0a4
@ -11,7 +11,7 @@
|
|||||||
#include <cstddef> // std::byte
|
#include <cstddef> // std::byte
|
||||||
#include <cstdio> // std::FILE
|
#include <cstdio> // std::FILE
|
||||||
#include <cstring> // std::strlen
|
#include <cstring> // std::strlen
|
||||||
#include <iterator> // std::back_insert_iterator
|
#include <iterator> // DEPRECATED!
|
||||||
#include <limits> // std::numeric_limits
|
#include <limits> // std::numeric_limits
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
@ -1099,16 +1099,27 @@ using has_formatter =
|
|||||||
|
|
||||||
// An output iterator that appends to a buffer.
|
// An output iterator that appends to a buffer.
|
||||||
// It is used to reduce symbol sizes for the common case.
|
// It is used to reduce symbol sizes for the common case.
|
||||||
class appender : public std::back_insert_iterator<detail::buffer<char>> {
|
class appender {
|
||||||
using base = std::back_insert_iterator<detail::buffer<char>>;
|
private:
|
||||||
|
detail::buffer<char>* buffer_;
|
||||||
|
|
||||||
|
friend auto get_container(appender app) -> detail::buffer<char>& {
|
||||||
|
return *app.buffer_;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using std::back_insert_iterator<detail::buffer<char>>::back_insert_iterator;
|
using difference_type = ptrdiff_t;
|
||||||
appender(base it) noexcept : base(it) {}
|
|
||||||
FMT_UNCHECKED_ITERATOR(appender);
|
FMT_UNCHECKED_ITERATOR(appender);
|
||||||
|
|
||||||
auto operator++() noexcept -> appender& { return *this; }
|
appender(detail::buffer<char>& buf) : buffer_(&buf) {}
|
||||||
auto operator++(int) noexcept -> appender { return *this; }
|
|
||||||
|
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 {
|
namespace detail {
|
||||||
@ -1545,6 +1556,8 @@ template <typename...> using void_t = void;
|
|||||||
template <typename It, typename T, typename Enable = void>
|
template <typename It, typename T, typename Enable = void>
|
||||||
struct is_output_iterator : std::false_type {};
|
struct is_output_iterator : std::false_type {};
|
||||||
|
|
||||||
|
template <> struct is_output_iterator<appender, char> : std::true_type {};
|
||||||
|
|
||||||
template <typename It, typename T>
|
template <typename It, typename T>
|
||||||
struct is_output_iterator<
|
struct is_output_iterator<
|
||||||
It, T,
|
It, T,
|
||||||
|
@ -262,6 +262,14 @@ inline auto ctzll(uint64_t x) -> int {
|
|||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template <>
|
||||||
|
struct iterator_traits<fmt::appender> {
|
||||||
|
using value_type = void;
|
||||||
|
using iterator_category = std::output_iterator_tag;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
#include "fmt/core.h"
|
#include "fmt/core.h"
|
||||||
|
|
||||||
#include <algorithm> // std::copy_n
|
|
||||||
#include <climits> // INT_MAX
|
#include <climits> // INT_MAX
|
||||||
#include <cstring> // std::strlen
|
#include <cstring> // std::strlen
|
||||||
#include <functional> // std::equal_to
|
#include <functional> // std::equal_to
|
||||||
@ -33,6 +32,11 @@ using testing::Return;
|
|||||||
# error core-test includes format.h
|
# error core-test includes format.h
|
||||||
#endif
|
#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) {
|
TEST(string_view_test, value_type) {
|
||||||
static_assert(std::is_same<string_view::value_type, char>::value, "");
|
static_assert(std::is_same<string_view::value_type, char>::value, "");
|
||||||
}
|
}
|
||||||
@ -102,16 +106,6 @@ TEST(core_test, is_output_iterator) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(core_test, buffer_appender) {
|
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<fmt::detail::buffer<char>>>::value ==
|
|
||||||
std::is_default_constructible<
|
|
||||||
fmt::detail::buffer_appender<char>>::value,
|
|
||||||
"");
|
|
||||||
|
|
||||||
#ifdef __cpp_lib_ranges
|
#ifdef __cpp_lib_ranges
|
||||||
static_assert(std::output_iterator<fmt::detail::buffer_appender<char>, char>);
|
static_assert(std::output_iterator<fmt::detail::buffer_appender<char>, char>);
|
||||||
#endif
|
#endif
|
||||||
@ -297,8 +291,7 @@ template <typename Char> struct formatter<test_struct, Char> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto format(test_struct, format_context& ctx) const -> decltype(ctx.out()) {
|
auto format(test_struct, format_context& ctx) const -> decltype(ctx.out()) {
|
||||||
auto test = string_view("test");
|
return copy("test", ctx.out());
|
||||||
return std::copy_n(test.data(), test.size(), ctx.out());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
@ -619,8 +612,7 @@ template <> struct formatter<const_formattable> {
|
|||||||
|
|
||||||
auto format(const const_formattable&, format_context& ctx)
|
auto format(const const_formattable&, format_context& ctx)
|
||||||
-> decltype(ctx.out()) {
|
-> decltype(ctx.out()) {
|
||||||
auto test = string_view("test");
|
return copy("test", ctx.out());
|
||||||
return std::copy_n(test.data(), test.size(), ctx.out());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -631,8 +623,7 @@ template <> struct formatter<nonconst_formattable> {
|
|||||||
|
|
||||||
auto format(nonconst_formattable&, format_context& ctx)
|
auto format(nonconst_formattable&, format_context& ctx)
|
||||||
-> decltype(ctx.out()) {
|
-> decltype(ctx.out()) {
|
||||||
auto test = string_view("test");
|
return copy("test", ctx.out());
|
||||||
return std::copy_n(test.data(), test.size(), ctx.out());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
@ -653,8 +644,7 @@ template <> struct formatter<convertible_to_pointer_formattable> {
|
|||||||
|
|
||||||
auto format(convertible_to_pointer_formattable, format_context& ctx) const
|
auto format(convertible_to_pointer_formattable, format_context& ctx) const
|
||||||
-> decltype(ctx.out()) {
|
-> decltype(ctx.out()) {
|
||||||
auto test = string_view("test");
|
return copy("test", ctx.out());
|
||||||
return std::copy_n(test.data(), test.size(), ctx.out());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
@ -732,7 +722,7 @@ template <> struct formatter<convertible_to_int> {
|
|||||||
}
|
}
|
||||||
auto format(convertible_to_int, format_context& ctx) const
|
auto format(convertible_to_int, format_context& ctx) const
|
||||||
-> decltype(ctx.out()) {
|
-> decltype(ctx.out()) {
|
||||||
return std::copy_n("foo", 3, ctx.out());
|
return copy("foo", ctx.out());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -742,7 +732,7 @@ template <> struct formatter<convertible_to_cstring> {
|
|||||||
}
|
}
|
||||||
auto format(convertible_to_cstring, format_context& ctx) const
|
auto format(convertible_to_cstring, format_context& ctx) const
|
||||||
-> decltype(ctx.out()) {
|
-> decltype(ctx.out()) {
|
||||||
return std::copy_n("bar", 3, ctx.out());
|
return copy("bar", ctx.out());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
@ -853,8 +843,7 @@ template <> struct formatter<its_a_trap> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto format(its_a_trap, format_context& ctx) const -> decltype(ctx.out()) {
|
auto format(its_a_trap, format_context& ctx) const -> decltype(ctx.out()) {
|
||||||
auto s = string_view("42");
|
return copy("42", ctx.out());
|
||||||
return std::copy(s.begin(), s.end(), ctx.out());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
Loading…
Reference in New Issue
Block a user