arg.cc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  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 <algorithm>
  20. #include <cassert>
  21. #include <cstddef>
  22. #include <cstdint>
  23. #include <cstdlib>
  24. #include <cstring>
  25. #include <cwchar>
  26. #include <string>
  27. #include <type_traits>
  28. #include "absl/base/config.h"
  29. #include "absl/base/optimization.h"
  30. #include "absl/container/fixed_array.h"
  31. #include "absl/numeric/int128.h"
  32. #include "absl/strings/internal/str_format/extension.h"
  33. #include "absl/strings/internal/str_format/float_conversion.h"
  34. #include "absl/strings/numbers.h"
  35. #include "absl/strings/string_view.h"
  36. #if defined(ABSL_HAVE_STD_STRING_VIEW)
  37. #include <string_view>
  38. #endif
  39. namespace absl {
  40. ABSL_NAMESPACE_BEGIN
  41. namespace str_format_internal {
  42. namespace {
  43. // Reduce *capacity by s.size(), clipped to a 0 minimum.
  44. void ReducePadding(string_view s, size_t *capacity) {
  45. *capacity = Excess(s.size(), *capacity);
  46. }
  47. // Reduce *capacity by n, clipped to a 0 minimum.
  48. void ReducePadding(size_t n, size_t *capacity) {
  49. *capacity = Excess(n, *capacity);
  50. }
  51. template <typename T>
  52. struct MakeUnsigned : std::make_unsigned<T> {};
  53. template <>
  54. struct MakeUnsigned<absl::int128> {
  55. using type = absl::uint128;
  56. };
  57. template <>
  58. struct MakeUnsigned<absl::uint128> {
  59. using type = absl::uint128;
  60. };
  61. template <typename T>
  62. struct IsSigned : std::is_signed<T> {};
  63. template <>
  64. struct IsSigned<absl::int128> : std::true_type {};
  65. template <>
  66. struct IsSigned<absl::uint128> : std::false_type {};
  67. // Integral digit printer.
  68. // Call one of the PrintAs* routines after construction once.
  69. // Use with_neg_and_zero/without_neg_or_zero/is_negative to access the results.
  70. class IntDigits {
  71. public:
  72. // Print the unsigned integer as octal.
  73. // Supports unsigned integral types and uint128.
  74. template <typename T>
  75. void PrintAsOct(T v) {
  76. static_assert(!IsSigned<T>::value, "");
  77. char *p = storage_ + sizeof(storage_);
  78. do {
  79. *--p = static_cast<char>('0' + (static_cast<size_t>(v) & 7));
  80. v >>= 3;
  81. } while (v);
  82. start_ = p;
  83. size_ = static_cast<size_t>(storage_ + sizeof(storage_) - p);
  84. }
  85. // Print the signed or unsigned integer as decimal.
  86. // Supports all integral types.
  87. template <typename T>
  88. void PrintAsDec(T v) {
  89. static_assert(std::is_integral<T>::value, "");
  90. start_ = storage_;
  91. size_ = static_cast<size_t>(numbers_internal::FastIntToBuffer(v, storage_) -
  92. storage_);
  93. }
  94. void PrintAsDec(int128 v) {
  95. auto u = static_cast<uint128>(v);
  96. bool add_neg = false;
  97. if (v < 0) {
  98. add_neg = true;
  99. u = uint128{} - u;
  100. }
  101. PrintAsDec(u, add_neg);
  102. }
  103. void PrintAsDec(uint128 v, bool add_neg = false) {
  104. // This function can be sped up if needed. We can call FastIntToBuffer
  105. // twice, or fix FastIntToBuffer to support uint128.
  106. char *p = storage_ + sizeof(storage_);
  107. do {
  108. p -= 2;
  109. numbers_internal::PutTwoDigits(static_cast<uint32_t>(v % 100), p);
  110. v /= 100;
  111. } while (v);
  112. if (p[0] == '0') {
  113. // We printed one too many hexits.
  114. ++p;
  115. }
  116. if (add_neg) {
  117. *--p = '-';
  118. }
  119. size_ = static_cast<size_t>(storage_ + sizeof(storage_) - p);
  120. start_ = p;
  121. }
  122. // Print the unsigned integer as hex using lowercase.
  123. // Supports unsigned integral types and uint128.
  124. template <typename T>
  125. void PrintAsHexLower(T v) {
  126. static_assert(!IsSigned<T>::value, "");
  127. char *p = storage_ + sizeof(storage_);
  128. do {
  129. p -= 2;
  130. constexpr const char* table = numbers_internal::kHexTable;
  131. std::memcpy(p, table + 2 * (static_cast<size_t>(v) & 0xFF), 2);
  132. if (sizeof(T) == 1) break;
  133. v >>= 8;
  134. } while (v);
  135. if (p[0] == '0') {
  136. // We printed one too many digits.
  137. ++p;
  138. }
  139. start_ = p;
  140. size_ = static_cast<size_t>(storage_ + sizeof(storage_) - p);
  141. }
  142. // Print the unsigned integer as hex using uppercase.
  143. // Supports unsigned integral types and uint128.
  144. template <typename T>
  145. void PrintAsHexUpper(T v) {
  146. static_assert(!IsSigned<T>::value, "");
  147. char *p = storage_ + sizeof(storage_);
  148. // kHexTable is only lowercase, so do it manually for uppercase.
  149. do {
  150. *--p = "0123456789ABCDEF"[static_cast<size_t>(v) & 15];
  151. v >>= 4;
  152. } while (v);
  153. start_ = p;
  154. size_ = static_cast<size_t>(storage_ + sizeof(storage_) - p);
  155. }
  156. // The printed value including the '-' sign if available.
  157. // For inputs of value `0`, this will return "0"
  158. string_view with_neg_and_zero() const { return {start_, size_}; }
  159. // The printed value not including the '-' sign.
  160. // For inputs of value `0`, this will return "".
  161. string_view without_neg_or_zero() const {
  162. static_assert('-' < '0', "The check below verifies both.");
  163. size_t advance = start_[0] <= '0' ? 1 : 0;
  164. return {start_ + advance, size_ - advance};
  165. }
  166. bool is_negative() const { return start_[0] == '-'; }
  167. private:
  168. const char *start_;
  169. size_t size_;
  170. // Max size: 128 bit value as octal -> 43 digits, plus sign char
  171. char storage_[128 / 3 + 1 + 1];
  172. };
  173. // Note: 'o' conversions do not have a base indicator, it's just that
  174. // the '#' flag is specified to modify the precision for 'o' conversions.
  175. string_view BaseIndicator(const IntDigits &as_digits,
  176. const FormatConversionSpecImpl conv) {
  177. // always show 0x for %p.
  178. bool alt = conv.has_alt_flag() ||
  179. conv.conversion_char() == FormatConversionCharInternal::p;
  180. bool hex = (conv.conversion_char() == FormatConversionCharInternal::x ||
  181. conv.conversion_char() == FormatConversionCharInternal::X ||
  182. conv.conversion_char() == FormatConversionCharInternal::p);
  183. // From the POSIX description of '#' flag:
  184. // "For x or X conversion specifiers, a non-zero result shall have
  185. // 0x (or 0X) prefixed to it."
  186. if (alt && hex && !as_digits.without_neg_or_zero().empty()) {
  187. return conv.conversion_char() == FormatConversionCharInternal::X ? "0X"
  188. : "0x";
  189. }
  190. return {};
  191. }
  192. string_view SignColumn(bool neg, const FormatConversionSpecImpl conv) {
  193. if (conv.conversion_char() == FormatConversionCharInternal::d ||
  194. conv.conversion_char() == FormatConversionCharInternal::i) {
  195. if (neg) return "-";
  196. if (conv.has_show_pos_flag()) return "+";
  197. if (conv.has_sign_col_flag()) return " ";
  198. }
  199. return {};
  200. }
  201. bool ConvertCharImpl(char v,
  202. const FormatConversionSpecImpl conv,
  203. FormatSinkImpl* sink) {
  204. size_t fill = 0;
  205. if (conv.width() >= 0)
  206. fill = static_cast<size_t>(conv.width());
  207. ReducePadding(1, &fill);
  208. if (!conv.has_left_flag()) sink->Append(fill, ' ');
  209. sink->Append(1, v);
  210. if (conv.has_left_flag()) sink->Append(fill, ' ');
  211. return true;
  212. }
  213. bool ConvertIntImplInnerSlow(const IntDigits &as_digits,
  214. const FormatConversionSpecImpl conv,
  215. FormatSinkImpl *sink) {
  216. // Print as a sequence of Substrings:
  217. // [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces]
  218. size_t fill = 0;
  219. if (conv.width() >= 0)
  220. fill = static_cast<size_t>(conv.width());
  221. string_view formatted = as_digits.without_neg_or_zero();
  222. ReducePadding(formatted, &fill);
  223. string_view sign = SignColumn(as_digits.is_negative(), conv);
  224. ReducePadding(sign, &fill);
  225. string_view base_indicator = BaseIndicator(as_digits, conv);
  226. ReducePadding(base_indicator, &fill);
  227. bool precision_specified = conv.precision() >= 0;
  228. size_t precision =
  229. precision_specified ? static_cast<size_t>(conv.precision()) : size_t{1};
  230. if (conv.has_alt_flag() &&
  231. conv.conversion_char() == FormatConversionCharInternal::o) {
  232. // From POSIX description of the '#' (alt) flag:
  233. // "For o conversion, it increases the precision (if necessary) to
  234. // force the first digit of the result to be zero."
  235. if (formatted.empty() || *formatted.begin() != '0') {
  236. size_t needed = formatted.size() + 1;
  237. precision = std::max(precision, needed);
  238. }
  239. }
  240. size_t num_zeroes = Excess(formatted.size(), precision);
  241. ReducePadding(num_zeroes, &fill);
  242. size_t num_left_spaces = !conv.has_left_flag() ? fill : 0;
  243. size_t num_right_spaces = conv.has_left_flag() ? fill : 0;
  244. // From POSIX description of the '0' (zero) flag:
  245. // "For d, i, o, u, x, and X conversion specifiers, if a precision
  246. // is specified, the '0' flag is ignored."
  247. if (!precision_specified && conv.has_zero_flag()) {
  248. num_zeroes += num_left_spaces;
  249. num_left_spaces = 0;
  250. }
  251. sink->Append(num_left_spaces, ' ');
  252. sink->Append(sign);
  253. sink->Append(base_indicator);
  254. sink->Append(num_zeroes, '0');
  255. sink->Append(formatted);
  256. sink->Append(num_right_spaces, ' ');
  257. return true;
  258. }
  259. template <typename T>
  260. bool ConvertFloatArg(T v, FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
  261. if (conv.conversion_char() == FormatConversionCharInternal::v) {
  262. conv.set_conversion_char(FormatConversionCharInternal::g);
  263. }
  264. return FormatConversionCharIsFloat(conv.conversion_char()) &&
  265. ConvertFloatImpl(v, conv, sink);
  266. }
  267. inline bool ConvertStringArg(string_view v, const FormatConversionSpecImpl conv,
  268. FormatSinkImpl *sink) {
  269. if (conv.is_basic()) {
  270. sink->Append(v);
  271. return true;
  272. }
  273. return sink->PutPaddedString(v, conv.width(), conv.precision(),
  274. conv.has_left_flag());
  275. }
  276. struct ShiftState {
  277. bool saw_high_surrogate = false;
  278. uint8_t bits = 0;
  279. };
  280. // Converts `v` from UTF-16 or UTF-32 to UTF-8 and writes to `buf`. `buf` is
  281. // assumed to have enough space for the output. `s` is used to carry state
  282. // between successive calls with a UTF-16 surrogate pair. Returns the number of
  283. // chars written, or `static_cast<size_t>(-1)` on failure.
  284. //
  285. // This is basically std::wcrtomb(), but always outputting UTF-8 instead of
  286. // respecting the current locale.
  287. inline size_t WideToUtf8(wchar_t wc, char *buf, ShiftState &s) {
  288. const auto v = static_cast<uint32_t>(wc);
  289. if (v < 0x80) {
  290. *buf = static_cast<char>(v);
  291. return 1;
  292. } else if (v < 0x800) {
  293. *buf++ = static_cast<char>(0xc0 | (v >> 6));
  294. *buf = static_cast<char>(0x80 | (v & 0x3f));
  295. return 2;
  296. } else if (v < 0xd800 || (v - 0xe000) < 0x2000) {
  297. *buf++ = static_cast<char>(0xe0 | (v >> 12));
  298. *buf++ = static_cast<char>(0x80 | ((v >> 6) & 0x3f));
  299. *buf = static_cast<char>(0x80 | (v & 0x3f));
  300. return 3;
  301. } else if ((v - 0x10000) < 0x100000) {
  302. *buf++ = static_cast<char>(0xf0 | (v >> 18));
  303. *buf++ = static_cast<char>(0x80 | ((v >> 12) & 0x3f));
  304. *buf++ = static_cast<char>(0x80 | ((v >> 6) & 0x3f));
  305. *buf = static_cast<char>(0x80 | (v & 0x3f));
  306. return 4;
  307. } else if (v < 0xdc00) {
  308. s.saw_high_surrogate = true;
  309. s.bits = static_cast<uint8_t>(v & 0x3);
  310. const uint8_t high_bits = ((v >> 6) & 0xf) + 1;
  311. *buf++ = static_cast<char>(0xf0 | (high_bits >> 2));
  312. *buf =
  313. static_cast<char>(0x80 | static_cast<uint8_t>((high_bits & 0x3) << 4) |
  314. static_cast<uint8_t>((v >> 2) & 0xf));
  315. return 2;
  316. } else if (v < 0xe000 && s.saw_high_surrogate) {
  317. *buf++ = static_cast<char>(0x80 | static_cast<uint8_t>(s.bits << 4) |
  318. static_cast<uint8_t>((v >> 6) & 0xf));
  319. *buf = static_cast<char>(0x80 | (v & 0x3f));
  320. s.saw_high_surrogate = false;
  321. s.bits = 0;
  322. return 2;
  323. } else {
  324. return static_cast<size_t>(-1);
  325. }
  326. }
  327. inline bool ConvertStringArg(const wchar_t *v,
  328. size_t len,
  329. const FormatConversionSpecImpl conv,
  330. FormatSinkImpl *sink) {
  331. FixedArray<char> mb(len * 4);
  332. ShiftState s;
  333. size_t chars_written = 0;
  334. for (size_t i = 0; i < len; ++i) {
  335. const size_t chars = WideToUtf8(v[i], &mb[chars_written], s);
  336. if (chars == static_cast<size_t>(-1)) { return false; }
  337. chars_written += chars;
  338. }
  339. return ConvertStringArg(string_view(mb.data(), chars_written), conv, sink);
  340. }
  341. bool ConvertWCharTImpl(wchar_t v, const FormatConversionSpecImpl conv,
  342. FormatSinkImpl *sink) {
  343. char mb[4];
  344. ShiftState s;
  345. const size_t chars_written = WideToUtf8(v, mb, s);
  346. return chars_written != static_cast<size_t>(-1) && !s.saw_high_surrogate &&
  347. ConvertStringArg(string_view(mb, chars_written), conv, sink);
  348. }
  349. } // namespace
  350. bool ConvertBoolArg(bool v, FormatSinkImpl *sink) {
  351. if (v) {
  352. sink->Append("true");
  353. } else {
  354. sink->Append("false");
  355. }
  356. return true;
  357. }
  358. template <typename T>
  359. bool ConvertIntArg(T v, FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
  360. using U = typename MakeUnsigned<T>::type;
  361. IntDigits as_digits;
  362. // This odd casting is due to a bug in -Wswitch behavior in gcc49 which causes
  363. // it to complain about a switch/case type mismatch, even though both are
  364. // FormatConversionChar. Likely this is because at this point
  365. // FormatConversionChar is declared, but not defined.
  366. switch (static_cast<uint8_t>(conv.conversion_char())) {
  367. case static_cast<uint8_t>(FormatConversionCharInternal::c):
  368. return (std::is_same<T, wchar_t>::value ||
  369. (conv.length_mod() == LengthMod::l))
  370. ? ConvertWCharTImpl(static_cast<wchar_t>(v), conv, sink)
  371. : ConvertCharImpl(static_cast<char>(v), conv, sink);
  372. case static_cast<uint8_t>(FormatConversionCharInternal::o):
  373. as_digits.PrintAsOct(static_cast<U>(v));
  374. break;
  375. case static_cast<uint8_t>(FormatConversionCharInternal::x):
  376. as_digits.PrintAsHexLower(static_cast<U>(v));
  377. break;
  378. case static_cast<uint8_t>(FormatConversionCharInternal::X):
  379. as_digits.PrintAsHexUpper(static_cast<U>(v));
  380. break;
  381. case static_cast<uint8_t>(FormatConversionCharInternal::u):
  382. as_digits.PrintAsDec(static_cast<U>(v));
  383. break;
  384. case static_cast<uint8_t>(FormatConversionCharInternal::d):
  385. case static_cast<uint8_t>(FormatConversionCharInternal::i):
  386. case static_cast<uint8_t>(FormatConversionCharInternal::v):
  387. as_digits.PrintAsDec(v);
  388. break;
  389. case static_cast<uint8_t>(FormatConversionCharInternal::a):
  390. case static_cast<uint8_t>(FormatConversionCharInternal::e):
  391. case static_cast<uint8_t>(FormatConversionCharInternal::f):
  392. case static_cast<uint8_t>(FormatConversionCharInternal::g):
  393. case static_cast<uint8_t>(FormatConversionCharInternal::A):
  394. case static_cast<uint8_t>(FormatConversionCharInternal::E):
  395. case static_cast<uint8_t>(FormatConversionCharInternal::F):
  396. case static_cast<uint8_t>(FormatConversionCharInternal::G):
  397. return ConvertFloatImpl(static_cast<double>(v), conv, sink);
  398. default:
  399. ABSL_ASSUME(false);
  400. }
  401. if (conv.is_basic()) {
  402. sink->Append(as_digits.with_neg_and_zero());
  403. return true;
  404. }
  405. return ConvertIntImplInnerSlow(as_digits, conv, sink);
  406. }
  407. template bool ConvertIntArg<char>(char v, FormatConversionSpecImpl conv,
  408. FormatSinkImpl *sink);
  409. template bool ConvertIntArg<signed char>(signed char v,
  410. FormatConversionSpecImpl conv,
  411. FormatSinkImpl *sink);
  412. template bool ConvertIntArg<unsigned char>(unsigned char v,
  413. FormatConversionSpecImpl conv,
  414. FormatSinkImpl *sink);
  415. template bool ConvertIntArg<wchar_t>(wchar_t v, FormatConversionSpecImpl conv,
  416. FormatSinkImpl *sink);
  417. template bool ConvertIntArg<short>(short v, // NOLINT
  418. FormatConversionSpecImpl conv,
  419. FormatSinkImpl *sink);
  420. template bool ConvertIntArg<unsigned short>(unsigned short v, // NOLINT
  421. FormatConversionSpecImpl conv,
  422. FormatSinkImpl *sink);
  423. template bool ConvertIntArg<int>(int v, FormatConversionSpecImpl conv,
  424. FormatSinkImpl *sink);
  425. template bool ConvertIntArg<unsigned int>(unsigned int v,
  426. FormatConversionSpecImpl conv,
  427. FormatSinkImpl *sink);
  428. template bool ConvertIntArg<long>(long v, // NOLINT
  429. FormatConversionSpecImpl conv,
  430. FormatSinkImpl *sink);
  431. template bool ConvertIntArg<unsigned long>(unsigned long v, // NOLINT
  432. FormatConversionSpecImpl conv,
  433. FormatSinkImpl *sink);
  434. template bool ConvertIntArg<long long>(long long v, // NOLINT
  435. FormatConversionSpecImpl conv,
  436. FormatSinkImpl *sink);
  437. template bool ConvertIntArg<unsigned long long>(unsigned long long v, // NOLINT
  438. FormatConversionSpecImpl conv,
  439. FormatSinkImpl *sink);
  440. // ==================== Strings ====================
  441. StringConvertResult FormatConvertImpl(const std::string &v,
  442. const FormatConversionSpecImpl conv,
  443. FormatSinkImpl *sink) {
  444. return {ConvertStringArg(v, conv, sink)};
  445. }
  446. StringConvertResult FormatConvertImpl(const std::wstring &v,
  447. const FormatConversionSpecImpl conv,
  448. FormatSinkImpl *sink) {
  449. return {ConvertStringArg(v.data(), v.size(), conv, sink)};
  450. }
  451. StringConvertResult FormatConvertImpl(string_view v,
  452. const FormatConversionSpecImpl conv,
  453. FormatSinkImpl *sink) {
  454. return {ConvertStringArg(v, conv, sink)};
  455. }
  456. #if defined(ABSL_HAVE_STD_STRING_VIEW)
  457. StringConvertResult FormatConvertImpl(std::wstring_view v,
  458. const FormatConversionSpecImpl conv,
  459. FormatSinkImpl* sink) {
  460. return {ConvertStringArg(v.data(), v.size(), conv, sink)};
  461. }
  462. #endif
  463. StringPtrConvertResult FormatConvertImpl(const char* v,
  464. const FormatConversionSpecImpl conv,
  465. FormatSinkImpl* sink) {
  466. if (conv.conversion_char() == FormatConversionCharInternal::p)
  467. return {FormatConvertImpl(VoidPtr(v), conv, sink).value};
  468. size_t len;
  469. if (v == nullptr) {
  470. len = 0;
  471. } else if (conv.precision() < 0) {
  472. len = std::strlen(v);
  473. } else {
  474. // If precision is set, we look for the NUL-terminator on the valid range.
  475. len = static_cast<size_t>(std::find(v, v + conv.precision(), '\0') - v);
  476. }
  477. return {ConvertStringArg(string_view(v, len), conv, sink)};
  478. }
  479. StringPtrConvertResult FormatConvertImpl(const wchar_t* v,
  480. const FormatConversionSpecImpl conv,
  481. FormatSinkImpl* sink) {
  482. if (conv.conversion_char() == FormatConversionCharInternal::p) {
  483. return {FormatConvertImpl(VoidPtr(v), conv, sink).value};
  484. }
  485. size_t len;
  486. if (v == nullptr) {
  487. len = 0;
  488. } else if (conv.precision() < 0) {
  489. len = std::wcslen(v);
  490. } else {
  491. // If precision is set, we look for the NUL-terminator on the valid range.
  492. len = static_cast<size_t>(std::find(v, v + conv.precision(), L'\0') - v);
  493. }
  494. return {ConvertStringArg(v, len, conv, sink)};
  495. }
  496. StringPtrConvertResult FormatConvertImpl(std::nullptr_t,
  497. const FormatConversionSpecImpl conv,
  498. FormatSinkImpl* sink) {
  499. return FormatConvertImpl(static_cast<const char*>(nullptr), conv, sink);
  500. }
  501. // ==================== Raw pointers ====================
  502. ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
  503. VoidPtr v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
  504. if (!v.value) {
  505. sink->Append("(nil)");
  506. return {true};
  507. }
  508. IntDigits as_digits;
  509. as_digits.PrintAsHexLower(v.value);
  510. return {ConvertIntImplInnerSlow(as_digits, conv, sink)};
  511. }
  512. // ==================== Floats ====================
  513. FloatingConvertResult FormatConvertImpl(float v,
  514. const FormatConversionSpecImpl conv,
  515. FormatSinkImpl *sink) {
  516. return {ConvertFloatArg(v, conv, sink)};
  517. }
  518. FloatingConvertResult FormatConvertImpl(double v,
  519. const FormatConversionSpecImpl conv,
  520. FormatSinkImpl *sink) {
  521. return {ConvertFloatArg(v, conv, sink)};
  522. }
  523. FloatingConvertResult FormatConvertImpl(long double v,
  524. const FormatConversionSpecImpl conv,
  525. FormatSinkImpl *sink) {
  526. return {ConvertFloatArg(v, conv, sink)};
  527. }
  528. // ==================== Chars ====================
  529. CharConvertResult FormatConvertImpl(char v, const FormatConversionSpecImpl conv,
  530. FormatSinkImpl *sink) {
  531. return {ConvertIntArg(v, conv, sink)};
  532. }
  533. CharConvertResult FormatConvertImpl(wchar_t v,
  534. const FormatConversionSpecImpl conv,
  535. FormatSinkImpl* sink) {
  536. return {ConvertIntArg(v, conv, sink)};
  537. }
  538. // ==================== Ints ====================
  539. IntegralConvertResult FormatConvertImpl(signed char v,
  540. const FormatConversionSpecImpl conv,
  541. FormatSinkImpl *sink) {
  542. return {ConvertIntArg(v, conv, sink)};
  543. }
  544. IntegralConvertResult FormatConvertImpl(unsigned char v,
  545. const FormatConversionSpecImpl conv,
  546. FormatSinkImpl *sink) {
  547. return {ConvertIntArg(v, conv, sink)};
  548. }
  549. IntegralConvertResult FormatConvertImpl(short v, // NOLINT
  550. const FormatConversionSpecImpl conv,
  551. FormatSinkImpl *sink) {
  552. return {ConvertIntArg(v, conv, sink)};
  553. }
  554. IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT
  555. const FormatConversionSpecImpl conv,
  556. FormatSinkImpl *sink) {
  557. return {ConvertIntArg(v, conv, sink)};
  558. }
  559. IntegralConvertResult FormatConvertImpl(int v,
  560. const FormatConversionSpecImpl conv,
  561. FormatSinkImpl *sink) {
  562. return {ConvertIntArg(v, conv, sink)};
  563. }
  564. IntegralConvertResult FormatConvertImpl(unsigned v,
  565. const FormatConversionSpecImpl conv,
  566. FormatSinkImpl *sink) {
  567. return {ConvertIntArg(v, conv, sink)};
  568. }
  569. IntegralConvertResult FormatConvertImpl(long v, // NOLINT
  570. const FormatConversionSpecImpl conv,
  571. FormatSinkImpl *sink) {
  572. return {ConvertIntArg(v, conv, sink)};
  573. }
  574. IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT
  575. const FormatConversionSpecImpl conv,
  576. FormatSinkImpl *sink) {
  577. return {ConvertIntArg(v, conv, sink)};
  578. }
  579. IntegralConvertResult FormatConvertImpl(long long v, // NOLINT
  580. const FormatConversionSpecImpl conv,
  581. FormatSinkImpl *sink) {
  582. return {ConvertIntArg(v, conv, sink)};
  583. }
  584. IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT
  585. const FormatConversionSpecImpl conv,
  586. FormatSinkImpl *sink) {
  587. return {ConvertIntArg(v, conv, sink)};
  588. }
  589. IntegralConvertResult FormatConvertImpl(absl::int128 v,
  590. const FormatConversionSpecImpl conv,
  591. FormatSinkImpl *sink) {
  592. return {ConvertIntArg(v, conv, sink)};
  593. }
  594. IntegralConvertResult FormatConvertImpl(absl::uint128 v,
  595. const FormatConversionSpecImpl conv,
  596. FormatSinkImpl *sink) {
  597. return {ConvertIntArg(v, conv, sink)};
  598. }
  599. ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_();
  600. } // namespace str_format_internal
  601. ABSL_NAMESPACE_END
  602. } // namespace absl