164 KiB
164 KiB
<html lang="en">
<head>
</head>
</html>
LCOV - code coverage report | ||||||||||||||||||||||
![]() | ||||||||||||||||||||||
|
||||||||||||||||||||||
![]() |
Line data Source code 1 : //===- llvm/ADT/SmallVector.h - 'Normally small' vectors --------*- C++ -*-===// 2 : // 3 : // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 : // See https://llvm.org/LICENSE.txt for license information. 5 : // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 : // 7 : //===----------------------------------------------------------------------===// 8 : // 9 : // This file defines the SmallVector class. 10 : // 11 : //===----------------------------------------------------------------------===// 12 : 13 : // ATen: modified from llvm::SmallVector. 14 : // used std::is_trivially_{copy,move}_constructible 15 : // replaced iterator_range constructor with inline Container&& constructor 16 : // replaced LLVM_NODISCARD, LLVM_LIKELY, and LLVM_UNLIKELY with c10 equivalents 17 : // removed LLVM_GSL_OWNER 18 : // added SmallVector::at 19 : // added operator<< for std::ostream 20 : // added C10_API to export SmallVectorBase 21 : 22 : #pragma once 23 : 24 : #include <c10/macros/Macros.h> 25 : #include <c10/util/AlignOf.h> 26 : 27 : #include <algorithm> 28 : #include <cassert> 29 : #include <cstddef> 30 : #include <cstdlib> 31 : #include <cstring> 32 : #include <functional> 33 : #include <initializer_list> 34 : #include <iterator> 35 : #include <limits> 36 : #include <memory> 37 : #include <new> 38 : #include <ostream> 39 : #include <type_traits> 40 : #include <utility> 41 : 42 : C10_CLANG_DIAGNOSTIC_PUSH() 43 : #if C10_CLANG_HAS_WARNING("-Wshorten-64-to-32") 44 : C10_CLANG_DIAGNOSTIC_IGNORE("-Wshorten-64-to-32") 45 : #endif 46 : 47 : namespace c10 { 48 : 49 : /// This is all the stuff common to all SmallVectors. 50 : /// 51 : /// The template parameter specifies the type which should be used to hold the 52 : /// Size and Capacity of the SmallVector, so it can be adjusted. 53 : /// Using 32 bit size is desirable to shrink the size of the SmallVector. 54 : /// Using 64 bit size is desirable for cases like SmallVector<char>, where a 55 : /// 32 bit size would limit the vector to ~4GB. SmallVectors are used for 56 : /// buffering bitcode output - which can exceed 4GB. 57 : template <class Size_T> 58 : class C10_API SmallVectorBase { 59 : protected: 60 : void* BeginX; 61 : Size_T Size = 0, Capacity; 62 : 63 : /// The maximum value of the Size_T used. 64 : static constexpr size_t SizeTypeMax() { 65 : return std::numeric_limits<Size_T>::max(); 66 : } 67 : 68 0 : SmallVectorBase(void* FirstEl, size_t TotalCapacity) 69 0 : : BeginX(FirstEl), Capacity(TotalCapacity) {} 70 : 71 : /// This is a helper for \a grow() that's out of line to reduce code 72 : /// duplication. This function will report a fatal error if it can't grow at 73 : /// least to \p MinSize. 74 : void* mallocForGrow(size_t MinSize, size_t TSize, size_t& NewCapacity); 75 : 76 : /// This is an implementation of the grow() method which only works 77 : /// on POD-like data types and is out of line to reduce code duplication. 78 : /// This function will report a fatal error if it cannot increase capacity. 79 : void grow_pod(void* FirstEl, size_t MinSize, size_t TSize); 80 : 81 : public: 82 : SmallVectorBase() = delete; 83 0 : size_t size() const { 84 0 : return Size; 85 : } 86 0 : size_t capacity() const { 87 0 : return Capacity; 88 : } 89 : 90 : C10_NODISCARD bool empty() const { 91 : return !Size; 92 : } 93 : 94 : /// Set the array size to \p N, which the current array must have enough 95 : /// capacity for. 96 : /// 97 : /// This does not construct or destroy any elements in the vector. 98 : /// 99 : /// Clients can use this in conjunction with capacity() to write past the end 100 : /// of the buffer when they know that more elements are available, and only 101 : /// update the size later. This avoids the cost of value initializing elements 102 : /// which will only be overwritten. 103 0 : void set_size(size_t N) { 104 0 : assert(N <= capacity()); 105 0 : Size = N; 106 0 : } 107 : }; 108 : 109 : template <class T> 110 : using SmallVectorSizeType = typename std:: 111 : conditional<sizeof(T) < 4 && sizeof(void*) >= 8, uint64_t, uint32_t>::type; 112 : 113 : /// Figure out the offset of the first element. 114 : template <class T, typename = void> 115 : struct SmallVectorAlignmentAndSize { 116 : alignas(SmallVectorBase<SmallVectorSizeType<T>>) char Base[sizeof( 117 : SmallVectorBase<SmallVectorSizeType<T>>)]; 118 : alignas(T) char FirstEl[sizeof(T)]; 119 : }; 120 : 121 : /// This is the part of SmallVectorTemplateBase which does not depend on whether 122 : /// the type T is a POD. The extra dummy template argument is used by ArrayRef 123 : /// to avoid unnecessarily requiring T to be complete. 124 : template <typename T, typename = void> 125 : class SmallVectorTemplateCommon 126 : : public SmallVectorBase<SmallVectorSizeType<T>> { 127 : using Base = SmallVectorBase<SmallVectorSizeType<T>>; 128 : 129 : /// Find the address of the first element. For this pointer math to be valid 130 : /// with small-size of 0 for T with lots of alignment, it's important that 131 : /// SmallVectorStorage is properly-aligned even for small-size of 0. 132 0 : void* getFirstEl() const { 133 : return const_cast<void*>(reinterpret_cast<const void*>( 134 : reinterpret_cast<const char*>(this) + 135 0 : offsetof(SmallVectorAlignmentAndSize<T>, FirstEl))); 136 : } 137 : // Space after 'FirstEl' is clobbered, do not add any instance vars after it. 138 : 139 : protected: 140 0 : SmallVectorTemplateCommon(size_t Size) : Base(getFirstEl(), Size) {} 141 : 142 0 : void grow_pod(size_t MinSize, size_t TSize) { 143 0 : Base::grow_pod(getFirstEl(), MinSize, TSize); 144 0 : } 145 : 146 : /// Return true if this is a smallvector which has not had dynamic 147 : /// memory allocated for it. 148 0 : bool isSmall() const { 149 0 : return this->BeginX == getFirstEl(); 150 : } 151 : 152 : /// Put this vector in a state of being small. 153 : void resetToSmall() { 154 : this->BeginX = getFirstEl(); 155 : this->Size = this->Capacity = 0; // FIXME: Setting Capacity to 0 is suspect. 156 : } 157 : 158 : /// Return true if V is an internal reference to the given range. 159 : bool isReferenceToRange(const void* V, const void* First, const void* Last) 160 : const { 161 : // Use std::less to avoid UB. 162 : std::less<> LessThan; 163 : return !LessThan(V, First) && LessThan(V, Last); 164 : } 165 : 166 : /// Return true if V is an internal reference to this vector. 167 : bool isReferenceToStorage(const void* V) const { 168 : return isReferenceToRange(V, this->begin(), this->end()); 169 : } 170 : 171 : /// Return true if First and Last form a valid (possibly empty) range in this 172 : /// vector's storage. 173 : bool isRangeInStorage(const void* First, const void* Last) const { 174 : // Use std::less to avoid UB. 175 : std::less<> LessThan; 176 : return !LessThan(First, this->begin()) && !LessThan(Last, First) && 177 : !LessThan(this->end(), Last); 178 : } 179 : 180 : /// Return true unless Elt will be invalidated by resizing the vector to 181 : /// NewSize. 182 : bool isSafeToReferenceAfterResize(const void* Elt, size_t NewSize) { 183 : // Past the end. 184 : if (C10_LIKELY(!isReferenceToStorage(Elt))) 185 : return true; 186 : 187 : // Return false if Elt will be destroyed by shrinking. 188 : if (NewSize <= this->size()) 189 : return Elt < this->begin() + NewSize; 190 : 191 : // Return false if we need to grow. 192 : return NewSize <= this->capacity(); 193 : } 194 : 195 : /// Check whether Elt will be invalidated by resizing the vector to NewSize. 196 : void assertSafeToReferenceAfterResize(const void* Elt, size_t NewSize) { 197 : (void)Elt; // Suppress unused variable warning 198 : (void)NewSize; // Suppress unused variable warning 199 : assert( 200 : isSafeToReferenceAfterResize(Elt, NewSize) && 201 : "Attempting to reference an element of the vector in an operation " 202 : "that invalidates it"); 203 : } 204 : 205 : /// Check whether Elt will be invalidated by increasing the size of the 206 : /// vector by N. 207 : void assertSafeToAdd(const void* Elt, size_t N = 1) { 208 : this->assertSafeToReferenceAfterResize(Elt, this->size() + N); 209 : } 210 : 211 : /// Check whether any part of the range will be invalidated by clearing. 212 : void assertSafeToReferenceAfterClear(const T* From, const T* To) { 213 : if (From == To) 214 : return; 215 : this->assertSafeToReferenceAfterResize(From, 0); 216 : this->assertSafeToReferenceAfterResize(To - 1, 0); 217 : } 218 : template < 219 : class ItTy, 220 : std::enable_if_t< 221 : !std::is_same<std::remove_const_t<ItTy>, T*>::value, 222 : bool> = false> 223 : void assertSafeToReferenceAfterClear(ItTy, ItTy) {} 224 : 225 : /// Check whether any part of the range will be invalidated by growing. 226 : void assertSafeToAddRange(const T* From, const T* To) { 227 : if (From == To) 228 : return; 229 : this->assertSafeToAdd(From, To - From); 230 : this->assertSafeToAdd(To - 1, To - From); 231 : } 232 : template < 233 : class ItTy, 234 : std::enable_if_t< 235 : !std::is_same<std::remove_const_t<ItTy>, T*>::value, 236 : bool> = false> 237 : void assertSafeToAddRange(ItTy, ItTy) {} 238 : 239 : /// Reserve enough space to add one element, and return the updated element 240 : /// pointer in case it was a reference to the storage. 241 : template <class U> 242 0 : static const T* reserveForParamAndGetAddressImpl( 243 : U* This, 244 : const T& Elt, 245 : size_t N) { 246 0 : size_t NewSize = This->size() + N; 247 0 : if (C10_LIKELY(NewSize <= This->capacity())) 248 0 : return &Elt; 249 : 250 0 : bool ReferencesStorage = false; 251 0 : int64_t Index = -1; 252 : if (!U::TakesParamByValue) { 253 : if (C10_UNLIKELY(This->isReferenceToStorage(&Elt))) { 254 : ReferencesStorage = true; 255 : Index = &Elt - This->begin(); 256 : } 257 : } 258 0 : This->grow(NewSize); 259 0 : return ReferencesStorage ? This->begin() + Index : &Elt; 260 : } 261 : 262 : public: 263 : using size_type = size_t; 264 : using difference_type = ptrdiff_t; 265 : using value_type = T; 266 : using iterator = T*; 267 : using const_iterator = const T*; 268 : 269 : using const_reverse_iterator = std::reverse_iterator<const_iterator>; 270 : using reverse_iterator = std::reverse_iterator<iterator>; 271 : 272 : using reference = T&; 273 : using const_reference = const T&; 274 : using pointer = T*; 275 : using const_pointer = const T*; 276 : 277 : using Base::capacity; 278 : using Base::empty; 279 : using Base::size; 280 : 281 : // forward iterator creation methods. 282 0 : iterator begin() { 283 0 : return (iterator)this->BeginX; 284 : } 285 : const_iterator begin() const { 286 : return (const_iterator)this->BeginX; 287 : } 288 0 : iterator end() { 289 0 : return begin() + size(); 290 : } 291 : const_iterator end() const { 292 : return begin() + size(); 293 : } 294 : 295 : // reverse iterator creation methods. 296 : reverse_iterator rbegin() { 297 : return reverse_iterator(end()); 298 : } 299 : const_reverse_iterator rbegin() const { 300 : return const_reverse_iterator(end()); 301 : } 302 : reverse_iterator rend() { 303 : return reverse_iterator(begin()); 304 : } 305 : const_reverse_iterator rend() const { 306 : return const_reverse_iterator(begin()); 307 : } 308 : 309 : size_type size_in_bytes() const { 310 : return size() * sizeof(T); 311 : } 312 : size_type max_size() const { 313 : return std::min(this->SizeTypeMax(), size_type(-1) / sizeof(T)); 314 : } 315 : 316 : size_t capacity_in_bytes() const { 317 : return capacity() * sizeof(T); 318 : } 319 : 320 : /// Return a pointer to the vector's buffer, even if empty(). 321 : pointer data() { 322 : return pointer(begin()); 323 : } 324 : /// Return a pointer to the vector's buffer, even if empty(). 325 : const_pointer data() const { 326 : return const_pointer(begin()); 327 : } 328 : 329 : // SmallVector::at is NOT from LLVM. 330 : reference at(size_type idx) { 331 : assert(idx < size()); 332 : return begin()[idx]; 333 : } 334 : const_reference at(size_type idx) const { 335 : assert(idx < size()); 336 : return begin()[idx]; 337 : } 338 : reference operator[](size_type idx) { 339 : assert(idx < size()); 340 : return begin()[idx]; 341 : } 342 : const_reference operator[](size_type idx) const { 343 : assert(idx < size()); 344 : return begin()[idx]; 345 : } 346 : 347 : reference front() { 348 : assert(!empty()); 349 : return begin()[0]; 350 : } 351 : const_reference front() const { 352 : assert(!empty()); 353 : return begin()[0]; 354 : } 355 : 356 : reference back() { 357 : assert(!empty()); 358 : return end()[-1]; 359 : } 360 : const_reference back() const { 361 : assert(!empty()); 362 : return end()[-1]; 363 : } 364 : }; 365 : 366 : /// SmallVectorTemplateBase<TriviallyCopyable = false> - This is where we put 367 : /// method implementations that are designed to work with non-trivial T's. 368 : /// 369 : /// We approximate is_trivially_copyable with trivial move/copy construction and 370 : /// trivial destruction. While the standard doesn't specify that you're allowed 371 : /// copy these types with memcpy, there is no way for the type to observe this. 372 : /// This catches the important case of std::pair<POD, POD>, which is not 373 : /// trivially assignable. 374 : /// 375 : /// XXX: if build fails here fall back to C10_IS_TRIVIALLY_COPYABLE and make a 376 : /// note 377 : template < 378 : typename T, 379 : bool = (std::is_trivially_copy_constructible<T>::value) && 380 : (std::is_trivially_move_constructible<T>::value) && 381 : std::is_trivially_destructible<T>::value> 382 : class SmallVectorTemplateBase : public SmallVectorTemplateCommon<T> { 383 : friend class SmallVectorTemplateCommon<T>; 384 : 385 : protected: 386 : static constexpr bool TakesParamByValue = false; 387 : using ValueParamT = const T&; 388 : 389 : SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {} 390 : 391 : static void destroy_range(T* S, T* E) { 392 : while (S != E) { 393 : --E; 394 : E->~T(); 395 : } 396 : } 397 : 398 : /// Move the range [I, E) into the uninitialized memory starting with "Dest", 399 : /// constructing elements as needed. 400 : template <typename It1, typename It2> 401 : static void uninitialized_move(It1 I, It1 E, It2 Dest) { 402 : std::uninitialized_copy( 403 : std::make_move_iterator(I), std::make_move_iterator(E), Dest); 404 : } 405 : 406 : /// Copy the range [I, E) onto the uninitialized memory starting with "Dest", 407 : /// constructing elements as needed. 408 : template <typename It1, typename It2> 409 : static void uninitialized_copy(It1 I, It1 E, It2 Dest) { 410 : std::uninitialized_copy(I, E, Dest); 411 : } 412 : 413 : /// Grow the allocated memory (without initializing new elements), doubling 414 : /// the size of the allocated memory. Guarantees space for at least one more 415 : /// element, or MinSize more elements if specified. 416 : void grow(size_t MinSize = 0); 417 : 418 : /// Create a new allocation big enough for \p MinSize and pass back its size 419 : /// in \p NewCapacity. This is the first section of \a grow(). 420 : T* mallocForGrow(size_t MinSize, size_t& NewCapacity) { 421 : return static_cast<T*>( 422 : SmallVectorBase<SmallVectorSizeType<T>>::mallocForGrow( 423 : MinSize, sizeof(T), NewCapacity)); 424 : } 425 : 426 : /// Move existing elements over to the new allocation \p NewElts, the middle 427 : /// section of \a grow(). 428 : void moveElementsForGrow(T* NewElts); 429 : 430 : /// Transfer ownership of the allocation, finishing up \a grow(). 431 : void takeAllocationForGrow(T* NewElts, size_t NewCapacity); 432 : 433 : /// Reserve enough space to add one element, and return the updated element 434 : /// pointer in case it was a reference to the storage. 435 : const T* reserveForParamAndGetAddress(const T& Elt, size_t N = 1) { 436 : return this->reserveForParamAndGetAddressImpl(this, Elt, N); 437 : } 438 : 439 : /// Reserve enough space to add one element, and return the updated element 440 : /// pointer in case it was a reference to the storage. 441 : T* reserveForParamAndGetAddress(T& Elt, size_t N = 1) { 442 : return const_cast<T*>(this->reserveForParamAndGetAddressImpl(this, Elt, N)); 443 : } 444 : 445 : static T&& forward_value_param(T&& V) { 446 : return std::move(V); 447 : } 448 : static const T& forward_value_param(const T& V) { 449 : return V; 450 : } 451 : 452 : void growAndAssign(size_t NumElts, const T& Elt) { 453 : // Grow manually in case Elt is an internal reference. 454 : size_t NewCapacity = 0; 455 : T* NewElts = mallocForGrow(NumElts, NewCapacity); 456 : std::uninitialized_fill_n(NewElts, NumElts, Elt); 457 : this->destroy_range(this->begin(), this->end()); 458 : takeAllocationForGrow(NewElts, NewCapacity); 459 : this->set_size(NumElts); 460 : } 461 : 462 : template <typename... ArgTypes> 463 : T& growAndEmplaceBack(ArgTypes&&... Args) { 464 : // Grow manually in case one of Args is an internal reference. 465 : size_t NewCapacity = 0; 466 : T* NewElts = mallocForGrow(0, NewCapacity); 467 : ::new ((void*)(NewElts + this->size())) T(std::forward<ArgTypes>(Args)...); 468 : moveElementsForGrow(NewElts); 469 : takeAllocationForGrow(NewElts, NewCapacity); 470 : this->set_size(this->size() + 1); 471 : return this->back(); 472 : } 473 : 474 : public: 475 : void push_back(const T& Elt) { 476 : const T* EltPtr = reserveForParamAndGetAddress(Elt); 477 : ::new ((void*)this->end()) T(*EltPtr); 478 : this->set_size(this->size() + 1); 479 : } 480 : 481 : void push_back(T&& Elt) { 482 : T* EltPtr = reserveForParamAndGetAddress(Elt); 483 : ::new ((void*)this->end()) T(::std::move(*EltPtr)); 484 : this->set_size(this->size() + 1); 485 : } 486 : 487 : void pop_back() { 488 : this->set_size(this->size() - 1); 489 : this->end()->~T(); 490 : } 491 : }; 492 : 493 : // Define this out-of-line to dissuade the C++ compiler from inlining it. 494 : template <typename T, bool TriviallyCopyable> 495 : void SmallVectorTemplateBase<T, TriviallyCopyable>::grow(size_t MinSize) { 496 : size_t NewCapacity = 0; 497 : T* NewElts = mallocForGrow(MinSize, NewCapacity); 498 : moveElementsForGrow(NewElts); 499 : takeAllocationForGrow(NewElts, NewCapacity); 500 : } 501 : 502 : // Define this out-of-line to dissuade the C++ compiler from inlining it. 503 : template <typename T, bool TriviallyCopyable> 504 : void SmallVectorTemplateBase<T, TriviallyCopyable>::moveElementsForGrow( 505 : T* NewElts) { 506 : // Move the elements over. 507 : this->uninitialized_move(this->begin(), this->end(), NewElts); 508 : 509 : // Destroy the original elements. 510 : destroy_range(this->begin(), this->end()); 511 : } 512 : 513 : // Define this out-of-line to dissuade the C++ compiler from inlining it. 514 : template <typename T, bool TriviallyCopyable> 515 : void SmallVectorTemplateBase<T, TriviallyCopyable>::takeAllocationForGrow( 516 : T* NewElts, 517 : size_t NewCapacity) { 518 : // If this wasn't grown from the inline copy, deallocate the old space. 519 : if (!this->isSmall()) 520 : free(this->begin()); 521 : 522 : this->BeginX = NewElts; 523 : this->Capacity = NewCapacity; 524 : } 525 : 526 : /// SmallVectorTemplateBase<TriviallyCopyable = true> - This is where we put 527 : /// method implementations that are designed to work with trivially copyable 528 : /// T's. This allows using memcpy in place of copy/move construction and 529 : /// skipping destruction. 530 : template <typename T> 531 : class SmallVectorTemplateBase<T, true> : public SmallVectorTemplateCommon<T> { 532 : friend class SmallVectorTemplateCommon<T>; 533 : 534 : protected: 535 : /// True if it's cheap enough to take parameters by value. Doing so avoids 536 : /// overhead related to mitigations for reference invalidation. 537 : static constexpr bool TakesParamByValue = sizeof(T) <= 2 * sizeof(void*); 538 : 539 : /// Either const T& or T, depending on whether it's cheap enough to take 540 : /// parameters by value. 541 : using ValueParamT = 542 : typename std::conditional<TakesParamByValue, T, const T&>::type; 543 : 544 0 : SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {} 545 : 546 : // No need to do a destroy loop for POD's. 547 0 : static void destroy_range(T*, T*) {} 548 : 549 : /// Move the range [I, E) onto the uninitialized memory 550 : /// starting with "Dest", constructing elements into it as needed. 551 : template <typename It1, typename It2> 552 : static void uninitialized_move(It1 I, It1 E, It2 Dest) { 553 : // Just do a copy. 554 : uninitialized_copy(I, E, Dest); 555 : } 556 : 557 : /// Copy the range [I, E) onto the uninitialized memory 558 : /// starting with "Dest", constructing elements into it as needed. 559 : template <typename It1, typename It2> 560 : static void uninitialized_copy(It1 I, It1 E, It2 Dest) { 561 : // Arbitrary iterator types; just use the basic implementation. 562 : std::uninitialized_copy(I, E, Dest); 563 : } 564 : 565 : /// Copy the range [I, E) onto the uninitialized memory 566 : /// starting with "Dest", constructing elements into it as needed. 567 : template <typename T1, typename T2> 568 : static void uninitialized_copy( 569 : T1* I, 570 : T1* E, 571 : T2* Dest, 572 : std::enable_if_t< 573 : std::is_same<typename std::remove_const<T1>::type, T2>::value>* = 574 : nullptr) { 575 : // Use memcpy for PODs iterated by pointers (which includes SmallVector 576 : // iterators): std::uninitialized_copy optimizes to memmove, but we can 577 : // use memcpy here. Note that I and E are iterators and thus might be 578 : // invalid for memcpy if they are equal. 579 : if (I != E) 580 : memcpy(reinterpret_cast<void*>(Dest), I, (E - I) * sizeof(T)); 581 : } 582 : 583 : /// Double the size of the allocated memory, guaranteeing space for at 584 : /// least one more element or MinSize if specified. 585 0 : void grow(size_t MinSize = 0) { 586 0 : this->grow_pod(MinSize, sizeof(T)); 587 0 : } 588 : 589 : /// Reserve enough space to add one element, and return the updated element 590 : /// pointer in case it was a reference to the storage. 591 : const T* reserveForParamAndGetAddress(const T& Elt, size_t N = 1) { 592 : return this->reserveForParamAndGetAddressImpl(this, Elt, N); 593 : } 594 : 595 : /// Reserve enough space to add one element, and return the updated element 596 : /// pointer in case it was a reference to the storage. 597 0 : T* reserveForParamAndGetAddress(T& Elt, size_t N = 1) { 598 0 : return const_cast<T*>(this->reserveForParamAndGetAddressImpl(this, Elt, N)); 599 : } 600 : 601 : /// Copy \p V or return a reference, depending on \a ValueParamT. 602 : static ValueParamT forward_value_param(ValueParamT V) { 603 : return V; 604 : } 605 : 606 : void growAndAssign(size_t NumElts, T Elt) { 607 : // Elt has been copied in case it's an internal reference, side-stepping 608 : // reference invalidation problems without losing the realloc optimization. 609 : this->set_size(0); 610 : this->grow(NumElts); 611 : std::uninitialized_fill_n(this->begin(), NumElts, Elt); 612 : this->set_size(NumElts); 613 : } 614 : 615 : template <typename... ArgTypes> 616 : T& growAndEmplaceBack(ArgTypes&&... Args) { 617 : // Use push_back with a copy in case Args has an internal reference, 618 : // side-stepping reference invalidation problems without losing the realloc 619 : // optimization. 620 : push_back(T(std::forward<ArgTypes>(Args)...)); 621 : return this->back(); 622 : } 623 : 624 : public: 625 0 : void push_back(ValueParamT Elt) { 626 0 : const T* EltPtr = reserveForParamAndGetAddress(Elt); 627 0 : memcpy(reinterpret_cast<void*>(this->end()), EltPtr, sizeof(T)); 628 0 : this->set_size(this->size() + 1); 629 0 : } 630 : 631 : void pop_back() { 632 : this->set_size(this->size() - 1); 633 : } 634 : }; 635 : 636 : /// This class consists of common code factored out of the SmallVector class to 637 : /// reduce code duplication based on the SmallVector 'N' template parameter. 638 : template <typename T> 639 : class SmallVectorImpl : public SmallVectorTemplateBase<T> { 640 : using SuperClass = SmallVectorTemplateBase<T>; 641 : 642 : public: 643 : using iterator = typename SuperClass::iterator; 644 : using const_iterator = typename SuperClass::const_iterator; 645 : using reference = typename SuperClass::reference; 646 : using size_type = typename SuperClass::size_type; 647 : 648 : protected: 649 : using SmallVectorTemplateBase<T>::TakesParamByValue; 650 : using ValueParamT = typename SuperClass::ValueParamT; 651 : 652 : // Default ctor - Initialize to empty. 653 0 : explicit SmallVectorImpl(unsigned N) : SmallVectorTemplateBase<T>(N) {} 654 : 655 : public: 656 : SmallVectorImpl(const SmallVectorImpl&) = delete; 657 : 658 0 : ~SmallVectorImpl() { 659 : // Subclass has already destructed this vector's elements. 660 : // If this wasn't grown from the inline copy, deallocate the old space. 661 0 : if (!this->isSmall()) 662 0 : free(this->begin()); 663 0 : } 664 : 665 : void clear() { 666 : this->destroy_range(this->begin(), this->end()); 667 : this->Size = 0; 668 : } 669 : 670 : private: 671 : template <bool ForOverwrite> 672 : void resizeImpl(size_type N) { 673 : if (N < this->size()) { 674 : this->pop_back_n(this->size() - N); 675 : } else if (N > this->size()) { 676 : this->reserve(N); 677 : for (auto I = this->end(), E = this->begin() + N; I != E; ++I) 678 : if (ForOverwrite) 679 : new (&*I) T; 680 : else 681 : new (&*I) T(); 682 : this->set_size(N); 683 : } 684 : } 685 : 686 : public: 687 : void resize(size_type N) { 688 : resizeImpl<false>(N); 689 : } 690 : 691 : /// Like resize, but \ref T is POD, the new values won't be initialized. 692 : void resize_for_overwrite(size_type N) { 693 : resizeImpl<true>(N); 694 : } 695 : 696 : void resize(size_type N, ValueParamT NV) { 697 : if (N == this->size()) 698 : return; 699 : 700 : if (N < this->size()) { 701 : this->pop_back_n(this->size() - N); 702 : return; 703 : } 704 : 705 : // N > this->size(). Defer to append. 706 : this->append(N - this->size(), NV); 707 : } 708 : 709 0 : void reserve(size_type N) { 710 0 : if (this->capacity() < N) 711 0 : this->grow(N); 712 0 : } 713 : 714 : void pop_back_n(size_type NumItems) { 715 : assert(this->size() >= NumItems); 716 : this->destroy_range(this->end() - NumItems, this->end()); 717 : this->set_size(this->size() - NumItems); 718 : } 719 : 720 : C10_NODISCARD T pop_back_val() { 721 : T Result = ::std::move(this->back()); 722 : this->pop_back(); 723 : return Result; 724 : } 725 : 726 : void swap(SmallVectorImpl& RHS); 727 : 728 : /// Add the specified range to the end of the SmallVector. 729 : template < 730 : typename in_iter, 731 : typename = std::enable_if_t<std::is_convertible< 732 : typename std::iterator_traits<in_iter>::iterator_category, 733 : std::input_iterator_tag>::value>> 734 : void append(in_iter in_start, in_iter in_end) { 735 : this->assertSafeToAddRange(in_start, in_end); 736 : size_type NumInputs = std::distance(in_start, in_end); 737 : this->reserve(this->size() + NumInputs); 738 : this->uninitialized_copy(in_start, in_end, this->end()); 739 : this->set_size(this->size() + NumInputs); 740 : } 741 : 742 : /// Append \p NumInputs copies of \p Elt to the end. 743 : void append(size_type NumInputs, ValueParamT Elt) { 744 : const T* EltPtr = this->reserveForParamAndGetAddress(Elt, NumInputs); 745 : std::uninitialized_fill_n(this->end(), NumInputs, *EltPtr); 746 : this->set_size(this->size() + NumInputs); 747 : } 748 : 749 : void append(std::initializer_list<T> IL) { 750 : append(IL.begin(), IL.end()); 751 : } 752 : 753 : void append(const SmallVectorImpl& RHS) { 754 : append(RHS.begin(), RHS.end()); 755 : } 756 : 757 : void assign(size_type NumElts, ValueParamT Elt) { 758 : // Note that Elt could be an internal reference. 759 : if (NumElts > this->capacity()) { 760 : this->growAndAssign(NumElts, Elt); 761 : return; 762 : } 763 : 764 : // Assign over existing elements. 765 : std::fill_n(this->begin(), std::min(NumElts, this->size()), Elt); 766 : if (NumElts > this->size()) 767 : std::uninitialized_fill_n(this->end(), NumElts - this->size(), Elt); 768 : else if (NumElts < this->size()) 769 : this->destroy_range(this->begin() + NumElts, this->end()); 770 : this->set_size(NumElts); 771 : } 772 : 773 : // FIXME: Consider assigning over existing elements, rather than clearing & 774 : // re-initializing them - for all assign(...) variants. 775 : 776 : template < 777 : typename in_iter, 778 : typename = std::enable_if_t<std::is_convertible< 779 : typename std::iterator_traits<in_iter>::iterator_category, 780 : std::input_iterator_tag>::value>> 781 : void assign(in_iter in_start, in_iter in_end) { 782 : this->assertSafeToReferenceAfterClear(in_start, in_end); 783 : clear(); 784 : append(in_start, in_end); 785 : } 786 : 787 : void assign(std::initializer_list<T> IL) { 788 : clear(); 789 : append(IL); 790 : } 791 : 792 : void assign(const SmallVectorImpl& RHS) { 793 : assign(RHS.begin(), RHS.end()); 794 : } 795 : 796 : iterator erase(const_iterator CI) { 797 : // Just cast away constness because this is a non-const member function. 798 : iterator I = const_cast<iterator>(CI); 799 : 800 : assert( 801 : this->isReferenceToStorage(CI) && 802 : "Iterator to erase is out of bounds."); 803 : 804 : iterator N = I; 805 : // Shift all elts down one. 806 : std::move(I + 1, this->end(), I); 807 : // Drop the last elt. 808 : this->pop_back(); 809 : return (N); 810 : } 811 : 812 : iterator erase(const_iterator CS, const_iterator CE) { 813 : // Just cast away constness because this is a non-const member function. 814 : iterator S = const_cast<iterator>(CS); 815 : iterator E = const_cast<iterator>(CE); 816 : 817 : assert(this->isRangeInStorage(S, E) && "Range to erase is out of bounds."); 818 : 819 : iterator N = S; 820 : // Shift all elts down. 821 : iterator I = std::move(E, this->end(), S); 822 : // Drop the last elts. 823 : this->destroy_range(I, this->end()); 824 : this->set_size(I - this->begin()); 825 : return (N); 826 : } 827 : 828 : private: 829 : template <class ArgType> 830 : iterator insert_one_impl(iterator I, ArgType&& Elt) { 831 : // Callers ensure that ArgType is derived from T. 832 : static_assert( 833 : std::is_same<std::remove_const_t<std::remove_reference_t<ArgType>>, T>:: 834 : value, 835 : "ArgType must be derived from T!"); 836 : 837 : if (I == this->end()) { // Important special case for empty vector. 838 : this->push_back(::std::forward<ArgType>(Elt)); 839 : return this->end() - 1; 840 : } 841 : 842 : assert( 843 : this->isReferenceToStorage(I) && 844 : "Insertion iterator is out of bounds."); 845 : 846 : // Grow if necessary. 847 : size_t Index = I - this->begin(); 848 : std::remove_reference_t<ArgType>* EltPtr = 849 : this->reserveForParamAndGetAddress(Elt); 850 : I = this->begin() + Index; 851 : 852 : ::new ((void*)this->end()) T(::std::move(this->back())); 853 : // Push everything else over. 854 : std::move_backward(I, this->end() - 1, this->end()); 855 : this->set_size(this->size() + 1); 856 : 857 : // If we just moved the element we're inserting, be sure to update 858 : // the reference (never happens if TakesParamByValue). 859 : static_assert( 860 : !TakesParamByValue || std::is_same<ArgType, T>::value, 861 : "ArgType must be 'T' when taking by value!"); 862 : if (!TakesParamByValue && this->isReferenceToRange(EltPtr, I, this->end())) 863 : ++EltPtr; 864 : 865 : *I = ::std::forward<ArgType>(*EltPtr); 866 : return I; 867 : } 868 : 869 : public: 870 : iterator insert(iterator I, T&& Elt) { 871 : return insert_one_impl(I, this->forward_value_param(std::move(Elt))); 872 : } 873 : 874 : iterator insert(iterator I, const T& Elt) { 875 : return insert_one_impl(I, this->forward_value_param(Elt)); 876 : } 877 : 878 : iterator insert(iterator I, size_type NumToInsert, ValueParamT Elt) { 879 : // Convert iterator to elt# to avoid invalidating iterator when we reserve() 880 : size_t InsertElt = I - this->begin(); 881 : 882 : if (I == this->end()) { // Important special case for empty vector. 883 : append(NumToInsert, Elt); 884 : return this->begin() + InsertElt; 885 : } 886 : 887 : assert( 888 : this->isReferenceToStorage(I) && 889 : "Insertion iterator is out of bounds."); 890 : 891 : // Ensure there is enough space, and get the (maybe updated) address of 892 : // Elt. 893 : const T* EltPtr = this->reserveForParamAndGetAddress(Elt, NumToInsert); 894 : 895 : // Uninvalidate the iterator. 896 : I = this->begin() + InsertElt; 897 : 898 : // If there are more elements between the insertion point and the end of the 899 : // range than there are being inserted, we can use a simple approach to 900 : // insertion. Since we already reserved space, we know that this won't 901 : // reallocate the vector. 902 : if (size_t(this->end() - I) >= NumToInsert) { 903 : T* OldEnd = this->end(); 904 : append( 905 : std::move_iterator<iterator>(this->end() - NumToInsert), 906 : std::move_iterator<iterator>(this->end())); 907 : 908 : // Copy the existing elements that get replaced. 909 : std::move_backward(I, OldEnd - NumToInsert, OldEnd); 910 : 911 : // If we just moved the element we're inserting, be sure to update 912 : // the reference (never happens if TakesParamByValue). 913 : if (!TakesParamByValue && I <= EltPtr && EltPtr < this->end()) 914 : EltPtr += NumToInsert; 915 : 916 : std::fill_n(I, NumToInsert, *EltPtr); 917 : return I; 918 : } 919 : 920 : // Otherwise, we're inserting more elements than exist already, and we're 921 : // not inserting at the end. 922 : 923 : // Move over the elements that we're about to overwrite. 924 : T* OldEnd = this->end(); 925 : this->set_size(this->size() + NumToInsert); 926 : size_t NumOverwritten = OldEnd - I; 927 : this->uninitialized_move(I, OldEnd, this->end() - NumOverwritten); 928 : 929 : // If we just moved the element we're inserting, be sure to update 930 : // the reference (never happens if TakesParamByValue). 931 : if (!TakesParamByValue && I <= EltPtr && EltPtr < this->end()) 932 : EltPtr += NumToInsert; 933 : 934 : // Replace the overwritten part. 935 : std::fill_n(I, NumOverwritten, *EltPtr); 936 : 937 : // Insert the non-overwritten middle part. 938 : std::uninitialized_fill_n(OldEnd, NumToInsert - NumOverwritten, *EltPtr); 939 : return I; 940 : } 941 : 942 : template < 943 : typename ItTy, 944 : typename = std::enable_if_t<std::is_convertible< 945 : typename std::iterator_traits<ItTy>::iterator_category, 946 : std::input_iterator_tag>::value>> 947 : iterator insert(iterator I, ItTy From, ItTy To) { 948 : // Convert iterator to elt# to avoid invalidating iterator when we reserve() 949 : size_t InsertElt = I - this->begin(); 950 : 951 : if (I == this->end()) { // Important special case for empty vector. 952 : append(From, To); 953 : return this->begin() + InsertElt; 954 : } 955 : 956 : assert( 957 : this->isReferenceToStorage(I) && 958 : "Insertion iterator is out of bounds."); 959 : 960 : // Check that the reserve that follows doesn't invalidate the iterators. 961 : this->assertSafeToAddRange(From, To); 962 : 963 : size_t NumToInsert = std::distance(From, To); 964 : 965 : // Ensure there is enough space. 966 : reserve(this->size() + NumToInsert); 967 : 968 : // Uninvalidate the iterator. 969 : I = this->begin() + InsertElt; 970 : 971 : // If there are more elements between the insertion point and the end of the 972 : // range than there are being inserted, we can use a simple approach to 973 : // insertion. Since we already reserved space, we know that this won't 974 : // reallocate the vector. 975 : if (size_t(this->end() - I) >= NumToInsert) { 976 : T* OldEnd = this->end(); 977 : append( 978 : std::move_iterator<iterator>(this->end() - NumToInsert), 979 : std::move_iterator<iterator>(this->end())); 980 : 981 : // Copy the existing elements that get replaced. 982 : std::move_backward(I, OldEnd - NumToInsert, OldEnd); 983 : 984 : std::copy(From, To, I); 985 : return I; 986 : } 987 : 988 : // Otherwise, we're inserting more elements than exist already, and we're 989 : // not inserting at the end. 990 : 991 : // Move over the elements that we're about to overwrite. 992 : T* OldEnd = this->end(); 993 : this->set_size(this->size() + NumToInsert); 994 : size_t NumOverwritten = OldEnd - I; 995 : this->uninitialized_move(I, OldEnd, this->end() - NumOverwritten); 996 : 997 : // Replace the overwritten part. 998 : for (T* J = I; NumOverwritten > 0; --NumOverwritten) { 999 : *J = *From; 1000 : ++J; 1001 : ++From; 1002 : } 1003 : 1004 : // Insert the non-overwritten middle part. 1005 : this->uninitialized_copy(From, To, OldEnd); 1006 : return I; 1007 : } 1008 : 1009 : void insert(iterator I, std::initializer_list<T> IL) { 1010 : insert(I, IL.begin(), IL.end()); 1011 : } 1012 : 1013 : template <typename... ArgTypes> 1014 : reference emplace_back(ArgTypes&&... Args) { 1015 : if (C10_UNLIKELY(this->size() >= this->capacity())) 1016 : return this->growAndEmplaceBack(std::forward<ArgTypes>(Args)...); 1017 : 1018 : ::new ((void*)this->end()) T(std::forward<ArgTypes>(Args)...); 1019 : this->set_size(this->size() + 1); 1020 : return this->back(); 1021 : } 1022 : 1023 : SmallVectorImpl& operator=(const SmallVectorImpl& RHS); 1024 : 1025 : SmallVectorImpl& operator=(SmallVectorImpl&& RHS); 1026 : 1027 : bool operator==(const SmallVectorImpl& RHS) const { 1028 : if (this->size() != RHS.size()) 1029 : return false; 1030 : return std::equal(this->begin(), this->end(), RHS.begin()); 1031 : } 1032 : bool operator!=(const SmallVectorImpl& RHS) const { 1033 : return !(*this == RHS); 1034 : } 1035 : 1036 : bool operator<(const SmallVectorImpl& RHS) const { 1037 : return std::lexicographical_compare( 1038 : this->begin(), this->end(), RHS.begin(), RHS.end()); 1039 : } 1040 : }; 1041 : 1042 : template <typename T> 1043 : void SmallVectorImpl<T>::swap(SmallVectorImpl<T>& RHS) { 1044 : if (this == &RHS) 1045 : return; 1046 : 1047 : // We can only avoid copying elements if neither vector is small. 1048 : if (!this->isSmall() && !RHS.isSmall()) { 1049 : std::swap(this->BeginX, RHS.BeginX); 1050 : std::swap(this->Size, RHS.Size); 1051 : std::swap(this->Capacity, RHS.Capacity); 1052 : return; 1053 : } 1054 : this->reserve(RHS.size()); 1055 : RHS.reserve(this->size()); 1056 : 1057 : // Swap the shared elements. 1058 : size_t NumShared = this->size(); 1059 : if (NumShared > RHS.size()) 1060 : NumShared = RHS.size(); 1061 : for (size_type i = 0; i != NumShared; ++i) 1062 : std::swap((*this)[i], RHS[i]); 1063 : 1064 : // Copy over the extra elts. 1065 : if (this->size() > RHS.size()) { 1066 : size_t EltDiff = this->size() - RHS.size(); 1067 : this->uninitialized_copy(this->begin() + NumShared, this->end(), RHS.end()); 1068 : RHS.set_size(RHS.size() + EltDiff); 1069 : this->destroy_range(this->begin() + NumShared, this->end()); 1070 : this->set_size(NumShared); 1071 : } else if (RHS.size() > this->size()) { 1072 : size_t EltDiff = RHS.size() - this->size(); 1073 : this->uninitialized_copy(RHS.begin() + NumShared, RHS.end(), this->end()); 1074 : this->set_size(this->size() + EltDiff); 1075 : this->destroy_range(RHS.begin() + NumShared, RHS.end()); 1076 : RHS.set_size(NumShared); 1077 : } 1078 : } 1079 : 1080 : template <typename T> 1081 : SmallVectorImpl<T>& SmallVectorImpl<T>::operator=( 1082 : const SmallVectorImpl<T>& RHS) { 1083 : // Avoid self-assignment. 1084 : if (this == &RHS) 1085 : return *this; 1086 : 1087 : // If we already have sufficient space, assign the common elements, then 1088 : // destroy any excess. 1089 : size_t RHSSize = RHS.size(); 1090 : size_t CurSize = this->size(); 1091 : if (CurSize >= RHSSize) { 1092 : // Assign common elements. 1093 : iterator NewEnd; 1094 : if (RHSSize) 1095 : NewEnd = std::copy(RHS.begin(), RHS.begin() + RHSSize, this->begin()); 1096 : else 1097 : NewEnd = this->begin(); 1098 : 1099 : // Destroy excess elements. 1100 : this->destroy_range(NewEnd, this->end()); 1101 : 1102 : // Trim. 1103 : this->set_size(RHSSize); 1104 : return *this; 1105 : } 1106 : 1107 : // If we have to grow to have enough elements, destroy the current elements. 1108 : // This allows us to avoid copying them during the grow. 1109 : // FIXME: don't do this if they're efficiently moveable. 1110 : if (this->capacity() < RHSSize) { 1111 : // Destroy current elements. 1112 : this->clear(); 1113 : CurSize = 0; 1114 : this->grow(RHSSize); 1115 : } else if (CurSize) { 1116 : // Otherwise, use assignment for the already-constructed elements. 1117 : std::copy(RHS.begin(), RHS.begin() + CurSize, this->begin()); 1118 : } 1119 : 1120 : // Copy construct the new elements in place. 1121 : this->uninitialized_copy( 1122 : RHS.begin() + CurSize, RHS.end(), this->begin() + CurSize); 1123 : 1124 : // Set end. 1125 : this->set_size(RHSSize); 1126 : return *this; 1127 : } 1128 : 1129 : template <typename T> 1130 : SmallVectorImpl<T>& SmallVectorImpl<T>::operator=(SmallVectorImpl<T>&& RHS) { 1131 : // Avoid self-assignment. 1132 : if (this == &RHS) 1133 : return *this; 1134 : 1135 : // If the RHS isn't small, clear this vector and then steal its buffer. 1136 : if (!RHS.isSmall()) { 1137 : this->destroy_range(this->begin(), this->end()); 1138 : if (!this->isSmall()) 1139 : free(this->begin()); 1140 : this->BeginX = RHS.BeginX; 1141 : this->Size = RHS.Size; 1142 : this->Capacity = RHS.Capacity; 1143 : RHS.resetToSmall(); 1144 : return *this; 1145 : } 1146 : 1147 : // If we already have sufficient space, assign the common elements, then 1148 : // destroy any excess. 1149 : size_t RHSSize = RHS.size(); 1150 : size_t CurSize = this->size(); 1151 : if (CurSize >= RHSSize) { 1152 : // Assign common elements. 1153 : iterator NewEnd = this->begin(); 1154 : if (RHSSize) 1155 : NewEnd = std::move(RHS.begin(), RHS.end(), NewEnd); 1156 : 1157 : // Destroy excess elements and trim the bounds. 1158 : this->destroy_range(NewEnd, this->end()); 1159 : this->set_size(RHSSize); 1160 : 1161 : // Clear the RHS. 1162 : RHS.clear(); 1163 : 1164 : return *this; 1165 : } 1166 : 1167 : // If we have to grow to have enough elements, destroy the current elements. 1168 : // This allows us to avoid copying them during the grow. 1169 : // FIXME: this may not actually make any sense if we can efficiently move 1170 : // elements. 1171 : if (this->capacity() < RHSSize) { 1172 : // Destroy current elements. 1173 : this->clear(); 1174 : CurSize = 0; 1175 : this->grow(RHSSize); 1176 : } else if (CurSize) { 1177 : // Otherwise, use assignment for the already-constructed elements. 1178 : std::move(RHS.begin(), RHS.begin() + CurSize, this->begin()); 1179 : } 1180 : 1181 : // Move-construct the new elements in place. 1182 : this->uninitialized_move( 1183 : RHS.begin() + CurSize, RHS.end(), this->begin() + CurSize); 1184 : 1185 : // Set end. 1186 : this->set_size(RHSSize); 1187 : 1188 : RHS.clear(); 1189 : return *this; 1190 : } 1191 : 1192 : /// Storage for the SmallVector elements. This is specialized for the N=0 case 1193 : /// to avoid allocating unnecessary storage. 1194 : template <typename T, unsigned N> 1195 : struct SmallVectorStorage { 1196 : alignas(T) char InlineElts[N * sizeof(T)]; 1197 : }; 1198 : 1199 : /// We need the storage to be properly aligned even for small-size of 0 so that 1200 : /// the pointer math in \a SmallVectorTemplateCommon::getFirstEl() is 1201 : /// well-defined. 1202 : template <typename T> 1203 : struct alignas(T) SmallVectorStorage<T, 0> {}; 1204 : 1205 : /// Forward declaration of SmallVector so that 1206 : /// calculateSmallVectorDefaultInlinedElements can reference 1207 : /// `sizeof(SmallVector<T, 0>)`. 1208 : template <typename T, unsigned N> 1209 : class /* LLVM_GSL_OWNER */ SmallVector; 1210 : 1211 : /// Helper class for calculating the default number of inline elements for 1212 : /// `SmallVector<T>`. 1213 : /// 1214 : /// This should be migrated to a constexpr function when our minimum 1215 : /// compiler support is enough for multi-statement constexpr functions. 1216 : template <typename T> 1217 : struct CalculateSmallVectorDefaultInlinedElements { 1218 : // Parameter controlling the default number of inlined elements 1219 : // for `SmallVector<T>`. 1220 : // 1221 : // The default number of inlined elements ensures that 1222 : // 1. There is at least one inlined element. 1223 : // 2. `sizeof(SmallVector<T>) <= kPreferredSmallVectorSizeof` unless 1224 : // it contradicts 1. 1225 : static constexpr size_t kPreferredSmallVectorSizeof = 64; 1226 : 1227 : // static_assert that sizeof(T) is not "too big". 1228 : // 1229 : // Because our policy guarantees at least one inlined element, it is possible 1230 : // for an arbitrarily large inlined element to allocate an arbitrarily large 1231 : // amount of inline storage. We generally consider it an antipattern for a 1232 : // SmallVector to allocate an excessive amount of inline storage, so we want 1233 : // to call attention to these cases and make sure that users are making an 1234 : // intentional decision if they request a lot of inline storage. 1235 : // 1236 : // We want this assertion to trigger in pathological cases, but otherwise 1237 : // not be too easy to hit. To accomplish that, the cutoff is actually somewhat 1238 : // larger than kPreferredSmallVectorSizeof (otherwise, 1239 : // `SmallVector<SmallVector<T>>` would be one easy way to trip it, and that 1240 : // pattern seems useful in practice). 1241 : // 1242 : // One wrinkle is that this assertion is in theory non-portable, since 1243 : // sizeof(T) is in general platform-dependent. However, we don't expect this 1244 : // to be much of an issue, because most LLVM development happens on 64-bit 1245 : // hosts, and therefore sizeof(T) is expected to *decrease* when compiled for 1246 : // 32-bit hosts, dodging the issue. The reverse situation, where development 1247 : // happens on a 32-bit host and then fails due to sizeof(T) *increasing* on a 1248 : // 64-bit host, is expected to be very rare. 1249 : static_assert( 1250 : sizeof(T) <= 256, 1251 : "You are trying to use a default number of inlined elements for " 1252 : "`SmallVector<T>` but `sizeof(T)` is really big! Please use an " 1253 : "explicit number of inlined elements with `SmallVector<T, N>` to make " 1254 : "sure you really want that much inline storage."); 1255 : 1256 : // Discount the size of the header itself when calculating the maximum inline 1257 : // bytes. 1258 : static constexpr size_t PreferredInlineBytes = 1259 : kPreferredSmallVectorSizeof - sizeof(SmallVector<T, 0>); 1260 : static constexpr size_t NumElementsThatFit = PreferredInlineBytes / sizeof(T); 1261 : static constexpr size_t value = 1262 : NumElementsThatFit == 0 ? 1 : NumElementsThatFit; 1263 : }; 1264 : 1265 : /// This is a 'vector' (really, a variable-sized array), optimized 1266 : /// for the case when the array is small. It contains some number of elements 1267 : /// in-place, which allows it to avoid heap allocation when the actual number of 1268 : /// elements is below that threshold. This allows normal "small" cases to be 1269 : /// fast without losing generality for large inputs. 1270 : /// 1271 : /// \note 1272 : /// In the absence of a well-motivated choice for the number of inlined 1273 : /// elements \p N, it is recommended to use \c SmallVector<T> (that is, 1274 : /// omitting the \p N). This will choose a default number of inlined elements 1275 : /// reasonable for allocation on the stack (for example, trying to keep \c 1276 : /// sizeof(SmallVector<T>) around 64 bytes). 1277 : /// 1278 : /// \warning This does not attempt to be exception safe. 1279 : /// 1280 : /// \see https://llvm.org/docs/ProgrammersManual.html#llvm-adt-smallvector-h 1281 : template < 1282 : typename T, 1283 : unsigned N = CalculateSmallVectorDefaultInlinedElements<T>::value> 1284 : class /* LLVM_GSL_OWNER */ SmallVector : public SmallVectorImpl<T>, 1285 : SmallVectorStorage<T, N> { 1286 : public: 1287 0 : SmallVector() : SmallVectorImpl<T>(N) {} 1288 : 1289 0 : ~SmallVector() { 1290 : // Destroy the constructed elements in the vector. 1291 0 : this->destroy_range(this->begin(), this->end()); 1292 0 : } 1293 : 1294 : explicit SmallVector(size_t Size, const T& Value = T()) 1295 : : SmallVectorImpl<T>(N) { 1296 : this->assign(Size, Value); 1297 : } 1298 : 1299 : template < 1300 : typename ItTy, 1301 : typename = std::enable_if_t<std::is_convertible< 1302 : typename std::iterator_traits<ItTy>::iterator_category, 1303 : std::input_iterator_tag>::value>> 1304 : SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(N) { 1305 : this->append(S, E); 1306 : } 1307 : 1308 : // note: The enable_if restricts Container to types that have a .begin() and 1309 : // .end() that return valid input iterators. 1310 : template < 1311 : typename Container, 1312 : std::enable_if_t< 1313 : std::is_convertible< 1314 : typename std::iterator_traits< 1315 : decltype(std::declval<Container>() 1316 : .begin())>::iterator_category, 1317 : std::input_iterator_tag>::value && 1318 : std::is_convertible< 1319 : typename std::iterator_traits< 1320 : decltype(std::declval<Container>() 1321 : .end())>::iterator_category, 1322 : std::input_iterator_tag>::value, 1323 : int> = 0> 1324 : explicit SmallVector(Container&& c) : SmallVectorImpl<T>(N) { 1325 : this->append(c.begin(), c.end()); 1326 : } 1327 : 1328 : SmallVector(std::initializer_list<T> IL) : SmallVectorImpl<T>(N) { 1329 : this->assign(IL); 1330 : } 1331 : 1332 : SmallVector(const SmallVector& RHS) : SmallVectorImpl<T>(N) { 1333 : if (!RHS.empty()) 1334 : SmallVectorImpl<T>::operator=(RHS); 1335 : } 1336 : 1337 : SmallVector& operator=(const SmallVector& RHS) { 1338 : SmallVectorImpl<T>::operator=(RHS); 1339 : return *this; 1340 : } 1341 : 1342 : SmallVector(SmallVector&& RHS) : SmallVectorImpl<T>(N) { 1343 : if (!RHS.empty()) 1344 : SmallVectorImpl<T>::operator=(::std::move(RHS)); 1345 : } 1346 : 1347 : // note: The enable_if restricts Container to types that have a .begin() and 1348 : // .end() that return valid input iterators. 1349 : template < 1350 : typename Container, 1351 : std::enable_if_t< 1352 : std::is_convertible< 1353 : typename std::iterator_traits< 1354 : decltype(std::declval<Container>() 1355 : .begin())>::iterator_category, 1356 : std::input_iterator_tag>::value && 1357 : std::is_convertible< 1358 : typename std::iterator_traits< 1359 : decltype(std::declval<Container>() 1360 : .end())>::iterator_category, 1361 : std::input_iterator_tag>::value, 1362 : int> = 0> 1363 : const SmallVector& operator=(const Container& RHS) { 1364 : this->assign(RHS.begin(), RHS.end()); 1365 : return *this; 1366 : } 1367 : 1368 : SmallVector(SmallVectorImpl<T>&& RHS) : SmallVectorImpl<T>(N) { 1369 : if (!RHS.empty()) 1370 : SmallVectorImpl<T>::operator=(::std::move(RHS)); 1371 : } 1372 : 1373 : SmallVector& operator=(SmallVector&& RHS) { 1374 : SmallVectorImpl<T>::operator=(::std::move(RHS)); 1375 : return *this; 1376 : } 1377 : 1378 : SmallVector& operator=(SmallVectorImpl<T>&& RHS) { 1379 : SmallVectorImpl<T>::operator=(::std::move(RHS)); 1380 : return *this; 1381 : } 1382 : 1383 : // note: The enable_if restricts Container to types that have a .begin() and 1384 : // .end() that return valid input iterators. 1385 : template < 1386 : typename Container, 1387 : std::enable_if_t< 1388 : std::is_convertible< 1389 : typename std::iterator_traits< 1390 : decltype(std::declval<Container>() 1391 : .begin())>::iterator_category, 1392 : std::input_iterator_tag>::value && 1393 : std::is_convertible< 1394 : typename std::iterator_traits< 1395 : decltype(std::declval<Container>() 1396 : .end())>::iterator_category, 1397 : std::input_iterator_tag>::value, 1398 : int> = 0> 1399 : const SmallVector& operator=(Container&& C) { 1400 : this->assign(C.begin(), C.end()); 1401 : return *this; 1402 : } 1403 : 1404 : SmallVector& operator=(std::initializer_list<T> IL) { 1405 : this->assign(IL); 1406 : return *this; 1407 : } 1408 : }; 1409 : 1410 : template <typename T, unsigned N> 1411 : inline size_t capacity_in_bytes(const SmallVector<T, N>& X) { 1412 : return X.capacity_in_bytes(); 1413 : } 1414 : 1415 : template <typename T, unsigned N> 1416 : std::ostream& operator<<(std::ostream& out, const SmallVector<T, N>& list) { 1417 : int i = 0; 1418 : out << "["; 1419 : for (auto e : list) { 1420 : if (i++ > 0) 1421 : out << ", "; 1422 : out << e; 1423 : } 1424 : out << "]"; 1425 : return out; 1426 : } 1427 : 1428 : template <typename RangeType> 1429 : using ValueTypeFromRangeType = 1430 : typename std::remove_const<typename std::remove_reference< 1431 : decltype(*std::begin(std::declval<RangeType&>()))>::type>::type; 1432 : 1433 : /// Given a range of type R, iterate the entire range and return a 1434 : /// SmallVector with elements of the vector. This is useful, for example, 1435 : /// when you want to iterate a range and then sort the results. 1436 : template <unsigned Size, typename R> 1437 : SmallVector<ValueTypeFromRangeType<R>, Size> to_vector(R&& Range) { 1438 : return {std::begin(Range), std::end(Range)}; 1439 : } 1440 : template <typename R> 1441 : SmallVector< 1442 : ValueTypeFromRangeType<R>, 1443 : CalculateSmallVectorDefaultInlinedElements< 1444 : ValueTypeFromRangeType<R>>::value> 1445 : to_vector(R&& Range) { 1446 : return {std::begin(Range), std::end(Range)}; 1447 : } 1448 : 1449 : } // end namespace c10 1450 : 1451 : namespace std { 1452 : 1453 : /// Implement std::swap in terms of SmallVector swap. 1454 : template <typename T> 1455 : inline void swap(c10::SmallVectorImpl<T>& LHS, c10::SmallVectorImpl<T>& RHS) { 1456 : LHS.swap(RHS); 1457 : } 1458 : 1459 : /// Implement std::swap in terms of SmallVector swap. 1460 : template <typename T, unsigned N> 1461 : inline void swap(c10::SmallVector<T, N>& LHS, c10::SmallVector<T, N>& RHS) { 1462 : LHS.swap(RHS); 1463 : } 1464 : 1465 : } // end namespace std 1466 : 1467 : C10_CLANG_DIAGNOSTIC_POP() |
![]() |
Generated by: LCOV version 2.0-1 |
</html>