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