arg.h
Go to the documentation of this file.
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"
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>
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>
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 };
57  FormatSinkImpl* sink);
58 
59 // Strings.
61  ConversionSpec conv,
62  FormatSinkImpl* sink);
64  FormatSinkImpl* sink);
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>
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 =
107 
108 // Floats.
110  FormatSinkImpl* sink);
112  FormatSinkImpl* sink);
114  FormatSinkImpl* sink);
115 
116 // Chars.
118  FormatSinkImpl* sink);
120  FormatSinkImpl* sink);
122  FormatSinkImpl* sink);
123 
124 // Ints.
126  ConversionSpec conv,
127  FormatSinkImpl* sink);
128 IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT
129  ConversionSpec conv,
130  FormatSinkImpl* sink);
132  FormatSinkImpl* sink);
134  FormatSinkImpl* sink);
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);
148  FormatSinkImpl* sink);
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>
160  IntegralConvertResult>::type
162 
163 template <typename T>
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.
176  template <class T = int>
178  ConversionSpec conv,
179  FormatSinkImpl* sink) {
181 
183  return {false};
184  *v2.p_ = static_cast<int>(sink->size());
185  return {true};
186  }
187 };
188 
189 template <class T = int>
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.
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>
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.
220  private:
221  enum { kInlinedSpace = 8 };
222 
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>
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 
381  Manager<T>::Value(arg), spec, static_cast<FormatSinkImpl*>(out))
382  .value;
383  }
384 
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 
420 
421 } // namespace str_format_internal
422 } // namespace absl
423 
424 #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
int v
Definition: variant_test.cc:81
static bool ToInt(Data arg, int *out, std::true_type, std::false_type)
Definition: arg.h:353
const volatile void * volatile_ptr
Definition: arg.h:227
static ConvertResult< Conv::n > ConvertHelper(const FormatCountCapture &v, ConversionSpec conv, FormatSinkImpl *sink)
Definition: arg.h:177
#define ABSL_PREDICT_FALSE(x)
Definition: optimization.h:177
static Arg::Dispatcher GetVTablePtrForTest(Arg arg)
Definition: arg.h:213
bool(*)(Data, ConversionSpec, void *out) Dispatcher
Definition: arg.h:231
char buf[N]
Definition: algorithm.h:29
void remove_suffix(size_type n)
Definition: string_view.h:320
constexpr size_type size() const noexcept
Definition: string_view.h:260
typename std::enable_if< B, T >::type enable_if_t
Definition: type_traits.h:547
static bool Dispatch(Data arg, ConversionSpec spec, void *out)
Definition: arg.h:373
char * ptr
size_t value
size_t Excess(size_t used, size_t capacity)
Definition: extension.h:403
static bool Convert(Arg arg, str_format_internal::ConversionSpec conv, FormatSinkImpl *out)
Definition: arg.h:207
static bool ToInt(Arg arg, int *out)
Definition: arg.h:200
static bool ToInt(Data arg, int *out, std::false_type, std::true_type)
Definition: arg.h:360
ConvertResult< Conv::s > FormatConvertImpl(const std::string &v, const ConversionSpec conv, FormatSinkImpl *sink)
Definition: arg.cc:255
static bool ToInt(Data, int *, std::false_type, std::false_type)
Definition: arg.h:368
typename type_traits_internal::VoidTImpl< Ts... >::type void_t
Definition: type_traits.h:171
void * arg
Definition: mutex.cc:292
char * out
Definition: mutex.h:1013


abseil_cpp
Author(s):
autogenerated on Mon Feb 28 2022 21:31:17