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