|
@@ -15,10 +15,15 @@ public:
|
|
|
class iterator;
|
|
|
|
|
|
using value_type = T;
|
|
|
- using pointer_type = value_type*;
|
|
|
- using reference_type = value_type&;
|
|
|
- using iterator_type = iterator<value_type*>;
|
|
|
- using const_iterator_type = iterator<const value_type*>;
|
|
|
+ using pointer_type = std::add_pointer_t<value_type>;
|
|
|
+ using reference_type = std::add_lvalue_reference_t<value_type>;
|
|
|
+ using iterator_type = iterator<pointer_type>;
|
|
|
+
|
|
|
+ using const_value_type = std::add_const_t<value_type>;
|
|
|
+ using const_pointer_type = std::add_pointer_t<const_value_type>;
|
|
|
+ using const_reference_type = std::add_lvalue_reference_t<const_value_type>;
|
|
|
+ using const_iterator_type = iterator<const_pointer_type>;
|
|
|
+
|
|
|
using size_type = size_t;
|
|
|
using difference_type = ssize_t;
|
|
|
using index_type = size_type;
|
|
@@ -32,105 +37,107 @@ public:
|
|
|
using Reference = std::add_lvalue_reference_t<Value>;
|
|
|
|
|
|
public:
|
|
|
- constexpr iterator(const iterator& iter) noexcept
|
|
|
- : p(iter.p)
|
|
|
- {
|
|
|
- }
|
|
|
+ explicit constexpr iterator(Pointer p) noexcept
|
|
|
+ : p(p) {}
|
|
|
|
|
|
+ constexpr iterator(const iterator& iter) noexcept
|
|
|
+ : p(iter.p) {}
|
|
|
constexpr iterator(iterator&& iter) noexcept
|
|
|
- : p(iter.p)
|
|
|
- {
|
|
|
- iter.p = nullptr;
|
|
|
- }
|
|
|
+ : p(std::exchange(iter.p, nullptr)) {}
|
|
|
|
|
|
constexpr iterator& operator=(const iterator& iter)
|
|
|
{
|
|
|
p = iter.p;
|
|
|
return *this;
|
|
|
}
|
|
|
-
|
|
|
- explicit constexpr iterator(Pointer p) noexcept
|
|
|
- : p(p)
|
|
|
+ constexpr iterator& operator=(iterator&& iter)
|
|
|
{
|
|
|
+ p = std::exchange(iter.p, nullptr);
|
|
|
+ return *this;
|
|
|
}
|
|
|
|
|
|
constexpr bool operator==(const iterator& iter) const noexcept
|
|
|
- {
|
|
|
- return this->p == iter.p;
|
|
|
- }
|
|
|
-
|
|
|
+ { return this->p == iter.p; }
|
|
|
constexpr bool operator!=(const iterator& iter) const noexcept
|
|
|
- {
|
|
|
- return !(*this == iter);
|
|
|
- }
|
|
|
+ { return !operator==(iter); }
|
|
|
|
|
|
constexpr iterator& operator++(void) noexcept
|
|
|
- {
|
|
|
- ++p;
|
|
|
- return *this;
|
|
|
- }
|
|
|
-
|
|
|
+ { ++p; return *this; }
|
|
|
constexpr iterator operator++(int) noexcept
|
|
|
- {
|
|
|
- iterator iter(*this);
|
|
|
- ++p;
|
|
|
- return iter;
|
|
|
- }
|
|
|
+ { iterator iter(*this); ++p; return iter; }
|
|
|
|
|
|
constexpr iterator& operator--(void) noexcept
|
|
|
- {
|
|
|
- --p;
|
|
|
- return *this;
|
|
|
- }
|
|
|
-
|
|
|
+ { --p; return *this; }
|
|
|
constexpr iterator operator--(int) noexcept
|
|
|
- {
|
|
|
- iterator iter(*this);
|
|
|
- --p;
|
|
|
- return iter;
|
|
|
- }
|
|
|
+ { iterator iter(*this); --p; return iter; }
|
|
|
|
|
|
constexpr iterator operator+(size_type n) noexcept
|
|
|
- {
|
|
|
- iterator iter(p + n);
|
|
|
- return iter;
|
|
|
- }
|
|
|
-
|
|
|
+ { return iterator { p + n }; }
|
|
|
constexpr iterator operator-(size_type n) noexcept
|
|
|
- {
|
|
|
- iterator iter(p - n);
|
|
|
- return iter;
|
|
|
- }
|
|
|
+ { return iterator { p - n }; }
|
|
|
|
|
|
constexpr Reference operator*(void) const noexcept
|
|
|
- {
|
|
|
- return *p;
|
|
|
- }
|
|
|
-
|
|
|
+ { return *p; }
|
|
|
constexpr Pointer operator&(void) const noexcept
|
|
|
- {
|
|
|
- return p;
|
|
|
- }
|
|
|
-
|
|
|
+ { return p; }
|
|
|
constexpr Pointer operator->(void) const noexcept
|
|
|
- {
|
|
|
- return p;
|
|
|
- }
|
|
|
+ { return p; }
|
|
|
|
|
|
protected:
|
|
|
Pointer p;
|
|
|
};
|
|
|
|
|
|
-public:
|
|
|
- explicit constexpr vector(size_type capacity = 1) noexcept
|
|
|
- : m_arr(nullptr)
|
|
|
- , m_size(0)
|
|
|
+protected:
|
|
|
+ constexpr const value_type& _at(index_type i) const
|
|
|
+ { return m_arr[i]; }
|
|
|
+ constexpr value_type& _at(index_type i)
|
|
|
+ { return m_arr[i]; }
|
|
|
+
|
|
|
+ // assert(n >= m_size)
|
|
|
+ constexpr void _reallocate_safe(size_type n)
|
|
|
+ {
|
|
|
+ auto* newptr = allocator_traits<allocator_type>::allocate(n);
|
|
|
+ for (size_t i = 0; i < m_size; ++i) {
|
|
|
+ allocator_traits<allocator_type>::construct(newptr + i, std::move(_at(i)));
|
|
|
+ allocator_traits<allocator_type>::deconstruct(m_arr + i);
|
|
|
+ }
|
|
|
+
|
|
|
+ allocator_traits<allocator_type>::deallocate(m_arr);
|
|
|
+ m_arr = newptr;
|
|
|
+ m_capacity = n;
|
|
|
+ }
|
|
|
+
|
|
|
+ // make m_capacity >= n >= m_size
|
|
|
+ constexpr void _pre_resize(size_type n)
|
|
|
{
|
|
|
- resize(capacity);
|
|
|
+ if (n == m_size)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (n < m_size) {
|
|
|
+ while (n < m_size)
|
|
|
+ pop_back();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ assert(n > m_size);
|
|
|
+ reserve(n);
|
|
|
}
|
|
|
|
|
|
+public:
|
|
|
+ constexpr vector() noexcept
|
|
|
+ : m_arr(nullptr)
|
|
|
+ , m_capacity(0)
|
|
|
+ , m_size(0) { }
|
|
|
+
|
|
|
+ explicit constexpr vector(size_type size)
|
|
|
+ : vector()
|
|
|
+ { resize(size); }
|
|
|
+
|
|
|
+ constexpr vector(size_type size, const value_type& value)
|
|
|
+ : vector()
|
|
|
+ { resize(size, value); }
|
|
|
+
|
|
|
constexpr vector(const vector& arr) noexcept
|
|
|
- : vector(arr.capacity())
|
|
|
+ : vector()
|
|
|
{
|
|
|
for (const auto& item : arr)
|
|
|
push_back(item);
|
|
@@ -138,61 +145,62 @@ public:
|
|
|
|
|
|
constexpr vector(vector&& arr) noexcept
|
|
|
{
|
|
|
- m_arr = arr.m_arr;
|
|
|
- m_capacity = arr.m_capacity;
|
|
|
- m_size = arr.m_size;
|
|
|
-
|
|
|
- arr.m_arr = nullptr;
|
|
|
- arr.m_capacity = 0;
|
|
|
- arr.m_size = 0;
|
|
|
+ m_arr = std::exchange(arr.m_arr, nullptr);
|
|
|
+ m_capacity = std::exchange(arr.m_capacity, 0);
|
|
|
+ m_size = std::exchange(arr.m_size, 0);
|
|
|
}
|
|
|
|
|
|
constexpr vector& operator=(vector&& arr)
|
|
|
{
|
|
|
resize(0);
|
|
|
- m_arr = arr.m_arr;
|
|
|
- m_capacity = arr.m_capacity;
|
|
|
- m_size = arr.m_size;
|
|
|
+ shrink_to_fit();
|
|
|
|
|
|
- arr.m_arr = nullptr;
|
|
|
- arr.m_capacity = 0;
|
|
|
- arr.m_size = 0;
|
|
|
+ m_arr = std::exchange(arr.m_arr, nullptr);
|
|
|
+ m_capacity = std::exchange(arr.m_capacity, 0);
|
|
|
+ m_size = std::exchange(arr.m_size, 0);
|
|
|
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
constexpr vector& operator=(const vector& arr)
|
|
|
{
|
|
|
- return operator=(vector(arr));
|
|
|
+ return operator=(vector {arr});
|
|
|
}
|
|
|
|
|
|
constexpr ~vector() noexcept
|
|
|
{
|
|
|
resize(0);
|
|
|
+ shrink_to_fit();
|
|
|
}
|
|
|
|
|
|
- constexpr void resize(size_type n)
|
|
|
+ constexpr void shrink_to_fit()
|
|
|
{
|
|
|
- if (m_size == n)
|
|
|
+ if (m_size == m_capacity)
|
|
|
return;
|
|
|
|
|
|
- value_type* new_ptr = allocator_traits<allocator_type>::allocate(n);
|
|
|
- assert(!n || (n && new_ptr));
|
|
|
+ _reallocate_safe(m_size);
|
|
|
+ }
|
|
|
|
|
|
- m_capacity = n;
|
|
|
- size_t orig_size = m_size;
|
|
|
- if (m_size > m_capacity)
|
|
|
- m_size = m_capacity;
|
|
|
+ constexpr void reserve(size_type n)
|
|
|
+ {
|
|
|
+ if (n <= m_capacity)
|
|
|
+ return;
|
|
|
|
|
|
- for (size_t i = 0; i < m_size; ++i)
|
|
|
- allocator_traits<allocator_type>::construct(new_ptr + i, _at(i));
|
|
|
+ _reallocate_safe(n);
|
|
|
+ }
|
|
|
|
|
|
- for (size_t i = 0; i < orig_size; ++i)
|
|
|
- allocator_traits<allocator_type>::deconstruct(m_arr + i);
|
|
|
+ constexpr void resize(size_type n)
|
|
|
+ {
|
|
|
+ _pre_resize(n);
|
|
|
+ while (n > m_size)
|
|
|
+ emplace_back();
|
|
|
+ }
|
|
|
|
|
|
- if (m_arr)
|
|
|
- allocator_traits<allocator_type>::deallocate(m_arr);
|
|
|
- m_arr = new_ptr;
|
|
|
+ constexpr void resize(size_type n, const value_type& value)
|
|
|
+ {
|
|
|
+ _pre_resize(n);
|
|
|
+ while (n > m_size)
|
|
|
+ emplace_back(value);
|
|
|
}
|
|
|
|
|
|
// TODO: find
|
|
@@ -225,21 +233,15 @@ public:
|
|
|
// }
|
|
|
|
|
|
constexpr value_type* data(void) noexcept
|
|
|
- {
|
|
|
- return m_arr;
|
|
|
- }
|
|
|
-
|
|
|
+ { return m_arr; }
|
|
|
constexpr const value_type* data(void) const noexcept
|
|
|
- {
|
|
|
- return m_arr;
|
|
|
- }
|
|
|
+ { return m_arr; }
|
|
|
|
|
|
constexpr value_type& at(index_type i) noexcept
|
|
|
{
|
|
|
assert(i + 1 <= this->size());
|
|
|
return _at(i);
|
|
|
}
|
|
|
-
|
|
|
constexpr const value_type& at(index_type i) const noexcept
|
|
|
{
|
|
|
assert(i + 1 <= this->size());
|
|
@@ -247,19 +249,14 @@ public:
|
|
|
}
|
|
|
|
|
|
constexpr value_type& operator[](index_type i) noexcept
|
|
|
- {
|
|
|
- return at(i);
|
|
|
- }
|
|
|
-
|
|
|
+ { return at(i); }
|
|
|
constexpr const value_type& operator[](index_type i) const noexcept
|
|
|
- {
|
|
|
- return at(i);
|
|
|
- }
|
|
|
+ { return at(i); }
|
|
|
|
|
|
constexpr void push_back(const value_type& v) noexcept
|
|
|
{
|
|
|
if (m_size == m_capacity)
|
|
|
- resize(m_capacity * 2);
|
|
|
+ reserve(m_capacity ? m_capacity * 2 : 1);
|
|
|
allocator_traits<allocator_type>::construct(m_arr + m_size, v);
|
|
|
++m_size;
|
|
|
}
|
|
@@ -267,7 +264,7 @@ public:
|
|
|
constexpr void push_back(value_type&& v) noexcept
|
|
|
{
|
|
|
if (m_size == m_capacity)
|
|
|
- resize(m_capacity * 2);
|
|
|
+ reserve(m_capacity ? m_capacity * 2 : 1);
|
|
|
allocator_traits<allocator_type>::construct(m_arr + m_size, std::move(v));
|
|
|
++m_size;
|
|
|
}
|
|
@@ -276,76 +273,54 @@ public:
|
|
|
constexpr iterator_type emplace_back(Args&&... args)
|
|
|
{
|
|
|
push_back(value_type(std::forward<Args>(args)...));
|
|
|
- return back();
|
|
|
+ return iterator_type(m_arr + m_size - 1);
|
|
|
}
|
|
|
|
|
|
constexpr void pop_back(void) noexcept
|
|
|
{
|
|
|
- allocator_traits<allocator_type>::deconstruct(&*back());
|
|
|
+ assert(m_size > 0);
|
|
|
+ allocator_traits<allocator_type>::deconstruct(m_arr + m_size - 1);
|
|
|
--m_size;
|
|
|
}
|
|
|
|
|
|
constexpr size_type size(void) const noexcept
|
|
|
- {
|
|
|
- return m_size;
|
|
|
- }
|
|
|
+ { return m_size; }
|
|
|
|
|
|
constexpr size_type capacity(void) const noexcept
|
|
|
- {
|
|
|
- return m_capacity;
|
|
|
- }
|
|
|
+ { return m_capacity; }
|
|
|
|
|
|
constexpr const_iterator_type cbegin() const noexcept
|
|
|
- {
|
|
|
- return const_iterator_type(m_arr);
|
|
|
- }
|
|
|
+ { return const_iterator_type(m_arr); }
|
|
|
|
|
|
constexpr const_iterator_type cend() const noexcept
|
|
|
- {
|
|
|
- return const_iterator_type(m_arr + m_size);
|
|
|
- }
|
|
|
+ { return const_iterator_type(m_arr + m_size); }
|
|
|
|
|
|
constexpr iterator_type begin() noexcept
|
|
|
- {
|
|
|
- return iterator_type(m_arr);
|
|
|
- }
|
|
|
-
|
|
|
+ { return iterator_type(m_arr); }
|
|
|
constexpr const_iterator_type begin() const noexcept
|
|
|
- {
|
|
|
- return cbegin();
|
|
|
- }
|
|
|
+ { return cbegin(); }
|
|
|
|
|
|
constexpr iterator_type end() noexcept
|
|
|
- {
|
|
|
- return iterator_type(m_arr + m_size);
|
|
|
- }
|
|
|
-
|
|
|
+ { return iterator_type(m_arr + m_size); }
|
|
|
constexpr const_iterator_type end() const noexcept
|
|
|
- {
|
|
|
- return cend();
|
|
|
- }
|
|
|
+ { return cend(); }
|
|
|
|
|
|
- constexpr iterator_type back() noexcept
|
|
|
+ constexpr value_type& back() noexcept
|
|
|
{
|
|
|
- return iterator_type(m_arr + m_size - 1);
|
|
|
+ assert(m_size != 0);
|
|
|
+ return at(m_size - 1);
|
|
|
}
|
|
|
-
|
|
|
- constexpr const_iterator_type back() const noexcept
|
|
|
+ constexpr const value_type& back() const noexcept
|
|
|
{
|
|
|
- return const_iterator_type(m_arr + m_size - 1);
|
|
|
+ assert(m_size != 0);
|
|
|
+ return at(m_size - 1);
|
|
|
}
|
|
|
|
|
|
constexpr bool empty(void) const noexcept
|
|
|
- {
|
|
|
- return size() == 0;
|
|
|
- }
|
|
|
+ { return m_size == 0; }
|
|
|
|
|
|
constexpr void clear(void)
|
|
|
- {
|
|
|
- for (size_t i = 0; i < size(); ++i)
|
|
|
- allocator_traits<allocator_type>::deconstruct(m_arr + i);
|
|
|
- m_size = 0;
|
|
|
- }
|
|
|
+ { resize(0); }
|
|
|
|
|
|
// TODO
|
|
|
|
|
@@ -355,16 +330,6 @@ public:
|
|
|
// iterator_type cr_start() noexcept;
|
|
|
// iterator_type cr_end() noexcept;
|
|
|
|
|
|
-protected:
|
|
|
- inline constexpr const value_type& _at(index_type i) const
|
|
|
- {
|
|
|
- return m_arr[i];
|
|
|
- }
|
|
|
- inline constexpr value_type& _at(index_type i)
|
|
|
- {
|
|
|
- return m_arr[i];
|
|
|
- }
|
|
|
-
|
|
|
protected:
|
|
|
T* m_arr;
|
|
|
size_type m_capacity;
|