extension.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. //
  2. // Copyright 2017 The Abseil Authors.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // https://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
  17. #define ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
  18. #include <limits.h>
  19. #include <cstddef>
  20. #include <cstring>
  21. #include <ostream>
  22. #include "absl/base/config.h"
  23. #include "absl/base/port.h"
  24. #include "absl/meta/type_traits.h"
  25. #include "absl/strings/internal/str_format/output.h"
  26. #include "absl/strings/string_view.h"
  27. namespace absl {
  28. ABSL_NAMESPACE_BEGIN
  29. enum class FormatConversionChar : uint8_t;
  30. enum class FormatConversionCharSet : uint64_t;
  31. namespace str_format_internal {
  32. class FormatRawSinkImpl {
  33. public:
  34. // Implicitly convert from any type that provides the hook function as
  35. // described above.
  36. template <typename T, decltype(str_format_internal::InvokeFlush(
  37. std::declval<T*>(), string_view()))* = nullptr>
  38. FormatRawSinkImpl(T* raw) // NOLINT
  39. : sink_(raw), write_(&FormatRawSinkImpl::Flush<T>) {}
  40. void Write(string_view s) { write_(sink_, s); }
  41. template <typename T>
  42. static FormatRawSinkImpl Extract(T s) {
  43. return s.sink_;
  44. }
  45. private:
  46. template <typename T>
  47. static void Flush(void* r, string_view s) {
  48. str_format_internal::InvokeFlush(static_cast<T*>(r), s);
  49. }
  50. void* sink_;
  51. void (*write_)(void*, string_view);
  52. };
  53. // An abstraction to which conversions write their string data.
  54. class FormatSinkImpl {
  55. public:
  56. explicit FormatSinkImpl(FormatRawSinkImpl raw) : raw_(raw) {}
  57. ~FormatSinkImpl() { Flush(); }
  58. void Flush() {
  59. raw_.Write(string_view(buf_, pos_ - buf_));
  60. pos_ = buf_;
  61. }
  62. void Append(size_t n, char c) {
  63. if (n == 0) return;
  64. size_ += n;
  65. auto raw_append = [&](size_t count) {
  66. memset(pos_, c, count);
  67. pos_ += count;
  68. };
  69. while (n > Avail()) {
  70. n -= Avail();
  71. if (Avail() > 0) {
  72. raw_append(Avail());
  73. }
  74. Flush();
  75. }
  76. raw_append(n);
  77. }
  78. void Append(string_view v) {
  79. size_t n = v.size();
  80. if (n == 0) return;
  81. size_ += n;
  82. if (n >= Avail()) {
  83. Flush();
  84. raw_.Write(v);
  85. return;
  86. }
  87. memcpy(pos_, v.data(), n);
  88. pos_ += n;
  89. }
  90. size_t size() const { return size_; }
  91. // Put 'v' to 'sink' with specified width, precision, and left flag.
  92. bool PutPaddedString(string_view v, int width, int precision, bool left);
  93. template <typename T>
  94. T Wrap() {
  95. return T(this);
  96. }
  97. template <typename T>
  98. static FormatSinkImpl* Extract(T* s) {
  99. return s->sink_;
  100. }
  101. private:
  102. size_t Avail() const { return buf_ + sizeof(buf_) - pos_; }
  103. FormatRawSinkImpl raw_;
  104. size_t size_ = 0;
  105. char* pos_ = buf_;
  106. char buf_[1024];
  107. };
  108. enum class Flags : uint8_t {
  109. kBasic = 0,
  110. kLeft = 1 << 0,
  111. kShowPos = 1 << 1,
  112. kSignCol = 1 << 2,
  113. kAlt = 1 << 3,
  114. kZero = 1 << 4,
  115. // This is not a real flag. It just exists to turn off kBasic when no other
  116. // flags are set. This is for when width/precision are specified.
  117. kNonBasic = 1 << 5,
  118. };
  119. constexpr Flags operator|(Flags a, Flags b) {
  120. return static_cast<Flags>(static_cast<uint8_t>(a) | static_cast<uint8_t>(b));
  121. }
  122. constexpr bool FlagsContains(Flags haystack, Flags needle) {
  123. return (static_cast<uint8_t>(haystack) & static_cast<uint8_t>(needle)) ==
  124. static_cast<uint8_t>(needle);
  125. }
  126. std::string FlagsToString(Flags v);
  127. inline std::ostream& operator<<(std::ostream& os, Flags v) {
  128. return os << FlagsToString(v);
  129. }
  130. // clang-format off
  131. #define ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \
  132. /* text */ \
  133. X_VAL(c) X_SEP X_VAL(s) X_SEP \
  134. /* ints */ \
  135. X_VAL(d) X_SEP X_VAL(i) X_SEP X_VAL(o) X_SEP \
  136. X_VAL(u) X_SEP X_VAL(x) X_SEP X_VAL(X) X_SEP \
  137. /* floats */ \
  138. X_VAL(f) X_SEP X_VAL(F) X_SEP X_VAL(e) X_SEP X_VAL(E) X_SEP \
  139. X_VAL(g) X_SEP X_VAL(G) X_SEP X_VAL(a) X_SEP X_VAL(A) X_SEP \
  140. /* misc */ \
  141. X_VAL(n) X_SEP X_VAL(p)
  142. // clang-format on
  143. // This type should not be referenced, it exists only to provide labels
  144. // internally that match the values declared in FormatConversionChar in
  145. // str_format.h. This is meant to allow internal libraries to use the same
  146. // declared interface type as the public interface
  147. // (absl::StrFormatConversionChar) while keeping the definition in a public
  148. // header.
  149. // Internal libraries should use the form
  150. // `FormatConversionCharInternal::c`, `FormatConversionCharInternal::kNone` for
  151. // comparisons. Use in switch statements is not recommended due to a bug in how
  152. // gcc 4.9 -Wswitch handles declared but undefined enums.
  153. struct FormatConversionCharInternal {
  154. FormatConversionCharInternal() = delete;
  155. private:
  156. // clang-format off
  157. enum class Enum : uint8_t {
  158. c, s, // text
  159. d, i, o, u, x, X, // int
  160. f, F, e, E, g, G, a, A, // float
  161. n, p, // misc
  162. kNone
  163. };
  164. // clang-format on
  165. public:
  166. #define ABSL_INTERNAL_X_VAL(id) \
  167. static constexpr FormatConversionChar id = \
  168. static_cast<FormatConversionChar>(Enum::id);
  169. ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
  170. #undef ABSL_INTERNAL_X_VAL
  171. static constexpr FormatConversionChar kNone =
  172. static_cast<FormatConversionChar>(Enum::kNone);
  173. };
  174. // clang-format on
  175. inline FormatConversionChar FormatConversionCharFromChar(char c) {
  176. switch (c) {
  177. #define ABSL_INTERNAL_X_VAL(id) \
  178. case #id[0]: \
  179. return FormatConversionCharInternal::id;
  180. ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
  181. #undef ABSL_INTERNAL_X_VAL
  182. }
  183. return FormatConversionCharInternal::kNone;
  184. }
  185. inline bool FormatConversionCharIsUpper(FormatConversionChar c) {
  186. if (c == FormatConversionCharInternal::X ||
  187. c == FormatConversionCharInternal::F ||
  188. c == FormatConversionCharInternal::E ||
  189. c == FormatConversionCharInternal::G ||
  190. c == FormatConversionCharInternal::A) {
  191. return true;
  192. } else {
  193. return false;
  194. }
  195. }
  196. inline bool FormatConversionCharIsFloat(FormatConversionChar c) {
  197. if (c == FormatConversionCharInternal::a ||
  198. c == FormatConversionCharInternal::e ||
  199. c == FormatConversionCharInternal::f ||
  200. c == FormatConversionCharInternal::g ||
  201. c == FormatConversionCharInternal::A ||
  202. c == FormatConversionCharInternal::E ||
  203. c == FormatConversionCharInternal::F ||
  204. c == FormatConversionCharInternal::G) {
  205. return true;
  206. } else {
  207. return false;
  208. }
  209. }
  210. inline char FormatConversionCharToChar(FormatConversionChar c) {
  211. if (c == FormatConversionCharInternal::kNone) {
  212. return '\0';
  213. #define ABSL_INTERNAL_X_VAL(e) \
  214. } else if (c == FormatConversionCharInternal::e) { \
  215. return #e[0];
  216. #define ABSL_INTERNAL_X_SEP
  217. ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL,
  218. ABSL_INTERNAL_X_SEP)
  219. } else {
  220. return '\0';
  221. }
  222. #undef ABSL_INTERNAL_X_VAL
  223. #undef ABSL_INTERNAL_X_SEP
  224. }
  225. // The associated char.
  226. inline std::ostream& operator<<(std::ostream& os, FormatConversionChar v) {
  227. char c = FormatConversionCharToChar(v);
  228. if (!c) c = '?';
  229. return os << c;
  230. }
  231. struct FormatConversionSpecImplFriend;
  232. class FormatConversionSpecImpl {
  233. public:
  234. // Width and precison are not specified, no flags are set.
  235. bool is_basic() const { return flags_ == Flags::kBasic; }
  236. bool has_left_flag() const { return FlagsContains(flags_, Flags::kLeft); }
  237. bool has_show_pos_flag() const {
  238. return FlagsContains(flags_, Flags::kShowPos);
  239. }
  240. bool has_sign_col_flag() const {
  241. return FlagsContains(flags_, Flags::kSignCol);
  242. }
  243. bool has_alt_flag() const { return FlagsContains(flags_, Flags::kAlt); }
  244. bool has_zero_flag() const { return FlagsContains(flags_, Flags::kZero); }
  245. FormatConversionChar conversion_char() const {
  246. // Keep this field first in the struct . It generates better code when
  247. // accessing it when ConversionSpec is passed by value in registers.
  248. static_assert(offsetof(FormatConversionSpecImpl, conv_) == 0, "");
  249. return conv_;
  250. }
  251. // Returns the specified width. If width is unspecfied, it returns a negative
  252. // value.
  253. int width() const { return width_; }
  254. // Returns the specified precision. If precision is unspecfied, it returns a
  255. // negative value.
  256. int precision() const { return precision_; }
  257. template <typename T>
  258. T Wrap() {
  259. return T(*this);
  260. }
  261. private:
  262. friend struct str_format_internal::FormatConversionSpecImplFriend;
  263. FormatConversionChar conv_ = FormatConversionCharInternal::kNone;
  264. Flags flags_;
  265. int width_;
  266. int precision_;
  267. };
  268. struct FormatConversionSpecImplFriend final {
  269. static void SetFlags(Flags f, FormatConversionSpecImpl* conv) {
  270. conv->flags_ = f;
  271. }
  272. static void SetConversionChar(FormatConversionChar c,
  273. FormatConversionSpecImpl* conv) {
  274. conv->conv_ = c;
  275. }
  276. static void SetWidth(int w, FormatConversionSpecImpl* conv) {
  277. conv->width_ = w;
  278. }
  279. static void SetPrecision(int p, FormatConversionSpecImpl* conv) {
  280. conv->precision_ = p;
  281. }
  282. static std::string FlagsToString(const FormatConversionSpecImpl& spec) {
  283. return str_format_internal::FlagsToString(spec.flags_);
  284. }
  285. };
  286. // Type safe OR operator.
  287. // We need this for two reasons:
  288. // 1. operator| on enums makes them decay to integers and the result is an
  289. // integer. We need the result to stay as an enum.
  290. // 2. We use "enum class" which would not work even if we accepted the decay.
  291. constexpr FormatConversionCharSet FormatConversionCharSetUnion(
  292. FormatConversionCharSet a) {
  293. return a;
  294. }
  295. template <typename... CharSet>
  296. constexpr FormatConversionCharSet FormatConversionCharSetUnion(
  297. FormatConversionCharSet a, CharSet... rest) {
  298. return static_cast<FormatConversionCharSet>(
  299. static_cast<uint64_t>(a) |
  300. static_cast<uint64_t>(FormatConversionCharSetUnion(rest...)));
  301. }
  302. constexpr uint64_t FormatConversionCharToConvInt(FormatConversionChar c) {
  303. return uint64_t{1} << (1 + static_cast<uint8_t>(c));
  304. }
  305. constexpr uint64_t FormatConversionCharToConvInt(char conv) {
  306. return
  307. #define ABSL_INTERNAL_CHAR_SET_CASE(c) \
  308. conv == #c[0] \
  309. ? FormatConversionCharToConvInt(FormatConversionCharInternal::c) \
  310. :
  311. ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
  312. #undef ABSL_INTERNAL_CHAR_SET_CASE
  313. conv == '*'
  314. ? 1
  315. : 0;
  316. }
  317. constexpr FormatConversionCharSet FormatConversionCharToConvValue(char conv) {
  318. return static_cast<FormatConversionCharSet>(
  319. FormatConversionCharToConvInt(conv));
  320. }
  321. struct FormatConversionCharSetInternal {
  322. #define ABSL_INTERNAL_CHAR_SET_CASE(c) \
  323. static constexpr FormatConversionCharSet c = \
  324. FormatConversionCharToConvValue(#c[0]);
  325. ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
  326. #undef ABSL_INTERNAL_CHAR_SET_CASE
  327. // Used for width/precision '*' specification.
  328. static constexpr FormatConversionCharSet kStar =
  329. FormatConversionCharToConvValue('*');
  330. static constexpr FormatConversionCharSet kIntegral =
  331. FormatConversionCharSetUnion(d, i, u, o, x, X);
  332. static constexpr FormatConversionCharSet kFloating =
  333. FormatConversionCharSetUnion(a, e, f, g, A, E, F, G);
  334. static constexpr FormatConversionCharSet kNumeric =
  335. FormatConversionCharSetUnion(kIntegral, kFloating);
  336. static constexpr FormatConversionCharSet kPointer = p;
  337. };
  338. // Type safe OR operator.
  339. // We need this for two reasons:
  340. // 1. operator| on enums makes them decay to integers and the result is an
  341. // integer. We need the result to stay as an enum.
  342. // 2. We use "enum class" which would not work even if we accepted the decay.
  343. constexpr FormatConversionCharSet operator|(FormatConversionCharSet a,
  344. FormatConversionCharSet b) {
  345. return FormatConversionCharSetUnion(a, b);
  346. }
  347. // Overloaded conversion functions to support absl::ParsedFormat.
  348. // Get a conversion with a single character in it.
  349. constexpr FormatConversionCharSet ToFormatConversionCharSet(char c) {
  350. return static_cast<FormatConversionCharSet>(
  351. FormatConversionCharToConvValue(c));
  352. }
  353. // Get a conversion with a single character in it.
  354. constexpr FormatConversionCharSet ToFormatConversionCharSet(
  355. FormatConversionCharSet c) {
  356. return c;
  357. }
  358. template <typename T>
  359. void ToFormatConversionCharSet(T) = delete;
  360. // Checks whether `c` exists in `set`.
  361. constexpr bool Contains(FormatConversionCharSet set, char c) {
  362. return (static_cast<uint64_t>(set) &
  363. static_cast<uint64_t>(FormatConversionCharToConvValue(c))) != 0;
  364. }
  365. // Checks whether all the characters in `c` are contained in `set`
  366. constexpr bool Contains(FormatConversionCharSet set,
  367. FormatConversionCharSet c) {
  368. return (static_cast<uint64_t>(set) & static_cast<uint64_t>(c)) ==
  369. static_cast<uint64_t>(c);
  370. }
  371. // Checks whether all the characters in `c` are contained in `set`
  372. constexpr bool Contains(FormatConversionCharSet set, FormatConversionChar c) {
  373. return (static_cast<uint64_t>(set) & FormatConversionCharToConvInt(c)) != 0;
  374. }
  375. // Return capacity - used, clipped to a minimum of 0.
  376. inline size_t Excess(size_t used, size_t capacity) {
  377. return used < capacity ? capacity - used : 0;
  378. }
  379. } // namespace str_format_internal
  380. ABSL_NAMESPACE_END
  381. } // namespace absl
  382. #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_