Distributed Ranges
Loading...
Searching...
No Matches
vector.hpp
1// SPDX-FileCopyrightText: Intel Corporation
2//
3// SPDX-License-Identifier: BSD-3-Clause
4
5#pragma once
6
7#include <memory>
8
9namespace dr::sp {
10
11// TODO: deal properly with non-trivially destructible types
12// - constructors, destructors, assign
13
14template <typename T, typename Allocator = std::allocator<T>> class vector {
15public:
16 using value_type = T;
17 using allocator_type = Allocator;
18 using size_type = std::size_t;
19 using difference_type = std::ptrdiff_t;
20 using pointer = typename std::allocator_traits<allocator_type>::pointer;
21 using const_pointer =
22 typename std::allocator_traits<allocator_type>::const_pointer;
23 using reference = decltype(*std::declval<pointer>());
24 using const_reference = decltype(*std::declval<const_pointer>());
25 using iterator = pointer;
26 using const_iterator = const_pointer;
27
28 vector() noexcept {}
29 explicit vector(const Allocator &allocator) noexcept
30 : allocator_(allocator) {}
31
32 explicit vector(size_type count, const T &value,
33 const Allocator &alloc = Allocator())
34 : allocator_(alloc) {
35 change_capacity_impl_(count);
36 using namespace std;
37 fill(data(), data() + size(), value);
38 }
39
40 explicit vector(size_type count, const Allocator &alloc = Allocator())
41 : allocator_(alloc) {
42 change_capacity_impl_(count);
43 using namespace std;
44 fill(data(), data() + size(), T{});
45 }
46
47 template <std::forward_iterator Iter>
48 constexpr vector(Iter first, Iter last, const Allocator &alloc = Allocator())
49 : allocator_(alloc) {
50 change_capacity_impl_(rng::distance(first, last));
51 using namespace std;
52 copy(first, last, begin());
53 }
54
55 vector(const vector &other) : allocator_(other.get_allocator()) {
56 change_capacity_impl_(other.size());
57 using namespace std;
58 copy(other.begin(), other.end(), begin());
59 }
60
61 vector(const vector &other, const Allocator &alloc) : allocator_(alloc) {
62 change_capacity_impl_(other.size());
63 using namespace std;
64 copy(other.begin(), other.end(), begin());
65 }
66
67 vector(vector &&other) noexcept
68 requires(std::is_trivially_move_constructible_v<T>)
69 : allocator_(other.get_allocator()) {
70 data_ = other.data_;
71 other.data_ = nullptr;
72 size_ = other.size_;
73 other.size_ = 0;
74 capacity_ = other.capacity_;
75 other.capacity_ = 0;
76 }
77
78 vector(vector &&other, const Allocator &alloc) noexcept
79 requires(std::is_trivially_move_constructible_v<T>)
80 : allocator_(alloc) {
81 data_ = other.data_;
82 other.data_ = nullptr;
83 size_ = other.size_;
84 other.size_ = 0;
85 capacity_ = other.capacity_;
86 other.capacity_ = 0;
87 }
88
89 vector(std::initializer_list<T> init, const Allocator &alloc = Allocator())
90 : allocator_(alloc) {
91 change_capacity_impl_(init.size());
92 using namespace std;
93 copy(init.begin(), init.end(), begin());
94 }
95
96 vector &operator=(const vector &other) {
97 assign(other.begin(), other.end());
98 return *this;
99 }
100
101 template <std::forward_iterator Iter> void assign(Iter first, Iter last) {
102 auto new_size = rng::distance(first, last);
103 reserve(new_size);
104 using namespace std;
105 copy(first, last, begin());
106 size_ = new_size;
107 }
108
109 ~vector() noexcept {
110 /*
111 for (auto iter = begin(); iter != end(); ++iter) {
112 std::allocator_traits<allocator_type>::destroy(allocator_, iter);
113 }
114 */
115 if (data() != nullptr) {
116 allocator_.deallocate(data(), capacity());
117 }
118 }
119
120 size_type size() const noexcept { return size_; }
121
122 bool empty() const noexcept { return size() == 0; }
123
124 size_type capacity() const noexcept { return capacity_; }
125
126 pointer data() noexcept { return data_; }
127
128 const_pointer data() const noexcept { return data_; }
129
130 allocator_type get_allocator() const noexcept { return allocator_; }
131
132 iterator begin() noexcept { return data_; }
133
134 iterator end() noexcept { return begin() + size(); }
135
136 const_iterator begin() const noexcept { return data_; }
137
138 const_iterator end() const noexcept { return begin() + size(); }
139
140 reference operator[](size_type pos) { return *(begin() + pos); }
141
142 const_reference operator[](size_type pos) const { return *(begin() + pos); }
143
144 void reserve(size_type new_cap) {
145 if (new_cap > capacity()) {
146 pointer new_data = get_allocator().allocate(new_cap);
147 using namespace std;
148 if (begin() != end()) {
149 using namespace std;
150 copy(begin(), end(), new_data);
151 }
152 if (data_ != nullptr) {
153 get_allocator().deallocate(data_, capacity());
154 }
155 data_ = new_data;
156 capacity_ = new_cap;
157 }
158 }
159
160 void push_back(const T &value) {
161 if (size() + 1 > capacity()) {
162 size_type new_capacity = next_highest_power_of_two_impl_(capacity());
163 reserve(new_capacity);
164 }
165
166 data()[size()] = value;
167 ++size_;
168 }
169
170 void push_back(T &&value) {
171 if (size() + 1 > capacity()) {
172 size_type new_capacity = next_highest_power_of_two_impl_(capacity());
173 reserve(new_capacity);
174 }
175
176 data()[size()] = std::move(value);
177 ++size_;
178 }
179
180 bool try_push_back(const T &value) {
181 if (size() + 1 <= capacity()) {
182 data()[size()] = value;
183 ++size_;
184 return true;
185 }
186 return false;
187 }
188
189 // TODO: properly construct/destruct
190 void resize(size_type count) {
191 if (count > capacity()) {
192 reserve(count);
193 }
194 if (count > size()) {
195 /*
196 for (std::size_t i = 0; i < count - size(); i++) {
197 end()[i] = T();
198 }
199 */
200 }
201 size_ = count;
202 }
203
204 void resize(size_type count, const value_type &value) {
205 if (count > capacity()) {
206 reserve(count);
207 }
208 if (count > size()) {
209 for (std::size_t i = 0; i < count - size(); i++) {
210 end()[i] = value;
211 }
212 }
213 size_ = count;
214 }
215
216private:
217 // For use only inside constructors and assignment operators
218 void change_capacity_impl_(size_type count) {
219 if (data_ != nullptr && capacity_ != count) {
220 allocator_.deallocate(data_, capacity());
221 }
222 size_ = capacity_ = count;
223 data_ = size_ ? allocator_.allocate(count) : nullptr;
224 }
225
226 // NOTE: algorithm copied from "Bit Twiddling Hacks"
227 // (Public domain)
228 constexpr size_type next_highest_power_of_two_impl_(size_type n) {
229 n--;
230 n |= n >> 1;
231 n |= n >> 2;
232 n |= n >> 4;
233 n |= n >> 8;
234 if constexpr (sizeof(size_type) > 2)
235 n |= n >> 16;
236 if constexpr (sizeof(size_type) > 4)
237 n |= n >> 32;
238 n++;
239 return n;
240 }
241
242 pointer data_ = nullptr;
243 size_type size_ = 0;
244 size_type capacity_ = 0;
245 allocator_type allocator_;
246};
247
248} // namespace dr::sp
Definition: vector.hpp:14