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
|
.. doxygenclass:: format::TempFormatter
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. doxygenstruct:: format::NoAction
|
.. doxygenclass:: format::NoAction
|
||||||
|
:members:
|
||||||
|
|
||||||
.. doxygenclass:: format::StringRef
|
.. doxygenclass:: format::StringRef
|
||||||
:members:
|
: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.
|
// Information about an integer type.
|
||||||
|
// IntTraits is not specialized for integer types smaller than int,
|
||||||
|
// since these are promoted to int.
|
||||||
template <typename T>
|
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;
|
typedef T UnsignedType;
|
||||||
static bool IsNegative(T) { return false; }
|
static bool IsNegative(T) { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct IntTraits<int> {
|
struct IntTraits<int> : SignedIntTraits<int, unsigned> {};
|
||||||
typedef unsigned UnsignedType;
|
|
||||||
static bool IsNegative(int value) { return value < 0; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct IntTraits<long> {
|
struct IntTraits<unsigned> : UnsignedIntTraits<unsigned> {};
|
||||||
typedef unsigned long UnsignedType;
|
|
||||||
static bool IsNegative(long value) { return value < 0; }
|
template <>
|
||||||
};
|
struct IntTraits<long> : SignedIntTraits<long, unsigned long> {};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct IntTraits<unsigned long> : UnsignedIntTraits<unsigned long> {};
|
||||||
|
|
||||||
class ArgInserter;
|
class ArgInserter;
|
||||||
}
|
}
|
||||||
@ -157,13 +170,31 @@ class StringRef {
|
|||||||
mutable std::size_t size_;
|
mutable std::size_t size_;
|
||||||
|
|
||||||
public:
|
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) {}
|
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()) {}
|
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()); }
|
operator std::string() const { return std::string(data_, size()); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the pointer to a C string.
|
||||||
|
*/
|
||||||
const char *c_str() const { return data_; }
|
const char *c_str() const { return data_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the string size.
|
||||||
|
*/
|
||||||
std::size_t size() const {
|
std::size_t size() const {
|
||||||
if (size_ == 0) size_ = std::strlen(data_);
|
if (size_ == 0) size_ = std::strlen(data_);
|
||||||
return size_;
|
return size_;
|
||||||
@ -256,28 +287,39 @@ class IntFormatter : public SpecT {
|
|||||||
T value() const { return value_; }
|
T value() const { return value_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
inline IntFormatter<int, TypeSpec<'o'> > oct(int value) {
|
// internal::IntTraits<T>::Type is used instead of T to avoid instantiating
|
||||||
return IntFormatter<int, TypeSpec<'o'> >(value, TypeSpec<'o'>());
|
// 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) {
|
template <typename T>
|
||||||
return IntFormatter<int, TypeSpec<'x'> >(value, TypeSpec<'x'>());
|
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) {
|
template <typename T>
|
||||||
return IntFormatter<int, TypeSpec<'X'> >(value, TypeSpec<'X'>());
|
inline IntFormatter<
|
||||||
|
typename internal::IntTraits<T>::Type, TypeSpec<'X'> > hexu(T value) {
|
||||||
|
return IntFormatter<T, TypeSpec<'X'> >(value, TypeSpec<'X'>());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <char TYPE>
|
template <typename T, char TYPE>
|
||||||
inline IntFormatter<int, AlignTypeSpec<TYPE> > pad(
|
inline IntFormatter<
|
||||||
IntFormatter<int, TypeSpec<TYPE> > f, unsigned width, char fill = ' ') {
|
typename internal::IntTraits<T>::Type, AlignTypeSpec<TYPE> > pad(
|
||||||
return IntFormatter<int, AlignTypeSpec<TYPE> >(
|
IntFormatter<T, TypeSpec<TYPE> > f, unsigned width, char fill = ' ') {
|
||||||
|
return IntFormatter<T, AlignTypeSpec<TYPE> >(
|
||||||
f.value(), AlignTypeSpec<TYPE>(width, fill));
|
f.value(), AlignTypeSpec<TYPE>(width, fill));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline IntFormatter<int, AlignTypeSpec<0> > pad(
|
template <typename T>
|
||||||
int value, unsigned width, char fill = ' ') {
|
inline IntFormatter<
|
||||||
return IntFormatter<int, AlignTypeSpec<0> >(
|
typename internal::IntTraits<T>::Type, AlignTypeSpec<0> > pad(
|
||||||
|
T value, unsigned width, char fill = ' ') {
|
||||||
|
return IntFormatter<T, AlignTypeSpec<0> >(
|
||||||
value, AlignTypeSpec<0>(width, fill));
|
value, AlignTypeSpec<0>(width, fill));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,25 +378,19 @@ class BasicFormatter {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
\rst
|
|
||||||
Returns the number of characters written to the output buffer.
|
Returns the number of characters written to the output buffer.
|
||||||
\endrst
|
|
||||||
*/
|
*/
|
||||||
std::size_t size() const { return buffer_.size(); }
|
std::size_t size() const { return buffer_.size(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
|
||||||
Returns a pointer to the output buffer content. No terminating null
|
Returns a pointer to the output buffer content. No terminating null
|
||||||
character is appended.
|
character is appended.
|
||||||
\endrst
|
|
||||||
*/
|
*/
|
||||||
const char *data() const { return &buffer_[0]; }
|
const char *data() const { return &buffer_[0]; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
|
||||||
Returns a pointer to the output buffer content with terminating null
|
Returns a pointer to the output buffer content with terminating null
|
||||||
character appended.
|
character appended.
|
||||||
\endrst
|
|
||||||
*/
|
*/
|
||||||
const char *c_str() const {
|
const char *c_str() const {
|
||||||
std::size_t size = buffer_.size();
|
std::size_t size = buffer_.size();
|
||||||
@ -364,9 +400,7 @@ class BasicFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
Returns the content of the output buffer as an `std::string`.
|
||||||
Returns the content of the output buffer as an ``std::string``.
|
|
||||||
\endrst
|
|
||||||
*/
|
*/
|
||||||
std::string str() const { return std::string(&buffer_[0], buffer_.size()); }
|
std::string str() const { return std::string(&buffer_[0], buffer_.size()); }
|
||||||
|
|
||||||
@ -628,18 +662,14 @@ class Formatter : public BasicFormatter {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
\rst
|
|
||||||
Constructs a formatter with an empty output buffer.
|
Constructs a formatter with an empty output buffer.
|
||||||
\endrst
|
|
||||||
*/
|
*/
|
||||||
Formatter() : format_(0) {}
|
Formatter() : format_(0) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
|
||||||
Formats a string appending the output to the internal buffer.
|
Formats a string appending the output to the internal buffer.
|
||||||
Arguments are accepted through the returned ``ArgInserter`` object
|
Arguments are accepted through the returned `ArgInserter` object
|
||||||
using inserter operator ``<<``.
|
using inserter operator `<<`.
|
||||||
\endrst
|
|
||||||
*/
|
*/
|
||||||
internal::ArgInserter operator()(StringRef format);
|
internal::ArgInserter operator()(StringRef format);
|
||||||
};
|
};
|
||||||
@ -764,17 +794,16 @@ inline internal::ArgInserter Formatter::operator()(StringRef format) {
|
|||||||
/**
|
/**
|
||||||
A formatting action that does nothing.
|
A formatting action that does nothing.
|
||||||
*/
|
*/
|
||||||
struct NoAction {
|
class NoAction {
|
||||||
|
public:
|
||||||
/** Does nothing. */
|
/** Does nothing. */
|
||||||
void operator()(const Formatter &) const {}
|
void operator()(const Formatter &) const {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
|
||||||
A formatter with an action performed when formatting is complete.
|
A formatter with an action performed when formatting is complete.
|
||||||
Objects of this class normally exist only as temporaries returned
|
Objects of this class normally exist only as temporaries returned
|
||||||
by one of the formatting functions which explains the name.
|
by one of the formatting functions which explains the name.
|
||||||
\endrst
|
|
||||||
*/
|
*/
|
||||||
template <typename Action = NoAction>
|
template <typename Action = NoAction>
|
||||||
class TempFormatter : public internal::ArgInserter {
|
class TempFormatter : public internal::ArgInserter {
|
||||||
|
@ -1065,21 +1065,29 @@ TEST(TempFormatterTest, Examples) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(StrTest, oct) {
|
TEST(StrTest, oct) {
|
||||||
BasicFormatter f;
|
EXPECT_EQ("12", (BasicFormatter() << oct(012)).str());
|
||||||
f << oct(042);
|
EXPECT_EQ("34", (BasicFormatter() << oct(034)).str());
|
||||||
EXPECT_EQ("42", f.str());
|
EXPECT_EQ("56", (BasicFormatter() << oct(056)).str());
|
||||||
|
EXPECT_EQ("70", (BasicFormatter() << oct(070)).str());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(StrTest, hex) {
|
TEST(StrTest, hex) {
|
||||||
BasicFormatter f;
|
fmt::IntFormatter<int, fmt::TypeSpec<'x'> > (*phex)(int value) = hex;
|
||||||
f << hex(0xbeef);
|
phex(42);
|
||||||
EXPECT_EQ("beef", f.str());
|
// 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) {
|
TEST(StrTest, hexu) {
|
||||||
BasicFormatter f;
|
EXPECT_EQ("CAFE", (BasicFormatter() << hexu(0xcafe)).str());
|
||||||
f << hexu(0xbabe);
|
EXPECT_EQ("BABE", (BasicFormatter() << hexu(0xbabeu)).str());
|
||||||
EXPECT_EQ("BABE", f.str());
|
EXPECT_EQ("DEAD", (BasicFormatter() << hexu(0xdeadl)).str());
|
||||||
|
EXPECT_EQ("BEEF", (BasicFormatter() << hexu(0xbeeful)).str());
|
||||||
}
|
}
|
||||||
|
|
||||||
class ISO8601DateFormatter {
|
class ISO8601DateFormatter {
|
||||||
@ -1098,9 +1106,17 @@ public:
|
|||||||
ISO8601DateFormatter iso8601(const Date &d) { return ISO8601DateFormatter(d); }
|
ISO8601DateFormatter iso8601(const Date &d) { return ISO8601DateFormatter(d); }
|
||||||
|
|
||||||
TEST(StrTest, pad) {
|
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;
|
BasicFormatter f;
|
||||||
f << pad(hex(0xbeef), 8);
|
|
||||||
EXPECT_EQ(" beef", f.str());
|
|
||||||
f.Clear();
|
f.Clear();
|
||||||
f << pad(42, 5, '0');
|
f << pad(42, 5, '0');
|
||||||
EXPECT_EQ("00042", f.str());
|
EXPECT_EQ("00042", f.str());
|
||||||
|
Loading…
Reference in New Issue
Block a user