Skip to content

Commit 081defb

Browse files
authored
feat: imp vector constructor (#27)
1 parent 347267f commit 081defb

File tree

1 file changed

+328
-0
lines changed

1 file changed

+328
-0
lines changed

source/tinystl/container/vector.h

Lines changed: 328 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,328 @@
1+
#pragma once
2+
3+
#include <concepts>
4+
#include <cstddef>
5+
#include <iterator>
6+
#include <memory>
7+
#include <stdexcept>
8+
9+
namespace tinystl {
10+
11+
template <class T, class Alloc = std::allocator<T>>
12+
class vector {
13+
using alloc_traits = std::allocator_traits<Alloc>;
14+
15+
public:
16+
using value_type = T;
17+
using allocator_type = Alloc;
18+
using size_type = std::size_t;
19+
using difference_type = std::ptrdiff_t;
20+
using reference = T &;
21+
using const_reference = const T &;
22+
using pointer = T *;
23+
using const_pointer = const T *;
24+
using iterator = T *;
25+
using const_iterator = const T *;
26+
using reverse_iterator = std::reverse_iterator<T *>;
27+
using const_reverse_iterator = std::reverse_iterator<T *>;
28+
29+
// construct/copy/destroy
30+
vector() noexcept(noexcept(Alloc()));
31+
explicit vector(const Alloc &alloc) noexcept;
32+
explicit vector(std::size_t n, const Alloc &alloc = Alloc());
33+
vector(std::size_t n, const T &val, const Alloc &alloc = Alloc());
34+
template <std::forward_iterator ForwardIter>
35+
requires std::constructible_from<T, std::iter_reference_t<ForwardIter>>
36+
vector(ForwardIter first, ForwardIter last, const Alloc &alloc = Alloc());
37+
template <std::input_iterator InputIter>
38+
requires std::constructible_from<T, std::iter_reference_t<InputIter>> &&
39+
(!std::forward_iterator<InputIter>) &&
40+
(std::movable<T> || std::copyable<T>)
41+
vector(InputIter first, InputIter last, const Alloc &alloc = Alloc());
42+
vector(std::initializer_list<T> init, const Alloc &alloc = Alloc());
43+
vector(const vector &other);
44+
vector(const vector &other, const Alloc &alloc);
45+
vector(vector &&other) noexcept;
46+
vector(vector &&other, const Alloc &alloc);
47+
48+
~vector();
49+
50+
vector &operator=(const vector &other);
51+
vector &operator=(vector &&other);
52+
vector &operator=(std::initializer_list<value_type> init);
53+
54+
void assign(std::size_t n, const T &val);
55+
template <class InputIt>
56+
void assign(InputIt first, InputIt last);
57+
void assign(std::initializer_list<T> ilist);
58+
59+
allocator_type get_allocator() const;
60+
61+
// element access
62+
reference at(std::size_t pos);
63+
const T &at(std::size_t pos) const;
64+
reference operator[](std::size_t pos);
65+
const T &operator[](std::size_t pos) const;
66+
reference front();
67+
const T &front() const;
68+
reference back();
69+
const T &back() const;
70+
T *data() noexcept;
71+
const T *data() const noexcept;
72+
73+
// iterators
74+
T *begin() noexcept;
75+
T *begin() const noexcept;
76+
T *cbegin() const noexcept;
77+
T *end() noexcept;
78+
T *end() const noexcept;
79+
T *cend() const noexcept;
80+
reverse_iterator rbegin() noexcept;
81+
const_reverse_iterator rbegin() const noexcept;
82+
const_reverse_iterator crbegin() const noexcept;
83+
reverse_iterator rend() noexcept;
84+
const_reverse_iterator rend() const noexcept;
85+
const_reverse_iterator crend() const noexcept;
86+
87+
// capacity
88+
bool empty() const noexcept;
89+
std::size_t size() const noexcept;
90+
std::size_t max_size() const noexcept;
91+
void reserve(std::size_t new_cap);
92+
std::size_t capacity() const noexcept;
93+
void shrink_to_fit();
94+
95+
// modifiers
96+
void clear() noexcept;
97+
T *insert(T *pos, const T &val);
98+
T *insert(T *pos, T &&val);
99+
T *insert(T *pos, std::size_t n, const T &val);
100+
template <class InputIter>
101+
T *insert(T *position, InputIter first, InputIter last);
102+
template <class... Args>
103+
T *emplace(T *pos, Args &&...args);
104+
T *erase(T *pos);
105+
T *erase(T *first, T *last);
106+
void push_back(const T &val);
107+
void push_back(T &&val);
108+
template <class... Args>
109+
reference emplace_back(Args &&...args);
110+
void pop_back();
111+
void resize(std::size_t sz);
112+
void resize(std::size_t sz, const value_type &val);
113+
void swap(vector &other) noexcept(
114+
alloc_traits::propagate_on_container_swap::val ||
115+
alloc_traits::is_always_equal::val
116+
);
117+
118+
private:
119+
void throw_length_error();
120+
121+
void allocate(std::size_t n);
122+
123+
void construct(std::size_t n);
124+
void construct(std::size_t n, const T& val);
125+
template <class InputIterator, class Sential>
126+
void construct(InputIterator first, Sential last, std::size_t n);
127+
128+
private:
129+
Alloc m_alloc;
130+
T *m_begin;
131+
T *m_end;
132+
T *m_cap;
133+
};
134+
135+
template <class T, class Alloc>
136+
bool operator==(const vector<T, Alloc> &lhs, const vector<T, Alloc> &rhs);
137+
138+
template <class T, class Alloc>
139+
auto operator<=>(const vector<T, Alloc> &lhs, const vector<T, Alloc> &rhs);
140+
141+
template <class T, class Alloc>
142+
void swap(vector<T, Alloc> &lhs, vector<T, Alloc> &rhs) noexcept;
143+
144+
template <class T, class Alloc, class U>
145+
typename vector<T, Alloc>::size_type erase(vector<T, Alloc> &c, const U &val);
146+
147+
template <class T, class Alloc, class Pred>
148+
typename vector<T, Alloc>::size_type erase_if(vector<T, Alloc> &c, Pred pred);
149+
150+
/* -------------------------------------------------------------------------- */
151+
/* public member functions */
152+
/* -------------------------------------------------------------------------- */
153+
154+
/* -------------------------------- construct ------------------------------- */
155+
template <class T, class Alloc>
156+
vector<T, Alloc>::vector() noexcept(noexcept(Alloc()))
157+
: m_begin(nullptr), m_end(nullptr), m_cap(nullptr) {}
158+
159+
template <class T, class Alloc>
160+
vector<T, Alloc>::vector(const Alloc &alloc) noexcept : m_alloc(alloc) {}
161+
162+
template <class T, class Alloc>
163+
vector<T, Alloc>::vector(std::size_t n, const Alloc &alloc) : m_alloc(alloc) {
164+
if (n > 0) {
165+
this->allocate(n);
166+
this->construct(n);
167+
} else {
168+
m_begin = m_end = m_cap = nullptr;
169+
}
170+
}
171+
172+
template <class T, class Alloc>
173+
vector<T, Alloc>::vector(std::size_t n, const T &val, const Alloc &alloc)
174+
: m_alloc(alloc) {
175+
if (n > 0) {
176+
this->allocate(n);
177+
this->construct(n, val);
178+
} else {
179+
m_begin = m_end = m_cap = nullptr;
180+
}
181+
}
182+
183+
template <class T, class Alloc>
184+
template <std::forward_iterator ForwardIter>
185+
requires std::constructible_from<T, std::iter_reference_t<ForwardIter>>
186+
vector<T, Alloc>::vector(
187+
ForwardIter first, ForwardIter last, const Alloc &alloc
188+
)
189+
: m_alloc(alloc) {
190+
std::size_t n = std::distance(first, last);
191+
if (n > 0) {
192+
this->allocate(n);
193+
this->construct(first, last, n);
194+
} else {
195+
m_begin = m_end = m_cap = nullptr;
196+
}
197+
}
198+
199+
template <class T, class Alloc>
200+
template <std::input_iterator InputIterator>
201+
requires std::constructible_from<T, std::iter_reference_t<InputIterator>> &&
202+
(!std::forward_iterator<InputIterator>) &&
203+
(std::movable<T> || std::copyable<T>)
204+
vector<T, Alloc>::vector(
205+
InputIterator first, InputIterator last, const Alloc &alloc
206+
) {
207+
static_assert(
208+
true, "tinystl::vector does not support construction from input iterators."
209+
);
210+
}
211+
212+
template <class T, class Alloc>
213+
vector<T, Alloc>::vector(std::initializer_list<T> init, const Alloc &alloc)
214+
: m_alloc(alloc) {
215+
std::size_t n = init.size();
216+
if (n > 0) {
217+
this->allocate(n);
218+
this->construct(init.begin(), init.end(), n);
219+
} else {
220+
m_begin = m_end = m_cap = nullptr;
221+
}
222+
}
223+
224+
/* ----------------------------- copy construct ----------------------------- */
225+
template <class T, class Alloc>
226+
vector<T, Alloc>::vector(const vector &other)
227+
: m_alloc(
228+
alloc_traits::select_on_container_copy_construction(other.m_alloc)
229+
) {
230+
std::size_t n = other.size();
231+
if (n > 0) {
232+
this->allocate(n);
233+
this->construct(other.begin(), other.end(), n);
234+
} else {
235+
m_end = m_cap = m_begin = nullptr;
236+
}
237+
}
238+
239+
template <class T, class Alloc>
240+
vector<T, Alloc>::vector(const vector &other, const Alloc &alloc)
241+
: m_alloc(alloc) {
242+
std::size_t n = other.size();
243+
if (n > 0) {
244+
this->allocate(n);
245+
this->construct(other.begin(), other.end(), n);
246+
} else {
247+
m_begin = m_end = m_cap = nullptr;
248+
}
249+
}
250+
251+
/* ----------------------------- move construct ----------------------------- */
252+
template <class T, class Alloc>
253+
vector<T, Alloc>::vector(vector &&other) noexcept
254+
: m_alloc(std::move(other.m_alloc)) {
255+
m_begin = other.m_begin;
256+
m_end = other.m_end;
257+
m_cap = other.m_cap;
258+
other.m_begin = other.m_end = other.m_cap = nullptr;
259+
}
260+
261+
template <class T, class Alloc>
262+
vector<T, Alloc>::vector(vector &&other, const Alloc &alloc) : m_alloc(alloc) {
263+
if (m_alloc == other.m_alloc) {
264+
m_begin = other.m_begin;
265+
m_end = other.m_end;
266+
m_cap = other.m_cap;
267+
other.m_begin = other.m_end = other.m_cap = nullptr;
268+
} else {
269+
std::size_t n = other.size();
270+
if (n > 0) {
271+
this->allocate(n);
272+
this->construct(std::make_move_iterator(other.begin()),
273+
std::make_move_iterator(other.end()), n);
274+
} else {
275+
m_begin = m_end = m_cap = nullptr;
276+
}
277+
}
278+
}
279+
280+
/* -------------------------------------------------------------------------- */
281+
/* private member functions */
282+
/* -------------------------------------------------------------------------- */
283+
template <class T, class Alloc>
284+
void vector<T, Alloc>::throw_length_error() {
285+
throw std::length_error("vector");
286+
}
287+
288+
template <class T, class Alloc>
289+
void vector<T, Alloc>::allocate(std::size_t n) {
290+
if (n > this->max_size()) {
291+
this->throw_length_error();
292+
} else {
293+
m_begin = alloc_traits::allocate(m_alloc, n);
294+
m_cap = m_begin + n;
295+
}
296+
}
297+
298+
template <class T, class Alloc>
299+
void vector<T, Alloc>::construct(std::size_t n) {
300+
m_end = m_begin;
301+
for (std::size_t i = 0; i < n; ++i) {
302+
alloc_traits::construct(m_alloc, m_end);
303+
++m_end;
304+
}
305+
}
306+
307+
template <class T, class Alloc>
308+
void vector<T, Alloc>::construct(std::size_t n, const T& val) {
309+
m_end = m_begin;
310+
for (std::size_t i = 0; i < n; ++i) {
311+
alloc_traits::construct(m_alloc, m_end, val);
312+
++m_end;
313+
}
314+
}
315+
316+
template <class T, class Alloc>
317+
template <class InputIterator, class Sential>
318+
void vector<T, Alloc>::construct(
319+
InputIterator first, Sential last, std::size_t n
320+
) {
321+
m_end = m_begin;
322+
for (std::size_t i = 0; i < n; ++i) {
323+
alloc_traits::construct(m_alloc, m_end, *first);
324+
++m_end;
325+
++first;
326+
}
327+
}
328+
} // namespace tinystl

0 commit comments

Comments
 (0)