Skip to content

Commit

Permalink
Tidy up
Browse files Browse the repository at this point in the history
  • Loading branch information
mattkleiny committed Apr 10, 2024
1 parent 339cfe8 commit 0ed14f5
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 123 deletions.
237 changes: 115 additions & 122 deletions common/src/collections/arena.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::unsafe_mutable_alias;
use std::mem::replace;

// TODO: implement a free list and next_free option on the arena
use crate::unsafe_mutable_alias;

/// Represents a safe index into an [`Arena`].
///
Expand All @@ -21,103 +21,29 @@ pub trait ArenaIndex {
fn ordinal(&self) -> u32;
}

/// Creates a new, opaque arena index type.
///
/// The type is implicitly convertible to and from [`u64`], [`u32`], and
/// [`ArenaIndex`], and can be used as a key in the [`Arena`] structure.
#[macro_export]
macro_rules! impl_arena_index {
($name:ident) => {
$crate::impl_arena_index!($name, "");
};
($name:ident, $comment:literal) => {
#[doc = $comment]
#[repr(transparent)]
#[derive(Default, Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct $name(u64);

impl $name {
/// A sentinel value representing an empty index.
pub const NONE: Self = Self(0);
}

impl $crate::ArenaIndex for $name {
#[inline(always)]
fn from_parts(ordinal: u32, generation: u32) -> Self {
Self((ordinal as u64) | ((generation as u64) << 32))
}

#[inline(always)]
fn generation(&self) -> u32 {
(self.0 >> 32) as u32
}

#[inline(always)]
fn ordinal(&self) -> u32 {
self.0 as u32
}
}

impl From<u32> for $name {
#[inline]
fn from(value: u32) -> Self {
<Self as $crate::ArenaIndex>::from_parts(value, 0)
}
}

impl From<$name> for u32 {
#[inline(always)]
fn from(value: $name) -> Self {
value.0 as u32
}
}

impl From<u64> for $name {
#[inline(always)]
fn from(packed: u64) -> Self {
Self(packed)
}
}

impl From<$name> for u64 {
#[inline(always)]
fn from(value: $name) -> Self {
value.0
}
}

impl $crate::FromRandom for $name {
#[inline]
fn from_random(random: &mut $crate::Random) -> Self {
Self::from(random.next_u64())
}
}
};
}

/// A simple generational arena of elements of type [`T`] .
///
/// An arena exposes safe externalized indices in the form of [`ArenaIndex`]es
/// that can be passed around the application safely.
///
/// An arena is a contiguous block of memory that is used to store a collection
/// of elements. When an element is removed from the arena, the slot that it
/// occupied remains empty until the next insert.. This means that the order of
/// occupied remains empty until the next insert. This means that the order of
/// elements in the arena is not guaranteed to be the same as the order in which
/// they were inserted.
#[derive(Debug)]
pub struct Arena<K, V> {
entries: Vec<Option<ArenaEntry<V>>>,
entries: Vec<ArenaEntry<V>>,
current_generation: u32,
is_generation_dirty: bool,
_key: std::marker::PhantomData<K>,
}

