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