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/container/inlined_vector.h" |
11 | #include "absl/strings/internal/str_format/arg.h" |
12 | #include "absl/strings/internal/str_format/checker.h" |
13 | #include "absl/strings/internal/str_format/parser.h" |
14 | #include "absl/types/span.h" |
15 | |
16 | namespace absl { |
17 | |
18 | class UntypedFormatSpec; |
19 | |
20 | namespace str_format_internal { |
21 | |
22 | class BoundConversion : public ConversionSpec { |
23 | public: |
24 | const FormatArgImpl* arg() const { return arg_; } |
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 | |
36 | explicit UntypedFormatSpecImpl(string_view s) |
37 | : data_(s.data()), size_(s.size()) {} |
38 | explicit UntypedFormatSpecImpl( |
39 | const str_format_internal::ParsedFormatBase* pc) |
40 | : data_(pc), size_(~size_t{}) {} |
41 | |
42 | bool has_parsed_conversion() const { return size_ == ~size_t{}; } |
43 | |
44 | string_view str() const { |
45 | assert(!has_parsed_conversion()); |
46 | return string_view(static_cast<const char*>(data_), size_); |
47 | } |
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> |
54 | static const UntypedFormatSpecImpl& (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 | #if 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> |
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. |
107 | FormatSpecTemplate(const char* s) // NOLINT |
108 | __attribute__((enable_if(ValidFormatImpl<ArgumentToConv<Args>()...>(s), |
109 | "bad format trap" ))) |
110 | : Base(s) {} |
111 | |
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 | sizeof...(C) == sizeof...(Args) && |
126 | AllOf(Contains(ArgumentToConv<Args>(), |
127 | C)...)>::type> |
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: |
139 | Streamable(const UntypedFormatSpecImpl& format, |
140 | absl::Span<const FormatArgImpl> args) |
141 | : format_(format), args_(args.begin(), args.end()) {} |
142 | |
143 | std::ostream& Print(std::ostream& os) const; |
144 | |
145 | friend std::ostream& operator<<(std::ostream& os, const Streamable& l) { |
146 | return l.Print(os); |
147 | } |
148 | |
149 | private: |
150 | const UntypedFormatSpecImpl& format_; |
151 | absl::InlinedVector<FormatArgImpl, 4> args_; |
152 | }; |
153 | |
154 | // for testing |
155 | std::string Summarize(UntypedFormatSpecImpl format, |
156 | absl::Span<const FormatArgImpl> args); |
157 | bool BindWithPack(const UnboundConversion* props, |
158 | absl::Span<const FormatArgImpl> pack, BoundConversion* bound); |
159 | |
160 | bool FormatUntyped(FormatRawSinkImpl raw_sink, |
161 | UntypedFormatSpecImpl format, |
162 | absl::Span<const FormatArgImpl> args); |
163 | |
164 | std::string& AppendPack(std::string* out, UntypedFormatSpecImpl format, |
165 | absl::Span<const FormatArgImpl> args); |
166 | |
167 | inline std::string FormatPack(const UntypedFormatSpecImpl format, |
168 | absl::Span<const FormatArgImpl> args) { |
169 | std::string out; |
170 | AppendPack(&out, format, args); |
171 | return out; |
172 | } |
173 | |
174 | int FprintF(std::FILE* output, UntypedFormatSpecImpl format, |
175 | absl::Span<const FormatArgImpl> args); |
176 | int SnprintF(char* output, size_t size, UntypedFormatSpecImpl format, |
177 | absl::Span<const FormatArgImpl> args); |
178 | |
179 | // Returned by Streamed(v). Converts via '%s' to the std::string created |
180 | // by std::ostream << v. |
181 | template <typename T> |
182 | class StreamedWrapper { |
183 | public: |
184 | explicit StreamedWrapper(const T& v) : v_(v) { } |
185 | |
186 | private: |
187 | template <typename S> |
188 | friend ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<S>& v, |
189 | ConversionSpec conv, |
190 | FormatSinkImpl* out); |
191 | const T& v_; |
192 | }; |
193 | |
194 | } // namespace str_format_internal |
195 | } // namespace absl |
196 | |
197 | #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ |
198 | |