From 7a5461a8f4945b5eacdf24816c5c5aa415e0d058 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=EB=B0=95=EC=A2=85=ED=98=84/=EB=8F=99=EC=9E=91=EC=A0=9C?= =?utf8?q?=EC=96=B4Lab=28SR=29/Staff=20Engineer/=EC=82=BC=EC=84=B1?= =?utf8?q?=EC=A0=84=EC=9E=90?= Date: Wed, 4 Jul 2018 19:09:01 +0900 Subject: [PATCH] Introduce 'pp' library (#430) * Introduce 'pp' library This commit introduces 'pp' library which provides various helper functions and classes for pretty-printing. The current implementation provides 'fmt' function which constructs a string using operator<<, and IndentedDocumentBuilder class which makes it easy to build indented documents especially when indentation is nested. Signed-off-by: Jonghyun Park * Check _level before unindent * Use static storage quantifier * Use strict compile options * Remove unnecessary override * Do not construct temporary string objects --- contrib/pp/.FORMATCHECKED | 0 contrib/pp/CMakeLists.txt | 18 ++++++++++++ contrib/pp/include/pp/Format.h | 27 ++++++++++++++++++ contrib/pp/include/pp/IndentedDocumentBuilder.h | 37 +++++++++++++++++++++++++ contrib/pp/src/Format.test.cpp | 14 ++++++++++ contrib/pp/src/IndentedDocumentBuilder.cpp | 33 ++++++++++++++++++++++ contrib/pp/src/IndentedDocumentBuilder.test.cpp | 22 +++++++++++++++ 7 files changed, 151 insertions(+) create mode 100644 contrib/pp/.FORMATCHECKED create mode 100644 contrib/pp/CMakeLists.txt create mode 100644 contrib/pp/include/pp/Format.h create mode 100644 contrib/pp/include/pp/IndentedDocumentBuilder.h create mode 100644 contrib/pp/src/Format.test.cpp create mode 100644 contrib/pp/src/IndentedDocumentBuilder.cpp create mode 100644 contrib/pp/src/IndentedDocumentBuilder.test.cpp diff --git a/contrib/pp/.FORMATCHECKED b/contrib/pp/.FORMATCHECKED new file mode 100644 index 0000000..e69de29 diff --git a/contrib/pp/CMakeLists.txt b/contrib/pp/CMakeLists.txt new file mode 100644 index 0000000..d69717b --- /dev/null +++ b/contrib/pp/CMakeLists.txt @@ -0,0 +1,18 @@ +file(GLOB_RECURSE SOURCES "src/*.cpp") +file(GLOB_RECURSE TESTS "src/*.test.cpp") +list(REMOVE_ITEM SOURCES ${TESTS}) + +add_library(pp STATIC ${SOURCES}) +target_include_directories(pp PUBLIC include) +target_compile_options(pp PRIVATE -Werror -Wall -Wextra) + +nncc_find_package(GTest QUIET) + +if(NOT GTest_FOUND) + return() +endif(NOT GTest_FOUND) + +add_executable(pp_test ${TESTS}) +target_link_libraries(pp_test pp) +target_link_libraries(pp_test gtest_main) +add_test(pp_test pp_test) diff --git a/contrib/pp/include/pp/Format.h b/contrib/pp/include/pp/Format.h new file mode 100644 index 0000000..001a93a --- /dev/null +++ b/contrib/pp/include/pp/Format.h @@ -0,0 +1,27 @@ +#ifndef __PP_FORMAT_H__ +#define __PP_FORMAT_H__ + +#include +#include + +namespace pp +{ + +template static inline void _fmt(std::ostream &os, const Arg &arg) { os << arg; } +template +static inline void _fmt(std::ostream &os, const Arg &arg, const Args &... args) +{ + _fmt(os, arg); + _fmt(os, args...); +} + +template static inline std::string fmt(const Args &... args) +{ + std::stringstream ss; + _fmt(ss, args...); + return ss.str(); +} + +} // namespace pp + +#endif // __PP_FORMAT_H__ diff --git a/contrib/pp/include/pp/IndentedDocumentBuilder.h b/contrib/pp/include/pp/IndentedDocumentBuilder.h new file mode 100644 index 0000000..c7e7dde --- /dev/null +++ b/contrib/pp/include/pp/IndentedDocumentBuilder.h @@ -0,0 +1,37 @@ +#ifndef __PP_INDENTED_DOCUMENT_BUILDER_H__ +#define __PP_INDENTED_DOCUMENT_BUILDER_H__ + +#include "pp/Format.h" + +namespace pp +{ + +class IndentedDocumentBuilder +{ +public: + IndentedDocumentBuilder(std::ostream &os) : _os(os), _level{0} + { + // DO NOTHING + } + +public: + void indent(void); + void unindent(void); + +public: + void empty(void); + void line(const std::string &content); + +public: + template void line(const Args &... args) { line(fmt(args...)); } + +private: + std::ostream &_os; + +private: + uint32_t _level; +}; + +} // namespace pp + +#endif // __PP_INDENTED_DOCUMENT_BUILDER_H__ diff --git a/contrib/pp/src/Format.test.cpp b/contrib/pp/src/Format.test.cpp new file mode 100644 index 0000000..be10e51 --- /dev/null +++ b/contrib/pp/src/Format.test.cpp @@ -0,0 +1,14 @@ +#include "pp/Format.h" + +#include + +TEST(FORMAT, simple_string) +{ + ASSERT_EQ(pp::fmt("Hello"), "Hello"); + ASSERT_EQ(pp::fmt("Hello ", 2), "Hello 2"); + ASSERT_EQ(pp::fmt("Hello ", 2 + 2), "Hello 4"); +} + +TEST(FORMAT, simple_number) { ASSERT_EQ(pp::fmt(2), "2"); } +TEST(FORMAT, concat_lvalue) { ASSERT_EQ(pp::fmt("Hello ", 2), "Hello 2"); } +TEST(FORMAT, concat_rvalue) { ASSERT_EQ(pp::fmt("Hello ", 2 + 2), "Hello 4"); } diff --git a/contrib/pp/src/IndentedDocumentBuilder.cpp b/contrib/pp/src/IndentedDocumentBuilder.cpp new file mode 100644 index 0000000..fe68bd8 --- /dev/null +++ b/contrib/pp/src/IndentedDocumentBuilder.cpp @@ -0,0 +1,33 @@ +#include "pp/IndentedDocumentBuilder.h" + +#include +#include + +namespace pp +{ + +void IndentedDocumentBuilder::indent(void) +{ + // TODO Check overflow + ++_level; +} + +void IndentedDocumentBuilder::unindent(void) +{ + assert(_level > 0); + --_level; +} + +void IndentedDocumentBuilder::empty(void) { _os << std::endl; } + +void IndentedDocumentBuilder::line(const std::string &content) +{ + assert(std::find(content.begin(), content.end(), '\n') == content.end()); + + const char c = ' '; + const size_t n = 2 * _level; + + _os << std::string(n, c) << content << std::endl; +} + +} // namespace pp diff --git a/contrib/pp/src/IndentedDocumentBuilder.test.cpp b/contrib/pp/src/IndentedDocumentBuilder.test.cpp new file mode 100644 index 0000000..f0eccf3 --- /dev/null +++ b/contrib/pp/src/IndentedDocumentBuilder.test.cpp @@ -0,0 +1,22 @@ +#include "pp/IndentedDocumentBuilder.h" + +#include + +TEST(INDENTED_DOCUMENT_BUILDER, usage) +{ + const char *expected = "A\n" + " B\n" + "C\n"; + + std::stringstream ss; + + pp::IndentedDocumentBuilder doc{ss}; + + doc.line("A"); + doc.indent(); + doc.line("B"); + doc.unindent(); + doc.line("C"); + + ASSERT_EQ(ss.str(), expected); +} -- 2.7.4