inlined_vector.h
Go to the documentation of this file.
00001 // Copyright 2019 The Abseil Authors.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //      https://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 //
00015 // -----------------------------------------------------------------------------
00016 // File: inlined_vector.h
00017 // -----------------------------------------------------------------------------
00018 //
00019 // This header file contains the declaration and definition of an "inlined
00020 // vector" which behaves in an equivalent fashion to a `std::vector`, except
00021 // that storage for small sequences of the vector are provided inline without
00022 // requiring any heap allocation.
00023 //
00024 // An `absl::InlinedVector<T, N>` specifies the default capacity `N` as one of
00025 // its template parameters. Instances where `size() <= N` hold contained
00026 // elements in inline space. Typically `N` is very small so that sequences that
00027 // are expected to be short do not require allocations.
00028 //
00029 // An `absl::InlinedVector` does not usually require a specific allocator. If
00030 // the inlined vector grows beyond its initial constraints, it will need to
00031 // allocate (as any normal `std::vector` would). This is usually performed with
00032 // the default allocator (defined as `std::allocator<T>`). Optionally, a custom
00033 // allocator type may be specified as `A` in `absl::InlinedVector<T, N, A>`.
00034 
00035 #ifndef ABSL_CONTAINER_INLINED_VECTOR_H_
00036 #define ABSL_CONTAINER_INLINED_VECTOR_H_
00037 
00038 #include <algorithm>
00039 #include <cassert>
00040 #include <cstddef>
00041 #include <cstdlib>
00042 #include <cstring>
00043 #include <initializer_list>
00044 #include <iterator>
00045 #include <memory>
00046 #include <type_traits>
00047 #include <utility>
00048 
00049 #include "absl/algorithm/algorithm.h"
00050 #include "absl/base/internal/throw_delegate.h"
00051 #include "absl/base/optimization.h"
00052 #include "absl/base/port.h"
00053 #include "absl/container/internal/inlined_vector.h"
00054 #include "absl/memory/memory.h"
00055 
00056 namespace absl {
00057 // -----------------------------------------------------------------------------
00058 // InlinedVector
00059 // -----------------------------------------------------------------------------
00060 //
00061 // An `absl::InlinedVector` is designed to be a drop-in replacement for
00062 // `std::vector` for use cases where the vector's size is sufficiently small
00063 // that it can be inlined. If the inlined vector does grow beyond its estimated
00064 // capacity, it will trigger an initial allocation on the heap, and will behave
00065 // as a `std:vector`. The API of the `absl::InlinedVector` within this file is
00066 // designed to cover the same API footprint as covered by `std::vector`.
00067 template <typename T, size_t N, typename A = std::allocator<T>>
00068 class InlinedVector {
00069   static_assert(
00070       N > 0, "InlinedVector cannot be instantiated with `0` inlined elements.");
00071 
00072   using Storage = inlined_vector_internal::Storage<T, N, A>;
00073   using AllocatorTraits = typename Storage::AllocatorTraits;
00074 
00075   template <typename Iterator>
00076   using EnableIfAtLeastForwardIterator = absl::enable_if_t<
00077       inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value>;
00078 
00079   template <typename Iterator>
00080   using DisableIfAtLeastForwardIterator = absl::enable_if_t<
00081       !inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value>;
00082 
00083   using rvalue_reference = typename Storage::rvalue_reference;
00084 
00085  public:
00086   using allocator_type = typename Storage::allocator_type;
00087   using value_type = typename Storage::value_type;
00088   using pointer = typename Storage::pointer;
00089   using const_pointer = typename Storage::const_pointer;
00090   using reference = typename Storage::reference;
00091   using const_reference = typename Storage::const_reference;
00092   using size_type = typename Storage::size_type;
00093   using difference_type = typename Storage::difference_type;
00094   using iterator = typename Storage::iterator;
00095   using const_iterator = typename Storage::const_iterator;
00096   using reverse_iterator = typename Storage::reverse_iterator;
00097   using const_reverse_iterator = typename Storage::const_reverse_iterator;
00098 
00099   // ---------------------------------------------------------------------------
00100   // InlinedVector Constructors and Destructor
00101   // ---------------------------------------------------------------------------
00102 
00103   // Creates an empty inlined vector with a default initialized allocator.
00104   InlinedVector() noexcept(noexcept(allocator_type()))
00105       : storage_(allocator_type()) {}
00106 
00107   // Creates an empty inlined vector with a specified allocator.
00108   explicit InlinedVector(const allocator_type& alloc) noexcept
00109       : storage_(alloc) {}
00110 
00111   // Creates an inlined vector with `n` copies of `value_type()`.
00112   explicit InlinedVector(size_type n,
00113                          const allocator_type& alloc = allocator_type())
00114       : storage_(alloc) {
00115     InitAssign(n);
00116   }
00117 
00118   // Creates an inlined vector with `n` copies of `v`.
00119   InlinedVector(size_type n, const_reference v,
00120                 const allocator_type& alloc = allocator_type())
00121       : storage_(alloc) {
00122     InitAssign(n, v);
00123   }
00124 
00125   // Creates an inlined vector of copies of the values in `list`.
00126   InlinedVector(std::initializer_list<value_type> list,
00127                 const allocator_type& alloc = allocator_type())
00128       : storage_(alloc) {
00129     AppendForwardRange(list.begin(), list.end());
00130   }
00131 
00132   // Creates an inlined vector with elements constructed from the provided
00133   // forward iterator range [`first`, `last`).
00134   //
00135   // NOTE: The `enable_if` prevents ambiguous interpretation between a call to
00136   // this constructor with two integral arguments and a call to the above
00137   // `InlinedVector(size_type, const_reference)` constructor.
00138   template <typename ForwardIterator,
00139             EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
00140   InlinedVector(ForwardIterator first, ForwardIterator last,
00141                 const allocator_type& alloc = allocator_type())
00142       : storage_(alloc) {
00143     AppendForwardRange(first, last);
00144   }
00145 
00146   // Creates an inlined vector with elements constructed from the provided input
00147   // iterator range [`first`, `last`).
00148   template <typename InputIterator,
00149             DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
00150   InlinedVector(InputIterator first, InputIterator last,
00151                 const allocator_type& alloc = allocator_type())
00152       : storage_(alloc) {
00153     std::copy(first, last, std::back_inserter(*this));
00154   }
00155 
00156   // Creates a copy of an `other` inlined vector using `other`'s allocator.
00157   InlinedVector(const InlinedVector& other)
00158       : InlinedVector(other, *other.storage_.GetAllocPtr()) {}
00159 
00160   // Creates a copy of an `other` inlined vector using a specified allocator.
00161   InlinedVector(const InlinedVector& other, const allocator_type& alloc)
00162       : storage_(alloc) {
00163     reserve(other.size());
00164     if (storage_.GetIsAllocated()) {
00165       UninitializedCopy(other.begin(), other.end(),
00166                         storage_.GetAllocatedData());
00167       storage_.SetAllocatedSize(other.size());
00168     } else {
00169       UninitializedCopy(other.begin(), other.end(), storage_.GetInlinedData());
00170       storage_.SetInlinedSize(other.size());
00171     }
00172   }
00173 
00174   // Creates an inlined vector by moving in the contents of an `other` inlined
00175   // vector without performing any allocations. If `other` contains allocated
00176   // memory, the newly-created instance will take ownership of that memory
00177   // (leaving `other` empty). However, if `other` does not contain allocated
00178   // memory (i.e. is inlined), the new inlined vector will perform element-wise
00179   // move construction of `other`'s elements.
00180   //
00181   // NOTE: since no allocation is performed for the inlined vector in either
00182   // case, the `noexcept(...)` specification depends on whether moving the
00183   // underlying objects can throw. We assume:
00184   //  a) Move constructors should only throw due to allocation failure.
00185   //  b) If `value_type`'s move constructor allocates, it uses the same
00186   //     allocation function as the `InlinedVector`'s allocator. Thus, the move
00187   //     constructor is non-throwing if the allocator is non-throwing or
00188   //     `value_type`'s move constructor is specified as `noexcept`.
00189   InlinedVector(InlinedVector&& other) noexcept(
00190       absl::allocator_is_nothrow<allocator_type>::value ||
00191       std::is_nothrow_move_constructible<value_type>::value)
00192       : storage_(*other.storage_.GetAllocPtr()) {
00193     if (other.storage_.GetIsAllocated()) {
00194       // We can just steal the underlying buffer from the source.
00195       // That leaves the source empty, so we clear its size.
00196       storage_.SetAllocatedData(other.storage_.GetAllocatedData());
00197       storage_.SetAllocatedCapacity(other.storage_.GetAllocatedCapacity());
00198       storage_.SetAllocatedSize(other.size());
00199       other.storage_.SetInlinedSize(0);
00200     } else {
00201       UninitializedCopy(
00202           std::make_move_iterator(other.storage_.GetInlinedData()),
00203           std::make_move_iterator(other.storage_.GetInlinedData() +
00204                                   other.size()),
00205           storage_.GetInlinedData());
00206       storage_.SetInlinedSize(other.size());
00207     }
00208   }
00209 
00210   // Creates an inlined vector by moving in the contents of an `other` inlined
00211   // vector, performing allocations with the specified `alloc` allocator. If
00212   // `other`'s allocator is not equal to `alloc` and `other` contains allocated
00213   // memory, this move constructor will create a new allocation.
00214   //
00215   // NOTE: since allocation is performed in this case, this constructor can
00216   // only be `noexcept` if the specified allocator is also `noexcept`. If this
00217   // is the case, or if `other` contains allocated memory, this constructor
00218   // performs element-wise move construction of its contents.
00219   //
00220   // Only in the case where `other`'s allocator is equal to `alloc` and `other`
00221   // contains allocated memory will the newly created inlined vector take
00222   // ownership of `other`'s allocated memory.
00223   InlinedVector(InlinedVector&& other, const allocator_type& alloc) noexcept(
00224       absl::allocator_is_nothrow<allocator_type>::value)
00225       : storage_(alloc) {
00226     if (other.storage_.GetIsAllocated()) {
00227       if (*storage_.GetAllocPtr() == *other.storage_.GetAllocPtr()) {
00228         // We can just steal the allocation from the source.
00229         storage_.SetAllocatedSize(other.size());
00230         storage_.SetAllocatedData(other.storage_.GetAllocatedData());
00231         storage_.SetAllocatedCapacity(other.storage_.GetAllocatedCapacity());
00232         other.storage_.SetInlinedSize(0);
00233       } else {
00234         // We need to use our own allocator
00235         reserve(other.size());
00236         UninitializedCopy(std::make_move_iterator(other.begin()),
00237                           std::make_move_iterator(other.end()),
00238                           storage_.GetAllocatedData());
00239         storage_.SetAllocatedSize(other.size());
00240       }
00241     } else {
00242       UninitializedCopy(
00243           std::make_move_iterator(other.storage_.GetInlinedData()),
00244           std::make_move_iterator(other.storage_.GetInlinedData() +
00245                                   other.size()),
00246           storage_.GetInlinedData());
00247       storage_.SetInlinedSize(other.size());
00248     }
00249   }
00250 
00251   ~InlinedVector() { clear(); }
00252 
00253   // ---------------------------------------------------------------------------
00254   // InlinedVector Member Accessors
00255   // ---------------------------------------------------------------------------
00256 
00257   // `InlinedVector::empty()`
00258   //
00259   // Checks if the inlined vector has no elements.
00260   bool empty() const noexcept { return !size(); }
00261 
00262   // `InlinedVector::size()`
00263   //
00264   // Returns the number of elements in the inlined vector.
00265   size_type size() const noexcept { return storage_.GetSize(); }
00266 
00267   // `InlinedVector::max_size()`
00268   //
00269   // Returns the maximum number of elements the vector can hold.
00270   size_type max_size() const noexcept {
00271     // One bit of the size storage is used to indicate whether the inlined
00272     // vector is allocated. As a result, the maximum size of the container that
00273     // we can express is half of the max for `size_type`.
00274     return (std::numeric_limits<size_type>::max)() / 2;
00275   }
00276 
00277   // `InlinedVector::capacity()`
00278   //
00279   // Returns the number of elements that can be stored in the inlined vector
00280   // without requiring a reallocation of underlying memory.
00281   //
00282   // NOTE: For most inlined vectors, `capacity()` should equal the template
00283   // parameter `N`. For inlined vectors which exceed this capacity, they
00284   // will no longer be inlined and `capacity()` will equal its capacity on the
00285   // allocated heap.
00286   size_type capacity() const noexcept {
00287     return storage_.GetIsAllocated() ? storage_.GetAllocatedCapacity()
00288                                      : static_cast<size_type>(N);
00289   }
00290 
00291   // `InlinedVector::data()`
00292   //
00293   // Returns a `pointer` to elements of the inlined vector. This pointer can be
00294   // used to access and modify the contained elements.
00295   // Only results within the range [`0`, `size()`) are defined.
00296   pointer data() noexcept {
00297     return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
00298                                      : storage_.GetInlinedData();
00299   }
00300 
00301   // Overload of `InlinedVector::data()` to return a `const_pointer` to elements
00302   // of the inlined vector. This pointer can be used to access (but not modify)
00303   // the contained elements.
00304   const_pointer data() const noexcept {
00305     return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
00306                                      : storage_.GetInlinedData();
00307   }
00308 
00309   // `InlinedVector::operator[]()`
00310   //
00311   // Returns a `reference` to the `i`th element of the inlined vector using the
00312   // array operator.
00313   reference operator[](size_type i) {
00314     assert(i < size());
00315     return data()[i];
00316   }
00317 
00318   // Overload of `InlinedVector::operator[]()` to return a `const_reference` to
00319   // the `i`th element of the inlined vector.
00320   const_reference operator[](size_type i) const {
00321     assert(i < size());
00322     return data()[i];
00323   }
00324 
00325   // `InlinedVector::at()`
00326   //
00327   // Returns a `reference` to the `i`th element of the inlined vector.
00328   reference at(size_type i) {
00329     if (ABSL_PREDICT_FALSE(i >= size())) {
00330       base_internal::ThrowStdOutOfRange(
00331           "`InlinedVector::at(size_type)` failed bounds check");
00332     }
00333     return data()[i];
00334   }
00335 
00336   // Overload of `InlinedVector::at()` to return a `const_reference` to the
00337   // `i`th element of the inlined vector.
00338   const_reference at(size_type i) const {
00339     if (ABSL_PREDICT_FALSE(i >= size())) {
00340       base_internal::ThrowStdOutOfRange(
00341           "`InlinedVector::at(size_type) const` failed bounds check");
00342     }
00343     return data()[i];
00344   }
00345 
00346   // `InlinedVector::front()`
00347   //
00348   // Returns a `reference` to the first element of the inlined vector.
00349   reference front() {
00350     assert(!empty());
00351     return at(0);
00352   }
00353 
00354   // Overload of `InlinedVector::front()` returns a `const_reference` to the
00355   // first element of the inlined vector.
00356   const_reference front() const {
00357     assert(!empty());
00358     return at(0);
00359   }
00360 
00361   // `InlinedVector::back()`
00362   //
00363   // Returns a `reference` to the last element of the inlined vector.
00364   reference back() {
00365     assert(!empty());
00366     return at(size() - 1);
00367   }
00368 
00369   // Overload of `InlinedVector::back()` to return a `const_reference` to the
00370   // last element of the inlined vector.
00371   const_reference back() const {
00372     assert(!empty());
00373     return at(size() - 1);
00374   }
00375 
00376   // `InlinedVector::begin()`
00377   //
00378   // Returns an `iterator` to the beginning of the inlined vector.
00379   iterator begin() noexcept { return data(); }
00380 
00381   // Overload of `InlinedVector::begin()` to return a `const_iterator` to
00382   // the beginning of the inlined vector.
00383   const_iterator begin() const noexcept { return data(); }
00384 
00385   // `InlinedVector::end()`
00386   //
00387   // Returns an `iterator` to the end of the inlined vector.
00388   iterator end() noexcept { return data() + size(); }
00389 
00390   // Overload of `InlinedVector::end()` to return a `const_iterator` to the
00391   // end of the inlined vector.
00392   const_iterator end() const noexcept { return data() + size(); }
00393 
00394   // `InlinedVector::cbegin()`
00395   //
00396   // Returns a `const_iterator` to the beginning of the inlined vector.
00397   const_iterator cbegin() const noexcept { return begin(); }
00398 
00399   // `InlinedVector::cend()`
00400   //
00401   // Returns a `const_iterator` to the end of the inlined vector.
00402   const_iterator cend() const noexcept { return end(); }
00403 
00404   // `InlinedVector::rbegin()`
00405   //
00406   // Returns a `reverse_iterator` from the end of the inlined vector.
00407   reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
00408 
00409   // Overload of `InlinedVector::rbegin()` to return a
00410   // `const_reverse_iterator` from the end of the inlined vector.
00411   const_reverse_iterator rbegin() const noexcept {
00412     return const_reverse_iterator(end());
00413   }
00414 
00415   // `InlinedVector::rend()`
00416   //
00417   // Returns a `reverse_iterator` from the beginning of the inlined vector.
00418   reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
00419 
00420   // Overload of `InlinedVector::rend()` to return a `const_reverse_iterator`
00421   // from the beginning of the inlined vector.
00422   const_reverse_iterator rend() const noexcept {
00423     return const_reverse_iterator(begin());
00424   }
00425 
00426   // `InlinedVector::crbegin()`
00427   //
00428   // Returns a `const_reverse_iterator` from the end of the inlined vector.
00429   const_reverse_iterator crbegin() const noexcept { return rbegin(); }
00430 
00431   // `InlinedVector::crend()`
00432   //
00433   // Returns a `const_reverse_iterator` from the beginning of the inlined
00434   // vector.
00435   const_reverse_iterator crend() const noexcept { return rend(); }
00436 
00437   // `InlinedVector::get_allocator()`
00438   //
00439   // Returns a copy of the allocator of the inlined vector.
00440   allocator_type get_allocator() const { return *storage_.GetAllocPtr(); }
00441 
00442   // ---------------------------------------------------------------------------
00443   // InlinedVector Member Mutators
00444   // ---------------------------------------------------------------------------
00445 
00446   // `InlinedVector::operator=()`
00447   //
00448   // Replaces the contents of the inlined vector with copies of the elements in
00449   // the provided `std::initializer_list`.
00450   InlinedVector& operator=(std::initializer_list<value_type> list) {
00451     assign(list.begin(), list.end());
00452     return *this;
00453   }
00454 
00455   // Overload of `InlinedVector::operator=()` to replace the contents of the
00456   // inlined vector with the contents of `other`.
00457   InlinedVector& operator=(const InlinedVector& other) {
00458     if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
00459       const_pointer other_data = other.data();
00460       assign(other_data, other_data + other.size());
00461     }
00462     return *this;
00463   }
00464 
00465   // Overload of `InlinedVector::operator=()` to replace the contents of the
00466   // inlined vector with the contents of `other`.
00467   //
00468   // NOTE: As a result of calling this overload, `other` may be empty or it's
00469   // contents may be left in a moved-from state.
00470   InlinedVector& operator=(InlinedVector&& other) {
00471     if (ABSL_PREDICT_FALSE(this == std::addressof(other))) return *this;
00472 
00473     if (other.storage_.GetIsAllocated()) {
00474       clear();
00475       storage_.SetAllocatedSize(other.size());
00476       storage_.SetAllocatedData(other.storage_.GetAllocatedData());
00477       storage_.SetAllocatedCapacity(other.storage_.GetAllocatedCapacity());
00478       other.storage_.SetInlinedSize(0);
00479     } else {
00480       if (storage_.GetIsAllocated()) clear();
00481       // Both are inlined now.
00482       if (size() < other.size()) {
00483         auto mid = std::make_move_iterator(other.begin() + size());
00484         std::copy(std::make_move_iterator(other.begin()), mid, begin());
00485         UninitializedCopy(mid, std::make_move_iterator(other.end()), end());
00486       } else {
00487         auto new_end = std::copy(std::make_move_iterator(other.begin()),
00488                                  std::make_move_iterator(other.end()), begin());
00489         Destroy(new_end, end());
00490       }
00491       storage_.SetInlinedSize(other.size());
00492     }
00493     return *this;
00494   }
00495 
00496   // `InlinedVector::assign()`
00497   //
00498   // Replaces the contents of the inlined vector with `n` copies of `v`.
00499   void assign(size_type n, const_reference v) {
00500     if (n <= size()) {  // Possibly shrink
00501       std::fill_n(begin(), n, v);
00502       erase(begin() + n, end());
00503       return;
00504     }
00505     // Grow
00506     reserve(n);
00507     std::fill_n(begin(), size(), v);
00508     if (storage_.GetIsAllocated()) {
00509       UninitializedFill(storage_.GetAllocatedData() + size(),
00510                         storage_.GetAllocatedData() + n, v);
00511       storage_.SetAllocatedSize(n);
00512     } else {
00513       UninitializedFill(storage_.GetInlinedData() + size(),
00514                         storage_.GetInlinedData() + n, v);
00515       storage_.SetInlinedSize(n);
00516     }
00517   }
00518 
00519   // Overload of `InlinedVector::assign()` to replace the contents of the
00520   // inlined vector with copies of the values in the provided
00521   // `std::initializer_list`.
00522   void assign(std::initializer_list<value_type> list) {
00523     assign(list.begin(), list.end());
00524   }
00525 
00526   // Overload of `InlinedVector::assign()` to replace the contents of the
00527   // inlined vector with the forward iterator range [`first`, `last`).
00528   template <typename ForwardIterator,
00529             EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
00530   void assign(ForwardIterator first, ForwardIterator last) {
00531     auto length = std::distance(first, last);
00532 
00533     // Prefer reassignment to copy construction for elements.
00534     if (static_cast<size_type>(length) <= size()) {
00535       erase(std::copy(first, last, begin()), end());
00536       return;
00537     }
00538 
00539     reserve(length);
00540     iterator out = begin();
00541     for (; out != end(); ++first, ++out) *out = *first;
00542     if (storage_.GetIsAllocated()) {
00543       UninitializedCopy(first, last, out);
00544       storage_.SetAllocatedSize(length);
00545     } else {
00546       UninitializedCopy(first, last, out);
00547       storage_.SetInlinedSize(length);
00548     }
00549   }
00550 
00551   // Overload of `InlinedVector::assign()` to replace the contents of the
00552   // inlined vector with the input iterator range [`first`, `last`).
00553   template <typename InputIterator,
00554             DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
00555   void assign(InputIterator first, InputIterator last) {
00556     size_type assign_index = 0;
00557     for (; (assign_index < size()) && (first != last);
00558          static_cast<void>(++assign_index), static_cast<void>(++first)) {
00559       *(data() + assign_index) = *first;
00560     }
00561     erase(data() + assign_index, data() + size());
00562     std::copy(first, last, std::back_inserter(*this));
00563   }
00564 
00565   // `InlinedVector::resize()`
00566   //
00567   // Resizes the inlined vector to contain `n` elements. If `n` is smaller than
00568   // the inlined vector's current size, extra elements are destroyed. If `n` is
00569   // larger than the initial size, new elements are value-initialized.
00570   void resize(size_type n) {
00571     size_type s = size();
00572     if (n < s) {
00573       erase(begin() + n, end());
00574       return;
00575     }
00576     reserve(n);
00577     assert(capacity() >= n);
00578 
00579     // Fill new space with elements constructed in-place.
00580     if (storage_.GetIsAllocated()) {
00581       UninitializedFill(storage_.GetAllocatedData() + s,
00582                         storage_.GetAllocatedData() + n);
00583       storage_.SetAllocatedSize(n);
00584     } else {
00585       UninitializedFill(storage_.GetInlinedData() + s,
00586                         storage_.GetInlinedData() + n);
00587       storage_.SetInlinedSize(n);
00588     }
00589   }
00590 
00591   // Overload of `InlinedVector::resize()` to resize the inlined vector to
00592   // contain `n` elements where, if `n` is larger than `size()`, the new values
00593   // will be copy-constructed from `v`.
00594   void resize(size_type n, const_reference v) {
00595     size_type s = size();
00596     if (n < s) {
00597       erase(begin() + n, end());
00598       return;
00599     }
00600     reserve(n);
00601     assert(capacity() >= n);
00602 
00603     // Fill new space with copies of `v`.
00604     if (storage_.GetIsAllocated()) {
00605       UninitializedFill(storage_.GetAllocatedData() + s,
00606                         storage_.GetAllocatedData() + n, v);
00607       storage_.SetAllocatedSize(n);
00608     } else {
00609       UninitializedFill(storage_.GetInlinedData() + s,
00610                         storage_.GetInlinedData() + n, v);
00611       storage_.SetInlinedSize(n);
00612     }
00613   }
00614 
00615   // `InlinedVector::insert()`
00616   //
00617   // Copies `v` into `pos`, returning an `iterator` pointing to the newly
00618   // inserted element.
00619   iterator insert(const_iterator pos, const_reference v) {
00620     return emplace(pos, v);
00621   }
00622 
00623   // Overload of `InlinedVector::insert()` for moving `v` into `pos`, returning
00624   // an iterator pointing to the newly inserted element.
00625   iterator insert(const_iterator pos, rvalue_reference v) {
00626     return emplace(pos, std::move(v));
00627   }
00628 
00629   // Overload of `InlinedVector::insert()` for inserting `n` contiguous copies
00630   // of `v` starting at `pos`. Returns an `iterator` pointing to the first of
00631   // the newly inserted elements.
00632   iterator insert(const_iterator pos, size_type n, const_reference v) {
00633     return InsertWithCount(pos, n, v);
00634   }
00635 
00636   // Overload of `InlinedVector::insert()` for copying the contents of the
00637   // `std::initializer_list` into the vector starting at `pos`. Returns an
00638   // `iterator` pointing to the first of the newly inserted elements.
00639   iterator insert(const_iterator pos, std::initializer_list<value_type> list) {
00640     return insert(pos, list.begin(), list.end());
00641   }
00642 
00643   // Overload of `InlinedVector::insert()` for inserting elements constructed
00644   // from the forward iterator range [`first`, `last`). Returns an `iterator`
00645   // pointing to the first of the newly inserted elements.
00646   //
00647   // NOTE: The `enable_if` is intended to disambiguate the two three-argument
00648   // overloads of `insert()`.
00649   template <typename ForwardIterator,
00650             EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
00651   iterator insert(const_iterator pos, ForwardIterator first,
00652                   ForwardIterator last) {
00653     return InsertWithForwardRange(pos, first, last);
00654   }
00655 
00656   // Overload of `InlinedVector::insert()` for inserting elements constructed
00657   // from the input iterator range [`first`, `last`). Returns an `iterator`
00658   // pointing to the first of the newly inserted elements.
00659   template <typename InputIterator,
00660             DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
00661   iterator insert(const_iterator pos, InputIterator first, InputIterator last) {
00662     size_type initial_insert_index = std::distance(cbegin(), pos);
00663     for (size_type insert_index = initial_insert_index; first != last;
00664          static_cast<void>(++insert_index), static_cast<void>(++first)) {
00665       insert(data() + insert_index, *first);
00666     }
00667     return iterator(data() + initial_insert_index);
00668   }
00669 
00670   // `InlinedVector::emplace()`
00671   //
00672   // Constructs and inserts an object in the inlined vector at the given `pos`,
00673   // returning an `iterator` pointing to the newly emplaced element.
00674   template <typename... Args>
00675   iterator emplace(const_iterator pos, Args&&... args) {
00676     assert(pos >= begin());
00677     assert(pos <= end());
00678     if (ABSL_PREDICT_FALSE(pos == end())) {
00679       emplace_back(std::forward<Args>(args)...);
00680       return end() - 1;
00681     }
00682 
00683     T new_t = T(std::forward<Args>(args)...);
00684 
00685     auto range = ShiftRight(pos, 1);
00686     if (range.first == range.second) {
00687       // constructing into uninitialized memory
00688       Construct(range.first, std::move(new_t));
00689     } else {
00690       // assigning into moved-from object
00691       *range.first = T(std::move(new_t));
00692     }
00693 
00694     return range.first;
00695   }
00696 
00697   // `InlinedVector::emplace_back()`
00698   //
00699   // Constructs and appends a new element to the end of the inlined vector,
00700   // returning a `reference` to the emplaced element.
00701   template <typename... Args>
00702   reference emplace_back(Args&&... args) {
00703     size_type s = size();
00704     if (ABSL_PREDICT_FALSE(s == capacity())) {
00705       return GrowAndEmplaceBack(std::forward<Args>(args)...);
00706     }
00707     pointer space;
00708     if (storage_.GetIsAllocated()) {
00709       storage_.SetAllocatedSize(s + 1);
00710       space = storage_.GetAllocatedData();
00711     } else {
00712       storage_.SetInlinedSize(s + 1);
00713       space = storage_.GetInlinedData();
00714     }
00715     return Construct(space + s, std::forward<Args>(args)...);
00716   }
00717 
00718   // `InlinedVector::push_back()`
00719   //
00720   // Appends a copy of `v` to the end of the inlined vector.
00721   void push_back(const_reference v) { static_cast<void>(emplace_back(v)); }
00722 
00723   // Overload of `InlinedVector::push_back()` for moving `v` into a newly
00724   // appended element.
00725   void push_back(rvalue_reference v) {
00726     static_cast<void>(emplace_back(std::move(v)));
00727   }
00728 
00729   // `InlinedVector::pop_back()`
00730   //
00731   // Destroys the element at the end of the inlined vector and shrinks the size
00732   // by `1` (unless the inlined vector is empty, in which case this is a no-op).
00733   void pop_back() noexcept {
00734     assert(!empty());
00735     size_type s = size();
00736     if (storage_.GetIsAllocated()) {
00737       Destroy(storage_.GetAllocatedData() + s - 1,
00738               storage_.GetAllocatedData() + s);
00739       storage_.SetAllocatedSize(s - 1);
00740     } else {
00741       Destroy(storage_.GetInlinedData() + s - 1, storage_.GetInlinedData() + s);
00742       storage_.SetInlinedSize(s - 1);
00743     }
00744   }
00745 
00746   // `InlinedVector::erase()`
00747   //
00748   // Erases the element at `pos` of the inlined vector, returning an `iterator`
00749   // pointing to the first element following the erased element.
00750   //
00751   // NOTE: May return the end iterator, which is not dereferencable.
00752   iterator erase(const_iterator pos) {
00753     assert(pos >= begin());
00754     assert(pos < end());
00755 
00756     iterator position = const_cast<iterator>(pos);
00757     std::move(position + 1, end(), position);
00758     pop_back();
00759     return position;
00760   }
00761 
00762   // Overload of `InlinedVector::erase()` for erasing all elements in the
00763   // range [`from`, `to`) in the inlined vector. Returns an `iterator` pointing
00764   // to the first element following the range erased or the end iterator if `to`
00765   // was the end iterator.
00766   iterator erase(const_iterator from, const_iterator to) {
00767     assert(begin() <= from);
00768     assert(from <= to);
00769     assert(to <= end());
00770 
00771     iterator range_start = const_cast<iterator>(from);
00772     iterator range_end = const_cast<iterator>(to);
00773 
00774     size_type s = size();
00775     ptrdiff_t erase_gap = std::distance(range_start, range_end);
00776     if (erase_gap > 0) {
00777       pointer space;
00778       if (storage_.GetIsAllocated()) {
00779         space = storage_.GetAllocatedData();
00780         storage_.SetAllocatedSize(s - erase_gap);
00781       } else {
00782         space = storage_.GetInlinedData();
00783         storage_.SetInlinedSize(s - erase_gap);
00784       }
00785       std::move(range_end, space + s, range_start);
00786       Destroy(space + s - erase_gap, space + s);
00787     }
00788     return range_start;
00789   }
00790 
00791   // `InlinedVector::clear()`
00792   //
00793   // Destroys all elements in the inlined vector, sets the size of `0` and
00794   // deallocates the heap allocation if the inlined vector was allocated.
00795   void clear() noexcept {
00796     const bool is_allocated = storage_.GetIsAllocated();
00797     pointer the_data =
00798         is_allocated ? storage_.GetAllocatedData() : storage_.GetInlinedData();
00799     inlined_vector_internal::DestroyElements(storage_.GetAllocPtr(), the_data,
00800                                              storage_.GetSize());
00801     storage_.SetInlinedSize(0);
00802     if (is_allocated) {
00803       AllocatorTraits::deallocate(*storage_.GetAllocPtr(), the_data,
00804                                   storage_.GetAllocatedCapacity());
00805     }
00806   }
00807 
00808   // `InlinedVector::reserve()`
00809   //
00810   // Enlarges the underlying representation of the inlined vector so it can hold
00811   // at least `n` elements. This method does not change `size()` or the actual
00812   // contents of the vector.
00813   //
00814   // NOTE: If `n` does not exceed `capacity()`, `reserve()` will have no
00815   // effects. Otherwise, `reserve()` will reallocate, performing an n-time
00816   // element-wise move of everything contained.
00817   void reserve(size_type n) {
00818     if (n > capacity()) {
00819       // Make room for new elements
00820       EnlargeBy(n - size());
00821     }
00822   }
00823 
00824   // `InlinedVector::shrink_to_fit()`
00825   //
00826   // Reduces memory usage by freeing unused memory. After this call, calls to
00827   // `capacity()` will be equal to `max(N, size())`.
00828   //
00829   // If `size() <= N` and the elements are currently stored on the heap, they
00830   // will be moved to the inlined storage and the heap memory will be
00831   // deallocated.
00832   //
00833   // If `size() > N` and `size() < capacity()` the elements will be moved to a
00834   // smaller heap allocation.
00835   void shrink_to_fit() {
00836     const auto s = size();
00837     if (ABSL_PREDICT_FALSE(!storage_.GetIsAllocated() || s == capacity()))
00838       return;
00839 
00840     if (s <= N) {
00841       // Move the elements to the inlined storage.
00842       // We have to do this using a temporary, because `inlined_storage` and
00843       // `allocation_storage` are in a union field.
00844       auto temp = std::move(*this);
00845       assign(std::make_move_iterator(temp.begin()),
00846              std::make_move_iterator(temp.end()));
00847       return;
00848     }
00849 
00850     // Reallocate storage and move elements.
00851     // We can't simply use the same approach as above, because `assign()` would
00852     // call into `reserve()` internally and reserve larger capacity than we need
00853     pointer new_data = AllocatorTraits::allocate(*storage_.GetAllocPtr(), s);
00854     UninitializedCopy(std::make_move_iterator(storage_.GetAllocatedData()),
00855                       std::make_move_iterator(storage_.GetAllocatedData() + s),
00856                       new_data);
00857     ResetAllocation(new_data, s, s);
00858   }
00859 
00860   // `InlinedVector::swap()`
00861   //
00862   // Swaps the contents of this inlined vector with the contents of `other`.
00863   void swap(InlinedVector& other) {
00864     if (ABSL_PREDICT_FALSE(this == std::addressof(other))) return;
00865 
00866     SwapImpl(other);
00867   }
00868 
00869  private:
00870   template <typename H, typename TheT, size_t TheN, typename TheA>
00871   friend H AbslHashValue(H h, const absl::InlinedVector<TheT, TheN, TheA>& a);
00872 
00873   void ResetAllocation(pointer new_data, size_type new_capacity,
00874                        size_type new_size) {
00875     if (storage_.GetIsAllocated()) {
00876       Destroy(storage_.GetAllocatedData(),
00877               storage_.GetAllocatedData() + size());
00878       assert(begin() == storage_.GetAllocatedData());
00879       AllocatorTraits::deallocate(*storage_.GetAllocPtr(),
00880                                   storage_.GetAllocatedData(),
00881                                   storage_.GetAllocatedCapacity());
00882     } else {
00883       Destroy(storage_.GetInlinedData(), storage_.GetInlinedData() + size());
00884     }
00885 
00886     storage_.SetAllocatedData(new_data);
00887     storage_.SetAllocatedCapacity(new_capacity);
00888     storage_.SetAllocatedSize(new_size);
00889   }
00890 
00891   template <typename... Args>
00892   reference Construct(pointer p, Args&&... args) {
00893     std::allocator_traits<allocator_type>::construct(
00894         *storage_.GetAllocPtr(), p, std::forward<Args>(args)...);
00895     return *p;
00896   }
00897 
00898   template <typename Iterator>
00899   void UninitializedCopy(Iterator src, Iterator src_last, pointer dst) {
00900     for (; src != src_last; ++dst, ++src) Construct(dst, *src);
00901   }
00902 
00903   template <typename... Args>
00904   void UninitializedFill(pointer dst, pointer dst_last, const Args&... args) {
00905     for (; dst != dst_last; ++dst) Construct(dst, args...);
00906   }
00907 
00908   // Destroy [`from`, `to`) in place.
00909   void Destroy(pointer from, pointer to) {
00910     for (pointer cur = from; cur != to; ++cur) {
00911       std::allocator_traits<allocator_type>::destroy(*storage_.GetAllocPtr(),
00912                                                      cur);
00913     }
00914 #if !defined(NDEBUG)
00915     // Overwrite unused memory with `0xab` so we can catch uninitialized usage.
00916     // Cast to `void*` to tell the compiler that we don't care that we might be
00917     // scribbling on a vtable pointer.
00918     if (from != to) {
00919       auto len = sizeof(value_type) * std::distance(from, to);
00920       std::memset(reinterpret_cast<void*>(from), 0xab, len);
00921     }
00922 #endif  // !defined(NDEBUG)
00923   }
00924 
00925   // Enlarge the underlying representation so we can store `size_ + delta` elems
00926   // in allocated space. The size is not changed, and any newly added memory is
00927   // not initialized.
00928   void EnlargeBy(size_type delta) {
00929     const size_type s = size();
00930     assert(s <= capacity());
00931 
00932     size_type target = (std::max)(static_cast<size_type>(N), s + delta);
00933 
00934     // Compute new capacity by repeatedly doubling current capacity
00935     // TODO(psrc): Check and avoid overflow?
00936     size_type new_capacity = capacity();
00937     while (new_capacity < target) {
00938       new_capacity <<= 1;
00939     }
00940 
00941     pointer new_data =
00942         AllocatorTraits::allocate(*storage_.GetAllocPtr(), new_capacity);
00943 
00944     UninitializedCopy(std::make_move_iterator(data()),
00945                       std::make_move_iterator(data() + s), new_data);
00946 
00947     ResetAllocation(new_data, new_capacity, s);
00948   }
00949 
00950   // Shift all elements from `position` to `end()` by `n` places to the right.
00951   // If the vector needs to be enlarged, memory will be allocated.
00952   // Returns `iterator`s pointing to the start of the previously-initialized
00953   // portion and the start of the uninitialized portion of the created gap.
00954   // The number of initialized spots is `pair.second - pair.first`. The number
00955   // of raw spots is `n - (pair.second - pair.first)`.
00956   //
00957   // Updates the size of the InlinedVector internally.
00958   std::pair<iterator, iterator> ShiftRight(const_iterator position,
00959                                            size_type n) {
00960     iterator start_used = const_cast<iterator>(position);
00961     iterator start_raw = const_cast<iterator>(position);
00962     size_type s = size();
00963     size_type required_size = s + n;
00964 
00965     if (required_size > capacity()) {
00966       // Compute new capacity by repeatedly doubling current capacity
00967       size_type new_capacity = capacity();
00968       while (new_capacity < required_size) {
00969         new_capacity <<= 1;
00970       }
00971       // Move everyone into the new allocation, leaving a gap of `n` for the
00972       // requested shift.
00973       pointer new_data =
00974           AllocatorTraits::allocate(*storage_.GetAllocPtr(), new_capacity);
00975       size_type index = position - begin();
00976       UninitializedCopy(std::make_move_iterator(data()),
00977                         std::make_move_iterator(data() + index), new_data);
00978       UninitializedCopy(std::make_move_iterator(data() + index),
00979                         std::make_move_iterator(data() + s),
00980                         new_data + index + n);
00981       ResetAllocation(new_data, new_capacity, s);
00982 
00983       // New allocation means our iterator is invalid, so we'll recalculate.
00984       // Since the entire gap is in new space, there's no used space to reuse.
00985       start_raw = begin() + index;
00986       start_used = start_raw;
00987     } else {
00988       // If we had enough space, it's a two-part move. Elements going into
00989       // previously-unoccupied space need an `UninitializedCopy()`. Elements
00990       // going into a previously-occupied space are just a `std::move()`.
00991       iterator pos = const_cast<iterator>(position);
00992       iterator raw_space = end();
00993       size_type slots_in_used_space = raw_space - pos;
00994       size_type new_elements_in_used_space = (std::min)(n, slots_in_used_space);
00995       size_type new_elements_in_raw_space = n - new_elements_in_used_space;
00996       size_type old_elements_in_used_space =
00997           slots_in_used_space - new_elements_in_used_space;
00998 
00999       UninitializedCopy(
01000           std::make_move_iterator(pos + old_elements_in_used_space),
01001           std::make_move_iterator(raw_space),
01002           raw_space + new_elements_in_raw_space);
01003       std::move_backward(pos, pos + old_elements_in_used_space, raw_space);
01004 
01005       // If the gap is entirely in raw space, the used space starts where the
01006       // raw space starts, leaving no elements in used space. If the gap is
01007       // entirely in used space, the raw space starts at the end of the gap,
01008       // leaving all elements accounted for within the used space.
01009       start_used = pos;
01010       start_raw = pos + new_elements_in_used_space;
01011     }
01012     storage_.AddSize(n);
01013     return std::make_pair(start_used, start_raw);
01014   }
01015 
01016   template <typename... Args>
01017   reference GrowAndEmplaceBack(Args&&... args) {
01018     assert(size() == capacity());
01019     const size_type s = size();
01020 
01021     size_type new_capacity = 2 * capacity();
01022     pointer new_data =
01023         AllocatorTraits::allocate(*storage_.GetAllocPtr(), new_capacity);
01024 
01025     reference new_element =
01026         Construct(new_data + s, std::forward<Args>(args)...);
01027     UninitializedCopy(std::make_move_iterator(data()),
01028                       std::make_move_iterator(data() + s), new_data);
01029 
01030     ResetAllocation(new_data, new_capacity, s + 1);
01031 
01032     return new_element;
01033   }
01034 
01035   void InitAssign(size_type n) {
01036     if (n > static_cast<size_type>(N)) {
01037       pointer new_data = AllocatorTraits::allocate(*storage_.GetAllocPtr(), n);
01038       storage_.SetAllocatedData(new_data);
01039       storage_.SetAllocatedCapacity(n);
01040       UninitializedFill(storage_.GetAllocatedData(),
01041                         storage_.GetAllocatedData() + n);
01042       storage_.SetAllocatedSize(n);
01043     } else {
01044       UninitializedFill(storage_.GetInlinedData(),
01045                         storage_.GetInlinedData() + n);
01046       storage_.SetInlinedSize(n);
01047     }
01048   }
01049 
01050   void InitAssign(size_type n, const_reference v) {
01051     if (n > static_cast<size_type>(N)) {
01052       pointer new_data = AllocatorTraits::allocate(*storage_.GetAllocPtr(), n);
01053       storage_.SetAllocatedData(new_data);
01054       storage_.SetAllocatedCapacity(n);
01055       UninitializedFill(storage_.GetAllocatedData(),
01056                         storage_.GetAllocatedData() + n, v);
01057       storage_.SetAllocatedSize(n);
01058     } else {
01059       UninitializedFill(storage_.GetInlinedData(),
01060                         storage_.GetInlinedData() + n, v);
01061       storage_.SetInlinedSize(n);
01062     }
01063   }
01064 
01065   template <typename ForwardIt>
01066   void AppendForwardRange(ForwardIt first, ForwardIt last) {
01067     static_assert(absl::inlined_vector_internal::IsAtLeastForwardIterator<
01068                       ForwardIt>::value,
01069                   "");
01070 
01071     auto length = std::distance(first, last);
01072     reserve(size() + length);
01073     if (storage_.GetIsAllocated()) {
01074       UninitializedCopy(first, last, storage_.GetAllocatedData() + size());
01075       storage_.SetAllocatedSize(size() + length);
01076     } else {
01077       UninitializedCopy(first, last, storage_.GetInlinedData() + size());
01078       storage_.SetInlinedSize(size() + length);
01079     }
01080   }
01081 
01082   iterator InsertWithCount(const_iterator position, size_type n,
01083                            const_reference v) {
01084     assert(position >= begin() && position <= end());
01085     if (ABSL_PREDICT_FALSE(n == 0)) return const_cast<iterator>(position);
01086 
01087     value_type copy = v;
01088     std::pair<iterator, iterator> it_pair = ShiftRight(position, n);
01089     std::fill(it_pair.first, it_pair.second, copy);
01090     UninitializedFill(it_pair.second, it_pair.first + n, copy);
01091 
01092     return it_pair.first;
01093   }
01094 
01095   template <typename ForwardIt>
01096   iterator InsertWithForwardRange(const_iterator position, ForwardIt first,
01097                                   ForwardIt last) {
01098     static_assert(absl::inlined_vector_internal::IsAtLeastForwardIterator<
01099                       ForwardIt>::value,
01100                   "");
01101     assert(position >= begin() && position <= end());
01102 
01103     if (ABSL_PREDICT_FALSE(first == last))
01104       return const_cast<iterator>(position);
01105 
01106     auto n = std::distance(first, last);
01107     std::pair<iterator, iterator> it_pair = ShiftRight(position, n);
01108     size_type used_spots = it_pair.second - it_pair.first;
01109     auto open_spot = std::next(first, used_spots);
01110     std::copy(first, open_spot, it_pair.first);
01111     UninitializedCopy(open_spot, last, it_pair.second);
01112     return it_pair.first;
01113   }
01114 
01115   void SwapImpl(InlinedVector& other) {
01116     using std::swap;
01117 
01118     bool is_allocated = storage_.GetIsAllocated();
01119     bool other_is_allocated = other.storage_.GetIsAllocated();
01120 
01121     if (is_allocated && other_is_allocated) {
01122       // Both out of line, so just swap the tag, allocation, and allocator.
01123       storage_.SwapSizeAndIsAllocated(std::addressof(other.storage_));
01124       storage_.SwapAllocatedSizeAndCapacity(std::addressof(other.storage_));
01125       swap(*storage_.GetAllocPtr(), *other.storage_.GetAllocPtr());
01126 
01127       return;
01128     }
01129 
01130     if (!is_allocated && !other_is_allocated) {
01131       // Both inlined: swap up to smaller size, then move remaining elements.
01132       InlinedVector* a = this;
01133       InlinedVector* b = std::addressof(other);
01134       if (size() < other.size()) {
01135         swap(a, b);
01136       }
01137 
01138       const size_type a_size = a->size();
01139       const size_type b_size = b->size();
01140       assert(a_size >= b_size);
01141       // `a` is larger. Swap the elements up to the smaller array size.
01142       std::swap_ranges(a->storage_.GetInlinedData(),
01143                        a->storage_.GetInlinedData() + b_size,
01144                        b->storage_.GetInlinedData());
01145 
01146       // Move the remaining elements:
01147       //   [`b_size`, `a_size`) from `a` -> [`b_size`, `a_size`) from `b`
01148       b->UninitializedCopy(a->storage_.GetInlinedData() + b_size,
01149                            a->storage_.GetInlinedData() + a_size,
01150                            b->storage_.GetInlinedData() + b_size);
01151       a->Destroy(a->storage_.GetInlinedData() + b_size,
01152                  a->storage_.GetInlinedData() + a_size);
01153 
01154       storage_.SwapSizeAndIsAllocated(std::addressof(other.storage_));
01155       swap(*storage_.GetAllocPtr(), *other.storage_.GetAllocPtr());
01156 
01157       assert(b->size() == a_size);
01158       assert(a->size() == b_size);
01159       return;
01160     }
01161 
01162     // One is out of line, one is inline.
01163     // We first move the elements from the inlined vector into the
01164     // inlined space in the other vector.  We then put the other vector's
01165     // pointer/capacity into the originally inlined vector and swap
01166     // the tags.
01167     InlinedVector* a = this;
01168     InlinedVector* b = std::addressof(other);
01169     if (a->storage_.GetIsAllocated()) {
01170       swap(a, b);
01171     }
01172 
01173     assert(!a->storage_.GetIsAllocated());
01174     assert(b->storage_.GetIsAllocated());
01175 
01176     const size_type a_size = a->size();
01177     const size_type b_size = b->size();
01178     // In an optimized build, `b_size` would be unused.
01179     static_cast<void>(b_size);
01180 
01181     // Made Local copies of `size()`, these can now be swapped
01182     a->storage_.SwapSizeAndIsAllocated(std::addressof(b->storage_));
01183 
01184     // Copy out before `b`'s union gets clobbered by `inline_space`
01185     pointer b_data = b->storage_.GetAllocatedData();
01186     size_type b_capacity = b->storage_.GetAllocatedCapacity();
01187 
01188     b->UninitializedCopy(a->storage_.GetInlinedData(),
01189                          a->storage_.GetInlinedData() + a_size,
01190                          b->storage_.GetInlinedData());
01191     a->Destroy(a->storage_.GetInlinedData(),
01192                a->storage_.GetInlinedData() + a_size);
01193 
01194     a->storage_.SetAllocatedData(b_data);
01195     a->storage_.SetAllocatedCapacity(b_capacity);
01196 
01197     if (*a->storage_.GetAllocPtr() != *b->storage_.GetAllocPtr()) {
01198       swap(*a->storage_.GetAllocPtr(), *b->storage_.GetAllocPtr());
01199     }
01200 
01201     assert(b->size() == a_size);
01202     assert(a->size() == b_size);
01203   }
01204 
01205   Storage storage_;
01206 };
01207 
01208 // -----------------------------------------------------------------------------
01209 // InlinedVector Non-Member Functions
01210 // -----------------------------------------------------------------------------
01211 
01212 // `swap()`
01213 //
01214 // Swaps the contents of two inlined vectors. This convenience function
01215 // simply calls `InlinedVector::swap()`.
01216 template <typename T, size_t N, typename A>
01217 void swap(absl::InlinedVector<T, N, A>& a,
01218           absl::InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) {
01219   a.swap(b);
01220 }
01221 
01222 // `operator==()`
01223 //
01224 // Tests the equivalency of the contents of two inlined vectors.
01225 template <typename T, size_t N, typename A>
01226 bool operator==(const absl::InlinedVector<T, N, A>& a,
01227                 const absl::InlinedVector<T, N, A>& b) {
01228   auto a_data = a.data();
01229   auto a_size = a.size();
01230   auto b_data = b.data();
01231   auto b_size = b.size();
01232   return absl::equal(a_data, a_data + a_size, b_data, b_data + b_size);
01233 }
01234 
01235 // `operator!=()`
01236 //
01237 // Tests the inequality of the contents of two inlined vectors.
01238 template <typename T, size_t N, typename A>
01239 bool operator!=(const absl::InlinedVector<T, N, A>& a,
01240                 const absl::InlinedVector<T, N, A>& b) {
01241   return !(a == b);
01242 }
01243 
01244 // `operator<()`
01245 //
01246 // Tests whether the contents of one inlined vector are less than the contents
01247 // of another through a lexicographical comparison operation.
01248 template <typename T, size_t N, typename A>
01249 bool operator<(const absl::InlinedVector<T, N, A>& a,
01250                const absl::InlinedVector<T, N, A>& b) {
01251   auto a_data = a.data();
01252   auto a_size = a.size();
01253   auto b_data = b.data();
01254   auto b_size = b.size();
01255   return std::lexicographical_compare(a_data, a_data + a_size, b_data,
01256                                       b_data + b_size);
01257 }
01258 
01259 // `operator>()`
01260 //
01261 // Tests whether the contents of one inlined vector are greater than the
01262 // contents of another through a lexicographical comparison operation.
01263 template <typename T, size_t N, typename A>
01264 bool operator>(const absl::InlinedVector<T, N, A>& a,
01265                const absl::InlinedVector<T, N, A>& b) {
01266   return b < a;
01267 }
01268 
01269 // `operator<=()`
01270 //
01271 // Tests whether the contents of one inlined vector are less than or equal to
01272 // the contents of another through a lexicographical comparison operation.
01273 template <typename T, size_t N, typename A>
01274 bool operator<=(const absl::InlinedVector<T, N, A>& a,
01275                 const absl::InlinedVector<T, N, A>& b) {
01276   return !(b < a);
01277 }
01278 
01279 // `operator>=()`
01280 //
01281 // Tests whether the contents of one inlined vector are greater than or equal to
01282 // the contents of another through a lexicographical comparison operation.
01283 template <typename T, size_t N, typename A>
01284 bool operator>=(const absl::InlinedVector<T, N, A>& a,
01285                 const absl::InlinedVector<T, N, A>& b) {
01286   return !(a < b);
01287 }
01288 
01289 // `AbslHashValue()`
01290 //
01291 // Provides `absl::Hash` support for `absl::InlinedVector`. You do not normally
01292 // call this function directly.
01293 template <typename H, typename TheT, size_t TheN, typename TheA>
01294 H AbslHashValue(H h, const absl::InlinedVector<TheT, TheN, TheA>& a) {
01295   auto a_data = a.data();
01296   auto a_size = a.size();
01297   return H::combine(H::combine_contiguous(std::move(h), a_data, a_size),
01298                     a_size);
01299 }
01300 
01301 }  // namespace absl
01302 
01303 #endif  // ABSL_CONTAINER_INLINED_VECTOR_H_


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:14