add custom back_insert_iterator with constexpr member functions
This commit is contained in:
parent
701ed6c874
commit
8a2de0f85d
@ -645,10 +645,17 @@ struct is_contiguous<std::basic_string<Char>> : std::true_type {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
#ifdef FMT_USE_CUSTOM_BACK_INSERT_ITERATOR
|
||||
template <typename Container> class back_insert_iterator;
|
||||
#else
|
||||
template <typename Container>
|
||||
using back_insert_iterator = std::back_insert_iterator<Container>;
|
||||
#endif
|
||||
|
||||
// Extracts a reference to the container from back_insert_iterator.
|
||||
template <typename Container>
|
||||
inline Container& get_container(std::back_insert_iterator<Container> it) {
|
||||
using bi_iterator = std::back_insert_iterator<Container>;
|
||||
inline Container& get_container(back_insert_iterator<Container> it) {
|
||||
using bi_iterator = back_insert_iterator<Container>;
|
||||
struct accessor : bi_iterator {
|
||||
accessor(bi_iterator iter) : bi_iterator(iter) {}
|
||||
using bi_iterator::container;
|
||||
@ -805,8 +812,83 @@ template <typename T> class iterator_buffer<T*, T> final : public buffer<T> {
|
||||
T* out() { return &*this->end(); }
|
||||
};
|
||||
|
||||
#ifdef FMT_USE_CUSTOM_BACK_INSERT_ITERATOR
|
||||
template <class Container> class back_insert_iterator {
|
||||
protected:
|
||||
Container* container;
|
||||
|
||||
public:
|
||||
using iterator_category = std::output_iterator_tag;
|
||||
using value_type = void;
|
||||
using difference_type = void;
|
||||
using pointer = void;
|
||||
using reference = void;
|
||||
|
||||
using container_type = Container;
|
||||
using container_value_type = typename Container::value_type;
|
||||
|
||||
constexpr explicit back_insert_iterator(Container& container)
|
||||
: container(std::addressof(container)) {}
|
||||
|
||||
constexpr explicit back_insert_iterator(
|
||||
const std::back_insert_iterator<Container>& bi_iterator) {
|
||||
using iterator = std::back_insert_iterator<Container>;
|
||||
struct accessor : iterator {
|
||||
explicit accessor(iterator iter) : iterator(iter) {}
|
||||
using iterator::container;
|
||||
};
|
||||
container = accessor(bi_iterator).container;
|
||||
}
|
||||
|
||||
constexpr back_insert_iterator& operator=(const container_value_type& value) {
|
||||
container->push_back(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr back_insert_iterator& operator=(container_value_type&& value) {
|
||||
container->push_back(std::move(value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr back_insert_iterator& operator*() { return *this; }
|
||||
constexpr back_insert_iterator& operator++() { return *this; }
|
||||
constexpr back_insert_iterator operator++(int) { return *this; }
|
||||
};
|
||||
|
||||
template <class Container>
|
||||
constexpr back_insert_iterator<Container> back_inserter(Container& container) {
|
||||
return back_insert_iterator<Container>(container);
|
||||
}
|
||||
#endif
|
||||
|
||||
// A buffer that writes to a container with the contiguous storage.
|
||||
template <typename Container>
|
||||
class iterator_buffer<back_insert_iterator<Container>,
|
||||
enable_if_t<is_contiguous<Container>::value,
|
||||
typename Container::value_type>>
|
||||
final : public buffer<typename Container::value_type> {
|
||||
private:
|
||||
Container& container_;
|
||||
|
||||
protected:
|
||||
void grow(size_t capacity) final FMT_OVERRIDE {
|
||||
container_.resize(capacity);
|
||||
this->set(&container_[0], capacity);
|
||||
}
|
||||
|
||||
public:
|
||||
explicit iterator_buffer(Container& c)
|
||||
: buffer<typename Container::value_type>(c.size()), container_(c) {}
|
||||
explicit iterator_buffer(back_insert_iterator<Container> out, size_t = 0)
|
||||
: iterator_buffer(get_container(out)) {}
|
||||
back_insert_iterator<Container> out() {
|
||||
return back_inserter(container_);
|
||||
}
|
||||
};
|
||||
|
||||
#if FMT_USE_CUSTOM_BACK_INSERT_ITERATOR
|
||||
// Explicit instantiation for std::back_insert_iterator
|
||||
template <typename Container>
|
||||
class iterator_buffer<std::back_insert_iterator<Container>,
|
||||
enable_if_t<is_contiguous<Container>::value,
|
||||
typename Container::value_type>>
|
||||
@ -824,11 +906,12 @@ class iterator_buffer<std::back_insert_iterator<Container>,
|
||||
explicit iterator_buffer(Container& c)
|
||||
: buffer<typename Container::value_type>(c.size()), container_(c) {}
|
||||
explicit iterator_buffer(std::back_insert_iterator<Container> out, size_t = 0)
|
||||
: iterator_buffer(get_container(out)) {}
|
||||
: iterator_buffer(get_container(back_insert_iterator<Container>{out})) {}
|
||||
std::back_insert_iterator<Container> out() {
|
||||
return std::back_inserter(container_);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// A buffer that counts the number of code units written discarding the output.
|
||||
template <typename T = char> class counting_buffer final : public buffer<T> {
|
||||
@ -853,8 +936,8 @@ template <typename T = char> class counting_buffer final : public buffer<T> {
|
||||
// An output iterator that appends to the buffer.
|
||||
// It is used to reduce symbol sizes for the common case.
|
||||
template <typename T>
|
||||
class buffer_appender : public std::back_insert_iterator<buffer<T>> {
|
||||
using base = std::back_insert_iterator<buffer<T>>;
|
||||
class buffer_appender : public back_insert_iterator<buffer<T>> {
|
||||
using base = back_insert_iterator<buffer<T>>;
|
||||
|
||||
public:
|
||||
explicit buffer_appender(buffer<T>& buf) : base(buf) {}
|
||||
@ -1385,13 +1468,13 @@ struct is_output_iterator<
|
||||
template <typename OutputIt>
|
||||
struct is_back_insert_iterator : std::false_type {};
|
||||
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 {};
|
||||
|
||||
template <typename OutputIt>
|
||||
struct is_contiguous_back_insert_iterator : std::false_type {};
|
||||
template <typename Container>
|
||||
struct is_contiguous_back_insert_iterator<std::back_insert_iterator<Container>>
|
||||
struct is_contiguous_back_insert_iterator<back_insert_iterator<Container>>
|
||||
: is_contiguous<Container> {};
|
||||
template <typename Char>
|
||||
struct is_contiguous_back_insert_iterator<buffer_appender<Char>>
|
||||
|
||||
@ -376,7 +376,7 @@ template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
|
||||
__attribute__((no_sanitize("undefined")))
|
||||
#endif
|
||||
inline checked_ptr<typename Container::value_type>
|
||||
reserve(std::back_insert_iterator<Container> it, size_t n) {
|
||||
reserve(back_insert_iterator<Container> it, size_t n) {
|
||||
Container& c = get_container(it);
|
||||
size_t size = c.size();
|
||||
c.resize(size + n);
|
||||
@ -407,8 +407,8 @@ template <typename T> T* to_pointer(buffer_appender<T> it, size_t n) {
|
||||
}
|
||||
|
||||
template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
|
||||
inline std::back_insert_iterator<Container> base_iterator(
|
||||
std::back_insert_iterator<Container>& it,
|
||||
inline back_insert_iterator<Container> base_iterator(
|
||||
back_insert_iterator<Container>& it,
|
||||
checked_ptr<typename Container::value_type>) {
|
||||
return it;
|
||||
}
|
||||
|
||||
@ -31,27 +31,27 @@ template dragonbox::decimal_fp<double> dragonbox::to_decimal(double x)
|
||||
|
||||
// DEPRECATED! This function exists for ABI compatibility.
|
||||
template <typename Char>
|
||||
typename basic_format_context<std::back_insert_iterator<buffer<Char>>,
|
||||
typename basic_format_context<back_insert_iterator<buffer<Char>>,
|
||||
Char>::iterator
|
||||
vformat_to(buffer<Char>& buf, basic_string_view<Char> format_str,
|
||||
basic_format_args<basic_format_context<
|
||||
std::back_insert_iterator<buffer<type_identity_t<Char>>>,
|
||||
back_insert_iterator<buffer<type_identity_t<Char>>>,
|
||||
type_identity_t<Char>>>
|
||||
args) {
|
||||
using iterator = std::back_insert_iterator<buffer<char>>;
|
||||
using context = basic_format_context<
|
||||
std::back_insert_iterator<buffer<type_identity_t<Char>>>,
|
||||
type_identity_t<Char>>;
|
||||
using iterator = back_insert_iterator<buffer<char>>;
|
||||
using context =
|
||||
basic_format_context<back_insert_iterator<buffer<type_identity_t<Char>>>,
|
||||
type_identity_t<Char>>;
|
||||
auto out = iterator(buf);
|
||||
format_handler<iterator, Char, context> h(out, format_str, args, {});
|
||||
parse_format_string<false>(format_str, h);
|
||||
return out;
|
||||
}
|
||||
template basic_format_context<std::back_insert_iterator<buffer<char>>,
|
||||
template basic_format_context<back_insert_iterator<buffer<char>>,
|
||||
char>::iterator
|
||||
vformat_to(buffer<char>&, string_view,
|
||||
basic_format_args<basic_format_context<
|
||||
std::back_insert_iterator<buffer<type_identity_t<char>>>,
|
||||
back_insert_iterator<buffer<type_identity_t<char>>>,
|
||||
type_identity_t<char>>>);
|
||||
} // namespace detail
|
||||
|
||||
|
||||
@ -292,7 +292,7 @@ VISIT_TYPE(unsigned long, unsigned long long);
|
||||
{ \
|
||||
testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \
|
||||
EXPECT_CALL(visitor, visit(expected)); \
|
||||
using iterator = std::back_insert_iterator<buffer<Char>>; \
|
||||
using iterator = fmt::detail::back_insert_iterator<buffer<Char>>; \
|
||||
fmt::visit_format_arg( \
|
||||
visitor, make_arg<fmt::basic_format_context<iterator, Char>>(value)); \
|
||||
}
|
||||
|
||||
@ -175,6 +175,8 @@ TEST(IteratorTest, IsOutputIterator) {
|
||||
EXPECT_TRUE(
|
||||
(fmt::detail::is_output_iterator<std::back_insert_iterator<std::string>,
|
||||
char>::value));
|
||||
EXPECT_TRUE((fmt::detail::is_output_iterator<
|
||||
fmt::detail::back_insert_iterator<std::string>, char>::value));
|
||||
EXPECT_TRUE(
|
||||
(fmt::detail::is_output_iterator<std::string::iterator, char>::value));
|
||||
EXPECT_FALSE((fmt::detail::is_output_iterator<std::string::const_iterator,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user