-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathAllocatedArrayOf.h
More file actions
138 lines (117 loc) · 4.85 KB
/
AllocatedArrayOf.h
File metadata and controls
138 lines (117 loc) · 4.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#pragma once
#include "AllocatedArrayUtils.h"
#include "MoveSliceOf.h"
#include "SliceOf.single.h"
#include <new> // new allocators
#include <stddef.h> // size_t
#include <type_traits> // is_nothrow_*
namespace array19 {
/// allocated array on the heap
/// * count is fixated at construction time
/// * all array elements are initialized (unlike std::vector)
///
/// note:
/// * C++ lacks a new T[] (custom-initializer) thing - so we would not be able to copy without default initializing
/// => to work around this we use ::operator new[] & ::operator delete[] and construct explicitly
template<class T> struct AllocatedArrayOf final {
using Element = T;
using Count = size_t;
using Index = size_t;
using Iterator = Element*;
using ConstIterator = const Element*;
using Slice = SliceOf<Element>;
using ConstSlice = SliceOf<const Element>;
using MoveSlice = MoveSliceOf<Element>;
private:
using Utils = AllocatedArrayUtils<T>;
T* m_pointer{};
size_t m_count{};
public:
AllocatedArrayOf() = default;
~AllocatedArrayOf() noexcept {
if (m_pointer) {
Utils::destruct(amend());
Utils::deallocate(amend());
}
}
explicit AllocatedArrayOf(ConstSlice slice) : m_pointer(Utils::allocate(slice.count())), m_count(0) {
Utils::copyConstruct(m_pointer, slice);
m_count = slice.count();
}
explicit AllocatedArrayOf(MoveSlice slice) : m_pointer(Utils::allocate(slice.count())), m_count(0) {
Utils::moveConstruct(m_pointer, slice);
m_count = slice.count();
}
template<class... Ts> requires(sizeof...(Ts) > 0) && requires(Ts&&... args) { (T{(Ts &&) args}, ...); }
explicit AllocatedArrayOf(Ts&&... args) : m_pointer(Utils::allocate(sizeof...(Ts)))
, m_count(0) {
(new (m_pointer + m_count++) T{(Ts &&) args}, ...);
}
AllocatedArrayOf(const AllocatedArrayOf& o) : AllocatedArrayOf(static_cast<ConstSlice>(o)) {}
AllocatedArrayOf& operator=(const AllocatedArrayOf& o) {
if (!m_pointer) {
*this = AllocatedArrayOf(o);
}
else if (o.m_count != m_count) {
Utils::destruct(amend());
Utils::deallocate(amend());
if (0 == o.m_count) {
m_pointer = nullptr;
m_count = 0;
}
else {
*this = AllocatedArrayOf(o);
}
}
else if (0 < m_count) {
Utils::copyAssign(m_pointer, o);
}
return *this;
}
AllocatedArrayOf(AllocatedArrayOf&& o) noexcept //
: m_pointer(o.m_pointer)
, m_count(o.m_count) {
o.m_pointer = nullptr;
}
AllocatedArrayOf& operator=(AllocatedArrayOf&& o) noexcept {
if (m_pointer) {
Utils::destruct(amend());
Utils::deallocate(amend());
}
m_pointer = o.m_pointer;
m_count = o.m_count;
o.m_pointer = nullptr;
return *this;
}
[[nodiscard]] static auto createCount(Count count) -> AllocatedArrayOf {
auto result = AllocatedArrayOf{};
if (count > 0) {
result.m_pointer = Utils::allocate(count);
Utils::defaultConstruct(Slice{result.m_pointer, count});
result.m_count = count;
}
return result;
}
[[nodiscard]] auto isEmpty() const noexcept -> bool { return m_count == 0; }
[[nodiscard]] auto count() const noexcept -> Count { return m_count; }
[[nodiscard]] auto front() const -> const T& { return *begin(); }
[[nodiscard]] auto back() const -> const T& { return *(begin() + m_count - 1); }
[[nodiscard]] auto begin() const noexcept -> ConstIterator { return std::launder(m_pointer); }
[[nodiscard]] auto end() const noexcept -> ConstIterator { return begin() + m_count; }
[[nodiscard]] auto operator[](Index index) const noexcept -> const T& { return *std::launder(m_pointer + index); }
operator ConstSlice() const noexcept { return SliceOf{begin(), m_count}; }
// hint: use `amend()` if you need to iterate and mutate
[[nodiscard]] auto amendBegin() noexcept -> Iterator { return std::launder(m_pointer); }
[[nodiscard]] auto amendEnd() noexcept -> Iterator { return amendBegin() + m_count; }
[[nodiscard]] auto amend() noexcept -> Slice { return SliceOf{amendBegin(), m_count}; }
};
/// simplified deduction guide
/// usage:
/// AllocatedArrayOf{1,2,3}
template<class T, class... Ts> AllocatedArrayOf(T&&, Ts&&...) -> AllocatedArrayOf<T>;
/// deduce SliceOf from AllocatedArrayOf
/// usage:
/// auto a = AllocatedArrayOf{1,2,3};
/// auto slice = SliceOf{a};
template<class T> SliceOf(const AllocatedArrayOf<T>&) -> SliceOf<const T>;
} // namespace array19