Make ListPool's alloc fill new memory with reserved values.
This makes it harder to misuse, as 0 could be confused for a valid value.
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
//! Small lists of entity references.
|
//! Small lists of entity references.
|
||||||
|
use crate::packed_option::ReservedValue;
|
||||||
use crate::EntityRef;
|
use crate::EntityRef;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
@@ -59,13 +60,13 @@ use std::vec::Vec;
|
|||||||
/// The index stored in an `EntityList` points to part 2, the list elements. The value 0 is
|
/// The index stored in an `EntityList` points to part 2, the list elements. The value 0 is
|
||||||
/// reserved for the empty list which isn't allocated in the vector.
|
/// reserved for the empty list which isn't allocated in the vector.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct EntityList<T: EntityRef> {
|
pub struct EntityList<T: EntityRef + ReservedValue> {
|
||||||
index: u32,
|
index: u32,
|
||||||
unused: PhantomData<T>,
|
unused: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an empty list.
|
/// Create an empty list.
|
||||||
impl<T: EntityRef> Default for EntityList<T> {
|
impl<T: EntityRef + ReservedValue> Default for EntityList<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
index: 0,
|
index: 0,
|
||||||
@@ -76,7 +77,7 @@ impl<T: EntityRef> Default for EntityList<T> {
|
|||||||
|
|
||||||
/// A memory pool for storing lists of `T`.
|
/// A memory pool for storing lists of `T`.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ListPool<T: EntityRef> {
|
pub struct ListPool<T: EntityRef + ReservedValue> {
|
||||||
// The main array containing the lists.
|
// The main array containing the lists.
|
||||||
data: Vec<T>,
|
data: Vec<T>,
|
||||||
|
|
||||||
@@ -105,7 +106,7 @@ fn is_sclass_min_length(len: usize) -> bool {
|
|||||||
len > 3 && len.is_power_of_two()
|
len > 3 && len.is_power_of_two()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: EntityRef> ListPool<T> {
|
impl<T: EntityRef + ReservedValue> ListPool<T> {
|
||||||
/// Create a new list pool.
|
/// Create a new list pool.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -140,7 +141,8 @@ impl<T: EntityRef> ListPool<T> {
|
|||||||
/// Allocate a storage block with a size given by `sclass`.
|
/// Allocate a storage block with a size given by `sclass`.
|
||||||
///
|
///
|
||||||
/// Returns the first index of an available segment of `self.data` containing
|
/// Returns the first index of an available segment of `self.data` containing
|
||||||
/// `sclass_size(sclass)` elements.
|
/// `sclass_size(sclass)` elements. The allocated memory is filled with reserved
|
||||||
|
/// values.
|
||||||
fn alloc(&mut self, sclass: SizeClass) -> usize {
|
fn alloc(&mut self, sclass: SizeClass) -> usize {
|
||||||
// First try the free list for this size class.
|
// First try the free list for this size class.
|
||||||
match self.free.get(sclass as usize).cloned() {
|
match self.free.get(sclass as usize).cloned() {
|
||||||
@@ -155,9 +157,8 @@ impl<T: EntityRef> ListPool<T> {
|
|||||||
_ => {
|
_ => {
|
||||||
// Nothing on the free list. Allocate more memory.
|
// Nothing on the free list. Allocate more memory.
|
||||||
let offset = self.data.len();
|
let offset = self.data.len();
|
||||||
// We don't want to mess around with uninitialized data.
|
self.data
|
||||||
// Just fill it up with nulls.
|
.resize(offset + sclass_size(sclass), T::reserved_value());
|
||||||
self.data.resize(offset + sclass_size(sclass), T::new(0));
|
|
||||||
offset
|
offset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,7 +220,7 @@ impl<T: EntityRef> ListPool<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: EntityRef> EntityList<T> {
|
impl<T: EntityRef + ReservedValue> EntityList<T> {
|
||||||
/// Create a new empty list.
|
/// Create a new empty list.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Default::default()
|
||||||
@@ -351,7 +352,7 @@ impl<T: EntityRef> EntityList<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Grow list by adding `count` uninitialized elements at the end.
|
/// Grow list by adding `count` reserved-value elements at the end.
|
||||||
///
|
///
|
||||||
/// Returns a mutable slice representing the whole list.
|
/// Returns a mutable slice representing the whole list.
|
||||||
fn grow<'a>(&'a mut self, count: usize, pool: &'a mut ListPool<T>) -> &'a mut [T] {
|
fn grow<'a>(&'a mut self, count: usize, pool: &'a mut ListPool<T>) -> &'a mut [T] {
|
||||||
@@ -483,6 +484,7 @@ impl<T: EntityRef> EntityList<T> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use super::{sclass_for_length, sclass_size};
|
use super::{sclass_for_length, sclass_size};
|
||||||
|
use crate::packed_option::ReservedValue;
|
||||||
use crate::EntityRef;
|
use crate::EntityRef;
|
||||||
|
|
||||||
/// An opaque reference to an instruction in a function.
|
/// An opaque reference to an instruction in a function.
|
||||||
|
|||||||
Reference in New Issue
Block a user