OXYGENHUB
◆ main openmsx / src / utils / static_vector.hh
4.4 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef STATIC_VECTOR_HH
2
#define STATIC_VECTOR_HH
3
4
#include "ranges.hh"
5
6
#include <algorithm>
7
#include <array>
8
#include <cassert>
9
#include <cstddef>
10
#include <cstdint>
11
#include <initializer_list>
12
#include <limits>
13
#include <span>
14
#include <type_traits>
15
#include <utility>
16
17
// This is a _very_ minimal implementation of the following (we can easily
18
// extend this when the need arises).
19
//
20
//    static_vector
21
//    A dynamically-resizable vector with fixed capacity and embedded storage
22
//    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0843r2.html
23
//
24
// For us the main purpose of this class is to use it during constexpr
25
// (compile-time) calculations. Because for now, it's no yet possible to use
26
// heap memory in constexpr functions (there are proposals to loosen this
27
// restriction in future C++ standards).
28
29
struct from_range_t {};
30
inline constexpr from_range_t from_range;
31
32
template<typename T, size_t N>
33
class static_vector
34
{
35
	using SizeType =
36
	        std::conditional_t<N <= std::numeric_limits<uint8_t >::max(), uint8_t,
37
	        std::conditional_t<N <= std::numeric_limits<uint16_t>::max(), uint16_t,
38
	        std::conditional_t<N <= std::numeric_limits<uint32_t>::max(), uint32_t,
39
	                                                                      uint64_t>>>;
40
41
public:
42
	using value_type = T;
43
	using reference = value_type&;
44
	using const_reference = const value_type&;
45
	using iterator = value_type*;
46
	using const_iterator = const value_type*;
47
	using pointer = value_type*;
48
	using const_pointer = const value_type*;
49
	using size_type = size_t;
50
	using difference_type = ptrdiff_t;
51
	using reverse_iterator = std::reverse_iterator<iterator>;
52
	using const_reverse_iterator = std::reverse_iterator<const_iterator>;
53
54
	constexpr static_vector() = default;
55
56
	constexpr static_vector(std::initializer_list<T> list) {
57
		assert(list.size() <= N);
58
		copy_to_range(list, array);
59
		sz = SizeType(list.size());
60
	}
61
62
	template<typename Range>
63
	constexpr static_vector(from_range_t, Range&& range) {
64
		for (auto&& elem : range) {
65
			push_back(std::forward<decltype(elem)>(elem));
66
		}
67
	}
68
69
	[[nodiscard]] constexpr auto begin()        noexcept { return array.begin(); }
70
	[[nodiscard]] constexpr auto begin()  const noexcept { return array.begin(); }
71
	[[nodiscard]] constexpr auto end()          noexcept { return array.begin() + sz; }
72
	[[nodiscard]] constexpr auto end()    const noexcept { return array.begin() + sz; }
73
	[[nodiscard]] constexpr auto rbegin()       noexcept { return       reverse_iterator(end()); }
74
	[[nodiscard]] constexpr auto rbegin() const noexcept { return const_reverse_iterator(end()); }
75
	[[nodiscard]] constexpr auto rend()         noexcept { return       reverse_iterator(begin()); }
76
	[[nodiscard]] constexpr auto rend()   const noexcept { return const_reverse_iterator(begin()); }
77
78
	[[nodiscard]] constexpr size_t size()     const noexcept { return sz; }
79
	[[nodiscard]] constexpr size_t max_size() const noexcept { return array.max_size(); }
80
	[[nodiscard]] constexpr bool   empty()    const noexcept { return sz == 0; }
81
82
	[[nodiscard]] constexpr       T& operator[](size_t index)       noexcept { return array[index]; }
83
	[[nodiscard]] constexpr const T& operator[](size_t index) const noexcept { return array[index]; }
84
	[[nodiscard]] constexpr T&       front()       noexcept { assert(sz > 0); return array[0]; }
85
	[[nodiscard]] constexpr const T& front() const noexcept { assert(sz > 0); return array[0]; }
86
	[[nodiscard]] constexpr T&       back()        noexcept { assert(sz > 0); return array[sz - 1]; }
87
	[[nodiscard]] constexpr const T& back()  const noexcept { assert(sz > 0); return array[sz - 1]; }
88
	[[nodiscard]] constexpr       T* data()        noexcept { return array.data(); }
89
	[[nodiscard]] constexpr const T* data()  const noexcept { return array.data(); }
90
91
	constexpr void push_back(const T& a) { assert(sz < N); array[sz++] = a; }
92
	constexpr void push_back(T&& a)      { assert(sz < N); array[sz++] = std::move(a); }
93
	template<typename... Args> constexpr T& emplace_back(Args&&... args) {
94
		assert(sz < N);
95
		array[sz++] = T(std::forward<Args>(args)...);
96
		return array[sz - 1];
97
	}
98
	constexpr void pop_back()   noexcept { assert(sz > 0); sz--; }
99
	constexpr void clear()      noexcept { sz = 0; }
100
101
	operator std::span<      T>()       noexcept { return {array.data(), sz}; }
102
	operator std::span<const T>() const noexcept { return {array.data(), sz}; }
103
104
private:
105
	std::array<T, N> array = {};
106
	SizeType sz = 0;
107
};
108
109
#endif