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
38template <typename T, typename SizeType = uint16_t>
40 public:
41 using value_type = T;
42 using size_type = SizeType;
43 using difference_type = std::ptrdiff_t;
44 using reference = value_type&;
45 using const_reference = const value_type&;
46 using pointer = value_type*;
47 using const_pointer = const value_type*;
49
50 private:
51 // Iterator that automatically dereferences the pointer.
52 template <bool kIsConst>
53 class Iterator {
54 public:
55 using iterator_category = std::random_access_iterator_tag;
56 using value_type = T;
57 using difference_type = std::ptrdiff_t;
58 using pointer = std::conditional_t<kIsConst, const T*, T*>;
59 using reference = std::conditional_t<kIsConst, const T&, T&>;
60
61 constexpr Iterator() = default;
62
63 // Allow conversion from non-const to const iterator.
64 template <bool kOtherConst,
65 typename = std::enable_if_t<kIsConst && !kOtherConst>>
66 constexpr Iterator(const Iterator<kOtherConst>& other) : it_(other.it_) {}
67
68 reference operator*() const { return **it_; }
69 pointer operator->() const { return *it_; }
70
71 Iterator& operator++() {
72 ++it_;
73 return *this;
74 }
75 Iterator operator++(int) { return Iterator(it_++); }
76 Iterator& operator--() {
77 --it_;
78 return *this;
79 }
80 Iterator operator--(int) { return Iterator(it_--); }
81
82 Iterator& operator+=(difference_type n) {
83 it_ += n;
84 return *this;
85 }
86 Iterator& operator-=(difference_type n) {
87 it_ -= n;
88 return *this;
89 }
90 friend Iterator operator+(Iterator it, difference_type n) {
91 return Iterator(it.it_ + n);
92 }
93 friend Iterator operator+(difference_type n, Iterator it) {
94 return Iterator(it.it_ + n);
95 }
96 friend Iterator operator-(Iterator it, difference_type n) {
97 return Iterator(it.it_ - n);
98 }
99 friend difference_type operator-(Iterator lhs, Iterator rhs) {
100 return lhs.it_ - rhs.it_;
101 }
102
103 friend bool operator==(Iterator lhs, Iterator rhs) {
104 return lhs.it_ == rhs.it_;
105 }
106 friend bool operator!=(Iterator lhs, Iterator rhs) {
107 return lhs.it_ != rhs.it_;
108 }
109 friend bool operator<(Iterator lhs, Iterator rhs) {
110 return lhs.it_ < rhs.it_;
111 }
112 friend bool operator<=(Iterator lhs, Iterator rhs) {
113 return lhs.it_ <= rhs.it_;
114 }
115 friend bool operator>(Iterator lhs, Iterator rhs) {
116 return lhs.it_ > rhs.it_;
117 }
118 friend bool operator>=(Iterator lhs, Iterator rhs) {
119 return lhs.it_ >= rhs.it_;
120 }
121
122 reference operator[](difference_type n) const { return *(*this + n); }
123
124 private:
125 using BaseIterator =
126 std::conditional_t<kIsConst,
129
130 explicit constexpr Iterator(BaseIterator it) : it_(it) {}
131
132 friend class DynamicPtrVector;
133 BaseIterator it_;
134 };
135
136 public:
137 using iterator = Iterator<false>;
138 using const_iterator = Iterator<true>;
139 using reverse_iterator = std::reverse_iterator<iterator>;
140 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
141
143 explicit constexpr DynamicPtrVector(Allocator& allocator)
144 : vector_(allocator) {}
145
146 ~DynamicPtrVector() { clear(); }
147
148 DynamicPtrVector(const DynamicPtrVector&) = delete;
149 DynamicPtrVector& operator=(const DynamicPtrVector&) = delete;
150
151 DynamicPtrVector(DynamicPtrVector&& other) noexcept = default;
152 DynamicPtrVector& operator=(DynamicPtrVector&& other) noexcept {
153 clear();
154 vector_ = std::move(other.vector_);
155 return *this;
156 }
157
158 // Iterators
159
160 iterator begin() { return iterator(vector_.begin()); }
161 const_iterator begin() const { return const_iterator(vector_.begin()); }
162 const_iterator cbegin() const { return begin(); }
163
164 iterator end() { return iterator(vector_.end()); }
165 const_iterator end() const { return const_iterator(vector_.end()); }
166 const_iterator cend() const { return end(); }
167
168 reverse_iterator rbegin() { return reverse_iterator(end()); }
169 const_reverse_iterator rbegin() const {
170 return const_reverse_iterator(end());
171 }
172 const_reverse_iterator crbegin() const { return rbegin(); }
173
174 reverse_iterator rend() { return reverse_iterator(begin()); }
175 const_reverse_iterator rend() const {
176 return const_reverse_iterator(begin());
177 }
178 const_reverse_iterator crend() const { return rend(); }
179
180 // Capacity
181
182 allocator_type& get_allocator() const { return vector_.get_allocator(); }
183 [[nodiscard]] bool empty() const { return vector_.empty(); }
184 size_type size() const { return vector_.size(); }
185 size_type ptr_capacity() const { return vector_.capacity(); }
186 size_type max_size() const { return vector_.max_size(); }
187
191 void reserve_ptr(size_type new_capacity) { vector_.reserve(new_capacity); }
192
194 void reserve_ptr_exact(size_type new_capacity) {
195 vector_.reserve_exact(new_capacity);
196 }
197
201 [[nodiscard]] bool try_reserve_ptr(size_type new_capacity) {
202 return vector_.try_reserve(new_capacity);
203 }
205 [[nodiscard]] bool try_reserve_ptr_exact(size_type new_capacity) {
206 return vector_.try_reserve_exact(new_capacity);
207 }
208
209 void shrink_to_fit() { vector_.shrink_to_fit(); }
210
211 // Element access
212
213 reference operator[](size_type pos) { return *vector_[pos]; }
214 const_reference operator[](size_type pos) const { return *vector_[pos]; }
215
216 reference at(size_type pos) { return *vector_.at(pos); }
217 const_reference at(size_type pos) const { return *vector_.at(pos); }
218
219 reference front() { return *vector_.front(); }
220 const_reference front() const { return *vector_.front(); }
221
222 reference back() { return *vector_.back(); }
223 const_reference back() const { return *vector_.back(); }
224
227 T* const* data() { return vector_.data(); }
228 const T* const* data() const { return vector_.data(); }
229
230 // Modifiers
231
233 void push_back(const T& value) { emplace_back(value); }
234
236 void push_back(T&& value) { emplace_back(std::move(value)); }
237
239 [[nodiscard]] bool try_push_back(const T& value) {
240 return try_emplace_back(value);
241 }
242
248 void push_back(UniquePtr<T>&& value) {
249 PW_ASSERT(value != nullptr);
250 if (value.deallocator()->IsEqual(get_allocator())) {
251 vector_.push_back(value.get());
252 value.Release();
253 } else {
254 emplace_back(std::move(*value));
255 value.Reset();
256 }
257 }
258
259 void pop_back() {
260 T* ptr = vector_.back();
261 vector_.pop_back();
262 Delete(ptr);
263 }
264
266 [[nodiscard]] pw::UniquePtr<T> take(const_iterator pos) {
267 T* ptr = const_cast<T*>(pos.operator->());
268 // Remove from vector WITHOUT destroying the object.
269 vector_.erase(pos.it_);
270 return pw::UniquePtr<T>(ptr, vector_.get_allocator());
271 }
272
282 template <typename U = T, typename... Args>
283 void emplace_back(Args&&... args) {
284 PW_ASSERT(try_emplace_back<U>(std::forward<Args>(args)...));
285 }
286
293 template <typename U = T, typename... Args>
294 [[nodiscard]] bool try_emplace_back(Args&&... args) {
295 return try_emplace<U>(end(), std::forward<Args>(args)...).has_value();
296 }
297
307 template <typename U = T, typename... Args>
308 iterator emplace(const_iterator pos, Args&&... args) {
309 std::optional<iterator> res =
310 try_emplace<U>(pos, std::forward<Args>(args)...);
311 PW_ASSERT(res.has_value());
312 return *res;
313 }
314
321 template <typename U = T, typename... Args>
322 [[nodiscard]] std::optional<iterator> try_emplace(const_iterator pos,
323 Args&&... args) {
324 static_assert(
325 std::is_same_v<T, U> ||
326 (std::is_base_of_v<T, U> && (std::is_trivially_destructible_v<U> ||
327 std::has_virtual_destructor_v<T>)),
328 "Objects must inherit from T and be either virtually or trivially "
329 "destructible");
330 // Get the index since try_reserve() invalidates iterators.
331 const auto index = std::distance(vector_.cbegin(), pos.it_);
332
333 if (!vector_.try_reserve(vector_.size() + 1)) {
334 return std::nullopt;
335 }
336
337 if (T* ptr = vector_.get_allocator().template New<U>(
338 std::forward<Args>(args)...);
339 ptr != nullptr) {
340 // Skip has_value() check; try_insert() will succeed due to try_reserve().
341 return iterator(*vector_.try_insert(vector_.begin() + index, ptr));
342 }
343 return std::nullopt;
344 }
345
346 iterator insert(const_iterator pos, const T& value) {
347 return emplace(pos, value);
348 }
349 iterator insert(const_iterator pos, T&& value) {
350 return emplace(pos, std::move(value));
351 }
352
358 iterator insert(const_iterator pos, UniquePtr<T>&& value) {
359 PW_ASSERT(value != nullptr);
360 if (value.deallocator()->IsEqual(get_allocator())) {
361 iterator it = iterator(vector_.insert(pos.it_, value.get()));
362 value.Release();
363 return it;
364 }
365
366 iterator it = emplace(pos, std::move(*value));
367 value.Reset();
368 return it;
369 }
370
371 [[nodiscard]] std::optional<iterator> try_insert(const_iterator pos,
372 const T& value) {
373 return try_emplace(pos, value);
374 }
375
376 iterator erase(const_iterator pos) { return erase(pos, pos + 1); }
377
378 iterator erase(const_iterator first, const_iterator last) {
379 // DynamicVector::erase moves elements to fill the gap, so delete first.
380 for (auto it = first; it != last; ++it) {
381 Delete(const_cast<T*>(it.operator->()));
382 }
383 return iterator(vector_.erase(first.it_, last.it_));
384 }
385
386 void clear() {
387 for (T* ptr : vector_) {
388 Delete(ptr);
389 }
390 vector_.clear();
391 }
392
394 void swap(DynamicPtrVector& other) { vector_.swap(other.vector_); }
395
398 void swap(size_type first, size_type second) {
399 std::swap(vector_[first], vector_[second]);
400 }
401
404 void swap(const_iterator first, const_iterator second) {
405 std::swap(const_cast<pointer&>(*first.it_),
406 const_cast<pointer&>(*second.it_));
407 }
408
409 private:
410 void Delete(T* ptr) { vector_.get_allocator().Delete(ptr); }
411
412 DynamicVector<T*, SizeType> vector_;
413};
414
416
417} // namespace pw
Definition: allocator.h:45
Definition: dynamic_ptr_vector.h:39
Definition: unique_ptr.h:43
Definition: ptr_iterator.h:164
Definition: ptr_iterator.h:142
void Delete(T *ptr)
Definition: deallocator.h:284
void swap(const_iterator first, const_iterator second)
Definition: dynamic_ptr_vector.h:404
std::optional< iterator > try_emplace(const_iterator pos, Args &&... args)
Definition: dynamic_ptr_vector.h:322
void swap(size_type first, size_type second)
Definition: dynamic_ptr_vector.h:398
void emplace_back(Args &&... args)
Definition: dynamic_ptr_vector.h:283
void push_back(const T &value)
Appends a new element by copying value.
Definition: dynamic_ptr_vector.h:233
void push_back(UniquePtr< T > &&value)
Definition: dynamic_ptr_vector.h:248
bool try_emplace_back(Args &&... args)
Definition: dynamic_ptr_vector.h:294
void reserve_ptr_exact(size_type new_capacity)
Definition: dynamic_ptr_vector.h:194
void swap(DynamicPtrVector &other)
Swaps the contents of this DynamicPtrVector with another one.
Definition: dynamic_ptr_vector.h:394
iterator emplace(const_iterator pos, Args &&... args)
Definition: dynamic_ptr_vector.h:308
bool try_reserve_ptr(size_type new_capacity)
Definition: dynamic_ptr_vector.h:201
constexpr DynamicPtrVector(Allocator &allocator)
Constructs an empty DynamicPtrVector using the provided allocator.
Definition: dynamic_ptr_vector.h:143
bool try_reserve_ptr_exact(size_type new_capacity)
Definition: dynamic_ptr_vector.h:205
void push_back(T &&value)
Appends a new element by moving value.
Definition: dynamic_ptr_vector.h:236
iterator insert(const_iterator pos, UniquePtr< T > &&value)
Definition: dynamic_ptr_vector.h:358
pw::UniquePtr< T > take(const_iterator pos)
Removes the element at pos and returns it as a UniquePtr.
Definition: dynamic_ptr_vector.h:266
void reserve_ptr(size_type new_capacity)
Definition: dynamic_ptr_vector.h:191
bool try_push_back(const T &value)
Attempts to append a new element by copying value.
Definition: dynamic_ptr_vector.h:239
T *const * data()
Definition: dynamic_ptr_vector.h:227
The Pigweed namespace.
Definition: alignment.h:27