From 5ee14d35087b3e30879de0ed12c13b957cbccea3 Mon Sep 17 00:00:00 2001 From: Vladislav Shchapov Date: Sat, 3 Aug 2024 19:13:32 +0500 Subject: [PATCH] Reintroduce constexpr fmt::formatted_size for C++20 (#4103) * Reintroduce constexpr fmt::formatted_size for C++20 Signed-off-by: Vladislav Shchapov * Disable constexpr fmt::formatted_size on Visual Studio 2019 Signed-off-by: Vladislav Shchapov --------- Signed-off-by: Vladislav Shchapov --- include/fmt/base.h | 33 +++++++++++++++++++++++---------- include/fmt/compile.h | 3 ++- include/fmt/format.h | 10 ++++++---- test/compile-test.cc | 2 +- 4 files changed, 32 insertions(+), 16 deletions(-) diff --git a/include/fmt/base.h b/include/fmt/base.h index b40b3bfb..86f3f5ae 100644 --- a/include/fmt/base.h +++ b/include/fmt/base.h @@ -494,7 +494,8 @@ struct is_back_insert_iterator< // Extracts a reference to the container from *insert_iterator. template -inline auto get_container(OutputIt it) -> typename OutputIt::container_type& { +inline FMT_CONSTEXPR20 auto get_container(OutputIt it) -> + typename OutputIt::container_type& { struct accessor : OutputIt { accessor(OutputIt base) : OutputIt(base) {} using OutputIt::container; @@ -901,7 +902,7 @@ template class buffer { FMT_CONSTEXPR auto data() const noexcept -> const T* { return ptr_; } /// Clears this buffer. - void clear() { size_ = 0; } + FMT_CONSTEXPR void clear() { size_ = 0; } // Tries resizing the buffer to contain `count` elements. If T is a POD type // the new elements may not be initialized. @@ -924,7 +925,15 @@ template class buffer { } /// Appends data to the end of the buffer. - template void append(const U* begin, const U* end) { + template +// Workaround for Visual Studio 2019 to fix error C2893: Failed to specialize +// function template 'void fmt::v11::detail::buffer::append(const U *,const +// U *)' +#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1930 + FMT_CONSTEXPR20 +#endif + void + append(const U* begin, const U* end) { while (begin != end) { auto count = to_unsigned(end - begin); try_reserve(size_ + count); @@ -1105,7 +1114,9 @@ template class counting_buffer : public buffer { public: FMT_CONSTEXPR counting_buffer() : buffer(grow, data_, 0, buffer_size) {} - auto count() -> size_t { return count_ + this->size(); } + constexpr auto count() const noexcept -> size_t { + return count_ + this->size(); + } }; } // namespace detail @@ -1155,7 +1166,8 @@ template class basic_appender { private: detail::buffer* buffer_; - friend auto get_container(basic_appender app) -> detail::buffer& { + friend FMT_CONSTEXPR20 auto get_container(basic_appender app) + -> detail::buffer& { return *app.buffer_; } @@ -1170,13 +1182,13 @@ template class basic_appender { FMT_CONSTEXPR basic_appender(detail::buffer& buf) : buffer_(&buf) {} - auto operator=(T c) -> basic_appender& { + FMT_CONSTEXPR20 auto operator=(T c) -> basic_appender& { buffer_->push_back(c); return *this; } - auto operator*() -> basic_appender& { return *this; } - auto operator++() -> basic_appender& { return *this; } - auto operator++(int) -> basic_appender { return *this; } + FMT_CONSTEXPR20 auto operator*() -> basic_appender& { return *this; } + FMT_CONSTEXPR20 auto operator++() -> basic_appender& { return *this; } + FMT_CONSTEXPR20 auto operator++(int) -> basic_appender { return *this; } }; using appender = basic_appender; @@ -1188,7 +1200,8 @@ struct is_back_insert_iterator> : std::true_type {}; // An optimized version of std::copy with the output value type (T). template ::value)> -auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt { +FMT_CONSTEXPR20 auto copy(InputIt begin, InputIt end, OutputIt out) + -> OutputIt { get_container(out).append(begin, end); return out; } diff --git a/include/fmt/compile.h b/include/fmt/compile.h index 8a632f63..49d077e0 100644 --- a/include/fmt/compile.h +++ b/include/fmt/compile.h @@ -488,7 +488,8 @@ auto format_to_n(OutputIt out, size_t n, const S& fmt, Args&&... args) template ::value)> -auto formatted_size(const S& fmt, const Args&... args) -> size_t { +FMT_CONSTEXPR20 auto formatted_size(const S& fmt, const Args&... args) + -> size_t { auto buf = detail::counting_buffer<>(); fmt::format_to(appender(buf), fmt, args...); return buf.count(); diff --git a/include/fmt/format.h b/include/fmt/format.h index 33ed7034..76e3b880 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -523,7 +523,7 @@ template = 307 && !FMT_ICC_VERSION __attribute__((no_sanitize("undefined"))) #endif -inline auto +FMT_CONSTEXPR20 inline auto reserve(OutputIt it, size_t n) -> typename OutputIt::value_type* { auto& c = get_container(it); size_t size = c.size(); @@ -532,7 +532,8 @@ reserve(OutputIt it, size_t n) -> typename OutputIt::value_type* { } template -inline auto reserve(basic_appender it, size_t n) -> basic_appender { +FMT_CONSTEXPR20 inline auto reserve(basic_appender it, size_t n) + -> basic_appender { buffer& buf = get_container(it); buf.try_reserve(buf.size() + n); return it; @@ -551,7 +552,8 @@ template constexpr auto to_pointer(OutputIt, size_t) -> T* { return nullptr; } -template auto to_pointer(basic_appender it, size_t n) -> T* { +template +FMT_CONSTEXPR20 auto to_pointer(basic_appender it, size_t n) -> T* { buffer& buf = get_container(it); auto size = buf.size(); buf.try_reserve(size + n); @@ -929,7 +931,7 @@ class basic_memory_buffer : public detail::buffer { using detail::buffer::append; template - void append(const ContiguousRange& range) { + FMT_CONSTEXPR20 void append(const ContiguousRange& range) { append(range.data(), range.data() + range.size()); } }; diff --git a/test/compile-test.cc b/test/compile-test.cc index e44eee9f..5ba3edea 100644 --- a/test/compile-test.cc +++ b/test/compile-test.cc @@ -198,7 +198,7 @@ TEST(compile_test, format_to_n) { EXPECT_STREQ("2a", buffer); } -# if 0 +# if FMT_USE_CONSTEVAL && (!FMT_MSC_VERSION || FMT_MSC_VERSION >= 1930) TEST(compile_test, constexpr_formatted_size) { FMT_CONSTEXPR20 size_t size = fmt::formatted_size(FMT_COMPILE("{}"), 42); EXPECT_EQ(size, 2);