"Fossies" - the Fresh Open Source Software Archive

Member "abseil-cpp-20230802.1/absl/strings/internal/str_format/arg.h" (18 Sep 2023, 25488 Bytes) of package /linux/misc/abseil-cpp-20230802.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "arg.h" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 20230125.3_vs_20230802.0.

    1 // Copyright 2020 The Abseil Authors.
    2 //
    3 // Licensed under the Apache License, Version 2.0 (the "License");
    4 // you may not use this file except in compliance with the License.
    5 // You may obtain a copy of the License at
    6 //
    7 //      https://www.apache.org/licenses/LICENSE-2.0
    8 //
    9 // Unless required by applicable law or agreed to in writing, software
   10 // distributed under the License is distributed on an "AS IS" BASIS,
   11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   12 // See the License for the specific language governing permissions and
   13 // limitations under the License.
   14 
   15 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
   16 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
   17 
   18 #include <string.h>
   19 #include <wchar.h>
   20 
   21 #include <algorithm>
   22 #include <cstdio>
   23 #include <iomanip>
   24 #include <limits>
   25 #include <memory>
   26 #include <sstream>
   27 #include <string>
   28 #include <type_traits>
   29 #include <utility>
   30 
   31 #include "absl/base/port.h"
   32 #include "absl/meta/type_traits.h"
   33 #include "absl/numeric/int128.h"
   34 #include "absl/strings/internal/has_absl_stringify.h"
   35 #include "absl/strings/internal/str_format/extension.h"
   36 #include "absl/strings/string_view.h"
   37 
   38 namespace absl {
   39 ABSL_NAMESPACE_BEGIN
   40 
   41 class Cord;
   42 class FormatCountCapture;
   43 class FormatSink;
   44 
   45 template <absl::FormatConversionCharSet C>
   46 struct FormatConvertResult;
   47 class FormatConversionSpec;
   48 
   49 namespace str_format_internal {
   50 
   51 template <FormatConversionCharSet C>
   52 struct ArgConvertResult {
   53   bool value;
   54 };
   55 
   56 using IntegralConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
   57     FormatConversionCharSetInternal::c,
   58     FormatConversionCharSetInternal::kNumeric,
   59     FormatConversionCharSetInternal::kStar,
   60     FormatConversionCharSetInternal::v)>;
   61 using FloatingConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
   62     FormatConversionCharSetInternal::kFloating,
   63     FormatConversionCharSetInternal::v)>;
   64 using CharConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
   65     FormatConversionCharSetInternal::c,
   66     FormatConversionCharSetInternal::kNumeric,
   67     FormatConversionCharSetInternal::kStar)>;
   68 
   69 template <typename T, typename = void>
   70 struct HasUserDefinedConvert : std::false_type {};
   71 
   72 template <typename T>
   73 struct HasUserDefinedConvert<T, void_t<decltype(AbslFormatConvert(
   74                                     std::declval<const T&>(),
   75                                     std::declval<const FormatConversionSpec&>(),
   76                                     std::declval<FormatSink*>()))>>
   77     : std::true_type {};
   78 
   79 // These declarations prevent ADL lookup from continuing in absl namespaces,
   80 // we are deliberately using these as ADL hooks and want them to consider
   81 // non-absl namespaces only.
   82 void AbslFormatConvert();
   83 void AbslStringify();
   84 
   85 template <typename T>
   86 bool ConvertIntArg(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
   87 
   88 // Forward declarations of internal `ConvertIntArg` function template
   89 // instantiations are here to avoid including the template body in the headers
   90 // and instantiating it in large numbers of translation units. Explicit
   91 // instantiations can be found in "absl/strings/internal/str_format/arg.cc"
   92 extern template bool ConvertIntArg<char>(char v, FormatConversionSpecImpl conv,
   93                                          FormatSinkImpl* sink);
   94 extern template bool ConvertIntArg<signed char>(signed char v,
   95                                                 FormatConversionSpecImpl conv,
   96                                                 FormatSinkImpl* sink);
   97 extern template bool ConvertIntArg<unsigned char>(unsigned char v,
   98                                                   FormatConversionSpecImpl conv,
   99                                                   FormatSinkImpl* sink);
  100 extern template bool ConvertIntArg<short>(short v,  // NOLINT
  101                                           FormatConversionSpecImpl conv,
  102                                           FormatSinkImpl* sink);
  103 extern template bool ConvertIntArg<unsigned short>(   // NOLINT
  104     unsigned short v, FormatConversionSpecImpl conv,  // NOLINT
  105     FormatSinkImpl* sink);
  106 extern template bool ConvertIntArg<int>(int v, FormatConversionSpecImpl conv,
  107                                         FormatSinkImpl* sink);
  108 extern template bool ConvertIntArg<unsigned int>(unsigned int v,
  109                                                  FormatConversionSpecImpl conv,
  110                                                  FormatSinkImpl* sink);
  111 extern template bool ConvertIntArg<long>(                           // NOLINT
  112     long v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);   // NOLINT
  113 extern template bool ConvertIntArg<unsigned long>(unsigned long v,  // NOLINT
  114                                                   FormatConversionSpecImpl conv,
  115                                                   FormatSinkImpl* sink);
  116 extern template bool ConvertIntArg<long long>(long long v,  // NOLINT
  117                                               FormatConversionSpecImpl conv,
  118                                               FormatSinkImpl* sink);
  119 extern template bool ConvertIntArg<unsigned long long>(   // NOLINT
  120     unsigned long long v, FormatConversionSpecImpl conv,  // NOLINT
  121     FormatSinkImpl* sink);
  122 
  123 template <typename T>
  124 auto FormatConvertImpl(const T& v, FormatConversionSpecImpl conv,
  125                        FormatSinkImpl* sink)
  126     -> decltype(AbslFormatConvert(v,
  127                                   std::declval<const FormatConversionSpec&>(),
  128                                   std::declval<FormatSink*>())) {
  129   using FormatConversionSpecT =
  130       absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatConversionSpec>;
  131   using FormatSinkT =
  132       absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatSink>;
  133   auto fcs = conv.Wrap<FormatConversionSpecT>();
  134   auto fs = sink->Wrap<FormatSinkT>();
  135   return AbslFormatConvert(v, fcs, &fs);
  136 }
  137 
  138 template <typename T>
  139 auto FormatConvertImpl(const T& v, FormatConversionSpecImpl conv,
  140                        FormatSinkImpl* sink)
  141     -> std::enable_if_t<std::is_enum<T>::value &&
  142                             std::is_void<decltype(AbslStringify(
  143                                 std::declval<FormatSink&>(), v))>::value,
  144                         IntegralConvertResult> {
  145   if (conv.conversion_char() == FormatConversionCharInternal::v) {
  146     using FormatSinkT =
  147         absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatSink>;
  148     auto fs = sink->Wrap<FormatSinkT>();
  149     AbslStringify(fs, v);
  150     return {true};
  151   } else {
  152     return {ConvertIntArg(
  153         static_cast<typename std::underlying_type<T>::type>(v), conv, sink)};
  154   }
  155 }
  156 
  157 template <typename T>
  158 auto FormatConvertImpl(const T& v, FormatConversionSpecImpl,
  159                        FormatSinkImpl* sink)
  160     -> std::enable_if_t<!std::is_enum<T>::value &&
  161                             std::is_void<decltype(AbslStringify(
  162                                 std::declval<FormatSink&>(), v))>::value,
  163                         ArgConvertResult<FormatConversionCharSetInternal::v>> {
  164   using FormatSinkT =
  165       absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatSink>;
  166   auto fs = sink->Wrap<FormatSinkT>();
  167   AbslStringify(fs, v);
  168   return {true};
  169 }
  170 
  171 template <typename T>
  172 class StreamedWrapper;
  173 
  174 // If 'v' can be converted (in the printf sense) according to 'conv',
  175 // then convert it, appending to `sink` and return `true`.
  176 // Otherwise fail and return `false`.
  177 
  178 // AbslFormatConvert(v, conv, sink) is intended to be found by ADL on 'v'
  179 // as an extension mechanism. These FormatConvertImpl functions are the default
  180 // implementations.
  181 // The ADL search is augmented via the 'Sink*' parameter, which also
  182 // serves as a disambiguator to reject possible unintended 'AbslFormatConvert'
  183 // functions in the namespaces associated with 'v'.
  184 
  185 // Raw pointers.
  186 struct VoidPtr {
  187   VoidPtr() = default;
  188   template <typename T,
  189             decltype(reinterpret_cast<uintptr_t>(std::declval<T*>())) = 0>
  190   VoidPtr(T* ptr)  // NOLINT
  191       : value(ptr ? reinterpret_cast<uintptr_t>(ptr) : 0) {}
  192   uintptr_t value;
  193 };
  194 
  195 template <FormatConversionCharSet C>
  196 constexpr FormatConversionCharSet ExtractCharSet(FormatConvertResult<C>) {
  197   return C;
  198 }
  199 
  200 template <FormatConversionCharSet C>
  201 constexpr FormatConversionCharSet ExtractCharSet(ArgConvertResult<C>) {
  202   return C;
  203 }
  204 
  205 using StringConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
  206     FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::v)>;
  207 ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
  208     VoidPtr v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
  209 
  210 // Strings.
  211 StringConvertResult FormatConvertImpl(const std::string& v,
  212                                       FormatConversionSpecImpl conv,
  213                                       FormatSinkImpl* sink);
  214 StringConvertResult FormatConvertImpl(string_view v,
  215                                       FormatConversionSpecImpl conv,
  216                                       FormatSinkImpl* sink);
  217 #if defined(ABSL_HAVE_STD_STRING_VIEW) && !defined(ABSL_USES_STD_STRING_VIEW)
  218 inline StringConvertResult FormatConvertImpl(std::string_view v,
  219                                              FormatConversionSpecImpl conv,
  220                                              FormatSinkImpl* sink) {
  221   return FormatConvertImpl(absl::string_view(v.data(), v.size()), conv, sink);
  222 }
  223 #endif  // ABSL_HAVE_STD_STRING_VIEW && !ABSL_USES_STD_STRING_VIEW
  224 
  225 ArgConvertResult<FormatConversionCharSetUnion(
  226     FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
  227 FormatConvertImpl(const char* v, const FormatConversionSpecImpl conv,
  228                   FormatSinkImpl* sink);
  229 
  230 template <class AbslCord, typename std::enable_if<std::is_same<
  231                               AbslCord, absl::Cord>::value>::type* = nullptr>
  232 StringConvertResult FormatConvertImpl(const AbslCord& value,
  233                                       FormatConversionSpecImpl conv,
  234                                       FormatSinkImpl* sink) {
  235   bool is_left = conv.has_left_flag();
  236   size_t space_remaining = 0;
  237 
  238   int width = conv.width();
  239   if (width >= 0) space_remaining = static_cast<size_t>(width);
  240 
  241   size_t to_write = value.size();
  242 
  243   int precision = conv.precision();
  244   if (precision >= 0)
  245     to_write = (std::min)(to_write, static_cast<size_t>(precision));
  246 
  247   space_remaining = Excess(to_write, space_remaining);
  248 
  249   if (space_remaining > 0 && !is_left) sink->Append(space_remaining, ' ');
  250 
  251   for (string_view piece : value.Chunks()) {
  252     if (piece.size() > to_write) {
  253       piece.remove_suffix(piece.size() - to_write);
  254       to_write = 0;
  255     } else {
  256       to_write -= piece.size();
  257     }
  258     sink->Append(piece);
  259     if (to_write == 0) {
  260       break;
  261     }
  262   }
  263 
  264   if (space_remaining > 0 && is_left) sink->Append(space_remaining, ' ');
  265   return {true};
  266 }
  267 
  268 bool ConvertBoolArg(bool v, FormatSinkImpl* sink);
  269 
  270 // Floats.
  271 FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv,
  272                                         FormatSinkImpl* sink);
  273 FloatingConvertResult FormatConvertImpl(double v, FormatConversionSpecImpl conv,
  274                                         FormatSinkImpl* sink);
  275 FloatingConvertResult FormatConvertImpl(long double v,
  276                                         FormatConversionSpecImpl conv,
  277                                         FormatSinkImpl* sink);
  278 
  279 // Chars.
  280 CharConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv,
  281                                     FormatSinkImpl* sink);
  282 
  283 // Ints.
  284 IntegralConvertResult FormatConvertImpl(signed char v,
  285                                         FormatConversionSpecImpl conv,
  286                                         FormatSinkImpl* sink);
  287 IntegralConvertResult FormatConvertImpl(unsigned char v,
  288                                         FormatConversionSpecImpl conv,
  289                                         FormatSinkImpl* sink);
  290 IntegralConvertResult FormatConvertImpl(short v,  // NOLINT
  291                                         FormatConversionSpecImpl conv,
  292                                         FormatSinkImpl* sink);
  293 IntegralConvertResult FormatConvertImpl(unsigned short v,  // NOLINT
  294                                         FormatConversionSpecImpl conv,
  295                                         FormatSinkImpl* sink);
  296 IntegralConvertResult FormatConvertImpl(int v, FormatConversionSpecImpl conv,
  297                                         FormatSinkImpl* sink);
  298 IntegralConvertResult FormatConvertImpl(unsigned v,
  299                                         FormatConversionSpecImpl conv,
  300                                         FormatSinkImpl* sink);
  301 IntegralConvertResult FormatConvertImpl(long v,  // NOLINT
  302                                         FormatConversionSpecImpl conv,
  303                                         FormatSinkImpl* sink);
  304 IntegralConvertResult FormatConvertImpl(unsigned long v,  // NOLINT
  305                                         FormatConversionSpecImpl conv,
  306                                         FormatSinkImpl* sink);
  307 IntegralConvertResult FormatConvertImpl(long long v,  // NOLINT
  308                                         FormatConversionSpecImpl conv,
  309                                         FormatSinkImpl* sink);
  310 IntegralConvertResult FormatConvertImpl(unsigned long long v,  // NOLINT
  311                                         FormatConversionSpecImpl conv,
  312                                         FormatSinkImpl* sink);
  313 IntegralConvertResult FormatConvertImpl(int128 v, FormatConversionSpecImpl conv,
  314                                         FormatSinkImpl* sink);
  315 IntegralConvertResult FormatConvertImpl(uint128 v,
  316                                         FormatConversionSpecImpl conv,
  317                                         FormatSinkImpl* sink);
  318 
  319 // This function needs to be a template due to ambiguity regarding type
  320 // conversions.
  321 template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0>
  322 IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv,
  323                                         FormatSinkImpl* sink) {
  324   if (conv.conversion_char() == FormatConversionCharInternal::v) {
  325     return {ConvertBoolArg(v, sink)};
  326   }
  327 
  328   return FormatConvertImpl(static_cast<int>(v), conv, sink);
  329 }
  330 
  331 // We provide this function to help the checker, but it is never defined.
  332 // FormatArgImpl will use the underlying Convert functions instead.
  333 template <typename T>
  334 typename std::enable_if<std::is_enum<T>::value &&
  335                             !HasUserDefinedConvert<T>::value &&
  336                             !strings_internal::HasAbslStringify<T>::value,
  337                         IntegralConvertResult>::type
  338 FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
  339 
  340 template <typename T>
  341 StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v,
  342                                       FormatConversionSpecImpl conv,
  343                                       FormatSinkImpl* out) {
  344   std::ostringstream oss;
  345   oss << v.v_;
  346   if (!oss) return {false};
  347   return str_format_internal::FormatConvertImpl(oss.str(), conv, out);
  348 }
  349 
  350 // Use templates and dependent types to delay evaluation of the function
  351 // until after FormatCountCapture is fully defined.
  352 struct FormatCountCaptureHelper {
  353   template <class T = int>
  354   static ArgConvertResult<FormatConversionCharSetInternal::n> ConvertHelper(
  355       const FormatCountCapture& v, FormatConversionSpecImpl conv,
  356       FormatSinkImpl* sink) {
  357     const absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v;
  358 
  359     if (conv.conversion_char() !=
  360         str_format_internal::FormatConversionCharInternal::n) {
  361       return {false};
  362     }
  363     *v2.p_ = static_cast<int>(sink->size());
  364     return {true};
  365   }
  366 };
  367 
  368 template <class T = int>
  369 ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl(
  370     const FormatCountCapture& v, FormatConversionSpecImpl conv,
  371     FormatSinkImpl* sink) {
  372   return FormatCountCaptureHelper::ConvertHelper(v, conv, sink);
  373 }
  374 
  375 // Helper friend struct to hide implementation details from the public API of
  376 // FormatArgImpl.
  377 struct FormatArgImplFriend {
  378   template <typename Arg>
  379   static bool ToInt(Arg arg, int* out) {
  380     // A value initialized FormatConversionSpecImpl has a `none` conv, which
  381     // tells the dispatcher to run the `int` conversion.
  382     return arg.dispatcher_(arg.data_, {}, out);
  383   }
  384 
  385   template <typename Arg>
  386   static bool Convert(Arg arg, FormatConversionSpecImpl conv,
  387                       FormatSinkImpl* out) {
  388     return arg.dispatcher_(arg.data_, conv, out);
  389   }
  390 
  391   template <typename Arg>
  392   static typename Arg::Dispatcher GetVTablePtrForTest(Arg arg) {
  393     return arg.dispatcher_;
  394   }
  395 };
  396 
  397 template <typename Arg>
  398 constexpr FormatConversionCharSet ArgumentToConv() {
  399   using ConvResult = decltype(str_format_internal::FormatConvertImpl(
  400       std::declval<const Arg&>(),
  401       std::declval<const FormatConversionSpecImpl&>(),
  402       std::declval<FormatSinkImpl*>()));
  403   return absl::str_format_internal::ExtractCharSet(ConvResult{});
  404 }
  405 
  406 // A type-erased handle to a format argument.
  407 class FormatArgImpl {
  408  private:
  409   enum { kInlinedSpace = 8 };
  410 
  411   using VoidPtr = str_format_internal::VoidPtr;
  412 
  413   union Data {
  414     const void* ptr;
  415     const volatile void* volatile_ptr;
  416     char buf[kInlinedSpace];
  417   };
  418 
  419   using Dispatcher = bool (*)(Data, FormatConversionSpecImpl, void* out);
  420 
  421   template <typename T>
  422   struct store_by_value
  423       : std::integral_constant<bool, (sizeof(T) <= kInlinedSpace) &&
  424                                          (std::is_integral<T>::value ||
  425                                           std::is_floating_point<T>::value ||
  426                                           std::is_pointer<T>::value ||
  427                                           std::is_same<VoidPtr, T>::value)> {};
  428 
  429   enum StoragePolicy { ByPointer, ByVolatilePointer, ByValue };
  430   template <typename T>
  431   struct storage_policy
  432       : std::integral_constant<StoragePolicy,
  433                                (std::is_volatile<T>::value
  434                                     ? ByVolatilePointer
  435                                     : (store_by_value<T>::value ? ByValue
  436                                                                 : ByPointer))> {
  437   };
  438 
  439   // To reduce the number of vtables we will decay values before hand.
  440   // Anything with a user-defined Convert will get its own vtable.
  441   // For everything else:
  442   //   - Decay char* and char arrays into `const char*`
  443   //   - Decay any other pointer to `const void*`
  444   //   - Decay all enums to the integral promotion of their underlying type.
  445   //   - Decay function pointers to void*.
  446   template <typename T, typename = void>
  447   struct DecayType {
  448     static constexpr bool kHasUserDefined =
  449         str_format_internal::HasUserDefinedConvert<T>::value ||
  450         strings_internal::HasAbslStringify<T>::value;
  451     using type = typename std::conditional<
  452         !kHasUserDefined && std::is_convertible<T, const char*>::value,
  453         const char*,
  454         typename std::conditional<!kHasUserDefined &&
  455                                       std::is_convertible<T, VoidPtr>::value,
  456                                   VoidPtr, const T&>::type>::type;
  457   };
  458   template <typename T>
  459   struct DecayType<T,
  460                    typename std::enable_if<
  461                        !str_format_internal::HasUserDefinedConvert<T>::value &&
  462                        !strings_internal::HasAbslStringify<T>::value &&
  463                        std::is_enum<T>::value>::type> {
  464     using type = decltype(+typename std::underlying_type<T>::type());
  465   };
  466 
  467  public:
  468   template <typename T>
  469   explicit FormatArgImpl(const T& value) {
  470     using D = typename DecayType<T>::type;
  471     static_assert(
  472         std::is_same<D, const T&>::value || storage_policy<D>::value == ByValue,
  473         "Decayed types must be stored by value");
  474     Init(static_cast<D>(value));
  475   }
  476 
  477  private:
  478   friend struct str_format_internal::FormatArgImplFriend;
  479   template <typename T, StoragePolicy = storage_policy<T>::value>
  480   struct Manager;
  481 
  482   template <typename T>
  483   struct Manager<T, ByPointer> {
  484     static Data SetValue(const T& value) {
  485       Data data;
  486       data.ptr = std::addressof(value);
  487       return data;
  488     }
  489 
  490     static const T& Value(Data arg) { return *static_cast<const T*>(arg.ptr); }
  491   };
  492 
  493   template <typename T>
  494   struct Manager<T, ByVolatilePointer> {
  495     static Data SetValue(const T& value) {
  496       Data data;
  497       data.volatile_ptr = &value;
  498       return data;
  499     }
  500 
  501     static const T& Value(Data arg) {
  502       return *static_cast<const T*>(arg.volatile_ptr);
  503     }
  504   };
  505 
  506   template <typename T>
  507   struct Manager<T, ByValue> {
  508     static Data SetValue(const T& value) {
  509       Data data;
  510       memcpy(data.buf, &value, sizeof(value));
  511       return data;
  512     }
  513 
  514     static T Value(Data arg) {
  515       T value;
  516       memcpy(&value, arg.buf, sizeof(T));
  517       return value;
  518     }
  519   };
  520 
  521   template <typename T>
  522   void Init(const T& value) {
  523     data_ = Manager<T>::SetValue(value);
  524     dispatcher_ = &Dispatch<T>;
  525   }
  526 
  527   template <typename T>
  528   static int ToIntVal(const T& val) {
  529     using CommonType = typename std::conditional<std::is_signed<T>::value,
  530                                                  int64_t, uint64_t>::type;
  531     if (static_cast<CommonType>(val) >
  532         static_cast<CommonType>((std::numeric_limits<int>::max)())) {
  533       return (std::numeric_limits<int>::max)();
  534     } else if (std::is_signed<T>::value &&
  535                static_cast<CommonType>(val) <
  536                    static_cast<CommonType>((std::numeric_limits<int>::min)())) {
  537       return (std::numeric_limits<int>::min)();
  538     }
  539     return static_cast<int>(val);
  540   }
  541 
  542   template <typename T>
  543   static bool ToInt(Data arg, int* out, std::true_type /* is_integral */,
  544                     std::false_type) {
  545     *out = ToIntVal(Manager<T>::Value(arg));
  546     return true;
  547   }
  548 
  549   template <typename T>
  550   static bool ToInt(Data arg, int* out, std::false_type,
  551                     std::true_type /* is_enum */) {
  552     *out = ToIntVal(static_cast<typename std::underlying_type<T>::type>(
  553         Manager<T>::Value(arg)));
  554     return true;
  555   }
  556 
  557   template <typename T>
  558   static bool ToInt(Data, int*, std::false_type, std::false_type) {
  559     return false;
  560   }
  561 
  562   template <typename T>
  563   static bool Dispatch(Data arg, FormatConversionSpecImpl spec, void* out) {
  564     // A `none` conv indicates that we want the `int` conversion.
  565     if (ABSL_PREDICT_FALSE(spec.conversion_char() ==
  566                            FormatConversionCharInternal::kNone)) {
  567       return ToInt<T>(arg, static_cast<int*>(out), std::is_integral<T>(),
  568                       std::is_enum<T>());
  569     }
  570     if (ABSL_PREDICT_FALSE(!Contains(ArgumentToConv<T>(),
  571                                      spec.conversion_char()))) {
  572       return false;
  573     }
  574     return str_format_internal::FormatConvertImpl(
  575                Manager<T>::Value(arg), spec,
  576                static_cast<FormatSinkImpl*>(out))
  577         .value;
  578   }
  579 
  580   Data data_;
  581   Dispatcher dispatcher_;
  582 };
  583 
  584 #define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E)                     \
  585   E template bool FormatArgImpl::Dispatch<T>(Data, FormatConversionSpecImpl, \
  586                                              void*)
  587 
  588 #define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...)                   \
  589   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr,     \
  590                                              __VA_ARGS__);                     \
  591   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(bool, __VA_ARGS__);               \
  592   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(char, __VA_ARGS__);               \
  593   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(signed char, __VA_ARGS__);        \
  594   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned char, __VA_ARGS__);      \
  595   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(short, __VA_ARGS__); /* NOLINT */ \
  596   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned short,      /* NOLINT */ \
  597                                              __VA_ARGS__);                     \
  598   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int, __VA_ARGS__);                \
  599   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned int, __VA_ARGS__);       \
  600   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long, __VA_ARGS__); /* NOLINT */  \
  601   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long,      /* NOLINT */  \
  602                                              __VA_ARGS__);                     \
  603   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long long, /* NOLINT */           \
  604                                              __VA_ARGS__);                     \
  605   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long long, /* NOLINT */  \
  606                                              __VA_ARGS__);                     \
  607   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int128, __VA_ARGS__);             \
  608   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(uint128, __VA_ARGS__);            \
  609   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(float, __VA_ARGS__);              \
  610   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(double, __VA_ARGS__);             \
  611   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long double, __VA_ARGS__);        \
  612   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(const char*, __VA_ARGS__);        \
  613   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::string, __VA_ARGS__);        \
  614   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(string_view, __VA_ARGS__)
  615 
  616 ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern);
  617 
  618 
  619 }  // namespace str_format_internal
  620 ABSL_NAMESPACE_END
  621 }  // namespace absl
  622 
  623 #endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_