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 {
|
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.
|
// Extracts a reference to the container from back_insert_iterator.
|
||||||
template <typename Container>
|
template <typename Container>
|
||||||
inline Container& get_container(std::back_insert_iterator<Container> it) {
|
inline Container& get_container(back_insert_iterator<Container> it) {
|
||||||
using bi_iterator = std::back_insert_iterator<Container>;
|
using bi_iterator = back_insert_iterator<Container>;
|
||||||
struct accessor : bi_iterator {
|
struct accessor : bi_iterator {
|
||||||
accessor(bi_iterator iter) : bi_iterator(iter) {}
|
accessor(bi_iterator iter) : bi_iterator(iter) {}
|
||||||
using bi_iterator::container;
|
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(); }
|
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.
|
// A buffer that writes to a container with the contiguous storage.
|
||||||
template <typename Container>
|
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>,
|
class iterator_buffer<std::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>>
|
||||||
@ -824,11 +906,12 @@ class iterator_buffer<std::back_insert_iterator<Container>,
|
|||||||
explicit iterator_buffer(Container& c)
|
explicit iterator_buffer(Container& c)
|
||||||
: buffer<typename Container::value_type>(c.size()), container_(c) {}
|
: buffer<typename Container::value_type>(c.size()), container_(c) {}
|
||||||
explicit iterator_buffer(std::back_insert_iterator<Container> out, size_t = 0)
|
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() {
|
std::back_insert_iterator<Container> out() {
|
||||||
return std::back_inserter(container_);
|
return std::back_inserter(container_);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
// A buffer that counts the number of code units written discarding the output.
|
// A buffer that counts the number of code units written discarding the output.
|
||||||
template <typename T = char> class counting_buffer final : public buffer<T> {
|
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.
|
// An output iterator that appends to the buffer.
|
||||||
// It is used to reduce symbol sizes for the common case.
|
// It is used to reduce symbol sizes for the common case.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class buffer_appender : public std::back_insert_iterator<buffer<T>> {
|
class buffer_appender : public back_insert_iterator<buffer<T>> {
|
||||||
using base = std::back_insert_iterator<buffer<T>>;
|
using base = back_insert_iterator<buffer<T>>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit buffer_appender(buffer<T>& buf) : base(buf) {}
|
explicit buffer_appender(buffer<T>& buf) : base(buf) {}
|
||||||
@ -1385,13 +1468,13 @@ struct is_output_iterator<
|
|||||||
template <typename OutputIt>
|
template <typename OutputIt>
|
||||||
struct is_back_insert_iterator : std::false_type {};
|
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 {};
|
||||||
|
|
||||||
template <typename OutputIt>
|
template <typename OutputIt>
|
||||||
struct is_contiguous_back_insert_iterator : std::false_type {};
|
struct is_contiguous_back_insert_iterator : std::false_type {};
|
||||||
template <typename Container>
|
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> {};
|
: is_contiguous<Container> {};
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
struct is_contiguous_back_insert_iterator<buffer_appender<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")))
|
__attribute__((no_sanitize("undefined")))
|
||||||
#endif
|
#endif
|
||||||
inline checked_ptr<typename Container::value_type>
|
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);
|
Container& c = get_container(it);
|
||||||
size_t size = c.size();
|
size_t size = c.size();
|
||||||
c.resize(size + n);
|
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)>
|
template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
|
||||||
inline std::back_insert_iterator<Container> base_iterator(
|
inline back_insert_iterator<Container> base_iterator(
|
||||||
std::back_insert_iterator<Container>& it,
|
back_insert_iterator<Container>& it,
|
||||||
checked_ptr<typename Container::value_type>) {
|
checked_ptr<typename Container::value_type>) {
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,27 +31,27 @@ template dragonbox::decimal_fp<double> dragonbox::to_decimal(double x)
|
|||||||
|
|
||||||
// DEPRECATED! This function exists for ABI compatibility.
|
// DEPRECATED! This function exists for ABI compatibility.
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
typename basic_format_context<std::back_insert_iterator<buffer<Char>>,
|
typename basic_format_context<back_insert_iterator<buffer<Char>>,
|
||||||
Char>::iterator
|
Char>::iterator
|
||||||
vformat_to(buffer<Char>& buf, basic_string_view<Char> format_str,
|
vformat_to(buffer<Char>& buf, basic_string_view<Char> format_str,
|
||||||
basic_format_args<basic_format_context<
|
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>>>
|
type_identity_t<Char>>>
|
||||||
args) {
|
args) {
|
||||||
using iterator = std::back_insert_iterator<buffer<char>>;
|
using iterator = back_insert_iterator<buffer<char>>;
|
||||||
using context = basic_format_context<
|
using context =
|
||||||
std::back_insert_iterator<buffer<type_identity_t<Char>>>,
|
basic_format_context<back_insert_iterator<buffer<type_identity_t<Char>>>,
|
||||||
type_identity_t<Char>>;
|
type_identity_t<Char>>;
|
||||||
auto out = iterator(buf);
|
auto out = iterator(buf);
|
||||||
format_handler<iterator, Char, context> h(out, format_str, args, {});
|
format_handler<iterator, Char, context> h(out, format_str, args, {});
|
||||||
parse_format_string<false>(format_str, h);
|
parse_format_string<false>(format_str, h);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
template basic_format_context<std::back_insert_iterator<buffer<char>>,
|
template basic_format_context<back_insert_iterator<buffer<char>>,
|
||||||
char>::iterator
|
char>::iterator
|
||||||
vformat_to(buffer<char>&, string_view,
|
vformat_to(buffer<char>&, string_view,
|
||||||
basic_format_args<basic_format_context<
|
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>>>);
|
type_identity_t<char>>>);
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
|
|||||||
@ -292,7 +292,7 @@ VISIT_TYPE(unsigned long, unsigned long long);
|
|||||||
{ \
|
{ \
|
||||||
testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \
|
testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \
|
||||||
EXPECT_CALL(visitor, visit(expected)); \
|
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( \
|
fmt::visit_format_arg( \
|
||||||
visitor, make_arg<fmt::basic_format_context<iterator, Char>>(value)); \
|
visitor, make_arg<fmt::basic_format_context<iterator, Char>>(value)); \
|
||||||
}
|
}
|
||||||
|
|||||||
@ -175,6 +175,8 @@ TEST(IteratorTest, IsOutputIterator) {
|
|||||||
EXPECT_TRUE(
|
EXPECT_TRUE(
|
||||||
(fmt::detail::is_output_iterator<std::back_insert_iterator<std::string>,
|
(fmt::detail::is_output_iterator<std::back_insert_iterator<std::string>,
|
||||||
char>::value));
|
char>::value));
|
||||||
|
EXPECT_TRUE((fmt::detail::is_output_iterator<
|
||||||
|
fmt::detail::back_insert_iterator<std::string>, char>::value));
|
||||||
EXPECT_TRUE(
|
EXPECT_TRUE(
|
||||||
(fmt::detail::is_output_iterator<std::string::iterator, char>::value));
|
(fmt::detail::is_output_iterator<std::string::iterator, char>::value));
|
||||||
EXPECT_FALSE((fmt::detail::is_output_iterator<std::string::const_iterator,
|
EXPECT_FALSE((fmt::detail::is_output_iterator<std::string::const_iterator,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user