• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // -----------------------------------------------------------------------------
16 // File: inlined_vector.h
17 // -----------------------------------------------------------------------------
18 //
19 // This header file contains the declaration and definition of an "inlined
20 // vector" which behaves in an equivalent fashion to a `std::vector`, except
21 // that storage for small sequences of the vector are provided inline without
22 // requiring any heap allocation.
23 //
24 // An `absl::InlinedVector<T, N>` specifies the default capacity `N` as one of
25 // its template parameters. Instances where `size() <= N` hold contained
26 // elements in inline space. Typically `N` is very small so that sequences that
27 // are expected to be short do not require allocations.
28 //
29 // An `absl::InlinedVector` does not usually require a specific allocator. If
30 // the inlined vector grows beyond its initial constraints, it will need to
31 // allocate (as any normal `std::vector` would). This is usually performed with
32 // the default allocator (defined as `std::allocator<T>`). Optionally, a custom
33 // allocator type may be specified as `A` in `absl::InlinedVector<T, N, A>`.
34 
35 #ifndef ABSL_CONTAINER_INLINED_VECTOR_H_
36 #define ABSL_CONTAINER_INLINED_VECTOR_H_
37 
38 #include <algorithm>
39 #include <cassert>
40 #include <cstddef>
41 #include <cstdlib>
42 #include <cstring>
43 #include <initializer_list>
44 #include <iterator>
45 #include <memory>
46 #include <type_traits>
47 #include <utility>
48 
49 #include "absl/algorithm/algorithm.h"
50 #include "absl/base/internal/throw_delegate.h"
51 #include "absl/base/optimization.h"
52 #include "absl/base/port.h"
53 #include "absl/container/internal/inlined_vector.h"
54 #include "absl/memory/memory.h"
55 
56 namespace absl {
57 ABSL_NAMESPACE_BEGIN
58 // -----------------------------------------------------------------------------
59 // InlinedVector
60 // -----------------------------------------------------------------------------
61 //
62 // An `absl::InlinedVector` is designed to be a drop-in replacement for
63 // `std::vector` for use cases where the vector's size is sufficiently small
64 // that it can be inlined. If the inlined vector does grow beyond its estimated
65 // capacity, it will trigger an initial allocation on the heap, and will behave
66 // as a `std:vector`. The API of the `absl::InlinedVector` within this file is
67 // designed to cover the same API footprint as covered by `std::vector`.
68 template <typename T, size_t N, typename A = std::allocator<T>>
69 class InlinedVector {
70   static_assert(N > 0, "`absl::InlinedVector` requires an inlined capacity.");
71 
72   using Storage = inlined_vector_internal::Storage<T, N, A>;
73 
74   using AllocatorTraits = typename Storage::AllocatorTraits;
75   using RValueReference = typename Storage::RValueReference;
76   using MoveIterator = typename Storage::MoveIterator;
77   using IsMemcpyOk = typename Storage::IsMemcpyOk;
78 
79   template <typename Iterator>
80   using IteratorValueAdapter =
81       typename Storage::template IteratorValueAdapter<Iterator>;
82   using CopyValueAdapter = typename Storage::CopyValueAdapter;
83   using DefaultValueAdapter = typename Storage::DefaultValueAdapter;
84 
85   template <typename Iterator>
86   using EnableIfAtLeastForwardIterator = absl::enable_if_t<
87       inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value>;
88   template <typename Iterator>
89   using DisableIfAtLeastForwardIterator = absl::enable_if_t<
90       !inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value>;
91 
92  public:
93   using allocator_type = typename Storage::allocator_type;
94   using value_type = typename Storage::value_type;
95   using pointer = typename Storage::pointer;
96   using const_pointer = typename Storage::const_pointer;
97   using size_type = typename Storage::size_type;
98   using difference_type = typename Storage::difference_type;
99   using reference = typename Storage::reference;
100   using const_reference = typename Storage::const_reference;
101   using iterator = typename Storage::iterator;
102   using const_iterator = typename Storage::const_iterator;
103   using reverse_iterator = typename Storage::reverse_iterator;
104   using const_reverse_iterator = typename Storage::const_reverse_iterator;
105 
106   // ---------------------------------------------------------------------------
107   // InlinedVector Constructors and Destructor
108   // ---------------------------------------------------------------------------
109 
110   // Creates an empty inlined vector with a value-initialized allocator.
noexcept(noexcept (allocator_type ()))111   InlinedVector() noexcept(noexcept(allocator_type())) : storage_() {}
112 
113   // Creates an empty inlined vector with a copy of `alloc`.
InlinedVector(const allocator_type & alloc)114   explicit InlinedVector(const allocator_type& alloc) noexcept
115       : storage_(alloc) {}
116 
117   // Creates an inlined vector with `n` copies of `value_type()`.
118   explicit InlinedVector(size_type n,
119                          const allocator_type& alloc = allocator_type())
storage_(alloc)120       : storage_(alloc) {
121     storage_.Initialize(DefaultValueAdapter(), n);
122   }
123 
124   // Creates an inlined vector with `n` copies of `v`.
125   InlinedVector(size_type n, const_reference v,
126                 const allocator_type& alloc = allocator_type())
storage_(alloc)127       : storage_(alloc) {
128     storage_.Initialize(CopyValueAdapter(v), n);
129   }
130 
131   // Creates an inlined vector with copies of the elements of `list`.
132   InlinedVector(std::initializer_list<value_type> list,
133                 const allocator_type& alloc = allocator_type())
134       : InlinedVector(list.begin(), list.end(), alloc) {}
135 
136   // Creates an inlined vector with elements constructed from the provided
137   // forward iterator range [`first`, `last`).
138   //
139   // NOTE: the `enable_if` prevents ambiguous interpretation between a call to
140   // this constructor with two integral arguments and a call to the above
141   // `InlinedVector(size_type, const_reference)` constructor.
142   template <typename ForwardIterator,
143             EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
144   InlinedVector(ForwardIterator first, ForwardIterator last,
145                 const allocator_type& alloc = allocator_type())
storage_(alloc)146       : storage_(alloc) {
147     storage_.Initialize(IteratorValueAdapter<ForwardIterator>(first),
148                         std::distance(first, last));
149   }
150 
151   // Creates an inlined vector with elements constructed from the provided input
152   // iterator range [`first`, `last`).
153   template <typename InputIterator,
154             DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
155   InlinedVector(InputIterator first, InputIterator last,
156                 const allocator_type& alloc = allocator_type())
storage_(alloc)157       : storage_(alloc) {
158     std::copy(first, last, std::back_inserter(*this));
159   }
160 
161   // Creates an inlined vector by copying the contents of `other` using
162   // `other`'s allocator.
InlinedVector(const InlinedVector & other)163   InlinedVector(const InlinedVector& other)
164       : InlinedVector(other, *other.storage_.GetAllocPtr()) {}
165 
166   // Creates an inlined vector by copying the contents of `other` using `alloc`.
InlinedVector(const InlinedVector & other,const allocator_type & alloc)167   InlinedVector(const InlinedVector& other, const allocator_type& alloc)
168       : storage_(alloc) {
169     if (IsMemcpyOk::value && !other.storage_.GetIsAllocated()) {
170       storage_.MemcpyFrom(other.storage_);
171     } else {
172       storage_.Initialize(IteratorValueAdapter<const_pointer>(other.data()),
173                           other.size());
174     }
175   }
176 
177   // Creates an inlined vector by moving in the contents of `other` without
178   // allocating. If `other` contains allocated memory, the newly-created inlined
179   // vector will take ownership of that memory. However, if `other` does not
180   // contain allocated memory, the newly-created inlined vector will perform
181   // element-wise move construction of the contents of `other`.
182   //
183   // NOTE: since no allocation is performed for the inlined vector in either
184   // case, the `noexcept(...)` specification depends on whether moving the
185   // underlying objects can throw. It is assumed assumed that...
186   //  a) move constructors should only throw due to allocation failure.
187   //  b) if `value_type`'s move constructor allocates, it uses the same
188   //     allocation function as the inlined vector's allocator.
189   // Thus, the move constructor is non-throwing if the allocator is non-throwing
190   // or `value_type`'s move constructor is specified as `noexcept`.
191   InlinedVector(InlinedVector&& other) noexcept(
192       absl::allocator_is_nothrow<allocator_type>::value ||
193       std::is_nothrow_move_constructible<value_type>::value)
194       : storage_(*other.storage_.GetAllocPtr()) {
195     if (IsMemcpyOk::value) {
196       storage_.MemcpyFrom(other.storage_);
197 
198       other.storage_.SetInlinedSize(0);
199     } else if (other.storage_.GetIsAllocated()) {
200       storage_.SetAllocatedData(other.storage_.GetAllocatedData(),
201                                 other.storage_.GetAllocatedCapacity());
202       storage_.SetAllocatedSize(other.storage_.GetSize());
203 
204       other.storage_.SetInlinedSize(0);
205     } else {
206       IteratorValueAdapter<MoveIterator> other_values(
207           MoveIterator(other.storage_.GetInlinedData()));
208 
209       inlined_vector_internal::ConstructElements(
210           storage_.GetAllocPtr(), storage_.GetInlinedData(), &other_values,
211           other.storage_.GetSize());
212 
213       storage_.SetInlinedSize(other.storage_.GetSize());
214     }
215   }
216 
217   // Creates an inlined vector by moving in the contents of `other` with a copy
218   // of `alloc`.
219   //
220   // NOTE: if `other`'s allocator is not equal to `alloc`, even if `other`
221   // contains allocated memory, this move constructor will still allocate. Since
222   // allocation is performed, this constructor can only be `noexcept` if the
223   // specified allocator is also `noexcept`.
InlinedVector(InlinedVector && other,const allocator_type & alloc)224   InlinedVector(InlinedVector&& other, const allocator_type& alloc) noexcept(
225       absl::allocator_is_nothrow<allocator_type>::value)
226       : storage_(alloc) {
227     if (IsMemcpyOk::value) {
228       storage_.MemcpyFrom(other.storage_);
229 
230       other.storage_.SetInlinedSize(0);
231     } else if ((*storage_.GetAllocPtr() == *other.storage_.GetAllocPtr()) &&
232                other.storage_.GetIsAllocated()) {
233       storage_.SetAllocatedData(other.storage_.GetAllocatedData(),
234                                 other.storage_.GetAllocatedCapacity());
235       storage_.SetAllocatedSize(other.storage_.GetSize());
236 
237       other.storage_.SetInlinedSize(0);
238     } else {
239       storage_.Initialize(
240           IteratorValueAdapter<MoveIterator>(MoveIterator(other.data())),
241           other.size());
242     }
243   }
244 
~InlinedVector()245   ~InlinedVector() {}
246 
247   // ---------------------------------------------------------------------------
248   // InlinedVector Member Accessors
249   // ---------------------------------------------------------------------------
250 
251   // `InlinedVector::empty()`
252   //
253   // Returns whether the inlined vector contains no elements.
empty()254   bool empty() const noexcept { return !size(); }
255 
256   // `InlinedVector::size()`
257   //
258   // Returns the number of elements in the inlined vector.
size()259   size_type size() const noexcept { return storage_.GetSize(); }
260 
261   // `InlinedVector::max_size()`
262   //
263   // Returns the maximum number of elements the inlined vector can hold.
max_size()264   size_type max_size() const noexcept {
265     // One bit of the size storage is used to indicate whether the inlined
266     // vector contains allocated memory. As a result, the maximum size that the
267     // inlined vector can express is half of the max for `size_type`.
268     return (std::numeric_limits<size_type>::max)() / 2;
269   }
270 
271   // `InlinedVector::capacity()`
272   //
273   // Returns the number of elements that could be stored in the inlined vector
274   // without requiring a reallocation.
275   //
276   // NOTE: for most inlined vectors, `capacity()` should be equal to the
277   // template parameter `N`. For inlined vectors which exceed this capacity,
278   // they will no longer be inlined and `capacity()` will equal the capactity of
279   // the allocated memory.
capacity()280   size_type capacity() const noexcept {
281     return storage_.GetIsAllocated() ? storage_.GetAllocatedCapacity()
282                                      : storage_.GetInlinedCapacity();
283   }
284 
285   // `InlinedVector::data()`
286   //
287   // Returns a `pointer` to the elements of the inlined vector. This pointer
288   // can be used to access and modify the contained elements.
289   //
290   // NOTE: only elements within [`data()`, `data() + size()`) are valid.
data()291   pointer data() noexcept {
292     return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
293                                      : storage_.GetInlinedData();
294   }
295 
296   // Overload of `InlinedVector::data()` that returns a `const_pointer` to the
297   // elements of the inlined vector. This pointer can be used to access but not
298   // modify the contained elements.
299   //
300   // NOTE: only elements within [`data()`, `data() + size()`) are valid.
data()301   const_pointer data() const noexcept {
302     return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
303                                      : storage_.GetInlinedData();
304   }
305 
306   // `InlinedVector::operator[](...)`
307   //
308   // Returns a `reference` to the `i`th element of the inlined vector.
309   reference operator[](size_type i) {
310     assert(i < size());
311 
312     return data()[i];
313   }
314 
315   // Overload of `InlinedVector::operator[](...)` that returns a
316   // `const_reference` to the `i`th element of the inlined vector.
317   const_reference operator[](size_type i) const {
318     assert(i < size());
319 
320     return data()[i];
321   }
322 
323   // `InlinedVector::at(...)`
324   //
325   // Returns a `reference` to the `i`th element of the inlined vector.
326   //
327   // NOTE: if `i` is not within the required range of `InlinedVector::at(...)`,
328   // in both debug and non-debug builds, `std::out_of_range` will be thrown.
at(size_type i)329   reference at(size_type i) {
330     if (ABSL_PREDICT_FALSE(i >= size())) {
331       base_internal::ThrowStdOutOfRange(
332           "`InlinedVector::at(size_type)` failed bounds check");
333     }
334 
335     return data()[i];
336   }
337 
338   // Overload of `InlinedVector::at(...)` that returns a `const_reference` to
339   // the `i`th element of the inlined vector.
340   //
341   // NOTE: if `i` is not within the required range of `InlinedVector::at(...)`,
342   // in both debug and non-debug builds, `std::out_of_range` will be thrown.
at(size_type i)343   const_reference at(size_type i) const {
344     if (ABSL_PREDICT_FALSE(i >= size())) {
345       base_internal::ThrowStdOutOfRange(
346           "`InlinedVector::at(size_type) const` failed bounds check");
347     }
348 
349     return data()[i];
350   }
351 
352   // `InlinedVector::front()`
353   //
354   // Returns a `reference` to the first element of the inlined vector.
front()355   reference front() {
356     assert(!empty());
357 
358     return at(0);
359   }
360 
361   // Overload of `InlinedVector::front()` that returns a `const_reference` to
362   // the first element of the inlined vector.
front()363   const_reference front() const {
364     assert(!empty());
365 
366     return at(0);
367   }
368 
369   // `InlinedVector::back()`
370   //
371   // Returns a `reference` to the last element of the inlined vector.
back()372   reference back() {
373     assert(!empty());
374 
375     return at(size() - 1);
376   }
377 
378   // Overload of `InlinedVector::back()` that returns a `const_reference` to the
379   // last element of the inlined vector.
back()380   const_reference back() const {
381     assert(!empty());
382 
383     return at(size() - 1);
384   }
385 
386   // `InlinedVector::begin()`
387   //
388   // Returns an `iterator` to the beginning of the inlined vector.
begin()389   iterator begin() noexcept { return data(); }
390 
391   // Overload of `InlinedVector::begin()` that returns a `const_iterator` to
392   // the beginning of the inlined vector.
begin()393   const_iterator begin() const noexcept { return data(); }
394 
395   // `InlinedVector::end()`
396   //
397   // Returns an `iterator` to the end of the inlined vector.
end()398   iterator end() noexcept { return data() + size(); }
399 
400   // Overload of `InlinedVector::end()` that returns a `const_iterator` to the
401   // end of the inlined vector.
end()402   const_iterator end() const noexcept { return data() + size(); }
403 
404   // `InlinedVector::cbegin()`
405   //
406   // Returns a `const_iterator` to the beginning of the inlined vector.
cbegin()407   const_iterator cbegin() const noexcept { return begin(); }
408 
409   // `InlinedVector::cend()`
410   //
411   // Returns a `const_iterator` to the end of the inlined vector.
cend()412   const_iterator cend() const noexcept { return end(); }
413 
414   // `InlinedVector::rbegin()`
415   //
416   // Returns a `reverse_iterator` from the end of the inlined vector.
rbegin()417   reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
418 
419   // Overload of `InlinedVector::rbegin()` that returns a
420   // `const_reverse_iterator` from the end of the inlined vector.
rbegin()421   const_reverse_iterator rbegin() const noexcept {
422     return const_reverse_iterator(end());
423   }
424 
425   // `InlinedVector::rend()`
426   //
427   // Returns a `reverse_iterator` from the beginning of the inlined vector.
rend()428   reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
429 
430   // Overload of `InlinedVector::rend()` that returns a `const_reverse_iterator`
431   // from the beginning of the inlined vector.
rend()432   const_reverse_iterator rend() const noexcept {
433     return const_reverse_iterator(begin());
434   }
435 
436   // `InlinedVector::crbegin()`
437   //
438   // Returns a `const_reverse_iterator` from the end of the inlined vector.
crbegin()439   const_reverse_iterator crbegin() const noexcept { return rbegin(); }
440 
441   // `InlinedVector::crend()`
442   //
443   // Returns a `const_reverse_iterator` from the beginning of the inlined
444   // vector.
crend()445   const_reverse_iterator crend() const noexcept { return rend(); }
446 
447   // `InlinedVector::get_allocator()`
448   //
449   // Returns a copy of the inlined vector's allocator.
get_allocator()450   allocator_type get_allocator() const { return *storage_.GetAllocPtr(); }
451 
452   // ---------------------------------------------------------------------------
453   // InlinedVector Member Mutators
454   // ---------------------------------------------------------------------------
455 
456   // `InlinedVector::operator=(...)`
457   //
458   // Replaces the elements of the inlined vector with copies of the elements of
459   // `list`.
460   InlinedVector& operator=(std::initializer_list<value_type> list) {
461     assign(list.begin(), list.end());
462 
463     return *this;
464   }
465 
466   // Overload of `InlinedVector::operator=(...)` that replaces the elements of
467   // the inlined vector with copies of the elements of `other`.
468   InlinedVector& operator=(const InlinedVector& other) {
469     if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
470       const_pointer other_data = other.data();
471       assign(other_data, other_data + other.size());
472     }
473 
474     return *this;
475   }
476 
477   // Overload of `InlinedVector::operator=(...)` that moves the elements of
478   // `other` into the inlined vector.
479   //
480   // NOTE: as a result of calling this overload, `other` is left in a valid but
481   // unspecified state.
482   InlinedVector& operator=(InlinedVector&& other) {
483     if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
484       if (IsMemcpyOk::value || other.storage_.GetIsAllocated()) {
485         inlined_vector_internal::DestroyElements(storage_.GetAllocPtr(), data(),
486                                                  size());
487         storage_.DeallocateIfAllocated();
488         storage_.MemcpyFrom(other.storage_);
489 
490         other.storage_.SetInlinedSize(0);
491       } else {
492         storage_.Assign(IteratorValueAdapter<MoveIterator>(
493                             MoveIterator(other.storage_.GetInlinedData())),
494                         other.size());
495       }
496     }
497 
498     return *this;
499   }
500 
501   // `InlinedVector::assign(...)`
502   //
503   // Replaces the contents of the inlined vector with `n` copies of `v`.
assign(size_type n,const_reference v)504   void assign(size_type n, const_reference v) {
505     storage_.Assign(CopyValueAdapter(v), n);
506   }
507 
508   // Overload of `InlinedVector::assign(...)` that replaces the contents of the
509   // inlined vector with copies of the elements of `list`.
assign(std::initializer_list<value_type> list)510   void assign(std::initializer_list<value_type> list) {
511     assign(list.begin(), list.end());
512   }
513 
514   // Overload of `InlinedVector::assign(...)` to replace the contents of the
515   // inlined vector with the range [`first`, `last`).
516   //
517   // NOTE: this overload is for iterators that are "forward" category or better.
518   template <typename ForwardIterator,
519             EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
assign(ForwardIterator first,ForwardIterator last)520   void assign(ForwardIterator first, ForwardIterator last) {
521     storage_.Assign(IteratorValueAdapter<ForwardIterator>(first),
522                     std::distance(first, last));
523   }
524 
525   // Overload of `InlinedVector::assign(...)` to replace the contents of the
526   // inlined vector with the range [`first`, `last`).
527   //
528   // NOTE: this overload is for iterators that are "input" category.
529   template <typename InputIterator,
530             DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
assign(InputIterator first,InputIterator last)531   void assign(InputIterator first, InputIterator last) {
532     size_type i = 0;
533     for (; i < size() && first != last; ++i, static_cast<void>(++first)) {
534       at(i) = *first;
535     }
536 
537     erase(data() + i, data() + size());
538     std::copy(first, last, std::back_inserter(*this));
539   }
540 
541   // `InlinedVector::resize(...)`
542   //
543   // Resizes the inlined vector to contain `n` elements.
544   //
545   // NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n`
546   // is larger than `size()`, new elements are value-initialized.
resize(size_type n)547   void resize(size_type n) { storage_.Resize(DefaultValueAdapter(), n); }
548 
549   // Overload of `InlinedVector::resize(...)` that resizes the inlined vector to
550   // contain `n` elements.
551   //
552   // NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n`
553   // is larger than `size()`, new elements are copied-constructed from `v`.
resize(size_type n,const_reference v)554   void resize(size_type n, const_reference v) {
555     storage_.Resize(CopyValueAdapter(v), n);
556   }
557 
558   // `InlinedVector::insert(...)`
559   //
560   // Inserts a copy of `v` at `pos`, returning an `iterator` to the newly
561   // inserted element.
insert(const_iterator pos,const_reference v)562   iterator insert(const_iterator pos, const_reference v) {
563     return emplace(pos, v);
564   }
565 
566   // Overload of `InlinedVector::insert(...)` that inserts `v` at `pos` using
567   // move semantics, returning an `iterator` to the newly inserted element.
insert(const_iterator pos,RValueReference v)568   iterator insert(const_iterator pos, RValueReference v) {
569     return emplace(pos, std::move(v));
570   }
571 
572   // Overload of `InlinedVector::insert(...)` that inserts `n` contiguous copies
573   // of `v` starting at `pos`, returning an `iterator` pointing to the first of
574   // the newly inserted elements.
insert(const_iterator pos,size_type n,const_reference v)575   iterator insert(const_iterator pos, size_type n, const_reference v) {
576     assert(pos >= begin());
577     assert(pos <= end());
578 
579     if (ABSL_PREDICT_TRUE(n != 0)) {
580       value_type dealias = v;
581       return storage_.Insert(pos, CopyValueAdapter(dealias), n);
582     } else {
583       return const_cast<iterator>(pos);
584     }
585   }
586 
587   // Overload of `InlinedVector::insert(...)` that inserts copies of the
588   // elements of `list` starting at `pos`, returning an `iterator` pointing to
589   // the first of the newly inserted elements.
insert(const_iterator pos,std::initializer_list<value_type> list)590   iterator insert(const_iterator pos, std::initializer_list<value_type> list) {
591     return insert(pos, list.begin(), list.end());
592   }
593 
594   // Overload of `InlinedVector::insert(...)` that inserts the range [`first`,
595   // `last`) starting at `pos`, returning an `iterator` pointing to the first
596   // of the newly inserted elements.
597   //
598   // NOTE: this overload is for iterators that are "forward" category or better.
599   template <typename ForwardIterator,
600             EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
insert(const_iterator pos,ForwardIterator first,ForwardIterator last)601   iterator insert(const_iterator pos, ForwardIterator first,
602                   ForwardIterator last) {
603     assert(pos >= begin());
604     assert(pos <= end());
605 
606     if (ABSL_PREDICT_TRUE(first != last)) {
607       return storage_.Insert(pos, IteratorValueAdapter<ForwardIterator>(first),
608                              std::distance(first, last));
609     } else {
610       return const_cast<iterator>(pos);
611     }
612   }
613 
614   // Overload of `InlinedVector::insert(...)` that inserts the range [`first`,
615   // `last`) starting at `pos`, returning an `iterator` pointing to the first
616   // of the newly inserted elements.
617   //
618   // NOTE: this overload is for iterators that are "input" category.
619   template <typename InputIterator,
620             DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
insert(const_iterator pos,InputIterator first,InputIterator last)621   iterator insert(const_iterator pos, InputIterator first, InputIterator last) {
622     assert(pos >= begin());
623     assert(pos <= end());
624 
625     size_type index = std::distance(cbegin(), pos);
626     for (size_type i = index; first != last; ++i, static_cast<void>(++first)) {
627       insert(data() + i, *first);
628     }
629 
630     return iterator(data() + index);
631   }
632 
633   // `InlinedVector::emplace(...)`
634   //
635   // Constructs and inserts an element using `args...` in the inlined vector at
636   // `pos`, returning an `iterator` pointing to the newly emplaced element.
637   template <typename... Args>
emplace(const_iterator pos,Args &&...args)638   iterator emplace(const_iterator pos, Args&&... args) {
639     assert(pos >= begin());
640     assert(pos <= end());
641 
642     value_type dealias(std::forward<Args>(args)...);
643     return storage_.Insert(pos,
644                            IteratorValueAdapter<MoveIterator>(
645                                MoveIterator(std::addressof(dealias))),
646                            1);
647   }
648 
649   // `InlinedVector::emplace_back(...)`
650   //
651   // Constructs and inserts an element using `args...` in the inlined vector at
652   // `end()`, returning a `reference` to the newly emplaced element.
653   template <typename... Args>
emplace_back(Args &&...args)654   reference emplace_back(Args&&... args) {
655     return storage_.EmplaceBack(std::forward<Args>(args)...);
656   }
657 
658   // `InlinedVector::push_back(...)`
659   //
660   // Inserts a copy of `v` in the inlined vector at `end()`.
push_back(const_reference v)661   void push_back(const_reference v) { static_cast<void>(emplace_back(v)); }
662 
663   // Overload of `InlinedVector::push_back(...)` for inserting `v` at `end()`
664   // using move semantics.
push_back(RValueReference v)665   void push_back(RValueReference v) {
666     static_cast<void>(emplace_back(std::move(v)));
667   }
668 
669   // `InlinedVector::pop_back()`
670   //
671   // Destroys the element at `back()`, reducing the size by `1`.
pop_back()672   void pop_back() noexcept {
673     assert(!empty());
674 
675     AllocatorTraits::destroy(*storage_.GetAllocPtr(), data() + (size() - 1));
676     storage_.SubtractSize(1);
677   }
678 
679   // `InlinedVector::erase(...)`
680   //
681   // Erases the element at `pos`, returning an `iterator` pointing to where the
682   // erased element was located.
683   //
684   // NOTE: may return `end()`, which is not dereferencable.
erase(const_iterator pos)685   iterator erase(const_iterator pos) {
686     assert(pos >= begin());
687     assert(pos < end());
688 
689     return storage_.Erase(pos, pos + 1);
690   }
691 
692   // Overload of `InlinedVector::erase(...)` that erases every element in the
693   // range [`from`, `to`), returning an `iterator` pointing to where the first
694   // erased element was located.
695   //
696   // NOTE: may return `end()`, which is not dereferencable.
erase(const_iterator from,const_iterator to)697   iterator erase(const_iterator from, const_iterator to) {
698     assert(from >= begin());
699     assert(from <= to);
700     assert(to <= end());
701 
702     if (ABSL_PREDICT_TRUE(from != to)) {
703       return storage_.Erase(from, to);
704     } else {
705       return const_cast<iterator>(from);
706     }
707   }
708 
709   // `InlinedVector::clear()`
710   //
711   // Destroys all elements in the inlined vector, setting the size to `0` and
712   // deallocating any held memory.
clear()713   void clear() noexcept {
714     inlined_vector_internal::DestroyElements(storage_.GetAllocPtr(), data(),
715                                              size());
716     storage_.DeallocateIfAllocated();
717 
718     storage_.SetInlinedSize(0);
719   }
720 
721   // `InlinedVector::reserve(...)`
722   //
723   // Ensures that there is enough room for at least `n` elements.
reserve(size_type n)724   void reserve(size_type n) { storage_.Reserve(n); }
725 
726   // `InlinedVector::shrink_to_fit()`
727   //
728   // Reduces memory usage by freeing unused memory. After being called, calls to
729   // `capacity()` will be equal to `max(N, size())`.
730   //
731   // If `size() <= N` and the inlined vector contains allocated memory, the
732   // elements will all be moved to the inlined space and the allocated memory
733   // will be deallocated.
734   //
735   // If `size() > N` and `size() < capacity()`, the elements will be moved to a
736   // smaller allocation.
shrink_to_fit()737   void shrink_to_fit() {
738     if (storage_.GetIsAllocated()) {
739       storage_.ShrinkToFit();
740     }
741   }
742 
743   // `InlinedVector::swap(...)`
744   //
745   // Swaps the contents of the inlined vector with `other`.
swap(InlinedVector & other)746   void swap(InlinedVector& other) {
747     if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
748       storage_.Swap(std::addressof(other.storage_));
749     }
750   }
751 
752  private:
753   template <typename H, typename TheT, size_t TheN, typename TheA>
754   friend H AbslHashValue(H h, const absl::InlinedVector<TheT, TheN, TheA>& a);
755 
756   Storage storage_;
757 };
758 
759 // -----------------------------------------------------------------------------
760 // InlinedVector Non-Member Functions
761 // -----------------------------------------------------------------------------
762 
763 // `swap(...)`
764 //
765 // Swaps the contents of two inlined vectors.
766 template <typename T, size_t N, typename A>
swap(absl::InlinedVector<T,N,A> & a,absl::InlinedVector<T,N,A> & b)767 void swap(absl::InlinedVector<T, N, A>& a,
768           absl::InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) {
769   a.swap(b);
770 }
771 
772 // `operator==(...)`
773 //
774 // Tests for value-equality of two inlined vectors.
775 template <typename T, size_t N, typename A>
776 bool operator==(const absl::InlinedVector<T, N, A>& a,
777                 const absl::InlinedVector<T, N, A>& b) {
778   auto a_data = a.data();
779   auto b_data = b.data();
780   return absl::equal(a_data, a_data + a.size(), b_data, b_data + b.size());
781 }
782 
783 // `operator!=(...)`
784 //
785 // Tests for value-inequality of two inlined vectors.
786 template <typename T, size_t N, typename A>
787 bool operator!=(const absl::InlinedVector<T, N, A>& a,
788                 const absl::InlinedVector<T, N, A>& b) {
789   return !(a == b);
790 }
791 
792 // `operator<(...)`
793 //
794 // Tests whether the value of an inlined vector is less than the value of
795 // another inlined vector using a lexicographical comparison algorithm.
796 template <typename T, size_t N, typename A>
797 bool operator<(const absl::InlinedVector<T, N, A>& a,
798                const absl::InlinedVector<T, N, A>& b) {
799   auto a_data = a.data();
800   auto b_data = b.data();
801   return std::lexicographical_compare(a_data, a_data + a.size(), b_data,
802                                       b_data + b.size());
803 }
804 
805 // `operator>(...)`
806 //
807 // Tests whether the value of an inlined vector is greater than the value of
808 // another inlined vector using a lexicographical comparison algorithm.
809 template <typename T, size_t N, typename A>
810 bool operator>(const absl::InlinedVector<T, N, A>& a,
811                const absl::InlinedVector<T, N, A>& b) {
812   return b < a;
813 }
814 
815 // `operator<=(...)`
816 //
817 // Tests whether the value of an inlined vector is less than or equal to the
818 // value of another inlined vector using a lexicographical comparison algorithm.
819 template <typename T, size_t N, typename A>
820 bool operator<=(const absl::InlinedVector<T, N, A>& a,
821                 const absl::InlinedVector<T, N, A>& b) {
822   return !(b < a);
823 }
824 
825 // `operator>=(...)`
826 //
827 // Tests whether the value of an inlined vector is greater than or equal to the
828 // value of another inlined vector using a lexicographical comparison algorithm.
829 template <typename T, size_t N, typename A>
830 bool operator>=(const absl::InlinedVector<T, N, A>& a,
831                 const absl::InlinedVector<T, N, A>& b) {
832   return !(a < b);
833 }
834 
835 // `AbslHashValue(...)`
836 //
837 // Provides `absl::Hash` support for `absl::InlinedVector`. It is uncommon to
838 // call this directly.
839 template <typename H, typename T, size_t N, typename A>
AbslHashValue(H h,const absl::InlinedVector<T,N,A> & a)840 H AbslHashValue(H h, const absl::InlinedVector<T, N, A>& a) {
841   auto size = a.size();
842   return H::combine(H::combine_contiguous(std::move(h), a.data(), size), size);
843 }
844 
845 ABSL_NAMESPACE_END
846 }  // namespace absl
847 
848 #endif  // ABSL_CONTAINER_INLINED_VECTOR_H_
849