{"id":15048030,"url":"https://github.com/martinus/svector","last_synced_at":"2025-08-01T23:34:33.948Z","repository":{"id":38444526,"uuid":"487457953","full_name":"martinus/svector","owner":"martinus","description":"Compact SVO optimized vector for C++17 or higher","archived":false,"fork":false,"pushed_at":"2024-05-21T00:34:35.000Z","size":390,"stargazers_count":102,"open_issues_count":5,"forks_count":9,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-04-10T01:11:53.793Z","etag":null,"topics":["container","cpp17","header-only","no-dependencies","small-vector","stl-container","vector"],"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/martinus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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},"funding":{"github":["martinus"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2022-05-01T05:57:24.000Z","updated_at":"2025-03-14T06:14:43.000Z","dependencies_parsed_at":"2024-01-31T09:03:16.781Z","dependency_job_id":"6ce60649-ebee-4263-8a4e-887a9c71bfdf","html_url":"https://github.com/martinus/svector","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/martinus/svector","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martinus%2Fsvector","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martinus%2Fsvector/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martinus%2Fsvector/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martinus%2Fsvector/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/martinus","download_url":"https://codeload.github.com/martinus/svector/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martinus%2Fsvector/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268311879,"owners_count":24230460,"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","status":"online","status_checked_at":"2025-08-01T02:00:08.611Z","response_time":67,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["container","cpp17","header-only","no-dependencies","small-vector","stl-container","vector"],"created_at":"2024-09-24T21:07:11.214Z","updated_at":"2025-08-01T23:34:33.923Z","avatar_url":"https://github.com/martinus.png","language":"C++","readme":"\u003ca id=\"top\"\u003e\u003c/a\u003e\n\n[![meson_build_test](https://github.com/martinus/svector/actions/workflows/main.yml/badge.svg)](https://github.com/martinus/svector/actions)\n[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/martinus/svector/main/LICENSE)\n[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/6091/badge)](https://bestpractices.coreinfrastructure.org/projects/6091)\n\n# ankerl::svector 🚚 \u003c!-- omit in toc --\u003e\n\n- [How compact can it get?](#how-compact-can-it-get)\n- [Design](#design)\n- [Benchmarks](#benchmarks)\n  - [push\\_back](#push_back)\n  - [Random Access](#random-access)\n  - [Random Insert](#random-insert)\n- [Building \\\u0026 Testing](#building--testing)\n- [Disclaimer](#disclaimer)\n\n`ankerl::svector` is an `std::vector`-like container that can hold some elements on the stack without the need for any allocation.\nThere are lots of small vector implementations ([absl](https://github.com/abseil/abseil-cpp/blob/master/absl/container/inlined_vector.h), [boost](https://www.boost.org/doc/libs/1_79_0/doc/html/boost/container/small_vector.html), [folly](https://github.com/facebook/folly/blob/main/folly/docs/small_vector.md), [llvm](https://llvm.org/doxygen/classllvm_1_1SmallVector.html), ...) but this here is special by how compact it is, while showing competitive benchmark results.\n\n## How compact can it get?\n\nWhat's the minimum `sizeof(..)` of the different implementations, how much capacity does it have, and what's the overhead?\n\n|                                  |  sizeof | capacity | overhead |\n|----------------------------------|--------:|--------:|---------:|\n| `boost::container::small_vector` |    32   |     8   |     24   |\n| `absl::InlinedVector`            |    24   |    16   |      8   |\n| **`ankerl::svector`** 🚚         |  **8**  |   **7** |    **1** |\n\n`ankerl::svector` can get as low as 8 bytes and still have space for 7 bytes on the stack. absl needs at least 24 bytes, and boost at least 32 bytes.\n\nThe overhead of `ankerl::svector` is just a single byte. Boost needs a whopping 24 bytes, absl is a bit better with 8 bytes overhead.\n\nNote that boost's `small_vector` cheats a bit. E.g. `boost::container::small_vector\u003cstd::byte, 15\u003e` won't give you 15 elements on the stack, but only 8 bytes. It seems to round down to the closest multiple of 8 bytes.\n\n## Design\n\n`ankerl::svector` uses a [tagged pointer](https://en.wikipedia.org/wiki/Tagged_pointer). It uses the lowest bit of a pointer to determine if the svector is in direct or indirect mode.\n\nIn **direct mode**, the lowest byte is the control structure. It's lowest *bit* is set to 1 to make it clear that it's direct mode, and the remaining 7 bit specify the current size. So we are limited to 127 elements of inline storage at most.\n\nIn **indirect mode**, the first 8 byte (4 byte for 32bit) hold a pointer to an allocated block which holds both a control structure and memory for the elements. The lowest bit of the pointer is always 0 (thanks to alignment) to mark that we are in indirect mode.\n\n## Benchmarks\n\nTo my surprise, the performance of the `ankerl::svector` is actually quite good. I wrote benchmarks to compare it against \n`boost::container::small_vector`, `absl::InlinedVector` and of course `std::vector`. In all benchmarks I'm using [nanobench](https://github.com/martinus/nanobench). All compiled with clang++ 13.0.1 with `-std=c++17 -O3`, and run on an Intel i7-8700 that is frequency locked to 3.2GHz.\n\n### push_back\n\nThis benchmark creates a new vector, and calls `push_back` to insert 1000 `int`. This is the benchmark loop:\n\n```cpp\nauto vec = Vec();\nfor (size_t i = 0; i \u003c num_iters; ++i) {\n    vec.push_back(i);\n}\nankerl::nanobench::doNotOptimizeAway(vec.data());\n```\n\nTo no surprise at all, `std::vector` is fastest here by a large margin. To much surprise though, `ankerl::svector` is actually quite fast compared to the other implementations.\n\n![benchmark push_back](doc/bench_push_back.png)\n\n\n### Random Access\n\nCreates a vector with 1000 elements, then accesses it on random locations with `operator[]` and sums up the results. Benchmark loop is:\n\n```cpp\nsum += vec[rng.bounded(s)];\nsum += vec[rng.bounded(s)];\nsum += vec[rng.bounded(s)];\nsum += vec[rng.bounded(s)];\n```\n\nTo minimize loop overhead I'm doing the same operation 4 times. nanobench's Rng is used which has a highly optimized `bounded()` implementation (which is much faster than `%`).\n\n![benchmark operator[]](doc/bench_randomaccess.png)\n\nAnother surprising result, `absl::InlinedVector` is much slower compared to all other alternatives, `ankerl::svector` is slower than `std::vector` or `boost` but not by a huge margin.\n\n### Random Insert\n\nCreates a new vector, and inserts a new element in a random location with `vec.emplace(it, i)`. This has to move lots of elements out of the way.\n\n```cpp\nauto rng = ankerl::nanobench::Rng(1234);\nauto vec = Vec();\nfor (size_t i = 0; i \u003c num_items; ++i) {\n    auto it = vec.begin() + rng.bounded(vec.size());\n    vec.emplace(it, i);\n}\nankerl::nanobench::doNotOptimizeAway(vec.data());\n```\n\nNote that I always recreate a seeded random generator so the loop is 100% deterministic. Again, overhead from `rng` is negligible. \n\n![benchmark random insert](doc/bench_random_insert.png)\n\nFor some reason `absl::InlinedVector` is almost 5 times slower than `std::vector`. I double checked that I'm actually compiling absl with `-O3`, and that is the case. While `ankerl::svector` is slower than `std::vector` or `boost::container::small_vector`, it is still by only about 20%.\n\n## Building \u0026 Testing\n\nThis project uses the [Meson](https://mesonbuild.com/) build system for building. the CMakeLists.txt file is added as a convenience and does not build or run the tests.\n\nHow to configure \u0026 run the tests:\n\nClone  `svector`, move to the root directory, and run\n\n```sh\nmeson setup builddir\ncd builddir\nmeson test\n```\n\n## Disclaimer\n\n`ankerl::svector` is new and relatively untested! I have implemented and tested all of std::vector's API though, and have 100% test coverage. Still, using it might set your computer on fire.\n","funding_links":["https://github.com/sponsors/martinus"],"categories":["Containers"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmartinus%2Fsvector","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmartinus%2Fsvector","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmartinus%2Fsvector/lists"}