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