From aba9e15021a788154090cc2b96e2944f72528e89 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 13 Jan 2013 07:14:54 -0800 Subject: [PATCH] Add support for types other than int in oct, hex, hexu & pad. Document the API. --- doc/format.rst | 3 +- format.h | 109 +++++++++++++++++++++++++++++++------------------ format_test.cc | 38 ++++++++++++----- 3 files changed, 98 insertions(+), 52 deletions(-) diff --git a/doc/format.rst b/doc/format.rst index 442441a9..f01f6e0f 100644 --- a/doc/format.rst +++ b/doc/format.rst @@ -13,7 +13,8 @@ String Formatting .. doxygenclass:: format::TempFormatter :members: -.. doxygenstruct:: format::NoAction +.. doxygenclass:: format::NoAction + :members: .. doxygenclass:: format::StringRef :members: diff --git a/format.h b/format.h index e9b8e3cb..11296a93 100644 --- a/format.h +++ b/format.h @@ -117,23 +117,36 @@ void Array::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 -struct IntTraits { +struct IntTraits {}; + +template +struct SignedIntTraits { + typedef T Type; + typedef UnsignedT UnsignedType; + static bool IsNegative(T value) { return value < 0; } +}; + +template +struct UnsignedIntTraits { + typedef T Type; typedef T UnsignedType; static bool IsNegative(T) { return false; } }; template <> -struct IntTraits { - typedef unsigned UnsignedType; - static bool IsNegative(int value) { return value < 0; } -}; +struct IntTraits : SignedIntTraits {}; template <> -struct IntTraits { - typedef unsigned long UnsignedType; - static bool IsNegative(long value) { return value < 0; } -}; +struct IntTraits : UnsignedIntTraits {}; + +template <> +struct IntTraits : SignedIntTraits {}; + +template <> +struct IntTraits : UnsignedIntTraits {}; 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 > oct(int value) { - return IntFormatter >(value, TypeSpec<'o'>()); +// internal::IntTraits::Type is used instead of T to avoid instantiating +// the function for types smaller than int similarly to enable_if. +template +inline IntFormatter< + typename internal::IntTraits::Type, TypeSpec<'o'> > oct(T value) { + return IntFormatter >(value, TypeSpec<'o'>()); } -inline IntFormatter > hex(int value) { - return IntFormatter >(value, TypeSpec<'x'>()); +template +inline IntFormatter< + typename internal::IntTraits::Type, TypeSpec<'x'> > hex(T value) { + return IntFormatter >(value, TypeSpec<'x'>()); } -inline IntFormatter > hexu(int value) { - return IntFormatter >(value, TypeSpec<'X'>()); +template +inline IntFormatter< + typename internal::IntTraits::Type, TypeSpec<'X'> > hexu(T value) { + return IntFormatter >(value, TypeSpec<'X'>()); } -template -inline IntFormatter > pad( - IntFormatter > f, unsigned width, char fill = ' ') { - return IntFormatter >( +template +inline IntFormatter< + typename internal::IntTraits::Type, AlignTypeSpec > pad( + IntFormatter > f, unsigned width, char fill = ' ') { + return IntFormatter >( f.value(), AlignTypeSpec(width, fill)); } -inline IntFormatter > pad( - int value, unsigned width, char fill = ' ') { - return IntFormatter >( +template +inline IntFormatter< + typename internal::IntTraits::Type, AlignTypeSpec<0> > pad( + T value, unsigned width, char fill = ' ') { + return IntFormatter >( 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 class TempFormatter : public internal::ArgInserter { diff --git a/format_test.cc b/format_test.cc index 40e575c8..0ead31f9 100644 --- a/format_test.cc +++ b/format_test.cc @@ -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 > (*phex)(int value) = hex; + phex(42); + // This shouldn't compile: + //fmt::IntFormatter > (*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());