This change makes the consteval function slightly faster to compile.
Instead of keeping the counts in an array and looping over that array,
we can just keep a sum of how many valid types are present, and check
that it equals the total number of types in the pack. We can also avoid
doing the check entirely for the common cases where the call comes from
check_dynamic_spec_integer or check_dynamic_spec_string, because those
always use valid lists of types.

The diagnostic is slightly worse now, because there's only a single
"invalid template argument types" string that appears in the output,
where previously we had either "non-unique template argument type" or
"disallowed template argument type" depending on the failure mode.

Given that most users will never use this function directly, and
probably won't use invalid types anyway, the inferior diagnostic seems
acceptable.

libstdc++-v3/ChangeLog:

        * include/std/format (basic_format_parse_context::__check_types):
        New variable template and partial specializations.
        (basic_format_parse_context::__check_dynamic_spec_types):
        Simplify for faster compilation.
        (basic_format_parse_context::check_dynamic_spec): Only use
        __check_dynamic_spec_types when __check_types is true. Use it as
        the condition for a constexpr if statement instead of as the
        initializer for a constexpr variable.
        (basic_format_parse_context::check_dynamic_spec_string): Use
        _CharT instead of char_type consistently.
---

Tested x86_64-linux.

 libstdc++-v3/include/std/format | 81 +++++++++++++++++++--------------
 1 file changed, 47 insertions(+), 34 deletions(-)

diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
index 0d6cc7f6bef..6269cbb80e6 100644
--- a/libstdc++-v3/include/std/format
+++ b/libstdc++-v3/include/std/format
@@ -305,41 +305,51 @@ namespace __format
       constexpr void
       check_dynamic_spec_string(size_t __id) noexcept
       {
-       check_dynamic_spec<const char_type*, basic_string_view<_CharT>>(__id);
+       check_dynamic_spec<const _CharT*, basic_string_view<_CharT>>(__id);
       }
 
     private:
-      // Check the Mandates: condition for check_dynamic_spec<Ts...>(n)
+      template<typename _Tp, typename... _Ts>
+       static constexpr bool __once = (is_same_v<_Tp, _Ts> + ...) == 1;
+
+      // True if we need to call __check_dynamic_spec_types for the pack Ts
+      template<typename... _Ts>
+       static constexpr bool __check_types = sizeof...(_Ts) > 0;
+      // The pack used by check_dynamic_spec_integral is valid, don't check it.
+      // FIXME: simplify these when PR c++/85282 is supported.
+      template<typename _Tp>
+       static constexpr bool
+       __check_types<_Tp, unsigned, long long, unsigned long long>
+         = ! is_same_v<_Tp, int>;
+      // The pack used by check_dynamic_spec_string is valid, don't check it.
+      template<typename _Tp>
+       static constexpr bool
+       __check_types<_Tp, basic_string_view<_CharT>>
+         = ! is_same_v<const _CharT*, _Tp>;
+
+      // Check the Mandates: conditions for check_dynamic_spec<Ts...>(n)
       template<typename... _Ts>
        static consteval bool
        __check_dynamic_spec_types()
        {
-         if constexpr (sizeof...(_Ts))
-           {
-             int __counts[] = {
-               (is_same_v<bool, _Ts> + ...),
-               (is_same_v<_CharT, _Ts> + ...),
-               (is_same_v<int, _Ts> + ...),
-               (is_same_v<unsigned, _Ts> + ...),
-               (is_same_v<long long, _Ts> + ...),
-               (is_same_v<unsigned long long, _Ts> + ...),
-               (is_same_v<float, _Ts> + ...),
-               (is_same_v<double, _Ts> + ...),
-               (is_same_v<long double, _Ts> + ...),
-               (is_same_v<const _CharT*, _Ts> + ...),
-               (is_same_v<basic_string_view<_CharT>, _Ts> + ...),
-               (is_same_v<const void*, _Ts> + ...)
-             };
-             int __sum = 0;
-             for (int __c : __counts)
-               {
-                 __sum += __c;
-                 if (__c > 1)
-                   __invalid_dynamic_spec("non-unique template argument type");
-               }
-             if (__sum != sizeof...(_Ts))
-               __invalid_dynamic_spec("disallowed template argument type");
-           }
+         // The types in Ts... are unique. Each type in Ts... is one of
+         // bool, char_type, int, unsigned int, long long int,
+         // unsigned long long int, float, double, long double,
+         // const char_type*, basic_string_view<char_type>, or const void*.
+         unsigned __sum = __once<bool, _Ts...>
+                        + __once<char_type, _Ts...>
+                        + __once<int, _Ts...>
+                        + __once<unsigned int, _Ts...>
+                        + __once<long long int, _Ts...>
+                        + __once<unsigned long long int, _Ts...>
+                        + __once<float, _Ts...>
+                        + __once<double, _Ts...>
+                        + __once<long double, _Ts...>
+                        + __once<const char_type*, _Ts...>
+                        + __once<basic_string_view<char_type>, _Ts...>
+                        + __once<const void*, _Ts...>;
+         if (__sum != sizeof...(_Ts))
+           __invalid_dynamic_spec("invalid template argument types");
          return true;
        }
 
@@ -4341,12 +4351,15 @@ namespace __format
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 4142. check_dynamic_spec should require at least one type
       static_assert(sizeof...(_Ts) >= 1);
-      // This call enforces the Mandates: condition that _Ts contains valid
-      // types and each type appears at most once. It could be a static_assert
-      // but this way failures give better diagnostics, due to calling the
-      // non-constexpr __invalid_dynamic_spec function.
-      [[maybe_unused]]
-      constexpr bool __ok = __check_dynamic_spec_types<_Ts...>();
+
+      if constexpr (__check_types<_Ts...>)
+       if constexpr (__check_dynamic_spec_types<_Ts...>())
+         {
+           // The call above enforces the Mandates: condition that _Ts
+           // contains valid types and each type appears at most once.
+           // Checking it in `if constexpr` means that failures give better
+           // diagnostics than if we used it as a static_assert condition.
+         }
 
       if consteval {
        if (__id >= _M_num_args)
-- 
2.48.1

Reply via email to