From e3b4c22ec9b215bba32cac922eb4503642004f16 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Tue, 20 Oct 2020 13:35:31 -0700 Subject: [PATCH] Simplify is_output_iterator --- include/fmt/color.h | 4 ++-- include/fmt/compile.h | 9 +++++---- include/fmt/core.h | 39 ++++++++++++++++----------------------- include/fmt/locale.h | 15 +++++++-------- test/format-test.cc | 37 +++++++++++++++++-------------------- 5 files changed, 47 insertions(+), 57 deletions(-) diff --git a/include/fmt/color.h b/include/fmt/color.h index a2e917df..78910589 100644 --- a/include/fmt/color.h +++ b/include/fmt/color.h @@ -567,7 +567,7 @@ inline std::basic_string format(const text_style& ts, const S& format_str, Formats a string with the given text_style and writes the output to ``out``. */ template ::value)> + FMT_ENABLE_IF(detail::is_output_iterator::value)> OutputIt vformat_to( OutputIt out, const text_style& ts, basic_string_view format_str, basic_format_args>> args) { @@ -589,7 +589,7 @@ OutputIt vformat_to( \endrst */ template ::value&& + FMT_ENABLE_IF(detail::is_output_iterator>::value&& detail::is_string::value)> inline OutputIt format_to(OutputIt out, const text_style& ts, const S& format_str, Args&&... args) { diff --git a/include/fmt/compile.h b/include/fmt/compile.h index 13406ce2..7db610d9 100644 --- a/include/fmt/compile.h +++ b/include/fmt/compile.h @@ -667,10 +667,11 @@ OutputIt format_to(OutputIt out, const S&, const Args&... args) { return format_to(out, compiled, args...); } -template < - typename OutputIt, typename CompiledFormat, typename... Args, - FMT_ENABLE_IF(detail::is_output_iterator::value&& std::is_base_of< - detail::basic_compiled_format, CompiledFormat>::value)> +template ::value&& + std::is_base_of::value)> format_to_n_result format_to_n(OutputIt out, size_t n, const CompiledFormat& cf, const Args&... args) { diff --git a/include/fmt/core.h b/include/fmt/core.h index ceb2a27c..6862fc4b 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -801,8 +801,8 @@ template class iterator_buffer final : public buffer { template class iterator_buffer, enable_if_t::value, - typename Container::value_type>> final - : public buffer { + typename Container::value_type>> + final : public buffer { private: Container& container_; @@ -1371,23 +1371,15 @@ struct iterator_category> { using type = typename It::iterator_category; }; -// Detect if *any* given type models the OutputIterator concept. -template class is_output_iterator { - // Check for mutability because all iterator categories derived from - // std::input_iterator_tag *may* also meet the requirements of an - // OutputIterator, thereby falling into the category of 'mutable iterators' - // [iterator.requirements.general] clause 4. The compiler reveals this - // property only at the point of *actually dereferencing* the iterator! - template - static decltype(*(std::declval())) test(std::input_iterator_tag); - template static char& test(std::output_iterator_tag); - template static const char& test(...); +template +struct is_output_iterator : std::false_type {}; - using type = decltype(test(typename iterator_category::type{})); - - public: - enum { value = !std::is_const>::value }; -}; +template +struct is_output_iterator< + It, T, + void_t::type, + decltype(*std::declval() = std::declval())>> + : std::true_type {}; template struct is_back_insert_iterator : std::false_type {}; @@ -1983,7 +1975,7 @@ inline void vprint_mojibake(std::FILE*, string_view, format_args) {} // GCC 8 and earlier cannot handle std::back_insert_iterator with // vformat_to(...) overload, so SFINAE on iterator type instead. template , - FMT_ENABLE_IF(detail::is_output_iterator::value)> + FMT_ENABLE_IF(detail::is_output_iterator::value)> OutputIt vformat_to( OutputIt out, const S& format_str, basic_format_args>> args) { @@ -2004,7 +1996,8 @@ OutputIt vformat_to( \endrst */ template ::value&& + typename Char = char_t, + FMT_ENABLE_IF(detail::is_output_iterator::value&& detail::is_string::value)> inline OutputIt format_to(OutputIt out, const S& format_str, Args&&... args) { const auto& vargs = fmt::make_args_checked(format_str, args...); @@ -2019,7 +2012,7 @@ template struct format_to_n_result { }; template ::value)> + FMT_ENABLE_IF(detail::is_output_iterator::value)> inline format_to_n_result vformat_to_n( OutputIt out, size_t n, basic_string_view format_str, basic_format_args>> args) { @@ -2037,8 +2030,8 @@ inline format_to_n_result vformat_to_n( \endrst */ template ::value&& - detail::is_output_iterator::value)> + FMT_ENABLE_IF(detail::is_string::value&& detail:: + is_output_iterator>::value)> inline format_to_n_result format_to_n(OutputIt out, size_t n, const S& format_str, const Args&... args) { diff --git a/include/fmt/locale.h b/include/fmt/locale.h index 84819238..3f5d7519 100644 --- a/include/fmt/locale.h +++ b/include/fmt/locale.h @@ -45,28 +45,27 @@ inline std::basic_string vformat( template > inline std::basic_string format(const std::locale& loc, const S& format_str, Args&&... args) { - return detail::vformat( - loc, to_string_view(format_str), - fmt::make_args_checked(format_str, args...)); + return detail::vformat(loc, to_string_view(format_str), + fmt::make_args_checked(format_str, args...)); } template ::value, char_t>> + typename Char = char_t, + FMT_ENABLE_IF(detail::is_output_iterator::value)> inline OutputIt vformat_to( OutputIt out, const std::locale& loc, const S& format_str, basic_format_args>> args) { decltype(detail::get_buffer(out)) buf(detail::get_buffer_init(out)); using af = - detail::arg_formatter::iterator, Char>; + detail::arg_formatter::iterator, Char>; vformat_to(detail::buffer_appender(buf), to_string_view(format_str), args, detail::locale_ref(loc)); return detail::get_iterator(buf); } template ::value&& - detail::is_string::value)> + typename Char = char_t, + FMT_ENABLE_IF(detail::is_output_iterator::value)> inline OutputIt format_to(OutputIt out, const std::locale& loc, const S& format_str, Args&&... args) { const auto& vargs = fmt::make_args_checked(format_str, args...); diff --git a/test/format-test.cc b/test/format-test.cc index 027c50a0..365c1594 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -169,20 +169,22 @@ TEST(IteratorTest, TruncatingBackInserter) { } TEST(IteratorTest, IsOutputIterator) { - EXPECT_TRUE(fmt::detail::is_output_iterator::value); - EXPECT_FALSE(fmt::detail::is_output_iterator::value); - EXPECT_FALSE(fmt::detail::is_output_iterator::value); - EXPECT_TRUE(fmt::detail::is_output_iterator< - std::back_insert_iterator>::value); - EXPECT_TRUE(fmt::detail::is_output_iterator::value); - EXPECT_FALSE( - fmt::detail::is_output_iterator::value); - EXPECT_FALSE(fmt::detail::is_output_iterator>::value); + EXPECT_TRUE((fmt::detail::is_output_iterator::value)); + EXPECT_FALSE((fmt::detail::is_output_iterator::value)); + EXPECT_FALSE((fmt::detail::is_output_iterator::value)); EXPECT_TRUE( - fmt::detail::is_output_iterator::iterator>::value); - EXPECT_FALSE( - fmt::detail::is_output_iterator::const_iterator>::value); - EXPECT_FALSE(fmt::detail::is_output_iterator::value); + (fmt::detail::is_output_iterator, + char>::value)); + EXPECT_TRUE( + (fmt::detail::is_output_iterator::value)); + EXPECT_FALSE((fmt::detail::is_output_iterator::value)); + EXPECT_FALSE((fmt::detail::is_output_iterator, char>::value)); + EXPECT_TRUE(( + fmt::detail::is_output_iterator::iterator, char>::value)); + EXPECT_FALSE((fmt::detail::is_output_iterator::const_iterator, + char>::value)); + EXPECT_FALSE((fmt::detail::is_output_iterator::value)); } TEST(MemoryBufferTest, Ctor) { @@ -720,13 +722,8 @@ TEST(FormatterTest, SpaceSign) { } TEST(FormatterTest, SignNotTruncated) { - wchar_t format_str[] = { - L'{', - L':', - '+' | (1 << fmt::detail::num_bits()), - L'}', - 0 - }; + wchar_t format_str[] = {L'{', L':', + '+' | (1 << fmt::detail::num_bits()), L'}', 0}; EXPECT_THROW(format(format_str, 42), format_error); }