├── external └── CMakeLists.txt ├── ttable ├── lib │ └── ttable.cpp ├── CMakeLists.txt └── include │ └── ttable │ ├── simd.h │ └── ttable.h ├── benchmark ├── CMakeLists.txt └── benchmark.cpp ├── tests ├── CMakeLists.txt └── ttableTest.cpp ├── .gitignore ├── CMakeLists.txt ├── README.md └── .clang-format /external/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(benchmark) 2 | -------------------------------------------------------------------------------- /ttable/lib/ttable.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by ewan on 3/15/22. 3 | // 4 | -------------------------------------------------------------------------------- /benchmark/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(ttable_benchmark benchmark.cpp) 2 | target_link_libraries(ttable_benchmark 3 | TTable 4 | benchmark 5 | ) 6 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | enable_testing() 2 | 3 | add_executable( 4 | TTableTest 5 | ttableTest.cpp 6 | ) 7 | target_link_libraries( 8 | TTableTest 9 | TTable 10 | gtest_main 11 | ) 12 | 13 | include(GoogleTest) 14 | gtest_discover_tests(TTableTest) 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /ttable/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set (HEADER_LIST 2 | include/ttable/ttable.h 3 | include/ttable/simd.h 4 | ) 5 | 6 | add_library( 7 | TTable 8 | STATIC 9 | lib/ttable.cpp 10 | ${HEADER_LIST} 11 | ) 12 | target_link_libraries(TTable ${Boost_LIBRARIES}) 13 | 14 | include_directories(${Boost_INCLUDE_DIRS}) 15 | 16 | target_include_directories(TTable INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") 17 | -------------------------------------------------------------------------------- /ttable/include/ttable/simd.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by ewan on 4/16/22. 3 | // 4 | 5 | #ifndef TTABLE_SIMD_H 6 | #define TTABLE_SIMD_H 7 | 8 | #include 9 | 10 | namespace TTable::SIMD 11 | { 12 | void add(int *result, const int *a, const int *b, size_t size) 13 | { 14 | //#pragma omp parallel for shared(a, b, c) private(i) schedule(static, 512) 15 | for (std::size_t i = 0; i < size; ++i) 16 | { 17 | result[i] = a[i] + b[i]; 18 | } 19 | } 20 | } // namespace TTable::SIMD 21 | 22 | #endif // TTABLE_SIMD_H 23 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | project(TTable VERSION 1.0) 4 | 5 | set(CMAKE_CXX_STANDARD 20) 6 | set(CMAKE_CXX_STANDARD_REQUIRED True) 7 | 8 | include(FetchContent) 9 | FetchContent_Declare( 10 | googletest 11 | URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip 12 | ) 13 | # For Windows: Prevent overriding the parent project's compiler/linker settings 14 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 15 | FetchContent_MakeAvailable(googletest) 16 | 17 | set(Boost_USE_STATIC_LIBS OFF) 18 | set(Boost_USE_MULTITHREADED ON) 19 | set(Boost_USE_STATIC_RUNTIME OFF) 20 | find_package(Boost 1.76.0) 21 | 22 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") 23 | 24 | #add_executable(progname file1.cxx file2.cxx) 25 | if(Boost_FOUND) 26 | else() 27 | MESSAGE(FATAL_ERROR "cannot find boost") 28 | endif() 29 | 30 | add_subdirectory(ttable) 31 | add_subdirectory(tests) 32 | add_subdirectory(external) 33 | add_subdirectory(benchmark) 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TTable 2 | 100% Compile time typed dataframe like tables. 3 | 4 | ## What is this? 5 | When accesing columns in a table-like structure we have two options. Create 6 | a generic `unordered_map>` approach or a struct of type listed below. 7 | ```c++ 8 | struct Table { 9 | std::vector id; 10 | std::vector name; 11 | } 12 | ``` 13 | Both are problematic. 14 | 15 | The first introduces the problem of attempting to get a column which doesn't 16 | exist resulting in undefined behaviour. 17 | The second introduces the problem of cluttering the namespace with many tables 18 | of different types. 19 | 20 | TTable attempts to allow users to create tables on the fly and typing checking 21 | all inserts and columns. If a column is added midway through the code the column will only exist there and will be unaccessable before. 22 | 23 | ## How to use 24 | 25 | ### Create a table schema 26 | ```c++ 27 | // Create all column types 28 | using id_col = TTable::column<"id", int>; 29 | using name_col = TTable::column<"name", std::string>; 30 | // Create table with columns 31 | auto table = TTable::create_table(); 32 | ``` 33 | 34 | ### Insert into table 35 | 36 | ```c++ 37 | TTable::push_back(table, 5, "test"); 38 | ``` 39 | 40 | ### Fetch first row 41 | ```c++ 42 | auto row = TTable::get_row(table, 0); 43 | auto id = TTable::get_col_from_row<"id">(row); 44 | auto name = TTable::get_col_from_row<"name">(row); 45 | std::cout << "id: " << id << " name: " << name << std::endl; 46 | ``` 47 | 48 | ### Insert new column 49 | 50 | ```c++ 51 | using IdCol = TTable::Column<"id", int>; 52 | auto table = TTable::create_table(); 53 | // Currently, unable to access age column 54 | using AgeCol = TTable::Column<"age", int>; 55 | auto newTable = TTable::add_column(table); 56 | // Now age column has been added to the type 57 | ``` 58 | 59 | ## Importing with CMake 60 | ```commandline 61 | git clone git@github.com:ewan15/TTable.git 62 | ``` 63 | ```cmake 64 | add_subdirectory(TTable) 65 | target_link_libraries( 66 | 67 | TTable 68 | ) 69 | ``` 70 | 71 | ### Note 72 | 73 | More examples in tests. 74 | -------------------------------------------------------------------------------- /benchmark/benchmark.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static void BM_SinglePushBack(benchmark::State &state) 5 | { 6 | for (auto _ : state) 7 | { 8 | using col = TTable::Column<"id", int>; 9 | using col2 = TTable::Column<"name", std::string>; 10 | auto table = TTable::create_table(); 11 | 12 | TTable::push_back(table, 5, "test"); 13 | } 14 | } 15 | // Register the function as a benchmark 16 | BENCHMARK(BM_SinglePushBack); 17 | 18 | #define ELEMENTS_PUSH_BACK 1000 19 | static void BM_MultiPushBack(benchmark::State &state) 20 | { 21 | for (auto _ : state) 22 | { 23 | using col = TTable::Column<"id", int>; 24 | using col2 = TTable::Column<"name", std::string>; 25 | auto table = TTable::create_table(); 26 | 27 | for (auto i = 0; i < ELEMENTS_PUSH_BACK; i++) 28 | { 29 | TTable::push_back(table, 5, "test"); 30 | } 31 | } 32 | } 33 | // Register the function as a benchmark 34 | BENCHMARK(BM_MultiPushBack); 35 | 36 | static void BM_AddColumn(benchmark::State &state) 37 | { 38 | using col = TTable::Column<"id", int>; 39 | using col2 = TTable::Column<"age", int>; 40 | auto table = TTable::create_table(); 41 | for (auto i = 0; i < ELEMENTS_PUSH_BACK; i++) 42 | { 43 | TTable::push_back(table, 5, 4); 44 | } 45 | 46 | for (auto _ : state) 47 | { 48 | auto newTable = TTable::add_column(table); 49 | } 50 | } 51 | // Register the function as a benchmark 52 | BENCHMARK(BM_AddColumn); 53 | 54 | #define ADD_TWO_COLUMN_ELEMENTS_PUSH_BACK 1000 55 | static void BM_AddTwoColumn(benchmark::State &state) 56 | { 57 | using Col = TTable::Column<"id", int>; 58 | using Col2 = TTable::Column<"age", int>; 59 | auto col = Col{}; 60 | auto col2 = Col2{}; 61 | for (auto i = 0; i < ADD_TWO_COLUMN_ELEMENTS_PUSH_BACK; i++) 62 | { 63 | col.vec.push_back(1); 64 | col2.vec.push_back(1); 65 | } 66 | 67 | for (auto _ : state) 68 | { 69 | TTable::add_two_columns<"new">(col, col2); 70 | } 71 | } 72 | // Register the function as a benchmark 73 | BENCHMARK(BM_AddTwoColumn); 74 | 75 | BENCHMARK_MAIN(); -------------------------------------------------------------------------------- /tests/ttableTest.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by ewan on 3/15/22. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | TEST(TTable, initCol) 9 | { 10 | using col = TTable::Column<"id", int>; 11 | ASSERT_TRUE(std::string_view("id") == col::name.value); 12 | } 13 | 14 | TEST(TTable, initTable) 15 | { 16 | using col = TTable::Column<"id", int>; 17 | auto table = TTable::create_table(); 18 | ASSERT_TRUE(std::string_view("id") == table.col.name.value); 19 | } 20 | 21 | TEST(TTable, mulitColumnInitTable) 22 | { 23 | using col = TTable::Column<"id", int>; 24 | using col2 = TTable::Column<"name", std::string>; 25 | auto table = TTable::create_table(); 26 | ASSERT_TRUE(std::string_view("id") == table.col.name.value); 27 | ASSERT_TRUE(std::string_view("name") == table.t.col.name.value); 28 | } 29 | 30 | TEST(TTable, getColumnByName) 31 | { 32 | using col = TTable::Column<"id", int>; 33 | using col2 = TTable::Column<"name", std::string>; 34 | auto table = TTable::create_table(); 35 | 36 | auto tempCol = TTable::get_column_by_name<"id">(table); 37 | ASSERT_TRUE(std::string_view("id") == tempCol.name.value); 38 | 39 | auto tempCol2 = TTable::get_column_by_name<"name">(table); 40 | ASSERT_TRUE(std::string_view("name") == tempCol2.name.value); 41 | } 42 | 43 | TEST(TTable, push_back) 44 | { 45 | using col = TTable::Column<"id", int>; 46 | using col2 = TTable::Column<"name", std::string>; 47 | auto table = TTable::create_table(); 48 | 49 | TTable::push_back(table, 5, "test"); 50 | } 51 | 52 | TEST(TTable, get_row) 53 | { 54 | using col = TTable::Column<"id", int>; 55 | using col2 = TTable::Column<"name", std::string>; 56 | auto table = TTable::create_table(); 57 | 58 | TTable::push_back(table, 5, "test"); 59 | 60 | auto row = TTable::get_row(table, 0); 61 | } 62 | 63 | TEST(TTable, get_col_from_row) 64 | { 65 | using col = TTable::Column<"id", int>; 66 | using col2 = TTable::Column<"name", std::string>; 67 | auto table = TTable::create_table(); 68 | 69 | TTable::push_back(table, 5, "test"); 70 | 71 | auto row = TTable::get_row(table, 0); 72 | auto name = TTable::get_col_from_row<"name">(row); 73 | auto id = TTable::get_col_from_row<"id">(row); 74 | 75 | ASSERT_EQ(name, "test"); 76 | ASSERT_EQ(id, 5); 77 | } 78 | 79 | TEST(TTable, adding_two_columns) 80 | { 81 | using IdCol = TTable::Column<"id", int>; 82 | using AgeCol = TTable::Column<"age", int>; 83 | // Inserting 12 values 84 | auto idCol = IdCol{.vec = {5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6}}; 85 | auto ageCol = AgeCol{.vec = {4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7}}; 86 | auto newCol = TTable::add_two_columns<"new_col">(idCol, ageCol); 87 | const auto correctValues = std::vector{9, 7, 5, 3, 1, 1, 3, 5, 7, 9, 11, 13}; 88 | ASSERT_TRUE(newCol.vec == correctValues); 89 | } 90 | 91 | TEST(TTable, minus_two_columns) 92 | { 93 | using IdCol = TTable::Column<"id", int>; 94 | using AgeCol = TTable::Column<"age", int>; 95 | // Inserting 12 values 96 | auto idCol = IdCol{.vec = {5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6}}; 97 | auto ageCol = AgeCol{.vec = {4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7}}; 98 | auto newCol = TTable::minus_two_columns<"new_col">(idCol, ageCol); 99 | const auto correctValues = std::vector{1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1}; 100 | ASSERT_TRUE(newCol.vec == correctValues); 101 | } 102 | 103 | TEST(TTable, new_table_from_existing) 104 | { 105 | using IdCol = TTable::Column<"id", int>; 106 | auto table = TTable::create_table(); 107 | TTable::push_back(table, 5); 108 | using AgeCol = TTable::Column<"age", int>; 109 | auto newTable = TTable::add_column(table); 110 | 111 | ASSERT_EQ(newTable.t.col.vec[0], 5); 112 | ASSERT_EQ(newTable.col.vec[0], 0); 113 | } 114 | 115 | TEST(TTable, drop_column) 116 | { 117 | using IdCol = TTable::Column<"id", int>; 118 | using AgeCol = TTable::Column<"age", int>; 119 | auto table = TTable::create_table(); 120 | TTable::push_back(table, 5, 6); 121 | 122 | auto newTable = TTable::drop_column<"age">(table); 123 | 124 | const auto idCol = TTable::get_column_by_name<"id">(newTable); 125 | // This line should fail 126 | // TTable::get_column_by_name<"age">(newTable); 127 | ASSERT_EQ(idCol.vec[0], 5); 128 | } 129 | 130 | TEST(TTable, vector_data_alignment) 131 | { 132 | //using IdCol = TTable::Column<"id", int>; 133 | //using AgeCol = TTable::Column<"age", int>; 134 | //// Inserting 12 values 135 | //auto idCol = IdCol{.vec = {5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6}}; 136 | //auto ageCol = AgeCol{.vec = {4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7}}; 137 | //auto alignment = (uintptr_t)idCol.vec.data() % 512; 138 | //std::cout << "alignment: " << alignment << std::endl; 139 | //auto newCol = TTable::add_two_columns<"new_col">(idCol, ageCol); 140 | //const auto correctValues = TTable::Vector{9, 7, 5, 3, 1, 1, 3, 5, 7, 9, 11, 13}; 141 | //ASSERT_TRUE(newCol.vec == correctValues); 142 | } -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: Microsoft 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: Align 6 | AlignArrayOfStructures: None 7 | AlignConsecutiveMacros: None 8 | AlignConsecutiveAssignments: None 9 | AlignConsecutiveBitFields: None 10 | AlignConsecutiveDeclarations: None 11 | AlignEscapedNewlines: Right 12 | AlignOperands: Align 13 | AlignTrailingComments: true 14 | AllowAllArgumentsOnNextLine: true 15 | AllowAllConstructorInitializersOnNextLine: true 16 | AllowAllParametersOfDeclarationOnNextLine: true 17 | AllowShortEnumsOnASingleLine: false 18 | AllowShortBlocksOnASingleLine: Never 19 | AllowShortCaseLabelsOnASingleLine: false 20 | AllowShortFunctionsOnASingleLine: None 21 | AllowShortLambdasOnASingleLine: All 22 | AllowShortIfStatementsOnASingleLine: Never 23 | AllowShortLoopsOnASingleLine: false 24 | AlwaysBreakAfterDefinitionReturnType: None 25 | AlwaysBreakAfterReturnType: None 26 | AlwaysBreakBeforeMultilineStrings: false 27 | AlwaysBreakTemplateDeclarations: Yes 28 | AttributeMacros: 29 | - __capability 30 | BinPackArguments: true 31 | BinPackParameters: true 32 | BraceWrapping: 33 | AfterCaseLabel: false 34 | AfterClass: true 35 | AfterControlStatement: Always 36 | AfterEnum: true 37 | AfterFunction: true 38 | AfterNamespace: true 39 | AfterObjCDeclaration: true 40 | AfterStruct: true 41 | AfterUnion: false 42 | AfterExternBlock: true 43 | BeforeCatch: true 44 | BeforeElse: true 45 | BeforeLambdaBody: false 46 | BeforeWhile: false 47 | IndentBraces: false 48 | SplitEmptyFunction: true 49 | SplitEmptyRecord: true 50 | SplitEmptyNamespace: true 51 | BreakBeforeBinaryOperators: None 52 | BreakBeforeConceptDeclarations: true 53 | BreakBeforeBraces: Custom 54 | BreakBeforeInheritanceComma: false 55 | BreakInheritanceList: BeforeColon 56 | BreakBeforeTernaryOperators: true 57 | BreakConstructorInitializersBeforeComma: false 58 | BreakConstructorInitializers: BeforeColon 59 | BreakAfterJavaFieldAnnotations: false 60 | BreakStringLiterals: true 61 | ColumnLimit: 120 62 | CommentPragmas: '^ IWYU pragma:' 63 | CompactNamespaces: false 64 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 65 | ConstructorInitializerIndentWidth: 4 66 | ContinuationIndentWidth: 4 67 | Cpp11BracedListStyle: true 68 | DeriveLineEnding: true 69 | DerivePointerAlignment: false 70 | DisableFormat: false 71 | EmptyLineAfterAccessModifier: Never 72 | EmptyLineBeforeAccessModifier: LogicalBlock 73 | ExperimentalAutoDetectBinPacking: false 74 | FixNamespaceComments: true 75 | ForEachMacros: 76 | - foreach 77 | - Q_FOREACH 78 | - BOOST_FOREACH 79 | IfMacros: 80 | - KJ_IF_MAYBE 81 | IncludeBlocks: Preserve 82 | IncludeCategories: 83 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 84 | Priority: 2 85 | SortPriority: 0 86 | CaseSensitive: false 87 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 88 | Priority: 3 89 | SortPriority: 0 90 | CaseSensitive: false 91 | - Regex: '.*' 92 | Priority: 1 93 | SortPriority: 0 94 | CaseSensitive: false 95 | IncludeIsMainRegex: '(Test)?$' 96 | IncludeIsMainSourceRegex: '' 97 | IndentAccessModifiers: false 98 | IndentCaseLabels: false 99 | IndentCaseBlocks: false 100 | IndentGotoLabels: true 101 | IndentPPDirectives: None 102 | IndentExternBlock: AfterExternBlock 103 | IndentRequires: false 104 | IndentWidth: 4 105 | IndentWrappedFunctionNames: false 106 | InsertTrailingCommas: None 107 | JavaScriptQuotes: Leave 108 | JavaScriptWrapImports: true 109 | KeepEmptyLinesAtTheStartOfBlocks: true 110 | LambdaBodyIndentation: Signature 111 | MacroBlockBegin: '' 112 | MacroBlockEnd: '' 113 | MaxEmptyLinesToKeep: 1 114 | NamespaceIndentation: None 115 | ObjCBinPackProtocolList: Auto 116 | ObjCBlockIndentWidth: 2 117 | ObjCBreakBeforeNestedBlockParam: true 118 | ObjCSpaceAfterProperty: false 119 | ObjCSpaceBeforeProtocolList: true 120 | PenaltyBreakAssignment: 2 121 | PenaltyBreakBeforeFirstCallParameter: 19 122 | PenaltyBreakComment: 300 123 | PenaltyBreakFirstLessLess: 120 124 | PenaltyBreakString: 1000 125 | PenaltyBreakTemplateDeclaration: 10 126 | PenaltyExcessCharacter: 1000000 127 | PenaltyReturnTypeOnItsOwnLine: 1000 128 | PenaltyIndentedWhitespace: 0 129 | PointerAlignment: Right 130 | PPIndentWidth: -1 131 | ReferenceAlignment: Pointer 132 | ReflowComments: true 133 | ShortNamespaceLines: 1 134 | SortIncludes: CaseSensitive 135 | SortJavaStaticImport: Before 136 | SortUsingDeclarations: true 137 | SpaceAfterCStyleCast: false 138 | SpaceAfterLogicalNot: false 139 | SpaceAfterTemplateKeyword: true 140 | SpaceBeforeAssignmentOperators: true 141 | SpaceBeforeCaseColon: false 142 | SpaceBeforeCpp11BracedList: false 143 | SpaceBeforeCtorInitializerColon: true 144 | SpaceBeforeInheritanceColon: true 145 | SpaceBeforeParens: ControlStatements 146 | SpaceAroundPointerQualifiers: Default 147 | SpaceBeforeRangeBasedForLoopColon: true 148 | SpaceInEmptyBlock: false 149 | SpaceInEmptyParentheses: false 150 | SpacesBeforeTrailingComments: 1 151 | SpacesInAngles: Never 152 | SpacesInConditionalStatement: false 153 | SpacesInContainerLiterals: true 154 | SpacesInCStyleCastParentheses: false 155 | SpacesInLineCommentPrefix: 156 | Minimum: 1 157 | Maximum: -1 158 | SpacesInParentheses: false 159 | SpacesInSquareBrackets: false 160 | SpaceBeforeSquareBrackets: false 161 | BitFieldColonSpacing: Both 162 | Standard: Latest 163 | StatementAttributeLikeMacros: 164 | - Q_EMIT 165 | StatementMacros: 166 | - Q_UNUSED 167 | - QT_REQUIRE_VERSION 168 | TabWidth: 4 169 | UseCRLF: false 170 | UseTab: Never 171 | WhitespaceSensitiveMacros: 172 | - STRINGIZE 173 | - PP_STRINGIZE 174 | - BOOST_PP_STRINGIZE 175 | - NS_SWIFT_NAME 176 | - CF_SWIFT_NAME 177 | ... 178 | 179 | -------------------------------------------------------------------------------- /ttable/include/ttable/ttable.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ewan Bains on 3/15/22. 3 | // 4 | 5 | #ifndef TTABLE_TTABLE_H 6 | #define TTABLE_TTABLE_H 7 | 8 | // Example type: TTable::TTable<"id", int, "name", string>() 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | namespace TTable 16 | { 17 | 18 | template 19 | struct StringLiteral 20 | { 21 | constexpr StringLiteral(const char (&str)[N]) 22 | { 23 | std::copy_n(str, N, value); 24 | } 25 | 26 | char value[N]; 27 | std::size_t len = N; 28 | }; 29 | 30 | template 31 | struct Column 32 | { 33 | static constexpr auto name = n; 34 | std::vector vec; 35 | using Type = T; 36 | }; 37 | 38 | template 39 | Column transform_two_columns(Column const &col1, Column const &col2) 40 | { 41 | static_assert(std::is_same(), "incompatible types"); 42 | using NewCol = TTable::Column; 43 | const auto size = col1.vec.size(); 44 | auto newCol = NewCol{.vec = std::vector(size)}; 45 | for (std::size_t i = 0; i < size; ++i) 46 | { 47 | newCol.vec[i] = operation(col1.vec[i], col2.vec[i]); 48 | } 49 | return newCol; 50 | } 51 | 52 | template 53 | Column add_two_columns(Column const &col1, Column const &col2) 54 | { 55 | const auto operation = [](T1 a, T2 b){return a+b;}; 56 | return transform_two_columns(col1, col2); 57 | } 58 | 59 | template 60 | Column minus_two_columns(Column const &col1, Column const &col2) 61 | { 62 | const auto operation = [](T1 a, T2 b){return a-b;}; 63 | return transform_two_columns(col1, col2); 64 | } 65 | 66 | 67 | template 68 | struct Table 69 | { 70 | Col col; 71 | Tail t; 72 | }; 73 | struct None 74 | { 75 | }; 76 | 77 | template 78 | std::ostream &operator<<(std::ostream &os, Table const &m) 79 | { 80 | return os << std::string_view("|") << std::string_view(m.col.name.value); 81 | } 82 | 83 | std::ostream &operator<<(std::ostream &os, None const &m) 84 | { 85 | return os << std::string_view("|"); 86 | } 87 | 88 | template 89 | auto create_table() 90 | { 91 | return Table(); 92 | } 93 | 94 | template 95 | auto create_table() 96 | { 97 | using tail = typeof(create_table()); 98 | return Table(); 99 | } 100 | 101 | template 102 | auto get_column_by_name(auto table) 103 | { 104 | static_assert(!std::is_same(), "cannot find column"); 105 | 106 | if constexpr (std::string_view(table.col.name.value) == name.value) 107 | return table.col; 108 | else 109 | return get_column_by_name(table.t); 110 | } 111 | 112 | template 113 | void push_back(auto &table, T &&row, Ts &&...rows) 114 | { 115 | table.col.vec.push_back(row); 116 | static_assert(std::is_same(), "missing elements to insert"); 117 | } 118 | 119 | template 120 | void push_back(auto &table, T &&row, T2 &&row2, Ts &&...rows) 121 | { 122 | table.col.vec.push_back(row); 123 | push_back(table.t, row2, rows...); 124 | } 125 | 126 | template 127 | struct RowElement 128 | { 129 | static constexpr auto name = n; 130 | T val; 131 | }; 132 | 133 | template 134 | struct Row 135 | { 136 | Col col; 137 | Tail t; 138 | }; 139 | 140 | auto get_row_typed(auto table, std::size_t index) 141 | { 142 | if constexpr (std::is_same()) 143 | { 144 | return None{}; 145 | } 146 | 147 | else 148 | { 149 | auto tail = get_row_typed(table.t, index); 150 | using T = typeof(table.col); 151 | using Type = typename T::Type; 152 | auto rowElement = RowElement{.val = table.col.vec.at(index)}; 153 | return Row{.col = rowElement, .t = tail}; 154 | } 155 | } 156 | 157 | auto get_row(auto table, std::size_t index) 158 | { 159 | return get_row_typed(table, index); 160 | } 161 | 162 | template 163 | auto get_col_from_row(auto row) 164 | { 165 | if constexpr (std::string_view(row.col.name.value) == name.value) 166 | return row.col.val; 167 | else 168 | return get_col_from_row(row.t); 169 | } 170 | 171 | void move_column(auto &source, auto &target) 172 | { 173 | if constexpr (std::is_same() || std::is_same()) 174 | { 175 | return; 176 | } 177 | else 178 | { 179 | target.col.vec = source.col.vec; 180 | move_column(source.t, target.t); 181 | } 182 | } 183 | 184 | template 185 | auto add_column(auto table) 186 | { 187 | using NewTableType = Table; 188 | auto newTable = NewTableType{}; 189 | newTable.col = col{}; 190 | newTable.col.vec.resize(table.col.vec.size()); 191 | move_column(table, newTable.t); 192 | return newTable; 193 | } 194 | 195 | template 196 | auto drop_column(auto table) 197 | { 198 | if constexpr (std::is_same()) 199 | { 200 | static_assert(true, "unable to find column name"); 201 | } 202 | else if constexpr (std::string_view(table.col.name.value) == name.value) 203 | { 204 | return table.t; 205 | } 206 | else 207 | { 208 | const auto col = drop_column(table.t); 209 | return Table{.col = table.col, .t = col}; 210 | } 211 | } 212 | } // namespace TTable 213 | 214 | #endif // TTABLE_TTABLE_H 215 | --------------------------------------------------------------------------------