Skip to content

Commit 5b1b87f

Browse files
authored
feat(vector): impl insert (#32)
1 parent 6e02ec6 commit 5b1b87f

File tree

1 file changed

+181
-18
lines changed

1 file changed

+181
-18
lines changed

source/tinystl/container/vector.h

Lines changed: 181 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,14 @@ class vector {
102102
iterator insert(const_iterator pos, const_reference val);
103103
iterator insert(const_iterator pos, value_type &&val);
104104
iterator insert(const_iterator pos, size_type n, const_reference val);
105-
template <class InputIter>
105+
template <std::forward_iterator ForwardIter>
106+
requires std::constructible_from<T, std::iter_reference_t<ForwardIter>>
107+
iterator insert(const_iterator pos, ForwardIter first, ForwardIter last);
108+
template <std::input_iterator InputIter>
109+
requires std::constructible_from<T, std::iter_reference_t<InputIter>> &&
110+
(!std::forward_iterator<InputIter>)
106111
iterator insert(const_iterator pos, InputIter first, InputIter last);
112+
iterator insert(const_iterator pos, std::initializer_list<T> init);
107113
template <class... Args>
108114
iterator emplace(const_iterator pos, Args &&...args);
109115
iterator erase(const_iterator pos);
@@ -136,6 +142,8 @@ class vector {
136142

137143
void destruct(pointer new_last);
138144

145+
void move_to_insert(pointer first, pointer last, pointer dst_first);
146+
139147
private:
140148
Alloc m_alloc;
141149
pointer m_begin = nullptr;
@@ -586,7 +594,7 @@ void vector<T, Alloc>::reserve(size_type n) {
586594
}
587595

588596
m_begin = new_begin;
589-
m_end = new_end;
597+
m_end = new_end;
590598
m_cap = new_cap;
591599
}
592600
}
@@ -640,12 +648,17 @@ vector<T, Alloc>::insert(const_iterator pos, const_reference val) {
640648
if (p == m_end) {
641649
this->construct(1, val);
642650
} else {
643-
alloc_traits::consturct(m_alloc, m_end, std::move(*(m_end - 1)));
644-
++m_end;
645-
std::move_backward(p, m_end - 2, m_end - 1);
651+
this->move_to_insert(p, m_end, p + 1);
652+
653+
const_pointer pval = std::pointer_traits<pointer>::pointer_to(val);
654+
const_pointer pp = std::to_address(p);
655+
const_pointer pend = std::to_address(m_end);
656+
if (!(pp <= pval && pval < pend)) {
657+
pval += 1;
658+
}
659+
646660
*p = val;
647661
}
648-
return iterator(p);
649662
} else {
650663
size_type sz = this->recommend(this->size() + 1);
651664
pointer new_begin = alloc_traits::allocate(m_alloc, sz);
@@ -673,9 +686,9 @@ vector<T, Alloc>::insert(const_iterator pos, const_reference val) {
673686
m_begin = new_begin;
674687
m_end = new_end;
675688
m_cap = new_cap;
676-
677-
return iterator(m_begin + offset);
678689
}
690+
691+
return iterator(p);
679692
}
680693

681694
template <class T, class Alloc>
@@ -688,20 +701,17 @@ vector<T, Alloc>::insert(const_iterator pos, value_type &&val) {
688701
alloc_traits::construct(m_alloc, p, std::move(val));
689702
++m_end;
690703
} else {
691-
alloc_traits::construct(m_alloc, m_end, std::move(*(m_end - 1)));
692-
++m_end;
693-
std::move_backward(p, m_end - 2, m_end - 1);
704+
this->move_to_insert(p, m_end, p + 1);
694705
*p = std::move(val);
695706
}
696-
return iterator(p);
697707
} else {
698708
size_type sz = this->recommend(this->size() + 1);
699709
pointer new_begin = alloc_traits::allocate(m_alloc, sz);
700710
pointer new_end = new_begin;
701711
pointer new_cap = new_begin + sz;
702712

703713
if constexpr (std::is_nothrow_move_constructible_v<value_type>) {
704-
new_end = std::uninitialized_move(m_begin, p, new_begin);
714+
new_end = std::uninitialized_move(m_begin, p, new_begin);
705715
} else {
706716
new_end = std::uninitialized_copy(m_begin, p, new_begin);
707717
}
@@ -710,7 +720,7 @@ vector<T, Alloc>::insert(const_iterator pos, value_type &&val) {
710720
++new_end;
711721

712722
if constexpr (std::is_nothrow_move_constructible_v<value_type>) {
713-
new_end = std::uninitialized_move(p, m_end, new_end);
723+
new_end = std::uninitialized_move(p, m_end, new_end);
714724
} else {
715725
new_end = std::uninitialized_copy(p, m_end, new_end);
716726
}
@@ -721,20 +731,157 @@ vector<T, Alloc>::insert(const_iterator pos, value_type &&val) {
721731
m_begin = new_begin;
722732
m_end = new_end;
723733
m_cap = new_cap;
724-
725-
return iterator(m_begin + offset);
726734
}
735+
return iterator(p);
727736
}
728737

729738
template <class T, class Alloc>
730739
typename vector<T, Alloc>::iterator
731740
vector<T, Alloc>::insert(const_iterator pos, size_type n, const_reference val) {
741+
size_type offset = static_cast<size_type>(std::distance(this->begin(), pos));
742+
pointer p = m_begin + offset;
743+
if (n > 0) {
744+
if (n <= static_cast<size_type>(m_cap - m_end)) {
745+
pointer old_end = m_end;
746+
size_type old_n = n;
747+
748+
size_type dx = static_cast<size_type>(m_end - p);
749+
if (n > dx) {
750+
this->construct(n - dx, val);
751+
n = dx;
752+
}
753+
754+
if (n > 0) {
755+
this->move_to_insert(p, old_end, p + old_n);
756+
757+
const_pointer pval = std::pointer_traits<pointer>::pointer_to(val);
758+
const_pointer pp = std::to_address(p);
759+
const_pointer pend = std::to_address(m_end);
760+
if (!(pp <= pval && pval < pend)) {
761+
pval += old_n;
762+
}
763+
std::fill_n(p, n, *pval);
764+
}
765+
} else {
766+
size_type sz = this->recommend(this->size() + n);
767+
pointer new_begin = alloc_traits::allocate(m_alloc, sz);
768+
pointer new_end = new_begin;
769+
pointer new_cap = new_begin + sz;
770+
771+
if constexpr (std::is_nothrow_move_constructible_v<value_type>) {
772+
new_end = std::uninitialized_move(m_begin, p, new_begin);
773+
} else {
774+
new_end = std::uninitialized_copy(m_begin, p, new_begin);
775+
}
776+
777+
for (size_type i = 0; i < n; ++i) {
778+
alloc_traits::construct(m_alloc, new_end, val);
779+
++new_end;
780+
}
781+
782+
if constexpr (std::is_nothrow_move_constructible_v<value_type>) {
783+
new_end = std::uninitialized_move(p, m_end, new_end);
784+
} else {
785+
new_end = std::uninitialized_copy(p, m_end, new_end);
786+
}
787+
788+
this->destruct(m_begin);
789+
this->deallocate();
790+
791+
m_begin = new_begin;
792+
m_end = new_end;
793+
m_cap = new_cap;
794+
}
795+
}
796+
797+
return iterator(p);
798+
}
799+
800+
template <class T, class Alloc>
801+
template <std::forward_iterator ForwardIter>
802+
requires std::constructible_from<T, std::iter_reference_t<ForwardIter>>
803+
typename vector<T, Alloc>::iterator vector<T, Alloc>::insert(
804+
const_iterator pos, ForwardIter first, ForwardIter last
805+
) {
806+
size_type offset = static_cast<size_type>(std::distance(this->begin(), pos));
807+
pointer p = m_begin + offset;
808+
809+
difference_type n = std::distance(first, last);
810+
811+
if (n > 0) {
812+
if (n <= static_cast<size_type>(m_cap - m_end)) {
813+
pointer old_end = m_end;
814+
815+
size_type dx = static_cast<size_type>(m_end - p);
816+
if (n > dx) {
817+
ForwardIter m = std::next(first, dx);
818+
this->construct(m, last, n - dx);
819+
n = dx;
820+
}
821+
if (n > 0) {
822+
this->move_to_insert(p, old_end, p + n);
823+
std::copy_n(first, n, p);
824+
}
825+
} else {
826+
size_type sz = this->recommend(this->size() + n);
827+
pointer new_begin = alloc_traits::allocate(m_alloc, sz);
828+
pointer new_end = new_begin;
829+
pointer new_cap = new_begin + sz;
830+
831+
if constexpr (std::is_move_constructible_v<value_type>) {
832+
new_end = std::uninitialized_move(m_begin, p, new_begin);
833+
} else {
834+
new_end = std::uninitialized_copy(m_begin, p, new_begin);
835+
}
836+
837+
for (size_type i = 0; i < n; ++i) {
838+
alloc_traits::construct(m_alloc, new_end, *first);
839+
++new_end;
840+
++first;
841+
}
842+
843+
if constexpr (std::is_move_constructible_v<value_type>) {
844+
new_end = std::uninitialized_move(p, m_end, new_end);
845+
} else {
846+
new_end = std::uninitialized_copy(p, m_end, new_end);
847+
}
848+
849+
this->destruct(m_begin);
850+
this->deallocate();
851+
852+
m_begin = new_begin;
853+
m_end = new_end;
854+
m_cap = new_cap;
855+
}
856+
}
857+
858+
return iterator(p);
859+
}
860+
861+
template <class T, class Alloc>
862+
template <std::input_iterator InputIter>
863+
requires std::constructible_from<T, std::iter_reference_t<InputIter>> &&
864+
(!std::forward_iterator<InputIter>)
865+
typename vector<T, Alloc>::iterator
866+
vector<T, Alloc>::insert(const_iterator pos, InputIter first, InputIter last) {
867+
size_type offset = static_cast<size_type>(std::distance(this->begin(), pos));
868+
pointer p = m_begin + offset;
869+
pointer old_end = m_end;
870+
871+
for (; first != last; ++first) {
872+
this->emplace_back(*first);
873+
}
874+
875+
std::rotate(p, old_end, m_end);
876+
877+
return iterator(p);
732878
}
733879

734880
template <class T, class Alloc>
735-
template <class InputIter>
736881
typename vector<T, Alloc>::iterator
737-
vector<T, Alloc>::insert(const_iterator pos, InputIter first, InputIter last) {}
882+
vector<T, Alloc>::insert(const_iterator pos, std::initializer_list<T> init) {
883+
return insert(pos, init.begin(), init.end());
884+
}
738885

739886
/* -------------------------------------------------------------------------- */
740887
/* private member functions */
@@ -816,4 +963,20 @@ void vector<T, Alloc>::destruct(pointer new_last) {
816963
}
817964
m_end = new_last;
818965
}
966+
967+
template <class T, class Alloc>
968+
void vector<T, Alloc>::move_to_insert(
969+
pointer from_s, pointer from_e, pointer to
970+
) {
971+
pointer from_mid = from_s + (m_end - to);
972+
pointer new_end = m_end;
973+
for (; from_mid < from_e; ++from_mid, ++new_end) {
974+
alloc_traits::construct(m_alloc, new_end, std::move(*from_mid));
975+
}
976+
977+
std::move_backward(from_s, from_mid, m_end);
978+
979+
m_end = new_end;
980+
}
981+
819982
} // namespace tinystl

0 commit comments

Comments
 (0)