1 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ 2 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ 3 4 #include <string.h> 5 #include <wchar.h> 6 7 #include <cstdio> 8 #include <iomanip> 9 #include <limits> 10 #include <memory> 11 #include <sstream> 12 #include <string> 13 #include <type_traits> 14 15 #include "absl/base/port.h" 16 #include "absl/meta/type_traits.h" 17 #include "absl/numeric/int128.h" 18 #include "absl/strings/internal/str_format/extension.h" 19 #include "absl/strings/string_view.h" 20 21 namespace absl { 22 ABSL_NAMESPACE_BEGIN 23 24 class Cord; 25 class FormatCountCapture; 26 class FormatSink; 27 28 template <absl::FormatConversionCharSet C> 29 struct FormatConvertResult; 30 class FormatConversionSpec; 31 32 namespace str_format_internal { 33 34 template <typename T, typename = void> 35 struct HasUserDefinedConvert : std::false_type {}; 36 37 template <typename T> 38 struct HasUserDefinedConvert<T, void_t<decltype(AbslFormatConvert( 39 std::declval<const T&>(), 40 std::declval<const FormatConversionSpec&>(), 41 std::declval<FormatSink*>()))>> 42 : std::true_type {}; 43 44 void AbslFormatConvert(); // Stops the lexical name lookup 45 template <typename T> 46 auto FormatConvertImpl(const T& v, FormatConversionSpecImpl conv, 47 FormatSinkImpl* sink) 48 -> decltype(AbslFormatConvert(v, 49 std::declval<const FormatConversionSpec&>(), 50 std::declval<FormatSink*>())) { 51 using FormatConversionSpecT = 52 absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatConversionSpec>; 53 using FormatSinkT = 54 absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatSink>; 55 auto fcs = conv.Wrap<FormatConversionSpecT>(); 56 auto fs = sink->Wrap<FormatSinkT>(); 57 return AbslFormatConvert(v, fcs, &fs); 58 } 59 60 template <typename T> 61 class StreamedWrapper; 62 63 // If 'v' can be converted (in the printf sense) according to 'conv', 64 // then convert it, appending to `sink` and return `true`. 65 // Otherwise fail and return `false`. 66 67 // AbslFormatConvert(v, conv, sink) is intended to be found by ADL on 'v' 68 // as an extension mechanism. These FormatConvertImpl functions are the default 69 // implementations. 70 // The ADL search is augmented via the 'Sink*' parameter, which also 71 // serves as a disambiguator to reject possible unintended 'AbslFormatConvert' 72 // functions in the namespaces associated with 'v'. 73 74 // Raw pointers. 75 struct VoidPtr { 76 VoidPtr() = default; 77 template <typename T, 78 decltype(reinterpret_cast<uintptr_t>(std::declval<T*>())) = 0> 79 VoidPtr(T* ptr) // NOLINT 80 : value(ptr ? reinterpret_cast<uintptr_t>(ptr) : 0) {} 81 uintptr_t value; 82 }; 83 84 template <FormatConversionCharSet C> 85 struct ArgConvertResult { 86 bool value; 87 }; 88 89 template <FormatConversionCharSet C> 90 constexpr FormatConversionCharSet ExtractCharSet(FormatConvertResult<C>) { 91 return C; 92 } 93 94 template <FormatConversionCharSet C> 95 constexpr FormatConversionCharSet ExtractCharSet(ArgConvertResult<C>) { 96 return C; 97 } 98 99 using StringConvertResult = 100 ArgConvertResult<FormatConversionCharSetInternal::s>; 101 ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl( 102 VoidPtr v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); 103 104 // Strings. 105 StringConvertResult FormatConvertImpl(const std::string& v, 106 FormatConversionSpecImpl conv, 107 FormatSinkImpl* sink); 108 StringConvertResult FormatConvertImpl(string_view v, 109 FormatConversionSpecImpl conv, 110 FormatSinkImpl* sink); 111 ArgConvertResult<FormatConversionCharSetUnion( 112 FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)> 113 FormatConvertImpl(const char* v, const FormatConversionSpecImpl conv, 114 FormatSinkImpl* sink); 115 116 template <class AbslCord, typename std::enable_if<std::is_same< 117 AbslCord, absl::Cord>::value>::type* = nullptr> 118 StringConvertResult FormatConvertImpl(const AbslCord& value, 119 FormatConversionSpecImpl conv, 120 FormatSinkImpl* sink) { 121 bool is_left = conv.has_left_flag(); 122 size_t space_remaining = 0; 123 124 int width = conv.width(); 125 if (width >= 0) space_remaining = width; 126 127 size_t to_write = value.size(); 128 129 int precision = conv.precision(); 130 if (precision >= 0) 131 to_write = (std::min)(to_write, static_cast<size_t>(precision)); 132 133 space_remaining = Excess(to_write, space_remaining); 134 135 if (space_remaining > 0 && !is_left) sink->Append(space_remaining, ' '); 136 137 for (string_view piece : value.Chunks()) { 138 if (piece.size() > to_write) { 139 piece.remove_suffix(piece.size() - to_write); 140 to_write = 0; 141 } else { 142 to_write -= piece.size(); 143 } 144 sink->Append(piece); 145 if (to_write == 0) { 146 break; 147 } 148 } 149 150 if (space_remaining > 0 && is_left) sink->Append(space_remaining, ' '); 151 return {true}; 152 } 153 154 using IntegralConvertResult = ArgConvertResult<FormatConversionCharSetUnion( 155 FormatConversionCharSetInternal::c, 156 FormatConversionCharSetInternal::kNumeric, 157 FormatConversionCharSetInternal::kStar)>; 158 using FloatingConvertResult = 159 ArgConvertResult<FormatConversionCharSetInternal::kFloating>; 160 161 // Floats. 162 FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv, 163 FormatSinkImpl* sink); 164 FloatingConvertResult FormatConvertImpl(double v, FormatConversionSpecImpl conv, 165 FormatSinkImpl* sink); 166 FloatingConvertResult FormatConvertImpl(long double v, 167 FormatConversionSpecImpl conv, 168 FormatSinkImpl* sink); 169 170 // Chars. 171 IntegralConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv, 172 FormatSinkImpl* sink); 173 IntegralConvertResult FormatConvertImpl(signed char v, 174 FormatConversionSpecImpl conv, 175 FormatSinkImpl* sink); 176 IntegralConvertResult FormatConvertImpl(unsigned char v, 177 FormatConversionSpecImpl conv, 178 FormatSinkImpl* sink); 179 180 // Ints. 181 IntegralConvertResult FormatConvertImpl(short v, // NOLINT 182 FormatConversionSpecImpl conv, 183 FormatSinkImpl* sink); 184 IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT 185 FormatConversionSpecImpl conv, 186 FormatSinkImpl* sink); 187 IntegralConvertResult FormatConvertImpl(int v, FormatConversionSpecImpl conv, 188 FormatSinkImpl* sink); 189 IntegralConvertResult FormatConvertImpl(unsigned v, 190 FormatConversionSpecImpl conv, 191 FormatSinkImpl* sink); 192 IntegralConvertResult FormatConvertImpl(long v, // NOLINT 193 FormatConversionSpecImpl conv, 194 FormatSinkImpl* sink); 195 IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT 196 FormatConversionSpecImpl conv, 197 FormatSinkImpl* sink); 198 IntegralConvertResult FormatConvertImpl(long long v, // NOLINT 199 FormatConversionSpecImpl conv, 200 FormatSinkImpl* sink); 201 IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT 202 FormatConversionSpecImpl conv, 203 FormatSinkImpl* sink); 204 IntegralConvertResult FormatConvertImpl(int128 v, FormatConversionSpecImpl conv, 205 FormatSinkImpl* sink); 206 IntegralConvertResult FormatConvertImpl(uint128 v, 207 FormatConversionSpecImpl conv, 208 FormatSinkImpl* sink); 209 template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0> 210 IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv, 211 FormatSinkImpl* sink) { 212 return FormatConvertImpl(static_cast<int>(v), conv, sink); 213 } 214 215 // We provide this function to help the checker, but it is never defined. 216 // FormatArgImpl will use the underlying Convert functions instead. 217 template <typename T> 218 typename std::enable_if<std::is_enum<T>::value && 219 !HasUserDefinedConvert<T>::value, 220 IntegralConvertResult>::type 221 FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); 222 223 template <typename T> 224 StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v, 225 FormatConversionSpecImpl conv, 226 FormatSinkImpl* out) { 227 std::ostringstream oss; 228 oss << v.v_; 229 if (!oss) return {false}; 230 return str_format_internal::FormatConvertImpl(oss.str(), conv, out); 231 } 232 233 // Use templates and dependent types to delay evaluation of the function 234 // until after FormatCountCapture is fully defined. 235 struct FormatCountCaptureHelper { 236 template <class T = int> 237 static ArgConvertResult<FormatConversionCharSetInternal::n> ConvertHelper( 238 const FormatCountCapture& v, FormatConversionSpecImpl conv, 239 FormatSinkImpl* sink) { 240 const absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v; 241 242 if (conv.conversion_char() != 243 str_format_internal::FormatConversionCharInternal::n) { 244 return {false}; 245 } 246 *v2.p_ = static_cast<int>(sink->size()); 247 return {true}; 248 } 249 }; 250 251 template <class T = int> 252 ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl( 253 const FormatCountCapture& v, FormatConversionSpecImpl conv, 254 FormatSinkImpl* sink) { 255 return FormatCountCaptureHelper::ConvertHelper(v, conv, sink); 256 } 257 258 // Helper friend struct to hide implementation details from the public API of 259 // FormatArgImpl. 260 struct FormatArgImplFriend { 261 template <typename Arg> 262 static bool ToInt(Arg arg, int* out) { 263 // A value initialized FormatConversionSpecImpl has a `none` conv, which 264 // tells the dispatcher to run the `int` conversion. 265 return arg.dispatcher_(arg.data_, {}, out); 266 } 267 268 template <typename Arg> 269 static bool Convert(Arg arg, FormatConversionSpecImpl conv, 270 FormatSinkImpl* out) { 271 return arg.dispatcher_(arg.data_, conv, out); 272 } 273 274 template <typename Arg> 275 static typename Arg::Dispatcher GetVTablePtrForTest(Arg arg) { 276 return arg.dispatcher_; 277 } 278 }; 279 280 template <typename Arg> 281 constexpr FormatConversionCharSet ArgumentToConv() { 282 return absl::str_format_internal::ExtractCharSet( 283 decltype(str_format_internal::FormatConvertImpl( 284 std::declval<const Arg&>(), 285 std::declval<const FormatConversionSpecImpl&>(), 286 std::declval<FormatSinkImpl*>())){}); 287 } 288 289 // A type-erased handle to a format argument. 290 class FormatArgImpl { 291 private: 292 enum { kInlinedSpace = 8 }; 293 294 using VoidPtr = str_format_internal::VoidPtr; 295 296 union Data { 297 const void* ptr; 298 const volatile void* volatile_ptr; 299 char buf[kInlinedSpace]; 300 }; 301 302 using Dispatcher = bool (*)(Data, FormatConversionSpecImpl, void* out); 303 304 template <typename T> 305 struct store_by_value 306 : std::integral_constant<bool, (sizeof(T) <= kInlinedSpace) && 307 (std::is_integral<T>::value || 308 std::is_floating_point<T>::value || 309 std::is_pointer<T>::value || 310 std::is_same<VoidPtr, T>::value)> {}; 311 312 enum StoragePolicy { ByPointer, ByVolatilePointer, ByValue }; 313 template <typename T> 314 struct storage_policy 315 : std::integral_constant<StoragePolicy, 316 (std::is_volatile<T>::value 317 ? ByVolatilePointer 318 : (store_by_value<T>::value ? ByValue 319 : ByPointer))> { 320 }; 321 322 // To reduce the number of vtables we will decay values before hand. 323 // Anything with a user-defined Convert will get its own vtable. 324 // For everything else: 325 // - Decay char* and char arrays into `const char*` 326 // - Decay any other pointer to `const void*` 327 // - Decay all enums to their underlying type. 328 // - Decay function pointers to void*. 329 template <typename T, typename = void> 330 struct DecayType { 331 static constexpr bool kHasUserDefined = 332 str_format_internal::HasUserDefinedConvert<T>::value; 333 using type = typename std::conditional< 334 !kHasUserDefined && std::is_convertible<T, const char*>::value, 335 const char*, 336 typename std::conditional<!kHasUserDefined && 337 std::is_convertible<T, VoidPtr>::value, 338 VoidPtr, const T&>::type>::type; 339 }; 340 template <typename T> 341 struct DecayType<T, 342 typename std::enable_if< 343 !str_format_internal::HasUserDefinedConvert<T>::value && 344 std::is_enum<T>::value>::type> { 345 using type = typename std::underlying_type<T>::type; 346 }; 347 348 public: 349 template <typename T> 350 explicit FormatArgImpl(const T& value) { 351 using D = typename DecayType<T>::type; 352 static_assert( 353 std::is_same<D, const T&>::value || storage_policy<D>::value == ByValue, 354 "Decayed types must be stored by value"); 355 Init(static_cast<D>(value)); 356 } 357 358 private: 359 friend struct str_format_internal::FormatArgImplFriend; 360 template <typename T, StoragePolicy = storage_policy<T>::value> 361 struct Manager; 362 363 template <typename T> 364 struct Manager<T, ByPointer> { 365 static Data SetValue(const T& value) { 366 Data data; 367 data.ptr = std::addressof(value); 368 return data; 369 } 370 371 static const T& Value(Data arg) { return *static_cast<const T*>(arg.ptr); } 372 }; 373 374 template <typename T> 375 struct Manager<T, ByVolatilePointer> { 376 static Data SetValue(const T& value) { 377 Data data; 378 data.volatile_ptr = &value; 379 return data; 380 } 381 382 static const T& Value(Data arg) { 383 return *static_cast<const T*>(arg.volatile_ptr); 384 } 385 }; 386 387 template <typename T> 388 struct Manager<T, ByValue> { 389 static Data SetValue(const T& value) { 390 Data data; 391 memcpy(data.buf, &value, sizeof(value)); 392 return data; 393 } 394 395 static T Value(Data arg) { 396 T value; 397 memcpy(&value, arg.buf, sizeof(T)); 398 return value; 399 } 400 }; 401 402 template <typename T> 403 void Init(const T& value) { 404 data_ = Manager<T>::SetValue(value); 405 dispatcher_ = &Dispatch<T>; 406 } 407 408 template <typename T> 409 static int ToIntVal(const T& val) { 410 using CommonType = typename std::conditional<std::is_signed<T>::value, 411 int64_t, uint64_t>::type; 412 if (static_cast<CommonType>(val) > 413 static_cast<CommonType>((std::numeric_limits<int>::max)())) { 414 return (std::numeric_limits<int>::max)(); 415 } else if (std::is_signed<T>::value && 416 static_cast<CommonType>(val) < 417 static_cast<CommonType>((std::numeric_limits<int>::min)())) { 418 return (std::numeric_limits<int>::min)(); 419 } 420 return static_cast<int>(val); 421 } 422 423 template <typename T> 424 static bool ToInt(Data arg, int* out, std::true_type /* is_integral */, 425 std::false_type) { 426 *out = ToIntVal(Manager<T>::Value(arg)); 427 return true; 428 } 429 430 template <typename T> 431 static bool ToInt(Data arg, int* out, std::false_type, 432 std::true_type /* is_enum */) { 433 *out = ToIntVal(static_cast<typename std::underlying_type<T>::type>( 434 Manager<T>::Value(arg))); 435 return true; 436 } 437 438 template <typename T> 439 static bool ToInt(Data, int*, std::false_type, std::false_type) { 440 return false; 441 } 442 443 template <typename T> 444 static bool Dispatch(Data arg, FormatConversionSpecImpl spec, void* out) { 445 // A `none` conv indicates that we want the `int` conversion. 446 if (ABSL_PREDICT_FALSE(spec.conversion_char() == 447 FormatConversionCharInternal::kNone)) { 448 return ToInt<T>(arg, static_cast<int*>(out), std::is_integral<T>(), 449 std::is_enum<T>()); 450 } 451 if (ABSL_PREDICT_FALSE(!Contains(ArgumentToConv<T>(), 452 spec.conversion_char()))) { 453 return false; 454 } 455 return str_format_internal::FormatConvertImpl( 456 Manager<T>::Value(arg), spec, 457 static_cast<FormatSinkImpl*>(out)) 458 .value; 459 } 460 461 Data data_; 462 Dispatcher dispatcher_; 463 }; 464 465 #define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \ 466 E template bool FormatArgImpl::Dispatch<T>(Data, FormatConversionSpecImpl, \ 467 void*) 468 469 #define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...) \ 470 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr, \ 471 __VA_ARGS__); \ 472 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(bool, __VA_ARGS__); \ 473 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(char, __VA_ARGS__); \ 474 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(signed char, __VA_ARGS__); \ 475 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned char, __VA_ARGS__); \ 476 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(short, __VA_ARGS__); /* NOLINT */ \ 477 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned short, /* NOLINT */ \ 478 __VA_ARGS__); \ 479 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int, __VA_ARGS__); \ 480 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned int, __VA_ARGS__); \ 481 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long, __VA_ARGS__); /* NOLINT */ \ 482 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long, /* NOLINT */ \ 483 __VA_ARGS__); \ 484 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long long, /* NOLINT */ \ 485 __VA_ARGS__); \ 486 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long long, /* NOLINT */ \ 487 __VA_ARGS__); \ 488 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int128, __VA_ARGS__); \ 489 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(uint128, __VA_ARGS__); \ 490 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(float, __VA_ARGS__); \ 491 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(double, __VA_ARGS__); \ 492 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long double, __VA_ARGS__); \ 493 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(const char*, __VA_ARGS__); \ 494 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::string, __VA_ARGS__); \ 495 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(string_view, __VA_ARGS__) 496 497 ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern); 498 499 500 } // namespace str_format_internal 501 ABSL_NAMESPACE_END 502 } // namespace absl 503 504 #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ 505