Add support for types other than int in oct, hex, hexu & pad. Document the API.
This commit is contained in:
parent
d53cc2bc12
commit
aba9e15021
@ -13,7 +13,8 @@ String Formatting
|
||||
.. doxygenclass:: format::TempFormatter
|
||||
:members:
|
||||
|
||||
.. doxygenstruct:: format::NoAction
|
||||
.. doxygenclass:: format::NoAction
|
||||
:members:
|
||||
|
||||
.. doxygenclass:: format::StringRef
|
||||
:members:
|
||||
|
109
format.h
109
format.h
@ -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 {
|
||||
|
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user