• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
16 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
17 
18 #include <array>
19 #include <cstdio>
20 #include <sstream>
21 #include <string>
22 
23 #include "absl/base/port.h"
24 #include "absl/container/inlined_vector.h"
25 #include "absl/strings/internal/str_format/arg.h"
26 #include "absl/strings/internal/str_format/checker.h"
27 #include "absl/strings/internal/str_format/parser.h"
28 #include "absl/types/span.h"
29 #include "absl/utility/utility.h"
30 
31 namespace absl {
32 ABSL_NAMESPACE_BEGIN
33 
34 class UntypedFormatSpec;
35 
36 namespace str_format_internal {
37 
38 class BoundConversion : public FormatConversionSpecImpl {
39  public:
arg()40   const FormatArgImpl* arg() const { return arg_; }
set_arg(const FormatArgImpl * a)41   void set_arg(const FormatArgImpl* a) { arg_ = a; }
42 
43  private:
44   const FormatArgImpl* arg_;
45 };
46 
47 // This is the type-erased class that the implementation uses.
48 class UntypedFormatSpecImpl {
49  public:
50   UntypedFormatSpecImpl() = delete;
51 
UntypedFormatSpecImpl(string_view s)52   explicit UntypedFormatSpecImpl(string_view s)
53       : data_(s.data()), size_(s.size()) {}
UntypedFormatSpecImpl(const str_format_internal::ParsedFormatBase * pc)54   explicit UntypedFormatSpecImpl(
55       const str_format_internal::ParsedFormatBase* pc)
56       : data_(pc), size_(~size_t{}) {}
57 
has_parsed_conversion()58   bool has_parsed_conversion() const { return size_ == ~size_t{}; }
59 
str()60   string_view str() const {
61     assert(!has_parsed_conversion());
62     return string_view(static_cast<const char*>(data_), size_);
63   }
parsed_conversion()64   const str_format_internal::ParsedFormatBase* parsed_conversion() const {
65     assert(has_parsed_conversion());
66     return static_cast<const str_format_internal::ParsedFormatBase*>(data_);
67   }
68 
69   template <typename T>
Extract(const T & s)70   static const UntypedFormatSpecImpl& Extract(const T& s) {
71     return s.spec_;
72   }
73 
74  private:
75   const void* data_;
76   size_t size_;
77 };
78 
79 template <typename T, FormatConversionCharSet...>
80 struct MakeDependent {
81   using type = T;
82 };
83 
84 // Implicitly convertible from `const char*`, `string_view`, and the
85 // `ExtendedParsedFormat` type. This abstraction allows all format functions to
86 // operate on any without providing too many overloads.
87 template <FormatConversionCharSet... Args>
88 class FormatSpecTemplate
89     : public MakeDependent<UntypedFormatSpec, Args...>::type {
90   using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type;
91 
92   template <bool res>
93   struct ErrorMaker {
operatorErrorMaker94     constexpr bool operator()(int) const { return res; }
95   };
96 
97   template <int i, int j>
98   static constexpr bool CheckArity(ErrorMaker<true> SpecifierCount = {},
99                                    ErrorMaker<i == j> ParametersPassed = {}) {
100     static_assert(SpecifierCount(i) == ParametersPassed(j),
101                   "Number of arguments passed must match the number of "
102                   "conversion specifiers.");
103     return true;
104   }
105 
106   template <FormatConversionCharSet specified, FormatConversionCharSet passed,
107             int arg>
108   static constexpr bool CheckMatch(
109       ErrorMaker<Contains(specified, passed)> MismatchedArgumentNumber = {}) {
110     static_assert(MismatchedArgumentNumber(arg),
111                   "Passed argument must match specified format.");
112     return true;
113   }
114 
115   template <FormatConversionCharSet... C, size_t... I>
CheckMatches(absl::index_sequence<I...>)116   static bool CheckMatches(absl::index_sequence<I...>) {
117     bool res[] = {true, CheckMatch<Args, C, I + 1>()...};
118     (void)res;
119     return true;
120   }
121 
122  public:
123 #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
124 
125   // Honeypot overload for when the string is not constexpr.
126   // We use the 'unavailable' attribute to give a better compiler error than
127   // just 'method is deleted'.
128   FormatSpecTemplate(...)  // NOLINT
129       __attribute__((unavailable("Format string is not constexpr.")));
130 
131   // Honeypot overload for when the format is constexpr and invalid.
132   // We use the 'unavailable' attribute to give a better compiler error than
133   // just 'method is deleted'.
134   // To avoid checking the format twice, we just check that the format is
135   // constexpr. If it is valid, then the overload below will kick in.
136   // We add the template here to make this overload have lower priority.
137   template <typename = void>
138   FormatSpecTemplate(const char* s)  // NOLINT
139       __attribute__((
140           enable_if(str_format_internal::EnsureConstexpr(s), "constexpr trap"),
141           unavailable(
142               "Format specified does not match the arguments passed.")));
143 
144   template <typename T = void>
FormatSpecTemplate(string_view s)145   FormatSpecTemplate(string_view s)  // NOLINT
146       __attribute__((enable_if(str_format_internal::EnsureConstexpr(s),
147                                "constexpr trap")))
148       : Base("to avoid noise in the compiler error") {
149     static_assert(sizeof(T*) == 0,
150                   "Format specified does not match the arguments passed.");
151   }
152 
153   // Good format overload.
FormatSpecTemplate(const char * s)154   FormatSpecTemplate(const char* s)  // NOLINT
155       __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap")))
156       : Base(s) {}
157 
FormatSpecTemplate(string_view s)158   FormatSpecTemplate(string_view s)  // NOLINT
159       __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap")))
160       : Base(s) {}
161 
162 #else  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
163 
164   FormatSpecTemplate(const char* s) : Base(s) {}  // NOLINT
165   FormatSpecTemplate(string_view s) : Base(s) {}  // NOLINT
166 
167 #endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
168 
169   template <FormatConversionCharSet... C>
FormatSpecTemplate(const ExtendedParsedFormat<C...> & pc)170   FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc)  // NOLINT
171       : Base(&pc) {
172     CheckArity<sizeof...(C), sizeof...(Args)>();
173     CheckMatches<C...>(absl::make_index_sequence<sizeof...(C)>{});
174   }
175 };
176 
177 class Streamable {
178  public:
Streamable(const UntypedFormatSpecImpl & format,absl::Span<const FormatArgImpl> args)179   Streamable(const UntypedFormatSpecImpl& format,
180              absl::Span<const FormatArgImpl> args)
181       : format_(format), args_(args.begin(), args.end()) {}
182 
183   std::ostream& Print(std::ostream& os) const;
184 
185   friend std::ostream& operator<<(std::ostream& os, const Streamable& l) {
186     return l.Print(os);
187   }
188 
189  private:
190   const UntypedFormatSpecImpl& format_;
191   absl::InlinedVector<FormatArgImpl, 4> args_;
192 };
193 
194 // for testing
195 std::string Summarize(UntypedFormatSpecImpl format,
196                       absl::Span<const FormatArgImpl> args);
197 bool BindWithPack(const UnboundConversion* props,
198                   absl::Span<const FormatArgImpl> pack, BoundConversion* bound);
199 
200 bool FormatUntyped(FormatRawSinkImpl raw_sink, UntypedFormatSpecImpl format,
201                    absl::Span<const FormatArgImpl> args);
202 
203 std::string& AppendPack(std::string* out, UntypedFormatSpecImpl format,
204                         absl::Span<const FormatArgImpl> args);
205 
206 std::string FormatPack(const UntypedFormatSpecImpl format,
207                        absl::Span<const FormatArgImpl> args);
208 
209 int FprintF(std::FILE* output, UntypedFormatSpecImpl format,
210             absl::Span<const FormatArgImpl> args);
211 int SnprintF(char* output, size_t size, UntypedFormatSpecImpl format,
212              absl::Span<const FormatArgImpl> args);
213 
214 // Returned by Streamed(v). Converts via '%s' to the std::string created
215 // by std::ostream << v.
216 template <typename T>
217 class StreamedWrapper {
218  public:
StreamedWrapper(const T & v)219   explicit StreamedWrapper(const T& v) : v_(v) {}
220 
221  private:
222   template <typename S>
223   friend ArgConvertResult<FormatConversionCharSetUnion(
224       FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::v)>
225   FormatConvertImpl(const StreamedWrapper<S>& v, FormatConversionSpecImpl conv,
226                     FormatSinkImpl* out);
227   const T& v_;
228 };
229 
230 }  // namespace str_format_internal
231 ABSL_NAMESPACE_END
232 }  // namespace absl
233 
234 #endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
235