arg.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  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. // POSIX spec:
  16. // http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html
  17. //
  18. #include "absl/strings/internal/str_format/arg.h"
  19. #include <cassert>
  20. #include <cerrno>
  21. #include <cstdlib>
  22. #include <string>
  23. #include <type_traits>
  24. #include "absl/base/port.h"
  25. #include "absl/strings/internal/str_format/float_conversion.h"
  26. #include "absl/strings/numbers.h"
  27. namespace absl {
  28. ABSL_NAMESPACE_BEGIN
  29. namespace str_format_internal {
  30. namespace {
  31. // Reduce *capacity by s.size(), clipped to a 0 minimum.
  32. void ReducePadding(string_view s, size_t *capacity) {
  33. *capacity = Excess(s.size(), *capacity);
  34. }
  35. // Reduce *capacity by n, clipped to a 0 minimum.
  36. void ReducePadding(size_t n, size_t *capacity) {
  37. *capacity = Excess(n, *capacity);
  38. }
  39. template <typename T>
  40. struct MakeUnsigned : std::make_unsigned<T> {};
  41. template <>
  42. struct MakeUnsigned<absl::int128> {
  43. using type = absl::uint128;
  44. };
  45. template <>
  46. struct MakeUnsigned<absl::uint128> {
  47. using type = absl::uint128;
  48. };
  49. template <typename T>
  50. struct IsSigned : std::is_signed<T> {};
  51. template <>
  52. struct IsSigned<absl::int128> : std::true_type {};
  53. template <>
  54. struct IsSigned<absl::uint128> : std::false_type {};
  55. // Integral digit printer.
  56. // Call one of the PrintAs* routines after construction once.
  57. // Use with_neg_and_zero/without_neg_or_zero/is_negative to access the results.
  58. class IntDigits {
  59. public:
  60. // Print the unsigned integer as octal.
  61. // Supports unsigned integral types and uint128.
  62. template <typename T>
  63. void PrintAsOct(T v) {
  64. static_assert(!IsSigned<T>::value, "");
  65. char *p = storage_ + sizeof(storage_);
  66. do {
  67. *--p = static_cast<char>('0' + (static_cast<size_t>(v) & 7));
  68. v >>= 3;
  69. } while (v);
  70. start_ = p;
  71. size_ = storage_ + sizeof(storage_) - p;
  72. }
  73. // Print the signed or unsigned integer as decimal.
  74. // Supports all integral types.
  75. template <typename T>
  76. void PrintAsDec(T v) {
  77. static_assert(std::is_integral<T>::value, "");
  78. start_ = storage_;
  79. size_ = numbers_internal::FastIntToBuffer(v, storage_) - storage_;
  80. }
  81. void PrintAsDec(int128 v) {
  82. auto u = static_cast<uint128>(v);
  83. bool add_neg = false;
  84. if (v < 0) {
  85. add_neg = true;
  86. u = uint128{} - u;
  87. }
  88. PrintAsDec(u, add_neg);
  89. }
  90. void PrintAsDec(uint128 v, bool add_neg = false) {
  91. // This function can be sped up if needed. We can call FastIntToBuffer
  92. // twice, or fix FastIntToBuffer to support uint128.
  93. char *p = storage_ + sizeof(storage_);
  94. do {
  95. p -= 2;
  96. numbers_internal::PutTwoDigits(static_cast<size_t>(v % 100), p);
  97. v /= 100;
  98. } while (v);
  99. if (p[0] == '0') {
  100. // We printed one too many hexits.
  101. ++p;
  102. }
  103. if (add_neg) {
  104. *--p = '-';
  105. }
  106. size_ = storage_ + sizeof(storage_) - p;
  107. start_ = p;
  108. }
  109. // Print the unsigned integer as hex using lowercase.
  110. // Supports unsigned integral types and uint128.
  111. template <typename T>
  112. void PrintAsHexLower(T v) {
  113. static_assert(!IsSigned<T>::value, "");
  114. char *p = storage_ + sizeof(storage_);
  115. do {
  116. p -= 2;
  117. constexpr const char* table = numbers_internal::kHexTable;
  118. std::memcpy(p, table + 2 * (static_cast<size_t>(v) & 0xFF), 2);
  119. if (sizeof(T) == 1) break;
  120. v >>= 8;
  121. } while (v);
  122. if (p[0] == '0') {
  123. // We printed one too many digits.
  124. ++p;
  125. }
  126. start_ = p;
  127. size_ = storage_ + sizeof(storage_) - p;
  128. }
  129. // Print the unsigned integer as hex using uppercase.
  130. // Supports unsigned integral types and uint128.
  131. template <typename T>
  132. void PrintAsHexUpper(T v) {
  133. static_assert(!IsSigned<T>::value, "");
  134. char *p = storage_ + sizeof(storage_);
  135. // kHexTable is only lowercase, so do it manually for uppercase.
  136. do {
  137. *--p = "0123456789ABCDEF"[static_cast<size_t>(v) & 15];
  138. v >>= 4;
  139. } while (v);
  140. start_ = p;
  141. size_ = storage_ + sizeof(storage_) - p;
  142. }
  143. // The printed value including the '-' sign if available.
  144. // For inputs of value `0`, this will return "0"
  145. string_view with_neg_and_zero() const { return {start_, size_}; }
  146. // The printed value not including the '-' sign.
  147. // For inputs of value `0`, this will return "".
  148. string_view without_neg_or_zero() const {
  149. static_assert('-' < '0', "The check below verifies both.");
  150. size_t advance = start_[0] <= '0' ? 1 : 0;
  151. return {start_ + advance, size_ - advance};
  152. }
  153. bool is_negative() const { return start_[0] == '-'; }
  154. private:
  155. const char *start_;
  156. size_t size_;
  157. // Max size: 128 bit value as octal -> 43 digits, plus sign char
  158. char storage_[128 / 3 + 1 + 1];
  159. };
  160. // Note: 'o' conversions do not have a base indicator, it's just that
  161. // the '#' flag is specified to modify the precision for 'o' conversions.
  162. string_view BaseIndicator(const IntDigits &as_digits,
  163. const FormatConversionSpecImpl conv) {
  164. // always show 0x for %p.
  165. bool alt = conv.has_alt_flag() ||
  166. conv.conversion_char() == FormatConversionCharInternal::p;
  167. bool hex = (conv.conversion_char() == FormatConversionCharInternal::x ||
  168. conv.conversion_char() == FormatConversionCharInternal::X ||
  169. conv.conversion_char() == FormatConversionCharInternal::p);
  170. // From the POSIX description of '#' flag:
  171. // "For x or X conversion specifiers, a non-zero result shall have
  172. // 0x (or 0X) prefixed to it."
  173. if (alt && hex && !as_digits.without_neg_or_zero().empty()) {
  174. return conv.conversion_char() == FormatConversionCharInternal::X ? "0X"
  175. : "0x";
  176. }
  177. return {};
  178. }
  179. string_view SignColumn(bool neg, const FormatConversionSpecImpl conv) {
  180. if (conv.conversion_char() == FormatConversionCharInternal::d ||
  181. conv.conversion_char() == FormatConversionCharInternal::i) {
  182. if (neg) return "-";
  183. if (conv.has_show_pos_flag()) return "+";
  184. if (conv.has_sign_col_flag()) return " ";
  185. }
  186. return {};
  187. }
  188. bool ConvertCharImpl(unsigned char v, const FormatConversionSpecImpl conv,
  189. FormatSinkImpl *sink) {
  190. size_t fill = 0;
  191. if (conv.width() >= 0) fill = conv.width();
  192. ReducePadding(1, &fill);
  193. if (!conv.has_left_flag()) sink->Append(fill, ' ');
  194. sink->Append(1, v);
  195. if (conv.has_left_flag()) sink->Append(fill, ' ');
  196. return true;
  197. }
  198. bool ConvertIntImplInnerSlow(const IntDigits &as_digits,
  199. const FormatConversionSpecImpl conv,
  200. FormatSinkImpl *sink) {
  201. // Print as a sequence of Substrings:
  202. // [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces]
  203. size_t fill = 0;
  204. if (conv.width() >= 0) fill = conv.width();
  205. string_view formatted = as_digits.without_neg_or_zero();
  206. ReducePadding(formatted, &fill);
  207. string_view sign = SignColumn(as_digits.is_negative(), conv);
  208. ReducePadding(sign, &fill);
  209. string_view base_indicator = BaseIndicator(as_digits, conv);
  210. ReducePadding(base_indicator, &fill);
  211. int precision = conv.precision();
  212. bool precision_specified = precision >= 0;
  213. if (!precision_specified)
  214. precision = 1;
  215. if (conv.has_alt_flag() &&
  216. conv.conversion_char() == FormatConversionCharInternal::o) {
  217. // From POSIX description of the '#' (alt) flag:
  218. // "For o conversion, it increases the precision (if necessary) to
  219. // force the first digit of the result to be zero."
  220. if (formatted.empty() || *formatted.begin() != '0') {
  221. int needed = static_cast<int>(formatted.size()) + 1;
  222. precision = std::max(precision, needed);
  223. }
  224. }
  225. size_t num_zeroes = Excess(formatted.size(), precision);
  226. ReducePadding(num_zeroes, &fill);
  227. size_t num_left_spaces = !conv.has_left_flag() ? fill : 0;
  228. size_t num_right_spaces = conv.has_left_flag() ? fill : 0;
  229. // From POSIX description of the '0' (zero) flag:
  230. // "For d, i, o, u, x, and X conversion specifiers, if a precision
  231. // is specified, the '0' flag is ignored."
  232. if (!precision_specified && conv.has_zero_flag()) {
  233. num_zeroes += num_left_spaces;
  234. num_left_spaces = 0;
  235. }
  236. sink->Append(num_left_spaces, ' ');
  237. sink->Append(sign);
  238. sink->Append(base_indicator);
  239. sink->Append(num_zeroes, '0');
  240. sink->Append(formatted);
  241. sink->Append(num_right_spaces, ' ');
  242. return true;
  243. }
  244. template <typename T>
  245. bool ConvertIntArg(T v, const FormatConversionSpecImpl conv,
  246. FormatSinkImpl *sink) {
  247. using U = typename MakeUnsigned<T>::type;
  248. IntDigits as_digits;
  249. // This odd casting is due to a bug in -Wswitch behavior in gcc49 which causes
  250. // it to complain about a switch/case type mismatch, even though both are
  251. // FormatConverionChar. Likely this is because at this point
  252. // FormatConversionChar is declared, but not defined.
  253. switch (static_cast<uint8_t>(conv.conversion_char())) {
  254. case static_cast<uint8_t>(FormatConversionCharInternal::c):
  255. return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);
  256. case static_cast<uint8_t>(FormatConversionCharInternal::o):
  257. as_digits.PrintAsOct(static_cast<U>(v));
  258. break;
  259. case static_cast<uint8_t>(FormatConversionCharInternal::x):
  260. as_digits.PrintAsHexLower(static_cast<U>(v));
  261. break;
  262. case static_cast<uint8_t>(FormatConversionCharInternal::X):
  263. as_digits.PrintAsHexUpper(static_cast<U>(v));
  264. break;
  265. case static_cast<uint8_t>(FormatConversionCharInternal::u):
  266. as_digits.PrintAsDec(static_cast<U>(v));
  267. break;
  268. case static_cast<uint8_t>(FormatConversionCharInternal::d):
  269. case static_cast<uint8_t>(FormatConversionCharInternal::i):
  270. as_digits.PrintAsDec(v);
  271. break;
  272. case static_cast<uint8_t>(FormatConversionCharInternal::a):
  273. case static_cast<uint8_t>(FormatConversionCharInternal::e):
  274. case static_cast<uint8_t>(FormatConversionCharInternal::f):
  275. case static_cast<uint8_t>(FormatConversionCharInternal::g):
  276. case static_cast<uint8_t>(FormatConversionCharInternal::A):
  277. case static_cast<uint8_t>(FormatConversionCharInternal::E):
  278. case static_cast<uint8_t>(FormatConversionCharInternal::F):
  279. case static_cast<uint8_t>(FormatConversionCharInternal::G):
  280. return ConvertFloatImpl(static_cast<double>(v), conv, sink);
  281. default:
  282. ABSL_INTERNAL_ASSUME(false);
  283. }
  284. if (conv.is_basic()) {
  285. sink->Append(as_digits.with_neg_and_zero());
  286. return true;
  287. }
  288. return ConvertIntImplInnerSlow(as_digits, conv, sink);
  289. }
  290. template <typename T>
  291. bool ConvertFloatArg(T v, const FormatConversionSpecImpl conv,
  292. FormatSinkImpl *sink) {
  293. return FormatConversionCharIsFloat(conv.conversion_char()) &&
  294. ConvertFloatImpl(v, conv, sink);
  295. }
  296. inline bool ConvertStringArg(string_view v, const FormatConversionSpecImpl conv,
  297. FormatSinkImpl *sink) {
  298. if (conv.is_basic()) {
  299. sink->Append(v);
  300. return true;
  301. }
  302. return sink->PutPaddedString(v, conv.width(), conv.precision(),
  303. conv.has_left_flag());
  304. }
  305. } // namespace
  306. // ==================== Strings ====================
  307. StringConvertResult FormatConvertImpl(const std::string &v,
  308. const FormatConversionSpecImpl conv,
  309. FormatSinkImpl *sink) {
  310. return {ConvertStringArg(v, conv, sink)};
  311. }
  312. StringConvertResult FormatConvertImpl(string_view v,
  313. const FormatConversionSpecImpl conv,
  314. FormatSinkImpl *sink) {
  315. return {ConvertStringArg(v, conv, sink)};
  316. }
  317. ArgConvertResult<FormatConversionCharSetUnion(
  318. FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
  319. FormatConvertImpl(const char *v, const FormatConversionSpecImpl conv,
  320. FormatSinkImpl *sink) {
  321. if (conv.conversion_char() == FormatConversionCharInternal::p)
  322. return {FormatConvertImpl(VoidPtr(v), conv, sink).value};
  323. size_t len;
  324. if (v == nullptr) {
  325. len = 0;
  326. } else if (conv.precision() < 0) {
  327. len = std::strlen(v);
  328. } else {
  329. // If precision is set, we look for the NUL-terminator on the valid range.
  330. len = std::find(v, v + conv.precision(), '\0') - v;
  331. }
  332. return {ConvertStringArg(string_view(v, len), conv, sink)};
  333. }
  334. // ==================== Raw pointers ====================
  335. ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
  336. VoidPtr v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
  337. if (!v.value) {
  338. sink->Append("(nil)");
  339. return {true};
  340. }
  341. IntDigits as_digits;
  342. as_digits.PrintAsHexLower(v.value);
  343. return {ConvertIntImplInnerSlow(as_digits, conv, sink)};
  344. }
  345. // ==================== Floats ====================
  346. FloatingConvertResult FormatConvertImpl(float v,
  347. const FormatConversionSpecImpl conv,
  348. FormatSinkImpl *sink) {
  349. return {ConvertFloatArg(v, conv, sink)};
  350. }
  351. FloatingConvertResult FormatConvertImpl(double v,
  352. const FormatConversionSpecImpl conv,
  353. FormatSinkImpl *sink) {
  354. return {ConvertFloatArg(v, conv, sink)};
  355. }
  356. FloatingConvertResult FormatConvertImpl(long double v,
  357. const FormatConversionSpecImpl conv,
  358. FormatSinkImpl *sink) {
  359. return {ConvertFloatArg(v, conv, sink)};
  360. }
  361. // ==================== Chars ====================
  362. IntegralConvertResult FormatConvertImpl(char v,
  363. const FormatConversionSpecImpl conv,
  364. FormatSinkImpl *sink) {
  365. return {ConvertIntArg(v, conv, sink)};
  366. }
  367. IntegralConvertResult FormatConvertImpl(signed char v,
  368. const FormatConversionSpecImpl conv,
  369. FormatSinkImpl *sink) {
  370. return {ConvertIntArg(v, conv, sink)};
  371. }
  372. IntegralConvertResult FormatConvertImpl(unsigned char v,
  373. const FormatConversionSpecImpl conv,
  374. FormatSinkImpl *sink) {
  375. return {ConvertIntArg(v, conv, sink)};
  376. }
  377. // ==================== Ints ====================
  378. IntegralConvertResult FormatConvertImpl(short v, // NOLINT
  379. const FormatConversionSpecImpl conv,
  380. FormatSinkImpl *sink) {
  381. return {ConvertIntArg(v, conv, sink)};
  382. }
  383. IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT
  384. const FormatConversionSpecImpl conv,
  385. FormatSinkImpl *sink) {
  386. return {ConvertIntArg(v, conv, sink)};
  387. }
  388. IntegralConvertResult FormatConvertImpl(int v,
  389. const FormatConversionSpecImpl conv,
  390. FormatSinkImpl *sink) {
  391. return {ConvertIntArg(v, conv, sink)};
  392. }
  393. IntegralConvertResult FormatConvertImpl(unsigned v,
  394. const FormatConversionSpecImpl conv,
  395. FormatSinkImpl *sink) {
  396. return {ConvertIntArg(v, conv, sink)};
  397. }
  398. IntegralConvertResult FormatConvertImpl(long v, // NOLINT
  399. const FormatConversionSpecImpl conv,
  400. FormatSinkImpl *sink) {
  401. return {ConvertIntArg(v, conv, sink)};
  402. }
  403. IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT
  404. const FormatConversionSpecImpl conv,
  405. FormatSinkImpl *sink) {
  406. return {ConvertIntArg(v, conv, sink)};
  407. }
  408. IntegralConvertResult FormatConvertImpl(long long v, // NOLINT
  409. const FormatConversionSpecImpl conv,
  410. FormatSinkImpl *sink) {
  411. return {ConvertIntArg(v, conv, sink)};
  412. }
  413. IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT
  414. const FormatConversionSpecImpl conv,
  415. FormatSinkImpl *sink) {
  416. return {ConvertIntArg(v, conv, sink)};
  417. }
  418. IntegralConvertResult FormatConvertImpl(absl::int128 v,
  419. const FormatConversionSpecImpl conv,
  420. FormatSinkImpl *sink) {
  421. return {ConvertIntArg(v, conv, sink)};
  422. }
  423. IntegralConvertResult FormatConvertImpl(absl::uint128 v,
  424. const FormatConversionSpecImpl conv,
  425. FormatSinkImpl *sink) {
  426. return {ConvertIntArg(v, conv, sink)};
  427. }
  428. ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_();
  429. } // namespace str_format_internal
  430. ABSL_NAMESPACE_END
  431. } // namespace absl