OXYGENHUB
◆ main openmsx / src / utils / dynarray.hh
3.8 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef DYNARRAY_HH
2
#define DYNARRAY_HH
3
4
// dynarray -- this models a dynamically sized array.
5
// This falls between a std::array and a std::vector.
6
//
7
// - Like vector the size of a dynarray is set at run-time (for std::array it's
8
//   set during compile-time).
9
// - Unlike vector the size of a dynarray can no longer change (grow/shrink)
10
//   after the initial construction.
11
//
12
// So qua functionality dynarray can do strictly less than a vector and strictly
13
// more than an array.
14
//
15
// The (only?) advantage of dynarray over vector is that the size of the
16
// dynarray itself is slightly smaller than the size of a vector (vector
17
// additionally needs to store the capacity; for dynarray size and capacity are
18
// always the same). (Typically on a 64-bit system: sizeof(vector)=24 and
19
// sizeof(dynarray)=16).
20
//
21
// This class is very similar to the array-version of std::unique_ptr (in fact
22
// the current implementation is based on unique_ptr<T[]>). The only addition is
23
// that dynarray also stores the size(*).
24
// (*) Technically, I think, unique_ptr<T[]> already stores the size internally
25
//     (typically at some offset in the allocated block). Though unfortunately
26
//     there's no portable way to access this size. So storing the size in the
27
//     dynarray class is necessary but strictly speaking redundant.
28
//
29
// The name and the interface of this class is based on the std::dynarray
30
// proposal for c++14. Though that proposal did not make it in c++14 and seems
31
// to be abandoned. Here's some (old) documentation:
32
//     https://www.enseignement.polytechnique.fr/informatique/INF478/docs/Cpp/en/cpp/container/dynarray.html
33
// This is not a full implementation of that proposal, just the easy parts
34
// and/or the parts that we currently need. Can easily be extended in the future
35
// (when needed).
36
37
#include <cassert>
38
#include <memory>
39
40
template<typename T>
41
class dynarray
42
{
43
public:
44
	dynarray() = default;
45
	dynarray(const dynarray&) = delete;
46
	dynarray& operator=(const dynarray&) = delete;
47
	~dynarray() = default;
48
49
	explicit dynarray(size_t n)
50
	        : m_size(n), m_data(std::make_unique<T[]>(n)) {}
51
52
	dynarray(size_t n, const T& value)
53
	        : m_size(n), m_data(std::make_unique<T[]>(n, value)) {}
54
55
	struct construct_from_range_tag {};
56
	template<typename SizedRange>
57
	dynarray(construct_from_range_tag, SizedRange&& range)
58
	        : m_size(std::size(range)), m_data(std::make_unique<T[]>(m_size)) {
59
		size_t i = 0;
60
		for (const auto& e : range) {
61
			m_data[i] = e;
62
			++i;
63
		}
64
	}
65
66
	dynarray(dynarray&& other) noexcept
67
		: m_size(other.m_size), m_data(std::move(other.m_data)) {
68
		other.m_size = 0;
69
		assert(!other.m_data);
70
	}
71
72
	dynarray& operator=(dynarray&& other) noexcept {
73
		if (this == &other) return *this;
74
		m_size = other.m_size;
75
		m_data = std::move(other.m_data);
76
		assert(!other.m_data);
77
		return *this;
78
	}
79
80
	[[nodiscard]] T& operator[](size_t i) {
81
		assert(i < m_size);
82
		return m_data[i];
83
	}
84
	[[nodiscard]] const T& operator[](size_t i) const {
85
		assert(i < m_size);
86
		return m_data[i];
87
	}
88
89
	[[nodiscard]] T& front() {
90
		assert(!empty());
91
		return m_data[0];
92
	}
93
	[[nodiscard]] const T& front() const {
94
		assert(!empty());
95
		return m_data[0];
96
	}
97
	[[nodiscard]] T& back() {
98
		assert(!empty());
99
		return m_data[m_size - 1];
100
	}
101
	[[nodiscard]] const T& back() const {
102
		assert(!empty());
103
		return m_data[m_size - 1];
104
	}
105
106
	[[nodiscard]] T* data() { return m_data.get(); }
107
	[[nodiscard]] const T* data() const { return m_data.get(); }
108
109
	[[nodiscard]] T* begin() { return m_data.get(); }
110
	[[nodiscard]] const T* begin() const { return m_data.get(); }
111
	[[nodiscard]] T* end() { return m_data.get() + m_size; }
112
	[[nodiscard]] const T* end() const { return m_data.get() + m_size; }
113
114
	[[nodiscard]] bool empty() const { return m_size == 0; }
115
	[[nodiscard]] size_t size() const { return m_size; }
116
117
private:
118
	size_t m_size = 0;
119
	std::unique_ptr<T[]> m_data;
120
};
121
122
#endif