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
19
20 #include <cstddef>
21 #include <cstdint>
22 #include <cstring>
23 #include <ostream>
24 #include <string>
25
26 #include "absl/base/config.h"
27 #include "absl/strings/internal/str_format/output.h"
28 #include "absl/strings/string_view.h"
29
30 namespace absl {
31 ABSL_NAMESPACE_BEGIN
32
33 enum class FormatConversionChar : uint8_t;
34 enum class FormatConversionCharSet : uint64_t;
35 enum class LengthMod : std::uint8_t { h, hh, l, ll, L, j, z, t, q, none };
36
37 namespace str_format_internal {
38
39 class FormatRawSinkImpl {
40 public:
41 // Implicitly convert from any type that provides the hook function as
42 // described above.
43 template <typename T, decltype(str_format_internal::InvokeFlush(
44 std::declval<T*>(), string_view()))* = nullptr>
FormatRawSinkImpl(T * raw)45 FormatRawSinkImpl(T* raw) // NOLINT
46 : sink_(raw), write_(&FormatRawSinkImpl::Flush<T>) {}
47
Write(string_view s)48 void Write(string_view s) { write_(sink_, s); }
49
50 template <typename T>
Extract(T s)51 static FormatRawSinkImpl Extract(T s) {
52 return s.sink_;
53 }
54
55 private:
56 template <typename T>
Flush(void * r,string_view s)57 static void Flush(void* r, string_view s) {
58 str_format_internal::InvokeFlush(static_cast<T*>(r), s);
59 }
60
61 void* sink_;
62 void (*write_)(void*, string_view);
63 };
64
65 // An abstraction to which conversions write their string data.
66 class FormatSinkImpl {
67 public:
FormatSinkImpl(FormatRawSinkImpl raw)68 explicit FormatSinkImpl(FormatRawSinkImpl raw) : raw_(raw) {}
69
~FormatSinkImpl()70 ~FormatSinkImpl() { Flush(); }
71
Flush()72 void Flush() {
73 raw_.Write(string_view(buf_, static_cast<size_t>(pos_ - buf_)));
74 pos_ = buf_;
75 }
76
Append(size_t n,char c)77 void Append(size_t n, char c) {
78 if (n == 0) return;
79 size_ += n;
80 auto raw_append = [&](size_t count) {
81 memset(pos_, c, count);
82 pos_ += count;
83 };
84 while (n > Avail()) {
85 n -= Avail();
86 if (Avail() > 0) {
87 raw_append(Avail());
88 }
89 Flush();
90 }
91 raw_append(n);
92 }
93
Append(string_view v)94 void Append(string_view v) {
95 size_t n = v.size();
96 if (n == 0) return;
97 size_ += n;
98 if (n >= Avail()) {
99 Flush();
100 raw_.Write(v);
101 return;
102 }
103 memcpy(pos_, v.data(), n);
104 pos_ += n;
105 }
106
size()107 size_t size() const { return size_; }
108
109 // Put 'v' to 'sink' with specified width, precision, and left flag.
110 bool PutPaddedString(string_view v, int width, int precision, bool left);
111
112 template <typename T>
Wrap()113 T Wrap() {
114 return T(this);
115 }
116
117 template <typename T>
Extract(T * s)118 static FormatSinkImpl* Extract(T* s) {
119 return s->sink_;
120 }
121
122 private:
Avail()123 size_t Avail() const {
124 return static_cast<size_t>(buf_ + sizeof(buf_) - pos_);
125 }
126
127 FormatRawSinkImpl raw_;
128 size_t size_ = 0;
129 char* pos_ = buf_;
130 char buf_[1024];
131 };
132
133 enum class Flags : uint8_t {
134 kBasic = 0,
135 kLeft = 1 << 0,
136 kShowPos = 1 << 1,
137 kSignCol = 1 << 2,
138 kAlt = 1 << 3,
139 kZero = 1 << 4,
140 // This is not a real flag. It just exists to turn off kBasic when no other
141 // flags are set. This is for when width/precision are specified, or a length
142 // modifier affects the behavior ("%lc").
143 kNonBasic = 1 << 5,
144 };
145
146 constexpr Flags operator|(Flags a, Flags b) {
147 return static_cast<Flags>(static_cast<uint8_t>(a) | static_cast<uint8_t>(b));
148 }
149
FlagsContains(Flags haystack,Flags needle)150 constexpr bool FlagsContains(Flags haystack, Flags needle) {
151 return (static_cast<uint8_t>(haystack) & static_cast<uint8_t>(needle)) ==
152 static_cast<uint8_t>(needle);
153 }
154
155 std::string FlagsToString(Flags v);
156
157 inline std::ostream& operator<<(std::ostream& os, Flags v) {
158 return os << FlagsToString(v);
159 }
160
161 // clang-format off
162 #define ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \
163 /* text */ \
164 X_VAL(c) X_SEP X_VAL(s) X_SEP \
165 /* ints */ \
166 X_VAL(d) X_SEP X_VAL(i) X_SEP X_VAL(o) X_SEP \
167 X_VAL(u) X_SEP X_VAL(x) X_SEP X_VAL(X) X_SEP \
168 /* floats */ \
169 X_VAL(f) X_SEP X_VAL(F) X_SEP X_VAL(e) X_SEP X_VAL(E) X_SEP \
170 X_VAL(g) X_SEP X_VAL(G) X_SEP X_VAL(a) X_SEP X_VAL(A) X_SEP \
171 /* misc */ \
172 X_VAL(n) X_SEP X_VAL(p) X_SEP X_VAL(v)
173 // clang-format on
174
175 // This type should not be referenced, it exists only to provide labels
176 // internally that match the values declared in FormatConversionChar in
177 // str_format.h. This is meant to allow internal libraries to use the same
178 // declared interface type as the public interface
179 // (absl::StrFormatConversionChar) while keeping the definition in a public
180 // header.
181 // Internal libraries should use the form
182 // `FormatConversionCharInternal::c`, `FormatConversionCharInternal::kNone` for
183 // comparisons. Use in switch statements is not recommended due to a bug in how
184 // gcc 4.9 -Wswitch handles declared but undefined enums.
185 struct FormatConversionCharInternal {
186 FormatConversionCharInternal() = delete;
187
188 private:
189 // clang-format off
190 enum class Enum : uint8_t {
191 c, s, // text
192 d, i, o, u, x, X, // int
193 f, F, e, E, g, G, a, A, // float
194 n, p, v, // misc
195 kNone
196 };
197 // clang-format on
198 public:
199 #define ABSL_INTERNAL_X_VAL(id) \
200 static constexpr FormatConversionChar id = \
201 static_cast<FormatConversionChar>(Enum::id);
202 ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
203 #undef ABSL_INTERNAL_X_VAL
204 static constexpr FormatConversionChar kNone =
205 static_cast<FormatConversionChar>(Enum::kNone);
206 };
207 // clang-format on
208
FormatConversionCharFromChar(char c)209 inline FormatConversionChar FormatConversionCharFromChar(char c) {
210 switch (c) {
211 #define ABSL_INTERNAL_X_VAL(id) \
212 case #id[0]: \
213 return FormatConversionCharInternal::id;
214 ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
215 #undef ABSL_INTERNAL_X_VAL
216 }
217 return FormatConversionCharInternal::kNone;
218 }
219
FormatConversionCharIsUpper(FormatConversionChar c)220 inline bool FormatConversionCharIsUpper(FormatConversionChar c) {
221 if (c == FormatConversionCharInternal::X ||
222 c == FormatConversionCharInternal::F ||
223 c == FormatConversionCharInternal::E ||
224 c == FormatConversionCharInternal::G ||
225 c == FormatConversionCharInternal::A) {
226 return true;
227 } else {
228 return false;
229 }
230 }
231
FormatConversionCharIsFloat(FormatConversionChar c)232 inline bool FormatConversionCharIsFloat(FormatConversionChar c) {
233 if (c == FormatConversionCharInternal::a ||
234 c == FormatConversionCharInternal::e ||
235 c == FormatConversionCharInternal::f ||
236 c == FormatConversionCharInternal::g ||
237 c == FormatConversionCharInternal::A ||
238 c == FormatConversionCharInternal::E ||
239 c == FormatConversionCharInternal::F ||
240 c == FormatConversionCharInternal::G) {
241 return true;
242 } else {
243 return false;
244 }
245 }
246
FormatConversionCharToChar(FormatConversionChar c)247 inline char FormatConversionCharToChar(FormatConversionChar c) {
248 if (c == FormatConversionCharInternal::kNone) {
249 return '\0';
250
251 #define ABSL_INTERNAL_X_VAL(e) \
252 } else if (c == FormatConversionCharInternal::e) { \
253 return #e[0];
254 #define ABSL_INTERNAL_X_SEP
255 ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL,
256 ABSL_INTERNAL_X_SEP)
257 } else {
258 return '\0';
259 }
260
261 #undef ABSL_INTERNAL_X_VAL
262 #undef ABSL_INTERNAL_X_SEP
263 }
264
265 // The associated char.
266 inline std::ostream& operator<<(std::ostream& os, FormatConversionChar v) {
267 char c = FormatConversionCharToChar(v);
268 if (!c) c = '?';
269 return os << c;
270 }
271
272 struct FormatConversionSpecImplFriend;
273
274 class FormatConversionSpecImpl {
275 public:
276 // Width and precision are not specified, no flags are set.
is_basic()277 bool is_basic() const { return flags_ == Flags::kBasic; }
has_left_flag()278 bool has_left_flag() const { return FlagsContains(flags_, Flags::kLeft); }
has_show_pos_flag()279 bool has_show_pos_flag() const {
280 return FlagsContains(flags_, Flags::kShowPos);
281 }
has_sign_col_flag()282 bool has_sign_col_flag() const {
283 return FlagsContains(flags_, Flags::kSignCol);
284 }
has_alt_flag()285 bool has_alt_flag() const { return FlagsContains(flags_, Flags::kAlt); }
has_zero_flag()286 bool has_zero_flag() const { return FlagsContains(flags_, Flags::kZero); }
287
length_mod()288 LengthMod length_mod() const { return length_mod_; }
289
conversion_char()290 FormatConversionChar conversion_char() const {
291 // Keep this field first in the struct . It generates better code when
292 // accessing it when ConversionSpec is passed by value in registers.
293 static_assert(offsetof(FormatConversionSpecImpl, conv_) == 0, "");
294 return conv_;
295 }
296
set_conversion_char(FormatConversionChar c)297 void set_conversion_char(FormatConversionChar c) { conv_ = c; }
298
299 // Returns the specified width. If width is unspecfied, it returns a negative
300 // value.
width()301 int width() const { return width_; }
302 // Returns the specified precision. If precision is unspecfied, it returns a
303 // negative value.
precision()304 int precision() const { return precision_; }
305
306 template <typename T>
Wrap()307 T Wrap() {
308 return T(*this);
309 }
310
311 private:
312 friend struct str_format_internal::FormatConversionSpecImplFriend;
313 FormatConversionChar conv_ = FormatConversionCharInternal::kNone;
314 Flags flags_;
315 LengthMod length_mod_ = LengthMod::none;
316 int width_;
317 int precision_;
318 };
319
320 struct FormatConversionSpecImplFriend final {
SetFlagsfinal321 static void SetFlags(Flags f, FormatConversionSpecImpl* conv) {
322 conv->flags_ = f;
323 }
SetLengthModfinal324 static void SetLengthMod(LengthMod l, FormatConversionSpecImpl* conv) {
325 conv->length_mod_ = l;
326 }
SetConversionCharfinal327 static void SetConversionChar(FormatConversionChar c,
328 FormatConversionSpecImpl* conv) {
329 conv->conv_ = c;
330 }
SetWidthfinal331 static void SetWidth(int w, FormatConversionSpecImpl* conv) {
332 conv->width_ = w;
333 }
SetPrecisionfinal334 static void SetPrecision(int p, FormatConversionSpecImpl* conv) {
335 conv->precision_ = p;
336 }
FlagsToStringfinal337 static std::string FlagsToString(const FormatConversionSpecImpl& spec) {
338 return str_format_internal::FlagsToString(spec.flags_);
339 }
340 };
341
342 // Type safe OR operator.
343 // We need this for two reasons:
344 // 1. operator| on enums makes them decay to integers and the result is an
345 // integer. We need the result to stay as an enum.
346 // 2. We use "enum class" which would not work even if we accepted the decay.
FormatConversionCharSetUnion(FormatConversionCharSet a)347 constexpr FormatConversionCharSet FormatConversionCharSetUnion(
348 FormatConversionCharSet a) {
349 return a;
350 }
351
352 template <typename... CharSet>
FormatConversionCharSetUnion(FormatConversionCharSet a,CharSet...rest)353 constexpr FormatConversionCharSet FormatConversionCharSetUnion(
354 FormatConversionCharSet a, CharSet... rest) {
355 return static_cast<FormatConversionCharSet>(
356 static_cast<uint64_t>(a) |
357 static_cast<uint64_t>(FormatConversionCharSetUnion(rest...)));
358 }
359
FormatConversionCharToConvInt(FormatConversionChar c)360 constexpr uint64_t FormatConversionCharToConvInt(FormatConversionChar c) {
361 return uint64_t{1} << (1 + static_cast<uint8_t>(c));
362 }
363
FormatConversionCharToConvInt(char conv)364 constexpr uint64_t FormatConversionCharToConvInt(char conv) {
365 return
366 #define ABSL_INTERNAL_CHAR_SET_CASE(c) \
367 conv == #c[0] \
368 ? FormatConversionCharToConvInt(FormatConversionCharInternal::c) \
369 :
370 ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
371 #undef ABSL_INTERNAL_CHAR_SET_CASE
372 conv == '*'
373 ? 1
374 : 0;
375 }
376
FormatConversionCharToConvValue(char conv)377 constexpr FormatConversionCharSet FormatConversionCharToConvValue(char conv) {
378 return static_cast<FormatConversionCharSet>(
379 FormatConversionCharToConvInt(conv));
380 }
381
382 struct FormatConversionCharSetInternal {
383 #define ABSL_INTERNAL_CHAR_SET_CASE(c) \
384 static constexpr FormatConversionCharSet c = \
385 FormatConversionCharToConvValue(#c[0]);
386 ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
387 #undef ABSL_INTERNAL_CHAR_SET_CASE
388
389 // Used for width/precision '*' specification.
390 static constexpr FormatConversionCharSet kStar =
391 FormatConversionCharToConvValue('*');
392
393 static constexpr FormatConversionCharSet kIntegral =
394 FormatConversionCharSetUnion(d, i, u, o, x, X);
395 static constexpr FormatConversionCharSet kFloating =
396 FormatConversionCharSetUnion(a, e, f, g, A, E, F, G);
397 static constexpr FormatConversionCharSet kNumeric =
398 FormatConversionCharSetUnion(kIntegral, kFloating);
399 static constexpr FormatConversionCharSet kPointer = p;
400 };
401
402 // Type safe OR operator.
403 // We need this for two reasons:
404 // 1. operator| on enums makes them decay to integers and the result is an
405 // integer. We need the result to stay as an enum.
406 // 2. We use "enum class" which would not work even if we accepted the decay.
407 constexpr FormatConversionCharSet operator|(FormatConversionCharSet a,
408 FormatConversionCharSet b) {
409 return FormatConversionCharSetUnion(a, b);
410 }
411
412 // Overloaded conversion functions to support absl::ParsedFormat.
413 // Get a conversion with a single character in it.
ToFormatConversionCharSet(char c)414 constexpr FormatConversionCharSet ToFormatConversionCharSet(char c) {
415 return static_cast<FormatConversionCharSet>(
416 FormatConversionCharToConvValue(c));
417 }
418
419 // Get a conversion with a single character in it.
ToFormatConversionCharSet(FormatConversionCharSet c)420 constexpr FormatConversionCharSet ToFormatConversionCharSet(
421 FormatConversionCharSet c) {
422 return c;
423 }
424
425 template <typename T>
426 void ToFormatConversionCharSet(T) = delete;
427
428 // Checks whether `c` exists in `set`.
Contains(FormatConversionCharSet set,char c)429 constexpr bool Contains(FormatConversionCharSet set, char c) {
430 return (static_cast<uint64_t>(set) &
431 static_cast<uint64_t>(FormatConversionCharToConvValue(c))) != 0;
432 }
433
434 // Checks whether all the characters in `c` are contained in `set`
Contains(FormatConversionCharSet set,FormatConversionCharSet c)435 constexpr bool Contains(FormatConversionCharSet set,
436 FormatConversionCharSet c) {
437 return (static_cast<uint64_t>(set) & static_cast<uint64_t>(c)) ==
438 static_cast<uint64_t>(c);
439 }
440
441 // Checks whether all the characters in `c` are contained in `set`
Contains(FormatConversionCharSet set,FormatConversionChar c)442 constexpr bool Contains(FormatConversionCharSet set, FormatConversionChar c) {
443 return (static_cast<uint64_t>(set) & FormatConversionCharToConvInt(c)) != 0;
444 }
445
446 // Return capacity - used, clipped to a minimum of 0.
Excess(size_t used,size_t capacity)447 inline size_t Excess(size_t used, size_t capacity) {
448 return used < capacity ? capacity - used : 0;
449 }
450
451 } // namespace str_format_internal
452
453 ABSL_NAMESPACE_END
454 } // namespace absl
455
456 #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
457