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