Remove dependency on back_insert_iterator

This commit is contained in:
Victor Zverovich
2024-01-03 05:59:48 -08:00
parent c9d233c0a4
commit f2c55f6bb8
3 changed files with 65 additions and 32 deletions

View File

@ -309,6 +309,36 @@ struct monostate {
constexpr monostate() {} constexpr monostate() {}
}; };
// An implementation of back_insert_iterator to avoid dependency on <iterator>.
template <typename Container> class back_insert_iterator {
private:
Container* container_;
friend auto get_container(back_insert_iterator it) -> Container& {
return *it.container_;
}
public:
using difference_type = ptrdiff_t;
FMT_UNCHECKED_ITERATOR(back_insert_iterator);
explicit back_insert_iterator(Container& c) : container_(&c) {}
auto operator=(const typename Container::value_type& value)
-> back_insert_iterator& {
container_->push_back(value);
return *this;
}
auto operator*() -> back_insert_iterator& { return *this; }
auto operator++() -> back_insert_iterator& { return *this; }
auto operator++(int) -> back_insert_iterator { return *this; }
};
template <typename Container>
auto back_inserter(Container& c) -> back_insert_iterator<Container> {
return {c};
}
// An enable_if helper to be used in template parameters which results in much // An enable_if helper to be used in template parameters which results in much
// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed // shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed
// to workaround a bug in MSVC 2019 (see #1140 and #1186). // to workaround a bug in MSVC 2019 (see #1140 and #1186).
@ -780,18 +810,6 @@ class compile_parse_context : public basic_format_parse_context<Char> {
} }
}; };
// Extracts a reference to the container from back_insert_iterator.
template <typename Container>
inline auto get_container(std::back_insert_iterator<Container> it)
-> Container& {
using base = std::back_insert_iterator<Container>;
struct accessor : base {
accessor(base b) : base(b) {}
using base::container;
};
return *accessor(it).container;
}
template <typename Char, typename InputIt, typename OutputIt> template <typename Char, typename InputIt, typename OutputIt>
FMT_CONSTEXPR auto copy_str(InputIt begin, InputIt end, OutputIt out) FMT_CONSTEXPR auto copy_str(InputIt begin, InputIt end, OutputIt out)
-> OutputIt { -> OutputIt {
@ -1012,7 +1030,7 @@ template <typename T> class iterator_buffer<T*, T> final : public buffer<T> {
// A buffer that writes to a container with the contiguous storage. // A buffer that writes to a container with the contiguous storage.
template <typename Container> template <typename Container>
class iterator_buffer<std::back_insert_iterator<Container>, class iterator_buffer<back_insert_iterator<Container>,
enable_if_t<is_contiguous<Container>::value, enable_if_t<is_contiguous<Container>::value,
typename Container::value_type>> typename Container::value_type>>
final : public buffer<typename Container::value_type> { final : public buffer<typename Container::value_type> {
@ -1029,11 +1047,11 @@ class iterator_buffer<std::back_insert_iterator<Container>,
public: public:
explicit iterator_buffer(Container& c) explicit iterator_buffer(Container& c)
: buffer<value_type>(grow, c.size()), container_(c) {} : buffer<value_type>(grow, c.size()), container_(c) {}
explicit iterator_buffer(std::back_insert_iterator<Container> out, size_t = 0) explicit iterator_buffer(back_insert_iterator<Container> out, size_t = 0)
: iterator_buffer(get_container(out)) {} : iterator_buffer(get_container(out)) {}
auto out() -> std::back_insert_iterator<Container> { auto out() -> back_insert_iterator<Container> {
return std::back_inserter(container_); return fmt::back_inserter(container_);
} }
}; };
@ -1097,8 +1115,8 @@ template <typename T, typename Context>
using has_formatter = using has_formatter =
std::is_constructible<typename Context::template formatter_type<T>>; std::is_constructible<typename Context::template formatter_type<T>>;
// An output iterator that appends to a buffer. // An output iterator that appends to a buffer. It is used instead of
// It is used to reduce symbol sizes for the common case. // back_insert_iterator to reduce symbol sizes for the common case.
class appender { class appender {
private: private:
detail::buffer<char>* buffer_; detail::buffer<char>* buffer_;
@ -1117,7 +1135,7 @@ class appender {
buffer_->push_back(c); buffer_->push_back(c);
return *this; return *this;
} }
auto operator*() -> appender& {return *this;} auto operator*() -> appender& { return *this; }
auto operator++() -> appender& { return *this; } auto operator++() -> appender& { return *this; }
auto operator++(int) -> appender { return *this; } auto operator++(int) -> appender { return *this; }
}; };
@ -1142,7 +1160,7 @@ constexpr auto has_const_formatter() -> bool {
template <typename T> template <typename T>
using buffer_appender = conditional_t<std::is_same<T, char>::value, appender, using buffer_appender = conditional_t<std::is_same<T, char>::value, appender,
std::back_insert_iterator<buffer<T>>>; back_insert_iterator<buffer<T>>>;
// Maps an output iterator to a buffer. // Maps an output iterator to a buffer.
template <typename T, typename OutputIt> template <typename T, typename OutputIt>
@ -1151,7 +1169,7 @@ auto get_buffer(OutputIt out) -> iterator_buffer<OutputIt, T> {
} }
template <typename T, typename Buf, template <typename T, typename Buf,
FMT_ENABLE_IF(std::is_base_of<buffer<char>, Buf>::value)> FMT_ENABLE_IF(std::is_base_of<buffer<char>, Buf>::value)>
auto get_buffer(std::back_insert_iterator<Buf> out) -> buffer<char>& { auto get_buffer(back_insert_iterator<Buf> out) -> buffer<char>& {
return get_container(out); return get_container(out);
} }
@ -1531,9 +1549,8 @@ auto copy_str(InputIt begin, InputIt end, appender out) -> appender {
return out; return out;
} }
template <typename Char, typename InputIt> template <typename Char, typename InputIt>
auto copy_str(InputIt begin, InputIt end, auto copy_str(InputIt begin, InputIt end, back_insert_iterator<std::string> out)
std::back_insert_iterator<std::string> out) -> back_insert_iterator<std::string> {
-> std::back_insert_iterator<std::string> {
get_container(out).append(begin, end); get_container(out).append(begin, end);
return out; return out;
} }
@ -1567,7 +1584,7 @@ struct is_output_iterator<
template <typename It> struct is_back_insert_iterator : std::false_type {}; template <typename It> struct is_back_insert_iterator : std::false_type {};
template <typename Container> template <typename Container>
struct is_back_insert_iterator<std::back_insert_iterator<Container>> struct is_back_insert_iterator<back_insert_iterator<Container>>
: std::true_type {}; : std::true_type {};
// A type-erased reference to an std::locale to avoid a heavy <locale> include. // A type-erased reference to an std::locale to avoid a heavy <locale> include.
@ -2726,7 +2743,7 @@ void check_format_string(S format_str) {
template <typename Char = char> struct vformat_args { template <typename Char = char> struct vformat_args {
using type = basic_format_args< using type = basic_format_args<
basic_format_context<std::back_insert_iterator<buffer<Char>>, Char>>; basic_format_context<back_insert_iterator<buffer<Char>>, Char>>;
}; };
template <> struct vformat_args<char> { template <> struct vformat_args<char> {
using type = format_args; using type = format_args;
@ -2869,7 +2886,7 @@ auto vformat_to(OutputIt out, string_view fmt, format_args args) -> OutputIt {
**Example**:: **Example**::
auto out = std::vector<char>(); auto out = std::vector<char>();
fmt::format_to(std::back_inserter(out), "{}", 42); fmt::format_to(fmt::back_inserter(out), "{}", 42);
\endrst \endrst
*/ */
template <typename OutputIt, typename... T, template <typename OutputIt, typename... T,

View File

@ -263,12 +263,16 @@ FMT_END_NAMESPACE
#endif #endif
namespace std { namespace std {
template <> template <> struct iterator_traits<fmt::appender> {
struct iterator_traits<fmt::appender> {
using value_type = void; using value_type = void;
using iterator_category = std::output_iterator_tag; using iterator_category = std::output_iterator_tag;
}; };
} template <typename Container>
struct iterator_traits<fmt::back_insert_iterator<Container>> {
using value_type = void;
using iterator_category = std::output_iterator_tag;
};
} // namespace std
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
namespace detail { namespace detail {
@ -500,6 +504,18 @@ FMT_INLINE void assume(bool condition) {
#endif #endif
} }
// Extracts a reference to the container from back_insert_iterator.
template <typename Container>
inline auto get_container(std::back_insert_iterator<Container> it)
-> Container& {
using base = std::back_insert_iterator<Container>;
struct accessor : base {
accessor(base b) : base(b) {}
using base::container;
};
return *accessor(it).container;
}
// An approximation of iterator_t for pre-C++20 systems. // An approximation of iterator_t for pre-C++20 systems.
template <typename T> template <typename T>
using iterator_t = decltype(std::begin(std::declval<T&>())); using iterator_t = decltype(std::begin(std::declval<T&>()));

View File

@ -23,7 +23,7 @@ namespace detail {
template <typename T> template <typename T>
using is_exotic_char = bool_constant<!std::is_same<T, char>::value>; using is_exotic_char = bool_constant<!std::is_same<T, char>::value>;
inline auto write_loc(std::back_insert_iterator<detail::buffer<wchar_t>> out, inline auto write_loc(back_insert_iterator<detail::buffer<wchar_t>> out,
loc_value value, const format_specs<wchar_t>& specs, loc_value value, const format_specs<wchar_t>& specs,
locale_ref loc) -> bool { locale_ref loc) -> bool {
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR #ifndef FMT_STATIC_THOUSANDS_SEPARATOR