From 7ce9a2e7db487bc3063ae76e73c2a47b6de75419 Mon Sep 17 00:00:00 2001 From: Vladislav Shchapov Date: Fri, 4 Aug 2023 23:13:43 +0500 Subject: [PATCH 1/5] Add test for std::vector::reference Co-authored-by: Felix Signed-off-by: Vladislav Shchapov --- test/std-test.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/std-test.cc b/test/std-test.cc index fda8e96bd122..643d93c688e1 100644 --- a/test/std-test.cc +++ b/test/std-test.cc @@ -221,3 +221,8 @@ TEST(std_test, exception) { } #endif } + +TEST(std_test, format_vector_bool_specialization) { + std::vector v = {true, false}; + EXPECT_EQ(fmt::format("{} {}", v[0], v[1]), "true false"); +} From 4298687d8bfaec812dd8b3b82400e1bd2b1466fa Mon Sep 17 00:00:00 2001 From: Vladislav Shchapov Date: Sat, 5 Aug 2023 13:41:34 +0500 Subject: [PATCH 2/5] Add test for std::bitset::reference Signed-off-by: Vladislav Shchapov --- test/std-test.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/std-test.cc b/test/std-test.cc index 643d93c688e1..53c0559eec45 100644 --- a/test/std-test.cc +++ b/test/std-test.cc @@ -7,6 +7,7 @@ #include "fmt/std.h" +#include #include #include #include @@ -222,7 +223,9 @@ TEST(std_test, exception) { #endif } -TEST(std_test, format_vector_bool_specialization) { +TEST(std_test, format_bit_reference) { + std::bitset<2> bs(1); + EXPECT_EQ(fmt::format("{} {}", bs[0], bs[1]), "true false"); std::vector v = {true, false}; EXPECT_EQ(fmt::format("{} {}", v[0], v[1]), "true false"); } From 8e34ac7d29668bcdd55df900c31f304a864225f8 Mon Sep 17 00:00:00 2001 From: Vladislav Shchapov Date: Sun, 6 Aug 2023 22:23:25 +0500 Subject: [PATCH 3/5] Add test for const std::bitset::reference and const std::vector::reference Signed-off-by: Vladislav Shchapov --- test/std-test.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/std-test.cc b/test/std-test.cc index 53c0559eec45..17b4792c625f 100644 --- a/test/std-test.cc +++ b/test/std-test.cc @@ -229,3 +229,10 @@ TEST(std_test, format_bit_reference) { std::vector v = {true, false}; EXPECT_EQ(fmt::format("{} {}", v[0], v[1]), "true false"); } + +TEST(std_test, format_const_bit_reference) { + const std::bitset<2> bs(1); + EXPECT_EQ(fmt::format("{} {}", bs[0], bs[1]), "true false"); + const std::vector v = {true, false}; + EXPECT_EQ(fmt::format("{} {}", v[0], v[1]), "true false"); +} From 67f44796917d0bb6b1dcbf3fd1f58a8d9cb995f8 Mon Sep 17 00:00:00 2001 From: Vladislav Shchapov Date: Fri, 4 Aug 2023 23:26:13 +0500 Subject: [PATCH 4/5] Add bit_reference-like formatter Signed-off-by: Vladislav Shchapov --- include/fmt/std.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/include/fmt/std.h b/include/fmt/std.h index a71a59db9a0d..b0e78e10ddfe 100644 --- a/include/fmt/std.h +++ b/include/fmt/std.h @@ -8,6 +8,7 @@ #ifndef FMT_STD_H_ #define FMT_STD_H_ +#include #include #include #include @@ -15,6 +16,7 @@ #include #include #include +#include #include "format.h" #include "ostream.h" @@ -389,6 +391,50 @@ struct formatter< #endif } }; + +namespace detail { + +template +struct has_flip : std::false_type {}; + +template +struct has_flip().flip())>> + : std::true_type {}; + +template struct is_bit_reference_like { + static constexpr const bool value = + std::is_convertible::value && + std::is_nothrow_assignable::value && has_flip::value; +}; + +#ifdef _LIBCPP_VERSION + +// Workaround for libc++ incompatibility with C++ standard. +// According to the Standard, `bitset::operator[] const` returns bool. +template +struct is_bit_reference_like> { + static constexpr const bool value = true; +}; + +#endif + +} // namespace detail + +// We can't use std::vector::reference and +// std::bitset::reference because the compiler can't deduce Allocator and N +// in partial specialization. +FMT_EXPORT +template +struct formatter::value>> + : formatter { + template + FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const + -> decltype(ctx.out()) { + return formatter::format(v, ctx); + } +}; + FMT_END_NAMESPACE #endif // FMT_STD_H_ From 4f5d18473db21ffca0a02da390c7abe00fe40053 Mon Sep 17 00:00:00 2001 From: Vladislav Shchapov Date: Sat, 5 Aug 2023 22:13:03 +0500 Subject: [PATCH 5/5] Use std::addressof Signed-off-by: Vladislav Shchapov --- include/fmt/core.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/fmt/core.h b/include/fmt/core.h index f6886cf41c66..1f3e58011fda 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -13,6 +13,7 @@ #include // std::strlen #include #include +#include // std::addressof #include #include @@ -1281,9 +1282,9 @@ template class value { FMT_INLINE value(const named_arg_info* args, size_t size) : named_args{args, size} {} - template FMT_CONSTEXPR FMT_INLINE value(T& val) { + template FMT_CONSTEXPR20 FMT_INLINE value(T& val) { using value_type = remove_const_t; - custom.value = const_cast(&val); + custom.value = const_cast(std::addressof(val)); // Get the formatter type through the context to allow different contexts // have different extension points, e.g. `formatter` for `format` and // `printf_formatter` for `printf`.