├── .clang-format ├── .github └── workflows │ └── build.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── benchmark ├── CMakeLists.txt ├── benchmark_log_10k_deserialize.cpp ├── benchmark_log_10k_serialize.cpp ├── benchmark_mesh_125k_deserialize.cpp ├── benchmark_mesh_125k_serialize.cpp ├── benchmark_minecraft_players_50_deserialize.cpp ├── benchmark_minecraft_players_50_serialize.cpp ├── log.h ├── mesh.h └── minecraft_save.h ├── benchmark_results.txt ├── clang_format.bash ├── cmake └── project-is-top-level.cmake ├── include └── alpaca │ ├── alpaca.h │ └── detail │ ├── aggregate_arity.h │ ├── crc32.h │ ├── endian.h │ ├── field_type.h │ ├── from_bytes.h │ ├── is_bitset.h │ ├── is_specialization.h │ ├── options.h │ ├── output_container.h │ ├── print_bytes.h │ ├── struct_nth_field.h │ ├── to_bytes.h │ ├── type_info.h │ ├── types │ ├── array.h │ ├── bitset.h │ ├── deque.h │ ├── duration.h │ ├── filesystem_path.h │ ├── glm_vector.h │ ├── list.h │ ├── map.h │ ├── optional.h │ ├── pair.h │ ├── set.h │ ├── string.h │ ├── tuple.h │ ├── unique_ptr.h │ ├── variant.h │ └── vector.h │ ├── variable_length_encoding.h │ └── variant_nth_field.h ├── packaging └── pkgconfig.pc.in ├── python ├── CMakeLists.txt ├── pyalpaca.cpp ├── python_deserialize_helper.h └── python_serialize_helper.h ├── samples ├── CMakeLists.txt ├── arrays_vectors_strings.cpp ├── chrono_duration.cpp ├── demo.cpp ├── fundamental_types.cpp ├── maps_and_sets.cpp ├── nested_structures.cpp ├── optional_values.cpp ├── pyalpaca_demo.py ├── time_t.cpp ├── unique_ptr.cpp ├── variant.cpp └── write_file.cpp └── test ├── CMakeLists.txt ├── doctest.hpp ├── main.cpp ├── test_backwards_compatibility.cpp ├── test_deserialize_array.cpp ├── test_deserialize_big_endian.cpp ├── test_deserialize_bool.cpp ├── test_deserialize_bool_from_array.cpp ├── test_deserialize_chrono_duration.cpp ├── test_deserialize_chrono_duration_from_array.cpp ├── test_deserialize_deque.cpp ├── test_deserialize_deque_from_array.cpp ├── test_deserialize_enum_class.cpp ├── test_deserialize_enum_class_from_array.cpp ├── test_deserialize_error_crc32.cpp ├── test_deserialize_error_crc32_from_array.cpp ├── test_deserialize_error_set.cpp ├── test_deserialize_error_set_from_array.cpp ├── test_deserialize_error_vector.cpp ├── test_deserialize_error_vector_from_array.cpp ├── test_deserialize_error_version.cpp ├── test_deserialize_error_version_from_array.cpp ├── test_deserialize_float.cpp ├── test_deserialize_float_from_array.cpp ├── test_deserialize_from_carray.cpp ├── test_deserialize_from_ifstream.cpp ├── test_deserialize_int.cpp ├── test_deserialize_int_from_array.cpp ├── test_deserialize_list.cpp ├── test_deserialize_list_from_array.cpp ├── test_deserialize_map.cpp ├── test_deserialize_map_from_array.cpp ├── test_deserialize_optional.cpp ├── test_deserialize_optional_from_array.cpp ├── test_deserialize_pair.cpp ├── test_deserialize_pair_from_array.cpp ├── test_deserialize_set.cpp ├── test_deserialize_set_from_array.cpp ├── test_deserialize_string.cpp ├── test_deserialize_string_from_array.cpp ├── test_deserialize_tuple.cpp ├── test_deserialize_tuple_from_array.cpp ├── test_deserialize_uint.cpp ├── test_deserialize_uint_from_array.cpp ├── test_deserialize_unique_ptr.cpp ├── test_deserialize_unique_ptr_from_array.cpp ├── test_deserialize_ustring.cpp ├── test_deserialize_variant.cpp ├── test_deserialize_variant_from_array.cpp ├── test_deserialize_vector.cpp ├── test_deserialize_vector_from_array.cpp ├── test_deserialize_with_crc32.cpp ├── test_deserialize_with_crc32_from_array.cpp ├── test_deserialize_with_version.cpp ├── test_deserialize_with_version_from_array.cpp ├── test_extended_serialize_deserialize.cpp ├── test_force_alignment.cpp ├── test_forwards_compatibility.cpp ├── test_forwards_compatibility_from_array.cpp ├── test_serialize_array.cpp ├── test_serialize_array_into_array.cpp ├── test_serialize_big_endian.cpp ├── test_serialize_big_endian_into_array.cpp ├── test_serialize_bool.cpp ├── test_serialize_bool_into_array.cpp ├── test_serialize_chrono_duration.cpp ├── test_serialize_chrono_duration_to_array.cpp ├── test_serialize_deque.cpp ├── test_serialize_deque_into_array.cpp ├── test_serialize_enum_class.cpp ├── test_serialize_enum_class_into_array.cpp ├── test_serialize_float.cpp ├── test_serialize_float_into_array.cpp ├── test_serialize_int.cpp ├── test_serialize_int_into_array.cpp ├── test_serialize_into_carray.cpp ├── test_serialize_list.cpp ├── test_serialize_list_into_array.cpp ├── test_serialize_map.cpp ├── test_serialize_map_into_array.cpp ├── test_serialize_nested_struct.cpp ├── test_serialize_nested_struct_into_array.cpp ├── test_serialize_optional.cpp ├── test_serialize_optional_into_array.cpp ├── test_serialize_pair.cpp ├── test_serialize_pair_optional.cpp ├── test_serialize_set.cpp ├── test_serialize_set_into_array.cpp ├── test_serialize_string.cpp ├── test_serialize_string_into_array.cpp ├── test_serialize_to_fstream.cpp ├── test_serialize_tuple.cpp ├── test_serialize_tuple_into_array.cpp ├── test_serialize_uint.cpp ├── test_serialize_uint_into_array.cpp ├── test_serialize_unique_ptr.cpp ├── test_serialize_unique_ptr_into_array.cpp ├── test_serialize_variant.cpp ├── test_serialize_variant_into_array.cpp ├── test_serialize_vector.cpp ├── test_serialize_vector_into_array.cpp ├── test_serialize_with_crc32.cpp ├── test_serialize_with_crc32_into_array.cpp └── test_type_info.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Right 9 | AlignOperands: true 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: All 15 | AllowShortIfStatementsOnASingleLine: false 16 | AllowShortLoopsOnASingleLine: false 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: false 21 | BinPackArguments: true 22 | BinPackParameters: true 23 | BraceWrapping: 24 | AfterClass: false 25 | AfterControlStatement: false 26 | AfterEnum: false 27 | AfterFunction: false 28 | AfterNamespace: false 29 | AfterObjCDeclaration: false 30 | AfterStruct: false 31 | AfterUnion: false 32 | AfterExternBlock: false 33 | BeforeCatch: false 34 | BeforeElse: false 35 | IndentBraces: false 36 | SplitEmptyFunction: true 37 | SplitEmptyRecord: true 38 | SplitEmptyNamespace: true 39 | BreakBeforeBinaryOperators: None 40 | BreakBeforeBraces: Attach 41 | BreakBeforeInheritanceComma: false 42 | BreakBeforeTernaryOperators: true 43 | BreakConstructorInitializersBeforeComma: false 44 | BreakConstructorInitializers: BeforeColon 45 | BreakAfterJavaFieldAnnotations: false 46 | BreakStringLiterals: true 47 | ColumnLimit: 80 48 | CommentPragmas: '^ IWYU pragma:' 49 | CompactNamespaces: false 50 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 51 | ConstructorInitializerIndentWidth: 4 52 | ContinuationIndentWidth: 4 53 | Cpp11BracedListStyle: true 54 | DerivePointerAlignment: false 55 | DisableFormat: false 56 | ExperimentalAutoDetectBinPacking: false 57 | FixNamespaceComments: true 58 | ForEachMacros: 59 | - foreach 60 | - Q_FOREACH 61 | - BOOST_FOREACH 62 | IncludeBlocks: Preserve 63 | IncludeCategories: 64 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 65 | Priority: 2 66 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 67 | Priority: 3 68 | - Regex: '.*' 69 | Priority: 1 70 | IncludeIsMainRegex: '(Test)?$' 71 | IndentCaseLabels: false 72 | IndentPPDirectives: None 73 | IndentWidth: 2 74 | IndentWrappedFunctionNames: false 75 | JavaScriptQuotes: Leave 76 | JavaScriptWrapImports: true 77 | KeepEmptyLinesAtTheStartOfBlocks: true 78 | MacroBlockBegin: '' 79 | MacroBlockEnd: '' 80 | MaxEmptyLinesToKeep: 1 81 | NamespaceIndentation: None 82 | ObjCBlockIndentWidth: 2 83 | ObjCSpaceAfterProperty: false 84 | ObjCSpaceBeforeProtocolList: true 85 | PenaltyBreakAssignment: 2 86 | PenaltyBreakBeforeFirstCallParameter: 19 87 | PenaltyBreakComment: 300 88 | PenaltyBreakFirstLessLess: 120 89 | PenaltyBreakString: 1000 90 | PenaltyExcessCharacter: 1000000 91 | PenaltyReturnTypeOnItsOwnLine: 60 92 | PointerAlignment: Right 93 | ReflowComments: true 94 | SortIncludes: true 95 | SortUsingDeclarations: true 96 | SpaceAfterCStyleCast: false 97 | SpaceAfterTemplateKeyword: true 98 | SpaceBeforeAssignmentOperators: true 99 | SpaceBeforeParens: ControlStatements 100 | SpaceInEmptyParentheses: false 101 | SpacesBeforeTrailingComments: 1 102 | SpacesInAngles: false 103 | SpacesInContainerLiterals: true 104 | SpacesInCStyleCastParentheses: false 105 | SpacesInParentheses: false 106 | SpacesInSquareBrackets: false 107 | Standard: Cpp11 108 | TabWidth: 8 109 | UseTab: Never 110 | ... 111 | 112 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: pull_request 4 | 5 | jobs: 6 | 7 | test: 8 | 9 | name: ${{ matrix.toolchain }} 10 | runs-on: ${{ matrix.os }} 11 | continue-on-error: true 12 | 13 | strategy: 14 | 15 | matrix: 16 | 17 | toolchain: 18 | - macos-latest-clang 19 | - macos-12-clang 20 | - ubuntu-latest-clang 21 | - ubuntu-latest-gcc 22 | - windows-2019-msvc 23 | - windows-latest-msvc 24 | - windows-latest-clang 25 | 26 | include: 27 | - toolchain: macos-latest-clang 28 | os: macos-latest 29 | c_compiler: clang 30 | cxx_compiler: clang++ 31 | cmake_opts: -DALPACA_BUILD_TESTS=on -DALPACA_BUILD_BENCHMARKS=on -DALPACA_BUILD_SAMPLES=on -DCMAKE_BUILD_TYPE=Release 32 | 33 | - toolchain: macos-12-clang 34 | os: macos-latest 35 | c_compiler: clang 36 | cxx_compiler: clang++ 37 | cmake_opts: -DALPACA_BUILD_TESTS=on -DALPACA_BUILD_BENCHMARKS=on -DALPACA_BUILD_SAMPLES=on -DCMAKE_BUILD_TYPE=Release 38 | 39 | - toolchain: ubuntu-latest-clang 40 | os: ubuntu-latest 41 | c_compiler: clang 42 | cxx_compiler: clang++ 43 | cmake_opts: -DALPACA_BUILD_TESTS=on -DALPACA_BUILD_BENCHMARKS=on -DALPACA_BUILD_SAMPLES=on -DCMAKE_BUILD_TYPE=Release 44 | 45 | - toolchain: ubuntu-latest-gcc 46 | os: ubuntu-latest 47 | c_compiler: cc 48 | cxx_compiler: g++ 49 | cmake_opts: -DALPACA_BUILD_TESTS=on -DALPACA_BUILD_BENCHMARKS=on -DALPACA_BUILD_SAMPLES=on -DCMAKE_BUILD_TYPE=Release 50 | 51 | - toolchain: windows-2019-msvc 52 | os: windows-2019 53 | c_compiler: msvc 54 | cxx_compiler: msvc 55 | cmake_opts: -DALPACA_BUILD_TESTS=on -DALPACA_BUILD_BENCHMARKS=on -DALPACA_BUILD_SAMPLES=on -DCMAKE_BUILD_TYPE=Release 56 | 57 | - toolchain: windows-latest-msvc 58 | os: windows-latest 59 | c_compiler: msvc 60 | cxx_compiler: msvc 61 | cmake_opts: -DALPACA_BUILD_TESTS=on -DALPACA_BUILD_BENCHMARKS=on -DALPACA_BUILD_SAMPLES=on -DCMAKE_BUILD_TYPE=Release 62 | 63 | - toolchain: windows-latest-clang 64 | os: windows-latest 65 | c_compiler: clang-cl 66 | cxx_compiler: clang-cl 67 | cmake_opts: -DALPACA_BUILD_TESTS=on -DALPACA_BUILD_BENCHMARKS=on -DALPACA_BUILD_SAMPLES=on -DCMAKE_BUILD_TYPE=Release -T ClangCL 68 | 69 | steps: 70 | 71 | - name: Checkout Code 72 | uses: actions/checkout@v2 73 | 74 | - name: Configure 75 | working-directory: test 76 | run: cmake -S . -B build ${{ matrix.cmake_opts }} 77 | env: 78 | CC: ${{ matrix.c_compiler }} 79 | CXX: ${{ matrix.cxx_compiler }} 80 | 81 | - name: Build for ${{ matrix.os }} with ${{ matrix.compiler }} 82 | working-directory: test 83 | run: cmake --build build 84 | 85 | - name: Test 86 | if: ${{ ! startsWith(matrix.os, 'windows') }} 87 | working-directory: test/build 88 | run: ./tests 89 | 90 | - name: Test (Windows) 91 | if: ${{ startsWith(matrix.os, 'windows') }} 92 | working-directory: test/build 93 | run: ./Debug/tests.exe 94 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "python/pybind11"] 2 | path = python/pybind11 3 | url = https://github.com/pybind/pybind11 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022 Pranav Srinivas Kumar 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /benchmark/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | 3 | project(alpacaBenchmark CXX) 4 | 5 | include(../cmake/project-is-top-level.cmake) 6 | 7 | if(PROJECT_IS_TOP_LEVEL) 8 | find_package(alpaca REQUIRED) 9 | endif() 10 | 11 | find_package(benchmark CONFIG) 12 | if(NOT benchmark_FOUND) 13 | message(STATUS "Using CMake Version ${CMAKE_VERSION}") 14 | if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.11.0") 15 | # User can fetch googlebenchmark 16 | message(STATUS "Downloading GoogleBenchmark") 17 | include(FetchContent) 18 | set(BENCHMARK_ENABLE_GTEST_TESTS OFF CACHE INTERNAL "") 19 | # Do not build and run googlebenchmark tests 20 | FetchContent_Declare(googlebenchmark GIT_REPOSITORY https://github.com/google/benchmark.git GIT_TAG v1.5.2) 21 | 22 | FetchContent_MakeAvailable(googlebenchmark) 23 | else() 24 | message(FATAL_ERROR "GoogleBenchmark is missing. Use CMake >= 3.11 or download it") 25 | endif() 26 | endif() 27 | 28 | if (NOT CMAKE_BUILD_TYPE MATCHES Debug) 29 | add_definitions(-DNDEBUG) 30 | endif() 31 | 32 | if(NOT CMAKE_BUILD_TYPE) 33 | set(CMAKE_BUILD_TYPE Release) 34 | endif() 35 | 36 | # Set default compile flags for GCC 37 | if(CMAKE_COMPILER_IS_GNUCXX) 38 | set(CMAKE_CXX_FLAGS "-Wall -Wextra") 39 | set(CMAKE_CXX_FLAGS_DEBUG "-g") 40 | set(CMAKE_CXX_FLAGS_RELEASE "-O3") 41 | endif(CMAKE_COMPILER_IS_GNUCXX) 42 | 43 | function(add_benchmark NAME) 44 | add_executable("${NAME}" "${NAME}.cpp") 45 | target_link_libraries("${NAME}" PRIVATE alpaca::alpaca benchmark::benchmark) 46 | target_compile_features("${NAME}" PRIVATE cxx_std_17) 47 | add_custom_target("run_${NAME}" COMMAND "${NAME}" VERBATIM) 48 | add_dependencies("run_${NAME}" "${NAME}") 49 | endfunction() 50 | 51 | add_benchmark(benchmark_log_10k_serialize) 52 | add_benchmark(benchmark_log_10k_deserialize) 53 | add_benchmark(benchmark_mesh_125k_serialize) 54 | add_benchmark(benchmark_mesh_125k_deserialize) 55 | add_benchmark(benchmark_minecraft_players_50_serialize) 56 | add_benchmark(benchmark_minecraft_players_50_deserialize) -------------------------------------------------------------------------------- /benchmark/benchmark_log_10k_deserialize.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "log.h" 4 | #include 5 | 6 | std::random_device rd; 7 | std::default_random_engine eng(rd()); 8 | std::uniform_real_distribution real_distr(-1000.0f, 1000.0f); 9 | 10 | static void BM_deserialize_log_10k(benchmark::State &state) { 11 | { 12 | auto logs = alpaca::benchmark::generate_logs(eng); 13 | 14 | std::array bytes; 15 | 16 | // serialize 17 | auto data_size = alpaca::serialize(logs, bytes); 18 | 19 | std::error_code ec; 20 | alpaca::benchmark::Logs logs_recovered; 21 | 22 | for (auto _ : state) { 23 | // This code gets timed 24 | logs_recovered = alpaca::deserialize(bytes, ec); 25 | } 26 | 27 | state.counters["Success"] = ((bool)ec == false); 28 | state.counters["BytesOutput"] = data_size; 29 | state.counters["Logs"] = logs_recovered.logs.size(); 30 | state.counters["DataRate"] = benchmark::Counter(data_size, benchmark::Counter::kIsRate); 31 | } 32 | } 33 | 34 | BENCHMARK(BM_deserialize_log_10k); 35 | 36 | BENCHMARK_MAIN(); -------------------------------------------------------------------------------- /benchmark/benchmark_log_10k_serialize.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "log.h" 4 | #include 5 | 6 | std::random_device rd; 7 | std::default_random_engine eng(rd()); 8 | std::uniform_real_distribution real_distr(-1000.0f, 1000.0f); 9 | 10 | static void BM_serialize_log_10k(benchmark::State &state) { 11 | { 12 | auto logs = alpaca::benchmark::generate_logs(eng); 13 | 14 | std::array bytes; 15 | std::size_t data_size = 0; 16 | 17 | for (auto _ : state) { 18 | // This code gets timed 19 | data_size = alpaca::serialize(logs, bytes); 20 | } 21 | 22 | std::error_code ec; 23 | auto logs_recovered = alpaca::deserialize(bytes, ec); 24 | state.counters["Success"] = ((bool)ec == false); 25 | state.counters["BytesOutput"] = data_size; 26 | state.counters["Logs"] = logs_recovered.logs.size(); 27 | state.counters["DataRate"] = benchmark::Counter(data_size, benchmark::Counter::kIsRate); 28 | } 29 | } 30 | 31 | BENCHMARK(BM_serialize_log_10k); 32 | 33 | BENCHMARK_MAIN(); -------------------------------------------------------------------------------- /benchmark/benchmark_mesh_125k_deserialize.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "mesh.h" 4 | #include 5 | 6 | std::random_device rd; 7 | std::default_random_engine eng(rd()); 8 | std::uniform_real_distribution real_distr(-1000.0f, 1000.0f); 9 | 10 | static void BM_deserialize_mesh_125k(benchmark::State &state) { 11 | constexpr auto NUM_TRIANGLES = 125000; 12 | 13 | alpaca::benchmark::Mesh m; 14 | alpaca::benchmark::generate_mesh(m, eng, real_distr); 15 | 16 | std::array bytes; 17 | std::size_t data_size = alpaca::serialize(m, bytes); 18 | 19 | std::error_code ec; 20 | alpaca::benchmark::Mesh m_recovered; 21 | 22 | for (auto _ : state) { 23 | // This code gets timed 24 | m_recovered = alpaca::deserialize(bytes, data_size, ec); 25 | } 26 | 27 | state.counters["Success"] = ((bool)ec == false); 28 | state.counters["BytesOutput"] = data_size; 29 | std::size_t num_triangles_verified = 0; 30 | 31 | // Verify result 32 | for (std::size_t i = 0; i < NUM_TRIANGLES; ++i) { 33 | if (m_recovered.triangles[i].v0.x == m.triangles[i].v0.x && 34 | m_recovered.triangles[i].v0.y == m.triangles[i].v0.y && 35 | m_recovered.triangles[i].v0.z == m.triangles[i].v0.z && 36 | m_recovered.triangles[i].v1.x == m.triangles[i].v1.x && 37 | m_recovered.triangles[i].v1.y == m.triangles[i].v1.y && 38 | m_recovered.triangles[i].v1.z == m.triangles[i].v1.z && 39 | m_recovered.triangles[i].v2.x == m.triangles[i].v2.x && 40 | m_recovered.triangles[i].v2.y == m.triangles[i].v2.y && 41 | m_recovered.triangles[i].v2.z == m.triangles[i].v2.z && 42 | m_recovered.triangles[i].normal.x == m.triangles[i].normal.x && 43 | m_recovered.triangles[i].normal.y == m.triangles[i].normal.y && 44 | m_recovered.triangles[i].normal.z == m.triangles[i].normal.z) { 45 | num_triangles_verified += 1; 46 | } 47 | } 48 | 49 | state.counters["Triangles"] = num_triangles_verified; 50 | state.counters["DataRate"] = benchmark::Counter(data_size, benchmark::Counter::kIsRate); 51 | } 52 | 53 | BENCHMARK(BM_deserialize_mesh_125k); 54 | 55 | BENCHMARK_MAIN(); 56 | -------------------------------------------------------------------------------- /benchmark/benchmark_mesh_125k_serialize.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "mesh.h" 4 | #include 5 | 6 | std::random_device rd; 7 | std::default_random_engine eng(rd()); 8 | std::uniform_real_distribution real_distr(-1000.0f, 1000.0f); 9 | 10 | static void BM_serialize_mesh_125k(benchmark::State &state) { 11 | constexpr auto NUM_TRIANGLES = 125000; 12 | 13 | alpaca::benchmark::Mesh m; 14 | alpaca::benchmark::generate_mesh(m, eng, real_distr); 15 | 16 | std::array bytes; 17 | std::size_t data_size = 0; 18 | 19 | for (auto _ : state) { 20 | // This code gets timed 21 | data_size = alpaca::serialize(m, bytes); 22 | } 23 | 24 | std::error_code ec; 25 | auto m_recovered = alpaca::deserialize(bytes, ec); 26 | state.counters["Success"] = ((bool)ec == false); 27 | state.counters["BytesOutput"] = data_size; 28 | std::size_t num_triangles_verified = 0; 29 | 30 | // Verify result 31 | for (std::size_t i = 0; i < NUM_TRIANGLES; ++i) { 32 | if (m_recovered.triangles[i].v0.x == m.triangles[i].v0.x && 33 | m_recovered.triangles[i].v0.y == m.triangles[i].v0.y && 34 | m_recovered.triangles[i].v0.z == m.triangles[i].v0.z && 35 | m_recovered.triangles[i].v1.x == m.triangles[i].v1.x && 36 | m_recovered.triangles[i].v1.y == m.triangles[i].v1.y && 37 | m_recovered.triangles[i].v1.z == m.triangles[i].v1.z && 38 | m_recovered.triangles[i].v2.x == m.triangles[i].v2.x && 39 | m_recovered.triangles[i].v2.y == m.triangles[i].v2.y && 40 | m_recovered.triangles[i].v2.z == m.triangles[i].v2.z && 41 | m_recovered.triangles[i].normal.x == m.triangles[i].normal.x && 42 | m_recovered.triangles[i].normal.y == m.triangles[i].normal.y && 43 | m_recovered.triangles[i].normal.z == m.triangles[i].normal.z) { 44 | num_triangles_verified += 1; 45 | } 46 | } 47 | 48 | state.counters["Triangles"] = num_triangles_verified; 49 | state.counters["DataRate"] = benchmark::Counter(data_size, benchmark::Counter::kIsRate); 50 | } 51 | 52 | BENCHMARK(BM_serialize_mesh_125k); 53 | 54 | BENCHMARK_MAIN(); 55 | -------------------------------------------------------------------------------- /benchmark/benchmark_minecraft_players_50_deserialize.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "log.h" 4 | #include 5 | 6 | std::random_device rd; 7 | std::default_random_engine eng(rd()); 8 | std::uniform_real_distribution real_distr(-1000.0f, 1000.0f); 9 | 10 | static void BM_deserialize_minecraft_players_50(benchmark::State &state) { 11 | { 12 | alpaca::benchmark::Players m; 13 | 14 | for (std::size_t i = 0; i < 50; ++i) { 15 | m.players.push_back(alpaca::benchmark::generate_player(eng)); 16 | } 17 | 18 | constexpr auto OPTIONS = alpaca::options::fixed_length_encoding; 19 | 20 | std::array bytes; 21 | std::size_t data_size = alpaca::serialize(m, bytes); 22 | 23 | std::error_code ec; 24 | alpaca::benchmark::Players m_recovered; 25 | 26 | for (auto _ : state) { 27 | // This code gets timed 28 | // serialize 29 | m_recovered = alpaca::deserialize(bytes, ec); 30 | } 31 | 32 | state.counters["Success"] = ((bool)ec == false); 33 | state.counters["BytesOutput"] = data_size; 34 | state.counters["Players"] = m_recovered.players.size(); 35 | state.counters["DataRate"] = benchmark::Counter(data_size, benchmark::Counter::kIsRate); 36 | } 37 | } 38 | 39 | BENCHMARK(BM_deserialize_minecraft_players_50); 40 | 41 | BENCHMARK_MAIN(); -------------------------------------------------------------------------------- /benchmark/benchmark_minecraft_players_50_serialize.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "log.h" 4 | #include 5 | 6 | std::random_device rd; 7 | std::default_random_engine eng(rd()); 8 | std::uniform_real_distribution real_distr(-1000.0f, 1000.0f); 9 | 10 | static void BM_serialize_minecraft_players_50(benchmark::State &state) { 11 | { 12 | alpaca::benchmark::Players m; 13 | 14 | for (std::size_t i = 0; i < 50; ++i) { 15 | m.players.push_back(alpaca::benchmark::generate_player(eng)); 16 | } 17 | 18 | std::array bytes; 19 | std::size_t data_size = 0; 20 | 21 | constexpr auto OPTIONS = alpaca::options::fixed_length_encoding; 22 | 23 | for (auto _ : state) { 24 | // This code gets timed 25 | // serialize 26 | data_size = alpaca::serialize(m, bytes); 27 | } 28 | 29 | std::error_code ec; 30 | auto m_recovered = alpaca::deserialize(bytes, ec); 31 | state.counters["Success"] = ((bool)ec == false); 32 | state.counters["BytesOutput"] = data_size; 33 | state.counters["Players"] = m_recovered.players.size(); 34 | state.counters["DataRate"] = benchmark::Counter(data_size, benchmark::Counter::kIsRate); 35 | } 36 | } 37 | 38 | BENCHMARK(BM_serialize_minecraft_players_50); 39 | 40 | BENCHMARK_MAIN(); -------------------------------------------------------------------------------- /benchmark/log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "minecraft_save.h" 5 | 6 | namespace alpaca { 7 | 8 | namespace benchmark { 9 | 10 | struct Address { 11 | uint32_t x0; 12 | uint32_t x1; 13 | uint32_t x2; 14 | uint32_t x3; 15 | }; 16 | 17 | struct Log { 18 | Address address; 19 | std::string identity; 20 | std::string userid; 21 | std::string date; 22 | std::string request; 23 | uint32_t code; 24 | uint64_t size; 25 | }; 26 | 27 | struct Logs { 28 | std::vector logs; 29 | }; 30 | 31 | template 32 | auto generate_address(Engine &eng) { 33 | std::uniform_int_distribution uint_distr(0, 20000); 34 | return Address { 35 | uint_distr(eng), 36 | uint_distr(eng), 37 | uint_distr(eng), 38 | uint_distr(eng) 39 | }; 40 | } 41 | 42 | template 43 | auto generate_log(Engine &eng) { 44 | std::uniform_int_distribution uint32_distr(0, 20000); 45 | std::uniform_int_distribution uint64_distr(0, 20000); 46 | 47 | return Log { 48 | generate_address(eng), 49 | generate_string(12), 50 | generate_string(8), 51 | generate_string(16), 52 | generate_string(32), 53 | uint32_distr(eng), 54 | uint64_distr(eng) 55 | }; 56 | } 57 | 58 | template 59 | auto generate_logs(Engine &eng) { 60 | constexpr auto size = 10000; 61 | Logs result{}; 62 | 63 | for (std::size_t i = 0; i < size; ++i) { 64 | result.logs.push_back(generate_log(eng)); 65 | } 66 | 67 | return result; 68 | } 69 | 70 | } 71 | 72 | } -------------------------------------------------------------------------------- /benchmark/mesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace alpaca { 5 | 6 | namespace benchmark { 7 | 8 | struct Vector3 { 9 | float x; 10 | float y; 11 | float z; 12 | }; 13 | 14 | struct Triangle { 15 | Vector3 v0; 16 | Vector3 v1; 17 | Vector3 v2; 18 | Vector3 normal; 19 | }; 20 | 21 | struct Mesh { 22 | std::vector triangles; 23 | }; 24 | 25 | template 26 | auto generate_mesh(Mesh& mesh, Engine& eng, Distr &distr) { 27 | for (std::size_t i = 0; i < NumTriangles; ++i) { 28 | mesh.triangles.push_back(Triangle{ 29 | Vector3{distr(eng), distr(eng), distr(eng)}, 30 | Vector3{distr(eng), distr(eng), distr(eng)}, 31 | Vector3{distr(eng), distr(eng), distr(eng)}, 32 | Vector3{distr(eng), distr(eng), distr(eng)} 33 | }); 34 | } 35 | } 36 | 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /clang_format.bash: -------------------------------------------------------------------------------- 1 | clang-format -i include/alpaca/*.h include/alpaca/detail/*.h test/*.cpp include/alpaca/detail/types/*.h samples/*.cpp python/*.cpp python/*.h 2 | -------------------------------------------------------------------------------- /cmake/project-is-top-level.cmake: -------------------------------------------------------------------------------- 1 | # This variable is set by project() in CMake 3.21+ 2 | string( 3 | COMPARE EQUAL 4 | "${CMAKE_SOURCE_DIR}" "${PROJECT_SOURCE_DIR}" 5 | PROJECT_IS_TOP_LEVEL 6 | ) -------------------------------------------------------------------------------- /include/alpaca/detail/aggregate_arity.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace alpaca { 5 | 6 | namespace detail { 7 | 8 | struct filler { 9 | template operator type(); 10 | }; 11 | 12 | template , 13 | typename = void> 14 | struct aggregate_arity : index_sequence {}; 15 | 16 | #ifdef __GNUC__ 17 | #pragma GCC diagnostic push 18 | #pragma GCC diagnostic ignored "-Wmissing-field-initializers" 19 | #endif 20 | 21 | template 22 | struct aggregate_arity< 23 | aggregate, std::index_sequence, 24 | std::void_t())..., 25 | std::declval()})>> 26 | : aggregate_arity> {}; 28 | 29 | #ifdef __GNUC__ 30 | #pragma GCC diagnostic pop 31 | #endif 32 | 33 | } // namespace detail 34 | 35 | } // namespace alpaca -------------------------------------------------------------------------------- /include/alpaca/detail/field_type.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace alpaca { 5 | 6 | namespace detail { 7 | 8 | enum class field_type : uint8_t { 9 | bool_, 10 | char_, 11 | uint8, 12 | uint16, 13 | uint32, 14 | uint64, 15 | int8, 16 | int16, 17 | int32, 18 | int64, 19 | float32, 20 | float64, 21 | enum_class, 22 | string, 23 | array, 24 | vector, 25 | map, 26 | unordered_map, 27 | set, 28 | unordered_set, 29 | optional, 30 | pair, 31 | tuple, 32 | variant, 33 | unique_ptr, 34 | struct_, 35 | chrono_duration, 36 | list, 37 | deque, 38 | filesystem_path, 39 | bitset, 40 | }; 41 | 42 | template constexpr uint8_t to_byte() { 43 | return static_cast(value); 44 | } 45 | 46 | } // namespace detail 47 | 48 | } // namespace alpaca 49 | -------------------------------------------------------------------------------- /include/alpaca/detail/is_bitset.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ALPACA_EXCLUDE_SUPPORT_STD_BITSET 3 | #include 4 | #include 5 | 6 | namespace alpaca { 7 | 8 | namespace detail { 9 | 10 | // check if T is instantiation of Bitset 11 | template 12 | struct is_bitset : std::false_type {}; 13 | 14 | template 15 | struct is_bitset> : std::true_type {}; 16 | 17 | } // namespace detail 18 | 19 | } // namespace alpaca 20 | 21 | #endif // ALPACA_EXCLUDE_SUPPORT_STD_BITSET 22 | -------------------------------------------------------------------------------- /include/alpaca/detail/is_specialization.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace alpaca { 5 | 6 | namespace detail { 7 | 8 | // check if T is instantiation of U 9 | template class Ref> 10 | struct is_specialization : std::false_type {}; 11 | 12 | template