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