• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <limits.h>
20 
21 #include <cstddef>
22 #include <cstring>
23 #include <ostream>
24 
25 #include "absl/base/config.h"
26 #include "absl/base/port.h"
27 #include "absl/meta/type_traits.h"
28 #include "absl/strings/internal/str_format/output.h"
29 #include "absl/strings/string_view.h"
30 
31 namespace absl {
32 ABSL_NAMESPACE_BEGIN
33 
34 enum class FormatConversionChar : uint8_t;
35 enum class FormatConversionCharSet : uint64_t;
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_, 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 { return buf_ + sizeof(buf_) - pos_; }
124 
125   FormatRawSinkImpl raw_;
126   size_t size_ = 0;
127   char* pos_ = buf_;
128   char buf_[1024];
129 };
130 
131 enum class Flags : uint8_t {
132   kBasic = 0,
133   kLeft = 1 << 0,
134   kShowPos = 1 << 1,
135   kSignCol = 1 << 2,
136   kAlt = 1 << 3,
137   kZero = 1 << 4,
138   // This is not a real flag. It just exists to turn off kBasic when no other
139   // flags are set. This is for when width/precision are specified.
140   kNonBasic = 1 << 5,
141 };
142 
143 constexpr Flags operator|(Flags a, Flags b) {
144   return static_cast<Flags>(static_cast<uint8_t>(a) | static_cast<uint8_t>(b));
145 }
146 
FlagsContains(Flags haystack,Flags needle)147 constexpr bool FlagsContains(Flags haystack, Flags needle) {
148   return (static_cast<uint8_t>(haystack) & static_cast<uint8_t>(needle)) ==
149          static_cast<uint8_t>(needle);
150 }
151 
152 std::string FlagsToString(Flags v);
153 
154 inline std::ostream& operator<<(std::ostream& os, Flags v) {
155   return os << FlagsToString(v);
156 }
157 
158 // clang-format off
159 #define ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \
160   /* text */ \
161   X_VAL(c) X_SEP X_VAL(s) X_SEP \
162   /* ints */ \
163   X_VAL(d) X_SEP X_VAL(i) X_SEP X_VAL(o) X_SEP \
164   X_VAL(u) X_SEP X_VAL(x) X_SEP X_VAL(X) X_SEP \
165   /* floats */ \
166   X_VAL(f) X_SEP X_VAL(F) X_SEP X_VAL(e) X_SEP X_VAL(E) X_SEP \
167   X_VAL(g) X_SEP X_VAL(G) X_SEP X_VAL(a) X_SEP X_VAL(A) X_SEP \
168   /* misc */ \
169   X_VAL(n) X_SEP X_VAL(p)
170 // clang-format on
171 
172 // This type should not be referenced, it exists only to provide labels
173 // internally that match the values declared in FormatConversionChar in
174 // str_format.h. This is meant to allow internal libraries to use the same
175 // declared interface type as the public interface
176 // (absl::StrFormatConversionChar) while keeping the definition in a public
177 // header.
178 // Internal libraries should use the form
179 // `FormatConversionCharInternal::c`, `FormatConversionCharInternal::kNone` for
180 // comparisons.  Use in switch statements is not recommended due to a bug in how
181 // gcc 4.9 -Wswitch handles declared but undefined enums.
182 struct FormatConversionCharInternal {
183   FormatConversionCharInternal() = delete;
184 
185  private:
186   // clang-format off
187   enum class Enum : uint8_t {
188     c, s,                    // text
189     d, i, o, u, x, X,        // int
190     f, F, e, E, g, G, a, A,  // float
191     n, p,                    // misc
192     kNone
193   };
194   // clang-format on
195  public:
196 #define ABSL_INTERNAL_X_VAL(id)              \
197   static constexpr FormatConversionChar id = \
198       static_cast<FormatConversionChar>(Enum::id);
199   ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
200 #undef ABSL_INTERNAL_X_VAL
201   static constexpr FormatConversionChar kNone =
202       static_cast<FormatConversionChar>(Enum::kNone);
203 };
204 // clang-format on
205 
FormatConversionCharFromChar(char c)206 inline FormatConversionChar FormatConversionCharFromChar(char c) {
207   switch (c) {
208 #define ABSL_INTERNAL_X_VAL(id) \
209   case #id[0]:                  \
210     return FormatConversionCharInternal::id;
211     ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
212 #undef ABSL_INTERNAL_X_VAL
213   }
214   return FormatConversionCharInternal::kNone;
215 }
216 
FormatConversionCharIsUpper(FormatConversionChar c)217 inline bool FormatConversionCharIsUpper(FormatConversionChar c) {
218   if (c == FormatConversionCharInternal::X ||
219       c == FormatConversionCharInternal::F ||
220       c == FormatConversionCharInternal::E ||
221       c == FormatConversionCharInternal::G ||
222       c == FormatConversionCharInternal::A) {
223     return true;
224   } else {
225     return false;
226   }
227 }
228 
FormatConversionCharIsFloat(FormatConversionChar c)229 inline bool FormatConversionCharIsFloat(FormatConversionChar c) {
230   if (c == FormatConversionCharInternal::a ||
231       c == FormatConversionCharInternal::e ||
232       c == FormatConversionCharInternal::f ||
233       c == FormatConversionCharInternal::g ||
234       c == FormatConversionCharInternal::A ||
235       c == FormatConversionCharInternal::E ||
236       c == FormatConversionCharInternal::F ||
237       c == FormatConversionCharInternal::G) {
238     return true;
239   } else {
240     return false;
241   }
242 }
243 
FormatConversionCharToChar(FormatConversionChar c)244 inline char FormatConversionCharToChar(FormatConversionChar c) {
245   if (c == FormatConversionCharInternal::kNone) {
246     return '\0';
247 
248 #define ABSL_INTERNAL_X_VAL(e)                       \
249   } else if (c == FormatConversionCharInternal::e) { \
250     return #e[0];
251 #define ABSL_INTERNAL_X_SEP
252   ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL,
253                                          ABSL_INTERNAL_X_SEP)
254   } else {
255     return '\0';
256   }
257 
258 #undef ABSL_INTERNAL_X_VAL
259 #undef ABSL_INTERNAL_X_SEP
260 }
261 
262 // The associated char.
263 inline std::ostream& operator<<(std::ostream& os, FormatConversionChar v) {
264   char c = FormatConversionCharToChar(v);
265   if (!c) c = '?';
266   return os << c;
267 }
268 
269 struct FormatConversionSpecImplFriend;
270 
271 class FormatConversionSpecImpl {
272  public:
273   // Width and precison are not specified, no flags are set.
is_basic()274   bool is_basic() const { return flags_ == Flags::kBasic; }
has_left_flag()275   bool has_left_flag() const { return FlagsContains(flags_, Flags::kLeft); }
has_show_pos_flag()276   bool has_show_pos_flag() const {
277     return FlagsContains(flags_, Flags::kShowPos);
278   }
has_sign_col_flag()279   bool has_sign_col_flag() const {
280     return FlagsContains(flags_, Flags::kSignCol);
281   }
has_alt_flag()282   bool has_alt_flag() const { return FlagsContains(flags_, Flags::kAlt); }
has_zero_flag()283   bool has_zero_flag() const { return FlagsContains(flags_, Flags::kZero); }
284 
conversion_char()285   FormatConversionChar conversion_char() const {
286     // Keep this field first in the struct . It generates better code when
287     // accessing it when ConversionSpec is passed by value in registers.
288     static_assert(offsetof(FormatConversionSpecImpl, conv_) == 0, "");
289     return conv_;
290   }
291 
292   // Returns the specified width. If width is unspecfied, it returns a negative
293   // value.
width()294   int width() const { return width_; }
295   // Returns the specified precision. If precision is unspecfied, it returns a
296   // negative value.
precision()297   int precision() const { return precision_; }
298 
299   template <typename T>
Wrap()300   T Wrap() {
301     return T(*this);
302   }
303 
304  private:
305   friend struct str_format_internal::FormatConversionSpecImplFriend;
306   FormatConversionChar conv_ = FormatConversionCharInternal::kNone;
307   Flags flags_;
308   int width_;
309   int precision_;
310 };
311 
312 struct FormatConversionSpecImplFriend final {
SetFlagsfinal313   static void SetFlags(Flags f, FormatConversionSpecImpl* conv) {
314     conv->flags_ = f;
315   }
SetConversionCharfinal316   static void SetConversionChar(FormatConversionChar c,
317                                 FormatConversionSpecImpl* conv) {
318     conv->conv_ = c;
319   }
SetWidthfinal320   static void SetWidth(int w, FormatConversionSpecImpl* conv) {
321     conv->width_ = w;
322   }
SetPrecisionfinal323   static void SetPrecision(int p, FormatConversionSpecImpl* conv) {
324     conv->precision_ = p;
325   }
FlagsToStringfinal326   static std::string FlagsToString(const FormatConversionSpecImpl& spec) {
327     return str_format_internal::FlagsToString(spec.flags_);
328   }
329 };
330 
331 // Type safe OR operator.
332 // We need this for two reasons:
333 //  1. operator| on enums makes them decay to integers and the result is an
334 //     integer. We need the result to stay as an enum.
335 //  2. We use "enum class" which would not work even if we accepted the decay.
FormatConversionCharSetUnion(FormatConversionCharSet a)336 constexpr FormatConversionCharSet FormatConversionCharSetUnion(
337     FormatConversionCharSet a) {
338   return a;
339 }
340 
341 template <typename... CharSet>
FormatConversionCharSetUnion(FormatConversionCharSet a,CharSet...rest)342 constexpr FormatConversionCharSet FormatConversionCharSetUnion(
343     FormatConversionCharSet a, CharSet... rest) {
344   return static_cast<FormatConversionCharSet>(
345       static_cast<uint64_t>(a) |
346       static_cast<uint64_t>(FormatConversionCharSetUnion(rest...)));
347 }
348 
FormatConversionCharToConvInt(FormatConversionChar c)349 constexpr uint64_t FormatConversionCharToConvInt(FormatConversionChar c) {
350   return uint64_t{1} << (1 + static_cast<uint8_t>(c));
351 }
352 
FormatConversionCharToConvInt(char conv)353 constexpr uint64_t FormatConversionCharToConvInt(char conv) {
354   return
355 #define ABSL_INTERNAL_CHAR_SET_CASE(c)                                 \
356   conv == #c[0]                                                        \
357       ? FormatConversionCharToConvInt(FormatConversionCharInternal::c) \
358       :
359       ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
360 #undef ABSL_INTERNAL_CHAR_SET_CASE
361                   conv == '*'
362           ? 1
363           : 0;
364 }
365 
FormatConversionCharToConvValue(char conv)366 constexpr FormatConversionCharSet FormatConversionCharToConvValue(char conv) {
367   return static_cast<FormatConversionCharSet>(
368       FormatConversionCharToConvInt(conv));
369 }
370 
371 struct FormatConversionCharSetInternal {
372 #define ABSL_INTERNAL_CHAR_SET_CASE(c)         \
373   static constexpr FormatConversionCharSet c = \
374       FormatConversionCharToConvValue(#c[0]);
375   ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
376 #undef ABSL_INTERNAL_CHAR_SET_CASE
377 
378   // Used for width/precision '*' specification.
379   static constexpr FormatConversionCharSet kStar =
380       FormatConversionCharToConvValue('*');
381 
382   static constexpr FormatConversionCharSet kIntegral =
383       FormatConversionCharSetUnion(d, i, u, o, x, X);
384   static constexpr FormatConversionCharSet kFloating =
385       FormatConversionCharSetUnion(a, e, f, g, A, E, F, G);
386   static constexpr FormatConversionCharSet kNumeric =
387       FormatConversionCharSetUnion(kIntegral, kFloating);
388   static constexpr FormatConversionCharSet kPointer = p;
389 };
390 
391 // Type safe OR operator.
392 // We need this for two reasons:
393 //  1. operator| on enums makes them decay to integers and the result is an
394 //     integer. We need the result to stay as an enum.
395 //  2. We use "enum class" which would not work even if we accepted the decay.
396 constexpr FormatConversionCharSet operator|(FormatConversionCharSet a,
397                                             FormatConversionCharSet b) {
398   return FormatConversionCharSetUnion(a, b);
399 }
400 
401 // Overloaded conversion functions to support absl::ParsedFormat.
402 // Get a conversion with a single character in it.
ToFormatConversionCharSet(char c)403 constexpr FormatConversionCharSet ToFormatConversionCharSet(char c) {
404   return static_cast<FormatConversionCharSet>(
405       FormatConversionCharToConvValue(c));
406 }
407 
408 // Get a conversion with a single character in it.
ToFormatConversionCharSet(FormatConversionCharSet c)409 constexpr FormatConversionCharSet ToFormatConversionCharSet(
410     FormatConversionCharSet c) {
411   return c;
412 }
413 
414 template <typename T>
415 void ToFormatConversionCharSet(T) = delete;
416 
417 // Checks whether `c` exists in `set`.
Contains(FormatConversionCharSet set,char c)418 constexpr bool Contains(FormatConversionCharSet set, char c) {
419   return (static_cast<uint64_t>(set) &
420           static_cast<uint64_t>(FormatConversionCharToConvValue(c))) != 0;
421 }
422 
423 // Checks whether all the characters in `c` are contained in `set`
Contains(FormatConversionCharSet set,FormatConversionCharSet c)424 constexpr bool Contains(FormatConversionCharSet set,
425                         FormatConversionCharSet c) {
426   return (static_cast<uint64_t>(set) & static_cast<uint64_t>(c)) ==
427          static_cast<uint64_t>(c);
428 }
429 
430 // Checks whether all the characters in `c` are contained in `set`
Contains(FormatConversionCharSet set,FormatConversionChar c)431 constexpr bool Contains(FormatConversionCharSet set, FormatConversionChar c) {
432   return (static_cast<uint64_t>(set) & FormatConversionCharToConvInt(c)) != 0;
433 }
434 
435 // Return capacity - used, clipped to a minimum of 0.
Excess(size_t used,size_t capacity)436 inline size_t Excess(size_t used, size_t capacity) {
437   return used < capacity ? capacity - used : 0;
438 }
439 
440 }  // namespace str_format_internal
441 
442 ABSL_NAMESPACE_END
443 }  // namespace absl
444 
445 #endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
446