arg.cc
Go to the documentation of this file.
1 //
2 // POSIX spec:
3 // http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html
4 //
6 
7 #include <cassert>
8 #include <cerrno>
9 #include <cstdlib>
10 #include <string>
11 #include <type_traits>
12 
13 #include "absl/base/port.h"
15 
16 namespace absl {
18 namespace {
19 
20 const char kDigit[2][32] = { "0123456789abcdef", "0123456789ABCDEF" };
21 
22 // Reduce *capacity by s.size(), clipped to a 0 minimum.
23 void ReducePadding(string_view s, size_t *capacity) {
24  *capacity = Excess(s.size(), *capacity);
25 }
26 
27 // Reduce *capacity by n, clipped to a 0 minimum.
28 void ReducePadding(size_t n, size_t *capacity) {
29  *capacity = Excess(n, *capacity);
30 }
31 
32 template <typename T>
33 struct MakeUnsigned : std::make_unsigned<T> {};
34 template <>
35 struct MakeUnsigned<absl::uint128> {
36  using type = absl::uint128;
37 };
38 
39 template <typename T>
40 struct IsSigned : std::is_signed<T> {};
41 template <>
42 struct IsSigned<absl::uint128> : std::false_type {};
43 
44 class ConvertedIntInfo {
45  public:
46  template <typename T>
47  ConvertedIntInfo(T v, ConversionChar conv) {
48  using Unsigned = typename MakeUnsigned<T>::type;
49  auto u = static_cast<Unsigned>(v);
50  if (IsNeg(v)) {
51  is_neg_ = true;
52  u = Unsigned{} - u;
53  } else {
54  is_neg_ = false;
55  }
56  UnsignedToStringRight(u, conv);
57  }
58 
59  string_view digits() const {
60  return {end() - size_, static_cast<size_t>(size_)};
61  }
62  bool is_neg() const { return is_neg_; }
63 
64  private:
65  template <typename T, bool IsSigned>
66  struct IsNegImpl {
67  static bool Eval(T v) { return v < 0; }
68  };
69  template <typename T>
70  struct IsNegImpl<T, false> {
71  static bool Eval(T) {
72  return false;
73  }
74  };
75 
76  template <typename T>
77  bool IsNeg(T v) {
78  return IsNegImpl<T, IsSigned<T>::value>::Eval(v);
79  }
80 
81  template <typename T>
82  void UnsignedToStringRight(T u, ConversionChar conv) {
83  char *p = end();
84  switch (conv.radix()) {
85  default:
86  case 10:
87  for (; u; u /= 10)
88  *--p = static_cast<char>('0' + static_cast<size_t>(u % 10));
89  break;
90  case 8:
91  for (; u; u /= 8)
92  *--p = static_cast<char>('0' + static_cast<size_t>(u % 8));
93  break;
94  case 16: {
95  const char *digits = kDigit[conv.upper() ? 1 : 0];
96  for (; u; u /= 16) *--p = digits[static_cast<size_t>(u % 16)];
97  break;
98  }
99  }
100  size_ = static_cast<int>(end() - p);
101  }
102 
103  const char *end() const { return storage_ + sizeof(storage_); }
104  char *end() { return storage_ + sizeof(storage_); }
105 
106  bool is_neg_;
107  int size_;
108  // Max size: 128 bit value as octal -> 43 digits
109  char storage_[128 / 3 + 1];
110 };
111 
112 // Note: 'o' conversions do not have a base indicator, it's just that
113 // the '#' flag is specified to modify the precision for 'o' conversions.
114 string_view BaseIndicator(const ConvertedIntInfo &info,
115  const ConversionSpec conv) {
116  bool alt = conv.flags().alt;
117  int radix = conv.conv().radix();
118  if (conv.conv().id() == ConversionChar::p)
119  alt = true; // always show 0x for %p.
120  // From the POSIX description of '#' flag:
121  // "For x or X conversion specifiers, a non-zero result shall have
122  // 0x (or 0X) prefixed to it."
123  if (alt && radix == 16 && !info.digits().empty()) {
124  if (conv.conv().upper()) return "0X";
125  return "0x";
126  }
127  return {};
128 }
129 
130 string_view SignColumn(bool neg, const ConversionSpec conv) {
131  if (conv.conv().is_signed()) {
132  if (neg) return "-";
133  if (conv.flags().show_pos) return "+";
134  if (conv.flags().sign_col) return " ";
135  }
136  return {};
137 }
138 
139 bool ConvertCharImpl(unsigned char v, const ConversionSpec conv,
140  FormatSinkImpl *sink) {
141  size_t fill = 0;
142  if (conv.width() >= 0) fill = conv.width();
143  ReducePadding(1, &fill);
144  if (!conv.flags().left) sink->Append(fill, ' ');
145  sink->Append(1, v);
146  if (conv.flags().left) sink->Append(fill, ' ');
147  return true;
148 }
149 
150 bool ConvertIntImplInner(const ConvertedIntInfo &info,
151  const ConversionSpec conv, FormatSinkImpl *sink) {
152  // Print as a sequence of Substrings:
153  // [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces]
154  size_t fill = 0;
155  if (conv.width() >= 0) fill = conv.width();
156 
157  string_view formatted = info.digits();
158  ReducePadding(formatted, &fill);
159 
160  string_view sign = SignColumn(info.is_neg(), conv);
161  ReducePadding(sign, &fill);
162 
163  string_view base_indicator = BaseIndicator(info, conv);
164  ReducePadding(base_indicator, &fill);
165 
166  int precision = conv.precision();
167  bool precision_specified = precision >= 0;
168  if (!precision_specified)
169  precision = 1;
170 
171  if (conv.flags().alt && conv.conv().id() == ConversionChar::o) {
172  // From POSIX description of the '#' (alt) flag:
173  // "For o conversion, it increases the precision (if necessary) to
174  // force the first digit of the result to be zero."
175  if (formatted.empty() || *formatted.begin() != '0') {
176  int needed = static_cast<int>(formatted.size()) + 1;
177  precision = std::max(precision, needed);
178  }
179  }
180 
181  size_t num_zeroes = Excess(formatted.size(), precision);
182  ReducePadding(num_zeroes, &fill);
183 
184  size_t num_left_spaces = !conv.flags().left ? fill : 0;
185  size_t num_right_spaces = conv.flags().left ? fill : 0;
186 
187  // From POSIX description of the '0' (zero) flag:
188  // "For d, i, o, u, x, and X conversion specifiers, if a precision
189  // is specified, the '0' flag is ignored."
190  if (!precision_specified && conv.flags().zero) {
191  num_zeroes += num_left_spaces;
192  num_left_spaces = 0;
193  }
194 
195  sink->Append(num_left_spaces, ' ');
196  sink->Append(sign);
197  sink->Append(base_indicator);
198  sink->Append(num_zeroes, '0');
199  sink->Append(formatted);
200  sink->Append(num_right_spaces, ' ');
201  return true;
202 }
203 
204 template <typename T>
205 bool ConvertIntImplInner(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
206  ConvertedIntInfo info(v, conv.conv());
207  if (conv.flags().basic && conv.conv().id() != ConversionChar::p) {
208  if (info.is_neg()) sink->Append(1, '-');
209  if (info.digits().empty()) {
210  sink->Append(1, '0');
211  } else {
212  sink->Append(info.digits());
213  }
214  return true;
215  }
216  return ConvertIntImplInner(info, conv, sink);
217 }
218 
219 template <typename T>
220 bool ConvertIntArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
221  if (conv.conv().is_float()) {
222  return FormatConvertImpl(static_cast<double>(v), conv, sink).value;
223  }
224  if (conv.conv().id() == ConversionChar::c)
225  return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);
226  if (!conv.conv().is_integral())
227  return false;
228  if (!conv.conv().is_signed() && IsSigned<T>::value) {
229  using U = typename MakeUnsigned<T>::type;
230  return FormatConvertImpl(static_cast<U>(v), conv, sink).value;
231  }
232  return ConvertIntImplInner(v, conv, sink);
233 }
234 
235 template <typename T>
236 bool ConvertFloatArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
237  return conv.conv().is_float() && ConvertFloatImpl(v, conv, sink);
238 }
239 
240 inline bool ConvertStringArg(string_view v, const ConversionSpec conv,
241  FormatSinkImpl *sink) {
242  if (conv.conv().id() != ConversionChar::s)
243  return false;
244  if (conv.flags().basic) {
245  sink->Append(v);
246  return true;
247  }
248  return sink->PutPaddedString(v, conv.width(), conv.precision(),
249  conv.flags().left);
250 }
251 
252 } // namespace
253 
254 // ==================== Strings ====================
256  const ConversionSpec conv,
257  FormatSinkImpl *sink) {
258  return {ConvertStringArg(v, conv, sink)};
259 }
260 
262  const ConversionSpec conv,
263  FormatSinkImpl *sink) {
264  return {ConvertStringArg(v, conv, sink)};
265 }
266 
268  const ConversionSpec conv,
269  FormatSinkImpl *sink) {
270  if (conv.conv().id() == ConversionChar::p)
271  return {FormatConvertImpl(VoidPtr(v), conv, sink).value};
272  size_t len;
273  if (v == nullptr) {
274  len = 0;
275  } else if (conv.precision() < 0) {
276  len = std::strlen(v);
277  } else {
278  // If precision is set, we look for the null terminator on the valid range.
279  len = std::find(v, v + conv.precision(), '\0') - v;
280  }
281  return {ConvertStringArg(string_view(v, len), conv, sink)};
282 }
283 
284 // ==================== Raw pointers ====================
286  FormatSinkImpl *sink) {
287  if (conv.conv().id() != ConversionChar::p)
288  return {false};
289  if (!v.value) {
290  sink->Append("(nil)");
291  return {true};
292  }
293  return {ConvertIntImplInner(v.value, conv, sink)};
294 }
295 
296 // ==================== Floats ====================
298  FormatSinkImpl *sink) {
299  return {ConvertFloatArg(v, conv, sink)};
300 }
302  FormatSinkImpl *sink) {
303  return {ConvertFloatArg(v, conv, sink)};
304 }
306  const ConversionSpec conv,
307  FormatSinkImpl *sink) {
308  return {ConvertFloatArg(v, conv, sink)};
309 }
310 
311 // ==================== Chars ====================
313  FormatSinkImpl *sink) {
314  return {ConvertIntArg(v, conv, sink)};
315 }
317  const ConversionSpec conv,
318  FormatSinkImpl *sink) {
319  return {ConvertIntArg(v, conv, sink)};
320 }
322  const ConversionSpec conv,
323  FormatSinkImpl *sink) {
324  return {ConvertIntArg(v, conv, sink)};
325 }
326 
327 // ==================== Ints ====================
329  const ConversionSpec conv,
330  FormatSinkImpl *sink) {
331  return {ConvertIntArg(v, conv, sink)};
332 }
333 IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT
334  const ConversionSpec conv,
335  FormatSinkImpl *sink) {
336  return {ConvertIntArg(v, conv, sink)};
337 }
339  FormatSinkImpl *sink) {
340  return {ConvertIntArg(v, conv, sink)};
341 }
343  FormatSinkImpl *sink) {
344  return {ConvertIntArg(v, conv, sink)};
345 }
347  const ConversionSpec conv,
348  FormatSinkImpl *sink) {
349  return {ConvertIntArg(v, conv, sink)};
350 }
351 IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT
352  const ConversionSpec conv,
353  FormatSinkImpl *sink) {
354  return {ConvertIntArg(v, conv, sink)};
355 }
357  const ConversionSpec conv,
358  FormatSinkImpl *sink) {
359  return {ConvertIntArg(v, conv, sink)};
360 }
361 IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT
362  const ConversionSpec conv,
363  FormatSinkImpl *sink) {
364  return {ConvertIntArg(v, conv, sink)};
365 }
367  const ConversionSpec conv,
368  FormatSinkImpl *sink) {
369  return {ConvertIntArg(v, conv, sink)};
370 }
371 
373 
374 
375 } // namespace str_format_internal
376 
377 } // namespace absl
int v
Definition: variant_test.cc:81
bool ConvertFloatImpl(long double v, const ConversionSpec &conv, FormatSinkImpl *sink)
int fill
char * end
std::pair< uint64_t, uint64_t > uint128
Definition: city.h:55
Definition: algorithm.h:29
constexpr size_type size() const noexcept
Definition: string_view.h:260
char storage_[128/3+1]
Definition: arg.cc:109
size_t value
size_t Excess(size_t used, size_t capacity)
Definition: extension.h:403
ConvertResult< Conv::s > FormatConvertImpl(const std::string &v, const ConversionSpec conv, FormatSinkImpl *sink)
Definition: arg.cc:255
int size_
Definition: arg.cc:107
int radix
bool is_neg_
Definition: arg.cc:106


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