• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
16 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
17 
18 #include <string.h>
19 #include <wchar.h>
20 
21 #include <cstdio>
22 #include <iomanip>
23 #include <limits>
24 #include <memory>
25 #include <sstream>
26 #include <string>
27 #include <type_traits>
28 
29 #include "absl/base/port.h"
30 #include "absl/meta/type_traits.h"
31 #include "absl/numeric/int128.h"
32 #include "absl/strings/internal/str_format/extension.h"
33 #include "absl/strings/string_view.h"
34 
35 namespace absl {
36 ABSL_NAMESPACE_BEGIN
37 
38 class Cord;
39 class FormatCountCapture;
40 class FormatSink;
41 
42 template <absl::FormatConversionCharSet C>
43 struct FormatConvertResult;
44 class FormatConversionSpec;
45 
46 namespace str_format_internal {
47 
48 template <typename T, typename = void>
49 struct HasUserDefinedConvert : std::false_type {};
50 
51 template <typename T>
52 struct HasUserDefinedConvert<T, void_t<decltype(AbslFormatConvert(
53                                     std::declval<const T&>(),
54                                     std::declval<const FormatConversionSpec&>(),
55                                     std::declval<FormatSink*>()))>>
56     : std::true_type {};
57 
58 void AbslFormatConvert();  // Stops the lexical name lookup
59 template <typename T>
60 auto FormatConvertImpl(const T& v, FormatConversionSpecImpl conv,
61                        FormatSinkImpl* sink)
62     -> decltype(AbslFormatConvert(v,
63                                   std::declval<const FormatConversionSpec&>(),
64                                   std::declval<FormatSink*>())) {
65   using FormatConversionSpecT =
66       absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatConversionSpec>;
67   using FormatSinkT =
68       absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatSink>;
69   auto fcs = conv.Wrap<FormatConversionSpecT>();
70   auto fs = sink->Wrap<FormatSinkT>();
71   return AbslFormatConvert(v, fcs, &fs);
72 }
73 
74 template <typename T>
75 class StreamedWrapper;
76 
77 // If 'v' can be converted (in the printf sense) according to 'conv',
78 // then convert it, appending to `sink` and return `true`.
79 // Otherwise fail and return `false`.
80 
81 // AbslFormatConvert(v, conv, sink) is intended to be found by ADL on 'v'
82 // as an extension mechanism. These FormatConvertImpl functions are the default
83 // implementations.
84 // The ADL search is augmented via the 'Sink*' parameter, which also
85 // serves as a disambiguator to reject possible unintended 'AbslFormatConvert'
86 // functions in the namespaces associated with 'v'.
87 
88 // Raw pointers.
89 struct VoidPtr {
90   VoidPtr() = default;
91   template <typename T,
92             decltype(reinterpret_cast<uintptr_t>(std::declval<T*>())) = 0>
93   VoidPtr(T* ptr)  // NOLINT
94       : value(ptr ? reinterpret_cast<uintptr_t>(ptr) : 0) {}
95   uintptr_t value;
96 };
97 
98 template <FormatConversionCharSet C>
99 struct ArgConvertResult {
100   bool value;
101 };
102 
103 template <FormatConversionCharSet C>
104 constexpr FormatConversionCharSet ExtractCharSet(FormatConvertResult<C>) {
105   return C;
106 }
107 
108 template <FormatConversionCharSet C>
109 constexpr FormatConversionCharSet ExtractCharSet(ArgConvertResult<C>) {
110   return C;
111 }
112 
113 using StringConvertResult =
114     ArgConvertResult<FormatConversionCharSetInternal::s>;
115 ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
116     VoidPtr v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
117 
118 // Strings.
119 StringConvertResult FormatConvertImpl(const std::string& v,
120                                       FormatConversionSpecImpl conv,
121                                       FormatSinkImpl* sink);
122 StringConvertResult FormatConvertImpl(string_view v,
123                                       FormatConversionSpecImpl conv,
124                                       FormatSinkImpl* sink);
125 #if defined(ABSL_HAVE_STD_STRING_VIEW) && !defined(ABSL_USES_STD_STRING_VIEW)
126 inline StringConvertResult FormatConvertImpl(std::string_view v,
127                                              FormatConversionSpecImpl conv,
128                                              FormatSinkImpl* sink) {
129   return FormatConvertImpl(absl::string_view(v.data(), v.size()), conv, sink);
130 }
131 #endif  // ABSL_HAVE_STD_STRING_VIEW && !ABSL_USES_STD_STRING_VIEW
132 
133 ArgConvertResult<FormatConversionCharSetUnion(
134     FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
135 FormatConvertImpl(const char* v, const FormatConversionSpecImpl conv,
136                   FormatSinkImpl* sink);
137 
138 template <class AbslCord, typename std::enable_if<std::is_same<
139                               AbslCord, absl::Cord>::value>::type* = nullptr>
140 StringConvertResult FormatConvertImpl(const AbslCord& value,
141                                       FormatConversionSpecImpl conv,
142                                       FormatSinkImpl* sink) {
143   bool is_left = conv.has_left_flag();
144   size_t space_remaining = 0;
145 
146   int width = conv.width();
147   if (width >= 0) space_remaining = width;
148 
149   size_t to_write = value.size();
150 
151   int precision = conv.precision();
152   if (precision >= 0)
153     to_write = (std::min)(to_write, static_cast<size_t>(precision));
154 
155   space_remaining = Excess(to_write, space_remaining);
156 
157   if (space_remaining > 0 && !is_left) sink->Append(space_remaining, ' ');
158 
159   for (string_view piece : value.Chunks()) {
160     if (piece.size() > to_write) {
161       piece.remove_suffix(piece.size() - to_write);
162       to_write = 0;
163     } else {
164       to_write -= piece.size();
165     }
166     sink->Append(piece);
167     if (to_write == 0) {
168       break;
169     }
170   }
171 
172   if (space_remaining > 0 && is_left) sink->Append(space_remaining, ' ');
173   return {true};
174 }
175 
176 using IntegralConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
177     FormatConversionCharSetInternal::c,
178     FormatConversionCharSetInternal::kNumeric,
179     FormatConversionCharSetInternal::kStar)>;
180 using FloatingConvertResult =
181     ArgConvertResult<FormatConversionCharSetInternal::kFloating>;
182 
183 // Floats.
184 FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv,
185                                         FormatSinkImpl* sink);
186 FloatingConvertResult FormatConvertImpl(double v, FormatConversionSpecImpl conv,
187                                         FormatSinkImpl* sink);
188 FloatingConvertResult FormatConvertImpl(long double v,
189                                         FormatConversionSpecImpl conv,
190                                         FormatSinkImpl* sink);
191 
192 // Chars.
193 IntegralConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv,
194                                         FormatSinkImpl* sink);
195 IntegralConvertResult FormatConvertImpl(signed char v,
196                                         FormatConversionSpecImpl conv,
197                                         FormatSinkImpl* sink);
198 IntegralConvertResult FormatConvertImpl(unsigned char v,
199                                         FormatConversionSpecImpl conv,
200                                         FormatSinkImpl* sink);
201 
202 // Ints.
203 IntegralConvertResult FormatConvertImpl(short v,  // NOLINT
204                                         FormatConversionSpecImpl conv,
205                                         FormatSinkImpl* sink);
206 IntegralConvertResult FormatConvertImpl(unsigned short v,  // NOLINT
207                                         FormatConversionSpecImpl conv,
208                                         FormatSinkImpl* sink);
209 IntegralConvertResult FormatConvertImpl(int v, FormatConversionSpecImpl conv,
210                                         FormatSinkImpl* sink);
211 IntegralConvertResult FormatConvertImpl(unsigned v,
212                                         FormatConversionSpecImpl conv,
213                                         FormatSinkImpl* sink);
214 IntegralConvertResult FormatConvertImpl(long v,  // NOLINT
215                                         FormatConversionSpecImpl conv,
216                                         FormatSinkImpl* sink);
217 IntegralConvertResult FormatConvertImpl(unsigned long v,  // NOLINT
218                                         FormatConversionSpecImpl conv,
219                                         FormatSinkImpl* sink);
220 IntegralConvertResult FormatConvertImpl(long long v,  // NOLINT
221                                         FormatConversionSpecImpl conv,
222                                         FormatSinkImpl* sink);
223 IntegralConvertResult FormatConvertImpl(unsigned long long v,  // NOLINT
224                                         FormatConversionSpecImpl conv,
225                                         FormatSinkImpl* sink);
226 IntegralConvertResult FormatConvertImpl(int128 v, FormatConversionSpecImpl conv,
227                                         FormatSinkImpl* sink);
228 IntegralConvertResult FormatConvertImpl(uint128 v,
229                                         FormatConversionSpecImpl conv,
230                                         FormatSinkImpl* sink);
231 template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0>
232 IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv,
233                                         FormatSinkImpl* sink) {
234   return FormatConvertImpl(static_cast<int>(v), conv, sink);
235 }
236 
237 // We provide this function to help the checker, but it is never defined.
238 // FormatArgImpl will use the underlying Convert functions instead.
239 template <typename T>
240 typename std::enable_if<std::is_enum<T>::value &&
241                             !HasUserDefinedConvert<T>::value,
242                         IntegralConvertResult>::type
243 FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
244 
245 template <typename T>
246 StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v,
247                                       FormatConversionSpecImpl conv,
248                                       FormatSinkImpl* out) {
249   std::ostringstream oss;
250   oss << v.v_;
251   if (!oss) return {false};
252   return str_format_internal::FormatConvertImpl(oss.str(), conv, out);
253 }
254 
255 // Use templates and dependent types to delay evaluation of the function
256 // until after FormatCountCapture is fully defined.
257 struct FormatCountCaptureHelper {
258   template <class T = int>
259   static ArgConvertResult<FormatConversionCharSetInternal::n> ConvertHelper(
260       const FormatCountCapture& v, FormatConversionSpecImpl conv,
261       FormatSinkImpl* sink) {
262     const absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v;
263 
264     if (conv.conversion_char() !=
265         str_format_internal::FormatConversionCharInternal::n) {
266       return {false};
267     }
268     *v2.p_ = static_cast<int>(sink->size());
269     return {true};
270   }
271 };
272 
273 template <class T = int>
274 ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl(
275     const FormatCountCapture& v, FormatConversionSpecImpl conv,
276     FormatSinkImpl* sink) {
277   return FormatCountCaptureHelper::ConvertHelper(v, conv, sink);
278 }
279 
280 // Helper friend struct to hide implementation details from the public API of
281 // FormatArgImpl.
282 struct FormatArgImplFriend {
283   template <typename Arg>
284   static bool ToInt(Arg arg, int* out) {
285     // A value initialized FormatConversionSpecImpl has a `none` conv, which
286     // tells the dispatcher to run the `int` conversion.
287     return arg.dispatcher_(arg.data_, {}, out);
288   }
289 
290   template <typename Arg>
291   static bool Convert(Arg arg, FormatConversionSpecImpl conv,
292                       FormatSinkImpl* out) {
293     return arg.dispatcher_(arg.data_, conv, out);
294   }
295 
296   template <typename Arg>
297   static typename Arg::Dispatcher GetVTablePtrForTest(Arg arg) {
298     return arg.dispatcher_;
299   }
300 };
301 
302 template <typename Arg>
303 constexpr FormatConversionCharSet ArgumentToConv() {
304   return absl::str_format_internal::ExtractCharSet(
305       decltype(str_format_internal::FormatConvertImpl(
306           std::declval<const Arg&>(),
307           std::declval<const FormatConversionSpecImpl&>(),
308           std::declval<FormatSinkImpl*>())){});
309 }
310 
311 // A type-erased handle to a format argument.
312 class FormatArgImpl {
313  private:
314   enum { kInlinedSpace = 8 };
315 
316   using VoidPtr = str_format_internal::VoidPtr;
317 
318   union Data {
319     const void* ptr;
320     const volatile void* volatile_ptr;
321     char buf[kInlinedSpace];
322   };
323 
324   using Dispatcher = bool (*)(Data, FormatConversionSpecImpl, void* out);
325 
326   template <typename T>
327   struct store_by_value
328       : std::integral_constant<bool, (sizeof(T) <= kInlinedSpace) &&
329                                          (std::is_integral<T>::value ||
330                                           std::is_floating_point<T>::value ||
331                                           std::is_pointer<T>::value ||
332                                           std::is_same<VoidPtr, T>::value)> {};
333 
334   enum StoragePolicy { ByPointer, ByVolatilePointer, ByValue };
335   template <typename T>
336   struct storage_policy
337       : std::integral_constant<StoragePolicy,
338                                (std::is_volatile<T>::value
339                                     ? ByVolatilePointer
340                                     : (store_by_value<T>::value ? ByValue
341                                                                 : ByPointer))> {
342   };
343 
344   // To reduce the number of vtables we will decay values before hand.
345   // Anything with a user-defined Convert will get its own vtable.
346   // For everything else:
347   //   - Decay char* and char arrays into `const char*`
348   //   - Decay any other pointer to `const void*`
349   //   - Decay all enums to their underlying type.
350   //   - Decay function pointers to void*.
351   template <typename T, typename = void>
352   struct DecayType {
353     static constexpr bool kHasUserDefined =
354         str_format_internal::HasUserDefinedConvert<T>::value;
355     using type = typename std::conditional<
356         !kHasUserDefined && std::is_convertible<T, const char*>::value,
357         const char*,
358         typename std::conditional<!kHasUserDefined &&
359                                       std::is_convertible<T, VoidPtr>::value,
360                                   VoidPtr, const T&>::type>::type;
361   };
362   template <typename T>
363   struct DecayType<T,
364                    typename std::enable_if<
365                        !str_format_internal::HasUserDefinedConvert<T>::value &&
366                        std::is_enum<T>::value>::type> {
367     using type = typename std::underlying_type<T>::type;
368   };
369 
370  public:
371   template <typename T>
372   explicit FormatArgImpl(const T& value) {
373     using D = typename DecayType<T>::type;
374     static_assert(
375         std::is_same<D, const T&>::value || storage_policy<D>::value == ByValue,
376         "Decayed types must be stored by value");
377     Init(static_cast<D>(value));
378   }
379 
380  private:
381   friend struct str_format_internal::FormatArgImplFriend;
382   template <typename T, StoragePolicy = storage_policy<T>::value>
383   struct Manager;
384 
385   template <typename T>
386   struct Manager<T, ByPointer> {
387     static Data SetValue(const T& value) {
388       Data data;
389       data.ptr = std::addressof(value);
390       return data;
391     }
392 
393     static const T& Value(Data arg) { return *static_cast<const T*>(arg.ptr); }
394   };
395 
396   template <typename T>
397   struct Manager<T, ByVolatilePointer> {
398     static Data SetValue(const T& value) {
399       Data data;
400       data.volatile_ptr = &value;
401       return data;
402     }
403 
404     static const T& Value(Data arg) {
405       return *static_cast<const T*>(arg.volatile_ptr);
406     }
407   };
408 
409   template <typename T>
410   struct Manager<T, ByValue> {
411     static Data SetValue(const T& value) {
412       Data data;
413       memcpy(data.buf, &value, sizeof(value));
414       return data;
415     }
416 
417     static T Value(Data arg) {
418       T value;
419       memcpy(&value, arg.buf, sizeof(T));
420       return value;
421     }
422   };
423 
424   template <typename T>
425   void Init(const T& value) {
426     data_ = Manager<T>::SetValue(value);
427     dispatcher_ = &Dispatch<T>;
428   }
429 
430   template <typename T>
431   static int ToIntVal(const T& val) {
432     using CommonType = typename std::conditional<std::is_signed<T>::value,
433                                                  int64_t, uint64_t>::type;
434     if (static_cast<CommonType>(val) >
435         static_cast<CommonType>((std::numeric_limits<int>::max)())) {
436       return (std::numeric_limits<int>::max)();
437     } else if (std::is_signed<T>::value &&
438                static_cast<CommonType>(val) <
439                    static_cast<CommonType>((std::numeric_limits<int>::min)())) {
440       return (std::numeric_limits<int>::min)();
441     }
442     return static_cast<int>(val);
443   }
444 
445   template <typename T>
446   static bool ToInt(Data arg, int* out, std::true_type /* is_integral */,
447                     std::false_type) {
448     *out = ToIntVal(Manager<T>::Value(arg));
449     return true;
450   }
451 
452   template <typename T>
453   static bool ToInt(Data arg, int* out, std::false_type,
454                     std::true_type /* is_enum */) {
455     *out = ToIntVal(static_cast<typename std::underlying_type<T>::type>(
456         Manager<T>::Value(arg)));
457     return true;
458   }
459 
460   template <typename T>
461   static bool ToInt(Data, int*, std::false_type, std::false_type) {
462     return false;
463   }
464 
465   template <typename T>
466   static bool Dispatch(Data arg, FormatConversionSpecImpl spec, void* out) {
467     // A `none` conv indicates that we want the `int` conversion.
468     if (ABSL_PREDICT_FALSE(spec.conversion_char() ==
469                            FormatConversionCharInternal::kNone)) {
470       return ToInt<T>(arg, static_cast<int*>(out), std::is_integral<T>(),
471                       std::is_enum<T>());
472     }
473     if (ABSL_PREDICT_FALSE(!Contains(ArgumentToConv<T>(),
474                                      spec.conversion_char()))) {
475       return false;
476     }
477     return str_format_internal::FormatConvertImpl(
478                Manager<T>::Value(arg), spec,
479                static_cast<FormatSinkImpl*>(out))
480         .value;
481   }
482 
483   Data data_;
484   Dispatcher dispatcher_;
485 };
486 
487 #define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E)                     \
488   E template bool FormatArgImpl::Dispatch<T>(Data, FormatConversionSpecImpl, \
489                                              void*)
490 
491 #define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...)                   \
492   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr,     \
493                                              __VA_ARGS__);                     \
494   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(bool, __VA_ARGS__);               \
495   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(char, __VA_ARGS__);               \
496   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(signed char, __VA_ARGS__);        \
497   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned char, __VA_ARGS__);      \
498   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(short, __VA_ARGS__); /* NOLINT */ \
499   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned short,      /* NOLINT */ \
500                                              __VA_ARGS__);                     \
501   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int, __VA_ARGS__);                \
502   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned int, __VA_ARGS__);       \
503   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long, __VA_ARGS__); /* NOLINT */  \
504   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long,      /* NOLINT */  \
505                                              __VA_ARGS__);                     \
506   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long long, /* NOLINT */           \
507                                              __VA_ARGS__);                     \
508   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long long, /* NOLINT */  \
509                                              __VA_ARGS__);                     \
510   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int128, __VA_ARGS__);             \
511   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(uint128, __VA_ARGS__);            \
512   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(float, __VA_ARGS__);              \
513   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(double, __VA_ARGS__);             \
514   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long double, __VA_ARGS__);        \
515   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(const char*, __VA_ARGS__);        \
516   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::string, __VA_ARGS__);        \
517   ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(string_view, __VA_ARGS__)
518 
519 ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern);
520 
521 
522 }  // namespace str_format_internal
523 ABSL_NAMESPACE_END
524 }  // namespace absl
525 
526 #endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
527