]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Add TextTable class
authorJoel Rosdahl <joel@rosdahl.net>
Fri, 23 Jul 2021 11:52:21 +0000 (13:52 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Sat, 24 Jul 2021 06:17:03 +0000 (08:17 +0200)
src/util/CMakeLists.txt
src/util/TextTable.cpp [new file with mode: 0644]
src/util/TextTable.hpp [new file with mode: 0644]
unittest/CMakeLists.txt
unittest/test_util_TextTable.cpp [new file with mode: 0644]

index 6912ad654b78e72c6041f95e4dd908cb3c0f5a67..48e96ae629fa5b3077e229b5842a626d002639d0 100644 (file)
@@ -1,5 +1,6 @@
 set(
   sources
+  ${CMAKE_CURRENT_SOURCE_DIR}/TextTable.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/Tokenizer.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/file.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/path.cpp
diff --git a/src/util/TextTable.cpp b/src/util/TextTable.cpp
new file mode 100644 (file)
index 0000000..809b1f8
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright (C) 2021 Joel Rosdahl and other contributors
+//
+// See doc/AUTHORS.adoc for a complete list of contributors.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "TextTable.hpp"
+
+#include <third_party/fmt/core.h>
+
+#include <algorithm>
+
+namespace util {
+
+void
+TextTable::add_heading(const std::string& text)
+{
+  Cell cell(text);
+  cell.m_heading = true;
+  m_rows.push_back({cell});
+}
+
+void
+TextTable::add_row(const std::initializer_list<Cell> cells)
+{
+  m_rows.emplace_back(cells);
+}
+
+std::string
+TextTable::render() const
+{
+  std::vector<size_t> column_widths;
+
+  for (const auto& row : m_rows) {
+    column_widths.resize(std::max(column_widths.size(), row.size()));
+    for (size_t i = 0; i < row.size(); ++i) {
+      if (!row[i].m_heading) {
+        column_widths[i] = std::max(column_widths[i], row[i].m_text.size());
+      }
+    }
+  }
+
+  std::string result;
+  for (const auto& row : m_rows) {
+    std::string r;
+    for (size_t i = 0; i < row.size(); ++i) {
+      if (i > 0) {
+        r += ' ';
+      }
+      r += fmt::format((row[i].m_right_align ? "{:>{}}" : "{:<{}}"),
+                       row[i].m_text,
+                       column_widths[i]);
+    }
+    result.append(r, 0, r.find_last_not_of(' ') + 1);
+    result += '\n';
+  }
+  return result;
+}
+
+TextTable::Cell::Cell(const std::string& text) : m_text(text)
+{
+}
+
+TextTable::Cell&
+TextTable::Cell::right_align()
+{
+  m_right_align = true;
+  return *this;
+}
+
+} // namespace util
diff --git a/src/util/TextTable.hpp b/src/util/TextTable.hpp
new file mode 100644 (file)
index 0000000..a6d1940
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright (C) 2021 Joel Rosdahl and other contributors
+//
+// See doc/AUTHORS.adoc for a complete list of contributors.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#pragma once
+
+#include <initializer_list>
+#include <string>
+#include <vector>
+
+namespace util {
+
+class TextTable
+{
+public:
+  class Cell
+  {
+  public:
+    Cell(const std::string& text);
+
+    Cell& right_align();
+
+  private:
+    friend TextTable;
+
+    const std::string m_text;
+    bool m_right_align = false;
+    bool m_heading = false;
+  };
+
+  void add_heading(const std::string& text);
+  void add_row(std::initializer_list<Cell> cells);
+  std::string render() const;
+
+private:
+  std::vector<std::vector<Cell>> m_rows;
+};
+
+} // namespace util
index 6c2b3d2cc2d5b892d8a1b303ed0a2b06cd8c6744..d30902084a6f9bec4f78d1647d925a23fbea6b61 100644 (file)
@@ -24,6 +24,7 @@ set(
   test_hashutil.cpp
   test_storage_primary_StatsFile.cpp
   test_storage_primary_util.cpp
+  test_util_TextTable.cpp
   test_util_Tokenizer.cpp
   test_util_expected.cpp
   test_util_path.cpp
diff --git a/unittest/test_util_TextTable.cpp b/unittest/test_util_TextTable.cpp
new file mode 100644 (file)
index 0000000..1435095
--- /dev/null
@@ -0,0 +1,86 @@
+// Copyright (C) 2021 Joel Rosdahl and other contributors
+//
+// See doc/AUTHORS.adoc for a complete list of contributors.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <util/TextTable.hpp>
+
+#include <third_party/doctest.h>
+
+#include <iostream> // macOS bug: https://github.com/onqtam/doctest/issues/126
+
+TEST_CASE("TextTable")
+{
+  using C = util::TextTable::Cell;
+
+  util::TextTable table;
+
+  SUBCASE("empty")
+  {
+    CHECK(table.render() == "");
+  }
+
+  SUBCASE("1x1")
+  {
+    table.add_row({{"a"}});
+    CHECK(table.render() == "a\n");
+  }
+
+  SUBCASE("2x1 with space prefix/suffix")
+  {
+    table.add_row({{" a "}, C(" b ")});
+    CHECK(table.render() == " a   b\n");
+  }
+
+  SUBCASE("1x2")
+  {
+    table.add_row({{"a"}});
+    table.add_row({{"b"}});
+    CHECK(table.render() == "a\nb\n");
+  }
+
+  SUBCASE("3 + 2")
+  {
+    table.add_row({{"a"}, {"b"}, {"c"}});
+    table.add_row({{"aa"}, {"bbb"}});
+    CHECK(table.render()
+          == ("a  b   c\n"
+              "aa bbb\n"));
+  }
+
+  SUBCASE("right align")
+  {
+    table.add_row({{"a"}, {"bbb"}, {"cc"}});
+    table.add_row(
+      {C("aa").right_align(), C("b").right_align(), C("ccc").right_align()});
+    table.add_row({{"aaa"}, {"bb"}, {"c"}});
+    CHECK(table.render()
+          == ("a   bbb cc\n"
+              " aa   b ccc\n"
+              "aaa bb  c\n"));
+  }
+
+  SUBCASE("heading")
+  {
+    table.add_row({{"a"}, {"b"}, {"c"}});
+    table.add_heading("DDDDDD");
+    table.add_row({{"aaa"}, {"bbb"}, {"ccc"}});
+    CHECK(table.render()
+          == ("a   b   c\n"
+              "DDDDDD\n"
+              "aaa bbb ccc\n"));
+  }
+}