mirror of
https://github.com/fmtlib/fmt.git
synced 2025-03-22 01:21:13 +00:00
Improve handling of back_insert_iterator that writes into a buffer
This commit is contained in:
parent
6a192f8d34
commit
33e7ed1eb5
@ -474,8 +474,13 @@ FMT_CONSTEXPR auto compare(const Char* s1, const Char* s2, std::size_t n)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace detect {
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
template <typename It, typename Enable = std::true_type>
|
template <typename It, typename Enable = std::true_type>
|
||||||
struct is_back_insert_iterator : std::false_type {};
|
struct is_back_insert_iterator : std::false_type {};
|
||||||
|
|
||||||
template <typename It>
|
template <typename It>
|
||||||
struct is_back_insert_iterator<
|
struct is_back_insert_iterator<
|
||||||
It,
|
It,
|
||||||
@ -483,6 +488,10 @@ struct is_back_insert_iterator<
|
|||||||
decltype(back_inserter(std::declval<typename It::container_type&>())),
|
decltype(back_inserter(std::declval<typename It::container_type&>())),
|
||||||
It>::value>> : std::true_type {};
|
It>::value>> : std::true_type {};
|
||||||
|
|
||||||
|
} // namespace detect
|
||||||
|
|
||||||
|
using detect::is_back_insert_iterator;
|
||||||
|
|
||||||
// Extracts a reference to the container from *insert_iterator.
|
// Extracts a reference to the container from *insert_iterator.
|
||||||
template <typename OutputIt>
|
template <typename OutputIt>
|
||||||
inline auto get_container(OutputIt it) -> typename OutputIt::container_type& {
|
inline auto get_container(OutputIt it) -> typename OutputIt::container_type& {
|
||||||
@ -1158,6 +1167,7 @@ template <typename T> class basic_appender {
|
|||||||
using difference_type = ptrdiff_t;
|
using difference_type = ptrdiff_t;
|
||||||
using pointer = T*;
|
using pointer = T*;
|
||||||
using reference = T&;
|
using reference = T&;
|
||||||
|
using container_type = detail::buffer<T>;
|
||||||
FMT_UNCHECKED_ITERATOR(basic_appender);
|
FMT_UNCHECKED_ITERATOR(basic_appender);
|
||||||
|
|
||||||
FMT_CONSTEXPR basic_appender(detail::buffer<T>& buf) : buffer_(&buf) {}
|
FMT_CONSTEXPR basic_appender(detail::buffer<T>& buf) : buffer_(&buf) {}
|
||||||
@ -1174,6 +1184,10 @@ template <typename T> class basic_appender {
|
|||||||
using appender = basic_appender<char>;
|
using appender = basic_appender<char>;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
namespace detect {
|
||||||
|
template <typename T>
|
||||||
|
struct is_back_insert_iterator<basic_appender<T>> : std::true_type {};
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T, typename Enable = void>
|
template <typename T, typename Enable = void>
|
||||||
struct locking : std::true_type {};
|
struct locking : std::true_type {};
|
||||||
@ -1239,12 +1253,25 @@ constexpr auto has_const_formatter() -> bool {
|
|||||||
return has_const_formatter_impl<Context>(static_cast<T*>(nullptr));
|
return has_const_formatter_impl<Context>(static_cast<T*>(nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename It, typename Enable = std::true_type>
|
||||||
|
struct is_buffer_appender : std::false_type {};
|
||||||
|
template <typename It>
|
||||||
|
struct is_buffer_appender<
|
||||||
|
It, bool_constant<
|
||||||
|
is_back_insert_iterator<It>::value &&
|
||||||
|
std::is_base_of<buffer<typename It::container_type::value_type>,
|
||||||
|
typename It::container_type>::value>>
|
||||||
|
: std::true_type {};
|
||||||
|
|
||||||
// Maps an output iterator to a buffer.
|
// Maps an output iterator to a buffer.
|
||||||
template <typename T, typename OutputIt>
|
template <typename T, typename OutputIt,
|
||||||
|
FMT_ENABLE_IF(!is_buffer_appender<OutputIt>::value)>
|
||||||
auto get_buffer(OutputIt out) -> iterator_buffer<OutputIt, T> {
|
auto get_buffer(OutputIt out) -> iterator_buffer<OutputIt, T> {
|
||||||
return iterator_buffer<OutputIt, T>(out);
|
return iterator_buffer<OutputIt, T>(out);
|
||||||
}
|
}
|
||||||
template <typename T> auto get_buffer(basic_appender<T> out) -> buffer<T>& {
|
template <typename T, typename OutputIt,
|
||||||
|
FMT_ENABLE_IF(is_buffer_appender<OutputIt>::value)>
|
||||||
|
auto get_buffer(OutputIt out) -> buffer<T>& {
|
||||||
return get_container(out);
|
return get_container(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ TEST(base_test, is_back_insert_iterator) {
|
|||||||
|
|
||||||
TEST(base_test, buffer_appender) {
|
TEST(base_test, buffer_appender) {
|
||||||
#ifdef __cpp_lib_ranges
|
#ifdef __cpp_lib_ranges
|
||||||
static_assert(std::output_iterator<fmt::appender, char>);
|
EXPECT_TRUE((std::output_iterator<fmt::appender, char>));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,6 +268,16 @@ TEST(buffer_test, append_allocates_enough_storage) {
|
|||||||
buffer.append(test, test + 9);
|
buffer.append(test, test + 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(base_test, get_buffer) {
|
||||||
|
mock_buffer<char> buffer;
|
||||||
|
void* buffer_ptr = &buffer;
|
||||||
|
auto&& appender_result = fmt::detail::get_buffer<char>(fmt::appender(buffer));
|
||||||
|
EXPECT_EQ(&appender_result, buffer_ptr);
|
||||||
|
auto&& back_inserter_result =
|
||||||
|
fmt::detail::get_buffer<char>(std::back_inserter(buffer));
|
||||||
|
EXPECT_EQ(&back_inserter_result, buffer_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
struct custom_context {
|
struct custom_context {
|
||||||
using char_type = char;
|
using char_type = char;
|
||||||
using parse_context_type = fmt::format_parse_context;
|
using parse_context_type = fmt::format_parse_context;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user