From d551b88a6d2ff1f2e47e1bc639fccad30f11b0a7 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 6 Jun 2021 09:25:12 -0700 Subject: [PATCH] Move is_char specializations to xchar.h --- include/fmt/core.h | 30 +++++++++++++++++++++++- include/fmt/format.h | 52 ---------------------------------------- include/fmt/xchar.h | 5 ++++ test/color-test.cc | 2 -- test/core-test.cc | 34 +++++++-------------------- test/ostream-test.cc | 3 --- test/test-assert.h | 1 - test/xchar-test.cc | 56 ++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 98 insertions(+), 85 deletions(-) diff --git a/include/fmt/core.h b/include/fmt/core.h index 94d97859..a15a80b6 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -724,6 +724,23 @@ inline auto get_container(std::back_insert_iterator it) return *accessor(it).container; } +template +FMT_CONSTEXPR auto copy_str(InputIt begin, InputIt end, OutputIt out) + -> OutputIt { + while (begin != end) *out++ = static_cast(*begin++); + return out; +} + +template ::value)> +FMT_CONSTEXPR auto copy_str(const Char* begin, const Char* end, Char* out) + -> Char* { + if (is_constant_evaluated()) + return copy_str(begin, end, out); + auto size = to_unsigned(end - begin); + memcpy(out, begin, size); + return out + size; +} + /** \rst A contiguous memory buffer with an optional growing ability. It is an internal @@ -848,7 +865,12 @@ class iterator_buffer final : public Traits, public buffer { void grow(size_t) final FMT_OVERRIDE { if (this->size() == buffer_size) flush(); } - void flush(); + + void flush() { + auto size = this->size(); + this->clear(); + out_ = copy_str(data_, data_ + this->limit(size), out_); + } public: explicit iterator_buffer(OutputIt out, size_t n = buffer_size) @@ -1463,6 +1485,12 @@ FMT_CONSTEXPR FMT_INLINE auto visit_format_arg( FMT_BEGIN_DETAIL_NAMESPACE +template +auto copy_str(InputIt begin, InputIt end, appender out) -> appender { + get_container(out).append(begin, end); + return out; +} + #if FMT_GCC_VERSION && FMT_GCC_VERSION < 500 // A workaround for gcc 4.8 to make void_t work in a SFINAE context. template struct void_t_impl { using type = void; }; diff --git a/include/fmt/format.h b/include/fmt/format.h index 3fcf3b20..ade11d70 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -432,46 +432,6 @@ using char8_type = char8_t; enum char8_type : unsigned char {}; #endif -template -using needs_conversion = bool_constant< - std::is_same::value_type, - char>::value && - std::is_same::value>; - -template ::value)> -FMT_CONSTEXPR auto copy_str(InputIt begin, InputIt end, OutputIt out) - -> OutputIt { - while (begin != end) *out++ = *begin++; - return out; -} - -template ::value)> -FMT_CONSTEXPR20 auto copy_str(InputIt begin, InputIt end, OutChar* out) - -> OutChar* { - if (is_constant_evaluated()) { - return copy_str(begin, end, out); - } - auto size = to_unsigned(end - begin); - std::uninitialized_copy(begin, end, make_checked(out, size)); - return out + size; -} - -template ::value)> -auto copy_str(InputIt begin, InputIt end, OutputIt out) -> OutputIt { - while (begin != end) *out++ = static_cast(*begin++); - return out; -} - -template ::value)> -auto copy_str(InputIt begin, InputIt end, appender out) -> appender { - get_container(out).append(begin, end); - return out; -} - template FMT_CONSTEXPR FMT_NOINLINE auto copy_str_noinline(InputIt begin, InputIt end, OutputIt out) -> OutputIt { @@ -633,13 +593,6 @@ void buffer::append(const U* begin, const U* end) { } } -template -void iterator_buffer::flush() { - auto size = this->size(); - this->clear(); - out_ = copy_str(data_, data_ + this->limit(size), out_); -} - template struct is_locale : std::false_type {}; template @@ -648,11 +601,6 @@ struct is_locale> : std::true_type {}; FMT_MODULE_EXPORT_BEGIN -template <> struct is_char : std::true_type {}; -template <> struct is_char : std::true_type {}; -template <> struct is_char : std::true_type {}; -template <> struct is_char : std::true_type {}; - // The number of characters to store in the basic_memory_buffer object itself // to avoid dynamic memory allocation. enum { inline_buffer_size = 500 }; diff --git a/include/fmt/xchar.h b/include/fmt/xchar.h index 69f44864..74c69045 100644 --- a/include/fmt/xchar.h +++ b/include/fmt/xchar.h @@ -35,6 +35,11 @@ template using wformat_string = basic_format_string...>; #endif +template <> struct is_char : std::true_type {}; +template <> struct is_char : std::true_type {}; +template <> struct is_char : std::true_type {}; +template <> struct is_char : std::true_type {}; + template constexpr format_arg_store make_wformat_args( const Args&... args) { diff --git a/test/color-test.cc b/test/color-test.cc index 9a38765a..e2408ca1 100644 --- a/test/color-test.cc +++ b/test/color-test.cc @@ -14,8 +14,6 @@ TEST(color_test, format) { EXPECT_EQ(fmt::format(fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30)"), "\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m"); - EXPECT_EQ(fmt::format(fg(fmt::rgb(255, 20, 30)), L"rgb(255,20,30) wide"), - L"\x1b[38;2;255;020;030mrgb(255,20,30) wide\x1b[0m"); EXPECT_EQ(fmt::format(fg(fmt::color::blue), "blue"), "\x1b[38;2;000;000;255mblue\x1b[0m"); EXPECT_EQ( diff --git a/test/core-test.cc b/test/core-test.cc index 43fa1d11..ad1bc38a 100644 --- a/test/core-test.cc +++ b/test/core-test.cc @@ -29,6 +29,10 @@ using testing::_; using testing::Invoke; using testing::Return; +#ifdef FMT_FORMAT_H_ +# error core-test includes format.h +#endif + TEST(string_view_test, value_type) { static_assert(std::is_same::value, ""); } @@ -90,34 +94,8 @@ template fmt::basic_string_view to_string_view(const test_string& s) { return {s.data(), s.length()}; } - -struct non_string {}; } // namespace test_ns -template class is_string_test : public testing::Test {}; - -using string_char_types = testing::Types; -TYPED_TEST_SUITE(is_string_test, string_char_types); - -template -struct derived_from_string_view : fmt::basic_string_view {}; - -TYPED_TEST(is_string_test, is_string) { - EXPECT_TRUE(fmt::detail::is_string::value); - EXPECT_TRUE(fmt::detail::is_string::value); - EXPECT_TRUE(fmt::detail::is_string::value); - EXPECT_TRUE(fmt::detail::is_string::value); - EXPECT_TRUE(fmt::detail::is_string>::value); - EXPECT_TRUE(fmt::detail::is_string>::value); - EXPECT_TRUE( - fmt::detail::is_string>::value); - using fmt_string_view = fmt::detail::std_string_view; - EXPECT_TRUE(std::is_empty::value != - fmt::detail::is_string::value); - EXPECT_TRUE(fmt::detail::is_string>::value); - EXPECT_FALSE(fmt::detail::is_string::value); -} - TEST(core_test, is_output_iterator) { EXPECT_TRUE((fmt::detail::is_output_iterator::value)); EXPECT_FALSE((fmt::detail::is_output_iterator::value)); @@ -428,6 +406,10 @@ TYPED_TEST(numeric_arg_test, make_and_visit) { CHECK_ARG_SIMPLE(std::numeric_limits::max()); } +namespace fmt { +template <> struct is_char : std::true_type {}; +} // namespace fmt + TEST(arg_test, char_arg) { CHECK_ARG(char, 'a', 'a'); CHECK_ARG(wchar_t, L'a', 'a'); diff --git a/test/ostream-test.cc b/test/ostream-test.cc index 62e45f5d..19105f45 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -96,9 +96,6 @@ TEST(ostream_test, print) { std::ostringstream os; fmt::print(os, "Don't {}!", "panic"); EXPECT_EQ("Don't panic!", os.str()); - std::wostringstream wos; - fmt::print(wos, L"Don't {}!", L"panic"); - EXPECT_EQ(L"Don't panic!", wos.str()); } TEST(ostream_test, write_to_ostream) { diff --git a/test/test-assert.h b/test/test-assert.h index cc7920df..ab7b2bf7 100644 --- a/test/test-assert.h +++ b/test/test-assert.h @@ -14,7 +14,6 @@ void throw_assertion_failure(const char* message); #define FMT_ASSERT(condition, message) \ if (!(condition)) throw_assertion_failure(message); -#include "gtest-extra.h" #include "gtest/gtest.h" class assertion_failure : public std::logic_error { diff --git a/test/xchar-test.cc b/test/xchar-test.cc index 52a15164..78ecb2c7 100644 --- a/test/xchar-test.cc +++ b/test/xchar-test.cc @@ -10,12 +10,57 @@ #include #include "fmt/chrono.h" +#include "fmt/color.h" #include "fmt/ostream.h" #include "fmt/ranges.h" #include "gtest/gtest.h" using fmt::detail::max_value; +namespace test_ns { +template class test_string { + private: + std::basic_string s_; + + public: + test_string(const Char* s) : s_(s) {} + const Char* data() const { return s_.data(); } + size_t length() const { return s_.size(); } + operator const Char*() const { return s_.c_str(); } +}; + +template +fmt::basic_string_view to_string_view(const test_string& s) { + return {s.data(), s.length()}; +} + +struct non_string {}; +} // namespace test_ns + +template class is_string_test : public testing::Test {}; + +using string_char_types = testing::Types; +TYPED_TEST_SUITE(is_string_test, string_char_types); + +template +struct derived_from_string_view : fmt::basic_string_view {}; + +TYPED_TEST(is_string_test, is_string) { + EXPECT_TRUE(fmt::detail::is_string::value); + EXPECT_TRUE(fmt::detail::is_string::value); + EXPECT_TRUE(fmt::detail::is_string::value); + EXPECT_TRUE(fmt::detail::is_string::value); + EXPECT_TRUE(fmt::detail::is_string>::value); + EXPECT_TRUE(fmt::detail::is_string>::value); + EXPECT_TRUE( + fmt::detail::is_string>::value); + using fmt_string_view = fmt::detail::std_string_view; + EXPECT_TRUE(std::is_empty::value != + fmt::detail::is_string::value); + EXPECT_TRUE(fmt::detail::is_string>::value); + EXPECT_FALSE(fmt::detail::is_string::value); +} + // std::is_constructible is broken in MSVC until version 2015. #if !FMT_MSC_VER || FMT_MSC_VER >= 1900 struct explicitly_convertible_to_wstring_view { @@ -214,6 +259,17 @@ TEST(xchar_test, chrono) { EXPECT_EQ(L"42s", fmt::format(L"{}", std::chrono::seconds(42))); } +TEST(xchar_test, color) { + EXPECT_EQ(fmt::format(fg(fmt::rgb(255, 20, 30)), L"rgb(255,20,30) wide"), + L"\x1b[38;2;255;020;030mrgb(255,20,30) wide\x1b[0m"); +} + +TEST(xchar_test, ostream) { + std::wostringstream wos; + fmt::print(wos, L"Don't {}!", L"panic"); + EXPECT_EQ(L"Don't panic!", wos.str()); +} + TEST(xchar_test, to_wstring) { EXPECT_EQ(L"42", fmt::to_wstring(42)); } #ifndef FMT_STATIC_THOUSANDS_SEPARATOR