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