123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501 |
- #ifndef __GBLIBCPP_VECTOR__
- #define __GBLIBCPP_VECTOR__
- #include <bits/iter_ops>
- #include <functional>
- #include <memory>
- #include <initializer_list>
- #include <cstddef>
- namespace std {
- template <typename T, typename Allocator = std::allocator<T>>
- class vector {
- public:
- using value_type = T;
- using allocator_type = Allocator;
- using size_type = std::size_t;
- using difference_type = std::ptrdiff_t;
- using reference = T&;
- using const_reference = const T&;
- template <bool Const>
- class _iterator {
- public:
- // TODO:
- // using iterator_category = std::random_access_iterator_tag;
- using value_type = std::conditional_t<Const, const T, T>;
- using difference_type = std::ptrdiff_t;
- using pointer = std::add_pointer_t<value_type>;
- using reference = std::add_lvalue_reference_t<value_type>;
- private:
- T* m_ptr;
- public:
- constexpr _iterator(void) noexcept : m_ptr() {}
- constexpr explicit _iterator(const T* ptr) noexcept
- : m_ptr(const_cast<T*>(ptr)) {}
- constexpr _iterator(const _iterator& other) noexcept = default;
- constexpr _iterator(_iterator&& other) noexcept = default;
- constexpr _iterator& operator=(const _iterator& other) noexcept = default;
- constexpr _iterator& operator=(_iterator&& other) noexcept = default;
- constexpr bool operator==(const _iterator& other) const noexcept = default;
- constexpr reference operator*() const noexcept { return *m_ptr; }
- constexpr pointer operator&() const noexcept
- { return std::addressof(this->operator*()); }
- constexpr pointer operator->() const noexcept
- { return this->operator&(); }
- constexpr _iterator& operator++() noexcept
- { ++m_ptr; return *this; }
- constexpr _iterator operator++(int) noexcept
- { _iterator ret(m_ptr); (void)this->operator++(); return ret; }
- constexpr _iterator& operator--(void) noexcept
- { --m_ptr; return *this; }
- constexpr _iterator operator--(int) noexcept
- { _iterator ret(m_ptr); (void)this->operator--(); return ret; }
- constexpr _iterator& operator+=(difference_type n) noexcept
- { m_ptr += n; return *this; }
- constexpr _iterator& operator-=(difference_type n) noexcept
- { m_ptr -= n; return *this; }
- constexpr _iterator operator+(difference_type n) const noexcept
- { return _iterator { m_ptr + n }; }
- constexpr _iterator operator-(difference_type n) const noexcept
- { return _iterator { m_ptr - n }; }
- constexpr difference_type operator-(const _iterator& other) const noexcept
- { return m_ptr - other.m_ptr; }
- constexpr reference operator[](difference_type n) const noexcept
- { return m_ptr[n]; }
- constexpr operator bool() { return m_ptr; }
- constexpr operator _iterator<true>() { return _iterator<true> { m_ptr }; }
- constexpr operator _iterator<false>() { return _iterator<false> { m_ptr }; }
- constexpr operator const T*() { return m_ptr; }
- };
- private:
- using alloc_traits = std::allocator_traits<Allocator>;
- public:
- using pointer = typename alloc_traits::pointer;
- using const_pointer = typename alloc_traits::const_pointer;
- using iterator = _iterator<false>;
- using const_iterator = _iterator<true>;
- private:
- T* m_data;
- size_type m_size;
- size_type m_capacity;
- allocator_type m_alloc;
- private:
- // assert(n >= m_size)
- constexpr void _reallocate_safe(size_type n)
- {
- T* newptr = nullptr;
- if (n)
- newptr = alloc_traits::allocate(m_alloc, n);
- for (size_t i = 0; i < m_size; ++i) {
- if (n)
- alloc_traits::construct(m_alloc, newptr + i, std::move(m_data[i]));
- alloc_traits::destroy(m_alloc, m_data + i);
- }
- alloc_traits::deallocate(m_alloc, m_data, m_capacity);
- m_data = newptr;
- m_capacity = n;
- }
- // make m_capacity >= n >= m_size
- constexpr void _pre_resize(size_type n)
- {
- if (n < m_size) {
- while (n < m_size)
- pop_back();
- }
- else if (n > m_size) {
- reserve(n);
- }
- }
- public:
- constexpr vector(void)
- noexcept(noexcept(Allocator()))
- : m_data(), m_size(), m_capacity(), m_alloc() {}
- constexpr explicit vector(const Allocator& alloc) noexcept
- : m_data(), m_size(), m_capacity(), m_alloc(alloc) {}
- constexpr vector(size_type n, const T& val,
- const Allocator& alloc = Allocator())
- : vector(alloc) { resize(n, val); }
- constexpr explicit vector(size_type n,
- const Allocator& alloc = Allocator())
- : vector(alloc) { resize(n); }
- // TODO: check whether InputIter satisfies LegacyInputIterator
- template <typename InputIter>
- constexpr vector(InputIter first, InputIter last,
- const Allocator& alloc = Allocator())
- : vector(alloc) { insert(cbegin(), first, last); }
- constexpr vector(const vector& other)
- : vector(std::allocator_traits<allocator_type>::
- select_on_container_copy_construction(other.m_alloc))
- { insert(cbegin(), other.begin(), other.end()); }
- constexpr vector(const vector& other, const Allocator& alloc)
- : vector(alloc) { insert(cbegin(), other.begin(), other.end()); }
- constexpr vector(vector&& other) noexcept
- : m_data(std::exchange(other.m_data, nullptr))
- , m_size(std::exchange(other.m_size, 0))
- , m_capacity(std::exchange(other.m_capacity, 0))
- , m_alloc(std::move(other.m_alloc)) {}
-
- constexpr vector(vector&& other, const Allocator& alloc)
- : vector(alloc)
- {
- if (alloc == other.get_allocator()) {
- m_data = std::exchange(other.m_data, nullptr);
- m_size = std::exchange(other.m_size, 0);
- m_capacity = std::exchange(other.m_capacity, 0);
- } else {
- // TODO: std::move_iterator
- // insert(cbegin(), std::make_move_iterator(other.begin()),
- // std::make_move_iterator(other.end()));
- for (auto& item : other)
- emplace_back(std::move(item));
- }
- }
- constexpr vector(std::initializer_list<T> init,
- const Allocator& alloc = Allocator())
- : vector(alloc) { insert(cbegin(), init.begin(), init.end()); }
- constexpr ~vector()
- {
- resize(0);
- shrink_to_fit();
- }
- constexpr vector& operator=(const vector& other)
- {
- clear();
- if constexpr (alloc_traits::
- propagate_on_container_copy_assignment::value) {
- if (m_alloc != other.m_alloc)
- shrink_to_fit();
- m_alloc = other.m_alloc;
- }
- insert(cbegin(), other.begin(), other.end());
- return *this;
- }
- constexpr vector& operator=(vector&& other)
- {
- clear();
- if constexpr (alloc_traits::
- propagate_on_container_move_assignment::value) {
- shrink_to_fit();
- m_alloc = std::move(other.m_alloc);
- }
- else {
- if (m_alloc != other.m_alloc) {
- // TODO: std::move_iterator
- for (auto& item : other)
- emplace_back(std::move(item));
- return *this;
- }
- shrink_to_fit();
- }
- m_data = std::exchange(other.m_data, nullptr);
- m_size = std::exchange(other.m_size, 0);
- m_capacity = std::exchange(other.m_capacity, 0);
- return *this;
- }
- constexpr vector& operator=(std::initializer_list<T> init)
- {
- assign(init.begin(), init.end());
- return *this;
- }
- constexpr void assign(size_type n, const T& val)
- {
- clear();
- resize(n, val);
- }
- // TODO: check whether InputIter satisfies LegacyInputIterator
- template <typename InputIter>
- constexpr void assign(InputIter first, InputIter last)
- {
- clear();
- insert(cbegin(), first, last);
- }
- constexpr void assign(std::initializer_list<T> init)
- {
- clear();
- insert(cbegin(), init.begin(), init.end());
- }
- constexpr allocator_type get_allocator(void) const noexcept
- { return m_alloc; }
- constexpr reference at(size_type pos)
- {
- // TODO: exceptions
- // if (pos >= sz)
- // throw std::out_of_range("vector::at");
- return m_data[pos];
- }
- constexpr const_reference at(size_type pos) const
- {
- // TODO: exceptions
- // if (pos >= sz)
- // throw std::out_of_range("vector::at");
- return m_data[pos];
- }
- constexpr reference operator[](size_type pos) noexcept
- { return m_data[pos]; }
- constexpr const_reference operator[](size_type pos) const noexcept
- { return m_data[pos]; }
- constexpr reference front() noexcept
- { return m_data[0]; }
- constexpr const_reference front() const noexcept
- { return m_data[0]; }
- constexpr reference back() noexcept
- { return m_data[m_size - 1]; }
- constexpr const_reference back() const noexcept
- { return m_data[m_size - 1]; }
- constexpr T* data(void) noexcept
- { return m_data; }
- constexpr const T* data(void) const noexcept
- { return m_data; }
- // TODO: std::reverse_iterator
- constexpr iterator begin() noexcept
- { return iterator { m_data }; }
- constexpr const_iterator begin() const noexcept
- { return const_iterator { m_data }; }
- constexpr const_iterator cbegin() const noexcept
- { return const_iterator { m_data }; }
- constexpr iterator end() noexcept
- { return iterator { m_data + m_size }; }
- constexpr const_iterator end() const noexcept
- { return const_iterator { m_data + m_size }; }
- constexpr const_iterator cend() const noexcept
- { return const_iterator { m_data + m_size }; }
- [[nodiscard]] constexpr bool empty() const noexcept
- { return m_size == 0; }
- constexpr size_type size() const noexcept
- { return m_size; }
- constexpr size_type capacity() const noexcept
- { return m_capacity; }
- constexpr void reserve(size_type new_cap)
- {
- if (new_cap > m_capacity)
- _reallocate_safe(new_cap);
- }
- constexpr void resize(size_type n)
- {
- _pre_resize(n);
- while (n > m_size)
- emplace_back();
- }
- constexpr void resize(size_type n, const value_type& value)
- {
- _pre_resize(n);
- while (n > m_size)
- emplace_back(value);
- }
- constexpr void shrink_to_fit()
- {
- if (m_size != m_capacity)
- _reallocate_safe(m_size);
- }
- constexpr void clear() noexcept
- { resize(0); }
- template <typename... Args>
- constexpr iterator emplace(const_iterator pos, Args&&... args)
- {
- size_type idx = pos - m_data;
- if (!pos)
- reserve(1);
- if (m_size == m_capacity)
- reserve(m_capacity * 2);
- for (size_type i = m_size; i > idx; --i)
- alloc_traits::construct(m_alloc, m_data + i, std::move(m_data[i-1]));
- alloc_traits::construct(m_alloc, m_data + idx,
- std::forward<Args>(args)...);
- ++m_size;
- return iterator { m_data + idx };
- }
- constexpr iterator insert(const_iterator pos, T&& val)
- { return emplace(pos, std::move(val)); }
- constexpr iterator insert(const_iterator pos, const T& val)
- { return emplace(pos, val); }
- constexpr iterator insert(const_iterator pos, size_type n, const T& val)
- {
- if (!n)
- return pos;
- size_type idx = pos - m_data;
- if (!pos)
- reserve(n);
- if (m_size + n > m_capacity)
- reserve(m_size + n);
- for (size_type i = m_size + n - 1; i >= idx + n; --i)
- alloc_traits::construct(m_alloc, m_data + i, std::move(m_data[i-n]));
- for (size_type i = idx; i < idx + n; ++i)
- alloc_traits::construct(m_alloc, m_data + i, val);
- m_size += n;
- return iterator { m_data + idx };
- }
- // TODO: LegacyInputIterator version of this
- template <typename ForwardIter>
- constexpr iterator insert(const_iterator pos,
- ForwardIter first, ForwardIter last)
- {
- size_type idx = pos - m_data;
- size_type n = 0;
- ForwardIter tmp = first;
- while (tmp != last)
- ++n, ++tmp;
- if (!n)
- return pos;
- if (!pos)
- reserve(n);
- if (m_size + n > m_capacity)
- reserve(m_size + n);
- for (size_type i = m_size + n - 1; i >= idx + n; --i)
- alloc_traits::construct(m_alloc, m_data + i, std::move(m_data[i-n]));
- for (size_type i = idx; i < idx + n; ++i)
- alloc_traits::construct(m_alloc, m_data + i, *first++);
- m_size += n;
- return iterator { m_data + idx };
- }
- constexpr iterator insert(const_iterator pos, std::initializer_list<T> init)
- { return insert(pos, init.begin(), init.end()); }
- constexpr iterator erase(const_iterator pos)
- {
- size_type idx = pos - m_data;
- alloc_traits::destroy(m_alloc, m_data + idx);
- for (size_type i = idx; i < m_size - 1; ++i)
- alloc_traits::construct(m_alloc, m_data + i, std::move(m_data[i+1]));
- --m_size;
- return iterator { m_data + idx };
- }
- constexpr iterator erase(const_iterator first, const_iterator last)
- {
- size_type n = last - first;
- if (!n)
- return last;
- size_type idx = first - m_data;
- for (size_type i = idx; i < idx + n; ++i)
- alloc_traits::destroy(m_alloc, m_data + i);
- for (size_type i = idx; i < m_size - n; ++i)
- m_alloc.construct(m_data + i, std::move(m_data[i+n]));
- m_size -= n;
- return iterator { m_data + idx };
- }
- constexpr void push_back(const T& val) { insert(cend(), val); }
- constexpr void push_back(T&& val) { insert(cend(), std::move(val)); }
- template <typename... Args>
- constexpr void emplace_back(Args&&... args)
- { emplace(cend(), std::forward<Args>(args)...); }
- constexpr void pop_back() { erase(--cend()); }
- constexpr void swap(vector& other) noexcept(
- alloc_traits::propagate_on_container_swap::value
- || alloc_traits::is_always_equal::value)
- {
- if (alloc_traits::propagate_on_container_swap::value)
- std::swap(m_alloc, other.m_alloc);
- std::swap(m_data, other.m_data);
- std::swap(m_size, other.m_size);
- std::swap(m_capacity, other.m_capacity);
- }
- };
- template <typename T, typename Allocator>
- constexpr void swap(
- std::vector<T, Allocator>& lhs,
- std::vector<T, Allocator>& rhs) noexcept(noexcept(lhs.swap(rhs)))
- { lhs.swap(rhs); }
- template <typename T, typename Allocator, typename U>
- constexpr typename std::vector<T, Allocator>::size_type
- erase(std::vector<T, Allocator>& vec, const U& value)
- {
- typename std::vector<T, Allocator>::size_type n = 0;
- for (auto iter = vec.begin(); iter != vec.end(); ) {
- if (*iter == value) {
- iter = vec.erase(iter);
- ++n;
- } else {
- ++iter;
- }
- }
- return n;
- }
- template <typename T, typename Allocator, typename Pred>
- constexpr typename std::vector<T, Allocator>::size_type
- erase_if(std::vector<T, Allocator>& vec, Pred pred)
- {
- typename std::vector<T, Allocator>::size_type n = 0;
- for (auto iter = vec.begin(); iter != vec.end(); ) {
- if (pred(*iter)) {
- iter = vec.erase(iter);
- ++n;
- } else {
- ++iter;
- }
- }
- return n;
- }
- } // namespace std
- #endif
|