Skip to content

Commit 9c2d800

Browse files
committed
Switch VecStorage to Vec<MaybeUninit<T>>
1 parent e4e2983 commit 9c2d800

File tree

6 files changed

+71
-112
lines changed

6 files changed

+71
-112
lines changed

.travis.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ language: rust
22

33
rust:
44
- nightly
5-
- 1.34.0
5+
- 1.36.0
66
- stable
77

88
cache:
@@ -22,7 +22,7 @@ script:
2222
cargo build --all-features --verbose;
2323
cargo test --all-features --verbose --no-run;
2424
cargo bench --verbose --no-run --all-features;
25-
elif [ "$TRAVIS_RUST_VERSION" == "1.34.0" ]; then
25+
elif [ "$TRAVIS_RUST_VERSION" == "1.36.0" ]; then
2626
cargo check --tests --no-default-features;
2727
cargo check --tests --no-default-features --features "parallel";
2828
cargo check --tests --no-default-features --features "serde";

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Unlike most other ECS libraries out there, it provides
3535
other and you can use barriers to force several stages in system execution
3636
* high performance for real-world applications
3737

38-
Minimum Rust version: 1.34
38+
Minimum Rust version: 1.36
3939

4040
## [Link to the book][book]
4141

docs/tutorials/src/05_storages.md

+19-19
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ to the corresponding heading.
5050

5151
Certain storages provide access to component slices:
5252

53-
|Storage Type | Safety | Density | Indices |
54-
|:----------------------:|---------|---------|---------------|
55-
| [`DenseVecStorage`] | Safe | Dense | Arbitrary |
56-
| [`VecStorage`] | Unsafe | Sparse | Entity `id()` |
57-
| [`DefaultVecStorage`] | Safe | Sparse | Entity `id()` |
53+
|Storage Type | Slice type | Density | Indices |
54+
|:----------------------:|---------------------|---------|---------------|
55+
| [`DenseVecStorage`] | `&[T]` | Dense | Arbitrary |
56+
| [`VecStorage`] | `&[MaybeUninit<T>]` | Sparse | Entity `id()` |
57+
| [`DefaultVecStorage`] | `&[T]` | Sparse | Entity `id()` |
5858

