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
21class Cord;
22class CordReader;
23
24namespace absl {
25
26class FormatCountCapture;
27class FormatSink;
28
29namespace str_format_internal {
30
31template <typename T, typename = void>
32struct HasUserDefinedConvert : std::false_type {};
33
34template <typename T>
35struct HasUserDefinedConvert<
36 T, void_t<decltype(AbslFormatConvert(
37 std::declval<const T&>(), std::declval<ConversionSpec>(),
38 std::declval<FormatSink*>()))>> : std::true_type {};
39
40template <typename T>
41class StreamedWrapper;
42
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`.
46
47// Raw pointers.
48struct VoidPtr {
49 VoidPtr() = default;
50 template <typename T,
51 decltype(reinterpret_cast<uintptr_t>(std::declval<T*>())) = 0>
52 VoidPtr(T* ptr) // NOLINT
53 : value(ptr ? reinterpret_cast<uintptr_t>(ptr) : 0) {}
54 uintptr_t value;
55};
56ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, ConversionSpec conv,
57 FormatSinkImpl* sink);
58
59// Strings.
60ConvertResult<Conv::s> FormatConvertImpl(const std::string& v,
61 ConversionSpec conv,
62 FormatSinkImpl* sink);
63ConvertResult<Conv::s> FormatConvertImpl(string_view v, ConversionSpec conv,
64 FormatSinkImpl* sink);
65ConvertResult<Conv::s | Conv::p> FormatConvertImpl(const char* v,
66 ConversionSpec conv,
67 FormatSinkImpl* sink);
68template <class AbslCord,
69 typename std::enable_if<
70 std::is_same<AbslCord, ::Cord>::value>::type* = nullptr,
71 class AbslCordReader = ::CordReader>
72ConvertResult<Conv::s> FormatConvertImpl(const AbslCord& value,
73 ConversionSpec conv,
74 FormatSinkImpl* sink) {
75 if (conv.conv().id() != ConversionChar::s) return {false};
76
77 bool is_left = conv.flags().left;
78 size_t space_remaining = 0;
79
80 int width = conv.width();
81 if (width >= 0) space_remaining = width;
82
83 size_t to_write = value.size();
84
85 int precision = conv.precision();
86 if (precision >= 0)
87 to_write = (std::min)(to_write, static_cast<size_t>(precision));
88
89 space_remaining = Excess(to_write, space_remaining);
90
91 if (space_remaining > 0 && !is_left) sink->Append(space_remaining, ' ');
92
93 string_view piece;
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);
97 sink->Append(piece);
98 }
99
100 if (space_remaining > 0 && is_left) sink->Append(space_remaining, ' ');
101 return {true};
102}
103
104using IntegralConvertResult =
105 ConvertResult<Conv::c | Conv::numeric | Conv::star>;
106using FloatingConvertResult = ConvertResult<Conv::floating>;
107
108// Floats.
109FloatingConvertResult FormatConvertImpl(float v, ConversionSpec conv,
110 FormatSinkImpl* sink);
111FloatingConvertResult FormatConvertImpl(double v, ConversionSpec conv,
112 FormatSinkImpl* sink);
113FloatingConvertResult FormatConvertImpl(long double v, ConversionSpec conv,
114 FormatSinkImpl* sink);
115
116// Chars.
117IntegralConvertResult FormatConvertImpl(char v, ConversionSpec conv,
118 FormatSinkImpl* sink);
119IntegralConvertResult FormatConvertImpl(signed char v, ConversionSpec conv,
120 FormatSinkImpl* sink);
121IntegralConvertResult FormatConvertImpl(unsigned char v, ConversionSpec conv,
122 FormatSinkImpl* sink);
123
124// Ints.
125IntegralConvertResult FormatConvertImpl(short v, // NOLINT
126 ConversionSpec conv,
127 FormatSinkImpl* sink);
128IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT
129 ConversionSpec conv,
130 FormatSinkImpl* sink);
131IntegralConvertResult FormatConvertImpl(int v, ConversionSpec conv,
132 FormatSinkImpl* sink);
133IntegralConvertResult FormatConvertImpl(unsigned v, ConversionSpec conv,
134 FormatSinkImpl* sink);
135IntegralConvertResult FormatConvertImpl(long v, // NOLINT
136 ConversionSpec conv,
137 FormatSinkImpl* sink);
138IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT
139 ConversionSpec conv,
140 FormatSinkImpl* sink);
141IntegralConvertResult FormatConvertImpl(long long v, // NOLINT
142 ConversionSpec conv,
143 FormatSinkImpl* sink);
144IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT
145 ConversionSpec conv,
146 FormatSinkImpl* sink);
147IntegralConvertResult FormatConvertImpl(uint128 v, ConversionSpec conv,
148 FormatSinkImpl* sink);
149template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0>
150IntegralConvertResult FormatConvertImpl(T v, ConversionSpec conv,
151 FormatSinkImpl* sink) {
152 return FormatConvertImpl(static_cast<int>(v), conv, sink);
153}
154
155// We provide this function to help the checker, but it is never defined.
156// FormatArgImpl will use the underlying Convert functions instead.
157template <typename T>
158typename std::enable_if<std::is_enum<T>::value &&
159 !HasUserDefinedConvert<T>::value,
160 IntegralConvertResult>::type
161FormatConvertImpl(T v, ConversionSpec conv, FormatSinkImpl* sink);
162
163template <typename T>
164ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<T>& v,
165 ConversionSpec conv,
166 FormatSinkImpl* out) {
167 std::ostringstream oss;
168 oss << v.v_;
169 if (!oss) return {false};
170 return str_format_internal::FormatConvertImpl(oss.str(), conv, out);
171}
172
173// Use templates and dependent types to delay evaluation of the function
174// until after FormatCountCapture is fully defined.
175struct FormatCountCaptureHelper {
176 template <class T = int>
177 static ConvertResult<Conv::n> ConvertHelper(const FormatCountCapture& v,
178 ConversionSpec conv,
179 FormatSinkImpl* sink) {
180 const absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v;
181
182 if (conv.conv().id() != str_format_internal::ConversionChar::n)
183 return {false};
184 *v2.p_ = static_cast<int>(sink->size());
185 return {true};
186 }
187};
188
189template <class T = int>
190ConvertResult<Conv::n> FormatConvertImpl(const FormatCountCapture& v,
191 ConversionSpec conv,
192 FormatSinkImpl* sink) {
193 return FormatCountCaptureHelper::ConvertHelper(v, conv, sink);
194}
195
196// Helper friend struct to hide implementation details from the public API of
197// FormatArgImpl.
198struct 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);
204 }
205
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);
210 }
211
212 template <typename Arg>
213 static typename Arg::Dispatcher GetVTablePtrForTest(Arg arg) {
214 return arg.dispatcher_;
215 }
216};
217
218// A type-erased handle to a format argument.
219class FormatArgImpl {
220 private:
221 enum { kInlinedSpace = 8 };
222
223 using VoidPtr = str_format_internal::VoidPtr;
224
225 union Data {
226 const void* ptr;
227 const volatile void* volatile_ptr;
228 char buf[kInlinedSpace];
229 };
230
231 using Dispatcher = bool (*)(Data, ConversionSpec, void* out);
232
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)> {};
240
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
246 ? ByVolatilePointer
247 : (store_by_value<T>::value ? ByValue
248 : ByPointer))> {
249 };
250
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>
259 struct DecayType {
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,
264 const char*,
265 typename std::conditional<!kHasUserDefined &&
266 std::is_convertible<T, VoidPtr>::value,
267 VoidPtr, const T&>::type>::type;
268 };
269 template <typename T>
270 struct DecayType<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;
275 };
276
277 public:
278 template <typename T>
279 explicit FormatArgImpl(const T& value) {
280 using D = typename DecayType<T>::type;
281 static_assert(
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));
285 }
286
287 private:
288 friend struct str_format_internal::FormatArgImplFriend;
289 template <typename T, StoragePolicy = storage_policy<T>::value>
290 struct Manager;
291
292 template <typename T>
293 struct Manager<T, ByPointer> {
294 static Data SetValue(const T& value) {
295 Data data;
296 data.ptr = std::addressof(value);
297 return data;
298 }
299
300 static const T& Value(Data arg) { return *static_cast<const T*>(arg.ptr); }
301 };
302
303 template <typename T>
304 struct Manager<T, ByVolatilePointer> {
305 static Data SetValue(const T& value) {
306 Data data;
307 data.volatile_ptr = &value;
308 return data;
309 }
310
311 static const T& Value(Data arg) {
312 return *static_cast<const T*>(arg.volatile_ptr);
313 }
314 };
315
316 template <typename T>
317 struct Manager<T, ByValue> {
318 static Data SetValue(const T& value) {
319 Data data;
320 memcpy(data.buf, &value, sizeof(value));
321 return data;
322 }
323
324 static T Value(Data arg) {
325 T value;
326 memcpy(&value, arg.buf, sizeof(T));
327 return value;
328 }
329 };
330
331 template <typename T>
332 void Init(const T& value) {
333 data_ = Manager<T>::SetValue(value);
334 dispatcher_ = &Dispatch<T>;
335 }
336
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)();
348 }
349 return static_cast<int>(val);
350 }
351
352 template <typename T>
353 static bool ToInt(Data arg, int* out, std::true_type /* is_integral */,
354 std::false_type) {
355 *out = ToIntVal(Manager<T>::Value(arg));
356 return true;
357 }
358
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)));
364 return true;
365 }
366
367 template <typename T>
368 static bool ToInt(Data, int*, std::false_type, std::false_type) {
369 return false;
370 }
371
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>(),
377 std::is_enum<T>());
378 }
379
380 return str_format_internal::FormatConvertImpl(
381 Manager<T>::Value(arg), spec, static_cast<FormatSinkImpl*>(out))
382 .value;
383 }
384
385 Data data_;
386 Dispatcher dispatcher_;
387};
388
389#define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \
390 E template bool FormatArgImpl::Dispatch<T>(Data, ConversionSpec, void*)
391
392#define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...) \
393 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr, \
394 __VA_ARGS__); \
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 */ \
401 __VA_ARGS__); \
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 */ \
406 __VA_ARGS__); \
407 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long long, /* NOLINT */ \
408 __VA_ARGS__); \
409 ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long long, /* NOLINT */ \
410 __VA_ARGS__); \
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__)
418
419ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern);
420
421} // namespace str_format_internal
422} // namespace absl
423
424#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
425