@@ -64,10 +64,47 @@ class Vec {
64
64
65
65
public:
66
66
// sus::construct::Default trait.
67
- inline constexpr Vec () noexcept : Vec(kDefault ) {}
67
+ inline constexpr Vec () noexcept : Vec(nullptr , 0_usize, 0_usize ) {}
68
68
69
- static inline Vec with_capacity (usize cap) noexcept {
70
- return Vec (kWithCap , cap);
69
+ // / Creates a Vec<T> with at least the specified capacity.
70
+ // /
71
+ // / The vector will be able to hold at least `capacity` elements without
72
+ // / reallocating. This method is allowed to allocate for more elements than
73
+ // / capacity. If capacity is 0, the vector will not allocate.
74
+ // /
75
+ // / It is important to note that although the returned vector has the minimum
76
+ // / capacity specified, the vector will have a zero length.
77
+ // /
78
+ // / # Panics
79
+ // / Panics if the capacity exceeds `isize::MAX` bytes.
80
+ static inline Vec with_capacity (usize capacity) noexcept {
81
+ check (::sus::mem::size_of<T>() * capacity <= usize (size_t {PTRDIFF_MAX}));
82
+ auto v = Vec (nullptr , 0_usize, 0_usize);
83
+ // TODO: Consider rounding up to nearest 2^N for some N? A min capacity?
84
+ v.grow_to_exact (capacity);
85
+ return v;
86
+ }
87
+
88
+ // / Creates a Vec<T> directly from a pointer, a capacity, and a length.
89
+ // /
90
+ // / # Safety
91
+ // /
92
+ // / This is highly unsafe, due to the number of invariants that aren’t
93
+ // / checked:
94
+ // /
95
+ // / * `T` needs to have an alignment no more than what `ptr` was allocated
96
+ // / with.
97
+ // / * The size of `T` times the `capacity` (ie. the allocated size in bytes)
98
+ // / needs to be the same size the pointer was allocated with.
99
+ // / * `length` needs to be less than or equal to `capacity`.
100
+ // / * The first `length` values must be properly initialized values of type
101
+ // / `T`.
102
+ // / * The allocated size in bytes must be no larger than `isize::MAX`.
103
+ // / * If `ptr` is null, then `length` and `capacity` must be `0_usize`, and
104
+ // / vice versa.
105
+ static Vec from_raw_parts (::sus::marker::UnsafeFnMarker, T* ptr, usize length,
106
+ usize capacity) noexcept {
107
+ return Vec (ptr, length, capacity);
71
108
}
72
109
73
110
// / Constructs a vector by taking all the elements from the iterator.
@@ -88,17 +125,17 @@ class Vec {
88
125
}
89
126
90
127
Vec (Vec&& o) noexcept
91
- : storage_(::sus::mem::replace_ptr(mref(o.storage_), moved_from_value() )),
92
- len_ (::sus::mem::replace(mref(o.len_), 0_usize )),
93
- capacity_(::sus::mem::replace(mref(o.capacity_), 0_usize )) {
128
+ : storage_(::sus::mem::replace_ptr(mref(o.storage_), nullptr )),
129
+ len_ (::sus::mem::replace(mref(o.len_), kMovedFromLen )),
130
+ capacity_(::sus::mem::replace(mref(o.capacity_), kMovedFromCapacity )) {
94
131
check (!is_moved_from ());
95
132
}
96
133
Vec& operator =(Vec&& o) noexcept {
97
134
check (!o.is_moved_from ());
98
135
if (is_alloced ()) free_storage ();
99
- storage_ = ::sus::mem::replace_ptr (mref (o.storage_ ), moved_from_value () );
100
- len_ = ::sus::mem::replace (mref (o.len_ ), 0_usize );
101
- capacity_ = ::sus::mem::replace (mref (o.capacity_ ), 0_usize );
136
+ storage_ = ::sus::mem::replace_ptr (mref (o.storage_ ), nullptr );
137
+ len_ = ::sus::mem::replace (mref (o.len_ ), kMovedFromLen );
138
+ capacity_ = ::sus::mem::replace (mref (o.capacity_ ), kMovedFromCapacity );
102
139
return *this ;
103
140
}
104
141
@@ -145,6 +182,25 @@ class Vec {
145
182
}
146
183
}
147
184
185
+ // / Decomposes a `Vec<T>` into its raw components.
186
+ // /
187
+ // / Returns the raw pointer to the underlying data, the length of the vector
188
+ // / (in elements), and the allocated capacity of the data (in elements). These
189
+ // / are the same arguments in the same order as the arguments to
190
+ // / `from_raw_parts()`.
191
+ // /
192
+ // / After calling this function, the caller is responsible for the memory
193
+ // / previously managed by the `Vec`. The only way to do this is to convert the
194
+ // / raw pointer, length, and capacity back into a `Vec` with the
195
+ // / `from_raw_parts()` function, allowing the destructor to perform the
196
+ // / cleanup.
197
+ ::sus::Tuple<T*, usize, usize> into_raw_parts () && noexcept {
198
+ check (!is_moved_from ());
199
+ return sus::tuple (::sus::mem::replace_ptr (mref (storage_), nullptr ),
200
+ ::sus::mem::replace (mref(len_), kMovedFromLen),
201
+ ::sus::mem::replace(mref(capacity_), kMovedFromCapacity));
202
+ }
203
+
148
204
// / Clears the vector, removing all values.
149
205
// /
150
206
// / Note that this method has no effect on the allocated capacity of the
@@ -169,6 +225,7 @@ class Vec {
169
225
void reserve (usize additional) noexcept {
170
226
check (!is_moved_from ());
171
227
if (len_ + additional <= capacity_) return ; // Nothing to do.
228
+ // TODO: Consider rounding up to nearest 2^N for some N?
172
229
grow_to_exact (apply_growth_function (additional));
173
230
}
174
231
@@ -206,16 +263,16 @@ class Vec {
206
263
const auto bytes = ::sus::mem::size_of<T>() * cap;
207
264
check (bytes <= usize (size_t {PTRDIFF_MAX}));
208
265
if (!is_alloced ()) {
209
- storage_ = static_cast <char *>(malloc (bytes.primitive_value ));
266
+ storage_ = static_cast <T *>(malloc (bytes.primitive_value ));
210
267
} else {
211
268
if constexpr (::sus::mem::relocate_by_memcpy<T>) {
212
- storage_ = static_cast <char *>(realloc (storage_, bytes.primitive_value ));
269
+ storage_ = static_cast <T *>(realloc (storage_, bytes.primitive_value ));
213
270
} else {
214
271
auto * const new_storage =
215
- static_cast <char *>(malloc (bytes.primitive_value ));
272
+ static_cast <T *>(malloc (bytes.primitive_value ));
216
273
auto * old_t = reinterpret_cast <T*>(storage_);
217
274
auto * new_t = reinterpret_cast <T*>(new_storage);
218
- const size_t len = len_. primitive_value ;
275
+ const size_t len = size_t { len_} ;
219
276
for (auto i = size_t {0 }; i < len; ++i) {
220
277
new (new_t ) T (::sus::move (*old_t ));
221
278
old_t ->~T ();
@@ -280,7 +337,7 @@ class Vec {
280
337
{
281
338
check (!is_moved_from ());
282
339
reserve (1_usize);
283
- new (as_mut_ptr () + len_. primitive_value ) T (::sus::move (t));
340
+ new (as_mut_ptr () + size_t { len_} ) T (::sus::move (t));
284
341
len_ += 1_usize;
285
342
}
286
343
@@ -305,7 +362,7 @@ class Vec {
305
362
{
306
363
check (!is_moved_from ());
307
364
reserve (1_usize);
308
- new (as_mut_ptr () + len_. primitive_value ) T (::sus::forward<Us>(args)...);
365
+ new (as_mut_ptr () + size_t { len_} ) T (::sus::forward<Us>(args)...);
309
366
len_ += 1_usize;
310
367
}
311
368
@@ -461,19 +518,8 @@ class Vec {
461
518
}
462
519
463
520
private:
464
- enum Default { kDefault };
465
- inline constexpr Vec (Default)
466
- : storage_(nullptr ), len_(0_usize), capacity_(0_usize) {}
467
-
468
- enum WithCap { kWithCap };
469
- Vec (WithCap, usize cap)
470
- : storage_(cap > 0_usize ? static_cast <char *>(malloc(
471
- size_t {::sus::mem::size_of<T>() * cap}))
472
- : nullptr ),
473
- len_ (0_usize),
474
- capacity_ (cap) {
475
- check (::sus::mem::size_of<T>() * cap <= usize (size_t {PTRDIFF_MAX}));
476
- }
521
+ Vec (T* ptr, usize len, usize cap)
522
+ : storage_(ptr), len_(len), capacity_(cap) {}
477
523
478
524
constexpr usize apply_growth_function (usize additional) const noexcept {
479
525
usize goal = additional + len_;
@@ -489,7 +535,7 @@ class Vec {
489
535
490
536
inline void destroy_storage_objects () {
491
537
if constexpr (!std::is_trivially_destructible_v<T>) {
492
- const size_t len = len_. primitive_value ;
538
+ const size_t len = size_t { len_} ;
493
539
for (auto i = size_t {0 }; i < len; ++i)
494
540
reinterpret_cast <T*>(storage_)[i].~T ();
495
541
}
@@ -507,14 +553,13 @@ class Vec {
507
553
508
554
// Checks if Vec has been moved from.
509
555
constexpr inline bool is_moved_from () const noexcept {
510
- return storage_ == moved_from_value ();
511
- }
512
- // The value used in storage_ to indicate moved-from.
513
- constexpr static char * moved_from_value () noexcept {
514
- return static_cast <char *>(nullptr ) + alignof (T);
556
+ return len_ > capacity_;
515
557
}
516
558
517
- alignas (T*) char * storage_;
559
+ static constexpr usize kMovedFromLen = 1_usize;
560
+ static constexpr usize kMovedFromCapacity = 0_usize;
561
+
562
+ T* storage_;
518
563
usize len_;
519
564
usize capacity_;
520
565
0 commit comments