C/C++ API Reference
Loading...
Searching...
No Matches
dynamic_ptr_vector.h
1// Copyright 2025 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// 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, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <type_traits>
17#include <utility>
18
19#include "pw_allocator/allocator.h"
20#include "pw_allocator/unique_ptr.h"
21#include "pw_containers/dynamic_vector.h"
22
23namespace pw {
24
28
49template <typename T, typename SizeType = uint16_t>
51 public:
52 using value_type = T;
53 using size_type = SizeType;
54 using difference_type = std::ptrdiff_t;
55 using reference = value_type&;
56 using const_reference = const value_type&;
57 using pointer = value_type*;
58 using const_pointer = const value_type*;
60
61 private:
62 // Iterator that automatically dereferences the pointer.
63 template <bool kIsConst>
64 class Iterator {
65 public:
66 using iterator_category = std::random_access_iterator_tag;
67 using value_type = T;
68 using difference_type = std::ptrdiff_t;
69 using pointer = std::conditional_t<kIsConst, const T*, T*>;
70 using reference = std::conditional_t<kIsConst, const T&, T&>;
71
72 constexpr Iterator() = default;
73
74 // Allow conversion from non-const to const iterator.
75 template <bool kOtherConst,
76 typename = std::enable_if_t<kIsConst && !kOtherConst>>
77 constexpr Iterator(const Iterator<kOtherConst>& other) : it_(other.it_) {}
78
79 reference operator*() const { return **it_; }
80 pointer operator->() const { return *it_; }
81
82 Iterator& operator++() {
83 ++it_;
84 return *this;
85 }
86 Iterator operator++(int) { return Iterator(it_++); }
87 Iterator& operator--() {
88 --it_;
89 return *this;
90 }
91 Iterator operator--(int) { return Iterator(it_--); }
92
93 Iterator& operator+=(difference_type n) {
94 it_ += n;
95 return *this;
96 }
97 Iterator& operator-=(difference_type n) {
98 it_ -= n;
99 return *this;
100 }
101 friend Iterator operator+(Iterator it, difference_type n) {
102 return Iterator(it.it_ + n);
103 }
104 friend Iterator operator+(difference_type n, Iterator it) {
105 return Iterator(it.it_ + n);
106 }
107 friend Iterator operator-(Iterator it, difference_type n) {
108 return Iterator(it.it_ - n);
109 }
110 friend difference_type operator-(Iterator lhs, Iterator rhs) {
111 return lhs.it_ - rhs.it_;
112 }
113
114 friend bool operator==(Iterator lhs, Iterator rhs) {
115 return lhs.it_ == rhs.it_;
116 }
117 friend bool operator!=(Iterator lhs, Iterator rhs) {
118 return lhs.it_ != rhs.it_;
119 }
120 friend bool operator<(Iterator lhs, Iterator rhs) {
121 return lhs.it_ < rhs.it_;
122 }
123 friend bool operator<=(Iterator lhs, Iterator rhs) {
124 return lhs.it_ <= rhs.it_;
125 }
126 friend bool operator>(Iterator lhs, Iterator rhs) {
127 return lhs.it_ > rhs.it_;
128 }
129 friend bool operator>=(Iterator lhs, Iterator rhs) {
130 return lhs.it_ >= rhs.it_;
131 }
132
133 reference operator[](difference_type n) const { return *(*this + n); }
134
135 private:
136 using BaseIterator =
137 std::conditional_t<kIsConst,
140
141 explicit constexpr Iterator(BaseIterator it) : it_(it) {}
142
143 friend class DynamicPtrVector;
144 BaseIterator it_;
145 };
146
147 public:
148 using iterator = Iterator<false>;
149 using const_iterator = Iterator<true>;
150 using reverse_iterator = std::reverse_iterator<iterator>;
151 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
152
154 explicit constexpr DynamicPtrVector(Allocator& allocator)
155 : vector_(allocator) {}
156
157 ~DynamicPtrVector() { clear(); }
158
159 DynamicPtrVector(const DynamicPtrVector&) = delete;
160 DynamicPtrVector& operator=(const DynamicPtrVector&) = delete;
161
162 DynamicPtrVector(DynamicPtrVector&& other) noexcept = default;
163 DynamicPtrVector& operator=(DynamicPtrVector&& other) noexcept {
164 clear();
165 vector_ = std::move(other.vector_);
166 return *this;
167 }
168
169 // Iterators
170
171 iterator begin() { return iterator(vector_.begin()); }
172 const_iterator begin() const { return const_iterator(vector_.begin()); }
173 const_iterator cbegin() const { return begin(); }
174
175 iterator end() { return iterator(vector_.end()); }
176 const_iterator end() const { return const_iterator(vector_.end()); }
177 const_iterator cend() const { return end(); }
178
179 reverse_iterator rbegin() { return reverse_iterator(end()); }
180 const_reverse_iterator rbegin() const {
181 return const_reverse_iterator(end());
182 }
183 const_reverse_iterator crbegin() const { return rbegin(); }
184
185 reverse_iterator rend() { return reverse_iterator(begin()); }
186 const_reverse_iterator rend() const {
187 return const_reverse_iterator(begin());
188 }
189 const_reverse_iterator crend() const { return rend(); }
190
191 // Capacity
192
193 allocator_type& get_allocator() const { return vector_.get_allocator(); }
194 [[nodiscard]] bool empty() const { return vector_.empty(); }
195 size_type size() const { return vector_.size(); }
196 size_type ptr_capacity() const { return vector_.capacity(); }
197 size_type max_size() const { return vector_.max_size(); }
198
202 void reserve_ptr(size_type new_capacity) { vector_.reserve(new_capacity); }
203
205 void reserve_ptr_exact(size_type new_capacity) {
206 vector_.reserve_exact(new_capacity);
207 }
208
212 [[nodiscard]] bool try_reserve_ptr(size_type new_capacity) {
213 return vector_.try_reserve(new_capacity);
214 }
216 [[nodiscard]] bool try_reserve_ptr_exact(size_type new_capacity) {
217 return vector_.try_reserve_exact(new_capacity);
218 }
219
220 void shrink_to_fit() { vector_.shrink_to_fit(); }
221
222 // Element access
223
224 reference operator[](size_type pos) { return *vector_[pos]; }
225 const_reference operator[](size_type pos) const { return *vector_[pos]; }
226
227 reference at(size_type pos) { return *vector_.at(pos); }
228 const_reference at(size_type pos) const { return *vector_.at(pos); }
229
230 reference front() { return *vector_.front(); }
231 const_reference front() const { return *vector_.front(); }
232
233 reference back() { return *vector_.back(); }
234 const_reference back() const { return *vector_.back(); }
235
238 T* const* data() { return vector_.data(); }
239 const T* const* data() const { return vector_.data(); }
240
241 // Modifiers
242
244 void push_back(const T& value) { emplace_back(value); }
245
247 void push_back(T&& value) { emplace_back(std::move(value)); }
248
250 [[nodiscard]] bool try_push_back(const T& value) {
251 return try_emplace_back(value);
252 }
253
259 void push_back(UniquePtr<T>&& value) {
260 PW_ASSERT(value != nullptr);
261 if (value.deallocator()->IsEqual(get_allocator())) {
262 vector_.push_back(value.get());
263 value.Release();
264 } else {
265 emplace_back(std::move(*value));
266 value.Reset();
267 }
268 }
269
270 void pop_back() {
271 T* ptr = vector_.back();
272 vector_.pop_back();
273 Delete(ptr);
274 }
275
277 [[nodiscard]] pw::UniquePtr<T> take(const_iterator pos) {
278 T* ptr = const_cast<T*>(pos.operator->());
279 // Remove from vector WITHOUT destroying the object.
280 vector_.erase(pos.it_);
281 return pw::UniquePtr<T>(ptr, vector_.get_allocator());
282 }
283
293 template <typename U = T, typename... Args>
294 void emplace_back(Args&&... args) {
295 PW_ASSERT(try_emplace_back<U>(std::forward<Args>(args)...));
296 }
297
304 template <typename U = T, typename... Args>
305 [[nodiscard]] bool try_emplace_back(Args&&... args) {
306 return try_emplace<U>(end(), std::forward<Args>(args)...).has_value();
307 }
308
318 template <typename U = T, typename... Args>
319 iterator emplace(const_iterator pos, Args&&... args) {
320 std::optional<iterator> res =
321 try_emplace<U>(pos, std::forward<Args>(args)...);
322 PW_ASSERT(res.has_value());
323 return *res;
324 }
325
332 template <typename U = T, typename... Args>
333 [[nodiscard]] std::optional<iterator> try_emplace(const_iterator pos,
334 Args&&... args) {
335 static_assert(
336 std::is_same_v<T, U> ||
337 (std::is_base_of_v<T, U> && (std::is_trivially_destructible_v<U> ||
338 std::has_virtual_destructor_v<T>)),
339 "Objects must inherit from T and be either virtually or trivially "
340 "destructible");
341 // Get the index since try_reserve() invalidates iterators.
342 const auto index = std::distance(vector_.cbegin(), pos.it_);
343
344 if (!vector_.try_reserve(vector_.size() + 1)) {
345 return std::nullopt;
346 }
347
348 if (T* ptr = vector_.get_allocator().template New<U>(
349 std::forward<Args>(args)...);
350 ptr != nullptr) {
351 // Skip has_value() check; try_insert() will succeed due to try_reserve().
352 return iterator(*vector_.try_insert(vector_.begin() + index, ptr));
353 }
354 return std::nullopt;
355 }
356
357 iterator insert(const_iterator pos, const T& value) {
358 return emplace(pos, value);
359 }
360 iterator insert(const_iterator pos, T&& value) {
361 return emplace(pos, std::move(value));
362 }
363
369 iterator insert(const_iterator pos, UniquePtr<T>&& value) {
370 PW_ASSERT(value != nullptr);
371 if (value.deallocator()->IsEqual(get_allocator())) {
372 iterator it = iterator(vector_.insert(pos.it_, value.get()));
373 value.Release();
374 return it;
375 }
376
377 iterator it = emplace(pos, std::move(*value));
378 value.Reset();
379 return it;
380 }
381
382 [[nodiscard]] std::optional<iterator> try_insert(const_iterator pos,
383 const T& value) {
384 return try_emplace(pos, value);
385 }
386
387 iterator erase(const_iterator pos) { return erase(pos, pos + 1); }
388
389 iterator erase(const_iterator first, const_iterator last) {
390 // DynamicVector::erase moves elements to fill the gap, so delete first.
391 for (auto it = first; it != last; ++it) {
392 Delete(const_cast<T*>(it.operator->()));
393 }
394 return iterator(vector_.erase(first.it_, last.it_));
395 }
396
397 void clear() {
398 for (T* ptr : vector_) {
399 Delete(ptr);
400 }
401 vector_.clear();
402 }
403
405 void reset() {
406 clear();
407 vector_.reset();
408 }
409
411 void swap(DynamicPtrVector& other) { vector_.swap(other.vector_); }
412
415 void swap(size_type first, size_type second) {
416 std::swap(vector_[first], vector_[second]);
417 }
418
421 void swap(const_iterator first, const_iterator second) {
422 std::swap(const_cast<pointer&>(*first.it_),
423 const_cast<pointer&>(*second.it_));
424 }
425
426 private:
427 void Delete(T* ptr) { vector_.get_allocator().Delete(ptr); }
428
429 DynamicVector<T*, SizeType> vector_;
430};
431
433
434} // namespace pw
Definition: allocator.h:42
Definition: dynamic_ptr_vector.h:50
Definition: unique_ptr.h:44
Definition: ptr_iterator.h:164
Definition: ptr_iterator.h:142
void Delete(T *ptr)
Definition: deallocator.h:248
void swap(const_iterator first, const_iterator second)
Definition: dynamic_ptr_vector.h:421
void reset()
Clears the deque and deallocates its buffer.
Definition: dynamic_ptr_vector.h:405
std::optional< iterator > try_emplace(const_iterator pos, Args &&... args)
Definition: dynamic_ptr_vector.h:333
void swap(size_type first, size_type second)
Definition: dynamic_ptr_vector.h:415
void emplace_back(Args &&... args)
Definition: dynamic_ptr_vector.h:294
void push_back(const T &value)
Appends a new element by copying value.
Definition: dynamic_ptr_vector.h:244
void push_back(UniquePtr< T > &&value)
Definition: dynamic_ptr_vector.h:259
bool try_emplace_back(Args &&... args)
Definition: dynamic_ptr_vector.h:305
void reserve_ptr_exact(size_type new_capacity)
Definition: dynamic_ptr_vector.h:205
void swap(DynamicPtrVector &other)
Swaps the contents of this DynamicPtrVector with another one.
Definition: dynamic_ptr_vector.h:411
iterator emplace(const_iterator pos, Args &&... args)
Definition: dynamic_ptr_vector.h:319
bool try_reserve_ptr(size_type new_capacity)
Definition: dynamic_ptr_vector.h:212
constexpr DynamicPtrVector(Allocator &allocator)
Constructs an empty DynamicPtrVector using the provided allocator.
Definition: dynamic_ptr_vector.h:154
bool try_reserve_ptr_exact(size_type new_capacity)
Definition: dynamic_ptr_vector.h:216
void push_back(T &&value)
Appends a new element by moving value.
Definition: dynamic_ptr_vector.h:247
iterator insert(const_iterator pos, UniquePtr< T > &&value)
Definition: dynamic_ptr_vector.h:369
pw::UniquePtr< T > take(const_iterator pos)
Removes the element at pos and returns it as a UniquePtr.
Definition: dynamic_ptr_vector.h:277
void reserve_ptr(size_type new_capacity)
Definition: dynamic_ptr_vector.h:202
bool try_push_back(const T &value)
Attempts to append a new element by copying value.
Definition: dynamic_ptr_vector.h:250
T *const * data()
Definition: dynamic_ptr_vector.h:238
The Pigweed namespace.
Definition: alignment.h:27