Browse Source

Add better documentation, and fix some floating point flag stuff

Michael Hansen 10 years ago
parent
commit
b199cb5ff0
  1. 2
      Doxyfile
  2. 18
      Sources/Plasma/CoreLib/plFormat.cpp
  3. 134
      Sources/Plasma/CoreLib/plFormat.h

2
Doxyfile

@ -1588,7 +1588,7 @@ INCLUDE_FILE_PATTERNS =
# undefined via #undef or recursively expanded use the := operator # undefined via #undef or recursively expanded use the := operator
# instead of the = operator. # instead of the = operator.
PREDEFINED = PREDEFINED = BUILDING_DOXYGEN
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded. # this tag can be used to specify a list of macro names that should be expanded.

18
Sources/Plasma/CoreLib/plFormat.cpp

@ -50,7 +50,7 @@ Mead, WA 99021
namespace plFormat_Private namespace plFormat_Private
{ {
static const char *_scanNextFormat(IFormatDataObject &data) static const char *_scanNextFormat(_IFormatDataObject &data)
{ {
hsAssert(data.fFormatStr, "Passed a null format string!"); hsAssert(data.fFormatStr, "Passed a null format string!");
@ -64,7 +64,7 @@ namespace plFormat_Private
return ptr; return ptr;
} }
static void _fetchPrefixChunk(IFormatDataObject &data) static void _fetchPrefixChunk(_IFormatDataObject &data)
{ {
do { do {
const char *next = _scanNextFormat(data); const char *next = _scanNextFormat(data);
@ -81,7 +81,7 @@ namespace plFormat_Private
} while (0); } while (0);
} }
FormatSpec FetchNextFormat(IFormatDataObject &data) FormatSpec _FetchNextFormat(_IFormatDataObject &data)
{ {
_fetchPrefixChunk(data); _fetchPrefixChunk(data);
hsAssert(*data.fFormatStr == '{', "Too many actual parameters for format string"); hsAssert(*data.fFormatStr == '{', "Too many actual parameters for format string");
@ -135,13 +135,13 @@ namespace plFormat_Private
spec.fDigitClass = kDigitChar; spec.fDigitClass = kDigitChar;
break; break;
case 'f': case 'f':
spec.fFloatClass = kFloatF; spec.fFloatClass = kFloatFixed;
break;
case 'g':
spec.fFloatClass = kFloatG;
break; break;
case 'e': case 'e':
spec.fFloatClass = kFloatE; spec.fFloatClass = kFloatExp;
break;
case 'E':
spec.fFloatClass = kFloatExpUpper;
break; break;
case '0': case '1': case '2': case '3': case '4': case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': case '5': case '6': case '7': case '8': case '9':
@ -166,7 +166,7 @@ namespace plFormat_Private
} }
} }
plString _IFormat(plFormat_Private::IFormatDataObject &data) plString _IFormat(plFormat_Private::_IFormatDataObject &data)
{ {
_fetchPrefixChunk(data); _fetchPrefixChunk(data);
hsAssert(*data.fFormatStr == 0, "Not enough actual parameters for format string"); hsAssert(*data.fFormatStr == 0, "Not enough actual parameters for format string");

134
Sources/Plasma/CoreLib/plFormat.h

@ -47,85 +47,105 @@ Mead, WA 99021
#include <list> #include <list>
#include <string> #include <string>
/* (TODO: Make this table doxygen-friendly) #ifdef BUILDING_DOXYGEN // Doxygen doesn't appear to support variadic templates yet
/** Format a string using type-safe arguments
* \param format The format string -- see below for details
* *
* FORMAT SPECIFICATION * Character Sequence | Description
* ------------------ | -----------
* `{}` | Format a value (using defaults)
* `{{` | Escape for a single '{' char
* `{options}` | Format a value, with the specified options (see below)
* *
* {} - format a value (defaults) * Formatting Options
* {{ - Escape for a single '{' char * ------------------
* {options} - Format a value, with the specified options (see below)
* *
* Options: * Format Option | Description
* < - Align left * ------------- | -----------
* > - Align right * `<` | Align left
* NNN - Pad to NNN characters (minimum - can be more) * `>` | Align right
* + - Show a '+' char for positive signed values (decimal only) * `NNN` | Pad to NNN characters (minimum - can be more)
* _C - Use C as the pad character (only '\001'..'\177' supported for now) * `+` | Show a '+' char for positive signed values (decimal only)
* x - Hex (lower-case) * `_C` | Use C as the pad character (only '\001'..'\177' supported for now)
* X - Hex (upper-case) * `x` | Hex (lower-case)
* o - Octal * `X` | Hex (upper-case)
* b - Binary * `o` | Octal
* d - Decimal (default) -- when used with char types, outputs a * `b` | Binary
* number instead of the UTF representation of the char * `d` | Decimal (default) -- when used with char types, outputs a number instead of the UTF representation of the char
* c - UTF character (default for character types) * `c` | UTF character (default for character types)
* FFF.EEE - Use FFF.EEE floating point precision * `FFF.EEE` | Use FFF.EEE floating point precision
* f - Use 'f' format for floating point numbers * `f` | Fixed floating point format (ddd.ddd)
* g - Use 'g' format for floating point numbers * `e` | Exponent notation for floating point (d.ddde[+/-]dd)
* e - Use 'e' format for floating point numbers * `E` | Same as 'e' format, but with upper case E (d.dddE[+/-]dd)
*/ */
plString plFormat(const char *format, ...);
#endif
// For internal use by plFormat and its helper function
namespace plFormat_Private namespace plFormat_Private
{ {
enum Alignment : unsigned char enum Alignment : unsigned char
{ {
kAlignDefault, kAlignLeft, kAlignRight kAlignDefault, /**< Left for strings, right for numbers */
kAlignLeft, /**< Left alignment */
kAlignRight /**< Right alignment */
}; };
enum DigitClass : unsigned char enum DigitClass : unsigned char
{ {
kDigitDefault, kDigitDec, kDigitDecAlwaysSigned, kDigitDefault, /**< Default digit formatting */
kDigitHex, kDigitHexUpper, kDigitOct, kDigitBin, kDigitChar kDigitDec, /**< Format as decimal integer */
kDigitDecAlwaysSigned, /**< Same as `kDigitDec`, but include a '+' for positive numbers too */
kDigitHex, /**< Hex integer (assume unsigned) */
kDigitHexUpper, /**< Hex integer with upper-case digits */
kDigitOct, /**< Octal integer (assume unsigned) */
kDigitBin, /**< Binary integer (assume unsigned) */
kDigitChar /**< Single unicode character (as UTF-8) */
}; };
enum FloatClass : unsigned char enum FloatClass : unsigned char
{ {
kFloatDefault, kFloatE, kFloatF, kFloatG kFloatDefault, /**< Use Fixed or Exp format depending on value */
kFloatFixed, /**< Use Fixed notation (ddd.ddd) */
kFloatExp, /**< Use Exp notation (d.ddde[+/-]dd) */
kFloatExpUpper /**< Same as `kFloatExp`, but with an upper-case E */
}; };
/** Represents a parsed format tag, for use in formatter implementations. */
struct FormatSpec struct FormatSpec
{ {
int fPrecisionLeft = 0; // Also used for padding int fPrecisionLeft = 0; /**< Requested padding and/or precision */
int fPrecisionRight = 0; int fPrecisionRight = 0; /**< Requested precision after the . for floating-point */
char fPadChar = 0; char fPadChar = 0; /**< Explicit padding char (default is space) */
Alignment fAlignment = kAlignDefault; Alignment fAlignment = kAlignDefault; /**< Requested pad alignment */
DigitClass fDigitClass = kDigitDefault; DigitClass fDigitClass = kDigitDefault; /**< Requested int formatting */
FloatClass fFloatClass = kFloatDefault; FloatClass fFloatClass = kFloatDefault; /**< Requested float formatting */
}; };
struct IFormatDataObject // These need to be publically visible for the macros below, but shouldn't
// be used directly outside of plFormat and its macros
struct _IFormatDataObject
{ {
const char *fFormatStr; const char *fFormatStr;
std::list<plStringBuffer<char>> fOutput; std::list<plStringBuffer<char>> fOutput;
}; };
extern FormatSpec FetchNextFormat(IFormatDataObject &data); extern FormatSpec _FetchNextFormat(_IFormatDataObject &data);
} }
// Fun fact: You can add your own formatters by declaring /** Declare a formattable type for `plFormat`.
// PL_FORMAT_TYPE(mytype) in a header, and * \sa PL_FORMAT_IMPL()
// PL_FORMAT_IMPL(mytype) { ... } in a source file */
#define PL_FORMAT_TYPE(_type) \ #define PL_FORMAT_TYPE(_type) \
extern plStringBuffer<char> _impl_plFormat_DataHandler( \ extern plStringBuffer<char> _impl_plFormat_DataHandler( \
const plFormat_Private::FormatSpec &format, _type value); \ const plFormat_Private::FormatSpec &format, _type value); \
namespace plFormat_Private \ namespace plFormat_Private \
{ \ { \
template <typename... _Args> \ template <typename... _Args> \
plString _IFormat(IFormatDataObject &data, _type value, _Args... args) \ plString _IFormat(_IFormatDataObject &data, _type value, _Args... args) \
{ \ { \
plFormat_Private::FormatSpec format = plFormat_Private::FetchNextFormat(data); \ plFormat_Private::FormatSpec format = plFormat_Private::_FetchNextFormat(data); \
data.fOutput.push_back(_impl_plFormat_DataHandler(format, value)); \ data.fOutput.push_back(_impl_plFormat_DataHandler(format, value)); \
return _IFormat(data, args...); \ return _IFormat(data, args...); \
} \ } \
@ -133,17 +153,41 @@ namespace plFormat_Private
template <typename... _Args> \ template <typename... _Args> \
plString plFormat(const char *fmt_str, _type value, _Args... args) \ plString plFormat(const char *fmt_str, _type value, _Args... args) \
{ \ { \
plFormat_Private::IFormatDataObject data; \ plFormat_Private::_IFormatDataObject data; \
data.fFormatStr = fmt_str; \ data.fFormatStr = fmt_str; \
plFormat_Private::FormatSpec format = plFormat_Private::FetchNextFormat(data); \ plFormat_Private::FormatSpec format = plFormat_Private::_FetchNextFormat(data); \
data.fOutput.push_back(_impl_plFormat_DataHandler(format, value)); \ data.fOutput.push_back(_impl_plFormat_DataHandler(format, value)); \
return plFormat_Private::_IFormat(data, args...); \ return plFormat_Private::_IFormat(data, args...); \
} }
/** Provide the implementation for a formattable type for `plFormat`.
* \sa PL_FORMAT_TYPE(), PL_FORMAT_FORWARD()
*
* Example:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* PL_FORMAT_IMPL(const MyType &)
* {
* return plFormat("MyType[data={},count={}]", value.data, value.count);
* }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#define PL_FORMAT_IMPL(_type) \ #define PL_FORMAT_IMPL(_type) \
plStringBuffer<char> _impl_plFormat_DataHandler( \ plStringBuffer<char> _impl_plFormat_DataHandler( \
const plFormat_Private::FormatSpec &format, _type value) const plFormat_Private::FormatSpec &format, _type value)
/** Shortcut to call another `PL_FORMAT_IMPL` formatter.
* \sa PL_FORMAT_IMPL()
*
* Example:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* PL_FORMAT_IMPL(const MyType &)
* {
* return PL_FORMAT_FORWARD(format, value.ToString());
* }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#define PL_FORMAT_FORWARD(format, fwd_value) \ #define PL_FORMAT_FORWARD(format, fwd_value) \
_impl_plFormat_DataHandler((format), (fwd_value)) _impl_plFormat_DataHandler((format), (fwd_value))
@ -174,10 +218,10 @@ PL_FORMAT_TYPE(const std::wstring &)
// To use other formats, don't pass us a bool directly... // To use other formats, don't pass us a bool directly...
PL_FORMAT_TYPE(bool) PL_FORMAT_TYPE(bool)
// End of the chain -- emits the last piece (if any) and builds the final string
namespace plFormat_Private namespace plFormat_Private
{ {
plString _IFormat(IFormatDataObject &data); // End of the chain -- emits the last piece (if any) and builds the final string
plString _IFormat(_IFormatDataObject &data);
} }
#endif // plFormat_Defined #endif // plFormat_Defined

Loading…
Cancel
Save