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
# instead of the = operator.
PREDEFINED =
PREDEFINED = BUILDING_DOXYGEN
# 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.

18
Sources/Plasma/CoreLib/plFormat.cpp

@ -50,7 +50,7 @@ Mead, WA 99021
namespace plFormat_Private
{
static const char *_scanNextFormat(IFormatDataObject &data)
static const char *_scanNextFormat(_IFormatDataObject &data)
{
hsAssert(data.fFormatStr, "Passed a null format string!");
@ -64,7 +64,7 @@ namespace plFormat_Private
return ptr;
}
static void _fetchPrefixChunk(IFormatDataObject &data)
static void _fetchPrefixChunk(_IFormatDataObject &data)
{
do {
const char *next = _scanNextFormat(data);
@ -81,7 +81,7 @@ namespace plFormat_Private
} while (0);
}
FormatSpec FetchNextFormat(IFormatDataObject &data)
FormatSpec _FetchNextFormat(_IFormatDataObject &data)
{
_fetchPrefixChunk(data);
hsAssert(*data.fFormatStr == '{', "Too many actual parameters for format string");
@ -135,13 +135,13 @@ namespace plFormat_Private
spec.fDigitClass = kDigitChar;
break;
case 'f':
spec.fFloatClass = kFloatF;
break;
case 'g':
spec.fFloatClass = kFloatG;
spec.fFloatClass = kFloatFixed;
break;
case 'e':
spec.fFloatClass = kFloatE;
spec.fFloatClass = kFloatExp;
break;
case 'E':
spec.fFloatClass = kFloatExpUpper;
break;
case '0': case '1': case '2': case '3': case '4':
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);
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 <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)
* {{ - Escape for a single '{' char
* {options} - Format a value, with the specified options (see below)
* Formatting Options
* ------------------
*
* Options:
* < - Align left
* > - Align right
* NNN - Pad to NNN characters (minimum - can be more)
* + - Show a '+' char for positive signed values (decimal only)
* _C - Use C as the pad character (only '\001'..'\177' supported for now)
* x - Hex (lower-case)
* X - Hex (upper-case)
* o - Octal
* b - Binary
* 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)
* FFF.EEE - Use FFF.EEE floating point precision
* f - Use 'f' format for floating point numbers
* g - Use 'g' format for floating point numbers
* e - Use 'e' format for floating point numbers
* Format Option | Description
* ------------- | -----------
* `<` | Align left
* `>` | Align right
* `NNN` | Pad to NNN characters (minimum - can be more)
* `+` | Show a '+' char for positive signed values (decimal only)
* `_C` | Use C as the pad character (only '\001'..'\177' supported for now)
* `x` | Hex (lower-case)
* `X` | Hex (upper-case)
* `o` | Octal
* `b` | Binary
* `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)
* `FFF.EEE` | Use FFF.EEE floating point precision
* `f` | Fixed floating point format (ddd.ddd)
* `e` | Exponent notation for floating point (d.ddde[+/-]dd)
* `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
{
enum Alignment : unsigned char
{
kAlignDefault, kAlignLeft, kAlignRight
kAlignDefault, /**< Left for strings, right for numbers */
kAlignLeft, /**< Left alignment */
kAlignRight /**< Right alignment */
};
enum DigitClass : unsigned char
{
kDigitDefault, kDigitDec, kDigitDecAlwaysSigned,
kDigitHex, kDigitHexUpper, kDigitOct, kDigitBin, kDigitChar
kDigitDefault, /**< Default digit formatting */
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
{
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
{
int fPrecisionLeft = 0; // Also used for padding
int fPrecisionRight = 0;
int fPrecisionLeft = 0; /**< Requested padding and/or precision */
int fPrecisionRight = 0; /**< Requested precision after the . for floating-point */
char fPadChar = 0;
Alignment fAlignment = kAlignDefault;
DigitClass fDigitClass = kDigitDefault;
FloatClass fFloatClass = kFloatDefault;
char fPadChar = 0; /**< Explicit padding char (default is space) */
Alignment fAlignment = kAlignDefault; /**< Requested pad alignment */
DigitClass fDigitClass = kDigitDefault; /**< Requested int formatting */
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;
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
// PL_FORMAT_TYPE(mytype) in a header, and
// PL_FORMAT_IMPL(mytype) { ... } in a source file
/** Declare a formattable type for `plFormat`.
* \sa PL_FORMAT_IMPL()
*/
#define PL_FORMAT_TYPE(_type) \
extern plStringBuffer<char> _impl_plFormat_DataHandler( \
const plFormat_Private::FormatSpec &format, _type value); \
namespace plFormat_Private \
{ \
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)); \
return _IFormat(data, args...); \
} \
@ -133,17 +153,41 @@ namespace plFormat_Private
template <typename... _Args> \
plString plFormat(const char *fmt_str, _type value, _Args... args) \
{ \
plFormat_Private::IFormatDataObject data; \
plFormat_Private::_IFormatDataObject data; \
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)); \
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) \
plStringBuffer<char> _impl_plFormat_DataHandler( \
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) \
_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...
PL_FORMAT_TYPE(bool)
// End of the chain -- emits the last piece (if any) and builds the final string
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

Loading…
Cancel
Save