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