diff --git a/doc/api.rst b/doc/api.rst index 54895190..b9a46bea 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -203,6 +203,9 @@ store output elsewhere by subclassing `~fmt::BasicWriter`. .. doxygenclass:: fmt::BasicStringWriter :members: +.. doxygenclass:: fmt::BasicContainerWriter + :members: + .. doxygenfunction:: bin(int) .. doxygenfunction:: oct(int) diff --git a/doc/build.py b/doc/build.py index ec045f74..55992b9f 100755 --- a/doc/build.py +++ b/doc/build.py @@ -72,7 +72,8 @@ def build_docs(version='dev', **kwargs): GENERATE_MAN = NO GENERATE_RTF = NO CASE_SENSE_NAMES = NO - INPUT = {0}/format.h {0}/ostream.h {0}/printf.h {0}/string.h + INPUT = {0}/container.h {0}/format.h {0}/ostream.h \ + {0}/printf.h {0}/string.h QUIET = YES JAVADOC_AUTOBRIEF = YES AUTOLINK_SUPPORT = NO diff --git a/fmt/CMakeLists.txt b/fmt/CMakeLists.txt index a57bfcdd..29e881b3 100644 --- a/fmt/CMakeLists.txt +++ b/fmt/CMakeLists.txt @@ -1,7 +1,7 @@ # Define the fmt library, its includes and the needed defines. # *.cc are added to FMT_HEADERS for the header-only configuration. -set(FMT_HEADERS format.h format.cc ostream.h ostream.cc printf.h printf.cc - string.h time.h) +set(FMT_HEADERS container.h format.h format.cc ostream.h ostream.cc printf.h + printf.cc string.h time.h) if (HAVE_OPEN) set(FMT_HEADERS ${FMT_HEADERS} posix.h) set(FMT_SOURCES ${FMT_SOURCES} posix.cc) diff --git a/fmt/container.h b/fmt/container.h new file mode 100644 index 00000000..cb6303fb --- /dev/null +++ b/fmt/container.h @@ -0,0 +1,82 @@ +/* + Formatting library for C++ - standard container utilities + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + For the license information refer to format.h. + */ + +#ifndef FMT_CONTAINER_H_ +#define FMT_CONTAINER_H_ + +#include "format.h" + +namespace fmt { + +namespace internal { + +/** + \rst + A "buffer" that appends data to a standard container (e.g. typically a + ``std::vector`` or ``std::basic_string``). + \endrst + */ +template +class ContainerBuffer : public Buffer { + private: + Container& container_; + + protected: + virtual void grow(std::size_t size) FMT_OVERRIDE { + container_.resize(size); + this->ptr_ = &container_[0]; + this->capacity_ = size; + } + + public: + explicit ContainerBuffer(Container& container) : container_(container) { + this->size_ = container_.size(); + if (this->size_ > 0) { + this->ptr_ = &container_[0]; + this->capacity_ = this->size_; + } + } +}; +} // namespace internal + +/** + \rst + This class template provides operations for formatting and appending data + to a standard *container* like ``std::vector`` or ``std::basic_string``. + + **Example**:: + + void vecformat(std::vector& dest, fmt::BasicCStringRef format, + fmt::ArgList args) { + fmt::BasicContainerWriter > appender(dest); + appender.write(format, args); + } + FMT_VARIADIC(void, vecformat, std::vector&, + fmt::BasicCStringRef); + \endrst + */ +template +class BasicContainerWriter + : public BasicWriter { + private: + internal::ContainerBuffer buffer_; + + public: + /** + \rst + Constructs a :class:`fmt::BasicContainerWriter` object. + \endrst + */ + explicit BasicContainerWriter(Container& dest) + : BasicWriter(buffer_), buffer_(dest) {} +}; + +} // namespace fmt + +#endif // FMT_CONTAINER_H_ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b805955e..31a418de 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -80,6 +80,7 @@ function(add_fmt_test name) endfunction() add_fmt_test(assert-test) +add_fmt_test(container-test) add_fmt_test(gtest-extra-test) add_fmt_test(format-test) add_fmt_test(format-impl-test) @@ -139,7 +140,7 @@ if (FMT_PEDANTIC) "${CMAKE_CURRENT_BINARY_DIR}/compile-test" --build-generator ${CMAKE_GENERATOR} --build-makeprogram ${CMAKE_MAKE_PROGRAM} - --build-options + --build-options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" "-DCPP11_FLAG=${CPP11_FLAG}" "-DSUPPORTS_USER_DEFINED_LITERALS=${SUPPORTS_USER_DEFINED_LITERALS}") diff --git a/test/container-test.cc b/test/container-test.cc new file mode 100644 index 00000000..8cafb3d0 --- /dev/null +++ b/test/container-test.cc @@ -0,0 +1,94 @@ +/* + Tests of container utilities + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + For the license information refer to format.h. + */ + +#include "fmt/container.h" +#include "gtest/gtest.h" + +using fmt::internal::ContainerBuffer; + +TEST(ContainerBufferTest, Empty) { + std::string data; + ContainerBuffer buffer(data); + EXPECT_EQ(0u, buffer.size()); + EXPECT_EQ(0u, buffer.capacity()); +} + +TEST(ContainerBufferTest, Reserve) { + std::string data; + ContainerBuffer buffer(data); + std::size_t capacity = std::string().capacity() + 10; + buffer.reserve(capacity); + EXPECT_EQ(0u, buffer.size()); + EXPECT_EQ(capacity, buffer.capacity()); +} + +TEST(ContainerBufferTest, Resize) { + std::string data; + ContainerBuffer buffer(data); + std::size_t size = std::string().capacity() + 10; + buffer.resize(size); + EXPECT_EQ(size, buffer.size()); + EXPECT_EQ(size, buffer.capacity()); +} + +TEST(ContainerBufferTest, Append) { + std::string data("Why so"); + const std::string serious(" serious"); + ContainerBuffer buffer(data); + buffer.append(serious.c_str(), serious.c_str() + serious.length()); + EXPECT_EQ("Why so serious", data); + EXPECT_EQ(data.length(), buffer.size()); +} + +TEST(BasicContainerWriterTest, String) { + std::string data; + fmt::BasicContainerWriter out(data); + out << "The answer is " << 42 << "\n"; + EXPECT_EQ("The answer is 42\n", data); + EXPECT_EQ(17u, out.size()); +} + +TEST(BasicContainerWriterTest, WString) { + std::wstring data; + fmt::BasicContainerWriter out(data); + out << "The answer is " << 42 << "\n"; + EXPECT_EQ(L"The answer is 42\n", data); + EXPECT_EQ(17u, out.size()); +} + +TEST(BasicContainerWriterTest, Vector) { + std::vector data; + fmt::BasicContainerWriter > out(data); + out << "The answer is " << 42 << "\n"; + EXPECT_EQ(17u, data.size()); + EXPECT_EQ(out.size(), data.size()); +} + +TEST(BasicContainerWriterTest, StringAppend) { + std::string data("The"); + fmt::BasicContainerWriter out(data); + EXPECT_EQ(3u, data.size()); + EXPECT_EQ(3u, out.size()); + out << " answer is " << 42 << "\n"; + EXPECT_EQ("The answer is 42\n", data); + EXPECT_EQ(17u, out.size()); +} + +TEST(BasicContainerWriterTest, VectorAppend) { + std::vector data; + data.push_back('T'); + data.push_back('h'); + data.push_back('e'); + fmt::BasicContainerWriter > out(data); + EXPECT_EQ(3u, data.size()); + EXPECT_EQ(3u, out.size()); + out << " answer is " << 42 << "\n"; + EXPECT_EQ(17u, data.size()); + EXPECT_EQ(17u, out.size()); +}