• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
2 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
3 
4 #include <array>
5 #include <cstdio>
6 #include <sstream>
7 #include <string>
8 
9 #include "absl/base/port.h"
10 #include "absl/strings/internal/str_format/arg.h"
11 #include "absl/strings/internal/str_format/checker.h"
12 #include "absl/strings/internal/str_format/parser.h"
13 #include "absl/types/span.h"
14 
15 namespace absl {
16 ABSL_NAMESPACE_BEGIN
17 
18 class UntypedFormatSpec;
19 
20 namespace str_format_internal {
21 
22 class BoundConversion : public FormatConversionSpecImpl {
23  public:
arg()24   const FormatArgImpl* arg() const { return arg_; }
set_arg(const FormatArgImpl * a)25   void set_arg(const FormatArgImpl* a) { arg_ = a; }
26 
27  private:
28   const FormatArgImpl* arg_;
29 };
30 
31 // This is the type-erased class that the implementation uses.
32 class UntypedFormatSpecImpl {
33  public:
34   UntypedFormatSpecImpl() = delete;
35 
UntypedFormatSpecImpl(string_view s)36   explicit UntypedFormatSpecImpl(string_view s)
37       : data_(s.data()), size_(s.size()) {}
UntypedFormatSpecImpl(const str_format_internal::ParsedFormatBase * pc)38   explicit UntypedFormatSpecImpl(
39       const str_format_internal::ParsedFormatBase* pc)
40       : data_(pc), size_(~size_t{}) {}
41 
has_parsed_conversion()42   bool has_parsed_conversion() const { return size_ == ~size_t{}; }
43 
str()44   string_view str() const {
45     assert(!has_parsed_conversion());
46     return string_view(static_cast<const char*>(data_), size_);
47   }
parsed_conversion()48   const str_format_internal::ParsedFormatBase* parsed_conversion() const {
49     assert(has_parsed_conversion());
50     return static_cast<const str_format_internal::ParsedFormatBase*>(data_);
51   }
52 
53   template <typename T>
Extract(const T & s)54   static const UntypedFormatSpecImpl& Extract(const T& s) {
55     return s.spec_;
56   }
57 
58  private:
59   const void* data_;
60   size_t size_;
61 };
62 
63 template <typename T, FormatConversionCharSet...>
64 struct MakeDependent {
65   using type = T;
66 };
67 
68 // Implicitly convertible from `const char*`, `string_view`, and the
69 // `ExtendedParsedFormat` type. This abstraction allows all format functions to
70 // operate on any without providing too many overloads.
71 template <FormatConversionCharSet... Args>
72 class FormatSpecTemplate
73     : public MakeDependent<UntypedFormatSpec, Args...>::type {
74   using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type;
75 
76  public:
77 #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
78 
79   // Honeypot overload for when the string is not constexpr.
80   // We use the 'unavailable' attribute to give a better compiler error than
81   // just 'method is deleted'.
82   FormatSpecTemplate(...)  // NOLINT
83       __attribute__((unavailable("Format string is not constexpr.")));
84 
85   // Honeypot overload for when the format is constexpr and invalid.
86   // We use the 'unavailable' attribute to give a better compiler error than
87   // just 'method is deleted'.
88   // To avoid checking the format twice, we just check that the format is
89   // constexpr. If is it valid, then the overload below will kick in.
90   // We add the template here to make this overload have lower priority.
91   template <typename = void>
92   FormatSpecTemplate(const char* s)  // NOLINT
93       __attribute__((
94           enable_if(str_format_internal::EnsureConstexpr(s), "constexpr trap"),
95           unavailable(
96               "Format specified does not match the arguments passed.")));
97 
98   template <typename T = void>
FormatSpecTemplate(string_view s)99   FormatSpecTemplate(string_view s)  // NOLINT
100       __attribute__((enable_if(str_format_internal::EnsureConstexpr(s),
101                                "constexpr trap"))) {
102     static_assert(sizeof(T*) == 0,
103                   "Format specified does not match the arguments passed.");
104   }
105 
106   // Good format overload.
FormatSpecTemplate(const char * s)107   FormatSpecTemplate(const char* s)  // NOLINT
108       __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap")))
109       : Base(s) {}
110 
FormatSpecTemplate(string_view s)111   FormatSpecTemplate(string_view s)  // NOLINT
112       __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap")))
113       : Base(s) {}
114 
115 #else  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
116 
117   FormatSpecTemplate(const char* s) : Base(s) {}  // NOLINT
118   FormatSpecTemplate(string_view s) : Base(s) {}  // NOLINT
119 
120 #endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
121 
122   template <FormatConversionCharSet... C,
123             typename = typename std::enable_if<
124                 AllOf(sizeof...(C) == sizeof...(Args), Contains(Args,
125                                                                 C)...)>::type>
FormatSpecTemplate(const ExtendedParsedFormat<C...> & pc)126   FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc)  // NOLINT
127       : Base(&pc) {}
128 };
129 
130 class Streamable {
131  public:
Streamable(const UntypedFormatSpecImpl & format,absl::Span<const FormatArgImpl> args)132   Streamable(const UntypedFormatSpecImpl& format,
133              absl::Span<const FormatArgImpl> args)
134       : format_(format) {
135     if (args.size() <= ABSL_ARRAYSIZE(few_args_)) {
136       for (size_t i = 0; i < args.size(); ++i) {
137         few_args_[i] = args[i];
138       }
139       args_ = absl::MakeSpan(few_args_, args.size());
140     } else {
141       many_args_.assign(args.begin(), args.end());
142       args_ = many_args_;
143     }
144   }
145 
146   std::ostream& Print(std::ostream& os) const;
147 
148   friend std::ostream& operator<<(std::ostream& os, const Streamable& l) {
149     return l.Print(os);
150   }
151 
152  private:
153   const UntypedFormatSpecImpl& format_;
154   absl::Span<const FormatArgImpl> args_;
155   // if args_.size() is 4 or less:
156   FormatArgImpl few_args_[4] = {FormatArgImpl(0), FormatArgImpl(0),
157                                 FormatArgImpl(0), FormatArgImpl(0)};
158   // if args_.size() is more than 4:
159   std::vector<FormatArgImpl> many_args_;
160 };
161 
162 // for testing
163 std::string Summarize(UntypedFormatSpecImpl format,
164                       absl::Span<const FormatArgImpl> args);
165 bool BindWithPack(const UnboundConversion* props,
166                   absl::Span<const FormatArgImpl> pack, BoundConversion* bound);
167 
168 bool FormatUntyped(FormatRawSinkImpl raw_sink,
169                    UntypedFormatSpecImpl format,
170                    absl::Span<const FormatArgImpl> args);
171 
172 std::string& AppendPack(std::string* out, UntypedFormatSpecImpl format,
173                         absl::Span<const FormatArgImpl> args);
174 
175 std::string FormatPack(const UntypedFormatSpecImpl format,
176                        absl::Span<const FormatArgImpl> args);
177 
178 int FprintF(std::FILE* output, UntypedFormatSpecImpl format,
179             absl::Span<const FormatArgImpl> args);
180 int SnprintF(char* output, size_t size, UntypedFormatSpecImpl format,
181              absl::Span<const FormatArgImpl> args);
182 
183 // Returned by Streamed(v). Converts via '%s' to the std::string created
184 // by std::ostream << v.
185 template <typename T>
186 class StreamedWrapper {
187  public:
StreamedWrapper(const T & v)188   explicit StreamedWrapper(const T& v) : v_(v) { }
189 
190  private:
191   template <typename S>
192   friend ArgConvertResult<FormatConversionCharSetInternal::s> FormatConvertImpl(
193       const StreamedWrapper<S>& v, FormatConversionSpecImpl conv,
194       FormatSinkImpl* out);
195   const T& v_;
196 };
197 
198 }  // namespace str_format_internal
199 ABSL_NAMESPACE_END
200 }  // namespace absl
201 
202 #endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
203