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
244 [[nodiscard]] bool try_push_back(T&& value) {
245 return try_emplace_back(std::move(value));
246 }
247
248 void pop_back() {
249 T* ptr = vector_.back();
250 vector_.pop_back();
251 Delete(ptr);
252 }
253
255 [[nodiscard]] pw::UniquePtr<T> take(const_iterator pos) {
256 T* ptr = const_cast<T*>(pos.operator->());
257 // Remove from vector WITHOUT destroying the object.
258 vector_.erase(pos.it_);
259 return pw::UniquePtr<T>(ptr, vector_.get_allocator());
260 }
261
271 template <typename U = T, typename... Args>
272 void emplace_back(Args&&... args) {
273 PW_ASSERT(try_emplace_back<U>(std::forward<Args>(args)...));
274 }
275
282 template <typename U = T, typename... Args>
283 [[nodiscard]] bool try_emplace_back(Args&&... args) {
284 return try_emplace<U>(end(), std::forward<Args>(args)...).has_value();
285 }
286
296 template <typename U = T, typename... Args>
297 iterator emplace(const_iterator pos, Args&&... args) {
298 std::optional<iterator> res =
299 try_emplace<U>(pos, std::forward<Args>(args)...);
300 PW_ASSERT(res.has_value());
301 return *res;
302 }
303
310 template <typename U = T, typename... Args>
311 [[nodiscard]] std::optional<iterator> try_emplace(const_iterator pos,
312 Args&&... args) {
313 static_assert(
314 std::is_same_v<T, U> ||
315 (std::is_base_of_v<T, U> && (std::is_trivially_destructible_v<U> ||
316 std::has_virtual_destructor_v<T>)),
317 "Objects must inherit from T and be either virtually or trivially "
318 "destructible");
319 // Get the index since try_reserve() invalidates iterators.
320 const auto index = std::distance(vector_.cbegin(), pos.it_);
321
322 if (!vector_.try_reserve(vector_.size() + 1)) {
323 return std::nullopt;
324 }
325
326 if (T* ptr = vector_.get_allocator().template New<U>(
327 std::forward<Args>(args)...);
328 ptr != nullptr) {
329 // Skip has_value() check; try_insert() will succeed due to try_reserve().
330 return iterator(*vector_.try_insert(vector_.begin() + index, ptr));
331 }
332 return std::nullopt;
333 }
334
335 iterator insert(const_iterator pos, const T& value) {
336 return emplace(pos, value);
337 }
338 iterator insert(const_iterator pos, T&& value) {
339 return emplace(pos, std::move(value));
340 }
341
342 [[nodiscard]] std::optional<iterator> try_insert(const_iterator pos,
343 const T& value) {
344 return try_emplace(pos, value);
345 }
346 [[nodiscard]] std::optional<iterator> try_insert(const_iterator pos,
347 T&& value) {
348 return try_emplace(pos, std::move(value));
349 }
350
351 iterator erase(const_iterator pos) { return erase(pos, pos + 1); }
352
353 iterator erase(const_iterator first, const_iterator last) {
354 // DynamicVector::erase moves elements to fill the gap, so delete first.
355 for (auto it = first; it != last; ++it) {
356 Delete(const_cast<T*>(it.operator->()));
357 }
358 return iterator(vector_.erase(first.it_, last.it_));
359 }
360
361 void clear() {
362 for (T* ptr : vector_) {
363 Delete(ptr);
364 }
365 vector_.clear();
366 }
367
368 private:
369 void Delete(T* ptr) { vector_.get_allocator().Delete(ptr); }
370
371 DynamicVector<T*, SizeType> vector_;
372};
373
375
376} // namespace pw
Definition: allocator.h:43
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
std::optional< iterator > try_emplace(const_iterator pos, Args &&... args)
Definition: dynamic_ptr_vector.h:311
bool try_push_back(T &&value)
Attempts to append a new element by moving value.
Definition: dynamic_ptr_vector.h:244
void emplace_back(Args &&... args)
Definition: dynamic_ptr_vector.h:272
void push_back(const T &value)
Appends a new element by copying value.
Definition: dynamic_ptr_vector.h:233
bool try_emplace_back(Args &&... args)
Definition: dynamic_ptr_vector.h:283
void reserve_ptr_exact(size_type new_capacity)
Definition: dynamic_ptr_vector.h:194
iterator emplace(const_iterator pos, Args &&... args)
Definition: dynamic_ptr_vector.h:297
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
pw::UniquePtr< T > take(const_iterator pos)
Removes the element at pos and returns it as a UniquePtr.
Definition: dynamic_ptr_vector.h:255
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