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 | class Cord; |
22 | class CordReader; |
23 | |
24 | namespace absl { |
25 | |
26 | class FormatCountCapture; |
27 | class FormatSink; |
28 | |
29 | namespace str_format_internal { |
30 | |
31 | template <typename T, typename = void> |
32 | struct HasUserDefinedConvert : std::false_type {}; |
33 | |
34 | template <typename T> |
35 | struct HasUserDefinedConvert< |
36 | T, void_t<decltype(AbslFormatConvert( |
37 | std::declval<const T&>(), std::declval<ConversionSpec>(), |
38 | std::declval<FormatSink*>()))>> : std::true_type {}; |
39 | |
40 | template <typename T> |
41 | class 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. |
48 | struct 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 | }; |
56 | ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, ConversionSpec conv, |
57 | FormatSinkImpl* sink); |
58 | |
59 | // Strings. |
60 | ConvertResult<Conv::s> FormatConvertImpl(const std::string& v, |
61 | ConversionSpec conv, |
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, |
66 | ConversionSpec conv, |
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, |
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 | |
104 | using IntegralConvertResult = |
105 | ConvertResult<Conv::c | Conv::numeric | Conv::star>; |
106 | using FloatingConvertResult = ConvertResult<Conv::floating>; |
107 | |
108 | // Floats. |
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); |
115 | |
116 | // Chars. |
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); |
123 | |
124 | // Ints. |
125 | IntegralConvertResult FormatConvertImpl(short v, // NOLINT |
126 | ConversionSpec conv, |
127 | FormatSinkImpl* sink); |
128 | IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT |
129 | ConversionSpec conv, |
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 |
136 | ConversionSpec conv, |
137 | FormatSinkImpl* sink); |
138 | IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT |
139 | ConversionSpec conv, |
140 | FormatSinkImpl* sink); |
141 | IntegralConvertResult FormatConvertImpl(long long v, // NOLINT |
142 | ConversionSpec conv, |
143 | FormatSinkImpl* sink); |
144 | IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT |
145 | ConversionSpec conv, |
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); |
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. |
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); |
162 | |
163 | template <typename T> |
164 | ConvertResult<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. |
175 | struct 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 | |
189 | template <class T = int> |
190 | ConvertResult<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. |
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); |
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. |
219 | class 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 | |
419 | ABSL_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 | |