"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:
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_