@@ -47,103 +47,147 @@ Mead, WA 99021
47
47
#include < list>
48
48
#include < string>
49
49
50
- /* (TODO: Make this table doxygen-friendly)
50
+ #ifdef BUILDING_DOXYGEN // Doxygen doesn't appear to support variadic templates yet
51
+ /* * Format a string using type-safe arguments
52
+ * \param format The format string -- see below for details
51
53
*
52
- * FORMAT SPECIFICATION
54
+ * Character Sequence | Description
55
+ * ------------------ | -----------
56
+ * `{}` | Format a value (using defaults)
57
+ * `{{` | Escape for a single '{' char
58
+ * `{options}` | Format a value, with the specified options (see below)
53
59
*
54
- * {} - format a value (defaults)
55
- * {{ - Escape for a single '{' char
56
- * {options} - Format a value, with the specified options (see below)
60
+ * Formatting Options
61
+ * ------------------
57
62
*
58
- * Options:
59
- * < - Align left
60
- * > - Align right
61
- * NNN - Pad to NNN characters (minimum - can be more)
62
- * + - Show a '+' char for positive signed values (decimal only )
63
- * _C - Use C as the pad character (only '\001'..'\177' supported for now )
64
- * x - Hex (lower-case )
65
- * X - Hex (upper -case)
66
- * o - Octal
67
- * b - Binary
68
- * d - Decimal (default) -- when used with char types, outputs a
69
- * number instead of the UTF representation of the char
70
- * c - UTF character (default for character types)
71
- * FFF.EEE - Use FFF.EEE floating point precision
72
- * f - Use 'f' format for floating point numbers
73
- * g - Use 'g' format for floating point numbers
74
- * e - Use 'e' format for floating point numbers
63
+ * Format Option | Description
64
+ * ------------- | -----------
65
+ * `<` | Align left
66
+ * `>` | Align right
67
+ * `NNN` | Pad to NNN characters (minimum - can be more )
68
+ * `+` | Show a '+' char for positive signed values (decimal only )
69
+ * `_C` | Use C as the pad character (only '\001'..'\177' supported for now )
70
+ * `x` | Hex (lower -case)
71
+ * `X` | Hex (upper-case)
72
+ * `o` | Octal
73
+ * `b` | Binary
74
+ * `d` | Decimal (default) -- when used with char types, outputs a number instead of the UTF representation of the char
75
+ * `c` | UTF character (default for character types)
76
+ * ` FFF.EEE` | Use FFF.EEE floating point precision
77
+ * `f` | Fixed floating point format (ddd.ddd)
78
+ * `e` | Exponent notation for floating point (d.ddde[+/-]dd)
79
+ * `E` | Same as 'e' format, but with upper case E (d.dddE[+/-]dd)
75
80
*/
81
+ plString plFormat (const char *format, ...);
82
+ #endif
83
+
76
84
77
- // For internal use by plFormat and its helper function
78
85
namespace plFormat_Private
79
86
{
80
87
enum Alignment : unsigned char
81
88
{
82
- kAlignDefault , kAlignLeft , kAlignRight
89
+ kAlignDefault , /* *< Left for strings, right for numbers */
90
+ kAlignLeft , /* *< Left alignment */
91
+ kAlignRight /* *< Right alignment */
83
92
};
84
93
85
94
enum DigitClass : unsigned char
86
95
{
87
- kDigitDefault , kDigitDec , kDigitDecAlwaysSigned ,
88
- kDigitHex , kDigitHexUpper , kDigitOct , kDigitBin , kDigitChar
96
+ kDigitDefault , /* *< Default digit formatting */
97
+ kDigitDec , /* *< Format as decimal integer */
98
+ kDigitDecAlwaysSigned , /* *< Same as `kDigitDec`, but include a '+' for positive numbers too */
99
+ kDigitHex , /* *< Hex integer (assume unsigned) */
100
+ kDigitHexUpper , /* *< Hex integer with upper-case digits */
101
+ kDigitOct , /* *< Octal integer (assume unsigned) */
102
+ kDigitBin , /* *< Binary integer (assume unsigned) */
103
+ kDigitChar /* *< Single unicode character (as UTF-8) */
89
104
};
90
105
91
106
enum FloatClass : unsigned char
92
107
{
93
- kFloatDefault , kFloatE , kFloatF , kFloatG
108
+ kFloatDefault , /* *< Use Fixed or Exp format depending on value */
109
+ kFloatFixed , /* *< Use Fixed notation (ddd.ddd) */
110
+ kFloatExp , /* *< Use Exp notation (d.ddde[+/-]dd) */
111
+ kFloatExpUpper /* *< Same as `kFloatExp`, but with an upper-case E */
94
112
};
95
113
114
+ /* * Represents a parsed format tag, for use in formatter implementations. */
96
115
struct FormatSpec
97
116
{
98
- int fPrecisionLeft = 0 ; // Also used for padding
99
- int fPrecisionRight = 0 ;
117
+ int fPrecisionLeft = 0 ; /* *< Requested padding and/or precision */
118
+ int fPrecisionRight = 0 ; /* *< Requested precision after the . for floating-point */
100
119
101
- char fPadChar = 0 ;
102
- Alignment fAlignment = kAlignDefault ;
103
- DigitClass fDigitClass = kDigitDefault ;
104
- FloatClass fFloatClass = kFloatDefault ;
120
+ char fPadChar = 0 ; /* *< Explicit padding char (default is space) */
121
+ Alignment fAlignment = kAlignDefault ; /* *< Requested pad alignment */
122
+ DigitClass fDigitClass = kDigitDefault ; /* *< Requested int formatting */
123
+ FloatClass fFloatClass = kFloatDefault ; /* *< Requested float formatting */
105
124
};
106
125
107
- struct IFormatDataObject
126
+ // These need to be publically visible for the macros below, but shouldn't
127
+ // be used directly outside of plFormat and its macros
128
+ struct _IFormatDataObject
108
129
{
109
130
const char *fFormatStr ;
110
131
std::list<plStringBuffer<char >> fOutput ;
111
132
};
112
133
113
- extern FormatSpec FetchNextFormat (IFormatDataObject &data);
134
+ extern FormatSpec _FetchNextFormat (_IFormatDataObject &data);
114
135
}
115
136
116
- // Fun fact: You can add your own formatters by declaring
117
- // PL_FORMAT_TYPE(mytype) in a header, and
118
- // PL_FORMAT_IMPL(mytype) { ... } in a source file
119
-
137
+ /* * Declare a formattable type for `plFormat`.
138
+ * \sa PL_FORMAT_IMPL()
139
+ */
120
140
#define PL_FORMAT_TYPE (_type ) \
121
141
extern plStringBuffer<char > _impl_plFormat_DataHandler ( \
122
142
const plFormat_Private::FormatSpec &format, _type value); \
123
143
namespace plFormat_Private \
124
144
{ \
125
145
template <typename ... _Args> \
126
- plString _IFormat (IFormatDataObject &data, _type value, _Args... args) \
146
+ plString _IFormat (_IFormatDataObject &data, _type value, _Args... args) \
127
147
{ \
128
- plFormat_Private::FormatSpec format = plFormat_Private::FetchNextFormat (data); \
148
+ plFormat_Private::FormatSpec format = plFormat_Private::_FetchNextFormat (data); \
129
149
data.fOutput .push_back (_impl_plFormat_DataHandler (format, value)); \
130
150
return _IFormat (data, args...); \
131
151
} \
132
152
} \
133
153
template <typename ... _Args> \
134
154
plString plFormat (const char *fmt_str, _type value, _Args... args) \
135
155
{ \
136
- plFormat_Private::IFormatDataObject data; \
156
+ plFormat_Private::_IFormatDataObject data; \
137
157
data.fFormatStr = fmt_str; \
138
- plFormat_Private::FormatSpec format = plFormat_Private::FetchNextFormat (data); \
158
+ plFormat_Private::FormatSpec format = plFormat_Private::_FetchNextFormat (data); \
139
159
data.fOutput .push_back (_impl_plFormat_DataHandler (format, value)); \
140
160
return plFormat_Private::_IFormat (data, args...); \
141
161
}
142
162
163
+ /* * Provide the implementation for a formattable type for `plFormat`.
164
+ * \sa PL_FORMAT_TYPE(), PL_FORMAT_FORWARD()
165
+ *
166
+ * Example:
167
+ *
168
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
169
+ * PL_FORMAT_IMPL(const MyType &)
170
+ * {
171
+ * return plFormat("MyType[data={},count={}]", value.data, value.count);
172
+ * }
173
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
174
+ */
143
175
#define PL_FORMAT_IMPL (_type ) \
144
176
plStringBuffer<char > _impl_plFormat_DataHandler ( \
145
177
const plFormat_Private::FormatSpec &format, _type value)
146
178
179
+ /* * Shortcut to call another `PL_FORMAT_IMPL` formatter.
180
+ * \sa PL_FORMAT_IMPL()
181
+ *
182
+ * Example:
183
+ *
184
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
185
+ * PL_FORMAT_IMPL(const MyType &)
186
+ * {
187
+ * return PL_FORMAT_FORWARD(format, value.ToString());
188
+ * }
189
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
190
+ */
147
191
#define PL_FORMAT_FORWARD (format, fwd_value ) \
148
192
_impl_plFormat_DataHandler ((format), (fwd_value))
149
193
@@ -174,10 +218,10 @@ PL_FORMAT_TYPE(const std::wstring &)
174
218
// To use other formats, don't pass us a bool directly...
175
219
PL_FORMAT_TYPE(bool )
176
220
177
- // End of the chain -- emits the last piece (if any) and builds the final string
178
221
namespace plFormat_Private
179
222
{
180
- plString _IFormat (IFormatDataObject &data);
223
+ // End of the chain -- emits the last piece (if any) and builds the final string
224
+ plString _IFormat (_IFormatDataObject &data);
181
225
}
182
226
183
227
#endif // plFormat_Defined
0 commit comments