• 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 ConversionSpec {
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, typename...>
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 <typename... 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 std::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 std::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<ArgumentToConv<Args>()...>(s),
109                                "bad format trap")))
110       : Base(s) {}
111 
FormatSpecTemplate(string_view s)112   FormatSpecTemplate(string_view s)  // NOLINT
113       __attribute__((enable_if(ValidFormatImpl<ArgumentToConv<Args>()...>(s),
114                                "bad format trap")))
115       : Base(s) {}
116 
117 #else  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
118 
119   FormatSpecTemplate(const char* s) : Base(s) {}  // NOLINT
120   FormatSpecTemplate(string_view s) : Base(s) {}  // NOLINT
121 
122 #endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
123 
124   template <Conv... C, typename = typename std::enable_if<
125                            AllOf(sizeof...(C) == sizeof...(Args),
126                              Contains(ArgumentToConv<Args>(),
127                                           C)...)>::type>
FormatSpecTemplate(const ExtendedParsedFormat<C...> & pc)128   FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc)  // NOLINT
129       : Base(&pc) {}
130 };
131 
132 template <typename... Args>
133 struct FormatSpecDeductionBarrier {
134   using type = FormatSpecTemplate<Args...>;
135 };
136 
137 class Streamable {
138  public:
Streamable(const UntypedFormatSpecImpl & format,absl::Span<const FormatArgImpl> args)139   Streamable(const UntypedFormatSpecImpl& format,
140              absl::Span<const FormatArgImpl> args)
141       : format_(format) {
142     if (args.size() <= ABSL_ARRAYSIZE(few_args_)) {
143       for (size_t i = 0; i < args.size(); ++i) {
144         few_args_[i] = args[i];
145       }
146       args_ = absl::MakeSpan(few_args_, args.size());
147     } else {
148       many_args_.assign(args.begin(), args.end());
149       args_ = many_args_;
150     }
151   }
152 
153   std::ostream& Print(std::ostream& os) const;
154 
155   friend std::ostream& operator<<(std::ostream& os, const Streamable& l) {
156     return l.Print(os);
157   }
158 
159  private:
160   const UntypedFormatSpecImpl& format_;
161   absl::Span<const FormatArgImpl> args_;
162   // if args_.size() is 4 or less:
163   FormatArgImpl few_args_[4] = {FormatArgImpl(0), FormatArgImpl(0),
164                                 FormatArgImpl(0), FormatArgImpl(0)};
165   // if args_.size() is more than 4:
166   std::vector<FormatArgImpl> many_args_;
167 };
168 
169 // for testing
170 std::string Summarize(UntypedFormatSpecImpl format,
171                       absl::Span<const FormatArgImpl> args);
172 bool BindWithPack(const UnboundConversion* props,
173                   absl::Span<const FormatArgImpl> pack, BoundConversion* bound);
174 
175 bool FormatUntyped(FormatRawSinkImpl raw_sink,
176                    UntypedFormatSpecImpl format,
177                    absl::Span<const FormatArgImpl> args);
178 
179 std::string& AppendPack(std::string* out, UntypedFormatSpecImpl format,
180                         absl::Span<const FormatArgImpl> args);
181 
182 std::string FormatPack(const UntypedFormatSpecImpl format,
183                        absl::Span<const FormatArgImpl> args);
184 
185 int FprintF(std::FILE* output, UntypedFormatSpecImpl format,
186             absl::Span<const FormatArgImpl> args);
187 int SnprintF(char* output, size_t size, UntypedFormatSpecImpl format,
188              absl::Span<const FormatArgImpl> args);
189 
190 // Returned by Streamed(v). Converts via '%s' to the std::string created
191 // by std::ostream << v.
192 template <typename T>
193 class StreamedWrapper {
194  public:
StreamedWrapper(const T & v)195   explicit StreamedWrapper(const T& v) : v_(v) { }
196 
197  private:
198   template <typename S>
199   friend ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<S>& v,
200                                                   ConversionSpec conv,
201                                                   FormatSinkImpl* out);
202   const T& v_;
203 };
204 
205 }  // namespace str_format_internal
206 ABSL_NAMESPACE_END
207 }  // namespace absl
208 
209 #endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
210