Taskflow  3.2.0-Master-Branch
Loading...
Searching...
No Matches
small_vector.hpp
Go to the documentation of this file.
1// small vector modified from llvm
2
3#pragma once
4
5#include <algorithm>
6#include <cassert>
7#include <cstddef>
8#include <cstdlib>
9#include <cstring>
10#include <initializer_list>
11#include <iterator>
12#include <memory>
13
14#if defined(__GNUC__)
15 #define TF_LIKELY(x) (__builtin_expect((x), 1))
16 #define TF_UNLIKELY(x) (__builtin_expect((x), 0))
17#else
18 #define TF_LIKELY(x) (x)
19 #define TF_UNLIKELY(x) (x)
20#endif
21
27namespace tf { namespace detail {
28
35inline uint64_t NextCapacity(uint64_t A) {
36 A |= (A >> 1);
37 A |= (A >> 2);
38 A |= (A >> 4);
39 A |= (A >> 8);
40 A |= (A >> 16);
41 A |= (A >> 32);
42 return A + 1;
43}
44
45}} // end of namespace tf::detail --------------------------------------------
46
47
48namespace tf {
49
53template <typename T>
54struct IsPod : std::integral_constant<bool, std::is_standard_layout<T>::value &&
55 std::is_trivial<T>::value> {};
56
60class SmallVectorBase {
61protected:
62 void *BeginX, *EndX, *CapacityX;
63
64protected:
65 SmallVectorBase(void *FirstEl, size_t Size)
66 : BeginX(FirstEl), EndX(FirstEl), CapacityX((char*)FirstEl+Size) {}
67
70 void grow_pod(void *FirstEl, size_t MinSizeInBytes, size_t TSize){
71 size_t CurSizeBytes = size_in_bytes();
72 size_t NewCapacityInBytes = 2 * capacity_in_bytes() + TSize; // Always grow.
73 if (NewCapacityInBytes < MinSizeInBytes) {
74 NewCapacityInBytes = MinSizeInBytes;
75 }
76
77 void *NewElts;
78 if (BeginX == FirstEl) {
79 NewElts = std::malloc(NewCapacityInBytes);
80
81 // Copy the elements over. No need to run dtors on PODs.
82 memcpy(NewElts, this->BeginX, CurSizeBytes);
83 } else {
84 // If this wasn't grown from the inline copy, grow the allocated space.
85 NewElts = realloc(this->BeginX, NewCapacityInBytes);
86 }
87 //assert(NewElts && "Out of memory");
88
89 this->EndX = (char*)NewElts+CurSizeBytes;
90 this->BeginX = NewElts;
91 this->CapacityX = (char*)this->BeginX + NewCapacityInBytes;
92 }
93
94public:
96 size_t size_in_bytes() const {
97 return size_t((char*)EndX - (char*)BeginX);
98 }
99
101 size_t capacity_in_bytes() const {
102 return size_t((char*)CapacityX - (char*)BeginX);
103 }
104
105 bool empty() const { return BeginX == EndX; }
106};
107
111template <typename T, unsigned N> struct SmallVectorStorage;
112
116template <typename T, typename = void>
117class SmallVectorTemplateCommon : public SmallVectorBase {
118
119 private:
120 template <typename, unsigned> friend struct SmallVectorStorage;
121
122 // Allocate raw space for N elements of type T. If T has a ctor or dtor, we
123 // don't want it to be automatically run, so we need to represent the space as
124 // something else. Use an array of char of sufficient alignment.
126 typedef typename std::aligned_union<1, T>::type U;
127 U FirstEl;
128 // Space after 'FirstEl' is clobbered, do not add any instance vars after it.
129
130 protected:
131 SmallVectorTemplateCommon(size_t Size) : SmallVectorBase(&FirstEl, Size) {}
132
133 void grow_pod(size_t MinSizeInBytes, size_t TSize) {
134 SmallVectorBase::grow_pod(&FirstEl, MinSizeInBytes, TSize);
135 }
136
139 bool isSmall() const {
140 return BeginX == static_cast<const void*>(&FirstEl);
141 }
142
144 void resetToSmall() {
145 BeginX = EndX = CapacityX = &FirstEl;
146 }
147
148 void setEnd(T *P) { this->EndX = P; }
149
150 public:
151 typedef size_t size_type;
152 typedef ptrdiff_t difference_type;
153 typedef T value_type;
154 typedef T *iterator;
155 typedef const T *const_iterator;
156
157 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
158 typedef std::reverse_iterator<iterator> reverse_iterator;
159
160 typedef T &reference;
161 typedef const T &const_reference;
162 typedef T *pointer;
163 typedef const T *const_pointer;
164
165 // forward iterator creation methods.
166 inline iterator begin() { return (iterator)this->BeginX; }
167 inline const_iterator begin() const { return (const_iterator)this->BeginX; }
168 inline iterator end() { return (iterator)this->EndX; }
169 inline const_iterator end() const { return (const_iterator)this->EndX; }
170
171 protected:
172
173 iterator capacity_ptr() { return (iterator)this->CapacityX; }
174 const_iterator capacity_ptr() const { return (const_iterator)this->CapacityX;}
175
176 public:
177
178 // reverse iterator creation methods.
179 reverse_iterator rbegin() { return reverse_iterator(end()); }
180 const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
181 reverse_iterator rend() { return reverse_iterator(begin()); }
182 const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
183
184 inline size_type size() const { return end()-begin(); }
185 inline size_type max_size() const { return size_type(-1) / sizeof(T); }
186
188 size_t capacity() const { return capacity_ptr() - begin(); }
189
191 pointer data() { return pointer(begin()); }
193 const_pointer data() const { return const_pointer(begin()); }
194
195 inline reference operator[](size_type idx) {
196 //assert(idx < size());
197 return begin()[idx];
198 }
199
200 inline const_reference operator[](size_type idx) const {
201 //assert(idx < size());
202 return begin()[idx];
203 }
204
205 reference front() {
206 //assert(!empty());
207 return begin()[0];
208 }
209
210 const_reference front() const {
211 //assert(!empty());
212 return begin()[0];
213 }
214
215 reference back() {
216 //assert(!empty());
217 return end()[-1];
218 }
219
220 const_reference back() const {
221 //assert(!empty());
222 return end()[-1];
223 }
224};
225
229template <typename T, bool isPodLike>
230class SmallVectorTemplateBase : public SmallVectorTemplateCommon<T> {
231
232protected:
233 SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {}
234
235 static void destroy_range(T *S, T *E) {
236 while (S != E) {
237 --E;
238 E->~T();
239 }
240 }
241
244 template<typename It1, typename It2>
245 static void uninitialized_move(It1 I, It1 E, It2 Dest) {
247 std::make_move_iterator(E), Dest);
248 }
249
252 template<typename It1, typename It2>
253 static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
254 std::uninitialized_copy(I, E, Dest);
255 }
256
260 void grow(size_t MinSize = 0);
261
262public:
263 void push_back(const T &Elt) {
264 if (TF_UNLIKELY(this->EndX >= this->CapacityX))
265 this->grow();
266 ::new ((void*) this->end()) T(Elt);
267 this->setEnd(this->end()+1);
268 }
269
270 void push_back(T &&Elt) {
271 if (TF_UNLIKELY(this->EndX >= this->CapacityX))
272 this->grow();
273 ::new ((void*) this->end()) T(::std::move(Elt));
274 this->setEnd(this->end()+1);
275 }
276
277 void pop_back() {
278 this->setEnd(this->end()-1);
279 this->end()->~T();
280 }
281};
282
286template <typename T, bool isPodLike>
287void SmallVectorTemplateBase<T, isPodLike>::grow(size_t MinSize) {
288 size_t CurCapacity = this->capacity();
289 size_t CurSize = this->size();
290 // Always grow, even from zero.
291 size_t NewCapacity = size_t(tf::detail::NextCapacity(CurCapacity+2));
292 if (NewCapacity < MinSize)
293 NewCapacity = MinSize;
294 T *NewElts = static_cast<T*>(std::malloc(NewCapacity*sizeof(T)));
295
296 // Move the elements over.
297 this->uninitialized_move(this->begin(), this->end(), NewElts);
298
299 // Destroy the original elements.
300 destroy_range(this->begin(), this->end());
301
302 // If this wasn't grown from the inline copy, deallocate the old space.
303 if (!this->isSmall())
304 std::free(this->begin());
305
306 this->setEnd(NewElts+CurSize);
307 this->BeginX = NewElts;
308 this->CapacityX = this->begin()+NewCapacity;
309}
310
314template <typename T>
315class SmallVectorTemplateBase<T, true> : public SmallVectorTemplateCommon<T> {
316protected:
317 SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {}
318
319 // No need to do a destroy loop for POD's.
320 static void destroy_range(T *, T *) {}
321
324 template<typename It1, typename It2>
325 static void uninitialized_move(It1 I, It1 E, It2 Dest) {
326 // Just do a copy.
327 uninitialized_copy(I, E, Dest);
328 }
329
332 template<typename It1, typename It2>
333 static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
334 // Arbitrary iterator types; just use the basic implementation.
335 std::uninitialized_copy(I, E, Dest);
336 }
337
340 template <typename T1, typename T2>
341 static void uninitialized_copy(
342 T1 *I, T1 *E, T2 *Dest,
344 T2>::value>::type * = nullptr) {
345 // Use memcpy for PODs iterated by pointers (which includes SmallVector
346 // iterators): std::uninitialized_copy optimizes to memmove, but we can
347 // use memcpy here. Note that I and E are iterators and thus might be
348 // invalid for memcpy if they are equal.
349 if (I != E)
350 memcpy(Dest, I, (E - I) * sizeof(T));
351 }
352
355 void grow(size_t MinSize = 0) {
356 this->grow_pod(MinSize*sizeof(T), sizeof(T));
357 }
358public:
359 void push_back(const T &Elt) {
360 if (TF_UNLIKELY(this->EndX >= this->CapacityX))
361 this->grow();
362 memcpy(this->end(), &Elt, sizeof(T));
363 this->setEnd(this->end()+1);
364 }
365
366 void pop_back() {
367 this->setEnd(this->end()-1);
368 }
369};
370
374template <typename T>
375class SmallVectorImpl : public SmallVectorTemplateBase<T, IsPod<T>::value> {
376 typedef SmallVectorTemplateBase<T, IsPod<T>::value> SuperClass;
377
378 SmallVectorImpl(const SmallVectorImpl&) = delete;
379
380public:
381 typedef typename SuperClass::iterator iterator;
382 typedef typename SuperClass::const_iterator const_iterator;
383 typedef typename SuperClass::size_type size_type;
384
385protected:
386 // Default ctor - Initialize to empty.
387 explicit SmallVectorImpl(unsigned N)
388 : SmallVectorTemplateBase<T, IsPod<T>::value>(N*sizeof(T)) {
389 }
390
391public:
392 ~SmallVectorImpl() {
393 // Destroy the constructed elements in the vector.
394 this->destroy_range(this->begin(), this->end());
395
396 // If this wasn't grown from the inline copy, deallocate the old space.
397 if (!this->isSmall())
398 std::free(this->begin());
399 }
400
401
402 void clear() {
403 this->destroy_range(this->begin(), this->end());
404 this->EndX = this->BeginX;
405 }
406
407 void resize(size_type N) {
408 if (N < this->size()) {
409 this->destroy_range(this->begin()+N, this->end());
410 this->setEnd(this->begin()+N);
411 } else if (N > this->size()) {
412 if (this->capacity() < N)
413 this->grow(N);
414 for (auto I = this->end(), E = this->begin() + N; I != E; ++I)
415 new (&*I) T();
416 this->setEnd(this->begin()+N);
417 }
418 }
419
420 void resize(size_type N, const T &NV) {
421 if (N < this->size()) {
422 this->destroy_range(this->begin()+N, this->end());
423 this->setEnd(this->begin()+N);
424 } else if (N > this->size()) {
425 if (this->capacity() < N)
426 this->grow(N);
427 std::uninitialized_fill(this->end(), this->begin()+N, NV);
428 this->setEnd(this->begin()+N);
429 }
430 }
431
432 void reserve(size_type N) {
433 if (this->capacity() < N)
434 this->grow(N);
435 }
436
437 T pop_back_val() {
438 T Result = ::std::move(this->back());
439 this->pop_back();
440 return Result;
441 }
442
443 void swap(SmallVectorImpl &RHS);
444
446 template<typename in_iter>
447 void append(in_iter in_start, in_iter in_end) {
448 size_type NumInputs = std::distance(in_start, in_end);
449 // Grow allocated space if needed.
450 if (NumInputs > size_type(this->capacity_ptr()-this->end()))
451 this->grow(this->size()+NumInputs);
452
453 // Copy the new elements over.
454 this->uninitialized_copy(in_start, in_end, this->end());
455 this->setEnd(this->end() + NumInputs);
456 }
457
459 void append(size_type NumInputs, const T &Elt) {
460 // Grow allocated space if needed.
461 if (NumInputs > size_type(this->capacity_ptr()-this->end()))
462 this->grow(this->size()+NumInputs);
463
464 // Copy the new elements over.
465 std::uninitialized_fill_n(this->end(), NumInputs, Elt);
466 this->setEnd(this->end() + NumInputs);
467 }
468
469 void append(std::initializer_list<T> IL) {
470 append(IL.begin(), IL.end());
471 }
472
473 void assign(size_type NumElts, const T &Elt) {
474 clear();
475 if (this->capacity() < NumElts)
476 this->grow(NumElts);
477 this->setEnd(this->begin()+NumElts);
478 std::uninitialized_fill(this->begin(), this->end(), Elt);
479 }
480
481 void assign(std::initializer_list<T> IL) {
482 clear();
483 append(IL);
484 }
485
486 iterator erase(const_iterator CI) {
487 // Just cast away constness because this is a non-const member function.
488 iterator I = const_cast<iterator>(CI);
489
490 //assert(I >= this->begin() && "Iterator to erase is out of bounds.");
491 //assert(I < this->end() && "Erasing at past-the-end iterator.");
492
493 iterator N = I;
494 // Shift all elts down one.
495 std::move(I+1, this->end(), I);
496 // Drop the last elt.
497 this->pop_back();
498 return(N);
499 }
500
501 iterator erase(const_iterator CS, const_iterator CE) {
502 // Just cast away constness because this is a non-const member function.
503 iterator S = const_cast<iterator>(CS);
504 iterator E = const_cast<iterator>(CE);
505
506 //assert(S >= this->begin() && "Range to erase is out of bounds.");
507 //assert(S <= E && "Trying to erase invalid range.");
508 //assert(E <= this->end() && "Trying to erase past the end.");
509
510 iterator N = S;
511 // Shift all elts down.
512 iterator I = std::move(E, this->end(), S);
513 // Drop the last elts.
514 this->destroy_range(I, this->end());
515 this->setEnd(I);
516 return(N);
517 }
518
519 iterator insert(iterator I, T &&Elt) {
520 if (I == this->end()) { // Important special case for empty vector.
521 this->push_back(::std::move(Elt));
522 return this->end()-1;
523 }
524
525 //assert(I >= this->begin() && "Insertion iterator is out of bounds.");
526 //assert(I <= this->end() && "Inserting past the end of the vector.");
527
528 if (this->EndX >= this->CapacityX) {
529 size_t EltNo = I-this->begin();
530 this->grow();
531 I = this->begin()+EltNo;
532 }
533
534 ::new ((void*) this->end()) T(::std::move(this->back()));
535 // Push everything else over.
536 std::move_backward(I, this->end()-1, this->end());
537 this->setEnd(this->end()+1);
538
539 // If we just moved the element we're inserting, be sure to update
540 // the reference.
541 T *EltPtr = &Elt;
542 if (I <= EltPtr && EltPtr < this->EndX)
543 ++EltPtr;
544
545 *I = ::std::move(*EltPtr);
546 return I;
547 }
548
549 iterator insert(iterator I, const T &Elt) {
550 if (I == this->end()) { // Important special case for empty vector.
551 this->push_back(Elt);
552 return this->end()-1;
553 }
554
555 //assert(I >= this->begin() && "Insertion iterator is out of bounds.");
556 //assert(I <= this->end() && "Inserting past the end of the vector.");
557
558 if (this->EndX >= this->CapacityX) {
559 size_t EltNo = I-this->begin();
560 this->grow();
561 I = this->begin()+EltNo;
562 }
563 ::new ((void*) this->end()) T(std::move(this->back()));
564 // Push everything else over.
565 std::move_backward(I, this->end()-1, this->end());
566 this->setEnd(this->end()+1);
567
568 // If we just moved the element we're inserting, be sure to update
569 // the reference.
570 const T *EltPtr = &Elt;
571 if (I <= EltPtr && EltPtr < this->EndX)
572 ++EltPtr;
573
574 *I = *EltPtr;
575 return I;
576 }
577
578 iterator insert(iterator I, size_type NumToInsert, const T &Elt) {
579 // Convert iterator to elt# to avoid invalidating iterator when we reserve()
580 size_t InsertElt = I - this->begin();
581
582 if (I == this->end()) { // Important special case for empty vector.
583 append(NumToInsert, Elt);
584 return this->begin()+InsertElt;
585 }
586
587 //assert(I >= this->begin() && "Insertion iterator is out of bounds.");
588 //assert(I <= this->end() && "Inserting past the end of the vector.");
589
590 // Ensure there is enough space.
591 reserve(this->size() + NumToInsert);
592
593 // Uninvalidate the iterator.
594 I = this->begin()+InsertElt;
595
596 // If there are more elements between the insertion point and the end of the
597 // range than there are being inserted, we can use a simple approach to
598 // insertion. Since we already reserved space, we know that this won't
599 // reallocate the vector.
600 if (size_t(this->end()-I) >= NumToInsert) {
601 T *OldEnd = this->end();
602 append(std::move_iterator<iterator>(this->end() - NumToInsert),
603 std::move_iterator<iterator>(this->end()));
604
605 // Copy the existing elements that get replaced.
606 std::move_backward(I, OldEnd-NumToInsert, OldEnd);
607
608 std::fill_n(I, NumToInsert, Elt);
609 return I;
610 }
611
612 // Otherwise, we're inserting more elements than exist already, and we're
613 // not inserting at the end.
614
615 // Move over the elements that we're about to overwrite.
616 T *OldEnd = this->end();
617 this->setEnd(this->end() + NumToInsert);
618 size_t NumOverwritten = OldEnd-I;
619 this->uninitialized_move(I, OldEnd, this->end()-NumOverwritten);
620
621 // Replace the overwritten part.
622 std::fill_n(I, NumOverwritten, Elt);
623
624 // Insert the non-overwritten middle part.
625 std::uninitialized_fill_n(OldEnd, NumToInsert-NumOverwritten, Elt);
626 return I;
627 }
628
629 template<typename ItTy>
630 iterator insert(iterator I, ItTy From, ItTy To) {
631 // Convert iterator to elt# to avoid invalidating iterator when we reserve()
632 size_t InsertElt = I - this->begin();
633
634 if (I == this->end()) { // Important special case for empty vector.
635 append(From, To);
636 return this->begin()+InsertElt;
637 }
638
639 //assert(I >= this->begin() && "Insertion iterator is out of bounds.");
640 //assert(I <= this->end() && "Inserting past the end of the vector.");
641
642 size_t NumToInsert = std::distance(From, To);
643
644 // Ensure there is enough space.
645 reserve(this->size() + NumToInsert);
646
647 // Uninvalidate the iterator.
648 I = this->begin()+InsertElt;
649
650 // If there are more elements between the insertion point and the end of the
651 // range than there are being inserted, we can use a simple approach to
652 // insertion. Since we already reserved space, we know that this won't
653 // reallocate the vector.
654 if (size_t(this->end()-I) >= NumToInsert) {
655 T *OldEnd = this->end();
656 append(std::move_iterator<iterator>(this->end() - NumToInsert),
657 std::move_iterator<iterator>(this->end()));
658
659 // Copy the existing elements that get replaced.
660 std::move_backward(I, OldEnd-NumToInsert, OldEnd);
661
662 std::copy(From, To, I);
663 return I;
664 }
665
666 // Otherwise, we're inserting more elements than exist already, and we're
667 // not inserting at the end.
668
669 // Move over the elements that we're about to overwrite.
670 T *OldEnd = this->end();
671 this->setEnd(this->end() + NumToInsert);
672 size_t NumOverwritten = OldEnd-I;
673 this->uninitialized_move(I, OldEnd, this->end()-NumOverwritten);
674
675 // Replace the overwritten part.
676 for (T *J = I; NumOverwritten > 0; --NumOverwritten) {
677 *J = *From;
678 ++J; ++From;
679 }
680
681 // Insert the non-overwritten middle part.
682 this->uninitialized_copy(From, To, OldEnd);
683 return I;
684 }
685
686 void insert(iterator I, std::initializer_list<T> IL) {
687 insert(I, IL.begin(), IL.end());
688 }
689
690 template <typename... ArgTypes> void emplace_back(ArgTypes &&... Args) {
691 if (TF_UNLIKELY(this->EndX >= this->CapacityX))
692 this->grow();
693 ::new ((void *)this->end()) T(std::forward<ArgTypes>(Args)...);
694 this->setEnd(this->end() + 1);
695 }
696
697 SmallVectorImpl &operator=(const SmallVectorImpl &RHS);
698
699 SmallVectorImpl &operator=(SmallVectorImpl &&RHS);
700
701 bool operator==(const SmallVectorImpl &RHS) const {
702 if (this->size() != RHS.size()) return false;
703 return std::equal(this->begin(), this->end(), RHS.begin());
704 }
705 bool operator!=(const SmallVectorImpl &RHS) const {
706 return !(*this == RHS);
707 }
708
709 bool operator<(const SmallVectorImpl &RHS) const {
710 return std::lexicographical_compare(this->begin(), this->end(),
711 RHS.begin(), RHS.end());
712 }
713
723 void set_size(size_type N) {
724 //assert(N <= this->capacity());
725 this->setEnd(this->begin() + N);
726 }
727};
728
729
730template <typename T>
731void SmallVectorImpl<T>::swap(SmallVectorImpl<T> &RHS) {
732 if (this == &RHS) return;
733
734 // We can only avoid copying elements if neither vector is small.
735 if (!this->isSmall() && !RHS.isSmall()) {
736 std::swap(this->BeginX, RHS.BeginX);
737 std::swap(this->EndX, RHS.EndX);
738 std::swap(this->CapacityX, RHS.CapacityX);
739 return;
740 }
741 if (RHS.size() > this->capacity())
742 this->grow(RHS.size());
743 if (this->size() > RHS.capacity())
744 RHS.grow(this->size());
745
746 // Swap the shared elements.
747 size_t NumShared = this->size();
748 if (NumShared > RHS.size()) NumShared = RHS.size();
749 for (size_type i = 0; i != NumShared; ++i)
750 std::swap((*this)[i], RHS[i]);
751
752 // Copy over the extra elts.
753 if (this->size() > RHS.size()) {
754 size_t EltDiff = this->size() - RHS.size();
755 this->uninitialized_copy(this->begin()+NumShared, this->end(), RHS.end());
756 RHS.setEnd(RHS.end()+EltDiff);
757 this->destroy_range(this->begin()+NumShared, this->end());
758 this->setEnd(this->begin()+NumShared);
759 } else if (RHS.size() > this->size()) {
760 size_t EltDiff = RHS.size() - this->size();
761 this->uninitialized_copy(RHS.begin()+NumShared, RHS.end(), this->end());
762 this->setEnd(this->end() + EltDiff);
763 this->destroy_range(RHS.begin()+NumShared, RHS.end());
764 RHS.setEnd(RHS.begin()+NumShared);
765 }
766}
767
768template <typename T>
769SmallVectorImpl<T> &SmallVectorImpl<T>::
770 operator=(const SmallVectorImpl<T> &RHS) {
771 // Avoid self-assignment.
772 if (this == &RHS) return *this;
773
774 // If we already have sufficient space, assign the common elements, then
775 // destroy any excess.
776 size_t RHSSize = RHS.size();
777 size_t CurSize = this->size();
778 if (CurSize >= RHSSize) {
779 // Assign common elements.
780 iterator NewEnd;
781 if (RHSSize)
782 NewEnd = std::copy(RHS.begin(), RHS.begin()+RHSSize, this->begin());
783 else
784 NewEnd = this->begin();
785
786 // Destroy excess elements.
787 this->destroy_range(NewEnd, this->end());
788
789 // Trim.
790 this->setEnd(NewEnd);
791 return *this;
792 }
793
794 // If we have to grow to have enough elements, destroy the current elements.
795 // This allows us to avoid copying them during the grow.
796 // FIXME: don't do this if they're efficiently moveable.
797 if (this->capacity() < RHSSize) {
798 // Destroy current elements.
799 this->destroy_range(this->begin(), this->end());
800 this->setEnd(this->begin());
801 CurSize = 0;
802 this->grow(RHSSize);
803 } else if (CurSize) {
804 // Otherwise, use assignment for the already-constructed elements.
805 std::copy(RHS.begin(), RHS.begin()+CurSize, this->begin());
806 }
807
808 // Copy construct the new elements in place.
809 this->uninitialized_copy(RHS.begin()+CurSize, RHS.end(),
810 this->begin()+CurSize);
811
812 // Set end.
813 this->setEnd(this->begin()+RHSSize);
814 return *this;
815}
816
817template <typename T>
818SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) {
819 // Avoid self-assignment.
820 if (this == &RHS) return *this;
821
822 // If the RHS isn't small, clear this vector and then steal its buffer.
823 if (!RHS.isSmall()) {
824 this->destroy_range(this->begin(), this->end());
825 if (!this->isSmall()) std::free(this->begin());
826 this->BeginX = RHS.BeginX;
827 this->EndX = RHS.EndX;
828 this->CapacityX = RHS.CapacityX;
829 RHS.resetToSmall();
830 return *this;
831 }
832
833 // If we already have sufficient space, assign the common elements, then
834 // destroy any excess.
835 size_t RHSSize = RHS.size();
836 size_t CurSize = this->size();
837 if (CurSize >= RHSSize) {
838 // Assign common elements.
839 iterator NewEnd = this->begin();
840 if (RHSSize)
841 NewEnd = std::move(RHS.begin(), RHS.end(), NewEnd);
842
843 // Destroy excess elements and trim the bounds.
844 this->destroy_range(NewEnd, this->end());
845 this->setEnd(NewEnd);
846
847 // Clear the RHS.
848 RHS.clear();
849
850 return *this;
851 }
852
853 // If we have to grow to have enough elements, destroy the current elements.
854 // This allows us to avoid copying them during the grow.
855 // FIXME: this may not actually make any sense if we can efficiently move
856 // elements.
857 if (this->capacity() < RHSSize) {
858 // Destroy current elements.
859 this->destroy_range(this->begin(), this->end());
860 this->setEnd(this->begin());
861 CurSize = 0;
862 this->grow(RHSSize);
863 } else if (CurSize) {
864 // Otherwise, use assignment for the already-constructed elements.
865 std::move(RHS.begin(), RHS.begin()+CurSize, this->begin());
866 }
867
868 // Move-construct the new elements in place.
869 this->uninitialized_move(RHS.begin()+CurSize, RHS.end(),
870 this->begin()+CurSize);
871
872 // Set end.
873 this->setEnd(this->begin()+RHSSize);
874
875 RHS.clear();
876 return *this;
877}
878
882template <typename T, unsigned N>
883struct SmallVectorStorage {
887 typename SmallVectorTemplateCommon<T>::U InlineElts[N - 1];
888};
889
893template <typename T> struct SmallVectorStorage<T, 1> {};
894
898template <typename T> struct SmallVectorStorage<T, 0> {};
899
917template <typename T, unsigned N = 2>
918class SmallVector : public SmallVectorImpl<T> {
920 SmallVectorStorage<T, N> Storage;
921
922public:
923
927 SmallVector() : SmallVectorImpl<T>(N) {
928 }
929
933 explicit SmallVector(size_t Size, const T &Value = T())
934 : SmallVectorImpl<T>(N) {
935 this->assign(Size, Value);
936 }
937
942 template<typename ItTy>
943 SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(N) {
944 this->append(S, E);
945 }
946
947 //template <typename RangeTy>
948 //explicit SmallVector(const tf::iterator_range<RangeTy> &R)
949 // : SmallVectorImpl<T>(N) {
950 // this->append(R.begin(), R.end());
951 //}
952
956 SmallVector(std::initializer_list<T> IL) : SmallVectorImpl<T>(N) {
957 this->assign(IL);
958 }
959
963 SmallVector(const SmallVector &RHS) : SmallVectorImpl<T>(N) {
964 if (!RHS.empty())
965 SmallVectorImpl<T>::operator=(RHS);
966 }
967
971 SmallVector(SmallVector &&RHS) : SmallVectorImpl<T>(N) {
972 if (!RHS.empty())
973 SmallVectorImpl<T>::operator=(::std::move(RHS));
974 }
975
979 const SmallVector &operator=(const SmallVector &RHS) {
980 SmallVectorImpl<T>::operator=(RHS);
981 return *this;
982 }
983
988 SmallVectorImpl<T>::operator=(::std::move(RHS));
989 return *this;
990 }
991
995 SmallVector(SmallVectorImpl<T> &&RHS) : SmallVectorImpl<T>(N) {
996 if (!RHS.empty())
997 SmallVectorImpl<T>::operator=(::std::move(RHS));
998 }
999
1003 const SmallVector &operator=(SmallVectorImpl<T> &&RHS) {
1004 SmallVectorImpl<T>::operator=(::std::move(RHS));
1005 return *this;
1006 }
1007
1012 this->assign(IL);
1013 return *this;
1014 }
1015};
1016
1017template<typename T, unsigned N>
1018static inline size_t capacity_in_bytes(const SmallVector<T, N> &X) {
1019 return X.capacity_in_bytes();
1020}
1021
1022} // end tf namespace ---------------------------------------------------------
1023
1024namespace std {
1026 template<typename T>
1027 inline void
1028 swap(tf::SmallVectorImpl<T> &LHS, tf::SmallVectorImpl<T> &RHS) {
1029 LHS.swap(RHS);
1030 }
1031
1033 template<typename T, unsigned N>
1034 inline void
1036 LHS.swap(RHS);
1037 }
1038} // end of namespace std ----------------------------------------------------
1039
1040
T begin(T... args)
class to define a vector optimized for small array
Definition small_vector.hpp:918
SmallVector(size_t Size, const T &Value=T())
constructs a vector with Size copies of elements with value value
Definition small_vector.hpp:933
const SmallVector & operator=(std::initializer_list< T > IL)
replaces the contents with the copy of the contents of an initializer list IL
Definition small_vector.hpp:1011
SmallVector(ItTy S, ItTy E)
constructs a vector with the contents of the range [S, E)
Definition small_vector.hpp:943
SmallVector(SmallVectorImpl< T > &&RHS)
constructs a vector with the contents of RHS using move semantics
Definition small_vector.hpp:995
const SmallVector & operator=(const SmallVector &RHS)
replaces the contents with a copy of the contents of RHS
Definition small_vector.hpp:979
const SmallVector & operator=(SmallVector &&RHS)
replaces the contents with the contents of RHS using move semantics
Definition small_vector.hpp:987
SmallVector()
constructs an empty vector
Definition small_vector.hpp:927
SmallVector(const SmallVector &RHS)
constructs the vector with the copy of the contents of RHS
Definition small_vector.hpp:963
SmallVector(SmallVector &&RHS)
constructs the vector with the contents of RHS using move semantics
Definition small_vector.hpp:971
SmallVector(std::initializer_list< T > IL)
constructs a vector with the contents of the initializer list IL
Definition small_vector.hpp:956
const SmallVector & operator=(SmallVectorImpl< T > &&RHS)
replaces the contents with the contents of RHS using move semantics
Definition small_vector.hpp:1003
T copy(T... args)
T distance(T... args)
T end(T... args)
T equal(T... args)
T fill_n(T... args)
T free(T... args)
T lexicographical_compare(T... args)
T make_move_iterator(T... args)
T malloc(T... args)
T memcpy(T... args)
T move_backward(T... args)
T move(T... args)
taskflow namespace
Definition small_vector.hpp:27
T operator!=(T... args)
T realloc(T... args)
T swap(T... args)
T uninitialized_copy(T... args)
T uninitialized_fill(T... args)
T uninitialized_fill_n(T... args)