• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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