{"id":19035298,"url":"https://github.com/tradias/contiguous","last_synced_at":"2025-04-23T18:08:54.653Z","repository":{"id":114569170,"uuid":"368289644","full_name":"Tradias/contiguous","owner":"Tradias","description":"C++ library for storing objects of different types contiguously","archived":false,"fork":false,"pushed_at":"2025-03-17T18:32:15.000Z","size":807,"stargazers_count":10,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-23T18:08:48.873Z","etag":null,"topics":["contiguous","contiguous-allocation","contiguous-containers","cpp","cpu-cache"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Tradias.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-05-17T18:46:27.000Z","updated_at":"2025-03-17T18:32:18.000Z","dependencies_parsed_at":null,"dependency_job_id":"1f93d0aa-000a-443f-8f58-c0b48f5f9e2d","html_url":"https://github.com/Tradias/contiguous","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tradias%2Fcontiguous","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tradias%2Fcontiguous/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tradias%2Fcontiguous/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tradias%2Fcontiguous/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Tradias","download_url":"https://codeload.github.com/Tradias/contiguous/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250487528,"owners_count":21438612,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["contiguous","contiguous-allocation","contiguous-containers","cpp","cpu-cache"],"created_at":"2024-11-08T21:50:00.991Z","updated_at":"2025-04-23T18:08:54.647Z","avatar_url":"https://github.com/Tradias.png","language":"C++","readme":"# contiguous\n\n[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=Tradias_contiguous\u0026metric=coverage)](https://sonarcloud.io/dashboard?id=Tradias_contiguous)\n\nC++ library for storing objects of different types contiguously. Header-only, zero dependencies, no exceptions, no rtti, C++17\n\n# Motivation\n\nData locality can greatly improve the performance of an algorithm due to better CPU cache utilization. If the size of the data needed for one step of the algorithm is \nknown at compile time then data locality can easily be achieved by storing elements in a vector of structs. But if the size is known only at runtime then you might \nfind yourself writing rather hard to read and maintain `memcpy` with offset code like [this](https://github.com/Neiko2002/deglib/blob/fd297878adfe98eb001c452bdbe387285d27b7ff/deglib/include/graph/sizebounded_graph.h#L263) for storing data and [reinterpret_cast'ing code for retrieving it](https://github.com/Neiko2002/deglib/blob/fd297878adfe98eb001c452bdbe387285d27b7ff/deglib/include/graph/sizebounded_graph.h#L173). And what if you want to add new data in the middle, \nincrease the memory size or store non-trivial types? This library aims to provide a generalized abstraction for such tasks through a templated container type.\n\n# Usage\n\nThe library can be used as a single header file, through `add_subdirectory` or through `find_package` in a CMake project.\n\n## Single header\n\nSimply copy the \u003ca href='/src/cntgs.hpp'\u003esingle header\u003c/a\u003e into your project and include it to use the library. You can also play with the library on [compiler-explorer](https://godbolt.org/z/7GjKe8rME).\n\n## As a subdirectory\n\nClone the repository into a subdirectory of your CMake project. Then add it and link it to your target.\n\n```cmake\nadd_subdirectory(/path/to/repository/root)\ntarget_link_libraries(your_app PUBLIC cntgs::cntgs)\n```\n\n## As a CMake package\n\nClone the repository and install the library\n\n```shell\nmkdir build\ncd build\ncmake -DCMAKE_INSTALL_PREFIX=/desired/installation/directory ..\ncmake --build . --target install\n```\n\nLocate it and link it to your target.\n\n```cmake\n# Make sure to set CMAKE_PREFIX_PATH to /desired/installation/directory\nfind_package(cntgs)\ntarget_link_libraries(your_app PUBLIC cntgs::cntgs)\n```\n\n# Documentation\n\nA full API reference documentation is still work-in-progress. Meanwhile, the following examples should help you get started.\n\n## Specialize a ContiguousVector\n\nThe main workhorse of this library is the `cntgs::ContiguousVector`, a container modelled after [SequenceContainer](https://en.cppreference.com/w/cpp/named_req/SequenceContainer). Start by defining a container capable of storing elements in your desired layout.\n\n\u003c!-- snippet: contiguous-vector-definition --\u003e\n\u003ca id='snippet-contiguous-vector-definition'\u003e\u003c/a\u003e\n```hpp\ntemplate \u003cclass... Parameter\u003e\nusing ContiguousVector = cntgs::BasicContiguousVector\u003ccntgs::Options\u003c\u003e, Parameter...\u003e;\n```\n\u003csup\u003e\u003ca href='/src/cntgs/vector.hpp#L34-L37' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-contiguous-vector-definition' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\nEach parameter must be a built-in or user-deinfed type, optionally wrapped into a parameter decorator. The vector stores objects of those types within one element in the order they are specified.\n\n### Store a fixed number of objects per element\n\nTo store objects within one element of the `cntgs::ContiguousVector` in the following layout, where `f` denotes an object of type `float`, `u` denotes an object of type `uint32_t` and `|` the end of one element:\n\n```\n|fffuuuuuf|fffuuuuuf|fffuuuuuf|\n```\n\n\u003c!-- snippet: fixed-vector-definition --\u003e\n\u003ca id='snippet-fixed-vector-definition'\u003e\u003c/a\u003e\n```cpp\nusing Vector = cntgs::ContiguousVector\u003ccntgs::FixedSize\u003cfloat\u003e,     //\n                                       cntgs::FixedSize\u003cuint32_t\u003e,  //\n                                       float\u003e;\n```\n\u003csup\u003e\u003ca href='/example/fixed-vector.cpp#L13-L17' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-fixed-vector-definition' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\nThe library employs special optimizations when all parameter are either plain types or `cntgs::FixedSize` (optionally wrapped into `cntgs::AlignAs`, see below).\n\n### Store a varying number of objects per element\n\nTo store objects within one element of the `cntgs::ContiguousVector` in the following layout, where `f` denotes an object of type `float`, `i` denotes an object of type `int32_t` and `|` the end of one element:\n\n```\n|iiiif|iif|iiif|iiiiiif|\n```\n\nDefine the `cntgs::ContiguousVector` as follows:\n\n\u003c!-- snippet: varying-vector-definition --\u003e\n\u003ca id='snippet-varying-vector-definition'\u003e\u003c/a\u003e\n```cpp\nusing Vector = cntgs::ContiguousVector\u003ccntgs::VaryingSize\u003cint32_t\u003e,  //\n                                       float\u003e;\n```\n\u003csup\u003e\u003ca href='/example/varying-vector.cpp#L13-L16' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-varying-vector-definition' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\n## Construct a ContiguousVector\n\nThe exact signature of the constructor of a `cntgs::ContiguousVector` depends on the provided template parameter. For a vector that in comprised of only plain types and `cntgs::FixedSize` parameter the constructor takes the initial capacity and the number of objects per elements for each `cntgs::FixedSize` parameter as arguments.\n\n\u003c!-- snippet: fixed-vector-construction --\u003e\n\u003ca id='snippet-fixed-vector-construction'\u003e\u003c/a\u003e\n```cpp\ncntgs::ContiguousVector\u003ccntgs::FixedSize\u003cfloat\u003e,     //\n                        cntgs::FixedSize\u003cuint32_t\u003e,  //\n                        float\u003e\n    vector{initial_capacity, {first_object_count, second_object_count}};\n```\n\u003csup\u003e\u003ca href='/example/fixed-vector.cpp#L23-L28' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-fixed-vector-construction' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\nFor `cntgs::ContiguousVector` with `cntgs::VaryingSize` parameter the constructor takes the total number of bytes that all objects of `cntgs::VaryingSize` parameter will need as an argument, in addition to the initial capacity.\n\n\u003c!-- snippet: varying-vector-construction --\u003e\n\u003ca id='snippet-varying-vector-construction'\u003e\u003c/a\u003e\n```cpp\ncntgs::ContiguousVector\u003ccntgs::VaryingSize\u003cint32_t\u003e,  //\n                        float\u003e                        //\n    vector{initial_capacity, varying_object_count * sizeof(int32_t)};\n```\n\u003csup\u003e\u003ca href='/example/varying-vector.cpp#L21-L25' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-varying-vector-construction' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\n`cntgs::ContiguousVector`s that have both `cntgs::FixedSize` and `cntgs::VaryingSize` parameter, first take the total number of bytes of all objects of `cntgs::VaryingSize` followed by the objects per elements for each `cntgs::FixedSize` parameter.\n\n\u003c!-- snippet: mixed-vector-construction --\u003e\n\u003ca id='snippet-mixed-vector-construction'\u003e\u003c/a\u003e\n```cpp\ncntgs::ContiguousVector\u003ccntgs::FixedSize\u003cstd::unique_ptr\u003cint32_t\u003e\u003e,  //\n                        cntgs::Varying\u003cstd::unique_ptr\u003cuint32_t\u003e\u003e\u003e\n    vector{initial_capacity, varying_object_count * sizeof(std::unique_ptr\u003cuint32_t\u003e), {fixed_object_count}};\n```\n\u003csup\u003e\u003ca href='/example/mixed-vector.cpp#L18-L22' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-mixed-vector-construction' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\n## Emplace elements into a ContiguousVector\n\nSimilar to the constructor, the exact signature of `emplace_back` also depends on the parameter of the `cntgs::ContiguousVector`. The objects of each parameter are constructed from one of the arguments provided to the function. For `cntgs::FixedSize` parameter the argument can either be a range of an iterator. As an example for the vector defined above, assuming that the size of the first parameter is no less than three and the size of the second parameter no more than five.\n\n\u003c!-- snippet: fixed-vector-emplace_back --\u003e\n\u003ca id='snippet-fixed-vector-emplace_back'\u003e\u003c/a\u003e\n```cpp\nstd::vector first{1.f, 2.f, 3.f};\nstd::vector second{10u, 20u, 30u, 40u, 50u};\nvector.emplace_back(first, second.begin(), 0.f);\n```\n\u003csup\u003e\u003ca href='/example/fixed-vector.cpp#L33-L37' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-fixed-vector-emplace_back' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\nFor `cntgs::VaryingSize` parameter the argument must be a range.\n\n\u003c!-- snippet: varying-vector-emplace_back --\u003e\n\u003ca id='snippet-varying-vector-emplace_back'\u003e\u003c/a\u003e\n```cpp\nvector.emplace_back(std::vector{1, 2}, 10.f);\nvector.emplace_back(std::vector{3, 4, 5}, 20.f);\n```\n\u003csup\u003e\u003ca href='/example/varying-vector.cpp#L30-L33' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-varying-vector-emplace_back' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\nTo emplace move-only types either pass the range as an rvalue or wrap its iterator into a [std::move_iterator](https://en.cppreference.com/w/cpp/iterator/move_iterator).\n\n\u003c!-- snippet: mixed-vector-emplace_back --\u003e\n\u003ca id='snippet-mixed-vector-emplace_back'\u003e\u003c/a\u003e\n```cpp\nstd::vector first{std::make_unique\u003cint32_t\u003e(1u), std::make_unique\u003cint32_t\u003e(2u)};\nstd::vector second{std::make_unique\u003cint32_t\u003e(10), std::make_unique\u003cint32_t\u003e(20)};\nvector.emplace_back(std::make_move_iterator(first.begin()), std::move(second));\n```\n\u003csup\u003e\u003ca href='/example/mixed-vector.cpp#L27-L31' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-mixed-vector-emplace_back' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\n## Retrieving elements\n\nElements can be retrieved through the subscript operator, `front()` or `back()` of the `cntgs::ContiguousVector` or by de-referencing its iterator. In either case a proxy reference is returned which is similar to a tuple of references.\n\n\u003c!-- snippet: varying-vector-subscript --\u003e\n\u003ca id='snippet-varying-vector-subscript'\u003e\u003c/a\u003e\n```cpp\nauto\u0026\u0026 [varying_int, the_float] = vector[0];\nassert((std::is_same_v\u003ccntgs::Span\u003cint32_t\u003e, decltype(varying_int)\u003e));\nassert((std::is_same_v\u003cfloat\u0026, decltype(the_float)\u003e));\n```\n\u003csup\u003e\u003ca href='/example/varying-vector.cpp#L37-L41' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-varying-vector-subscript' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\nThe objects of an individual parameter of one element can also be accessed using `cntgs::get`.\n\n\u003c!-- snippet: mixed-vector-get --\u003e\n\u003ca id='snippet-mixed-vector-get'\u003e\u003c/a\u003e\n```cpp\nauto\u0026\u0026 objects_of_first_parameter = cntgs::get\u003c0\u003e(vector.front());\n```\n\u003csup\u003e\u003ca href='/example/mixed-vector.cpp#L33-L35' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-mixed-vector-get' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\n## Additional ContiguousVector member functions\n\nThe `cntgs::ContiguousVector` has additional member functions that behave very similar to their stl counterpart like `pop_back`, `reserve`, `erase`, `clear`, `size`, `capacity`, `empty`, `data`, `get_allocator`, `operator=` and `operator\u003c=\u003e`. See the [source file](/src/cntgs/vector.hpp) for more details.\n\n## Allocator support\n\nThe allocator used by the `cntgs::ContiguousVector` can be changed to any allocator that fulfills the standard [allocator requirements](https://en.cppreference.com/w/cpp/named_req/Allocator). The actual allocator used by the vector and returned by `vector.get_allocator()` will be rebound to [std::byte](https://en.cppreference.com/w/cpp/types/byte).\n\n\u003c!-- snippet: pmr-vector-definition --\u003e\n\u003ca id='snippet-pmr-vector-definition'\u003e\u003c/a\u003e\n```cpp\nusing Vector = cntgs::BasicContiguousVector\u003c                                       //\n    cntgs::Options\u003ccntgs::Allocator\u003cstd::pmr::polymorphic_allocator\u003cstd::byte\u003e\u003e\u003e,  //\n    cntgs::FixedSize\u003cuint32_t\u003e, float\u003e;\n```\n\u003csup\u003e\u003ca href='/example/pmr-vector.cpp#L13-L17' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-pmr-vector-definition' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\nAt construction pass the allocator as the last argument.\n\n\u003c!-- snippet: pmr-vector-construction --\u003e\n\u003ca id='snippet-pmr-vector-construction'\u003e\u003c/a\u003e\n```cpp\nstd::pmr::monotonic_buffer_resource resource;\nVector vector{initial_capacity, {fixed_object_count}, \u0026resource};\n```\n\u003csup\u003e\u003ca href='/example/pmr-vector.cpp#L22-L25' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-pmr-vector-construction' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\n## Alignment\n\nThe default alignment of objects stored in a `cntgs::ContiguousVector` is one. Some types require an alignment larger than that. On most processors however, misaligned memory access works correctly and has basically no performance penalty. On some processors, like RISC, unaligned memory access is not supported at all.\n\nIf you need aligned objects because you want to load them into a SIMD register or because you have measured a performance penalty then specify the desired alignment with the `cntgs::AlignAs` parameter decorator.\n\nEach element in the following `cntgs::ContiguousVector` is comprised of a fixed number of 32-byte aligned floats, followed by a variable number of 8-byte aligned integers, followed by one 8-byte aligned integer.\n\n\u003c!-- snippet: vector-with-alignment --\u003e\n\u003ca id='snippet-vector-with-alignment'\u003e\u003c/a\u003e\n```cpp\nusing Vector = cntgs::ContiguousVector\u003c              //\n    cntgs::FixedSize\u003ccntgs::AlignAs\u003cfloat, 32\u003e\u003e,     //\n    cntgs::VaryingSize\u003ccntgs::AlignAs\u003cint32_t, 8\u003e\u003e,  //\n    cntgs::AlignAs\u003cint32_t, 8\u003e\u003e;\n```\n\u003csup\u003e\u003ca href='/example/vector-with-alignment.cpp#L29-L34' title='Snippet source file'\u003esnippet source\u003c/a\u003e | \u003ca href='#snippet-vector-with-alignment' title='Start of snippet'\u003eanchor\u003c/a\u003e\u003c/sup\u003e\n\u003c!-- endSnippet --\u003e\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftradias%2Fcontiguous","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftradias%2Fcontiguous","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftradias%2Fcontiguous/lists"}