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