blob: 54369c856829f518bb62391b3fd0c6e36af22f04 [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#ifndef ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_
16#define ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_
17
18#include <algorithm>
19#include <cstddef>
20#include <cstring>
21#include <iterator>
22#include <limits>
23#include <memory>
24#include <utility>
25
26#include "absl/base/macros.h"
27#include "absl/container/internal/compressed_tuple.h"
28#include "absl/memory/memory.h"
29#include "absl/meta/type_traits.h"
30#include "absl/types/span.h"
31
32namespace absl {
33namespace inlined_vector_internal {
34
35template <typename Iterator>
36using IsAtLeastForwardIterator = std::is_convertible<
37 typename std::iterator_traits<Iterator>::iterator_category,
38 std::forward_iterator_tag>;
39
40template <typename AllocatorType>
41using IsMemcpyOk = absl::conjunction<
42 std::is_same<std::allocator<typename AllocatorType::value_type>,
43 AllocatorType>,
44 absl::is_trivially_copy_constructible<typename AllocatorType::value_type>,
45 absl::is_trivially_copy_assignable<typename AllocatorType::value_type>,
46 absl::is_trivially_destructible<typename AllocatorType::value_type>>;
47
48template <typename AllocatorType, typename ValueType, typename SizeType>
49void DestroyElements(AllocatorType* alloc_ptr, ValueType* destroy_first,
50 SizeType destroy_size) {
51 using AllocatorTraits = absl::allocator_traits<AllocatorType>;
52
53 if (destroy_first != nullptr) {
54 for (auto i = destroy_size; i != 0;) {
55 --i;
56 AllocatorTraits::destroy(*alloc_ptr, destroy_first + i);
57 }
58
59#if !defined(NDEBUG)
60 // Overwrite unused memory with `0xab` so we can catch uninitialized usage.
61 //
62 // Cast to `void*` to tell the compiler that we don't care that we might be
63 // scribbling on a vtable pointer.
64 auto* memory_ptr = static_cast<void*>(destroy_first);
65 auto memory_size = sizeof(ValueType) * destroy_size;
66 std::memset(memory_ptr, 0xab, memory_size);
67#endif // !defined(NDEBUG)
68 }
69}
70
71template <typename AllocatorType, typename ValueType, typename ValueAdapter,
72 typename SizeType>
73void ConstructElements(AllocatorType* alloc_ptr, ValueType* construct_first,
74 ValueAdapter* values_ptr, SizeType construct_size) {
75 for (SizeType i = 0; i < construct_size; ++i) {
76 ABSL_INTERNAL_TRY {
77 values_ptr->ConstructNext(alloc_ptr, construct_first + i);
78 }
79 ABSL_INTERNAL_CATCH_ANY {
80 inlined_vector_internal::DestroyElements(alloc_ptr, construct_first, i);
81 ABSL_INTERNAL_RETHROW;
82 }
83 }
84}
85
86template <typename ValueType, typename ValueAdapter, typename SizeType>
87void AssignElements(ValueType* assign_first, ValueAdapter* values_ptr,
88 SizeType assign_size) {
89 for (SizeType i = 0; i < assign_size; ++i) {
90 values_ptr->AssignNext(assign_first + i);
91 }
92}
93
94template <typename AllocatorType>
95struct StorageView {
96 using pointer = typename AllocatorType::pointer;
97 using size_type = typename AllocatorType::size_type;
98
99 pointer data;
100 size_type size;
101 size_type capacity;
102};
103
104template <typename AllocatorType, typename Iterator>
105class IteratorValueAdapter {
106 using pointer = typename AllocatorType::pointer;
107 using AllocatorTraits = absl::allocator_traits<AllocatorType>;
108
109 public:
110 explicit IteratorValueAdapter(const Iterator& it) : it_(it) {}
111
112 void ConstructNext(AllocatorType* alloc_ptr, pointer construct_at) {
113 AllocatorTraits::construct(*alloc_ptr, construct_at, *it_);
114 ++it_;
115 }
116
117 void AssignNext(pointer assign_at) {
118 *assign_at = *it_;
119 ++it_;
120 }
121
122 private:
123 Iterator it_;
124};
125
126template <typename AllocatorType>
127class CopyValueAdapter {
128 using pointer = typename AllocatorType::pointer;
129 using const_pointer = typename AllocatorType::const_pointer;
130 using const_reference = typename AllocatorType::const_reference;
131 using AllocatorTraits = absl::allocator_traits<AllocatorType>;
132
133 public:
134 explicit CopyValueAdapter(const_reference v) : ptr_(std::addressof(v)) {}
135
136 void ConstructNext(AllocatorType* alloc_ptr, pointer construct_at) {
137 AllocatorTraits::construct(*alloc_ptr, construct_at, *ptr_);
138 }
139
140 void AssignNext(pointer assign_at) { *assign_at = *ptr_; }
141
142 private:
143 const_pointer ptr_;
144};
145
146template <typename AllocatorType>
147class DefaultValueAdapter {
148 using pointer = typename AllocatorType::pointer;
149 using value_type = typename AllocatorType::value_type;
150 using AllocatorTraits = absl::allocator_traits<AllocatorType>;
151
152 public:
153 explicit DefaultValueAdapter() {}
154
155 void ConstructNext(AllocatorType* alloc_ptr, pointer construct_at) {
156 AllocatorTraits::construct(*alloc_ptr, construct_at);
157 }
158
159 void AssignNext(pointer assign_at) { *assign_at = value_type(); }
160};
161
162template <typename AllocatorType>
163class AllocationTransaction {
164 using value_type = typename AllocatorType::value_type;
165 using pointer = typename AllocatorType::pointer;
166 using size_type = typename AllocatorType::size_type;
167 using AllocatorTraits = absl::allocator_traits<AllocatorType>;
168
169 public:
170 explicit AllocationTransaction(AllocatorType* alloc_ptr)
171 : alloc_data_(*alloc_ptr, nullptr) {}
172
173 ~AllocationTransaction() {
174 if (DidAllocate()) {
175 AllocatorTraits::deallocate(GetAllocator(), GetData(), GetCapacity());
176 }
177 }
178
179 AllocationTransaction(const AllocationTransaction&) = delete;
180 void operator=(const AllocationTransaction&) = delete;
181
182 AllocatorType& GetAllocator() { return alloc_data_.template get<0>(); }
183 pointer& GetData() { return alloc_data_.template get<1>(); }
184 size_type& GetCapacity() { return capacity_; }
185
186 bool DidAllocate() { return GetData() != nullptr; }
187 pointer Allocate(size_type capacity) {
188 GetData() = AllocatorTraits::allocate(GetAllocator(), capacity);
189 GetCapacity() = capacity;
190 return GetData();
191 }
192
193 void Reset() {
194 GetData() = nullptr;
195 GetCapacity() = 0;
196 }
197
198 private:
199 container_internal::CompressedTuple<AllocatorType, pointer> alloc_data_;
200 size_type capacity_ = 0;
201};
202
203template <typename AllocatorType>
204class ConstructionTransaction {
205 using pointer = typename AllocatorType::pointer;
206 using size_type = typename AllocatorType::size_type;
207
208 public:
209 explicit ConstructionTransaction(AllocatorType* alloc_ptr)
210 : alloc_data_(*alloc_ptr, nullptr) {}
211
212 ~ConstructionTransaction() {
213 if (DidConstruct()) {
214 inlined_vector_internal::DestroyElements(std::addressof(GetAllocator()),
215 GetData(), GetSize());
216 }
217 }
218
219 ConstructionTransaction(const ConstructionTransaction&) = delete;
220 void operator=(const ConstructionTransaction&) = delete;
221
222 AllocatorType& GetAllocator() { return alloc_data_.template get<0>(); }
223 pointer& GetData() { return alloc_data_.template get<1>(); }
224 size_type& GetSize() { return size_; }
225
226 bool DidConstruct() { return GetData() != nullptr; }
227 template <typename ValueAdapter>
228 void Construct(pointer data, ValueAdapter* values_ptr, size_type size) {
229 inlined_vector_internal::ConstructElements(std::addressof(GetAllocator()),
230 data, values_ptr, size);
231 GetData() = data;
232 GetSize() = size;
233 }
234 void Commit() {
235 GetData() = nullptr;
236 GetSize() = 0;
237 }
238
239 private:
240 container_internal::CompressedTuple<AllocatorType, pointer> alloc_data_;
241 size_type size_ = 0;
242};
243
244template <typename T, size_t N, typename A>
245class Storage {
246 public:
247 using allocator_type = A;
248 using value_type = typename allocator_type::value_type;
249 using pointer = typename allocator_type::pointer;
250 using const_pointer = typename allocator_type::const_pointer;
251 using reference = typename allocator_type::reference;
252 using const_reference = typename allocator_type::const_reference;
253 using rvalue_reference = typename allocator_type::value_type&&;
254 using size_type = typename allocator_type::size_type;
255 using difference_type = typename allocator_type::difference_type;
256 using iterator = pointer;
257 using const_iterator = const_pointer;
258 using reverse_iterator = std::reverse_iterator<iterator>;
259 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
260 using MoveIterator = std::move_iterator<iterator>;
261 using AllocatorTraits = absl::allocator_traits<allocator_type>;
262 using IsMemcpyOk = inlined_vector_internal::IsMemcpyOk<allocator_type>;
263
264 using StorageView = inlined_vector_internal::StorageView<allocator_type>;
265
266 template <typename Iterator>
267 using IteratorValueAdapter =
268 inlined_vector_internal::IteratorValueAdapter<allocator_type, Iterator>;
269 using CopyValueAdapter =
270 inlined_vector_internal::CopyValueAdapter<allocator_type>;
271 using DefaultValueAdapter =
272 inlined_vector_internal::DefaultValueAdapter<allocator_type>;
273
274 using AllocationTransaction =
275 inlined_vector_internal::AllocationTransaction<allocator_type>;
276 using ConstructionTransaction =
277 inlined_vector_internal::ConstructionTransaction<allocator_type>;
278
279 static size_type NextCapacity(size_type current_capacity) {
280 return current_capacity * 2;
281 }
282
283 static size_type ComputeCapacity(size_type current_capacity,
284 size_type requested_capacity) {
285 return (std::max)(NextCapacity(current_capacity), requested_capacity);
286 }
287
288 // ---------------------------------------------------------------------------
289 // Storage Constructors and Destructor
290 // ---------------------------------------------------------------------------
291
292 Storage() : metadata_() {}
293
294 explicit Storage(const allocator_type& alloc) : metadata_(alloc, {}) {}
295
296 ~Storage() {
297 pointer data = GetIsAllocated() ? GetAllocatedData() : GetInlinedData();
298 inlined_vector_internal::DestroyElements(GetAllocPtr(), data, GetSize());
299 DeallocateIfAllocated();
300 }
301
302 // ---------------------------------------------------------------------------
303 // Storage Member Accessors
304 // ---------------------------------------------------------------------------
305
306 size_type& GetSizeAndIsAllocated() { return metadata_.template get<1>(); }
307
308 const size_type& GetSizeAndIsAllocated() const {
309 return metadata_.template get<1>();
310 }
311
312 size_type GetSize() const { return GetSizeAndIsAllocated() >> 1; }
313
314 bool GetIsAllocated() const { return GetSizeAndIsAllocated() & 1; }
315
316 pointer GetAllocatedData() { return data_.allocated.allocated_data; }
317
318 const_pointer GetAllocatedData() const {
319 return data_.allocated.allocated_data;
320 }
321
322 pointer GetInlinedData() {
323 return reinterpret_cast<pointer>(
324 std::addressof(data_.inlined.inlined_data[0]));
325 }
326
327 const_pointer GetInlinedData() const {
328 return reinterpret_cast<const_pointer>(
329 std::addressof(data_.inlined.inlined_data[0]));
330 }
331
332 size_type GetAllocatedCapacity() const {
333 return data_.allocated.allocated_capacity;
334 }
335
336 size_type GetInlinedCapacity() const { return static_cast<size_type>(N); }
337
338 StorageView MakeStorageView() {
339 return GetIsAllocated()
340 ? StorageView{GetAllocatedData(), GetSize(),
341 GetAllocatedCapacity()}
342 : StorageView{GetInlinedData(), GetSize(), GetInlinedCapacity()};
343 }
344
345 allocator_type* GetAllocPtr() {
346 return std::addressof(metadata_.template get<0>());
347 }
348
349 const allocator_type* GetAllocPtr() const {
350 return std::addressof(metadata_.template get<0>());
351 }
352
353 // ---------------------------------------------------------------------------
354 // Storage Member Mutators
355 // ---------------------------------------------------------------------------
356
357 template <typename ValueAdapter>
358 void Initialize(ValueAdapter values, size_type new_size);
359
360 template <typename ValueAdapter>
361 void Assign(ValueAdapter values, size_type new_size);
362
363 template <typename ValueAdapter>
364 void Resize(ValueAdapter values, size_type new_size);
365
366 template <typename ValueAdapter>
367 iterator Insert(const_iterator pos, ValueAdapter values,
368 size_type insert_count);
369
370 template <typename... Args>
371 reference EmplaceBack(Args&&... args);
372
373 iterator Erase(const_iterator from, const_iterator to);
374
375 void Reserve(size_type requested_capacity);
376
377 void ShrinkToFit();
378
379 void Swap(Storage* other_storage_ptr);
380
381 void SetIsAllocated() {
382 GetSizeAndIsAllocated() |= static_cast<size_type>(1);
383 }
384
385 void UnsetIsAllocated() {
386 GetSizeAndIsAllocated() &= ((std::numeric_limits<size_type>::max)() - 1);
387 }
388
389 void SetSize(size_type size) {
390 GetSizeAndIsAllocated() =
391 (size << 1) | static_cast<size_type>(GetIsAllocated());
392 }
393
394 void SetAllocatedSize(size_type size) {
395 GetSizeAndIsAllocated() = (size << 1) | static_cast<size_type>(1);
396 }
397
398 void SetInlinedSize(size_type size) {
399 GetSizeAndIsAllocated() = size << static_cast<size_type>(1);
400 }
401
402 void AddSize(size_type count) {
403 GetSizeAndIsAllocated() += count << static_cast<size_type>(1);
404 }
405
406 void SubtractSize(size_type count) {
407 assert(count <= GetSize());
408
409 GetSizeAndIsAllocated() -= count << static_cast<size_type>(1);
410 }
411
412 void SetAllocatedData(pointer data, size_type capacity) {
413 data_.allocated.allocated_data = data;
414 data_.allocated.allocated_capacity = capacity;
415 }
416
417 void AcquireAllocatedData(AllocationTransaction* allocation_tx_ptr) {
418 SetAllocatedData(allocation_tx_ptr->GetData(),
419 allocation_tx_ptr->GetCapacity());
420
421 allocation_tx_ptr->Reset();
422 }
423
424 void MemcpyFrom(const Storage& other_storage) {
425 assert(IsMemcpyOk::value || other_storage.GetIsAllocated());
426
427 GetSizeAndIsAllocated() = other_storage.GetSizeAndIsAllocated();
428 data_ = other_storage.data_;
429 }
430
431 void DeallocateIfAllocated() {
432 if (GetIsAllocated()) {
433 AllocatorTraits::deallocate(*GetAllocPtr(), GetAllocatedData(),
434 GetAllocatedCapacity());
435 }
436 }
437
438 private:
439 using Metadata =
440 container_internal::CompressedTuple<allocator_type, size_type>;
441
442 struct Allocated {
443 pointer allocated_data;
444 size_type allocated_capacity;
445 };
446
447 struct Inlined {
448 alignas(value_type) char inlined_data[sizeof(value_type[N])];
449 };
450
451 union Data {
452 Allocated allocated;
453 Inlined inlined;
454 };
455
456 Metadata metadata_;
457 Data data_;
458};
459
460template <typename T, size_t N, typename A>
461template <typename ValueAdapter>
462auto Storage<T, N, A>::Initialize(ValueAdapter values, size_type new_size)
463 -> void {
464 // Only callable from constructors!
465 assert(!GetIsAllocated());
466 assert(GetSize() == 0);
467
468 pointer construct_data;
469 if (new_size > GetInlinedCapacity()) {
470 // Because this is only called from the `InlinedVector` constructors, it's
471 // safe to take on the allocation with size `0`. If `ConstructElements(...)`
472 // throws, deallocation will be automatically handled by `~Storage()`.
473 size_type new_capacity = ComputeCapacity(GetInlinedCapacity(), new_size);
474 pointer new_data = AllocatorTraits::allocate(*GetAllocPtr(), new_capacity);
475
476 SetAllocatedData(new_data, new_capacity);
477 SetIsAllocated();
478
479 construct_data = new_data;
480 } else {
481 construct_data = GetInlinedData();
482 }
483
484 inlined_vector_internal::ConstructElements(GetAllocPtr(), construct_data,
485 &values, new_size);
486
487 // Since the initial size was guaranteed to be `0` and the allocated bit is
488 // already correct for either case, *adding* `new_size` gives us the correct
489 // result faster than setting it directly.
490 AddSize(new_size);
491}
492
493template <typename T, size_t N, typename A>
494template <typename ValueAdapter>
495auto Storage<T, N, A>::Assign(ValueAdapter values, size_type new_size) -> void {
496 StorageView storage_view = MakeStorageView();
497
498 AllocationTransaction allocation_tx(GetAllocPtr());
499
500 absl::Span<value_type> assign_loop;
501 absl::Span<value_type> construct_loop;
502 absl::Span<value_type> destroy_loop;
503
504 if (new_size > storage_view.capacity) {
505 size_type new_capacity = ComputeCapacity(storage_view.capacity, new_size);
506 pointer new_data = allocation_tx.Allocate(new_capacity);
507
508 construct_loop = {new_data, new_size};
509 destroy_loop = {storage_view.data, storage_view.size};
510 } else if (new_size > storage_view.size) {
511 assign_loop = {storage_view.data, storage_view.size};
512 construct_loop = {storage_view.data + storage_view.size,
513 new_size - storage_view.size};
514 } else {
515 assign_loop = {storage_view.data, new_size};
516 destroy_loop = {storage_view.data + new_size, storage_view.size - new_size};
517 }
518
519 inlined_vector_internal::AssignElements(assign_loop.data(), &values,
520 assign_loop.size());
521
522 inlined_vector_internal::ConstructElements(
523 GetAllocPtr(), construct_loop.data(), &values, construct_loop.size());
524
525 inlined_vector_internal::DestroyElements(GetAllocPtr(), destroy_loop.data(),
526 destroy_loop.size());
527
528 if (allocation_tx.DidAllocate()) {
529 DeallocateIfAllocated();
530 AcquireAllocatedData(&allocation_tx);
531 SetIsAllocated();
532 }
533
534 SetSize(new_size);
535}
536
537template <typename T, size_t N, typename A>
538template <typename ValueAdapter>
539auto Storage<T, N, A>::Resize(ValueAdapter values, size_type new_size) -> void {
540 StorageView storage_view = MakeStorageView();
541
542 AllocationTransaction allocation_tx(GetAllocPtr());
543 ConstructionTransaction construction_tx(GetAllocPtr());
544
545 IteratorValueAdapter<MoveIterator> move_values(
546 MoveIterator(storage_view.data));
547
548 absl::Span<value_type> construct_loop;
549 absl::Span<value_type> move_construct_loop;
550 absl::Span<value_type> destroy_loop;
551
552 if (new_size > storage_view.capacity) {
553 size_type new_capacity = ComputeCapacity(storage_view.capacity, new_size);
554 pointer new_data = allocation_tx.Allocate(new_capacity);
555
556 construct_loop = {new_data + storage_view.size,
557 new_size - storage_view.size};
558 move_construct_loop = {new_data, storage_view.size};
559 destroy_loop = {storage_view.data, storage_view.size};
560 } else if (new_size > storage_view.size) {
561 construct_loop = {storage_view.data + storage_view.size,
562 new_size - storage_view.size};
563 } else {
564 destroy_loop = {storage_view.data + new_size, storage_view.size - new_size};
565 }
566
567 construction_tx.Construct(construct_loop.data(), &values,
568 construct_loop.size());
569
570 inlined_vector_internal::ConstructElements(
571 GetAllocPtr(), move_construct_loop.data(), &move_values,
572 move_construct_loop.size());
573
574 inlined_vector_internal::DestroyElements(GetAllocPtr(), destroy_loop.data(),
575 destroy_loop.size());
576
577 construction_tx.Commit();
578 if (allocation_tx.DidAllocate()) {
579 DeallocateIfAllocated();
580 AcquireAllocatedData(&allocation_tx);
581 SetIsAllocated();
582 }
583
584 SetSize(new_size);
585}
586
587template <typename T, size_t N, typename A>
588template <typename ValueAdapter>
589auto Storage<T, N, A>::Insert(const_iterator pos, ValueAdapter values,
590 size_type insert_count) -> iterator {
591 StorageView storage_view = MakeStorageView();
592
593 size_type insert_index =
594 std::distance(const_iterator(storage_view.data), pos);
595 size_type insert_end_index = insert_index + insert_count;
596 size_type new_size = storage_view.size + insert_count;
597
598 if (new_size > storage_view.capacity) {
599 AllocationTransaction allocation_tx(GetAllocPtr());
600 ConstructionTransaction construction_tx(GetAllocPtr());
601 ConstructionTransaction move_construciton_tx(GetAllocPtr());
602
603 IteratorValueAdapter<MoveIterator> move_values(
604 MoveIterator(storage_view.data));
605
606 size_type new_capacity = ComputeCapacity(storage_view.capacity, new_size);
607 pointer new_data = allocation_tx.Allocate(new_capacity);
608
609 construction_tx.Construct(new_data + insert_index, &values, insert_count);
610
611 move_construciton_tx.Construct(new_data, &move_values, insert_index);
612
613 inlined_vector_internal::ConstructElements(
614 GetAllocPtr(), new_data + insert_end_index, &move_values,
615 storage_view.size - insert_index);
616
617 inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
618 storage_view.size);
619
620 construction_tx.Commit();
621 move_construciton_tx.Commit();
622 DeallocateIfAllocated();
623 AcquireAllocatedData(&allocation_tx);
624
625 SetAllocatedSize(new_size);
626 return iterator(new_data + insert_index);
627 } else {
628 size_type move_construction_destination_index =
629 (std::max)(insert_end_index, storage_view.size);
630
631 ConstructionTransaction move_construction_tx(GetAllocPtr());
632
633 IteratorValueAdapter<MoveIterator> move_construction_values(
634 MoveIterator(storage_view.data +
635 (move_construction_destination_index - insert_count)));
636 absl::Span<value_type> move_construction = {
637 storage_view.data + move_construction_destination_index,
638 new_size - move_construction_destination_index};
639
640 pointer move_assignment_values = storage_view.data + insert_index;
641 absl::Span<value_type> move_assignment = {
642 storage_view.data + insert_end_index,
643 move_construction_destination_index - insert_end_index};
644
645 absl::Span<value_type> insert_assignment = {move_assignment_values,
646 move_construction.size()};
647
648 absl::Span<value_type> insert_construction = {
649 insert_assignment.data() + insert_assignment.size(),
650 insert_count - insert_assignment.size()};
651
652 move_construction_tx.Construct(move_construction.data(),
653 &move_construction_values,
654 move_construction.size());
655
656 for (pointer destination = move_assignment.data() + move_assignment.size(),
657 last_destination = move_assignment.data(),
658 source = move_assignment_values + move_assignment.size();
659 ;) {
660 --destination;
661 --source;
662 if (destination < last_destination) break;
663 *destination = std::move(*source);
664 }
665
666 inlined_vector_internal::AssignElements(insert_assignment.data(), &values,
667 insert_assignment.size());
668
669 inlined_vector_internal::ConstructElements(
670 GetAllocPtr(), insert_construction.data(), &values,
671 insert_construction.size());
672
673 move_construction_tx.Commit();
674
675 AddSize(insert_count);
676 return iterator(storage_view.data + insert_index);
677 }
678}
679
680template <typename T, size_t N, typename A>
681template <typename... Args>
682auto Storage<T, N, A>::EmplaceBack(Args&&... args) -> reference {
683 StorageView storage_view = MakeStorageView();
684
685 AllocationTransaction allocation_tx(GetAllocPtr());
686
687 IteratorValueAdapter<MoveIterator> move_values(
688 MoveIterator(storage_view.data));
689
690 pointer construct_data;
691 if (storage_view.size == storage_view.capacity) {
692 size_type new_capacity = NextCapacity(storage_view.capacity);
693 pointer new_data = allocation_tx.Allocate(new_capacity);
694
695 construct_data = new_data;
696 } else {
697 construct_data = storage_view.data;
698 }
699
700 AllocatorTraits::construct(*GetAllocPtr(), construct_data + storage_view.size,
701 std::forward<Args>(args)...);
702
703 if (allocation_tx.DidAllocate()) {
704 ABSL_INTERNAL_TRY {
705 inlined_vector_internal::ConstructElements(
706 GetAllocPtr(), allocation_tx.GetData(), &move_values,
707 storage_view.size);
708 }
709 ABSL_INTERNAL_CATCH_ANY {
710 AllocatorTraits::destroy(*GetAllocPtr(),
711 construct_data + storage_view.size);
712 ABSL_INTERNAL_RETHROW;
713 }
714
715 inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
716 storage_view.size);
717
718 DeallocateIfAllocated();
719 AcquireAllocatedData(&allocation_tx);
720 SetIsAllocated();
721 }
722
723 AddSize(1);
724 return *(construct_data + storage_view.size);
725}
726
727template <typename T, size_t N, typename A>
728auto Storage<T, N, A>::Erase(const_iterator from, const_iterator to)
729 -> iterator {
730 assert(from != to);
731
732 StorageView storage_view = MakeStorageView();
733
734 size_type erase_size = std::distance(from, to);
735 size_type erase_index =
736 std::distance(const_iterator(storage_view.data), from);
737 size_type erase_end_index = erase_index + erase_size;
738
739 IteratorValueAdapter<MoveIterator> move_values(
740 MoveIterator(storage_view.data + erase_end_index));
741
742 inlined_vector_internal::AssignElements(storage_view.data + erase_index,
743 &move_values,
744 storage_view.size - erase_end_index);
745
746 inlined_vector_internal::DestroyElements(
747 GetAllocPtr(), storage_view.data + (storage_view.size - erase_size),
748 erase_size);
749
750 SubtractSize(erase_size);
751 return iterator(storage_view.data + erase_index);
752}
753
754template <typename T, size_t N, typename A>
755auto Storage<T, N, A>::Reserve(size_type requested_capacity) -> void {
756 StorageView storage_view = MakeStorageView();
757
758 if (ABSL_PREDICT_FALSE(requested_capacity <= storage_view.capacity)) return;
759
760 AllocationTransaction allocation_tx(GetAllocPtr());
761
762 IteratorValueAdapter<MoveIterator> move_values(
763 MoveIterator(storage_view.data));
764
765 size_type new_capacity =
766 ComputeCapacity(storage_view.capacity, requested_capacity);
767 pointer new_data = allocation_tx.Allocate(new_capacity);
768
769 inlined_vector_internal::ConstructElements(GetAllocPtr(), new_data,
770 &move_values, storage_view.size);
771
772 inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
773 storage_view.size);
774
775 DeallocateIfAllocated();
776 AcquireAllocatedData(&allocation_tx);
777 SetIsAllocated();
778}
779
780template <typename T, size_t N, typename A>
781auto Storage<T, N, A>::ShrinkToFit() -> void {
782 // May only be called on allocated instances!
783 assert(GetIsAllocated());
784
785 StorageView storage_view{GetAllocatedData(), GetSize(),
786 GetAllocatedCapacity()};
787
788 if (ABSL_PREDICT_FALSE(storage_view.size == storage_view.capacity)) return;
789
790 AllocationTransaction allocation_tx(GetAllocPtr());
791
792 IteratorValueAdapter<MoveIterator> move_values(
793 MoveIterator(storage_view.data));
794
795 pointer construct_data;
796 if (storage_view.size > GetInlinedCapacity()) {
797 size_type new_capacity = storage_view.size;
798 pointer new_data = allocation_tx.Allocate(new_capacity);
799
800 construct_data = new_data;
801 } else {
802 construct_data = GetInlinedData();
803 }
804
805 ABSL_INTERNAL_TRY {
806 inlined_vector_internal::ConstructElements(GetAllocPtr(), construct_data,
807 &move_values, storage_view.size);
808 }
809 ABSL_INTERNAL_CATCH_ANY {
810 SetAllocatedData(storage_view.data, storage_view.capacity);
811 ABSL_INTERNAL_RETHROW;
812 }
813
814 inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
815 storage_view.size);
816
817 AllocatorTraits::deallocate(*GetAllocPtr(), storage_view.data,
818 storage_view.capacity);
819
820 if (allocation_tx.DidAllocate()) {
821 AcquireAllocatedData(&allocation_tx);
822 } else {
823 UnsetIsAllocated();
824 }
825}
826
827template <typename T, size_t N, typename A>
828auto Storage<T, N, A>::Swap(Storage* other_storage_ptr) -> void {
829 using std::swap;
830 assert(this != other_storage_ptr);
831
832 if (GetIsAllocated() && other_storage_ptr->GetIsAllocated()) {
833 swap(data_.allocated, other_storage_ptr->data_.allocated);
834 } else if (!GetIsAllocated() && !other_storage_ptr->GetIsAllocated()) {
835 Storage* small_ptr = this;
836 Storage* large_ptr = other_storage_ptr;
837 if (small_ptr->GetSize() > large_ptr->GetSize()) swap(small_ptr, large_ptr);
838
839 for (size_type i = 0; i < small_ptr->GetSize(); ++i) {
840 swap(small_ptr->GetInlinedData()[i], large_ptr->GetInlinedData()[i]);
841 }
842
843 IteratorValueAdapter<MoveIterator> move_values(
844 MoveIterator(large_ptr->GetInlinedData() + small_ptr->GetSize()));
845
846 inlined_vector_internal::ConstructElements(
847 large_ptr->GetAllocPtr(),
848 small_ptr->GetInlinedData() + small_ptr->GetSize(), &move_values,
849 large_ptr->GetSize() - small_ptr->GetSize());
850
851 inlined_vector_internal::DestroyElements(
852 large_ptr->GetAllocPtr(),
853 large_ptr->GetInlinedData() + small_ptr->GetSize(),
854 large_ptr->GetSize() - small_ptr->GetSize());
855 } else {
856 Storage* allocated_ptr = this;
857 Storage* inlined_ptr = other_storage_ptr;
858 if (!allocated_ptr->GetIsAllocated()) swap(allocated_ptr, inlined_ptr);
859
860 StorageView allocated_storage_view{allocated_ptr->GetAllocatedData(),
861 allocated_ptr->GetSize(),
862 allocated_ptr->GetAllocatedCapacity()};
863
864 IteratorValueAdapter<MoveIterator> move_values(
865 MoveIterator(inlined_ptr->GetInlinedData()));
866
867 ABSL_INTERNAL_TRY {
868 inlined_vector_internal::ConstructElements(
869 inlined_ptr->GetAllocPtr(), allocated_ptr->GetInlinedData(),
870 &move_values, inlined_ptr->GetSize());
871 }
872 ABSL_INTERNAL_CATCH_ANY {
873 allocated_ptr->SetAllocatedData(allocated_storage_view.data,
874 allocated_storage_view.capacity);
875 ABSL_INTERNAL_RETHROW;
876 }
877
878 inlined_vector_internal::DestroyElements(inlined_ptr->GetAllocPtr(),
879 inlined_ptr->GetInlinedData(),
880 inlined_ptr->GetSize());
881
882 inlined_ptr->SetAllocatedData(allocated_storage_view.data,
883 allocated_storage_view.capacity);
884 }
885
886 swap(GetSizeAndIsAllocated(), other_storage_ptr->GetSizeAndIsAllocated());
887 swap(*GetAllocPtr(), *other_storage_ptr->GetAllocPtr());
888}
889
890} // namespace inlined_vector_internal
891} // namespace absl
892
893#endif // ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_