From 76d480c6fd2032fdee5ffe7d52c2a3feca75007e Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 31 Jan 2026 19:35:50 -0800 Subject: [PATCH] Cleanup handling of adaptors --- include/fmt/ranges.h | 29 ++++++++++++-------------- test/ranges-test.cc | 49 +++++++++++++++++--------------------------- 2 files changed, 32 insertions(+), 46 deletions(-) diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h index d67f59af..0f7cd7cc 100644 --- a/include/fmt/ranges.h +++ b/include/fmt/ranges.h @@ -746,18 +746,8 @@ struct formatter, Char, return do_format(value, ctx, std::integral_constant()); } }; + namespace detail { -// Check if T has an interface like a container adaptor (e.g. std::stack, -// std::queue, std::priority_queue). -template class is_container_adaptor_like { - template static auto check(U* p) -> typename U::container_type; - template static void check(...); - - public: - static constexpr bool value = - !std::is_void(nullptr))>::value; -}; - template struct all { const Container& c; auto begin() const -> typename Container::const_iterator { return c.begin(); } @@ -766,13 +756,20 @@ template struct all { } // namespace detail /** - * returns "true" if "T" is a container adaptor (like "std::stack") - * that should be formatted by iterating over the underlying container. - * */ - + * Specifies if `T` is a container adaptor (like `std::stack`) that should be + * formatted as the underlying container. + */ FMT_EXPORT template -struct is_container_adaptor : detail::is_container_adaptor_like {}; +struct is_container_adaptor { + private: + template static auto check(U* p) -> typename U::container_type; + template static void check(...); + + public: + static constexpr bool value = + !std::is_void(nullptr))>::value; +}; template struct formatter< diff --git a/test/ranges-test.cc b/test/ranges-test.cc index f82569b2..2d84840d 100644 --- a/test/ranges-test.cc +++ b/test/ranges-test.cc @@ -128,7 +128,7 @@ TEST(ranges_test, format_set) { // Models std::flat_set close enough to test if no ambiguous lookup of a // formatter happens due to the flat_set type matching is_set and -// is_container_adaptor_like. +// is_container_adaptor. template class flat_set { public: using key_type = T; @@ -608,12 +608,11 @@ TEST(ranges_test, vector_char) { TEST(ranges_test, container_adaptor) { { - using fmt::detail::is_container_adaptor_like; using T = std::nullptr_t; - static_assert(is_container_adaptor_like>::value, ""); - static_assert(is_container_adaptor_like>::value, ""); - static_assert(is_container_adaptor_like>::value, ""); - static_assert(!is_container_adaptor_like>::value, ""); + static_assert(fmt::is_container_adaptor>::value, ""); + static_assert(fmt::is_container_adaptor>::value, ""); + static_assert(fmt::is_container_adaptor>::value, ""); + static_assert(!fmt::is_container_adaptor>::value, ""); } { @@ -798,32 +797,22 @@ struct not_range { }; static_assert(!fmt::is_formattable{}, ""); -namespace test_detail { - template - struct partial_opt_out_wrapper { - using container_type = std::vector; - std::vector c = {1, 2, 3}; - }; -} // namespace test_detail +struct test_adaptor { + using container_type = std::vector; + std::vector c = {1, 2, 3}; +}; namespace fmt { - template - struct is_container_adaptor> : std::false_type {}; +template <> struct is_container_adaptor : std::false_type {}; - template - struct formatter> { - constexpr fmt::format_parse_context::iterator parse(fmt::format_parse_context& ctx) const { - return ctx.begin(); - } - - fmt::format_context::iterator format(const test_detail::partial_opt_out_wrapper& val, - fmt::format_context& ctx) const { - return fmt::format_to(ctx.out(), "PartialOptOut(size={})", val.c.size()); - } - }; +template <> struct formatter : formatter { + auto format(const test_adaptor&, format_context& ctx) const + -> format_context::iterator { + return formatter::format("test", ctx); + } +}; } // namespace fmt -TEST(ranges_test, container_adaptor_partial_specialization) { - test_detail::partial_opt_out_wrapper obj; - EXPECT_EQ(fmt::format("{}", obj), "PartialOptOut(size=3)"); -} \ No newline at end of file +TEST(ranges_test, container_adaptor_opt_out) { + EXPECT_EQ(fmt::format("{}", test_adaptor()), "test"); +}