extension.h
Go to the documentation of this file.
00001 //
00002 // Copyright 2017 The Abseil Authors.
00003 //
00004 // Licensed under the Apache License, Version 2.0 (the "License");
00005 // you may not use this file except in compliance with the License.
00006 // You may obtain a copy of the License at
00007 //
00008 //      https://www.apache.org/licenses/LICENSE-2.0
00009 //
00010 // Unless required by applicable law or agreed to in writing, software
00011 // distributed under the License is distributed on an "AS IS" BASIS,
00012 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013 // See the License for the specific language governing permissions and
00014 // limitations under the License.
00015 //
00016 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
00017 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
00018 
00019 #include <limits.h>
00020 #include <cstddef>
00021 #include <cstring>
00022 #include <ostream>
00023 
00024 #include "absl/base/port.h"
00025 #include "absl/strings/internal/str_format/output.h"
00026 #include "absl/strings/string_view.h"
00027 
00028 class Cord;
00029 
00030 namespace absl {
00031 
00032 namespace str_format_internal {
00033 
00034 class FormatRawSinkImpl {
00035  public:
00036   // Implicitly convert from any type that provides the hook function as
00037   // described above.
00038   template <typename T, decltype(str_format_internal::InvokeFlush(
00039                             std::declval<T*>(), string_view()))* = nullptr>
00040   FormatRawSinkImpl(T* raw)  // NOLINT
00041       : sink_(raw), write_(&FormatRawSinkImpl::Flush<T>) {}
00042 
00043   void Write(string_view s) { write_(sink_, s); }
00044 
00045   template <typename T>
00046   static FormatRawSinkImpl Extract(T s) {
00047     return s.sink_;
00048   }
00049 
00050  private:
00051   template <typename T>
00052   static void Flush(void* r, string_view s) {
00053     str_format_internal::InvokeFlush(static_cast<T*>(r), s);
00054   }
00055 
00056   void* sink_;
00057   void (*write_)(void*, string_view);
00058 };
00059 
00060 // An abstraction to which conversions write their string data.
00061 class FormatSinkImpl {
00062  public:
00063   explicit FormatSinkImpl(FormatRawSinkImpl raw) : raw_(raw) {}
00064 
00065   ~FormatSinkImpl() { Flush(); }
00066 
00067   void Flush() {
00068     raw_.Write(string_view(buf_, pos_ - buf_));
00069     pos_ = buf_;
00070   }
00071 
00072   void Append(size_t n, char c) {
00073     if (n == 0) return;
00074     size_ += n;
00075     auto raw_append = [&](size_t count) {
00076       memset(pos_, c, count);
00077       pos_ += count;
00078     };
00079     while (n > Avail()) {
00080       n -= Avail();
00081       if (Avail() > 0) {
00082         raw_append(Avail());
00083       }
00084       Flush();
00085     }
00086     raw_append(n);
00087   }
00088 
00089   void Append(string_view v) {
00090     size_t n = v.size();
00091     if (n == 0) return;
00092     size_ += n;
00093     if (n >= Avail()) {
00094       Flush();
00095       raw_.Write(v);
00096       return;
00097     }
00098     memcpy(pos_, v.data(), n);
00099     pos_ += n;
00100   }
00101 
00102   size_t size() const { return size_; }
00103 
00104   // Put 'v' to 'sink' with specified width, precision, and left flag.
00105   bool PutPaddedString(string_view v, int w, int p, bool l);
00106 
00107   template <typename T>
00108   T Wrap() {
00109     return T(this);
00110   }
00111 
00112   template <typename T>
00113   static FormatSinkImpl* Extract(T* s) {
00114     return s->sink_;
00115   }
00116 
00117  private:
00118   size_t Avail() const { return buf_ + sizeof(buf_) - pos_; }
00119 
00120   FormatRawSinkImpl raw_;
00121   size_t size_ = 0;
00122   char* pos_ = buf_;
00123   char buf_[1024];
00124 };
00125 
00126 struct Flags {
00127   bool basic : 1;     // fastest conversion: no flags, width, or precision
00128   bool left : 1;      // "-"
00129   bool show_pos : 1;  // "+"
00130   bool sign_col : 1;  // " "
00131   bool alt : 1;       // "#"
00132   bool zero : 1;      // "0"
00133   std::string ToString() const;
00134   friend std::ostream& operator<<(std::ostream& os, const Flags& v) {
00135     return os << v.ToString();
00136   }
00137 };
00138 
00139 struct LengthMod {
00140  public:
00141   enum Id : uint8_t {
00142     h, hh, l, ll, L, j, z, t, q, none
00143   };
00144   static const size_t kNumValues = none + 1;
00145 
00146   LengthMod() : id_(none) {}
00147 
00148   // Index into the opaque array of LengthMod enums.
00149   // Requires: i < kNumValues
00150   static LengthMod FromIndex(size_t i) {
00151     return LengthMod(kSpecs[i].value);
00152   }
00153 
00154   static LengthMod FromId(Id id) { return LengthMod(id); }
00155 
00156   // The length modifier std::string associated with a specified LengthMod.
00157   string_view name() const {
00158     const Spec& spec = kSpecs[id_];
00159     return {spec.name, spec.name_length};
00160   }
00161 
00162   Id id() const { return id_; }
00163 
00164   friend bool operator==(const LengthMod& a, const LengthMod& b) {
00165     return a.id() == b.id();
00166   }
00167   friend bool operator!=(const LengthMod& a, const LengthMod& b) {
00168     return !(a == b);
00169   }
00170   friend std::ostream& operator<<(std::ostream& os, const LengthMod& v) {
00171     return os << v.name();
00172   }
00173 
00174  private:
00175   struct Spec {
00176     Id value;
00177     const char *name;
00178     size_t name_length;
00179   };
00180   static const Spec kSpecs[];
00181 
00182   explicit LengthMod(Id id) : id_(id) {}
00183 
00184   Id id_;
00185 };
00186 
00187 // clang-format off
00188 #define ABSL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \
00189   /* text */ \
00190   X_VAL(c) X_SEP X_VAL(C) X_SEP X_VAL(s) X_SEP X_VAL(S) X_SEP \
00191   /* ints */ \
00192   X_VAL(d) X_SEP X_VAL(i) X_SEP X_VAL(o) X_SEP \
00193   X_VAL(u) X_SEP X_VAL(x) X_SEP X_VAL(X) X_SEP \
00194   /* floats */ \
00195   X_VAL(f) X_SEP X_VAL(F) X_SEP X_VAL(e) X_SEP X_VAL(E) X_SEP \
00196   X_VAL(g) X_SEP X_VAL(G) X_SEP X_VAL(a) X_SEP X_VAL(A) X_SEP \
00197   /* misc */ \
00198   X_VAL(n) X_SEP X_VAL(p)
00199 // clang-format on
00200 
00201 struct ConversionChar {
00202  public:
00203   enum Id : uint8_t {
00204     c, C, s, S,              // text
00205     d, i, o, u, x, X,        // int
00206     f, F, e, E, g, G, a, A,  // float
00207     n, p,                    // misc
00208     none
00209   };
00210   static const size_t kNumValues = none + 1;
00211 
00212   ConversionChar() : id_(none) {}
00213 
00214  public:
00215   // Index into the opaque array of ConversionChar enums.
00216   // Requires: i < kNumValues
00217   static ConversionChar FromIndex(size_t i) {
00218     return ConversionChar(kSpecs[i].value);
00219   }
00220 
00221   static ConversionChar FromChar(char c) {
00222     ConversionChar::Id out_id = ConversionChar::none;
00223     switch (c) {
00224 #define X_VAL(id)                \
00225   case #id[0]:                   \
00226     out_id = ConversionChar::id; \
00227     break;
00228       ABSL_CONVERSION_CHARS_EXPAND_(X_VAL, )
00229 #undef X_VAL
00230       default:
00231         break;
00232     }
00233     return ConversionChar(out_id);
00234   }
00235 
00236   static ConversionChar FromId(Id id) { return ConversionChar(id); }
00237   Id id() const { return id_; }
00238 
00239   int radix() const {
00240     switch (id()) {
00241       case x: case X: case a: case A: case p: return 16;
00242       case o: return 8;
00243       default: return 10;
00244     }
00245   }
00246 
00247   bool upper() const {
00248     switch (id()) {
00249       case X: case F: case E: case G: case A: return true;
00250       default: return false;
00251     }
00252   }
00253 
00254   bool is_signed() const {
00255     switch (id()) {
00256       case d: case i: return true;
00257       default: return false;
00258     }
00259   }
00260 
00261   bool is_integral() const {
00262     switch (id()) {
00263       case d: case i: case u: case o: case x: case X:
00264         return true;
00265       default: return false;
00266     }
00267   }
00268 
00269   bool is_float() const {
00270     switch (id()) {
00271       case a: case e: case f: case g: case A: case E: case F: case G:
00272         return true;
00273       default: return false;
00274     }
00275   }
00276 
00277   bool IsValid() const { return id() != none; }
00278 
00279   // The associated char.
00280   char Char() const { return kSpecs[id_].name; }
00281 
00282   friend bool operator==(const ConversionChar& a, const ConversionChar& b) {
00283     return a.id() == b.id();
00284   }
00285   friend bool operator!=(const ConversionChar& a, const ConversionChar& b) {
00286     return !(a == b);
00287   }
00288   friend std::ostream& operator<<(std::ostream& os, const ConversionChar& v) {
00289     char c = v.Char();
00290     if (!c) c = '?';
00291     return os << c;
00292   }
00293 
00294  private:
00295   struct Spec {
00296     Id value;
00297     char name;
00298   };
00299   static const Spec kSpecs[];
00300 
00301   explicit ConversionChar(Id id) : id_(id) {}
00302 
00303   Id id_;
00304 };
00305 
00306 class ConversionSpec {
00307  public:
00308   Flags flags() const { return flags_; }
00309   LengthMod length_mod() const { return length_mod_; }
00310   ConversionChar conv() const {
00311     // Keep this field first in the struct . It generates better code when
00312     // accessing it when ConversionSpec is passed by value in registers.
00313     static_assert(offsetof(ConversionSpec, conv_) == 0, "");
00314     return conv_;
00315   }
00316 
00317   // Returns the specified width. If width is unspecfied, it returns a negative
00318   // value.
00319   int width() const { return width_; }
00320   // Returns the specified precision. If precision is unspecfied, it returns a
00321   // negative value.
00322   int precision() const { return precision_; }
00323 
00324   void set_flags(Flags f) { flags_ = f; }
00325   void set_length_mod(LengthMod lm) { length_mod_ = lm; }
00326   void set_conv(ConversionChar c) { conv_ = c; }
00327   void set_width(int w) { width_ = w; }
00328   void set_precision(int p) { precision_ = p; }
00329   void set_left(bool b) { flags_.left = b; }
00330 
00331  private:
00332   ConversionChar conv_;
00333   Flags flags_;
00334   LengthMod length_mod_;
00335   int width_;
00336   int precision_;
00337 };
00338 
00339 constexpr uint64_t ConversionCharToConvValue(char conv) {
00340   return
00341 #define CONV_SET_CASE(c) \
00342   conv == #c[0] ? (uint64_t{1} << (1 + ConversionChar::Id::c)):
00343       ABSL_CONVERSION_CHARS_EXPAND_(CONV_SET_CASE, )
00344 #undef CONV_SET_CASE
00345                   conv == '*'
00346           ? 1
00347           : 0;
00348 }
00349 
00350 enum class Conv : uint64_t {
00351 #define CONV_SET_CASE(c) c = ConversionCharToConvValue(#c[0]),
00352   ABSL_CONVERSION_CHARS_EXPAND_(CONV_SET_CASE, )
00353 #undef CONV_SET_CASE
00354 
00355   // Used for width/precision '*' specification.
00356   star = ConversionCharToConvValue('*'),
00357 
00358   // Some predefined values:
00359   integral = d | i | u | o | x | X,
00360   floating = a | e | f | g | A | E | F | G,
00361   numeric = integral | floating,
00362   string = s,
00363   pointer = p
00364 };
00365 
00366 // Type safe OR operator.
00367 // We need this for two reasons:
00368 //  1. operator| on enums makes them decay to integers and the result is an
00369 //     integer. We need the result to stay as an enum.
00370 //  2. We use "enum class" which would not work even if we accepted the decay.
00371 constexpr Conv operator|(Conv a, Conv b) {
00372   return Conv(static_cast<uint64_t>(a) | static_cast<uint64_t>(b));
00373 }
00374 
00375 // Get a conversion with a single character in it.
00376 constexpr Conv ConversionCharToConv(char c) {
00377   return Conv(ConversionCharToConvValue(c));
00378 }
00379 
00380 // Checks whether `c` exists in `set`.
00381 constexpr bool Contains(Conv set, char c) {
00382   return (static_cast<uint64_t>(set) & ConversionCharToConvValue(c)) != 0;
00383 }
00384 
00385 // Checks whether all the characters in `c` are contained in `set`
00386 constexpr bool Contains(Conv set, Conv c) {
00387   return (static_cast<uint64_t>(set) & static_cast<uint64_t>(c)) ==
00388          static_cast<uint64_t>(c);
00389 }
00390 
00391 // Return type of the AbslFormatConvert() functions.
00392 // The Conv template parameter is used to inform the framework of what
00393 // conversion characters are supported by that AbslFormatConvert routine.
00394 template <Conv C>
00395 struct ConvertResult {
00396   static constexpr Conv kConv = C;
00397   bool value;
00398 };
00399 template <Conv C>
00400 constexpr Conv ConvertResult<C>::kConv;
00401 
00402 // Return capacity - used, clipped to a minimum of 0.
00403 inline size_t Excess(size_t used, size_t capacity) {
00404   return used < capacity ? capacity - used : 0;
00405 }
00406 
00407 }  // namespace str_format_internal
00408 
00409 }  // namespace absl
00410 
00411 #endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:14