5959
This is intended as an advanced technique. Component slices provide
6060
maximally efficient reads and writes, but they are incompatible with
@@ -73,10 +73,10 @@ one which provides a mapping from the entity id to the index for the data vec
7373
(it's a redirection table). This is useful when your component is bigger
7474
than a `usize` because it consumes less RAM.
7575

76-
`DenseVecStorage` provides `as_slice()` and `as_mut_slice()` accessors to
77-
directly access component data. The indices in this slice do not correspond
78-
to entity IDs, nor do they correspond to indices in any other storage, nor
79-
do they correspond to indices in this storage at a different point in time.
76+
`DefaultVecStorage<T>` provides `as_slice()` and `as_mut_slice()` accessors
77+
which return `&[T]`. The indices in this slice do not correspond to entity
78+
IDs, nor do they correspond to indices in any other storage, nor do they
79+
correspond to indices in this storage at a different point in time.
8080

8181
## `HashMapStorage`
8282

@@ -103,11 +103,10 @@ Therefore it would be a waste of memory to use this storage for
103103
rare components, but it's best suited for commonly used components
104104
(like transform values).
105105

106-
`VecStorage` provides unsafe `as_slice()` and `as_mut_slice()` accessors.
107-
These functions are `unsafe` because the slices contain uninitialized and
108-
dropped values. (Consult the `Storage::mask()` to determine which indices
109-
are populated.) Slice indices cannot be converted to `Entity` values
110-
because they lack a generation counter, but they do correspond to
106+
`VecStorage<T>` provides `as_slice()` and `as_mut_slice()` accessors which
107+
return `&[MaybeUninit<T>]`. Consult the `Storage::mask()` to determine
108+
which indices are populated. Slice indices cannot be converted to `Entity`
109+
values because they lack a generation counter, but they do correspond to
111110
`Entity::id()`s, so indices can be used to collate between multiple
112111
`VecStorage`s.
113112

@@ -118,8 +117,9 @@ uninitialized, it fills them with the component's default value. This
118117
requires the component to `impl Default`, and it results in more memory
119118
writes than `VecStorage`.
120119

121-
`DefaultVecStorage` provides `as_slice()` and `as_mut_slice()` accessors to
122-
directly access component data. Slice usage is equivalent to `VecStorage`,
123-
except that every value is initialized so the resulting slice can be safely
124-
used without checking the mask. `DefaultVecStorage` indices all correspond
125-
with each other and with `VecStorage` indices.
120+
`DefaultVecStorage` provides `as_slice()` and `as_mut_slice()` accessors
121+
which return `&[T]`. `Storage::mask()` can be used to determine which
122+
indices are in active use, but all indices are fully initialized, so the
123+
`mask()` is not necessary for safety. `DefaultVecStorage` indices all
124+
correspond with each other, with `VecStorage` indices, and with
125+
`Entity::id()`s.

src/storage/mod.rs

+5-43
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub use self::{
1313
track::{ComponentEvent, Tracked},
1414
};
1515

16-
use self::storages::{SafeSliceAccess, UnsafeSliceAccess};
16+
use self::storages::SliceAccess;
1717

1818
use std::{
1919
self,
@@ -265,13 +265,13 @@ impl<'e, T, D> Storage<'e, T, D>
265265
where
266266
T: Component,
267267
D: Deref<Target = MaskedStorage<T>>,
268-
T::Storage: SafeSliceAccess<T>
268+
T::Storage: SliceAccess<T>
269269
{
270270
/// Returns the component data as a slice.
271271
///
272272
/// The indices of this slice may not correspond to anything in particular.
273273
/// Check the underlying storage documentation for details.
274-
pub fn as_slice(&self) -> &[T] {
274+
pub fn as_slice(&self) -> &[<T::Storage as SliceAccess<T>>::Element] {
275275
self.data.inner.as_slice()
276276
}
277277
}
@@ -280,55 +280,17 @@ impl<'e, T, D> Storage<'e, T, D>
280280
where
281281
T: Component,
282282
D: DerefMut<Target = MaskedStorage<T>>,
283-
T::Storage: SafeSliceAccess<T>
283+
T::Storage: SliceAccess<T>
284284
{
285285
/// Returns the component data as a slice.
286286
///
287287
/// The indices of this slice may not correspond to anything in particular.
288288
/// Check the underlying storage documentation for details.
289-
pub fn as_mut_slice(&mut self) -> &mut [T] {
289+
pub fn as_mut_slice(&mut self) -> &mut [<T::Storage as SliceAccess<T>>::Element] {
290290
self.data.inner.as_mut_slice()
291291
}
292292
}
293293

294-
impl<'e, T, D> Storage<'e, T, D>
295-
where
296-
T: Component,
297-
D: Deref<Target = MaskedStorage<T>>,
298-
T::Storage: UnsafeSliceAccess<T>
299-
{
300-
/// Returns the component data as a slice.
301-
///
302-
/// The indices of this slice may not correspond to anything in particular.
303-
/// Check the underlying storage documentation for details.
304-
///
305-
/// # Safety
306-
///
307-
/// This slice contains uninitialized or dropped data.
308-
pub unsafe fn unsafe_slice(&self) -> &[T] {
309-
self.data.inner.unsafe_slice()
310-
}
311-
}
312-
313-
impl<'e, T, D> Storage<'e, T, D>
314-
where
315-
T: Component,
316-
D: DerefMut<Target = MaskedStorage<T>>,
317-
T::Storage: UnsafeSliceAccess<T>
318-
{
319-
/// Returns the component data as a slice.
320-
///
321-
/// The indices of this slice may not correspond to anything in particular.
322-
/// Check the underlying storage documentation for details.
323-
///
324-
/// # Safety
325-
///
326-
/// This slice contains uninitialized or dropped data.
327-
pub unsafe fn unsafe_mut_slice(&mut self) -> &mut [T] {
328-
self.data.inner.unsafe_mut_slice()
329-
}
330-
}
331-
332294
impl<'e, T, D> Storage<'e, T, D>
333295
where
334296
T: Component,

src/storage/storages.rs

+33-38
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Different types of storages you can use for your components.
22
33
use std::collections::BTreeMap;
4+
use std::mem::MaybeUninit;
45

56
use derivative::Derivative;
67
use hashbrown::HashMap;
@@ -11,14 +12,16 @@ use crate::{
1112
world::Index,
1213
};
1314

14-
pub trait SafeSliceAccess<T> {
15-
fn as_slice(&self) -> &[T];
16-
fn as_mut_slice(&mut self) -> &mut [T];
17-
}
18-
19-
pub trait UnsafeSliceAccess<T> {
20-
unsafe fn unsafe_slice(&self) -> &[T];
21-
unsafe fn unsafe_mut_slice(&mut self) -> &mut [T];
15+
/// Some storages can provide slices to access the underlying data.
16+
///
17+
/// The underlying data may be of type `T`, or it may be of a type
18+
/// which wraps `T`. The associated type `Element` identifies what
19+
/// the slices will contain.
20+
pub trait SliceAccess<T> {
21+
type Element;
22+
23+
fn as_slice(&self) -> &[Self::Element];
24+
fn as_mut_slice(&mut self) -> &mut [Self::Element];
2225
}
2326

2427
/// BTreeMap-based storage.
@@ -107,13 +110,15 @@ pub struct DenseVecStorage<T> {
107110
data_id: Vec<Index>,
108111
}
109112

110-
impl<T> SafeSliceAccess<T> for DenseVecStorage<T> {
113+
impl<T> SliceAccess<T> for DenseVecStorage<T> {
114+
type Element = T;
115+
111116
/// Returns a slice of all the components in this storage.
112117
///
113118
/// Indices inside the slice do not correspond to anything in particular, and
114119
/// especially do not correspond with entity IDs.
115120
#[inline]
116-
fn as_slice(&self) -> &[T] {
121+
fn as_slice(&self) -> &[Self::Element] {
117122
self.data.as_slice()
118123
}
119124

@@ -122,7 +127,7 @@ impl<T> SafeSliceAccess<T> for DenseVecStorage<T> {
122127
/// Indices inside the slice do not correspond to anything in particular, and
123128
/// especially do not correspond with entity IDs.
124129
#[inline]
125-
fn as_mut_slice(&mut self) -> &mut [T] {
130+
fn as_mut_slice(&mut self) -> &mut [Self::Element] {
126131
self.data.as_mut_slice()
127132
}
128133
}
@@ -216,34 +221,24 @@ unsafe impl<T> DistinctStorage for NullStorage<T> {}
216221
/// Vector storage. Uses a simple `Vec`. Supposed to have maximum
217222
/// performance for the components mostly present in entities.
218223
///
219-
/// `unsafe_slice()` and `unsafe_mut_slice()` indices correspond to
224+
/// `as_slice()` and `as_mut_slice()` indices correspond to
220225
/// entity IDs. These can be compared to other `VecStorage`s, to
221226
/// other `DefaultVecStorage`s, and to `Entity::id()`s for live
222227
/// entities.
223228
#[derive(Derivative)]
224229
#[derivative(Default(bound = ""))]
225-
pub struct VecStorage<T>(Vec<T>);
230+
pub struct VecStorage<T>(Vec<MaybeUninit<T>>);
231+
232+
impl<T> SliceAccess<T> for VecStorage<T> {
233+
type Element = MaybeUninit<T>;
226234

227-
impl<T> UnsafeSliceAccess<T> for VecStorage<T> {
228-
/// Returns a slice of all the components in this storage.
229-
///
230-
/// # Safety
231-
///
232-
/// This slice contains uninitialized and dropped values. If this is a
233-
/// problem, consider using `DefaultVecStorage` or `DenseVecStorage` instead.
234235
#[inline]
235-
unsafe fn unsafe_slice(&self) -> &[T] {
236+
fn as_slice(&self) -> &[Self::Element] {
236237
self.0.as_slice()
237238
}
238239

239-
/// Returns a mutable slice of all the components in this storage.
240-
///
241-
/// # Safety
242-
///
243-
/// This slice contains uninitialized and dropped values. If this is a
244-
/// problem, consider using `DefaultVecStorage` or `DenseVecStorage` instead.
245240
#[inline]
246-
unsafe fn unsafe_mut_slice(&mut self) -> &mut [T] {
241+
fn as_mut_slice(&mut self) -> &mut [Self::Element] {
247242
self.0.as_mut_slice()
248243
}
249244
}
@@ -256,23 +251,22 @@ impl<T> UnprotectedStorage<T> for VecStorage<T> {
256251
use std::ptr;
257252
for (i, v) in self.0.iter_mut().enumerate() {
258253
if has.contains(i as u32) {
259-
ptr::drop_in_place(v);
254+
// drop in place
255+
ptr::drop_in_place(&mut *v.as_mut_ptr());
260256
}
261257
}
262258
self.0.set_len(0);
263259
}
264260

265261
unsafe fn get(&self, id: Index) -> &T {
266-
self.0.get_unchecked(id as usize)
262+
&*self.0.get_unchecked(id as usize).as_ptr()
267263
}
268264

269265
unsafe fn get_mut(&mut self, id: Index) -> &mut T {
270-
self.0.get_unchecked_mut(id as usize)
266+
&mut *self.0.get_unchecked_mut(id as usize).as_mut_ptr()
271267
}
272268

273269
unsafe fn insert(&mut self, id: Index, v: T) {
274-
use std::ptr;
275-
276270
let id = id as usize;
277271
if self.0.len() <= id {
278272
let delta = id + 1 - self.0.len();
@@ -281,12 +275,11 @@ impl<T> UnprotectedStorage<T> for VecStorage<T> {
281275
}
282276
// Write the value without reading or dropping
283277
// the (currently uninitialized) memory.
284-
ptr::write(self.0.get_unchecked_mut(id), v);
278+
*self.0.get_unchecked_mut(id as usize) = MaybeUninit::new(v);
285279
}
286280

287281
unsafe fn remove(&mut self, id: Index) -> T {
288282
use std::ptr;
289-
290283
ptr::read(self.get(id))
291284
}
292285
}
@@ -347,16 +340,18 @@ impl<T> UnprotectedStorage<T> for DefaultVecStorage<T> where T: Default {
347340

348341
unsafe impl<T> DistinctStorage for DefaultVecStorage<T> {}
349342

350-
impl<T> SafeSliceAccess<T> for DefaultVecStorage<T> {
343+
impl<T> SliceAccess<T> for DefaultVecStorage<T> {
344+
type Element = T;
345+
351346
/// Returns a slice of all the components in this storage.
352347
#[inline]
353-
fn as_slice(&self) -> &[T] {
348+
fn as_slice(&self) -> &[Self::Element] {
354349
self.0.as_slice()
355350
}
356351

357352
/// Returns a mutable slice of all the components in this storage.
358353
#[inline]
359-
fn as_mut_slice(&mut self) -> &mut [T] {
354+
fn as_mut_slice(&mut self) -> &mut [Self::Element] {
360355
self.0.as_mut_slice()
361356
}
362357
}

0 commit comments

Comments
 (0)