From b29defcbfdc25588fae13271d5b3c403c4a6608b 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: Mon, 9 Jul 2018 17:19:50 +0900 Subject: [PATCH] [pp] Add 'LinearDocument' class (#565) This commit adds 'LinearDocument' class which maintains a linearly appendable document (either in forward/reverse direction). Signed-off-by: Jonghyun Park --- contrib/pp/include/pp/LinearDocument.h | 62 ++++++++++++++++++ contrib/pp/src/LinearDocument.cpp | 55 ++++++++++++++++ contrib/pp/src/LinearDocument.test.cpp | 112 +++++++++++++++++++++++++++++++++ 3 files changed, 229 insertions(+) create mode 100644 contrib/pp/include/pp/LinearDocument.h create mode 100644 contrib/pp/src/LinearDocument.cpp create mode 100644 contrib/pp/src/LinearDocument.test.cpp diff --git a/contrib/pp/include/pp/LinearDocument.h b/contrib/pp/include/pp/LinearDocument.h new file mode 100644 index 0000000..1c471f6 --- /dev/null +++ b/contrib/pp/include/pp/LinearDocument.h @@ -0,0 +1,62 @@ +#ifndef __PP_LINEAR_DOCUMENT_H__ +#define __PP_LINEAR_DOCUMENT_H__ + +#include "pp/Format.h" +#include "pp/IndentedStringBuilder.h" + +#include +#include + +namespace pp +{ + +class LinearDocument +{ +public: + enum class Direction + { + Forward, + Reverse + }; + +public: + LinearDocument() : _direction{Direction::Forward} + { + // DO NOTHING + } + +public: + LinearDocument(const Direction &direction) : _direction{direction} + { + // DO NOTHING + } + +public: + void indent(void); + void unindent(void); + +public: + void append(void); + +public: + void append(const std::string &line); + template void append(const Args &... args) { append(fmt(args...)); } + +public: + void append(const LinearDocument &doc); + +public: + uint32_t lines(void) const { return _lines.size(); } + +public: + const std::string &line(uint32_t n) const; + +private: + Direction const _direction; + IndentedStringBuilder _indent; + std::vector _lines; +}; + +} // namespace pp + +#endif // __PP_LINEAR_DOCUMENT_H__ diff --git a/contrib/pp/src/LinearDocument.cpp b/contrib/pp/src/LinearDocument.cpp new file mode 100644 index 0000000..44aace6 --- /dev/null +++ b/contrib/pp/src/LinearDocument.cpp @@ -0,0 +1,55 @@ +#include "pp/LinearDocument.h" + +#include + +namespace pp +{ + +void LinearDocument::indent(void) { _indent.increase(); } +void LinearDocument::unindent(void) { _indent.decrease(); } + +void LinearDocument::append(void) +{ + // NOTE Do NOT indent empty lines + _lines.emplace_back(""); +} + +void LinearDocument::append(const std::string &line) +{ + if (line.empty()) + { + append(); + return; + } + + // Append indentation space(s), and insert the update string to lines + _lines.emplace_back(_indent.build(line)); +} + +void LinearDocument::append(const LinearDocument &doc) +{ + for (uint32_t n = 0; n < doc.lines(); ++n) + { + // NOTE Do NOT update _lines here and use append method + append(doc.line(n)); + } +} + +const std::string &LinearDocument::line(uint32_t n) const +{ + switch (_direction) + { + case Direction::Forward: + { + return _lines.at(n); + } + case Direction::Reverse: + { + return _lines.at(lines() - n - 1); + } + } + + throw std::runtime_error{"unreachable"}; +} + +} // namespace pp diff --git a/contrib/pp/src/LinearDocument.test.cpp b/contrib/pp/src/LinearDocument.test.cpp new file mode 100644 index 0000000..f424dd9 --- /dev/null +++ b/contrib/pp/src/LinearDocument.test.cpp @@ -0,0 +1,112 @@ +#include "pp/LinearDocument.h" + +#include + +TEST(LINEAR_DOCUMENT, append_void) +{ + pp::LinearDocument doc; + + doc.indent(); + doc.append(); + + ASSERT_EQ(doc.lines(), 1); + ASSERT_EQ(doc.line(0), ""); +} + +TEST(LINEAR_DOCUMENT, append_empty_string) +{ + pp::LinearDocument doc; + + doc.indent(); + doc.append(""); + + ASSERT_EQ(doc.lines(), 1); + ASSERT_EQ(doc.line(0), ""); +} + +TEST(LINEAR_DOCUMENT, formatted_append) +{ + pp::LinearDocument doc; + + doc.append("Hello ", 1); + ASSERT_EQ(doc.lines(), 1); + ASSERT_EQ(doc.line(0), "Hello 1"); +} + +TEST(LINEAR_DOCUMENT, forward_append) +{ + pp::LinearDocument doc; + + ASSERT_EQ(doc.lines(), 0); + + doc.append("A"); + doc.append("B"); + doc.append("C"); + + ASSERT_EQ(doc.lines(), 3); + ASSERT_EQ(doc.line(0), "A"); + ASSERT_EQ(doc.line(1), "B"); + ASSERT_EQ(doc.line(2), "C"); +} + +TEST(LINEAR_DOCUMENT, reverse_append) +{ + pp::LinearDocument doc{pp::LinearDocument::Direction::Reverse}; + + ASSERT_EQ(doc.lines(), 0); + + doc.append("A"); + doc.append("B"); + doc.append("C"); + + ASSERT_EQ(doc.lines(), 3); + ASSERT_EQ(doc.line(0), "C"); + ASSERT_EQ(doc.line(1), "B"); + ASSERT_EQ(doc.line(2), "A"); +} + +TEST(LINEAR_DOCUMENT, document_append) +{ + pp::LinearDocument doc{pp::LinearDocument::Direction::Forward}; + pp::LinearDocument sub{pp::LinearDocument::Direction::Reverse}; + + doc.append("A"); + doc.indent(); + + sub.append("D"); + sub.indent(); + sub.append("C"); + sub.unindent(); + sub.append("B"); + + doc.append(sub); + doc.unindent(); + doc.append("E"); + + ASSERT_EQ(doc.lines(), 5); + + ASSERT_EQ(doc.line(0), "A"); + ASSERT_EQ(doc.line(1), " B"); + ASSERT_EQ(doc.line(2), " C"); + ASSERT_EQ(doc.line(3), " D"); + ASSERT_EQ(doc.line(4), "E"); +} + +TEST(LINEAR_DOCUMENT, indent) +{ + pp::LinearDocument doc; + + ASSERT_EQ(doc.lines(), 0); + + doc.append("A"); + doc.indent(); + doc.append("B"); + doc.unindent(); + doc.append("C"); + + ASSERT_EQ(doc.lines(), 3); + + ASSERT_EQ(doc.line(0), "A"); + ASSERT_EQ(doc.line(1), " B"); + ASSERT_EQ(doc.line(2), "C"); +} -- 2.7.4