• 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/strings/internal/str_format/output.h"
28 #include "absl/strings/string_view.h"
29 
30 namespace absl {
31 ABSL_NAMESPACE_BEGIN
32 namespace str_format_internal {
33 
34 class FormatRawSinkImpl {
35  public:
36   // Implicitly convert from any type that provides the hook function as
37   // described above.
38   template <typename T, decltype(str_format_internal::InvokeFlush(
39                             std::declval<T*>(), string_view()))* = nullptr>
FormatRawSinkImpl(T * raw)40   FormatRawSinkImpl(T* raw)  // NOLINT
41       : sink_(raw), write_(&FormatRawSinkImpl::Flush<T>) {}
42 
Write(string_view s)43   void Write(string_view s) { write_(sink_, s); }
44 
45   template <typename T>
Extract(T s)46   static FormatRawSinkImpl Extract(T s) {
47     return s.sink_;
48   }
49 
50  private:
51   template <typename T>
Flush(void * r,string_view s)52   static void Flush(void* r, string_view s) {
53     str_format_internal::InvokeFlush(static_cast<T*>(r), s);
54   }
55 
56   void* sink_;
57   void (*write_)(void*, string_view);
58 };
59 
60 // An abstraction to which conversions write their string data.
61 class FormatSinkImpl {
62  public:
FormatSinkImpl(FormatRawSinkImpl raw)63   explicit FormatSinkImpl(FormatRawSinkImpl raw) : raw_(raw) {}
64 
~FormatSinkImpl()65   ~FormatSinkImpl() { Flush(); }
66 
Flush()67   void Flush() {
68     raw_.Write(string_view(buf_, pos_ - buf_));
69     pos_ = buf_;
70   }
71 
Append(size_t n,char c)72   void Append(size_t n, char c) {
73     if (n == 0) return;
74     size_ += n;
75     auto raw_append = [&](size_t count) {
76       memset(pos_, c, count);
77       pos_ += count;
78     };
79     while (n > Avail()) {
80       n -= Avail();
81       if (Avail() > 0) {
82         raw_append(Avail());
83       }
84       Flush();
85     }
86     raw_append(n);
87   }
88 
Append(string_view v)89   void Append(string_view v) {
90     size_t n = v.size();
91     if (n == 0) return;
92     size_ += n;
93     if (n >= Avail()) {
94       Flush();
95       raw_.Write(v);
96       return;
97     }
98     memcpy(pos_, v.data(), n);
99     pos_ += n;
100   }
101 
size()102   size_t size() const { return size_; }
103 
104   // Put 'v' to 'sink' with specified width, precision, and left flag.
105   bool PutPaddedString(string_view v, int w, int p, bool l);
106 
107   template <typename T>
Wrap()108   T Wrap() {
109     return T(this);
110   }
111 
112   template <typename T>
Extract(T * s)113   static FormatSinkImpl* Extract(T* s) {
114     return s->sink_;
115   }
116 
117  private:
Avail()118   size_t Avail() const { return buf_ + sizeof(buf_) - pos_; }
119 
120   FormatRawSinkImpl raw_;
121   size_t size_ = 0;
122   char* pos_ = buf_;
123   char buf_[1024];
124 };
125 
126 struct Flags {
127   bool basic : 1;     // fastest conversion: no flags, width, or precision
128   bool left : 1;      // "-"
129   bool show_pos : 1;  // "+"
130   bool sign_col : 1;  // " "
131   bool alt : 1;       // "#"
132   bool zero : 1;      // "0"
133   std::string ToString() const;
134   friend std::ostream& operator<<(std::ostream& os, const Flags& v) {
135     return os << v.ToString();
136   }
137 };
138 
139 // clang-format off
140 #define ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \
141   /* text */ \
142   X_VAL(c) X_SEP X_VAL(C) X_SEP X_VAL(s) X_SEP X_VAL(S) X_SEP \
143   /* ints */ \
144   X_VAL(d) X_SEP X_VAL(i) X_SEP X_VAL(o) X_SEP \
145   X_VAL(u) X_SEP X_VAL(x) X_SEP X_VAL(X) X_SEP \
146   /* floats */ \
147   X_VAL(f) X_SEP X_VAL(F) X_SEP X_VAL(e) X_SEP X_VAL(E) X_SEP \
148   X_VAL(g) X_SEP X_VAL(G) X_SEP X_VAL(a) X_SEP X_VAL(A) X_SEP \
149   /* misc */ \
150   X_VAL(n) X_SEP X_VAL(p)
151 
152 enum class FormatConversionChar : uint8_t {
153     c, C, s, S,              // text
154     d, i, o, u, x, X,        // int
155     f, F, e, E, g, G, a, A,  // float
156     n, p,                    // misc
157     kNone,
158     none = kNone
159 };
160 // clang-format on
161 
FormatConversionCharFromChar(char c)162 inline FormatConversionChar FormatConversionCharFromChar(char c) {
163   switch (c) {
164 #define ABSL_INTERNAL_X_VAL(id) \
165   case #id[0]:                  \
166     return FormatConversionChar::id;
167     ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
168 #undef ABSL_INTERNAL_X_VAL
169   }
170   return FormatConversionChar::kNone;
171 }
172 
FormatConversionCharRadix(FormatConversionChar c)173 inline int FormatConversionCharRadix(FormatConversionChar c) {
174   switch (c) {
175     case FormatConversionChar::x:
176     case FormatConversionChar::X:
177     case FormatConversionChar::a:
178     case FormatConversionChar::A:
179     case FormatConversionChar::p:
180       return 16;
181     case FormatConversionChar::o:
182       return 8;
183     default:
184       return 10;
185   }
186 }
187 
FormatConversionCharIsUpper(FormatConversionChar c)188 inline bool FormatConversionCharIsUpper(FormatConversionChar c) {
189   switch (c) {
190     case FormatConversionChar::X:
191     case FormatConversionChar::F:
192     case FormatConversionChar::E:
193     case FormatConversionChar::G:
194     case FormatConversionChar::A:
195       return true;
196     default:
197       return false;
198   }
199 }
200 
FormatConversionCharIsSigned(FormatConversionChar c)201 inline bool FormatConversionCharIsSigned(FormatConversionChar c) {
202   switch (c) {
203     case FormatConversionChar::d:
204     case FormatConversionChar::i:
205       return true;
206     default:
207       return false;
208   }
209 }
210 
FormatConversionCharIsIntegral(FormatConversionChar c)211 inline bool FormatConversionCharIsIntegral(FormatConversionChar c) {
212   switch (c) {
213     case FormatConversionChar::d:
214     case FormatConversionChar::i:
215     case FormatConversionChar::u:
216     case FormatConversionChar::o:
217     case FormatConversionChar::x:
218     case FormatConversionChar::X:
219       return true;
220     default:
221       return false;
222   }
223 }
224 
FormatConversionCharIsFloat(FormatConversionChar c)225 inline bool FormatConversionCharIsFloat(FormatConversionChar c) {
226   switch (c) {
227     case FormatConversionChar::a:
228     case FormatConversionChar::e:
229     case FormatConversionChar::f:
230     case FormatConversionChar::g:
231     case FormatConversionChar::A:
232     case FormatConversionChar::E:
233     case FormatConversionChar::F:
234     case FormatConversionChar::G:
235       return true;
236     default:
237       return false;
238   }
239 }
240 
FormatConversionCharToChar(FormatConversionChar c)241 inline char FormatConversionCharToChar(FormatConversionChar c) {
242   switch (c) {
243 #define ABSL_INTERNAL_X_VAL(e)  \
244   case FormatConversionChar::e: \
245     return #e[0];
246 #define ABSL_INTERNAL_X_SEP
247     ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL,
248                                            ABSL_INTERNAL_X_SEP)
249     case FormatConversionChar::kNone:
250       return '\0';
251 #undef ABSL_INTERNAL_X_VAL
252 #undef ABSL_INTERNAL_X_SEP
253   }
254   return '\0';
255 }
256 
257 // The associated char.
258 inline std::ostream& operator<<(std::ostream& os, FormatConversionChar v) {
259   char c = FormatConversionCharToChar(v);
260   if (!c) c = '?';
261   return os << c;
262 }
263 
264 struct FormatConversionSpecImplFriend;
265 
266 class FormatConversionSpec {
267  public:
268   // Width and precison are not specified, no flags are set.
is_basic()269   bool is_basic() const { return flags_.basic; }
has_left_flag()270   bool has_left_flag() const { return flags_.left; }
has_show_pos_flag()271   bool has_show_pos_flag() const { return flags_.show_pos; }
has_sign_col_flag()272   bool has_sign_col_flag() const { return flags_.sign_col; }
has_alt_flag()273   bool has_alt_flag() const { return flags_.alt; }
has_zero_flag()274   bool has_zero_flag() const { return flags_.zero; }
275 
conversion_char()276   FormatConversionChar conversion_char() const {
277     // Keep this field first in the struct . It generates better code when
278     // accessing it when ConversionSpec is passed by value in registers.
279     static_assert(offsetof(FormatConversionSpec, conv_) == 0, "");
280     return conv_;
281   }
282 
283   // Returns the specified width. If width is unspecfied, it returns a negative
284   // value.
width()285   int width() const { return width_; }
286   // Returns the specified precision. If precision is unspecfied, it returns a
287   // negative value.
precision()288   int precision() const { return precision_; }
289 
290   // Deprecated (use has_x_flag() instead).
flags()291   Flags flags() const { return flags_; }
292   // Deprecated
conv()293   FormatConversionChar conv() const { return conversion_char(); }
294 
295  private:
296   friend struct str_format_internal::FormatConversionSpecImplFriend;
297   FormatConversionChar conv_ = FormatConversionChar::kNone;
298   Flags flags_;
299   int width_;
300   int precision_;
301 };
302 
303 struct FormatConversionSpecImplFriend final {
SetFlagsfinal304   static void SetFlags(Flags f, FormatConversionSpec* conv) {
305     conv->flags_ = f;
306   }
SetConversionCharfinal307   static void SetConversionChar(FormatConversionChar c,
308                                 FormatConversionSpec* conv) {
309     conv->conv_ = c;
310   }
SetWidthfinal311   static void SetWidth(int w, FormatConversionSpec* conv) { conv->width_ = w; }
SetPrecisionfinal312   static void SetPrecision(int p, FormatConversionSpec* conv) {
313     conv->precision_ = p;
314   }
FlagsToStringfinal315   static std::string FlagsToString(const FormatConversionSpec& spec) {
316     return spec.flags_.ToString();
317   }
318 };
319 
FormatConversionCharToConvValue(char conv)320 constexpr uint64_t FormatConversionCharToConvValue(char conv) {
321   return
322 #define ABSL_INTERNAL_CHAR_SET_CASE(c)                                       \
323   conv == #c[0]                                                              \
324       ? (uint64_t{1} << (1 + static_cast<uint8_t>(FormatConversionChar::c))) \
325       :
326       ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
327 #undef ABSL_INTERNAL_CHAR_SET_CASE
328                   conv == '*'
329           ? 1
330           : 0;
331 }
332 
333 enum class FormatConversionCharSet : uint64_t {
334 #define ABSL_INTERNAL_CHAR_SET_CASE(c) \
335   c = FormatConversionCharToConvValue(#c[0]),
336   ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
337 #undef ABSL_INTERNAL_CHAR_SET_CASE
338 
339   // Used for width/precision '*' specification.
340   kStar = FormatConversionCharToConvValue('*'),
341   // Some predefined values:
342   kIntegral = d | i | u | o | x | X,
343   kFloating = a | e | f | g | A | E | F | G,
344   kNumeric = kIntegral | kFloating,
345   kString = s,
346   kPointer = p,
347 
348   // The following are deprecated
349   star = kStar,
350   integral = kIntegral,
351   floating = kFloating,
352   numeric = kNumeric,
353   string = kString,
354   pointer = kPointer
355 };
356 
357 // Type safe OR operator.
358 // We need this for two reasons:
359 //  1. operator| on enums makes them decay to integers and the result is an
360 //     integer. We need the result to stay as an enum.
361 //  2. We use "enum class" which would not work even if we accepted the decay.
362 constexpr FormatConversionCharSet operator|(FormatConversionCharSet a,
363                                             FormatConversionCharSet b) {
364   return FormatConversionCharSet(static_cast<uint64_t>(a) |
365                                  static_cast<uint64_t>(b));
366 }
367 
368 // Get a conversion with a single character in it.
ConversionCharToConv(char c)369 constexpr FormatConversionCharSet ConversionCharToConv(char c) {
370   return FormatConversionCharSet(FormatConversionCharToConvValue(c));
371 }
372 
373 // Checks whether `c` exists in `set`.
Contains(FormatConversionCharSet set,char c)374 constexpr bool Contains(FormatConversionCharSet set, char c) {
375   return (static_cast<uint64_t>(set) & FormatConversionCharToConvValue(c)) != 0;
376 }
377 
378 // Checks whether all the characters in `c` are contained in `set`
Contains(FormatConversionCharSet set,FormatConversionCharSet c)379 constexpr bool Contains(FormatConversionCharSet set,
380                         FormatConversionCharSet c) {
381   return (static_cast<uint64_t>(set) & static_cast<uint64_t>(c)) ==
382          static_cast<uint64_t>(c);
383 }
384 
385 // Return type of the AbslFormatConvert() functions.
386 // The FormatConversionCharSet template parameter is used to inform the
387 // framework of what conversion characters are supported by that
388 // AbslFormatConvert routine.
389 template <FormatConversionCharSet C>
390 struct FormatConvertResult {
391   static constexpr FormatConversionCharSet kConv = C;
392   bool value;
393 };
394 
395 template <FormatConversionCharSet C>
396 constexpr FormatConversionCharSet FormatConvertResult<C>::kConv;
397 
398 // Return capacity - used, clipped to a minimum of 0.
Excess(size_t used,size_t capacity)399 inline size_t Excess(size_t used, size_t capacity) {
400   return used < capacity ? capacity - used : 0;
401 }
402 
403 // Type alias for use during migration.
404 using ConversionChar = FormatConversionChar;
405 using ConversionSpec = FormatConversionSpec;
406 using Conv = FormatConversionCharSet;
407 template <FormatConversionCharSet C>
408 using ConvertResult = FormatConvertResult<C>;
409 
410 }  // namespace str_format_internal
411 
412 ABSL_NAMESPACE_END
413 }  // namespace absl
414 
415 #endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
416