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