/// A single entry in an `Arena`.
#[derive(Debug)]
struct ArenaEntry<V> {
value: V,
generation: u32,
enum ArenaEntry<T> {
Vacant,
Occupied { value: T, generation: u32 },
}

impl<K: ArenaIndex, V> Default for Arena<K, V> {
Expand Down Expand Up @@ -157,7 +83,7 @@ impl<K: ArenaIndex, V> Arena<K, V> {
let mut count = 0;

for entry in &self.entries {
if entry.is_some() {
if matches!(entry, ArenaEntry::Occupied { .. }) {
count += 1;
}
}
Expand All @@ -172,18 +98,16 @@ impl<K: ArenaIndex, V> Arena<K, V> {

/// Returns a reference to the item at the given index.
pub fn get(&self, key: K) -> Option<&V> {
let ordinal = key.ordinal();
let generation = key.generation();

// sanity check external index
let ordinal = key.ordinal();
if ordinal as usize >= self.entries.len() {
return None;
}

// if this entry exists and the generation matches
if let Some(Some(entry)) = self.entries.get(ordinal as usize) {
if entry.generation == generation {
return Some(&entry.value);
if let Some(ArenaEntry::Occupied { value, generation }) = self.entries.get(ordinal as usize) {
if *generation == key.generation() {
return Some(value);
}
}

Expand All @@ -192,56 +116,53 @@ impl<K: ArenaIndex, V> Arena<K, V> {

/// Returns a mutable reference to the item at the given index.
pub fn get_mut(&mut self, key: K) -> Option<&mut V> {
let ordinal = key.ordinal();
let generation = key.generation();

// sanity check external index
let ordinal = key.ordinal();
if ordinal as usize >= self.entries.len() {
return None;
}

// if this entry exists and the generation matches
if let Some(Some(entry)) = self.entries.get_mut(ordinal as usize) {
if entry.generation == generation {
return Some(&mut entry.value);
if let Some(ArenaEntry::Occupied { value, generation }) = self.entries.get_mut(ordinal as usize) {
if *generation == key.generation() {
return Some(value);
}
}

None
}

/// Inserts an entry to the arena and returns it's index.
/// Inserts an entry to the arena and returns its index.
pub fn insert(&mut self, value: V) -> K {
let key = self.allocate_key();

let ordinal = key.ordinal();
let generation = key.generation();

self.entries[ordinal as usize] = Some(ArenaEntry {
value,
generation: generation,
});
self.entries[ordinal as usize] = ArenaEntry::Occupied { value, generation };

key
}

/// Removes an item from the arena.
pub fn remove(&mut self, key: K) -> Option<V> {
let ordinal = key.ordinal();
let generation = key.generation();

// sanity check external index
let ordinal = key.ordinal();
if ordinal as usize >= self.entries.len() {
return None;
}

// if this is the relevant entry and the generation matches
if let Some(entry) = &self.entries[ordinal as usize] {
if generation == entry.generation {
let entry = self.entries[ordinal as usize].take().unwrap();
self.is_generation_dirty = true;
if let ArenaEntry::Occupied { generation, .. } = &self.entries[ordinal as usize] {
if *generation == key.generation() {
let dest = &mut self.entries[ordinal as usize];
let entry = replace(dest, ArenaEntry::Vacant);

if let ArenaEntry::Occupied { value, .. } = entry {
self.is_generation_dirty = true;

return Some(entry.value);
return Some(value);
}
}
}

Expand All @@ -266,10 +187,10 @@ impl<K: ArenaIndex, V> Arena<K, V> {

fn next(&mut self) -> Option<Self::Item> {
while let Some(entry) = self.arena.entries.get(self.index) {
if let Some(value) = entry {
if let ArenaEntry::Occupied { value, .. } = entry {
self.index += 1;

return Some(&value.value);
return Some(value);
}

self.index += 1;
Expand Down Expand Up @@ -299,12 +220,10 @@ impl<K: ArenaIndex, V> Arena<K, V> {

fn next(&mut self) -> Option<Self::Item> {
while let Some(entry) = self.arena.entries.get_mut(self.index) {
if let Some(value) = entry.as_mut() {
if let ArenaEntry::Occupied { value, .. } = entry {
self.index += 1;

let value = unsafe { unsafe_mutable_alias(value) }; // elide the lifetime

return Some(&mut value.value);
return Some(unsafe { unsafe_mutable_alias(value) });
}

self.index += 1;
Expand Down Expand Up @@ -334,12 +253,12 @@ impl<K: ArenaIndex, V> Arena<K, V> {

fn next(&mut self) -> Option<Self::Item> {
while let Some(entry) = self.arena.entries.get(self.index) {
if let Some(value) = entry {
let key = K::from_parts(self.index as u32, value.generation);
if let ArenaEntry::Occupied { value, generation } = entry {
let key = K::from_parts(self.index as u32, *generation);

self.index += 1;

return Some((key, &value.value));
return Some((key, &value));
}

self.index += 1;
Expand Down Expand Up @@ -369,13 +288,13 @@ impl<K: ArenaIndex, V> Arena<K, V> {

fn next(&mut self) -> Option<Self::Item> {
while let Some(entry) = self.arena.entries.get_mut(self.index) {
if let Some(value) = entry.as_mut() {
let key = K::from_parts(self.index as u32, value.generation);
if let ArenaEntry::Occupied { value, generation } = entry {
let key = K::from_parts(self.index as u32, *generation);
let value = unsafe { unsafe_mutable_alias(value) }; // elide the lifetime

self.index += 1;

return Some((key, &mut value.value));
return Some((key, value));
}

self.index += 1;
Expand Down Expand Up @@ -403,13 +322,13 @@ impl<K: ArenaIndex, V> Arena<K, V> {

// scan through existing entries and find an empty slot
for index in 0..self.entries.len() {
if self.entries[index].is_none() {
if matches!(self.entries[index], ArenaEntry::Vacant { .. }) {
return K::from_parts(index as u32, self.current_generation);
}
}

// otherwise allocate a new entry
self.entries.push(None);
// otherwise allocate a new empty entry
self.entries.push(ArenaEntry::Vacant);

K::from_parts((self.entries.len() - 1) as u32, self.current_generation)
}
Expand Down Expand Up @@ -448,6 +367,80 @@ impl<K: ArenaIndex, V> FromIterator<V> for Arena<K, V> {
}
}

/// Creates a new, opaque arena index type.
///
/// The type is implicitly convertible to and from [`u64`], [`u32`], and
/// [`ArenaIndex`], and can be used as a key in the [`Arena`] structure.
#[macro_export]
macro_rules! impl_arena_index {
($name:ident) => {
$crate::impl_arena_index!($name, "");
};
($name:ident, $comment:literal) => {
#[doc = $comment]
#[repr(transparent)]
#[derive(Default, Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct $name(u64);

impl $name {
/// A sentinel value representing an empty index.
pub const NONE: Self = Self(0);
}

impl $crate::ArenaIndex for $name {
#[inline(always)]
fn from_parts(ordinal: u32, generation: u32) -> Self {
Self((ordinal as u64) | ((generation as u64) << 32))
}

#[inline(always)]
fn generation(&self) -> u32 {
(self.0 >> 32) as u32
}

#[inline(always)]
fn ordinal(&self) -> u32 {
self.0 as u32
}
}

impl From<u32> for $name {
#[inline]
fn from(value: u32) -> Self {
<Self as $crate::ArenaIndex>::from_parts(value, 0)
}
}

impl From<$name> for u32 {
#[inline(always)]
fn from(value: $name) -> Self {
value.0 as u32
}
}

impl From<u64> for $name {
#[inline(always)]
fn from(packed: u64) -> Self {
Self(packed)
}
}

impl From<$name> for u64 {
#[inline(always)]
fn from(value: $name) -> Self {
value.0
}
}

impl $crate::FromRandom for $name {
#[inline]
fn from_random(random: &mut $crate::Random) -> Self {
Self::from(random.next_u64())
}
}
};
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
5 changes: 4 additions & 1 deletion samples/flappy-bird/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ fn main() {
let mut queue = RenderQueue::new();
let mut game = Game::new(&graphics);

material.set_uniform("u_projectionView", Mat4::IDENTITY);
material.set_uniform(
"u_projectionView",
Mat4::orthographic_rh_gl(0.0, 800.0, 0.0, 600.0, -1.0, 1.0),
);

game.initialize();

Expand Down

0 comments on commit 0ed14f5

Please sign in to comment.