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/strings/internal/str_format/arg.h" |
25 | #include "absl/strings/internal/str_format/checker.h" |
26 | #include "absl/strings/internal/str_format/parser.h" |
27 | #include "absl/types/span.h" |
28 | #include "absl/utility/utility.h" |
29 | |
30 | namespace absl { |
31 | ABSL_NAMESPACE_BEGIN |
32 | |
33 | class UntypedFormatSpec; |
34 | |
35 | namespace str_format_internal { |
36 | |
37 | class BoundConversion : public FormatConversionSpecImpl { |
38 | public: |
39 | const FormatArgImpl* arg() const { return arg_; } |
40 | void set_arg(const FormatArgImpl* a) { arg_ = a; } |
41 | |
42 | private: |
43 | const FormatArgImpl* arg_; |
44 | }; |
45 | |
46 | // This is the type-erased class that the implementation uses. |
47 | class UntypedFormatSpecImpl { |
48 | public: |
49 | UntypedFormatSpecImpl() = delete; |
50 | |
51 | explicit UntypedFormatSpecImpl(string_view s) |
52 | : data_(s.data()), size_(s.size()) {} |
53 | explicit UntypedFormatSpecImpl( |
54 | const str_format_internal::ParsedFormatBase* pc) |
55 | : data_(pc), size_(~size_t{}) {} |
56 | |
57 | bool has_parsed_conversion() const { return size_ == ~size_t{}; } |
58 | |
59 | string_view str() const { |
60 | assert(!has_parsed_conversion()); |
61 | return string_view(static_cast<const char*>(data_), size_); |
62 | } |
63 | const str_format_internal::ParsedFormatBase* parsed_conversion() const { |
64 | assert(has_parsed_conversion()); |
65 | return static_cast<const str_format_internal::ParsedFormatBase*>(data_); |
66 | } |
67 | |
68 | template <typename T> |
69 | static const UntypedFormatSpecImpl& (const T& s) { |
70 | return s.spec_; |
71 | } |
72 | |
73 | private: |
74 | const void* data_; |
75 | size_t size_; |
76 | }; |
77 | |
78 | template <typename T, FormatConversionCharSet...> |
79 | struct MakeDependent { |
80 | using type = T; |
81 | }; |
82 | |
83 | // Implicitly convertible from `const char*`, `string_view`, and the |
84 | // `ExtendedParsedFormat` type. This abstraction allows all format functions to |
85 | // operate on any without providing too many overloads. |
86 | template <FormatConversionCharSet... Args> |
87 | class FormatSpecTemplate |
88 | : public MakeDependent<UntypedFormatSpec, Args...>::type { |
89 | using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type; |
90 | |
91 | template <bool res> |
92 | struct ErrorMaker { |
93 | constexpr bool operator()(int) const { return res; } |
94 | }; |
95 | |
96 | template <int i, int j> |
97 | static constexpr bool CheckArity(ErrorMaker<true> SpecifierCount = {}, |
98 | ErrorMaker<i == j> ParametersPassed = {}) { |
99 | static_assert(SpecifierCount(i) == ParametersPassed(j), |
100 | "Number of arguments passed must match the number of " |
101 | "conversion specifiers." ); |
102 | return true; |
103 | } |
104 | |
105 | template <FormatConversionCharSet specified, FormatConversionCharSet passed, |
106 | int arg> |
107 | static constexpr bool CheckMatch( |
108 | ErrorMaker<Contains(specified, passed)> MismatchedArgumentNumber = {}) { |
109 | static_assert(MismatchedArgumentNumber(arg), |
110 | "Passed argument must match specified format." ); |
111 | return true; |
112 | } |
113 | |
114 | template <FormatConversionCharSet... C, size_t... I> |
115 | static bool CheckMatches(absl::index_sequence<I...>) { |
116 | bool res[] = {true, CheckMatch<Args, C, I + 1>()...}; |
117 | (void)res; |
118 | return true; |
119 | } |
120 | |
121 | public: |
122 | #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER |
123 | |
124 | // Honeypot overload for when the string is not constexpr. |
125 | // We use the 'unavailable' attribute to give a better compiler error than |
126 | // just 'method is deleted'. |
127 | FormatSpecTemplate(...) // NOLINT |
128 | __attribute__((unavailable("Format string is not constexpr." ))); |
129 | |
130 | // Honeypot overload for when the format is constexpr and invalid. |
131 | // We use the 'unavailable' attribute to give a better compiler error than |
132 | // just 'method is deleted'. |
133 | // To avoid checking the format twice, we just check that the format is |
134 | // constexpr. If it is valid, then the overload below will kick in. |
135 | // We add the template here to make this overload have lower priority. |
136 | template <typename = void> |
137 | FormatSpecTemplate(const char* s) // NOLINT |
138 | __attribute__(( |
139 | enable_if(str_format_internal::EnsureConstexpr(s), "constexpr trap" ), |
140 | unavailable( |
141 | "Format specified does not match the arguments passed." ))); |
142 | |
143 | template <typename T = void> |
144 | FormatSpecTemplate(string_view s) // NOLINT |
145 | __attribute__((enable_if(str_format_internal::EnsureConstexpr(s), |
146 | "constexpr trap" ))) |
147 | : Base("to avoid noise in the compiler error" ) { |
148 | static_assert(sizeof(T*) == 0, |
149 | "Format specified does not match the arguments passed." ); |
150 | } |
151 | |
152 | // Good format overload. |
153 | FormatSpecTemplate(const char* s) // NOLINT |
154 | __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap" ))) |
155 | : Base(s) {} |
156 | |
157 | FormatSpecTemplate(string_view s) // NOLINT |
158 | __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap" ))) |
159 | : Base(s) {} |
160 | |
161 | #else // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER |
162 | |
163 | FormatSpecTemplate(const char* s) : Base(s) {} // NOLINT |
164 | FormatSpecTemplate(string_view s) : Base(s) {} // NOLINT |
165 | |
166 | #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER |
167 | |
168 | template <FormatConversionCharSet... C> |
169 | FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc) // NOLINT |
170 | : Base(&pc) { |
171 | CheckArity<sizeof...(C), sizeof...(Args)>(); |
172 | CheckMatches<C...>(absl::make_index_sequence<sizeof...(C)>{}); |
173 | } |
174 | }; |
175 | |
176 | class Streamable { |
177 | public: |
178 | Streamable(const UntypedFormatSpecImpl& format, |
179 | absl::Span<const FormatArgImpl> args) |
180 | : format_(format) { |
181 | if (args.size() <= ABSL_ARRAYSIZE(few_args_)) { |
182 | for (size_t i = 0; i < args.size(); ++i) { |
183 | few_args_[i] = args[i]; |
184 | } |
185 | args_ = absl::MakeSpan(few_args_, args.size()); |
186 | } else { |
187 | many_args_.assign(args.begin(), args.end()); |
188 | args_ = many_args_; |
189 | } |
190 | } |
191 | |
192 | std::ostream& Print(std::ostream& os) const; |
193 | |
194 | friend std::ostream& operator<<(std::ostream& os, const Streamable& l) { |
195 | return l.Print(os); |
196 | } |
197 | |
198 | private: |
199 | const UntypedFormatSpecImpl& format_; |
200 | absl::Span<const FormatArgImpl> args_; |
201 | // if args_.size() is 4 or less: |
202 | FormatArgImpl few_args_[4] = {FormatArgImpl(0), FormatArgImpl(0), |
203 | FormatArgImpl(0), FormatArgImpl(0)}; |
204 | // if args_.size() is more than 4: |
205 | std::vector<FormatArgImpl> many_args_; |
206 | }; |
207 | |
208 | // for testing |
209 | std::string Summarize(UntypedFormatSpecImpl format, |
210 | absl::Span<const FormatArgImpl> args); |
211 | bool BindWithPack(const UnboundConversion* props, |
212 | absl::Span<const FormatArgImpl> pack, BoundConversion* bound); |
213 | |
214 | bool FormatUntyped(FormatRawSinkImpl raw_sink, |
215 | UntypedFormatSpecImpl format, |
216 | absl::Span<const FormatArgImpl> args); |
217 | |
218 | std::string& AppendPack(std::string* out, UntypedFormatSpecImpl format, |
219 | absl::Span<const FormatArgImpl> args); |
220 | |
221 | std::string FormatPack(const UntypedFormatSpecImpl format, |
222 | absl::Span<const FormatArgImpl> args); |
223 | |
224 | int FprintF(std::FILE* output, UntypedFormatSpecImpl format, |
225 | absl::Span<const FormatArgImpl> args); |
226 | int SnprintF(char* output, size_t size, UntypedFormatSpecImpl format, |
227 | absl::Span<const FormatArgImpl> args); |
228 | |
229 | // Returned by Streamed(v). Converts via '%s' to the std::string created |
230 | // by std::ostream << v. |
231 | template <typename T> |
232 | class StreamedWrapper { |
233 | public: |
234 | explicit StreamedWrapper(const T& v) : v_(v) { } |
235 | |
236 | private: |
237 | template <typename S> |
238 | friend ArgConvertResult<FormatConversionCharSetInternal::s> FormatConvertImpl( |
239 | const StreamedWrapper<S>& v, FormatConversionSpecImpl conv, |
240 | FormatSinkImpl* out); |
241 | const T& v_; |
242 | }; |
243 | |
244 | } // namespace str_format_internal |
245 | ABSL_NAMESPACE_END |
246 | } // namespace absl |
247 | |
248 | #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ |
249 | |