33
33
34
34
namespace llvm {
35
35
36
+ // / Utility class that parses printf-style format strings to yield the expected
37
+ // / C type(s) of each specifier. This class is used to verify that a format
38
+ // / string unknown at compile-time is equivalent to another format string (which
39
+ // / itself is hopefully known at compile-time).
40
+ class PrintfStyleFormatReader {
41
+ public:
42
+ enum SpecifierType : char {
43
+ ST_EndOfFormatString,
44
+ ST_Unknown,
45
+ ST_WideChar,
46
+ ST_Int,
47
+ ST_Long,
48
+ ST_LongLong,
49
+ ST_IntMax,
50
+ ST_Size,
51
+ ST_Ptrdiff,
52
+ ST_Double,
53
+ ST_LongDouble,
54
+ ST_CString,
55
+ ST_WideCString,
56
+ ST_VoidPointer,
57
+ ST_Count_Char,
58
+ ST_Count_Short,
59
+ ST_Count_Int,
60
+ ST_Count_Long,
61
+ ST_Count_LongLong,
62
+ ST_Count_IntMax,
63
+ ST_Count_Size,
64
+ ST_Count_Ptrdiff
65
+ };
66
+
67
+ private:
68
+ const char *Fmt;
69
+ llvm::SmallVector<SpecifierType, 3 > SpecifierQueue;
70
+
71
+ void refillSpecifierQueue ();
72
+
73
+ public:
74
+ // / Verify that the format specifiers in \p Fmt consume no more arguments than
75
+ // / those in \p Expected, and that all consumed arguments have a compatible
76
+ // / type. If \p Fmt is compatible with \p Expected in this way, \p Fmt is
77
+ // / returned. Otherwise, \p Expected is returned.
78
+ static const char *ensureCompatible (const char *Expected, const char *Fmt);
79
+
80
+ PrintfStyleFormatReader (const char *Fmt) : Fmt(Fmt) {}
81
+
82
+ SpecifierType nextSpecifier () {
83
+ if (SpecifierQueue.empty ())
84
+ refillSpecifierQueue ();
85
+ return SpecifierQueue.pop_back_val ();
86
+ }
87
+ };
88
+
36
89
// / This is a helper class used for handling formatted output. It is the
37
90
// / abstract base class of a templated derived class.
38
91
class format_object_base {
39
92
protected:
40
- const char *Fmt;
41
93
~format_object_base () = default ; // Disallow polymorphic deletion.
42
94
format_object_base (const format_object_base &) = default;
43
95
virtual void home (); // Out of line virtual method.
@@ -46,7 +98,7 @@ class format_object_base {
46
98
virtual int snprint (char *Buffer, unsigned BufferSize) const = 0;
47
99
48
100
public:
49
- format_object_base (const char *fmt) : Fmt(fmt) {}
101
+ format_object_base () = default;
50
102
51
103
// / Format the object into the specified buffer. On success, this returns
52
104
// / the length of the formatted string. If the buffer is too small, this
@@ -86,28 +138,27 @@ struct validate_format_parameters<Arg, Args...> {
86
138
};
87
139
template <> struct validate_format_parameters <> {};
88
140
89
- template <typename ... Ts>
90
- class format_object final : public format_object_base {
91
- std::tuple<Ts...> Vals;
92
-
93
- template <std::size_t ... Is>
94
- int snprint_tuple (char *Buffer, unsigned BufferSize,
95
- std::index_sequence<Is...>) const {
141
+ template <typename ... Ts> auto format_capture (const char *Fmt, Ts... Vals) {
142
+ validate_format_parameters<Ts...>();
143
+ return [=](char *Buffer, unsigned BufferSize) {
96
144
#ifdef _MSC_VER
97
- return _snprintf (Buffer, BufferSize, Fmt, std::get<Is>( Vals) ...);
145
+ return _snprintf (Buffer, BufferSize, Fmt, Vals...);
98
146
#else
99
- return snprintf (Buffer, BufferSize, Fmt, std::get<Is>( Vals) ...);
147
+ return snprintf (Buffer, BufferSize, Fmt, Vals...);
100
148
#endif
101
- }
149
+ };
150
+ }
151
+
152
+ template <typename ... Ts>
153
+ class format_object final : public format_object_base {
154
+ decltype (format_capture<Ts...>(" " , std::declval<Ts>()...)) Format;
102
155
103
156
public:
104
- format_object (const char *fmt, const Ts &... vals)
105
- : format_object_base(fmt), Vals(vals...) {
106
- validate_format_parameters<Ts...>();
107
- }
157
+ format_object (const char *Fmt, const Ts &...vals)
158
+ : Format(format_capture(Fmt, vals...)) {}
108
159
109
160
int snprint (char *Buffer, unsigned BufferSize) const override {
110
- return snprint_tuple (Buffer, BufferSize, std::index_sequence_for<Ts...>() );
161
+ return Format (Buffer, BufferSize);
111
162
}
112
163
};
113
164
0 commit comments