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 namespace str_format_internal { 29 30 template <typename T, typename = void> 31 struct HasUserDefinedConvert : std::false_type {}; 32 33 template <typename T> 34 struct HasUserDefinedConvert< 35 T, void_t<decltype(AbslFormatConvert( 36 std::declval<const T&>(), std::declval<ConversionSpec>(), 37 std::declval<FormatSink*>()))>> : std::true_type {}; 38 39 template <typename T> 40 class StreamedWrapper; 41 42 // If 'v' can be converted (in the printf sense) according to 'conv', 43 // then convert it, appending to `sink` and return `true`. 44 // Otherwise fail and return `false`. 45 46 // Raw pointers. 47 struct VoidPtr { 48 VoidPtr() = default; 49 template <typename T, 50 decltype(reinterpret_cast<uintptr_t>(std::declval<T*>())) = 0> 51 VoidPtr(T* ptr) // NOLINT 52 : value(ptr ? reinterpret_cast<uintptr_t>(ptr) : 0) {} 53 uintptr_t value; 54 }; 55 ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, ConversionSpec conv, 56 FormatSinkImpl* sink); 57 58 // Strings. 59 ConvertResult<Conv::s> FormatConvertImpl(const std::string& v, 60 ConversionSpec conv, 61 FormatSinkImpl* sink); 62 ConvertResult<Conv::s> FormatConvertImpl(string_view v, ConversionSpec conv, 63 FormatSinkImpl* sink); 64 ConvertResult<Conv::s | Conv::p> FormatConvertImpl(const char* v, 65 ConversionSpec conv, 66 FormatSinkImpl* sink); 67 template <class AbslCord, 68 typename std::enable_if< 69 std::is_same<AbslCord, absl::Cord>::value>::type* = nullptr> 70 ConvertResult<Conv::s> FormatConvertImpl(const AbslCord& value, 71 ConversionSpec conv, 72 FormatSinkImpl* sink) { 73 if (conv.conv() != ConversionChar::s) return {false}; 74 75 bool is_left = conv.flags().left; 76 size_t space_remaining = 0; 77 78 int width = conv.width(); 79 if (width >= 0) space_remaining = width; 80 81 size_t to_write = value.size(); 82 83 int precision = conv.precision(); 84 if (precision >= 0) 85 to_write = (std::min)(to_write, static_cast<size_t>(precision)); 86 87 space_remaining = Excess(to_write, space_remaining); 88 89 if (space_remaining > 0 && !is_left) sink->Append(space_remaining, ' '); 90 91 for (string_view piece : value.Chunks()) { 92 if (piece.size() > to_write) { 93 piece.remove_suffix(piece.size() - to_write); 94 to_write = 0; 95 } else { 96 to_write -= piece.size(); 97 } 98 sink->Append(piece); 99 if (to_write == 0) { 100 break; 101 } 102 } 103 104 if (space_remaining > 0 && is_left) sink->Append(space_remaining, ' '); 105 return {true}; 106 } 107 108 using IntegralConvertResult = 109 ConvertResult<Conv::c | Conv::numeric | Conv::star>; 110 using FloatingConvertResult = ConvertResult<Conv::floating>; 111 112 // Floats. 113 FloatingConvertResult FormatConvertImpl(float v, ConversionSpec conv, 114 FormatSinkImpl* sink); 115 FloatingConvertResult FormatConvertImpl(double v, ConversionSpec conv, 116 FormatSinkImpl* sink); 117 FloatingConvertResult FormatConvertImpl(long double v, ConversionSpec conv, 118 FormatSinkImpl* sink); 119 120 // Chars. 121 IntegralConvertResult FormatConvertImpl(char v, ConversionSpec conv, 122 FormatSinkImpl* sink); 123 IntegralConvertResult FormatConvertImpl(signed char v, ConversionSpec conv, 124 FormatSinkImpl* sink); 125 IntegralConvertResult FormatConvertImpl(unsigned char v, ConversionSpec conv, 126 FormatSinkImpl* sink); 127 128 // Ints. 129 IntegralConvertResult FormatConvertImpl(short v, // NOLINT 130 ConversionSpec conv, 131 FormatSinkImpl* sink); 132 IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT 133 ConversionSpec conv, 134 FormatSinkImpl* sink); 135 IntegralConvertResult FormatConvertImpl(int v, ConversionSpec conv, 136 FormatSinkImpl* sink); 137 IntegralConvertResult FormatConvertImpl(unsigned v, ConversionSpec conv, 138 FormatSinkImpl* sink); 139 IntegralConvertResult FormatConvertImpl(long v, // NOLINT 140 ConversionSpec conv, 141 FormatSinkImpl* sink); 142 IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT 143 ConversionSpec conv, 144 FormatSinkImpl* sink); 145 IntegralConvertResult FormatConvertImpl(long long v, // NOLINT 146 ConversionSpec conv, 147 FormatSinkImpl* sink); 148 IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT 149 ConversionSpec conv, 150 FormatSinkImpl* sink); 151 IntegralConvertResult FormatConvertImpl(int128 v, ConversionSpec conv, 152 FormatSinkImpl* sink); 153 IntegralConvertResult FormatConvertImpl(uint128 v, ConversionSpec conv, 154 FormatSinkImpl* sink); 155 template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0> 156 IntegralConvertResult FormatConvertImpl(T v, ConversionSpec conv, 157 FormatSinkImpl* sink) { 158 return FormatConvertImpl(static_cast<int>(v), conv, sink); 159 } 160 161 // We provide this function to help the checker, but it is never defined. 162 // FormatArgImpl will use the underlying Convert functions instead. 163 template <typename T> 164 typename std::enable_if<std::is_enum<T>::value && 165 !HasUserDefinedConvert<T>::value, 166 IntegralConvertResult>::type 167 FormatConvertImpl(T v, ConversionSpec conv, FormatSinkImpl* sink); 168 169 template <typename T> 170 ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<T>& v, 171 ConversionSpec conv, 172 FormatSinkImpl* out) { 173 std::ostringstream oss; 174 oss << v.v_; 175 if (!oss) return {false}; 176 return str_format_internal::FormatConvertImpl(oss.str(), conv, out); 177 } 178 179 // Use templates and dependent types to delay evaluation of the function 180 // until after FormatCountCapture is fully defined. 181 struct FormatCountCaptureHelper { 182 template <class T = int> 183 static ConvertResult<Conv::n> ConvertHelper(const FormatCountCapture& v, 184 ConversionSpec conv, 185 FormatSinkImpl* sink) { 186 const absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v; 187 188 if (conv.conv() != str_format_internal::ConversionChar::n) return {false}; 189 *v2.p_ = static_cast<int>(sink->size()); 190 return {true}; 191 } 192 }; 193 194 template <class T = int> 195 ConvertResult<Conv::n> FormatConvertImpl(const FormatCountCapture& v, 196 ConversionSpec conv, 197 FormatSinkImpl* sink) { 198 return FormatCountCaptureHelper::ConvertHelper(v, conv, sink); 199 } 200 201 // Helper friend struct to hide implementation details from the public API of 202 // FormatArgImpl. 203 struct FormatArgImplFriend { 204 template <typename Arg> 205 static bool ToInt(Arg arg, int* out) { 206 // A value initialized ConversionSpec has a `none` conv, which tells the 207 // dispatcher to run the `int` conversion. 208 return arg.dispatcher_(arg.data_, {}, out); 209 } 210 211 template <typename Arg> 212 static bool Convert(Arg arg, str_format_internal::ConversionSpec conv, 213 FormatSinkImpl* out) { 214 return arg.dispatcher_(arg.data_, conv, out); 215 } 216 217 template <typename Arg> 218 static typename Arg::Dispatcher GetVTablePtrForTest(Arg arg) { 219 return arg.dispatcher_; 220 } 221 }; 222 223 // A type-erased handle to a format argument. 224 class FormatArgImpl { 225 private: 226 enum { kInlinedSpace = 8 }; 227 228 using VoidPtr = str_format_internal::VoidPtr; 229 230 union Data { 231 const void* ptr; 232 const volatile void* volatile_ptr; 233 char buf[kInlinedSpace]; 234 }; 235 236 using Dispatcher = bool (*)(Data, ConversionSpec, void* out); 237 238 template <typename T> 239 struct store_by_value 240 : std::integral_constant<bool, (sizeof(T) <= kInlinedSpace) && 241 (std::is_integral<T>::value || 242 std::is_floating_point<T>::value || 243 std::is_pointer<T>::value || 244 std::is_same<VoidPtr, T>::value)> {}; 245 246 enum StoragePolicy { ByPointer, ByVolatilePointer, ByValue }; 247 template <typename T> 248 struct storage_policy 249 : std::integral_constant<StoragePolicy, 250 (std::is_volatile<T>::value 251 ? ByVolatilePointer 252 : (store_by_value<T>::value ? ByValue 253 : ByPointer))> { 254 }; 255 256 // To reduce the number of vtables we will decay values before hand. 257 // Anything with a user-defined Convert will get its own vtable. 258 // For everything else: 259 // - Decay char* and char arrays into `const char*` 260 // - Decay any other pointer to `const void*` 261 // - Decay all enums to their underlying type. 262 // - Decay function pointers to void*. 263 template <typename T, typename = void> 264 struct DecayType { 265 static constexpr bool kHasUserDefined = 266 str_format_internal::HasUserDefinedConvert<T>::value; 267 using type = typename std::conditional< 268 !kHasUserDefined && std::is_convertible<T, const char*>::value, 269 const char*, 270 typename std::conditional<!kHasUserDefined && 271 std::is_convertible<T, VoidPtr>::value, 272 VoidPtr, const T&>::type>::type; 273 }; 274 template <typename T> 275 struct DecayType<T, 276 typename std::enable_if< 277 !str_format_internal::HasUserDefinedConvert<T>::value && 278 std::is_enum<T>::value>::type> { 279 using type = typename std::underlying_type<T>::type; 280 }; 281 282 public: 283 template <typename T> 284 explicit FormatArgImpl(const T& value) { 285 using D = typename DecayType<T>::type; 286 static_assert( 287 std::is_same<D, const T&>::value || storage_policy<D>::value == ByValue, 288 "Decayed types must be stored by value"); 289 Init(static_cast<D>(value)); 290 } 291 292 private: 293 friend struct str_format_internal::FormatArgImplFriend; 294 template <typename T, StoragePolicy = storage_policy<T>::value> 295 struct Manager; 296 297 template <typename T> 298 struct Manager<T, ByPointer> { 299 static Data SetValue(const T& value) { 300 Data data; 301 data.ptr = std::addressof(value); 302 return data; 303 } 304 305 static const T& Value(Data arg) { return *static_cast<const T*>(arg.ptr); } 306 }; 307 308 template <typename T> 309 struct Manager<T, ByVolatilePointer> { 310 static Data SetValue(const T& value) { 311 Data data; 312 data.volatile_ptr = &value; 313 return data; 314 } 315 316 static const T& Value(Data arg) { 317 return *static_cast<const T*>(arg.volatile_ptr); 318 } 319 }; 320 321 template <typename T> 322 struct Manager<T, ByValue> { 323 static Data SetValue(const T& value) { 324 Data data; 325 memcpy(data.buf, &value, sizeof(value)); 326 return data; 327 } 328 329 static T Value(Data arg) { 330 T value; 331 memcpy(&value, arg.buf, sizeof(T)); 332 return value; 333 } 334 }; 335 336 template <typename T> 337 void Init(const T& value) { 338 data_ = Manager<T>::SetValue(value); 339 dispatcher_ = &Dispatch<T>; 340 } 341 342 template <typename T> 343 static int ToIntVal(const T& val) { 344 using CommonType = typename std::conditional<std::is_signed<T>::value, 345 int64_t, uint64_t>::type; 346 if (static_cast<CommonType>(val) > 347 static_cast<CommonType>((std::numeric_limits<int>::max)())) { 348 return (std::numeric_limits<int>::max)(); 349 } else if (std::is_signed<T>::value && 350 static_cast<CommonType>(val) < 351 static_cast<CommonType>((std::numeric_limits<int>::min)())) { 352 return (std::numeric_limits<int>::min)(); 353 } 354 return static_cast<int>(val); 355 } 356 357 template <typename T> 358 static bool ToInt(Data arg, int* out, std::true_type /* is_integral */, 359 std::false_type) { 360 *out = ToIntVal(Manager<T>::Value(arg)); 361 return true; 362 } 363 364 template <typename T> 365 static bool ToInt(Data arg, int* out, std::false_type, 366 std::true_type /* is_enum */) { 367 *out = ToIntVal(static_cast<typename std::underlying_type<T>::type>( 368 Manager<T>::Value(arg))); 369 return true; 370 } 371 372 template <typename T> 373 static bool ToInt(Data, int*, std::false_type, std::false_type) { 374 return false; 375 } 376 377 template <typename T> 378 static bool Dispatch(Data arg, ConversionSpec spec, void* out) { 379 // A `none` conv indicates that we want the `int` conversion. 380 if (ABSL_PREDICT_FALSE(spec.conv() == ConversionChar::none)) { 381 return ToInt<T>(arg, static_cast<int*>(out), std::is_integral<T>(), 382 std::is_enum<T>()); 383 } 384 385 return str_format_internal::FormatConvertImpl( 386 Manager<T>::Value(arg), spec, static_cast<FormatSinkImpl*>(out)) 387 .value; 388 } 389 390 Data data_; 391 Dispatcher dispatcher_; 392 }; 393 394 #define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \ 395 E template bool FormatArgImpl::Dispatch<T>(Data, ConversionSpec, void*) 396 397 #define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...) \ 398 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr, \ 399 __VA_ARGS__); \ 400 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(bool, __VA_ARGS__); \ 401 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(char, __VA_ARGS__); \ 402 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(signed char, __VA_ARGS__); \ 403 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned char, __VA_ARGS__); \ 404 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(short, __VA_ARGS__); /* NOLINT */ \ 405 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned short, /* NOLINT */ \ 406 __VA_ARGS__); \ 407 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int, __VA_ARGS__); \ 408 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned int, __VA_ARGS__); \ 409 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long, __VA_ARGS__); /* NOLINT */ \ 410 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long, /* NOLINT */ \ 411 __VA_ARGS__); \ 412 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long long, /* NOLINT */ \ 413 __VA_ARGS__); \ 414 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long long, /* NOLINT */ \ 415 __VA_ARGS__); \ 416 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int128, __VA_ARGS__); \ 417 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(uint128, __VA_ARGS__); \ 418 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(float, __VA_ARGS__); \ 419 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(double, __VA_ARGS__); \ 420 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long double, __VA_ARGS__); \ 421 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(const char*, __VA_ARGS__); \ 422 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::string, __VA_ARGS__); \ 423 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(string_view, __VA_ARGS__) 424 425 ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern); 426 427 428 } // namespace str_format_internal 429 ABSL_NAMESPACE_END 430 } // namespace absl 431 432 #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ 433