c++17: Refactor table with generic lambda
authorSangwan Kwon <sangwan.kwon@samsung.com>
Thu, 23 Jan 2020 10:09:29 +0000 (19:09 +0900)
committerSangwan Kwon <sangwan.kwon@samsung.com>
Thu, 30 Jan 2020 04:14:41 +0000 (13:14 +0900)
Signed-off-by: Sangwan Kwon <sangwan.kwon@samsung.com>
Move ColumnPack to Table

Signed-off-by: Sangwan Kwon <sangwan.kwon@samsung.com>
src/vist/query-builder/column.hpp
src/vist/query-builder/database.hpp
src/vist/query-builder/table-pack.hpp
src/vist/query-builder/table.hpp
src/vist/query-builder/tests/columns.cpp [deleted file]
src/vist/query-builder/tests/table.cpp [new file with mode: 0644]

index 70b1c75c955b11358daf88a7639002b1f8a98e1a..aeabdf19debb507a7f471872c5b1d9d53333c4ef 100644 (file)
@@ -26,7 +26,7 @@ template<typename Object, typename Field>
 struct Column final {
        using Type = Field Object::*;
        using FieldType = Field;
-       using TableType = Object;
+       using Table = Object;
 
        Column(const std::string& name, Field Object::*field) : name(name), type(field)
        {
index ef6189bf94564f1fd50c688554d0f6ad47f1fb60..9cfa109e46b8a6e9ba6799d5021959a9095d1056 100644 (file)
@@ -85,7 +85,7 @@ private:
                void operator()(T&& type)
                {
                        auto column = make_column("anonymous", type);
-                       using TableType = typename decltype(column)::TableType;
+                       using TableType = typename decltype(column)::Table;
                        auto name = this->tablePack.getName(TableType());
                        if (!name.empty())
                                names.emplace(name);
index eeda955f2bf403fdc68bc643f2445b736f3ee7e4..d76b309df4c94153d60ec794f0e8cf3115eaf605 100644 (file)
 
 #pragma once
 
-#include <vector>
+#include "tuple-helper.hpp"
+
 #include <set>
 #include <string>
+#include <tuple>
+#include <vector>
 
 namespace vist {
 namespace tsqb {
 namespace internal {
 
-template<typename... Base>
-class TablePack {
+template<typename... Tables>
+class TablePack final {
 public:
-       virtual ~TablePack() = default;
+       using TupleType = std::tuple<Tables...>;
 
-       template<typename TableType>
-       std::string getName(TableType&&) const noexcept { return std::string(); }
-
-       template<typename ColumnType>
-       std::string getColumnName(ColumnType&&) const noexcept { return std::string(); }
-};
-
-template<typename Front, typename... Rest>
-class TablePack<Front, Rest...> : public TablePack<Rest...> {
-public:
-       using Table = Front;
-
-       explicit TablePack(Front&& front, Rest&& ...rest);
-       virtual ~TablePack() = default;
+       explicit TablePack(Tables ...tables) : tables(tables...)
+       {
+       }
 
-       TablePack(const TablePack&) = delete;
-       TablePack& operator=(const TablePack&) = delete;
+       template<typename TableType>
+       std::string getName(TableType&& table) const noexcept
+       {
+               std::string name;
+               auto predicate = [&name, &table](const auto& iter) {
+                       if (iter.compare(table))
+                               name = iter.name;
+               };
 
-       TablePack(TablePack&&) = default;
-       TablePack& operator=(TablePack&&) = default;
+               tuple_helper::for_each(this->tables, predicate);
 
-       template<typename TableType>
-       std::string getName(TableType&& table) const noexcept;
+               return name;
+       }
 
        template<typename ColumnType>
-       std::string getColumnName(ColumnType&& column) const noexcept;
+       std::string getColumnName(ColumnType&& column) const noexcept
+       {
+               using TableType = typename ColumnType::Table;
+
+               std::string name;
+               TableType table;
+               auto predicate = [&name, &table, column](const auto& iter) {
+                       if (iter.compare(table)) {
+                               auto cname = iter.getColumnName(column.type);
+                               name = iter.name + "." + cname;
+                       }
+               };
+
+               tuple_helper::for_each(this->tables, predicate);
+
+               return name;
+       }
 
 private:
-       using Base = TablePack<Rest...>;
-
-       Table table;
+       std::tuple<Tables...> tables;
 };
 
-template<typename Front, typename... Rest>
-TablePack<Front, Rest...>::TablePack(Front&& front, Rest&& ...rest) :
-       Base(std::forward<Rest>(rest)...), table(front)
-{
-}
-
-template<typename Front, typename... Rest>
-template<typename TableType>
-std::string TablePack<Front, Rest...>::getName(TableType&& table) const noexcept
-{
-       if (this->table.compare(table))
-               return this->table.name;
-
-       return Base::template getName<TableType>(std::forward<TableType>(table));
-}
-
-template<typename Front, typename... Rest>
-template<typename ColumnType>
-std::string TablePack<Front, Rest...>::getColumnName(ColumnType&& column) const noexcept
-{
-       using DecayColumnType = typename std::decay<ColumnType>::type;
-       using DecayTableType = typename DecayColumnType::TableType;
-       if (this->table.compare(DecayTableType())) {
-               auto cname = this->table.getColumnName(column.type);
-               return this->table.name + "." + cname;
-       }
-
-       return Base::template getColumnName<ColumnType>(std::forward<ColumnType>(column));
-}
-
 } // namespace internal
 } // namespace tsqb
 } // namespace vist
index fe7e208adc2a21637c7710fa657eabf7855225f0..3ec559d76b630f079ea3f738c3b1b92cb8c22276 100644 (file)
 
 #pragma once
 
-#include "crud.hpp"
 #include "column.hpp"
-#include "column-pack.hpp"
+#include "crud.hpp"
 #include "tuple-helper.hpp"
+#include "type.hpp"
 #include "util.hpp"
 
-#include <vector>
-#include <string>
 #include <sstream>
+#include <string>
+#include <tuple>
+#include <vector>
 
 namespace vist {
 namespace tsqb {
@@ -32,73 +33,54 @@ namespace tsqb {
 template<typename... Columns>
 class Table : public Crud<Table<Columns...>> {
 public:
-       virtual ~Table() = default;
+       /// Make first stuct type to table type
+       using Type = typename std::tuple_element<0, std::tuple<Columns...>>::type::Table;
 
-       Table(const Table&) = delete;
-       Table& operator=(const Table&) = delete;
-
-       Table(Table&&) = default;
-       Table& operator=(Table&&) = default;
-
-       // Functions for Crud
-       template<typename Cs>
-       std::set<std::string> getTableNames(Cs&& tuple) const noexcept;
-       template<typename Cs>
-       std::vector<std::string> getColumnNames(Cs&& tuple) const noexcept;
-       template<typename That>
-       std::string getTableName(That&& type) const noexcept;
-       template<typename ColumnType>
-       std::string getColumnName(ColumnType&& type) const noexcept;
+       explicit Table(const std::string& name, Columns&& ...columns) :
+               name(name), columns(columns...) {}
 
+       std::string getName(void) const noexcept;
        std::vector<std::string> getColumnNames(void) const noexcept;
 
        template<typename That>
        bool compare(const That& that) const noexcept;
 
-       int size() const noexcept;
+       std::size_t size() const noexcept;
 
        operator std::string();
 
-       std::string name;
-       std::vector<std::string> cache;
+       const std::string name;
 
-private:
-       using ColumnPackType = internal::ColumnPack<Columns...>;
-       using TableType = typename ColumnPackType::TableType;
+public: // CRTP(Curiously Recurring Template Pattern) for CRUD
+       template<typename Cs>
+       std::set<std::string> getTableNames(Cs&& tuple) const noexcept;
+       template<typename That>
+       std::string getTableName(That&& type) const noexcept;
+       template<typename Cs>
+       std::vector<std::string> getColumnNames(Cs&& tuple) const noexcept;
+       template<typename Column>
+       std::string getColumnName(const Column& column) const noexcept;
 
-       explicit Table(const std::string& name, ColumnPackType&& columnPack);
+       std::vector<std::string> cache;
 
+private:
        template<typename ...Cs>
        friend Table<Cs...> make_table(const std::string& name, Cs&& ...columns);
 
-       struct GetColumnNames {
-               const ColumnPackType& columnPack;
-               std::vector<std::string> names;
-
-               GetColumnNames(const ColumnPackType& columnPack) : columnPack(columnPack) {}
-
-               template <typename T>
-               void operator()(T&& type)
-               {
-                       auto name = this->columnPack.getName(std::forward<T>(type));
-                       if (!name.empty())
-                               names.emplace_back(name);
-               }
-       };
-
-       ColumnPackType columnPack;
+       std::tuple<Columns...> columns;
 };
 
 template<typename ...Columns>
 Table<Columns...> make_table(const std::string& name, Columns&& ...cs)
 {
-       auto columnPack = internal::ColumnPack<Columns...>(std::forward<Columns>(cs)...);
-       return Table<Columns...>(name, std::move(columnPack));
+       return Table<Columns...>(name, std::forward<Columns>(cs)...);
 }
 
 template<typename... Columns>
-Table<Columns...>::Table(const std::string& name, ColumnPackType&& columnPack)
-       : name(name), columnPack(std::move(columnPack)) {}
+std::string Table<Columns...>::getName() const noexcept
+{
+       return this->name;
+}
 
 template<typename... Columns>
 template<typename Cs>
@@ -111,37 +93,58 @@ template<typename... Columns>
 template<typename Cs>
 std::vector<std::string> Table<Columns...>::getColumnNames(Cs&& tuple) const noexcept
 {
-       GetColumnNames closure(this->columnPack);
+       std::vector<std::string> names;
+       auto closure = [this, &names](auto type) {
+               auto name = this->getColumnName(type);
+               if (!name.empty())
+                       names.emplace_back(name);
+       };
+
        tuple_helper::for_each(std::forward<Cs>(tuple), closure);
 
-       return closure.names;
+       return names;
 }
 
 template<typename... Columns>
 template<typename That>
-std::string Table<Columns...>::getTableName(That&& type) const noexcept
+std::string Table<Columns...>::getTableName(That&&) const noexcept
 {
        return this->name;
 }
 
 template<typename... Columns>
-template<typename ColumnType>
-std::string Table<Columns...>::getColumnName(ColumnType&& type) const noexcept
+std::vector<std::string> Table<Columns...>::getColumnNames(void) const noexcept
 {
-       return this->columnPack.getName(std::forward<ColumnType>(type));
+       std::vector<std::string> names;
+       auto closure = [&names](const auto& iter) {
+               names.push_back(iter.name);
+       };
+
+       tuple_helper::for_each(this->columns, closure);
+
+       return names;
 }
 
 template<typename... Columns>
-std::vector<std::string> Table<Columns...>::getColumnNames(void) const noexcept
+template<typename Column>
+std::string Table<Columns...>::getColumnName(const Column& column) const noexcept
 {
-       return this->columnPack.getNames();
+       std::string name;
+       auto predicate = [&name, &column](const auto& iter) {
+               if (type::cast_compare(column, iter.type)) 
+                       name = iter.name;
+       };
+
+       tuple_helper::for_each(this->columns, predicate);
+
+       return name;
 }
 
 template<typename... Columns>
 template<typename That>
 bool Table<Columns...>::compare(const That& that) const noexcept
 {
-       using This = TableType;
+       using This = Type;
        return type::compare(This(), that);
 }
 
@@ -157,9 +160,10 @@ Table<Columns...>::operator std::string()
 }
 
 template<typename... Columns>
-int Table<Columns...>::size() const noexcept
+std::size_t Table<Columns...>::size() const noexcept
 {
-       return this->columnPack.size();
+       using TupleType = std::tuple<Columns...>;
+       return std::tuple_size<TupleType>::value;
 }
 
 } // namespace tsqb
diff --git a/src/vist/query-builder/tests/columns.cpp b/src/vist/query-builder/tests/columns.cpp
deleted file mode 100644 (file)
index 23ddc4e..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- *  Copyright (c) 2020-present Samsung Electronics Co., Ltd All Rights Reserved
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License
- */
-
-#include <gtest/gtest.h>
-
-#include <vist/query-builder/column-pack.hpp>
-#include <vist/query-builder/column.hpp>
-
-using namespace vist::tsqb;
-using namespace vist::tsqb::internal;
-
-namespace {
-
-struct Sample {
-       int int1;
-       int int2;
-       std::string str1;
-       std::string str2;
-       bool bool1;
-       bool bool2;
-};
-
-ColumnPack columns { Column("int1", &Sample::int1),
-                                        Column("int2", &Sample::int2),
-                                        Column("str1", &Sample::str1),
-                                        Column("str2", &Sample::str2),
-                                        Column("bool1", &Sample::bool1),
-                                        Column("bool2", &Sample::bool2) };
-}
-
-TEST(ColumnTests, size)
-{
-       EXPECT_EQ(columns.size(), 6);
-}
-
-TEST(ColumnTests, get_name)
-{
-       EXPECT_EQ(columns.getName(&Sample::int1), "int1");
-       EXPECT_EQ(columns.getName(&Sample::int2), "int2");
-       EXPECT_EQ(columns.getName(&Sample::str1), "str1");
-       EXPECT_EQ(columns.getName(&Sample::str2), "str2");
-       EXPECT_EQ(columns.getName(&Sample::bool1), "bool1");
-       EXPECT_EQ(columns.getName(&Sample::bool2), "bool2");
-}
-
-TEST(ColumnTests, get_names)
-{
-       EXPECT_EQ(columns.getNames().size(), 6);
-}
diff --git a/src/vist/query-builder/tests/table.cpp b/src/vist/query-builder/tests/table.cpp
new file mode 100644 (file)
index 0000000..dda8ca9
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *  Copyright (c) 2020-present Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+#include <gtest/gtest.h>
+
+#include <vist/query-builder/column.hpp>
+#include <vist/query-builder/table-pack.hpp>
+#include <vist/query-builder/table.hpp>
+
+using namespace vist::tsqb;
+using namespace vist::tsqb::internal;
+
+namespace {
+
+struct Table1 {
+       int column1;
+       std::string column2;
+       bool column3;
+};
+
+struct Table2 {
+       int column1;
+       std::string column2;
+       bool column3;
+       float column4;
+       double column5;
+};
+
+Table table1 { "table1", Column("column1", &Table1::column1),
+                                                Column("column2", &Table1::column2),
+                                                Column("column3", &Table1::column3) };
+
+Table table2 { "table2", Column("column1", &Table2::column1),
+                                                Column("column2", &Table2::column2),
+                                                Column("column3", &Table2::column3),
+                                                Column("column4", &Table2::column4),
+                                                Column("column5", &Table2::column5) };
+
+TablePack tables { table1, table2 };
+
+} // anonymous namespace
+
+TEST(TableTests, size)
+{
+       EXPECT_EQ(table1.size(), 3);
+       EXPECT_EQ(table2.size(), 5);
+}
+
+TEST(TableTests, get_name)
+{
+       EXPECT_EQ(table1.getName(), "table1");
+       EXPECT_EQ(table2.name, "table2");
+
+       EXPECT_EQ(table1.getColumnName(&Table1::column1), "column1");
+       EXPECT_EQ(table1.getColumnName(&Table1::column2), "column2");
+       EXPECT_EQ(table1.getColumnName(&Table1::column3), "column3");
+
+       EXPECT_EQ(table2.getColumnName(&Table2::column1), "column1");
+       EXPECT_EQ(table2.getColumnName(&Table2::column2), "column2");
+       EXPECT_EQ(table2.getColumnName(&Table2::column3), "column3");
+       EXPECT_EQ(table2.getColumnName(&Table2::column4), "column4");
+       EXPECT_EQ(table2.getColumnName(&Table2::column5), "column5");
+}
+
+TEST(TableTests, get_names)
+{
+       EXPECT_EQ(table1.getColumnNames().size(), 3);
+       EXPECT_EQ(table2.getColumnNames().size(), 5);
+}
+
+TEST(TableTests, compare)
+{
+       EXPECT_TRUE(table1.compare(Table1()));
+}
+
+TEST(TableTests, pack_get_column)
+{
+       EXPECT_EQ(tables.getColumnName(Column("anonymous", &Table1::column1)), "table1.column1");
+       EXPECT_EQ(tables.getColumnName(Column("anonymous", &Table1::column2)), "table1.column2");
+       EXPECT_EQ(tables.getColumnName(Column("anonymous", &Table1::column3)), "table1.column3");
+}