{"id":13424494,"url":"https://github.com/gnzlbg/static_vector","last_synced_at":"2025-04-13T18:52:32.446Z","repository":{"id":48186227,"uuid":"47333078","full_name":"gnzlbg/static_vector","owner":"gnzlbg","description":"A dynamically-resizable vector with fixed capacity and embedded storage","archived":false,"fork":false,"pushed_at":"2021-04-09T07:57:06.000Z","size":274,"stargazers_count":170,"open_issues_count":20,"forks_count":21,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-27T09:41:12.621Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://gnzlbg.github.io/static_vector","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":"2015-12-03T13:16:23.000Z","updated_at":"2025-01-20T21:27:34.000Z","dependencies_parsed_at":"2022-09-06T15:21:13.833Z","dependency_job_id":null,"html_url":"https://github.com/gnzlbg/static_vector","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%2Fstatic_vector","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnzlbg%2Fstatic_vector/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnzlbg%2Fstatic_vector/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnzlbg%2Fstatic_vector/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gnzlbg","download_url":"https://codeload.github.com/gnzlbg/static_vector/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248765999,"owners_count":21158296,"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-07-31T00:00:55.170Z","updated_at":"2025-04-13T18:52:32.320Z","avatar_url":"https://github.com/gnzlbg.png","language":"C++","readme":"# static_vector\u003cT\u003e\n\n\u003e A dynamically-resizable vector with fixed capacity and embedded storage (revision 3)\n\n**Document number**: P0843r3.\n\n**Date**: 2019-01-20.\n\n**Project**: Programming Language C++, Library Working Group.\n\n**Audience**: LEWG.\n\n**Reply-to**: Gonzalo Brito Gadeschi \u003cgonzalo.gadeschi at rwth-aachen dot de\u003e.\n\n# Table of contents\n\n- [1. Introduction](#INTRODUCTION)\n- [2. Motivation](#MOTIVATION)\n- [3. Existing practice](#EXISTING_PRACTICE)\n- [4. Design Decisions](#DESIGN)\n  - [4.1 Storage/Memory Layout](#STORAGE)\n  - [4.2 Move semantics](#MOVE)\n  - [4.3 `constexpr` support](#CONSTEXPR)\n  - [4.4 Exception safety](#EXCEPTION)\n  - [4.5 Iterator invalidation](#ITERATOR)\n  - [4.6 Naming](#NAMING)\n  - [4.7 Potential extensions](#EXTENSIONS)\n- [5. Technical Specification](#TECHNICAL_SPECIFICATION)\n  - [5.1 Overview](#OVERVIEW)\n  - [5.2 Construction](#CONSTRUCTION)\n  - [5.3 Destruction](#DESTRUCTION)\n  - [5.4 Size and capacity](#SIZE)\n  - [5.5 Element and data access](#ACCESS)\n  - [5.6 Modifiers](#MODIFIERS)\n  - [5.7 Specialized algorithms](#SPEC_ALG)\n- [6. Acknowledgments](#ACKNOWLEDGEMENTS)\n- [7. References](#REFERENCES)\n\n### Changelog \n\n#### Revision 4\n\n- LEWG suggested that `push_back` should be UB when the capacity is exceeded\n- LEWG suggested that this should be a free-standing header\n\n#### Revision 3\n\n- Include LWG design questions for LEWG.\n- Incorporates LWG feedback.\n\n#### Revision 2\n\n- Replace the placeholder name `fixed_capacity_vector` with `static_vector`\n- Remove `at` checked element access member function.\n- Add changelog section.\n\n#### Revision 1\n\n- Minor style changes and bugfixes.\n\n# Design Questions from LWG to LEWG \n\nLWG asks LEWG to re-consider the following two design decisions:\n\n* In this document, exceeding the capacity in methods like `static_vector::push_back` is a pre-condition violation, that is, if the capacity is exceeded, the behavior is undefined. LWG suggested that exceeding the capacity in these methods should `std::abort` instead. The trade-offs in this space are discussed in Section [4.4 Exception safety](#EXCEPTION) of this proposal.\n\n* In this document, `\u003cstatic_vector\u003e` is a _free-standing_ header, this is now clarified in Section [5. Technical Specification](#TECHNICAL_SPECIFICATION). LWG suggests that `static_vector` should be included in `\u003cvector\u003e` instead.\n\n# \u003ca id=\"INTRODUCTION\"\u003e\u003c/a\u003e1. Introduction\n\nThis paper proposes a modernized version of\n[`boost::container::static_vector\u003cT,Capacity\u003e`][boost_static_vector] [1]. That\nis, a dynamically-resizable `vector` with compile-time fixed capacity and\ncontiguous embedded storage in which the elements are stored within the vector\nobject itself.\n\nIts API closely resembles that of `std::vector\u003cT, A\u003e`. It is a contiguous\ncontainer with `O(1)` insertion and removal of elements at the end\n(non-amortized) and worst case `O(size())` insertion and removal otherwise. Like\n`std::vector`, the elements are initialized on insertion and destroyed on\nremoval. For trivial `value_type`s, the vector is fully usable inside\n`constexpr` functions.\n\n# \u003ca id=\"MOTIVATION\"\u003e\u003c/a\u003e2. Motivation and Scope\n\nThe `static_vector` container is useful when:\n\n- memory allocation is not possible, e.g., embedded environments without a free\n  store, where only a stack and the static memory segment are available,\n- memory allocation imposes an unacceptable performance penalty, e.g., with\n  respect to latency,\n- allocation of objects with complex lifetimes in the _static_-memory segment is\n  required,\n- `std::array` is not an option, e.g., if non-default constructible objects must\n  be stored,\n- a dynamically-resizable array is required within `constexpr` functions, \n- the storage location of the `static_vector` elements is required to be within\n  the `static_vector` object itself (e.g. to support `memcopy` for serialization\n  purposes).\n\n# \u003ca id=\"EXISTING_PRACTICE\"\u003e\u003c/a\u003e3. Existing practice\n\nThere are at least 3 widely used implementations of `static_vector`:\n[Boost.Container][boost_static_vector] [1], [EASTL][eastl] [2], and\n[Folly][folly] [3]. The main difference between these is that `Boost.Container`\nimplements `static_vector` as a standalone type with its own guarantees, while\nboth EASTL and Folly implement it by adding an extra template parameter to their\n`small_vector` types.\n\nA `static_vector` can also be poorly emulated by using a custom\nallocator, like for example [Howard Hinnant's `stack_alloc`][stack_alloc] [4],\non top of `std::vector`.\n\nThis proposal shares a similar purpose with [P0494R0][contiguous_container] [5]\nand [P0597R0: `std::constexpr_vector\u003cT\u003e`][constexpr_vector_1] [6]. The main\ndifference is that this proposal closely follows\n[`boost::container::static_vector`][boost_static_vector] [1] and proposes to\nstandardize existing practice. A prototype implementation of this proposal for\nstandardization purposes is provided here:\n[`http://github.com/gnzlbg/fixed_capacity_vector`][fixed_capacity_vector].\n\n# \u003ca id=\"DESIGN\"\u003e\u003c/a\u003e4. Design Decisions\n\nThe most fundamental question that must be answered is:\n\n\u003e Should `static_vector` be a standalone type or a special case of some other\n\u003e type?\n\nThe [EASTL][eastl] [2] and [Folly][folly] [3] special case `small_vector`, e.g.,\nusing a 4th template parameter, to make it become a `static_vector`. The paper\n[P0639R0: Changing attack vector of the `constexpr_vector`][constexpr_vector_2]\n[7] proposes improving the `Allocator` concepts to allow `static_vector`, among\nothers, to be implemented as a special case of `std::vector` with a custom\nallocator.\n\nBoth approaches run into the same fundamental issue: `static_vector` methods are\nidentically-named to those of `std::vector` yet they have subtly different\neffects, exception-safety, iterator invalidation, and complexity guarantees.\n\nThis proposal\n follows\n [`boost::container::static_vector\u003cT,Capacity\u003e`][boost_static_vector] [1]\n closely and specifies the semantics that `static_vector` ought to have\n as a standalone type. As a library component this delivers immediate\n value.\n\nI hope that having the concise semantics of this type specified will also be\nhelpful for those that want to generalize the `Allocator` interface to allow\nimplementing `static_vector` as a `std::vector` with a custom allocator.\n\n## \u003ca id=\"STORAGE\"\u003e\u003c/a\u003e4.1 Storage/Memory Layout\n\nThe container models `ContiguousContainer`. The elements of the `static_vector`\nare contiguously stored and properly aligned within the `static_vector` object\nitself. The exact location of the contiguous elements within the `static_vector`\nis not specified. If the `Capacity` is zero the container has zero size:\n\n```c++\nstatic_assert(is_empty_v\u003cstatic_vector\u003cT, 0\u003e\u003e); // for all T\n```\n\nThis optimization is easily implementable, enables the EBO, and felt right.\n\n## \u003ca id=\"MOVE\"\u003e\u003c/a\u003e4.2 Move semantics\n\nThe move semantics of `static_vector\u003cT, Capacity\u003e` are equal to those of \n`std::array\u003cT, Size\u003e`. That is, after\n\n```c++\nstatic_vector a(10);\nstatic_vector b(std::move(a));\n```\n\nthe elements of `a` have been moved element-wise into `b`, the elements of `a`\nare left in an initialized but unspecified state (have been moved from state),\nthe size of `a` is not altered, and `a.size() == b.size()`.\n\nNote: this behavior differs from `std::vector\u003cT, Allocator\u003e`, in particular for\nthe similar case in which\n`std::allocator_traits\u003cAllocator\u003e::propagate_on_container_move_assignment` is\n`false`. In this situation the state of `std::vector` is initialized but\nunspecified.\n\n## \u003ca id=\"CONSTEXPR\"\u003e\u003c/a\u003e4.3 `constexpr` support\n\nThe API of `static_vector\u003cT, Capacity\u003e` is `constexpr`. If\n`is_trivially_copyable_v\u003cT\u003e \u0026\u0026 is_default_constructible_v\u003cT\u003e` is `true`, \n`static_vector`s can be seamlessly used\nfrom `constexpr` code. This allows using `static_vector` as a\n`constexpr_vector` to, e.g., implement other constexpr containers.\n\nThe implementation cost of this is small: the prototye implementation\nspecializes the storage for trivial types to use a C array with \nvalue-initialized elements and a defaulted destructor.\n\nThis changes the algorithmic complexity of `static_vector` \nconstructors for trivial-types from \"Linear in `N`\" to \"Constant \nin `Capacity`. When the value-initialization takes place at run-time, \nthis difference in behavior might be signficiant: \n`static_vector\u003cnon_trivial_type, 38721943228473\u003e(4)` will only\ninitialize 4 elements but \n`static_vector\u003ctrivial_type, 38721943228473\u003e(4)`\nmust value-initialize the `38721943228473 - 4` excess elements to be a\nvalid `constexpr` constructor. \n\nVery large `static_vector`'s are not the \ntarget use case of this container class and will have, in general, worse\nperformance than, e.g., `std::vector` (e.g. due to moves being `O(N)`). \n\nFuture improvements to `constexpr` (e.g. being able to properly use \n`std::aligned_storage` in constexpr contexts) allow improving \nthe performance of `static_vector` in a backwards \ncompatible way.\n\n## \u003ca id=\"EXCEPTION\"\u003e\u003c/a\u003e4.4 Exception Safety\n\nThe only operations that can actually fail within `static_vector\u003cvalue_type,\nCapacity\u003e` are:\n\n  1. `value_type`'s constructors/assignment/destructors/swap can potentially\n     throw,\n\n  2. Mutating operations exceeding the capacity (`push_back`, `insert`,\n     `emplace`, `static_vector(value_type, size)`,\n     `static_vector(begin, end)`...).\n\n  3. Out-of-bounds unchecked access:\n     - 3.1 `front`/`back`/`pop_back` when empty, `operator[]` (unchecked\n       random-access).\n\nWhen `value_type`'s operations are invoked, the exception safety guarantees of\n`static_vector` depend on whether these operations can throw. This is\ndetected with `noexcept`.\n\nSince its `Capacity` is fixed at compile-time, `static_vector` never\ndynamically allocates memory, the answer to the following question determines\nthe exception safety for all other operations:\n\n\u003e What should `static_vector` do when its `Capacity` is exceeded?\n\nThree main answers were explored in the prototype implementation:\n\n1. Throw an exception.\n2. Abort the process.\n3. Make this a precondition violation. \n\n\nThrowing an exception is appealing because it makes the interface slightly more\nsimilar to that of `std::vector`. However, which exception should be thrown? It\ncannot be `std::bad_alloc`, because nothing is being allocated. It could throw\neither `std::out_of_bounds` or `std::logic_error` but in any case the interface\ndoes not end up being equal to that of `std::vector`.\n\nAborting the process avoids the perils of undefined behavior but comes at the\ncost of enforcing a particular \"error handling\" mechanism in the implementation,\nwhich would not allow extending it to use, e.g., Contracts, in the future.\n\nThe alternative is to make not exceeding the capacity a precondition on the\n`static_vector`'s methods. This approach allows implementations to provide good\nrun-time diagnostics if they so desire, e.g., on debug builds by means of an\nassertion, and makes implementation that avoid run-time checks conforming as\nwell. Since the mutating methods have a precondition, they have narrow\ncontracts, and are not conditionally `noexcept`. This provides implementations\nthat desire throwing an exception the freedom to do so, and it also provides the\nstandard the freedom to improve these APIs by using contracts in the future.\n\nThis proposal previously chooses this path and makes exceeding the\n`static_vector`'s capacity a precondition violation that results in undefined\nbehavior. Throwing `checked_xxx` methods can be provided in a backwards\ncompatible way.\n\n## \u003ca id=\"ITERATOR\"\u003e\u003c/a\u003e4.5 Iterator invalidation\n\nThe iterator invalidation rules are different than those for `std::vector`,\nsince:\n\n- moving a `static_vector` invalidates all iterators,\n- swapping two `static_vector`s invalidates all iterators, and \n- inserting elements at the end of an `static_vector` never invalidates\n  iterators.\n\nThe following functions can potentially invalidate the iterators of\n`static_vector`s: `resize(n)`, `resize(n, v)`, `pop_back`, `erase`, and `swap`.\n\n## \u003ca id=\"NAMING\"\u003e\u003c/a\u003e4.6 Naming\n\nThe `static_vector` name was chosen after considering the following names via a\npoll in LEWG:\n\n- `array_vector`: a vector whose storage is backed up by a raw array.\n- `bounded_vector`: clearly indicates that the the size of the vector is bounded. \n- `fixed_capacity_vector`: clearly indicates that the capacity is fixed.\n- `static_capacity_vector`: clearly indicates that the capacity is fixed at compile time (static is overloaded).\n- `static_vector` (Boost.Container): due to \"static\" / compile-time allocation\n   of the elements. The term `static` is, however, overloaded in C++ (e.g.\n   `static` memory?).\n- `embedded_vector\u003cT, Capacity\u003e`: since the elements are \"embedded\" within the\n   `fixed_capacity_vector` object itself. Sadly, the name `embedded` is\n   overloaded, e.g., embedded systems.\n- `inline_vector`: the elements are stored \"inline\" within the\n   `fixed_capacity_vector` object itself. The term `inline` is, however, already\n   overloaded in C++ (e.g. `inline` functions =\u003e ODR, inlining, `inline`\n   variables).\n- `stack_vector`: to denote that the elements can be stored on the stack. Is\n  confusing since the elements can be on the stack, the heap, or the static\n  memory segment. It also has a resemblance with `std::stack`.\n- `limited_vector`\n- `vector_n`\n\nThe names `static_vector` and `vector_n` tied in the number of votes. Many users\nare already familiar with the most widely implementation of this container\n(`boost::container::static_vector`), which gives `static_vector` an edge over a\ncompletely new name.\n\n## \u003ca id=\"EXTENSIONS\"\u003e\u003c/a\u003e4.7 Future extensions \n\nThe following extensions could be added in a backwards compatible way:\n\n- utilities for hiding the concrete type of vector-like containers (e.g.\n  `any_vector_ref\u003cT\u003e`/`any_vector\u003cT\u003e`).\n \n- default-initialization of the vector elements (as opposed to\n  value-initialization): e.g. by using a tagged constructor with a\n  `default_initialized_t` tag.\n\n- tagged-constructor of the form `static_vector(with_size_t, std::size_t\nN, T const\u0026 t = T())` to avoid the complexity introduced by initializer lists\nand braced initialization:\n\n```c++\nusing vec_t = static_vector\u003cstd::size_t, Capacity\u003e;\nvec_t v0(2);  // two-elements: 0, 0\nvec_t v1{2};  // one-element: 2\nvec_t v2(2, 1);  // two-elements: 1, 1\nvec_t v3{2, 1};  // two-elements: 2, 1\n```\n\nAll these extensions are generally useful and not part of this proposal.\n\n# \u003ca id=\"TECHNICAL_SPECIFICATION\"\u003e\u003c/a\u003e5. Technical specification\n\n---\n\nNote to editor: This enhancement is a pure header-only addition to the C++\nstandard library as the _freestanding_ `\u003cstatic_vector\u003e` header. It belongs in\nthe \"Sequence containers\" (`\\ref{sequences}`) part of the \"Containers library\"\n(`\\ref{containers}`) as \"Class template `static_vector`\".\n\nNote to LWG: one of the primary use cases for this container is\nembedded/freestanding. An alternative to adding a new `\u003cstatic_vector\u003e` header\nwould be to add `static_vector` to any of the _freestanding_ headers. None of\nthe current _freestanding_ headers is a good semantic fit.\n\n---\n\n## 5. Class template `static_vector`\n\nChanges to `library.requirements.organization.headers` table \"C++ library\nheaders\", add a new header: `\u003cstatic_vector\u003e`.\n\nChanges to `library.requirements.organization.compliance` table \"C++ headers for\nfreestanding implementations\", add a new row:\n\n\u003e [static_vector] Static vector `\u003cstatic_vector\u003e`\n\nChanges to `container.requirements.general`. \n\nThe note of Table \"Container Requirements\" should be changed to contain\n`static_vector` as well:\n\n```diff\nThose entries marked “(Note A)” or “(Note B)” have linear complexity \n- for array\n+ for array and static_vector\nand have constant complexity for all other standard containers. \n[ Note: The algorithm equal() is defined in [algorithms]. — end note ]\n```\n\nChanges to `sequence.reqmts.1`:\n\n```diff\nThe library provides four basic kinds of sequence containers: vector,\n- forward_­list, list, and deque.\n+ static_vector, forward_­list, list, and deque.\n```\n\nChanges to `sequence.reqmts.2`:\n\n```diff\nvector is the type of sequence container that should be used by default. \n+ static_vector should be used when the container has a fixed capacity known during translation.\narray should be used when the container has a fixed size known during translation. \n```\n\n### \u003ca id=\"OVERVIEW\"\u003e\u003c/a\u003e5.1 Class template `static_vector` overview\n\n- 1. A `static_vector` is a contiguous container that supports constant time\n  insert and erase operations at the end; insert and erase in the middle take\n  linear time. Its capacity is part of its type and its elements are stored\n  within the `static_vector` object itself, meaning that that if `v` is a\n  `static_vector\u003cT, N\u003e` then it obeys the identity `\u0026v[n] == \u0026v[0] + n` for all\n  `0 \u003c= n \u003c= v.size()`.\n\n- 2. A `static_vector` satisfies the container requirements\n  (`\\ref{container.requirements}`) with the exception of the `swap` member\n  function, whose complexity is linear instead of constant. It satisfies the\n  sequence container requirements, including the optional sequence container\n  requirements (`\\ref{sequence.reqmts}`), with the exception of the\n  `push_front`, `pop_front`, and `emplace_front` member functions, which are not\n  provided. It satisfies the reversible container\n  (`\\ref{container.requirements}`) and contiguous container\n  (`\\ref{container.requirements.general}`) requirements. Descriptions are\n  provided here only for operations on `static_vector` that are not described in\n  one of these tables or for operations where there is additional semantic\n  information.\n  \n- 3. Class `static_vector` relies on the implicitly-declared special member\n  functions (`\\ref{class.default.ctor}`, `\\ref{class.dtor}`, and\n  `\\ref{class.copy.ctor}`) to conform to the container requirements table in\n  `\\ref{container.requirements}`. In addition to the requirements specified in\n  the container requirements table, the move constructor and move assignment\n  operator for array require that `T` be `Cpp17MoveConstructible` or\n  `Cpp17MoveAssignable`, respectively.\n  \n\n```c++\nnamespace std {\n\ntemplate \u003ctypename T, size_t N\u003e\nclass static_vector {\npublic:\n// types:\nusing value_type = T;\nusing pointer = T*;\nusing const_pointer = const T*; \nusing reference = value_type\u0026;\nusing const_reference = const value_type\u0026;\nusing size_type =  size_t;\nusing difference_type = ptrdiff_t;\nusing iterator = implementation-defined;  // see [container.requirements]\nusing const_iterator = implementation-defined; // see [container.requirements]\nusing reverse_iterator = std::reverse_iterator\u003citerator\u003e;\nusing const_reverse_iterator = std::reverse_iterator\u003cconst_iterator\u003e;\n\n// 5.2, copy/move construction:\nconstexpr static_vector() noexcept;\nconstexpr static_vector(const static_vector\u0026);\nconstexpr static_vector(static_vector\u0026\u0026);\nconstexpr explicit static_vector(size_type n);\nconstexpr static_vector(size_type n, const value_type\u0026 value);\ntemplate \u003cclass InputIterator\u003e\nconstexpr static_vector(InputIterator first, InputIterator last);\nconstexpr static_vector(initializer_list\u003cvalue_type\u003e il);\n\n// 5.3, copy/move assignment:\nconstexpr static_vector\u0026 operator=(const static_vector\u0026 other)\n  noexcept(is_nothrow_copy_assignable_v\u003cvalue_type\u003e);\nconstexpr static_vector\u0026 operator=(static_vector\u0026\u0026 other);\n  noexcept(is_nothrow_move_assignable_v\u003cvalue_type\u003e);\ntemplate \u003cclass InputIterator\u003e\nconstexpr void assign(InputIterator first, InputIterator last);\nconstexpr void assign(size_type n, const value_type\u0026 u);\nconstexpr void assign(initializer_list\u003cvalue_type\u003e il);\n\n// 5.4, destruction\n~static_vector();\n\n// iterators\nconstexpr iterator               begin()         noexcept;\nconstexpr const_iterator         begin()   const noexcept;\nconstexpr iterator               end()           noexcept;\nconstexpr const_iterator         end()     const noexcept;\nconstexpr reverse_iterator       rbegin()        noexcept;\nconstexpr const_reverse_iterator rbegin()  const noexcept;\nconstexpr reverse_iterator       rend()          noexcept;\nconstexpr const_reverse_iterator rend()    const noexcept;\nconstexpr const_iterator         cbegin()  const noexcept;\nconstexpr const_iterator         cend()    const noexcept;\nconstexpr const_reverse_iterator crbegin() const noexcept;\nconstexpr const_reverse_iterator crend()   const noexcept;\n\n// 5.5, size/capacity:\nconstexpr bool empty() const noexcept;\nconstexpr size_type size() const noexcept;\nstatic constexpr size_type max_size() noexcept;\nstatic constexpr size_type capacity() noexcept;\nconstexpr void resize(size_type sz);\nconstexpr void resize(size_type sz, const value_type\u0026 c);\n\n// 5.6, element and data access:\nconstexpr reference       operator[](size_type n); \nconstexpr const_reference operator[](size_type n) const;\nconstexpr reference       front();\nconstexpr const_reference front() const;\nconstexpr reference       back();\nconstexpr const_reference back() const;\nconstexpr       T* data()       noexcept;\nconstexpr const T* data() const noexcept;\n\n// 5.7, modifiers:\nconstexpr iterator insert(const_iterator position, const value_type\u0026 x);\nconstexpr iterator insert(const_iterator position, value_type\u0026\u0026 x);\nconstexpr iterator insert(const_iterator position, size_type n, const value_type\u0026 x);\ntemplate \u003cclass InputIterator\u003e\n  constexpr iterator insert(const_iterator position, InputIterator first, InputIterator last);\nconstexpr iterator insert(const_iterator position, initializer_list\u003cvalue_type\u003e il);\n\ntemplate \u003cclass... Args\u003e\n  constexpr iterator emplace(const_iterator position, Args\u0026\u0026... args);\ntemplate \u003cclass... Args\u003e\n  constexpr reference emplace_back(Args\u0026\u0026... args);\nconstexpr void push_back(const value_type\u0026 x);\nconstexpr void push_back(value_type\u0026\u0026 x);\n\nconstexpr void pop_back();\nconstexpr iterator erase(const_iterator position);\nconstexpr iterator erase(const_iterator first, const_iterator last);\n\nconstexpr void clear() noexcept;\n\nconstexpr void swap(static_vector\u0026 x)\n  noexcept(is_nothrow_swappable_v\u003cvalue_type\u003e \u0026\u0026\n           is_nothrow_move_constructible_v\u003cvalue_type\u003e);\n};\n\ntemplate \u003ctypename T, size_t N\u003e\nconstexpr bool operator==(const static_vector\u003cT, N\u003e\u0026 a, const static_vector\u003cT, N\u003e\u0026 b);\ntemplate \u003ctypename T, size_t N\u003e\nconstexpr bool operator!=(const static_vector\u003cT, N\u003e\u0026 a, const static_vector\u003cT, N\u003e\u0026 b);\ntemplate \u003ctypename T, size_t N\u003e\nconstexpr bool operator\u003c(const static_vector\u003cT, N\u003e\u0026 a, const static_vector\u003cT, N\u003e\u0026 b);\ntemplate \u003ctypename T, size_t N\u003e\nconstexpr bool operator\u003c=(const static_vector\u003cT, N\u003e\u0026 a, const static_vector\u003cT, N\u003e\u0026 b);\ntemplate \u003ctypename T, size_t N\u003e\nconstexpr bool operator\u003e(const static_vector\u003cT, N\u003e\u0026 a, const static_vector\u003cT, N\u003e\u0026 b);\ntemplate \u003ctypename T, size_t N\u003e\nconstexpr bool operator\u003e=(const static_vector\u003cT, N\u003e\u0026 a, const static_vector\u003cT, N\u003e\u0026 b);\n\n// 5.8, specialized algorithms:\ntemplate \u003ctypename T, size_t N\u003e\nconstexpr void swap(static_vector\u003cT, N\u003e\u0026 x, static_vector\u003cT, N\u003e\u0026 y)\n  noexcept(noexcept(x.swap(y)));\n  \n}  // namespace std\n```\n\n## \u003ca id=\"CONSTRUCTION\"\u003e\u003c/a\u003e5.2 `static_vector` constructors\n\n---\n\n```c++\nconstexpr static_vector() noexcept;\n```\n\n\u003e - _Effects_: Constructs an empty `static_vector`.\n\u003e\n\u003e - _Ensures_: `empty()`.\n\u003e\n\u003e - _Complexity_: Constant.\n\n---\n\n```c++\nconstexpr static_vector(static_vector\u0026\u0026 rv);\n```\n\n\u003e - _Effects_: Constructs a `static_vector` by move-inserting the elements of\n\u003e   `rv`.\n\u003e\n\u003e - _Mandates_: `std::is_move_constructivle\u003cvalue_type\u003e`.\n\u003e\n\u003e - _Ensures_: The `static_vector` is equal to the value that `rv` had before\n\u003e   this construction.\n\u003e\n\u003e - _Complexity_: Linear in `rv.size()`.\n\n---\n\n```c++\nconstexpr explicit static_vector(size_type n);\n```\n\n\u003e - _Effects_: Constructs a `static_vector` with `n` default-inserted elements.\n\u003e\n\u003e - _Mandates_: `std::is_default_constructible\u003cvalue_type\u003e`.\n\u003e\n\u003e - _Expects_: `n \u003c= capacity()`.\n\u003e\n\u003e - _Complexity_: Linear in `n`.\n\n---\n\n```c++\nconstexpr static_vector(size_type n, const value_type\u0026 value);\n```\n\n\u003e - _Effects_: Constructs a `static_vector` with `n` copies of `value`.\n\u003e\n\u003e - _Mandates_: `std::is_copy_constructible\u003cvalue_type\u003e`\n\u003e\n\u003e - _Expects_: `n \u003c= capacity()`.\n\u003e\n\u003e - _Complexity_: Linear in `n`.\n\n---\n\n```c++ \ntemplate \u003cclass InputIterator\u003e\nconstexpr static_vector(InputIterator first, InputIterator last);\n```\n\n\u003e - _Effects_: Constructs a `static_vector` equal to the range `[first, last)`\n\u003e\n\u003e - _Mandates_: `std::is_constructible\u003cvalue_type, decltype(*first)\u003e`\n\u003e\n\u003e - _Expects_: `distance(first, last) \u003c= capacity()`\n\u003e\n\u003e - _Complexity_: Linear in `distance(first, last)`.\n\n## \u003ca id=\"DESTRUCTION\"\u003e\u003c/a\u003e5.3 Destruction\n\n```c++\n~static_vector();\n```\n\n\u003e _Effects_: Destroys the `static_vector` and its elements.\n\u003e\n\u003e _Remarks_: This destructor is trivial if the destructor of `value_type` is\n\u003e trivial.\n\n## \u003ca id=\"SIZE\"\u003e\u003c/a\u003e5.4 Size and capacity\n\n\n```c++\nstatic constexpr size_type capacity() noexcept\nstatic constexpr size_type max_size() noexcept\n```\n\n\u003e - _Returns_: `N`.\n\n---\n\n```c++\nconstexpr void resize(size_type sz);\n```\n\n\u003e - _Effects_: If `sz \u003c size()`, erases the last `size() - sz` elements from the\n\u003e   sequence. Otherwise, appends `sz - size()` default-constructed elements.\n\u003e\n\u003e - _Mandates_: `std::is_default_constructible\u003cvalue_type\u003e`. \n\u003e\n\u003e - _Expects_: `sz \u003c= capacity()`. \n\u003e\n\u003e - _Complexity_: Linear in `sz`.\n\n---\n\n```c++\nconstexpr void resize(size_type sz, const value_type\u0026 c);\n```\n\n\u003e - _Effects_: If `sz \u003c size()`, erases the last `size() - sz` elements from the\n\u003e   sequence. Otherwise, appends `sz - size()` copies of `c`.\n\u003e\n\u003e - _Mandates_: `std::is_copy_constructible\u003cvalue_type\u003e`.\n\u003e\n\u003e - _Expects_: `sz \u003c= capacity()`. \n\u003e\n\u003e - _Complexity_: Linear in `sz`.\n\n\n## \u003ca id=\"ACCESS\"\u003e\u003c/a\u003e5.5 Element and data access\n\n```c++\nconstexpr       T* data()       noexcept;\nconstexpr const T* data() const noexcept;\n```\n\n\u003e - _Returns_: A pointer such that `[data(), data() + size())` is a valid range.\n\u003e    For a non-empty `static_vector`, `data() == addressof(front())`.\n\u003e\n\u003e - _Complexity_: Constant time.\n\n## \u003ca id=\"MODIFIERS\"\u003e\u003c/a\u003e5.6 Modifiers\n\n---\n\nNote to LWG: All modifiers have a pre-condition on not exceeding the\n`capacity()` when inserting elements. That is, exceeding the `capacity()` of the\nvector is undefined behavior. This supports some of the major use cases of this\ncontainer (embedded, freestanding, etc.) and was required by the stakeholders\nduring LEWG review. Currently, this provides maximum freedom to the\nimplementation to choose an appropriate behavior: `abort`, `assert`, throw an\nexception (which exception? `bad_alloc`? `logic_error`? `out_of_bounds`? etc. ).\nIn the future, this freedom allows us to specify these pre-conditions using\ncontracts.\n\nNote to LWG: Because all modifiers have preconditions, they all have narrow\ncontracts and are not unconditionally `noexcept`.\n\n---\n\n```c++\nconstexpr iterator insert(const_iterator position, const value_type\u0026 x);\n```\n\n\u003e - _Effects_: Inserts `x` at `position` and invalidates all references to\n\u003e   elements after `position`. \n\u003e\n\u003e - _Expects_: `size() \u003c capacity()`.\n\u003e\n\u003e - _Mandates_: `std::is_copy_constructible\u003cvalue_type\u003e`.\n\u003e\n\u003e - _Complexity_: Linear in `size()`. \n\u003e\n\u003e - _Remarks_: If an exception is thrown by `value_type`'s copy constructor and\n\u003e   `is_nothrow_move_constructible_v\u003cvalue_type\u003e` is `true` there are no\n\u003e   effects. Otherwise, if an exception is thrown by `value_type`'s copy\n\u003e   constructor the effects are _unspecified_.\n\n---\n\n```c++\nconstexpr iterator insert(const_iterator position, size_type n, const value_type\u0026 x);\n```\n\n\u003e - _Effects_: Inserts `n` copies of `x` at `position` and invalidates all\n\u003e   references to elements after `position`.\n\u003e\n\u003e - _Expects_: `n \u003c= capacity() - size()`.\n\u003e\n\u003e - _Mandates_: `std::is_copy_constructible\u003cvalue_type\u003e`.\n\u003e\n\u003e - _Complexity_: Linear in `size()` and `n`. \n\u003e\n\u003e - _Remarks_: If an exception is thrown by `value_type`'s copy constructor and\n\u003e   `is_nothrow_move_constructible_v\u003cvalue_type\u003e` is `true` there are no\n\u003e   effects. Otherwise, if an exception is thrown by `value_type`'s copy\n\u003e   constructor the effects are _unspecified_.\n\n---\n\n```c++\nconstexpr iterator insert(const_iterator position, value_type\u0026\u0026 x);\n```\n\n\u003e - _Effects_: Inserts `x` at `position` and invalidates all references to\n\u003e   elements after `position`.\n\u003e\n\u003e - _Expects_: `size() \u003c capacity()`.\n\u003e\n\u003e - _Mandates_: `std::is_move_constructible\u003cvalue_type\u003e`.\n\u003e\n\u003e - _Complexity_: Linear in `size()`. \n\u003e\n\u003e - _Remarks_: If an exception is thrown by `value_type`'s move constructor the\n\u003e   effects are _unspecified_.\n\n---\n\n```c++\ntemplate \u003ctypename InputIterator\u003e\nconstexpr iterator insert(const_iterator position, InputIterator first, InputIterator last);\n```\n\n\u003e - _Effects_: Inserts elements in range `[first, last)` at `position` and\n\u003e   invalidates all references to elements after `position`.\n\u003e\n\u003e - _Expects_: `distance(first, last) \u003c= capacity() - size()`.\n\u003e\n\u003e - _Mandates_: `std::is_constructible\u003cvalue_type, decltype(*first)\u003e`.\n\u003e\n\u003e - _Complexity_: Linear in `size()` and `distance(first, last)`. \n\u003e\n\u003e - _Remarks_: If an exception is thrown by `value_type` constructor from\n\u003e   `decltype(*first)` and `is_nothrow_move_constructible_v\u003cvalue_type\u003e` is\n\u003e   `true` there are no effects. Otherwise, if an exception is thrown by\n\u003e   `value_type`'s constructor from `decltype(*first)` the effects are\n\u003e   _unspecified_.\n\n---\n\n```c++\nconstexpr iterator insert(const_iterator position, initializer_list\u003cvalue_type\u003e il);\n```\n\n\u003e - _Effects_: Inserts elements of `il` at `position` and invalidates all\n\u003e   references to elements after `position`.\n\u003e\n\u003e - _Expects_: `il.size() \u003c= capacity() - size()`.\n\u003e\n\u003e - _Mandates_: `std::is_copy_constructible\u003cvalue_type\u003e`.\n\u003e\n\u003e - _Complexity_: Linear in `size()` and `il.size()`. \n\u003e\n\u003e - _Remarks_: If an exception is thrown by `value_type`'s copy constructor and\n\u003e   `is_nothrow_move_constructible_v\u003cvalue_type\u003e` is `true` there are no\n\u003e   effects. Otherwise, if an exception is thrown by `value_type`'s copy\n\u003e   constructor the effects are _unspecified_.\n\n---\n\n```c++\ntemplate \u003cclass... Args\u003e\nconstexpr iterator emplace(const_iterator position, Args\u0026\u0026... args);\n```\n\n\u003e - _Effects_: Inserts an element constructed from `args...` at `position` and\n\u003e   invalidates all references to elements after `position`.\n\u003e\n\u003e - _Expects_: `size() \u003c capacity()`.\n\u003e\n\u003e - _Mandates_: `std::is_constructible\u003cvalue_type, Args...\u003e`.\n\u003e\n\u003e - _Complexity_: Linear in `size()`.\n\u003e\n\u003e - _Remarks_: If an exception is thrown by `value_type`'s constructor from\n\u003e   `args...` and `is_nothrow_move_constructible_v\u003cvalue_type\u003e` is `true` there\n\u003e   are no effects. Otherwise, if an exception is thrown by `value_type`'s\n\u003e   constructor from `args...` the effects are _unspecified_.\n\n---\n\n```c++\ntemplate \u003cclass... Args\u003e\nconstexpr reference emplace_back(Args\u0026\u0026... args);\n```\n\n\u003e - _Effects_: Inserts an element constructed from `args...` at the end.\n\u003e\n\u003e - _Expects_: `size() \u003c capacity()`.\n\u003e\n\u003e - _Mandates_: `std::is_constructible\u003cvalue_type, Args...\u003e`.\n\u003e\n\u003e - _Complexity_: Constant.\n\u003e\n\u003e - _Remarks_: If an exception is thrown by `value_type`'s constructor from\n\u003e   `args...` there are no effects.\n\n---\n\n```c++\nconstexpr void push_back(const value_type\u0026 x);\n```\n\n\u003e - _Effects_: Inserts a copy of `x` at the end.\n\u003e\n\u003e - _Expects_: `size() \u003c capacity()`.\n\u003e\n\u003e - _Mandates_: `std::is_copy_constructible\u003cvalue_type\u003e`.\n\u003e\n\u003e - _Complexity_: Constant.\n\u003e\n\u003e - _Remarks_: If an exception is thrown by `value_type`'s copy constructor\n\u003e   there are no effects.\n\n---\n\n```c++\nconstexpr void push_back(value_type\u0026\u0026 x);\n```\n\n\u003e - _Effects_: Moves `x` to the end.\n\u003e\n\u003e - _Expects_: `size() \u003c capacity()`.\n\u003e\n\u003e - _Mandates_: `std::is_move_constructible\u003cvalue_type\u003e`.\n\u003e\n\u003e - _Complexity_: Constant.\n\u003e\n\u003e - _Remarks_: If an exception is thrown by `value_type`'s move constructor\n\u003e   there are no effects.\n\n---\n\n\n```c++\nconstexpr void pop_back();\n```\n\n\u003e - _Effects_: Removes the last element of the container and destroys it.\n\u003e\n\u003e - _Expects_: `!empty()`.\n\u003e\n\u003e - _Complexity_: Constant.\n\n---\n\n```c++\nconstexpr iterator erase(const_iterator position);\n```\n\n\u003e - _Effects_: Removes the element at `position`, destroys it, and invalidates\n\u003e   references to elements after `position`.\n\u003e\n\u003e - _Expects_: `position` in range `[begin(), end())`.\n\u003e\n\u003e - _Complexity_: Linear in `size()`.\n\u003e\n\u003e - _Remarks_: If an exception is thrown by `value_type`'s move constructor\n\u003e   the effects are _unspecified_.\n\n---\n\n```c++\nconstexpr iterator erase(const_iterator first, const_iterator last);\n```\n\n\u003e - _Effects_: Removes the elements in range `[first, last)`, destroying them,\n\u003e   and invalidating references to elements after `last`.\n\u003e\n\u003e - _Expects_: `[first, last)` in range `[begin(), end())`.\n\u003e\n\u003e - _Complexity_: Linear in `size()` and `distance(first, last)`.\n\u003e\n\u003e - _Remarks_: If an exception is thrown by `value_type`'s move constructor\n\u003e   the effects are _unspecified_.\n\n---\n\n```c++\nconstexpr void swap(static_vector\u0026 x)\n  noexcept(is_nothrow_swappable_v\u003cvalue_type\u003e \u0026\u0026\n           is_nothrow_move_constructible_v\u003cvalue_type\u003e);\n```\n\n\u003e - _Effects_: Exchanges the contents of `*this` with `x`. All references to the\n\u003e   elements of `*this` and `x` are invalidated.\n\u003e\n\u003e - _Complexity_: Linear in `size()` and `x.size()`.\n\u003e\n\u003e - _Remarks_: Shall not participate in overload resolution unless\n\u003e   `is_move_constructible_v\u003cvalue_type\u003e` is `true` and\n\u003e   `is_swappable_v\u003cvalue_type\u003e` is `true`\n\n## \u003ca id=\"SPEC_ALG\"\u003e\u003c/a\u003e5.7 `static_vector` specialized algorithms\n\n```c++\ntemplate \u003ctypename T, size_t N\u003e\nconstexpr void swap(static_vector\u003cT, N\u003e\u0026 x, \n                    static_vector\u003cT, N\u003e\u0026 y)\n  noexcept(noexcept(x.swap(y)));\n```\n\n\u003e - _Constraints_: This function shall not participate in overload resolution\n\u003e   unless `is_swappable_v\u003cT\u003e` is `true`.\n\u003e\n\u003e - _Effects_: As if by `x.swap(y)`.\n\u003e\n\u003e - _Complexity_: Linear in `size()` and `x.size()`.\n\n# \u003ca id=\"ACKNOWLEDGEMENTS\"\u003e\u003c/a\u003e6. Acknowledgments\n\nThe following people have significantly contributed to the development of this\nproposal. This proposal is based on Boost.Container's\n`boost::container::static_vector` and my extensive usage of this class over the\nyears. As a consequence the authors of Boost.Container (Adam Wulkiewicz, Andrew\nHundt, and Ion Gaztanaga) have had a very significant indirect impact on this\nproposal. The implementation of libc++ `std::vector` and the libc++ test-suite\nhave been used extensively while prototyping this proposal, such that its\nauthor, Howard Hinnant, has had a significant indirect impact on the result of\nthis proposal as well. The following people provided valuable feedback that\ninfluenced some aspects of this proposal: Walter Brown, Zach Laine, Rein\nHalbersma, and Andrzej Krzemieński. But I want to wholeheartedly acknowledge\nCasey Carter for taking the time to do a very detailed analysis of the whole\nproposal, which was invaluable and reshaped it in fundamental ways.\n\n# \u003ca id=\"REFERENCES\"\u003e\u003c/a\u003e7. References\n\n- [1] [Boost.Container::static_vector][boost_static_vector]: http://www.boost.org/doc/libs/1_59_0/doc/html/boost/container/static_vector.html .\n- [2] [EASTL fixed_vector][eastl]: https://github.com/questor/eastl/blob/master/fixed_vector.h#L71 .\n- [3] [Folly small_vector][folly]: https://github.com/facebook/folly/blob/master/folly/docs/small_vector.md .\n- [4] [Howard Hinnant's stack_alloc][stack_alloc]:  https://howardhinnant.github.io/stack_alloc.html .\n- [5] [P0494R0: `contiguous_container` proposal][contiguous_container]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0494r0.pdf\n- [6] [P0597R0: `std::constexpr_vector\u003cT\u003e`][constexpr_vector_1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0597r0.html\n- [7] [P0639R0: Changing attack vector of the `constexpr_vector`][constexpr_vector_2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0639r0.html .\n- [8] [PR0274: Clump – A Vector-like Contiguous Sequence Container with Embedded Storage][clump]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0274r0.pdf\n- [9] [Boost.Container::small_vector][boostsmallvector]: http://www.boost.org/doc/libs/master/doc/html/boost/container/small_vector.html.\n- [10] [LLVM small_vector][llvmsmallvector]: http://llvm.org/docs/doxygen/html/classllvm_1_1SmallVector.html .\n- [11] [EASTL design][eastldesign]: https://github.com/questor/eastl/blob/master/doc/EASTL%20Design.html#L284 .\n- [12] [Interest in StaticVector - fixed capacity vector](https:\u003e\u003egroups.google.com\u003ed\u003etopic\u003eboost-developers-archive\u003e4n1QuJyKTTk\u003ediscussion):  https://groups.google.com/d/topic/boost-developers-archive/4n1QuJyKTTk/discussion .\n- [13] [Stack-based vector container](https:\u003e\u003egroups.google.com\u003ed\u003etopic\u003eboost-developers-archive\u003e9BEXjV8ZMeQ\u003ediscussion): https://groups.google.com/d/topic/boost-developers-archive/9BEXjV8ZMeQ/discussion.\n- [14] [static_vector: fixed capacity vector update](https:\u003e\u003egroups.google.com\u003ed\u003etopic\u003eboost-developers-archive\u003ed5_Kp-nmW6c\u003ediscussion): https://groups.google.com/d/topic/boost-developers-archive/d5_Kp-nmW6c/discussion.\n\n\u003c!-- Links --\u003e\n[stack_alloc]: https://howardhinnant.github.io/stack_alloc.html\n[fixed_capacity_vector]: http://github.com/gnzlbg/fixed_capacity_vector\n[boost_static_vector]: http://www.boost.org/doc/libs/1_59_0/doc/html/boost/container/static_vector.html\n[travis-shield]: https://img.shields.io/travis/gnzlbg/embedded_vector.svg?style=flat-square\n[travis]: https://travis-ci.org/gnzlbg/embedded_vector\n[coveralls-shield]: https://img.shields.io/coveralls/gnzlbg/embedded_vector.svg?style=flat-square\n[coveralls]: https://coveralls.io/github/gnzlbg/embedded_vector\n[docs-shield]: https://img.shields.io/badge/docs-online-blue.svg?style=flat-square\n[docs]: https://gnzlbg.github.io/embedded_vector\n[folly]: https://github.com/facebook/folly/blob/master/folly/docs/small_vector.md\n[eastl]: https://github.com/questor/eastl/blob/master/fixed_vector.h#L71\n[eastldesign]: https://github.com/questor/eastl/blob/master/doc/EASTL%20Design.html#L284\n[clump]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0274r0.pdf\n[boostsmallvector]: http://www.boost.org/doc/libs/master/doc/html/boost/container/small_vector.html\n[llvmsmallvector]: http://llvm.org/docs/doxygen/html/classllvm_1_1SmallVector.html\n[contiguous_container]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0494r0.pdf\n[constexpr_vector_1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0597r0.html\n[constexpr_vector_2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0639r0.html\n","funding_links":[],"categories":["Containers and Algorithms"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgnzlbg%2Fstatic_vector","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgnzlbg%2Fstatic_vector","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgnzlbg%2Fstatic_vector/lists"}