1 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
2 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
13 #include <type_traits>
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"
26 class FormatCountCapture;
29 namespace str_format_internal {
31 template <typename T, typename = void>
32 struct HasUserDefinedConvert : std::false_type {};
35 struct HasUserDefinedConvert<
36 T, void_t<decltype(AbslFormatConvert(
37 std::declval<const T&>(), std::declval<ConversionSpec>(),
38 std::declval<FormatSink*>()))>> : std::true_type {};
41 class StreamedWrapper;
43 // If 'v' can be converted (in the printf sense) according to 'conv',
44 // then convert it, appending to `sink` and return `true`.
45 // Otherwise fail and return `false`.
51 decltype(reinterpret_cast<uintptr_t>(std::declval<T*>())) = 0>
52 VoidPtr(T* ptr) // NOLINT
53 : value(ptr ? reinterpret_cast<uintptr_t>(ptr) : 0) {}
56 ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, ConversionSpec conv,
57 FormatSinkImpl* sink);
60 ConvertResult<Conv::s> FormatConvertImpl(const std::string& v,
62 FormatSinkImpl* sink);
63 ConvertResult<Conv::s> FormatConvertImpl(string_view v, ConversionSpec conv,
64 FormatSinkImpl* sink);
65 ConvertResult<Conv::s | Conv::p> FormatConvertImpl(const char* v,
67 FormatSinkImpl* sink);
68 template <class AbslCord,
69 typename std::enable_if<
70 std::is_same<AbslCord, ::Cord>::value>::type* = nullptr,
71 class AbslCordReader = ::CordReader>
72 ConvertResult<Conv::s> FormatConvertImpl(const AbslCord& value,
74 FormatSinkImpl* sink) {
75 if (conv.conv().id() != ConversionChar::s) return {false};
77 bool is_left = conv.flags().left;
78 size_t space_remaining = 0;
80 int width = conv.width();
81 if (width >= 0) space_remaining = width;
83 size_t to_write = value.size();
85 int precision = conv.precision();
87 to_write = (std::min)(to_write, static_cast<size_t>(precision));
89 space_remaining = Excess(to_write, space_remaining);
91 if (space_remaining > 0 && !is_left) sink->Append(space_remaining, ' ');
94 for (AbslCordReader reader(value);
95 to_write > 0 && reader.ReadFragment(&piece); to_write -= piece.size()) {
96 if (piece.size() > to_write) piece.remove_suffix(piece.size() - to_write);
100 if (space_remaining > 0 && is_left) sink->Append(space_remaining, ' ');
104 using IntegralConvertResult =
105 ConvertResult<Conv::c | Conv::numeric | Conv::star>;
106 using FloatingConvertResult = ConvertResult<Conv::floating>;
109 FloatingConvertResult FormatConvertImpl(float v, ConversionSpec conv,
110 FormatSinkImpl* sink);
111 FloatingConvertResult FormatConvertImpl(double v, ConversionSpec conv,
112 FormatSinkImpl* sink);
113 FloatingConvertResult FormatConvertImpl(long double v, ConversionSpec conv,
114 FormatSinkImpl* sink);
117 IntegralConvertResult FormatConvertImpl(char v, ConversionSpec conv,
118 FormatSinkImpl* sink);
119 IntegralConvertResult FormatConvertImpl(signed char v, ConversionSpec conv,
120 FormatSinkImpl* sink);
121 IntegralConvertResult FormatConvertImpl(unsigned char v, ConversionSpec conv,
122 FormatSinkImpl* sink);
125 IntegralConvertResult FormatConvertImpl(short v, // NOLINT
127 FormatSinkImpl* sink);
128 IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT
130 FormatSinkImpl* sink);
131 IntegralConvertResult FormatConvertImpl(int v, ConversionSpec conv,
132 FormatSinkImpl* sink);
133 IntegralConvertResult FormatConvertImpl(unsigned v, ConversionSpec conv,
134 FormatSinkImpl* sink);
135 IntegralConvertResult FormatConvertImpl(long v, // NOLINT
137 FormatSinkImpl* sink);
138 IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT
140 FormatSinkImpl* sink);
141 IntegralConvertResult FormatConvertImpl(long long v, // NOLINT
143 FormatSinkImpl* sink);
144 IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT
146 FormatSinkImpl* sink);
147 IntegralConvertResult FormatConvertImpl(uint128 v, ConversionSpec conv,
148 FormatSinkImpl* sink);
149 template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0>
150 IntegralConvertResult FormatConvertImpl(T v, ConversionSpec conv,
151 FormatSinkImpl* sink) {
152 return FormatConvertImpl(static_cast<int>(v), conv, sink);
155 // We provide this function to help the checker, but it is never defined.
156 // FormatArgImpl will use the underlying Convert functions instead.
157 template <typename T>
158 typename std::enable_if<std::is_enum<T>::value &&
159 !HasUserDefinedConvert<T>::value,
160 IntegralConvertResult>::type
161 FormatConvertImpl(T v, ConversionSpec conv, FormatSinkImpl* sink);
163 template <typename T>
164 ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<T>& v,
166 FormatSinkImpl* out) {
167 std::ostringstream oss;
169 if (!oss) return {false};
170 return str_format_internal::FormatConvertImpl(oss.str(), conv, out);
173 // Use templates and dependent types to delay evaluation of the function
174 // until after FormatCountCapture is fully defined.
175 struct FormatCountCaptureHelper {
176 template <class T = int>
177 static ConvertResult<Conv::n> ConvertHelper(const FormatCountCapture& v,
179 FormatSinkImpl* sink) {
180 const absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v;
182 if (conv.conv().id() != str_format_internal::ConversionChar::n)
184 *v2.p_ = static_cast<int>(sink->size());
189 template <class T = int>
190 ConvertResult<Conv::n> FormatConvertImpl(const FormatCountCapture& v,
192 FormatSinkImpl* sink) {
193 return FormatCountCaptureHelper::ConvertHelper(v, conv, sink);
196 // Helper friend struct to hide implementation details from the public API of
198 struct FormatArgImplFriend {
199 template <typename Arg>
200 static bool ToInt(Arg arg, int* out) {
201 // A value initialized ConversionSpec has a `none` conv, which tells the
202 // dispatcher to run the `int` conversion.
203 return arg.dispatcher_(arg.data_, {}, out);
206 template <typename Arg>
207 static bool Convert(Arg arg, str_format_internal::ConversionSpec conv,
208 FormatSinkImpl* out) {
209 return arg.dispatcher_(arg.data_, conv, out);
212 template <typename Arg>
213 static typename Arg::Dispatcher GetVTablePtrForTest(Arg arg) {
214 return arg.dispatcher_;
218 // A type-erased handle to a format argument.
219 class FormatArgImpl {
221 enum { kInlinedSpace = 8 };
223 using VoidPtr = str_format_internal::VoidPtr;
227 const volatile void* volatile_ptr;
228 char buf[kInlinedSpace];
231 using Dispatcher = bool (*)(Data, ConversionSpec, void* out);
233 template <typename T>
234 struct store_by_value
235 : std::integral_constant<bool, (sizeof(T) <= kInlinedSpace) &&
236 (std::is_integral<T>::value ||
237 std::is_floating_point<T>::value ||
238 std::is_pointer<T>::value ||
239 std::is_same<VoidPtr, T>::value)> {};
241 enum StoragePolicy { ByPointer, ByVolatilePointer, ByValue };
242 template <typename T>
243 struct storage_policy
244 : std::integral_constant<StoragePolicy,
245 (std::is_volatile<T>::value
247 : (store_by_value<T>::value ? ByValue
251 // To reduce the number of vtables we will decay values before hand.
252 // Anything with a user-defined Convert will get its own vtable.
253 // For everything else:
254 // - Decay char* and char arrays into `const char*`
255 // - Decay any other pointer to `const void*`
256 // - Decay all enums to their underlying type.
257 // - Decay function pointers to void*.
258 template <typename T, typename = void>
260 static constexpr bool kHasUserDefined =
261 str_format_internal::HasUserDefinedConvert<T>::value;
262 using type = typename std::conditional<
263 !kHasUserDefined && std::is_convertible<T, const char*>::value,
265 typename std::conditional<!kHasUserDefined &&
266 std::is_convertible<T, VoidPtr>::value,
267 VoidPtr, const T&>::type>::type;
269 template <typename T>
271 typename std::enable_if<
272 !str_format_internal::HasUserDefinedConvert<T>::value &&
273 std::is_enum<T>::value>::type> {
274 using type = typename std::underlying_type<T>::type;
278 template <typename T>
279 explicit FormatArgImpl(const T& value) {
280 using D = typename DecayType<T>::type;
282 std::is_same<D, const T&>::value || storage_policy<D>::value == ByValue,
283 "Decayed types must be stored by value");
284 Init(static_cast<D>(value));
288 friend struct str_format_internal::FormatArgImplFriend;
289 template <typename T, StoragePolicy = storage_policy<T>::value>
292 template <typename T>
293 struct Manager<T, ByPointer> {
294 static Data SetValue(const T& value) {
296 data.ptr = std::addressof(value);
300 static const T& Value(Data arg) { return *static_cast<const T*>(arg.ptr); }
303 template <typename T>
304 struct Manager<T, ByVolatilePointer> {
305 static Data SetValue(const T& value) {
307 data.volatile_ptr = &value;
311 static const T& Value(Data arg) {
312 return *static_cast<const T*>(arg.volatile_ptr);
316 template <typename T>
317 struct Manager<T, ByValue> {
318 static Data SetValue(const T& value) {
320 memcpy(data.buf, &value, sizeof(value));
324 static T Value(Data arg) {
326 memcpy(&value, arg.buf, sizeof(T));
331 template <typename T>
332 void Init(const T& value) {
333 data_ = Manager<T>::SetValue(value);
334 dispatcher_ = &Dispatch<T>;
337 template <typename T>
338 static int ToIntVal(const T& val) {
339 using CommonType = typename std::conditional<std::is_signed<T>::value,
340 int64_t, uint64_t>::type;
341 if (static_cast<CommonType>(val) >
342 static_cast<CommonType>((std::numeric_limits<int>::max)())) {
343 return (std::numeric_limits<int>::max)();
344 } else if (std::is_signed<T>::value &&
345 static_cast<CommonType>(val) <
346 static_cast<CommonType>((std::numeric_limits<int>::min)())) {
347 return (std::numeric_limits<int>::min)();
349 return static_cast<int>(val);
352 template <typename T>
353 static bool ToInt(Data arg, int* out, std::true_type /* is_integral */,
355 *out = ToIntVal(Manager<T>::Value(arg));
359 template <typename T>
360 static bool ToInt(Data arg, int* out, std::false_type,
361 std::true_type /* is_enum */) {
362 *out = ToIntVal(static_cast<typename std::underlying_type<T>::type>(
363 Manager<T>::Value(arg)));
367 template <typename T>
368 static bool ToInt(Data, int*, std::false_type, std::false_type) {
372 template <typename T>
373 static bool Dispatch(Data arg, ConversionSpec spec, void* out) {
374 // A `none` conv indicates that we want the `int` conversion.
375 if (ABSL_PREDICT_FALSE(spec.conv().id() == ConversionChar::none)) {
376 return ToInt<T>(arg, static_cast<int*>(out), std::is_integral<T>(),
380 return str_format_internal::FormatConvertImpl(
381 Manager<T>::Value(arg), spec, static_cast<FormatSinkImpl*>(out))
386 Dispatcher dispatcher_;
389 #define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \
390 E template bool FormatArgImpl::Dispatch<T>(Data, ConversionSpec, void*)
392 #define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...) \
393 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr, \
395 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(bool, __VA_ARGS__); \
396 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(char, __VA_ARGS__); \
397 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(signed char, __VA_ARGS__); \
398 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned char, __VA_ARGS__); \
399 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(short, __VA_ARGS__); /* NOLINT */ \
400 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned short, /* NOLINT */ \
402 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int, __VA_ARGS__); \
403 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned int, __VA_ARGS__); \
404 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long, __VA_ARGS__); /* NOLINT */ \
405 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long, /* NOLINT */ \
407 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long long, /* NOLINT */ \
409 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long long, /* NOLINT */ \
411 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(uint128, __VA_ARGS__); \
412 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(float, __VA_ARGS__); \
413 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(double, __VA_ARGS__); \
414 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long double, __VA_ARGS__); \
415 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(const char*, __VA_ARGS__); \
416 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::string, __VA_ARGS__); \
417 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(string_view, __VA_ARGS__)
419 ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern);
421 } // namespace str_format_internal
424 #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_