Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 297 lines (257 sloc) 12.609 kB
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
1 #ifndef _STRINGF_H
2 #define _STRINGF_H
3
87ec978 @johnbartholomew Second pass at the string formatting routines.
johnbartholomew authored
4 #include "libs.h"
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
5 #include <string>
87ec978 @johnbartholomew Second pass at the string formatting routines.
johnbartholomew authored
6 #include <SDL_stdinc.h>
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
7
8 // provides (for integer types, floating point types, const char* and std::string):
9 //
10 // Basic value -> string functions:
11 // std::string to_string(T value);
12 // std::string to_string(T value, const FormatSpec& format);
13 //
14 // You may extend the system by providing your own overloads for
56c3979 @johnbartholomew Add some documentation of stringf() to the header.
johnbartholomew authored
15 // std::string to_string(T value, const FormatSpec& format)
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
16 //
17 // String formatter:
18 // std::string stringf(const char* fmt, ...);
19 //
20 // This should work for up to 7 arguments, where each argument is:
21 // - An object of type FormatArg or FormatArgT<T> for some T
22 // - Or, the result of a call to formatarg(name, value)
23 // - Or, a value of a type that can be converted to a string with to_string
24 //
87ec978 @johnbartholomew Second pass at the string formatting routines.
johnbartholomew authored
25 // formatarg() allows you to give a name and optionally a default format
26 // for an argument to stringf()
27 // e.g., formatarg("distance", 42.5, "f.2")
28 //
29 // That argument can then be referenced in the format template as %distance,
30 // and will be formatted as a fixed-point number with 2 decimal places.
31 //
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
32 // stringf(), along with FormatArg and formatarg() is a wrapper around
87ec978 @johnbartholomew Second pass at the string formatting routines.
johnbartholomew authored
33 // string_format(const char* fmt, int numargs, const FormatArg * const args[])
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
34 //
56c3979 @johnbartholomew Add some documentation of stringf() to the header.
johnbartholomew authored
35 // Syntax for argument references:
36 // ref = '%' ( ident | int | '{' [^}]+ '}' ) ( '{' formatspec '}' )?
37 // int = [0-9]+
38 // ident = [a-zA-Z_] [a-zA-Z0-9_]*
39 // alpha = [a-zA-Z]
40 // formatspec = alpha+ ( ':'? fmtparam ( '|' fmtparam)* )
41 // fmtparam = ( [^}\] | '\' any )*
42 //
43 // To insert a literal % character, use %% (as in printf)
44 //
45 // References are either an integer argument index (0-based),
46 // or a text string, which can follow C identifier rules, or be any string
47 // enclosed in braces.
48 //
49 // The format specifier, if provided, consists of a style name, followed by
50 // a series of parameters. Style names are alphabetic only (no underscore,
51 // digits or puncutation). Parameters may immediately follow the style name,
52 // or be separated from the style name by a colon.
53 // Parameters are separated from each other by a pipe character.
54 // Backslash may be used within format parameters to escape '|' and '}',
55 // more generally, backslash within a format parameter causes the next
56 // character to be taken as a literal, regardless of what that character is
57 //
58 // Examples of references:
59 // stringf("Hello, %0.", "Jameson") -> "Hello, Jameson."
60 // stringf("Hello, %0.", formatarg("name", "Jameson")) -> "Hello, Jameson."
61 // stringf("Hello, %name.", formatarg("name", "Jameson")) -> "Hello, Jameson."
62 // stringf("That's %{mood}tastic!", formatarg("mood", "funky")) -> "That's funkytastic!"
63 //
64 // stringf("I've already wasted %count %{trip(s)} on this fooling endeavour!",
65 // formatarg("count", 3), formatarg("trip(s)", "trips"))
66 // -> "I've already wasted 3 trips on this fooling endeavour!"
67 //
68 // stringf("I've already wasted %count %{trip(s)} on this fooling endeavour!",
69 // formatarg("count", 1), formatarg("trip(s)", "trip"))
70 // -> "I've already wasted 1 trip on this fooling endeavour!"
71 //
72 // stringf("That'll be %0 credits, Mr. %1.", 50, "Jameson")
73 // -> "That'll be 50 credits, Mr. Jameson."
74 // stringf("Excellent choice, Mr. %1! That'll be %0 credits, please.", 50, "Jameson")
75 // -> "Excellent choice, Mr. Jameson! That'll be 50 credits, please."
76 //
77 // Currently implemented format styles are designed to mostly match printf()
78 // specifiers, except to follow the general syntax described above, the
79 // specifier itself comes first, then any flags as a parameter. Only numeric
80 // types currently interpret these format specifiers. So:
81 //
82 // printf("%s", "Hello") =~= stringf("%0", "Hello")
83 // printf("%f", 42.125) =~= stringf("%0{f}", 42.125)
84 // printf("%.2f", 42.125) =~= stringf("%0{f.2}", 42.125)
85 // printf("%+2.3f", 42.125) =~= stringf("%0{f+2.3}", 42.125)
86 // printf("%08d", 42) =~= stringf("%0{d08}", 42)
87 //
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
88
87ec978 @johnbartholomew Second pass at the string formatting routines.
johnbartholomew authored
89 class FormatSpec {
90 public:
91 FormatSpec();
92 FormatSpec(const char* format);
93 FormatSpec(const char* format, int formatlen);
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
94
87ec978 @johnbartholomew Second pass at the string formatting routines.
johnbartholomew authored
95 bool empty() const;
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
96
87ec978 @johnbartholomew Second pass at the string formatting routines.
johnbartholomew authored
97 // access to components of the formatspec
98 bool specifierIs(const char* specifier) const;
99 int paramCount() const;
100 std::string param(int idx) const;
101 void paramPtr(int idx, const char*& begin, const char*& end) const;
102
103 private:
104 static const int MAX_PARAMS = 3;
105
106 void parseFormat(int length);
107
108 const char * const format;
109 // each entry in the params array specifies the index within format[]
110 // of the first byte in the parameter
111 uint16_t params[MAX_PARAMS+1];
112 };
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
113
87ec978 @johnbartholomew Second pass at the string formatting routines.
johnbartholomew authored
114 std::string to_string(int32_t value, const FormatSpec& fmt);
115 std::string to_string(int64_t value, const FormatSpec& fmt);
116 std::string to_string(uint32_t value, const FormatSpec& fmt);
117 std::string to_string(uint64_t value, const FormatSpec& fmt);
118 std::string to_string(float value, const FormatSpec& fmt);
119 std::string to_string(double value, const FormatSpec& fmt);
120 std::string to_string(fixed value, const FormatSpec& fmt);
121 std::string to_string(const char* value, const FormatSpec& fmt);
122 std::string to_string(const std::string& value, const FormatSpec& fmt);
123
124 inline std::string to_string(int32_t value, const FormatSpec& fmt) {
125 return to_string(int64_t(value), fmt);
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
126 }
127
87ec978 @johnbartholomew Second pass at the string formatting routines.
johnbartholomew authored
128 inline std::string to_string(uint32_t value, const FormatSpec& fmt) {
129 return to_string(uint64_t(value), fmt);
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
130 }
131
87ec978 @johnbartholomew Second pass at the string formatting routines.
johnbartholomew authored
132 inline std::string to_string(float value, const FormatSpec& fmt) {
133 return to_string(double(value), fmt);
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
134 }
135
87ec978 @johnbartholomew Second pass at the string formatting routines.
johnbartholomew authored
136 inline std::string to_string(fixed value, const FormatSpec& fmt) {
137 return to_string(value.ToDouble(), fmt);
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
138 }
139
140 template <typename T>
87ec978 @johnbartholomew Second pass at the string formatting routines.
johnbartholomew authored
141 inline std::string to_string(const T& value) {
142 return to_string(value, FormatSpec());
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
143 }
144
145 class FormatArg {
146 public:
87ec978 @johnbartholomew Second pass at the string formatting routines.
johnbartholomew authored
147 explicit FormatArg(const char* name_ = 0, const char* defaultformat_ = 0):
148 name(name_), defaultformat(defaultformat_) {}
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
149
150 char const * const name;
87ec978 @johnbartholomew Second pass at the string formatting routines.
johnbartholomew authored
151 char const * const defaultformat;
152
153 virtual std::string format(const FormatSpec& spec) const = 0;
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
154 };
155
156 template <typename T>
157 class FormatArgT : public FormatArg {
158 public:
87ec978 @johnbartholomew Second pass at the string formatting routines.
johnbartholomew authored
159 FormatArgT(const char* name_, const T& value_, const char* defaultformat_):
160 FormatArg(name_, defaultformat_), value(value_) {}
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
161
87ec978 @johnbartholomew Second pass at the string formatting routines.
johnbartholomew authored
162 virtual std::string format(const FormatSpec& spec) const {
163 return to_string(value, spec);
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
164 }
165
166 private:
167 const T value;
168 };
169
170 // ---------------------------------------------------------------------------
171
172 template <typename T> struct FormatArgWrapper;
173
174 template <typename T> struct FormatArgWrapper {
175 typedef FormatArgT<T> type;
79b0e85 @johnbartholomew Fix type errors in StringF when passing a static char array to format…
johnbartholomew authored
176 static type wrap(const T& arg, const char* name = 0, const char* defaultformat = 0)
177 { return FormatArgT<T>(name, arg, defaultformat); }
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
178 };
179 template <int N> struct FormatArgWrapper<char[N]> {
180 typedef FormatArgT<const char*> type;
79b0e85 @johnbartholomew Fix type errors in StringF when passing a static char array to format…
johnbartholomew authored
181 static type wrap(const char (&arg)[N], const char* name = 0, const char* defaultformat = 0)
182 { return FormatArgT<const char*>(name, arg, defaultformat); }
183 };
184 template <> struct FormatArgWrapper<char[]> {
185 typedef FormatArgT<const char*> type;
186 static type wrap(const char *arg, const char* name = 0, const char* defaultformat = 0)
187 { return FormatArgT<const char*>(name, arg, defaultformat); }
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
188 };
189 template <> struct FormatArgWrapper<FormatArg> {
190 typedef FormatArg type;
191 static const type& wrap(const FormatArg& arg) { return arg; }
192 };
193 template <typename T> struct FormatArgWrapper< FormatArgT<T> > {
194 typedef FormatArgT<T> type;
195 static const type& wrap(const FormatArgT<T>& arg) { return arg; }
196 };
197
79b0e85 @johnbartholomew Fix type errors in StringF when passing a static char array to format…
johnbartholomew authored
198 // ---------------------------------------------------------------------------
199
200 // this version is safer (doesn't rely on the value out-living the FormatArgT object)
201 // but performs a string copy
202 /*
203 FormatArgT<std::string> formatarg(const char* name, const char* value) {
204 return FormatArgT<std::string>(name, std::string(value));
205 }
206 */
207
208 template <typename T>
209 inline typename FormatArgWrapper<T>::type
210 formatarg(const char* name, const T& value, const char* defaultformat = 0) {
211 return FormatArgWrapper<T>::wrap(value, name, defaultformat);
212 }
213
214 // underlying formatting function
215
216 std::string string_format(const char* fmt, int numargs, FormatArg const * const args[]);
217
218 // ---------------------------------------------------------------------------
219
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
220 // ---- stringf(format, args...) for 0 to 7 arguments ----
221
222 inline std::string stringf(const char* fmt) {
223 return string_format(fmt, 0, 0);
224 }
225
226 template <typename T0>
227 inline std::string stringf(const char* fmt, const T0& p0) {
228 const typename FormatArgWrapper<T0>::type& arg0 = FormatArgWrapper<T0>::wrap(p0);
229 FormatArg const * const args[] = { &arg0 };
86b376e @johnbartholomew use COUNTOF in the stringf functions
johnbartholomew authored
230 return string_format(fmt, COUNTOF(args), args);
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
231 }
232
233 template <typename T0, typename T1>
234 inline std::string stringf(const char* fmt, const T0& p0, const T1& p1) {
235 const typename FormatArgWrapper<T0>::type& arg0 = FormatArgWrapper<T0>::wrap(p0);
236 const typename FormatArgWrapper<T1>::type& arg1 = FormatArgWrapper<T1>::wrap(p1);
237 FormatArg const * const args[] = { &arg0, &arg1 };
86b376e @johnbartholomew use COUNTOF in the stringf functions
johnbartholomew authored
238 return string_format(fmt, COUNTOF(args), args);
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
239 }
240
241 template <typename T0, typename T1, typename T2>
242 inline std::string stringf(const char* fmt, const T0& p0, const T1& p1, const T2& p2) {
243 const typename FormatArgWrapper<T0>::type& arg0 = FormatArgWrapper<T0>::wrap(p0);
244 const typename FormatArgWrapper<T1>::type& arg1 = FormatArgWrapper<T1>::wrap(p1);
245 const typename FormatArgWrapper<T2>::type& arg2 = FormatArgWrapper<T2>::wrap(p2);
246 FormatArg const * const args[] = { &arg0, &arg1, &arg2 };
86b376e @johnbartholomew use COUNTOF in the stringf functions
johnbartholomew authored
247 return string_format(fmt, COUNTOF(args), args);
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
248 }
249
250 template <typename T0, typename T1, typename T2, typename T3>
251 inline std::string stringf(const char* fmt, const T0& p0, const T1& p1, const T2& p2, const T3& p3) {
252 const typename FormatArgWrapper<T0>::type& arg0 = FormatArgWrapper<T0>::wrap(p0);
253 const typename FormatArgWrapper<T1>::type& arg1 = FormatArgWrapper<T1>::wrap(p1);
254 const typename FormatArgWrapper<T2>::type& arg2 = FormatArgWrapper<T2>::wrap(p2);
255 const typename FormatArgWrapper<T3>::type& arg3 = FormatArgWrapper<T3>::wrap(p3);
256 FormatArg const * const args[] = { &arg0, &arg1, &arg2, &arg3 };
86b376e @johnbartholomew use COUNTOF in the stringf functions
johnbartholomew authored
257 return string_format(fmt, COUNTOF(args), args);
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
258 }
259
260 template <typename T0, typename T1, typename T2, typename T3, typename T4>
261 inline std::string stringf(const char* fmt, const T0& p0, const T1& p1, const T2& p2, const T3& p3, const T4& p4) {
262 const typename FormatArgWrapper<T0>::type& arg0 = FormatArgWrapper<T0>::wrap(p0);
263 const typename FormatArgWrapper<T1>::type& arg1 = FormatArgWrapper<T1>::wrap(p1);
264 const typename FormatArgWrapper<T2>::type& arg2 = FormatArgWrapper<T2>::wrap(p2);
265 const typename FormatArgWrapper<T3>::type& arg3 = FormatArgWrapper<T3>::wrap(p3);
266 const typename FormatArgWrapper<T4>::type& arg4 = FormatArgWrapper<T4>::wrap(p4);
267 FormatArg const * const args[] = { &arg0, &arg1, &arg2, &arg3, &arg4 };
86b376e @johnbartholomew use COUNTOF in the stringf functions
johnbartholomew authored
268 return string_format(fmt, COUNTOF(args), args);
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
269 }
270
271 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
272 inline std::string stringf(const char* fmt, const T0& p0, const T1& p1, const T2& p2, const T3& p3, const T4& p4, const T5& p5) {
273 const typename FormatArgWrapper<T0>::type& arg0 = FormatArgWrapper<T0>::wrap(p0);
274 const typename FormatArgWrapper<T1>::type& arg1 = FormatArgWrapper<T1>::wrap(p1);
275 const typename FormatArgWrapper<T2>::type& arg2 = FormatArgWrapper<T2>::wrap(p2);
276 const typename FormatArgWrapper<T3>::type& arg3 = FormatArgWrapper<T3>::wrap(p3);
277 const typename FormatArgWrapper<T4>::type& arg4 = FormatArgWrapper<T4>::wrap(p4);
278 const typename FormatArgWrapper<T5>::type& arg5 = FormatArgWrapper<T5>::wrap(p5);
279 FormatArg const * const args[] = { &arg0, &arg1, &arg2, &arg3, &arg4, &arg5 };
86b376e @johnbartholomew use COUNTOF in the stringf functions
johnbartholomew authored
280 return string_format(fmt, COUNTOF(args), args);
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
281 }
282
283 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
284 inline std::string stringf(const char* fmt, const T0& p0, const T1& p1, const T2& p2, const T3& p3, const T4& p4, const T5& p5, const T6& p6) {
285 const typename FormatArgWrapper<T0>::type& arg0 = FormatArgWrapper<T0>::wrap(p0);
286 const typename FormatArgWrapper<T1>::type& arg1 = FormatArgWrapper<T1>::wrap(p1);
287 const typename FormatArgWrapper<T2>::type& arg2 = FormatArgWrapper<T2>::wrap(p2);
288 const typename FormatArgWrapper<T3>::type& arg3 = FormatArgWrapper<T3>::wrap(p3);
289 const typename FormatArgWrapper<T4>::type& arg4 = FormatArgWrapper<T4>::wrap(p4);
290 const typename FormatArgWrapper<T5>::type& arg5 = FormatArgWrapper<T5>::wrap(p5);
291 const typename FormatArgWrapper<T6>::type& arg6 = FormatArgWrapper<T6>::wrap(p6);
292 FormatArg const * const args[] = { &arg0, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6 };
86b376e @johnbartholomew use COUNTOF in the stringf functions
johnbartholomew authored
293 return string_format(fmt, COUNTOF(args), args);
d5f5849 @johnbartholomew First pass at a better string template/formatter function.
johnbartholomew authored
294 }
295
28d87ef @richardpl put newline at eof
richardpl authored
296 #endif
Something went wrong with that request. Please try again.