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
16namespace absl {
17
18class UntypedFormatSpec;
19
20namespace str_format_internal {
21
22class 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.
32class 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& Extract(const T& s) {
55 return s.spec_;
56 }
57
58 private:
59 const void* data_;
60 size_t size_;
61};
62
63template <typename T, typename...>
64struct 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.
71template <typename... Args>
72class 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
132template <typename... Args>
133struct FormatSpecDeductionBarrier {
134 using type = FormatSpecTemplate<Args...>;
135};
136
137class 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
155std::string Summarize(UntypedFormatSpecImpl format,
156 absl::Span<const FormatArgImpl> args);
157bool BindWithPack(const UnboundConversion* props,
158 absl::Span<const FormatArgImpl> pack, BoundConversion* bound);
159
160bool FormatUntyped(FormatRawSinkImpl raw_sink,
161 UntypedFormatSpecImpl format,
162 absl::Span<const FormatArgImpl> args);
163
164std::string& AppendPack(std::string* out, UntypedFormatSpecImpl format,
165 absl::Span<const FormatArgImpl> args);
166
167inline 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
174int FprintF(std::FILE* output, UntypedFormatSpecImpl format,
175 absl::Span<const FormatArgImpl> args);
176int 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.
181template <typename T>
182class 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