diff --git a/source/tinystl/container/vector.h b/source/tinystl/container/vector.h index ee93ebb..4f185b4 100644 --- a/source/tinystl/container/vector.h +++ b/source/tinystl/container/vector.h @@ -102,8 +102,14 @@ class vector { iterator insert(const_iterator pos, const_reference val); iterator insert(const_iterator pos, value_type &&val); iterator insert(const_iterator pos, size_type n, const_reference val); - template + template + requires std::constructible_from> + iterator insert(const_iterator pos, ForwardIter first, ForwardIter last); + template + requires std::constructible_from> && + (!std::forward_iterator) iterator insert(const_iterator pos, InputIter first, InputIter last); + iterator insert(const_iterator pos, std::initializer_list init); template iterator emplace(const_iterator pos, Args &&...args); iterator erase(const_iterator pos); @@ -136,6 +142,8 @@ class vector { void destruct(pointer new_last); + void move_to_insert(pointer first, pointer last, pointer dst_first); + private: Alloc m_alloc; pointer m_begin = nullptr; @@ -586,7 +594,7 @@ void vector::reserve(size_type n) { } m_begin = new_begin; - m_end = new_end; + m_end = new_end; m_cap = new_cap; } } @@ -640,12 +648,17 @@ vector::insert(const_iterator pos, const_reference val) { if (p == m_end) { this->construct(1, val); } else { - alloc_traits::consturct(m_alloc, m_end, std::move(*(m_end - 1))); - ++m_end; - std::move_backward(p, m_end - 2, m_end - 1); + this->move_to_insert(p, m_end, p + 1); + + const_pointer pval = std::pointer_traits::pointer_to(val); + const_pointer pp = std::to_address(p); + const_pointer pend = std::to_address(m_end); + if (!(pp <= pval && pval < pend)) { + pval += 1; + } + *p = val; } - return iterator(p); } else { size_type sz = this->recommend(this->size() + 1); pointer new_begin = alloc_traits::allocate(m_alloc, sz); @@ -673,9 +686,9 @@ vector::insert(const_iterator pos, const_reference val) { m_begin = new_begin; m_end = new_end; m_cap = new_cap; - - return iterator(m_begin + offset); } + + return iterator(p); } template @@ -688,12 +701,9 @@ vector::insert(const_iterator pos, value_type &&val) { alloc_traits::construct(m_alloc, p, std::move(val)); ++m_end; } else { - alloc_traits::construct(m_alloc, m_end, std::move(*(m_end - 1))); - ++m_end; - std::move_backward(p, m_end - 2, m_end - 1); + this->move_to_insert(p, m_end, p + 1); *p = std::move(val); } - return iterator(p); } else { size_type sz = this->recommend(this->size() + 1); pointer new_begin = alloc_traits::allocate(m_alloc, sz); @@ -701,7 +711,7 @@ vector::insert(const_iterator pos, value_type &&val) { pointer new_cap = new_begin + sz; if constexpr (std::is_nothrow_move_constructible_v) { - new_end = std::uninitialized_move(m_begin, p, new_begin); + new_end = std::uninitialized_move(m_begin, p, new_begin); } else { new_end = std::uninitialized_copy(m_begin, p, new_begin); } @@ -710,7 +720,7 @@ vector::insert(const_iterator pos, value_type &&val) { ++new_end; if constexpr (std::is_nothrow_move_constructible_v) { - new_end = std::uninitialized_move(p, m_end, new_end); + new_end = std::uninitialized_move(p, m_end, new_end); } else { new_end = std::uninitialized_copy(p, m_end, new_end); } @@ -721,20 +731,157 @@ vector::insert(const_iterator pos, value_type &&val) { m_begin = new_begin; m_end = new_end; m_cap = new_cap; - - return iterator(m_begin + offset); } + return iterator(p); } template typename vector::iterator vector::insert(const_iterator pos, size_type n, const_reference val) { + size_type offset = static_cast(std::distance(this->begin(), pos)); + pointer p = m_begin + offset; + if (n > 0) { + if (n <= static_cast(m_cap - m_end)) { + pointer old_end = m_end; + size_type old_n = n; + + size_type dx = static_cast(m_end - p); + if (n > dx) { + this->construct(n - dx, val); + n = dx; + } + + if (n > 0) { + this->move_to_insert(p, old_end, p + old_n); + + const_pointer pval = std::pointer_traits::pointer_to(val); + const_pointer pp = std::to_address(p); + const_pointer pend = std::to_address(m_end); + if (!(pp <= pval && pval < pend)) { + pval += old_n; + } + std::fill_n(p, n, *pval); + } + } else { + size_type sz = this->recommend(this->size() + n); + pointer new_begin = alloc_traits::allocate(m_alloc, sz); + pointer new_end = new_begin; + pointer new_cap = new_begin + sz; + + if constexpr (std::is_nothrow_move_constructible_v) { + new_end = std::uninitialized_move(m_begin, p, new_begin); + } else { + new_end = std::uninitialized_copy(m_begin, p, new_begin); + } + + for (size_type i = 0; i < n; ++i) { + alloc_traits::construct(m_alloc, new_end, val); + ++new_end; + } + + if constexpr (std::is_nothrow_move_constructible_v) { + new_end = std::uninitialized_move(p, m_end, new_end); + } else { + new_end = std::uninitialized_copy(p, m_end, new_end); + } + + this->destruct(m_begin); + this->deallocate(); + + m_begin = new_begin; + m_end = new_end; + m_cap = new_cap; + } + } + + return iterator(p); +} + +template +template + requires std::constructible_from> +typename vector::iterator vector::insert( + const_iterator pos, ForwardIter first, ForwardIter last +) { + size_type offset = static_cast(std::distance(this->begin(), pos)); + pointer p = m_begin + offset; + + difference_type n = std::distance(first, last); + + if (n > 0) { + if (n <= static_cast(m_cap - m_end)) { + pointer old_end = m_end; + + size_type dx = static_cast(m_end - p); + if (n > dx) { + ForwardIter m = std::next(first, dx); + this->construct(m, last, n - dx); + n = dx; + } + if (n > 0) { + this->move_to_insert(p, old_end, p + n); + std::copy_n(first, n, p); + } + } else { + size_type sz = this->recommend(this->size() + n); + pointer new_begin = alloc_traits::allocate(m_alloc, sz); + pointer new_end = new_begin; + pointer new_cap = new_begin + sz; + + if constexpr (std::is_move_constructible_v) { + new_end = std::uninitialized_move(m_begin, p, new_begin); + } else { + new_end = std::uninitialized_copy(m_begin, p, new_begin); + } + + for (size_type i = 0; i < n; ++i) { + alloc_traits::construct(m_alloc, new_end, *first); + ++new_end; + ++first; + } + + if constexpr (std::is_move_constructible_v) { + new_end = std::uninitialized_move(p, m_end, new_end); + } else { + new_end = std::uninitialized_copy(p, m_end, new_end); + } + + this->destruct(m_begin); + this->deallocate(); + + m_begin = new_begin; + m_end = new_end; + m_cap = new_cap; + } + } + + return iterator(p); +} + +template +template + requires std::constructible_from> && + (!std::forward_iterator) +typename vector::iterator +vector::insert(const_iterator pos, InputIter first, InputIter last) { + size_type offset = static_cast(std::distance(this->begin(), pos)); + pointer p = m_begin + offset; + pointer old_end = m_end; + + for (; first != last; ++first) { + this->emplace_back(*first); + } + + std::rotate(p, old_end, m_end); + + return iterator(p); } template -template typename vector::iterator -vector::insert(const_iterator pos, InputIter first, InputIter last) {} +vector::insert(const_iterator pos, std::initializer_list init) { + return insert(pos, init.begin(), init.end()); +} /* -------------------------------------------------------------------------- */ /* private member functions */ @@ -816,4 +963,20 @@ void vector::destruct(pointer new_last) { } m_end = new_last; } + +template +void vector::move_to_insert( + pointer from_s, pointer from_e, pointer to +) { + pointer from_mid = from_s + (m_end - to); + pointer new_end = m_end; + for (; from_mid < from_e; ++from_mid, ++new_end) { + alloc_traits::construct(m_alloc, new_end, std::move(*from_mid)); + } + + std::move_backward(from_s, from_mid, m_end); + + m_end = new_end; +} + } // namespace tinystl