From 57dbd2c3fe0dede9082b955fe99a56ab08cc9da8 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Tue, 11 Dec 2012 12:23:52 -0800 Subject: [PATCH] Rename Buffer to Array and test it. --- format.cc | 3 +- format.h | 45 ++++++++++++++------------ format_test.cc | 88 +++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 113 insertions(+), 23 deletions(-) diff --git a/format.cc b/format.cc index c39090a3..1e1feda7 100644 --- a/format.cc +++ b/format.cc @@ -223,8 +223,9 @@ void fmt::Formatter::FormatDouble( } } -void fmt::Formatter::Format() { +void fmt::Formatter::DoFormat() { const char *start = format_; + format_ = 0; const char *s = start; while (*s) { char c = *s++; diff --git a/format.h b/format.h index 49bee56f..d4b67b4e 100644 --- a/format.h +++ b/format.h @@ -15,9 +15,10 @@ namespace format { -// A buffer with the first SIZE elements stored in the object itself. +// A simple array for POD types with the first SIZE elements stored in +// the object itself. It supports a subset of std::vector's operations. template -class Buffer { +class Array { private: std::size_t size_; std::size_t capacity_; @@ -27,22 +28,22 @@ class Buffer { void Grow(std::size_t size); // Do not implement! - Buffer(const Buffer &); - void operator=(const Buffer &); + Array(const Array &); + void operator=(const Array &); public: - Buffer() : size_(0), capacity_(SIZE), ptr_(data_) {} - ~Buffer() { + Array() : size_(0), capacity_(SIZE), ptr_(data_) {} + ~Array() { if (ptr_ != data_) delete [] ptr_; } - // Returns the size of this buffer. + // Returns the size of this array. std::size_t size() const { return size_; } - // Returns the capacity of this buffer. + // Returns the capacity of this array. std::size_t capacity() const { return capacity_; } - // Resizes the buffer. If T is a POD type new elements are not initialized. + // Resizes the array. If T is a POD type new elements are not initialized. void resize(std::size_t new_size) { if (new_size > capacity_) Grow(new_size); @@ -62,7 +63,7 @@ class Buffer { ptr_[size_++] = value; } - // Appends data to the end of the buffer. + // Appends data to the end of the array. void append(const T *begin, const T *end); T &operator[](std::size_t index) { return ptr_[index]; } @@ -70,7 +71,7 @@ class Buffer { }; template -void Buffer::Grow(std::size_t size) { +void Array::Grow(std::size_t size) { capacity_ = std::max(size, capacity_ + capacity_ / 2); T *p = new T[capacity_]; std::copy(ptr_, ptr_ + size_, p); @@ -80,7 +81,7 @@ void Buffer::Grow(std::size_t size) { } template -void Buffer::append(const T *begin, const T *end) { +void Array::append(const T *begin, const T *end) { std::ptrdiff_t num_elements = end - begin; if (size_ + num_elements > capacity_) Grow(num_elements); @@ -112,7 +113,7 @@ class BasicArgFormatter; class Formatter { private: enum { INLINE_BUFFER_SIZE = 500 }; - Buffer buffer_; // Output buffer. + Array buffer_; // Output buffer. enum Type { // Numeric types should go first. @@ -160,7 +161,7 @@ class Formatter { FormatFunc format; }; }; - mutable Formatter **formatter; + mutable Formatter *formatter; Arg(int value) : type(INT), int_value(value) {} Arg(unsigned value) : type(UINT), uint_value(value) {} @@ -193,15 +194,12 @@ class Formatter { // so it will be alive in the Arg's destructor when Format is called. // Note that the string object will not necessarily be alive when // the destructor of BasicArgFormatter is called. - if (*formatter) { - (*formatter)->Format(); - *formatter = 0; - } + formatter->Format(); } }; enum { NUM_INLINE_ARGS = 10 }; - Buffer args_; // Format arguments. + Array args_; // Format arguments. const char *format_; // Format string. @@ -224,7 +222,12 @@ class Formatter { template void FormatCustomArg(const void *arg, int width); - void Format(); + void DoFormat(); + + void Format() { + if (!format_) return; + DoFormat(); + } // Grows the buffer by n characters and returns a pointer to the newly // allocated area. @@ -284,7 +287,7 @@ class BasicArgFormatter { ~BasicArgFormatter(); BasicArgFormatter &operator<<(const Formatter::Arg &arg) { - arg.formatter = &formatter_; + arg.formatter = formatter_; formatter_->Add(arg); return *this; } diff --git a/format_test.cc b/format_test.cc index d36ab42d..d510edbf 100644 --- a/format_test.cc +++ b/format_test.cc @@ -66,6 +66,82 @@ class TestString { } }; +TEST(ArrayTest, Ctor) { + fmt::Array array; + EXPECT_EQ(0, array.size()); + EXPECT_EQ(123, array.capacity()); +} + +TEST(ArrayTest, Access) { + fmt::Array array; + array[0] = 11; + EXPECT_EQ(11, array[0]); + array[3] = 42; + EXPECT_EQ(42, *(&array[0] + 3)); + const fmt::Array &carray = array; + EXPECT_EQ(42, carray[3]); +} + +TEST(ArrayTest, Resize) { + fmt::Array array; + array[10] = 42; + EXPECT_EQ(42, array[10]); + array.resize(20); + EXPECT_EQ(20, array.size()); + EXPECT_EQ(123, array.capacity()); + EXPECT_EQ(42, array[10]); + array.resize(5); + EXPECT_EQ(5, array.size()); + EXPECT_EQ(123, array.capacity()); + EXPECT_EQ(42, array[10]); +} + +TEST(ArrayTest, Grow) { + fmt::Array array; + array.resize(10); + for (int i = 0; i < 10; ++i) + array[i] = i * i; + array.resize(20); + EXPECT_EQ(20, array.size()); + EXPECT_EQ(20, array.capacity()); + for (int i = 0; i < 10; ++i) + EXPECT_EQ(i * i, array[i]); +} + +TEST(ArrayTest, Clear) { + fmt::Array array; + array.resize(20); + array.clear(); + EXPECT_EQ(0, array.size()); + EXPECT_EQ(20, array.capacity()); +} + +TEST(ArrayTest, PushBack) { + fmt::Array array; + array.push_back(11); + EXPECT_EQ(11, array[0]); + EXPECT_EQ(1, array.size()); + array.resize(10); + array.push_back(22); + EXPECT_EQ(22, array[10]); + EXPECT_EQ(11, array.size()); + EXPECT_EQ(15, array.capacity()); +} + +TEST(ArrayTest, Append) { + fmt::Array array; + const char *test = "test"; + array.append(test, test + 5); + EXPECT_STREQ("test", &array[0]); + EXPECT_EQ(5, array.size()); + array.resize(10); + array.append(test, test + 2); + EXPECT_EQ('t', array[10]); + EXPECT_EQ('e', array[11]); + EXPECT_EQ(12, array.size()); + EXPECT_EQ(15, array.capacity()); +} + TEST(FormatterTest, Escape) { EXPECT_EQ("{", str(Format("{{"))); EXPECT_EQ("before {", str(Format("before {{"))); @@ -446,6 +522,16 @@ TEST(FormatterTest, FormatStringFromSpeedTest) { << reinterpret_cast(1000) << 'X')); } +TEST(FormatterTest, ArgLifetime) { + // The following code is for testing purposes only. It is a definite abuse + // of the API and shouldn't be used in real applications. + const fmt::BasicArgFormatter &af = fmt::Format("{0}"); + const_cast(af) << std::string("test"); + // String object passed as an argument to Print has been destroyed, + // but BasicArgFormatter dtor hasn't been called yet. + EXPECT_EQ("test", str(af)); +} + TEST(FormatterTest, Formatter) { Formatter format; format("Current point:\n"); @@ -453,4 +539,4 @@ TEST(FormatterTest, Formatter) { EXPECT_STREQ("Current point:\n(-3.140000, +3.140000)\n", format.c_str()); } -// TODO: test Buffer +// TODO: test API