Add support for types other than int in oct, hex, hexu & pad. Document the API.

This commit is contained in:
Victor Zverovich 2013-01-13 07:14:54 -08:00
parent d53cc2bc12
commit aba9e15021
3 changed files with 98 additions and 52 deletions

View File

@ -13,7 +13,8 @@ String Formatting
.. doxygenclass:: format::TempFormatter
:members:
.. doxygenstruct:: format::NoAction
.. doxygenclass:: format::NoAction
:members:
.. doxygenclass:: format::StringRef
:members:

109
format.h
View File

@ -117,23 +117,36 @@ void Array<T, SIZE>::append(const T *begin, const T *end) {
}
// Information about an integer type.
// IntTraits is not specialized for integer types smaller than int,
// since these are promoted to int.
template <typename T>
struct IntTraits {
struct IntTraits {};
template <typename T, typename UnsignedT>
struct SignedIntTraits {
typedef T Type;
typedef UnsignedT UnsignedType;
static bool IsNegative(T value) { return value < 0; }
};
template <typename T>
struct UnsignedIntTraits {
typedef T Type;
typedef T UnsignedType;
static bool IsNegative(T) { return false; }
};
template <>
struct IntTraits<int> {
typedef unsigned UnsignedType;
static bool IsNegative(int value) { return value < 0; }
};
struct IntTraits<int> : SignedIntTraits<int, unsigned> {};
template <>
struct IntTraits<long> {
typedef unsigned long UnsignedType;
static bool IsNegative(long value) { return value < 0; }
};
struct IntTraits<unsigned> : UnsignedIntTraits<unsigned> {};
template <>
struct IntTraits<long> : SignedIntTraits<long, unsigned long> {};
template <>
struct IntTraits<unsigned long> : UnsignedIntTraits<unsigned long> {};
class ArgInserter;
}
@ -157,13 +170,31 @@ class StringRef {
mutable std::size_t size_;
public:
/**
Constructs a string reference object from a C string and a size.
If `size` is zero, which is the default, the size is computed with
`strlen`.
*/
StringRef(const char *s, std::size_t size = 0) : data_(s), size_(size) {}
/**
Constructs a string reference from an `std::string` object.
*/
StringRef(const std::string &s) : data_(s.c_str()), size_(s.size()) {}
/**
Converts a string reference to an `std::string` object.
*/
operator std::string() const { return std::string(data_, size()); }
/**
Returns the pointer to a C string.
*/
const char *c_str() const { return data_; }
/**
Returns the string size.
*/
std::size_t size() const {
if (size_ == 0) size_ = std::strlen(data_);
return size_;
@ -256,28 +287,39 @@ class IntFormatter : public SpecT {
T value() const { return value_; }
};
inline IntFormatter<int, TypeSpec<'o'> > oct(int value) {
return IntFormatter<int, TypeSpec<'o'> >(value, TypeSpec<'o'>());
// internal::IntTraits<T>::Type is used instead of T to avoid instantiating
// the function for types smaller than int similarly to enable_if.
template <typename T>
inline IntFormatter<
typename internal::IntTraits<T>::Type, TypeSpec<'o'> > oct(T value) {
return IntFormatter<T, TypeSpec<'o'> >(value, TypeSpec<'o'>());
}
inline IntFormatter<int, TypeSpec<'x'> > hex(int value) {
return IntFormatter<int, TypeSpec<'x'> >(value, TypeSpec<'x'>());
template <typename T>
inline IntFormatter<
typename internal::IntTraits<T>::Type, TypeSpec<'x'> > hex(T value) {
return IntFormatter<T, TypeSpec<'x'> >(value, TypeSpec<'x'>());
}
inline IntFormatter<int, TypeSpec<'X'> > hexu(int value) {
return IntFormatter<int, TypeSpec<'X'> >(value, TypeSpec<'X'>());
template <typename T>
inline IntFormatter<
typename internal::IntTraits<T>::Type, TypeSpec<'X'> > hexu(T value) {
return IntFormatter<T, TypeSpec<'X'> >(value, TypeSpec<'X'>());
}
template <char TYPE>
inline IntFormatter<int, AlignTypeSpec<TYPE> > pad(
IntFormatter<int, TypeSpec<TYPE> > f, unsigned width, char fill = ' ') {
return IntFormatter<int, AlignTypeSpec<TYPE> >(
template <typename T, char TYPE>
inline IntFormatter<
typename internal::IntTraits<T>::Type, AlignTypeSpec<TYPE> > pad(
IntFormatter<T, TypeSpec<TYPE> > f, unsigned width, char fill = ' ') {
return IntFormatter<T, AlignTypeSpec<TYPE> >(
f.value(), AlignTypeSpec<TYPE>(width, fill));
}
inline IntFormatter<int, AlignTypeSpec<0> > pad(
int value, unsigned width, char fill = ' ') {
return IntFormatter<int, AlignTypeSpec<0> >(
template <typename T>
inline IntFormatter<
typename internal::IntTraits<T>::Type, AlignTypeSpec<0> > pad(
T value, unsigned width, char fill = ' ') {
return IntFormatter<T, AlignTypeSpec<0> >(
value, AlignTypeSpec<0>(width, fill));
}
@ -336,25 +378,19 @@ class BasicFormatter {
public:
/**
\rst
Returns the number of characters written to the output buffer.
\endrst
*/
std::size_t size() const { return buffer_.size(); }
/**
\rst
Returns a pointer to the output buffer content. No terminating null
character is appended.
\endrst
*/
const char *data() const { return &buffer_[0]; }
/**
\rst
Returns a pointer to the output buffer content with terminating null
character appended.
\endrst
*/
const char *c_str() const {
std::size_t size = buffer_.size();
@ -364,9 +400,7 @@ class BasicFormatter {
}
/**
\rst
Returns the content of the output buffer as an ``std::string``.
\endrst
Returns the content of the output buffer as an `std::string`.
*/
std::string str() const { return std::string(&buffer_[0], buffer_.size()); }
@ -628,18 +662,14 @@ class Formatter : public BasicFormatter {
public:
/**
\rst
Constructs a formatter with an empty output buffer.
\endrst
*/
Formatter() : format_(0) {}
/**
\rst
Formats a string appending the output to the internal buffer.
Arguments are accepted through the returned ``ArgInserter`` object
using inserter operator ``<<``.
\endrst
Arguments are accepted through the returned `ArgInserter` object
using inserter operator `<<`.
*/
internal::ArgInserter operator()(StringRef format);
};
@ -764,17 +794,16 @@ inline internal::ArgInserter Formatter::operator()(StringRef format) {
/**
A formatting action that does nothing.
*/
struct NoAction {
class NoAction {
public:
/** Does nothing. */
void operator()(const Formatter &) const {}
};
/**
\rst
A formatter with an action performed when formatting is complete.
Objects of this class normally exist only as temporaries returned
by one of the formatting functions which explains the name.
\endrst
*/
template <typename Action = NoAction>
class TempFormatter : public internal::ArgInserter {

View File

@ -1065,21 +1065,29 @@ TEST(TempFormatterTest, Examples) {
}
TEST(StrTest, oct) {
BasicFormatter f;
f << oct(042);
EXPECT_EQ("42", f.str());
EXPECT_EQ("12", (BasicFormatter() << oct(012)).str());
EXPECT_EQ("34", (BasicFormatter() << oct(034)).str());
EXPECT_EQ("56", (BasicFormatter() << oct(056)).str());
EXPECT_EQ("70", (BasicFormatter() << oct(070)).str());
}
TEST(StrTest, hex) {
BasicFormatter f;
f << hex(0xbeef);
EXPECT_EQ("beef", f.str());
fmt::IntFormatter<int, fmt::TypeSpec<'x'> > (*phex)(int value) = hex;
phex(42);
// This shouldn't compile:
//fmt::IntFormatter<short, fmt::TypeSpec<'x'> > (*phex2)(short value) = hex;
EXPECT_EQ("cafe", (BasicFormatter() << hex(0xcafe)).str());
EXPECT_EQ("babe", (BasicFormatter() << hex(0xbabeu)).str());
EXPECT_EQ("dead", (BasicFormatter() << hex(0xdeadl)).str());
EXPECT_EQ("beef", (BasicFormatter() << hex(0xbeeful)).str());
}
TEST(StrTest, hexu) {
BasicFormatter f;
f << hexu(0xbabe);
EXPECT_EQ("BABE", f.str());
EXPECT_EQ("CAFE", (BasicFormatter() << hexu(0xcafe)).str());
EXPECT_EQ("BABE", (BasicFormatter() << hexu(0xbabeu)).str());
EXPECT_EQ("DEAD", (BasicFormatter() << hexu(0xdeadl)).str());
EXPECT_EQ("BEEF", (BasicFormatter() << hexu(0xbeeful)).str());
}
class ISO8601DateFormatter {
@ -1098,9 +1106,17 @@ public:
ISO8601DateFormatter iso8601(const Date &d) { return ISO8601DateFormatter(d); }
TEST(StrTest, pad) {
EXPECT_EQ(" cafe", (BasicFormatter() << pad(hex(0xcafe), 8)).str());
EXPECT_EQ(" babe", (BasicFormatter() << pad(hex(0xbabeu), 8)).str());
EXPECT_EQ(" dead", (BasicFormatter() << pad(hex(0xdeadl), 8)).str());
EXPECT_EQ(" beef", (BasicFormatter() << pad(hex(0xbeeful), 8)).str());
EXPECT_EQ(" 11", (BasicFormatter() << pad(11, 7)).str());
EXPECT_EQ(" 22", (BasicFormatter() << pad(22u, 7)).str());
EXPECT_EQ(" 33", (BasicFormatter() << pad(33l, 7)).str());
EXPECT_EQ(" 44", (BasicFormatter() << pad(44lu, 7)).str());
BasicFormatter f;
f << pad(hex(0xbeef), 8);
EXPECT_EQ(" beef", f.str());
f.Clear();
f << pad(42, 5, '0');
EXPECT_EQ("00042", f.str());