@@ -36,10 +36,18 @@ template <typename T> class ArrayRef;
3636
3737template <typename IteratorT> class iterator_range ;
3838
39- template <class Iterator >
40- using EnableIfConvertibleToInputIterator = std::enable_if_t <std::is_convertible<
39+ namespace detail {
40+ template <typename Iterator, typename IteratorCategory>
41+ inline constexpr bool IsOfIteratorCategory = std::is_convertible_v<
4142 typename std::iterator_traits<Iterator>::iterator_category,
42- std::input_iterator_tag>::value>;
43+ IteratorCategory>;
44+
45+ template <typename Iterator>
46+ using EnableIfConvertibleToInputIterator =
47+ std::enable_if_t <std::is_convertible_v<
48+ typename std::iterator_traits<Iterator>::iterator_category,
49+ std::input_iterator_tag>>;
50+ } // namespace detail
4351
4452// / This is all the stuff common to all SmallVectors.
4553// /
@@ -679,13 +687,37 @@ class SmallVectorImpl : public SmallVectorTemplateBase<T> {
679687 void swap (SmallVectorImpl &RHS);
680688
681689 // / Add the specified range to the end of the SmallVector.
682- template <typename ItTy, typename = EnableIfConvertibleToInputIterator<ItTy>>
690+ template <typename ItTy,
691+ typename = detail::EnableIfConvertibleToInputIterator<ItTy>>
683692 void append (ItTy in_start, ItTy in_end) {
684693 this ->assertSafeToAddRange (in_start, in_end);
685- size_type NumInputs = std::distance (in_start, in_end);
686- this ->reserve (this ->size () + NumInputs);
687- this ->uninitialized_copy (in_start, in_end, this ->end ());
688- this ->set_size (this ->size () + NumInputs);
694+ if constexpr (detail::IsOfIteratorCategory<
695+ ItTy, std::random_access_iterator_tag>) {
696+ // Only reserve the required extra size upfront when the size calculation
697+ // is guaranteed to be O(1).
698+ size_type NumInputs = std::distance (in_start, in_end);
699+ this ->reserve (this ->size () + NumInputs);
700+ this ->uninitialized_copy (in_start, in_end, this ->end ());
701+ this ->set_size (this ->size () + NumInputs);
702+ } else {
703+ // Otherwise, append using `in_end` as the sentinel and reserve more space
704+ // as necessary.
705+ for (ItTy It = in_start; It != in_end;) {
706+ iterator Dest = this ->end ();
707+ size_type InitialSize = this ->size ();
708+ size_type ExtraCap = this ->capacity () - InitialSize;
709+ size_type NumCopied = 0 ;
710+ for (; NumCopied != ExtraCap && It != in_end; ++It, ++NumCopied) {
711+ ::new ((void *)(Dest + NumCopied)) T (*It);
712+ }
713+ size_type NewSize = InitialSize + NumCopied;
714+ this ->set_size (NewSize);
715+
716+ if (It != in_end) {
717+ this ->reserve (NewSize + 1 );
718+ }
719+ }
720+ }
689721 }
690722
691723 // / Append \p NumInputs copies of \p Elt to the end.
@@ -720,7 +752,8 @@ class SmallVectorImpl : public SmallVectorTemplateBase<T> {
720752 // FIXME: Consider assigning over existing elements, rather than clearing &
721753 // re-initializing them - for all assign(...) variants.
722754
723- template <typename ItTy, typename = EnableIfConvertibleToInputIterator<ItTy>>
755+ template <typename ItTy,
756+ typename = detail::EnableIfConvertibleToInputIterator<ItTy>>
724757 void assign (ItTy in_start, ItTy in_end) {
725758 this ->assertSafeToReferenceAfterClear (in_start, in_end);
726759 clear ();
@@ -871,7 +904,8 @@ class SmallVectorImpl : public SmallVectorTemplateBase<T> {
871904 return I;
872905 }
873906
874- template <typename ItTy, typename = EnableIfConvertibleToInputIterator<ItTy>>
907+ template <typename ItTy,
908+ typename = detail::EnableIfConvertibleToInputIterator<ItTy>>
875909 iterator insert (iterator I, ItTy From, ItTy To) {
876910 // Convert iterator to elt# to avoid invalidating iterator when we reserve()
877911 size_t InsertElt = I - this ->begin ();
@@ -887,8 +921,8 @@ class SmallVectorImpl : public SmallVectorTemplateBase<T> {
887921 this ->assertSafeToAddRange (From, To);
888922
889923 size_t NumToInsert = std::distance (From, To);
890-
891- // Ensure there is enough space .
924+ // Ensure there is enough space so that we do not have to re-allocate mid
925+ // insertion .
892926 reserve (this ->size () + NumToInsert);
893927
894928 // Uninvalidate the iterator.
@@ -1212,7 +1246,8 @@ class LLVM_GSL_OWNER SmallVector : public SmallVectorImpl<T>,
12121246 this ->assign (Size, Value);
12131247 }
12141248
1215- template <typename ItTy, typename = EnableIfConvertibleToInputIterator<ItTy>>
1249+ template <typename ItTy,
1250+ typename = detail::EnableIfConvertibleToInputIterator<ItTy>>
12161251 SmallVector (ItTy S, ItTy E) : SmallVectorImpl<T>(N) {
12171252 this ->append (S, E);
12181253 }
0 commit comments