{"id":13730606,"url":"https://github.com/gnzlbg/scattered","last_synced_at":"2025-04-14T08:31:44.019Z","repository":{"id":11962978,"uuid":"14535137","full_name":"gnzlbg/scattered","owner":"gnzlbg","description":"C++ Scattered Containers","archived":false,"fork":false,"pushed_at":"2017-07-22T11:29:54.000Z","size":117,"stargazers_count":67,"open_issues_count":4,"forks_count":33,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-27T22:04:42.144Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gnzlbg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-11-19T19:17:45.000Z","updated_at":"2025-02-10T12:06:51.000Z","dependencies_parsed_at":"2022-08-29T08:51:13.886Z","dependency_job_id":null,"html_url":"https://github.com/gnzlbg/scattered","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/gnzlbg%2Fscattered","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnzlbg%2Fscattered/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnzlbg%2Fscattered/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnzlbg%2Fscattered/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gnzlbg","download_url":"https://codeload.github.com/gnzlbg/scattered/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248845639,"owners_count":21170829,"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":[],"created_at":"2024-08-03T02:01:17.120Z","updated_at":"2025-04-14T08:31:43.926Z","avatar_url":"https://github.com/gnzlbg.png","language":"C++","funding_links":[],"categories":["C++"],"sub_categories":[],"readme":"#### Introduction\n\nScattered container store each type's data member sequentially for all\nobjects. That is, the first data member of all objects is stored contiguosly in\nmemory, then the second data member, and so on as shown in the following figure: \n\n![Memory layout of standard and scattered\n containers](https://rawgithub.com/gnzlbg/scattered/master/docs/img/memory_layout.svg\n \"Memory layout of standard and scattered containers for a type containing an\n int, a bool, and a double as data members.\")\n\nThis improves cache line utilization when iterating sequentially over a\ncontainer without accessing all object's data members. They also allow\nasynchronous processing of object's data member without false sharing.\n\nThe following containers are available:\n  - `scattered::vector\u003cT\u003e` (analogous to `std::vector\u003cT\u003e`).\n\nScattered is a [Boost Software License](http://www.boost.org/LICENSE_1_0.txt)'d\nheader only C++1y library and is tested with Boost 1.54 (1.55 not supported yet,\nsee issue tracker) and trunk clang/libc++. It depends on [Boost.MPL]() and\n[Boost.Fusion]().\n\n##### Example: `scattered::vector\u003cT\u003e`\n\n```c++\n#include \u003calgorithm\u003e\n#include \u003cboost/range/algorithm.hpp\u003e\n#include \u003cboost/fusion/adapted/struct/adapt_assoc_struct.hpp\u003e\n#include \"scattered/vector.hpp\"\n\n/// T is a struct; k contains keys to access the struct elements:\nstruct T {\n  float x; double y; int i; bool b;\n  struct k { struct x {}; struct y {}; struct i {}; struct b {}; };\n};\n\n/// This adapts the class as an associative fusion sequence\nBOOST_FUSION_ADAPT_ASSOC_STRUCT(\n    T, (float, x, T::k::x)(double, y, T::k::y)\n       (int  , i, T::k::i)(bool  , b, T::k::b))\n\nint main() {\n  using scattered::get;\n  using k = T::k;\n\n  scattered::vector\u003cT\u003e vec(10);\n\n  /// To modify the elements of the vector in place\n  /// the keys are used on a reference proxy:\n  int count = 0;\n  for (auto i : vec) {\n    get\u003ck::x\u003e(i) = static_cast\u003cfloat\u003e(count);\n    get\u003ck::y\u003e(i) = static_cast\u003cdouble\u003e(count);\n    get\u003ck::i\u003e(i) = count;\n    get\u003ck::b\u003e(i) = count % 2 == 0;\n    ++count;\n  }\n\n  /// Cache lines contain only \"y\" data-members:\n  for (auto i : vec) { get\u003ck::y\u003e(i) += get\u003ck::y\u003e(i); }\n\n  /// Boost and STL algorithms work out of the box\n  boost::stable_sort(vec, [](auto i, auto j) {\n    return get\u003ck::x\u003e(i) \u003e get\u003ck::x\u003e(j);\n  });\n\n  /// Reference proxy implicitly converts to T\n  boost::transform(vec, std::begin(vec), [](T i) { i.y *= i.y; return i; });\n  vec.push_back(T{4.0, 3.0, 2, false});\n}\n```\n\n#### Getting started\n - `./configure.sh` is used to provide libc++'s path and select the compilation\n mode (debug/release/sanitizers are provided, see `./configure,sh -h`).\n - `make` compiles the tests, `ctest` launches all tests.\n - `make docs` builds the documentation.\n - `make update-format` reformats the code with clang-format.\n - `make bench` runs all benchmarks.\n\n##### Caveats\n\nScattered containers use proxy reference types and, as a consequence, have the\nfollowing caveats similar to those of `std::vector\u003cbool\u003e`:\n\n```c++\n// i's type = scattered::vector\u003cT\u003e::reference, not scattered::vector\u003cT\u003e::value_type\nauto  i = *scatteredVector.begin();\n\n// j's type = scattered::vector\u003cT\u003e::reference\u0026\nauto\u0026 j = *scatteredVector.begin();\n\n// this modifies scatteredVector:\ni = T{};\n\n// to get a value you need to use value_type (or T)\nT value = *scatteredVector.begin();\n\n// This fails because T\u0026 cannot bind to scattered::vector\u003cT\u003e::reference\u0026\nT\u0026 ref = *catteredVector.begin();  // Compilation Error\n```\n\n##### Main idea behind implementation\n\nScattered relies on\n[BOOST_FUSION_ADAPT_ASSOC_X](http://www.boost.org/doc/libs/1_55_0/libs/fusion/doc/html/fusion/adapted.html)\nto adapt classes as associative Boost.Fusion sequences. The\n`scattered::get\u003ckey\u003e(reference_proxy)` function returns a reference to the\nobject's data member associated with the `key`.\n\n#### Benchmarks\n\nThe aim of the library is to maximize memory bandwidth usage for algorithms that\niterate *sequentially* over the container. The following benchmarks are located\nin the `benchmarks/` directory and can be run with `make bench`.\n\n#### Todo:\n\nSee the [roadmaps](https://github.com/gnzlbg/scattered/issues) page in the issue\nlist.\n\n- Finish: `scattered::vector` will be provided.\n- Other containers: `scattered::flat_set` and `scattered::unordered_map`.\n\n#### Acknowledgments\n\nThe Scattered library resulted from efforts to improve the cache performance of\nnumerical fluid mechanics codes at the Institute of Aerodynamics, Aachen. I'd\nlike to thank Georg Geiser for introducing me to [What Every Programmer Should\nKnow About\nMemory](http://people.freebsd.org/~lstewart/articles/cpumemory.pdf). Furthermore,\nI want to thank the guests of the\n[LoungeC++](http://chat.stackoverflow.com/rooms/10/loungec) for their\ndiscussions, company, and help. In particular, to Evgeny Panasyuk who motivated\nme to write this library.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgnzlbg%2Fscattered","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgnzlbg%2Fscattered","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgnzlbg%2Fscattered/lists"}