[pp] Add 'LinearDocument' class (#565)
author박종현/동작제어Lab(SR)/Staff Engineer/삼성전자 <jh1302.park@samsung.com>
Mon, 9 Jul 2018 08:19:50 +0000 (17:19 +0900)
committerGitHub Enterprise <noreply-CODE@samsung.com>
Mon, 9 Jul 2018 08:19:50 +0000 (17:19 +0900)
This commit adds 'LinearDocument' class which maintains a
linearly appendable document (either in forward/reverse direction).

Signed-off-by: Jonghyun Park <jh1302.park@samsung.com>
contrib/pp/include/pp/LinearDocument.h [new file with mode: 0644]
contrib/pp/src/LinearDocument.cpp [new file with mode: 0644]
contrib/pp/src/LinearDocument.test.cpp [new file with mode: 0644]

diff --git a/contrib/pp/include/pp/LinearDocument.h b/contrib/pp/include/pp/LinearDocument.h
new file mode 100644 (file)
index 0000000..1c471f6
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef __PP_LINEAR_DOCUMENT_H__
+#define __PP_LINEAR_DOCUMENT_H__
+
+#include "pp/Format.h"
+#include "pp/IndentedStringBuilder.h"
+
+#include <vector>
+#include <string>
+
+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 <typename... Args> 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<std::string> _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 (file)
index 0000000..44aace6
--- /dev/null
@@ -0,0 +1,55 @@
+#include "pp/LinearDocument.h"
+
+#include <stdexcept>
+
+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 (file)
index 0000000..f424dd9
--- /dev/null
@@ -0,0 +1,112 @@
+#include "pp/LinearDocument.h"
+
+#include <gtest/gtest.h>
+
+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");
+}