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