Skip to content

Commit

Permalink
Adds retain/iter/iter_mut/values/values_mut for HandlePool and `Obj…
Browse files Browse the repository at this point in the history
…ectPool`.
  • Loading branch information
shawnscode committed Oct 8, 2018
1 parent 80c434d commit 9c28844
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 99 deletions.
2 changes: 1 addition & 1 deletion src/res/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ impl<H: HandleLike + 'static, R: Register<Handle = H> + Clone + 'static> Registr
/// Returns true if the `Registry` contains a resource associated with `handle`.
#[inline]
pub fn contains(&self, handle: H) -> bool {
self.payload.read().unwrap().items.is_alive(handle)
self.payload.read().unwrap().items.contains(handle)
}

/// Gets the registery value if available.
Expand Down
40 changes: 23 additions & 17 deletions src/utils/handle_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,16 @@ impl<T: HandleLike> HandlePool<T> {

/// Returns true if this `Handle` was created by `HandlePool`, and has not been
/// freed yet.
pub fn is_alive(&self, handle: T) -> bool {
pub fn contains(&self, handle: T) -> bool {
let index = handle.index() as usize;
self.is_alive_at(index) && (self.versions[index] == handle.version())
}

#[inline]
fn is_alive_at(&self, index: usize) -> bool {
(index < self.versions.len()) && ((self.versions[index] & 0x1) == 1)
(index < self.versions.len())
&& ((self.versions[index] & 0x1) == 1)
&& (self.versions[index] == handle.version())
}

/// Recycles the `Handle` index, and mark its version as dead.
pub fn free(&mut self, handle: T) -> bool {
if !self.is_alive(handle) {
if !self.contains(handle) {
false
} else {
self.versions[handle.index() as usize] += 1;
Expand All @@ -91,14 +88,23 @@ impl<T: HandleLike> HandlePool<T> {
}
}

/// Recycles the `Handle` index, and mark its version as dead.
pub fn free_at(&mut self, index: usize) -> Option<T> {
if !self.is_alive_at(index) {
None
} else {
self.versions[index] += 1;
self.frees.push(InverseHandleIndex(index as HandleIndex));
Some(T::new(index as HandleIndex, self.versions[index] - 1))
/// Retains only the elements specified by the predicate.
///
/// In other words, remove all elements e such that predicate(&T) returns false.
pub fn retain<P>(&mut self, mut predicate: P)
where
P: FnMut(T) -> bool,
{
unsafe {
for i in 0..self.versions.len() {
let v = *self.versions.get_unchecked(i);
if v & 0x1 == 1 {
if !predicate(T::new(i as u32, v)) {
self.versions[i] += 1;
self.frees.push(InverseHandleIndex(i as u32));
}
}
}
}
}

Expand All @@ -121,7 +127,7 @@ impl<T: HandleLike> HandlePool<T> {
self.len() == 0
}

/// Returns an iterator over the `HandlePool`.
/// An iterator visiting all the handles.
#[inline]
pub fn iter(&self) -> Iter<T> {
Iter::new(self)
Expand Down
148 changes: 73 additions & 75 deletions src/utils/object_pool.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use super::handle::HandleLike;
use super::handle_pool::{HandlePool, Iter};
use super::handle_pool::HandlePool;

/// A named object collections. Every time u create or free a handle, a
/// attached instance `T` will be created/ freed.
#[derive(Default)]
pub struct ObjectPool<H: HandleLike, T: Sized> {
handles: HandlePool<H>,
entries: Vec<Option<T>>,
entries: Vec<T>,
}

impl<H: HandleLike, T: Sized> ObjectPool<H, T> {
Expand All @@ -31,9 +31,9 @@ impl<H: HandleLike, T: Sized> ObjectPool<H, T> {
let handle = self.handles.create();

if handle.index() >= self.entries.len() as u32 {
self.entries.push(Some(value));
self.entries.push(value);
} else {
self.entries[handle.index() as usize] = Some(value);
self.entries[handle.index() as usize] = value;
}

handle
Expand All @@ -42,8 +42,8 @@ impl<H: HandleLike, T: Sized> ObjectPool<H, T> {
/// Returns mutable reference to internal value with name `Handle`.
#[inline]
pub fn get_mut(&mut self, handle: H) -> Option<&mut T> {
if self.handles.is_alive(handle) {
self.entries[handle.index() as usize].as_mut()
if self.handles.contains(handle) {
unsafe { Some(self.entries.get_unchecked_mut(handle.index() as usize)) }
} else {
None
}
Expand All @@ -52,8 +52,8 @@ impl<H: HandleLike, T: Sized> ObjectPool<H, T> {
/// Returns immutable reference to internal value with name `Handle`.
#[inline]
pub fn get(&self, handle: H) -> Option<&T> {
if self.handles.is_alive(handle) {
self.entries[handle.index() as usize].as_ref()
if self.handles.contains(handle) {
unsafe { Some(self.entries.get_unchecked(handle.index() as usize)) }
} else {
None
}
Expand All @@ -62,33 +62,42 @@ impl<H: HandleLike, T: Sized> ObjectPool<H, T> {
/// Returns true if this `Handle` was created by `ObjectPool`, and has not been
/// freed yet.
#[inline]
pub fn is_alive(&self, handle: H) -> bool {
self.handles.is_alive(handle)
pub fn contains(&self, handle: H) -> bool {
self.handles.contains(handle)
}

/// Recycles the value with name `Handle`.
#[inline]
pub fn free(&mut self, handle: H) -> Option<T> {
if self.handles.free(handle) {
let mut v = None;
::std::mem::swap(&mut v, &mut self.entries[handle.index() as usize]);
v
unsafe {
let mut v = ::std::mem::uninitialized();
::std::mem::swap(&mut v, &mut self.entries[handle.index() as usize]);
Some(v)
}
} else {
None
}
}

/// Remove all objects matching with `predicate` from pool incrementally.
pub fn free_if<P>(&mut self, predicate: P) -> FreeIter<H, T, P>
/// Retains only the elements specified by the predicate.
///
/// In other words, remove all objects such that f(k, &mut v) returns false.
pub fn retain<P>(&mut self, mut predicate: P)
where
P: FnMut(&T) -> bool,
P: FnMut(H, &mut T) -> bool,
{
FreeIter {
index: 0,
entries: &mut self.entries[..],
handles: &mut self.handles,
predicate: predicate,
}
let entries = &mut self.entries;
self.handles.retain(|handle| unsafe {
let mut v = entries.get_unchecked_mut(handle.index() as usize);
if predicate(handle, v) {
true
} else {
let mut w = ::std::mem::uninitialized();
::std::mem::swap(&mut v, &mut w);
false
}
});
}

/// Returns the total number of alive handle in this `ObjectPool`.
Expand All @@ -103,68 +112,57 @@ impl<H: HandleLike, T: Sized> ObjectPool<H, T> {
self.len() == 0
}

/// Returns an iterator over the `ObjectPool`.
/// an iterator visiting all key-value pairs in order. the iterator element type is (h, &t).
#[inline]
pub fn iter<'a>(&'a self) -> impl Iterator<Item = (H, &T)> + 'a {
self.handles
.iter()
.map(move |v| unsafe { (v, self.entries.get_unchecked(v.index() as usize)) })
}

/// an iterator visiting all key-value pairs in order. the iterator element type is (h, &mut t).
#[inline]
pub fn iter(&self) -> Iter<H> {
pub fn iter_mut<'a>(&'a mut self) -> impl Iterator<Item = (H, &'a mut T)> {
let entries = &mut self.entries;
self.handles.iter().map(move |v| unsafe {
let w = entries.get_unchecked_mut(v.index() as usize);
(v, &mut *(w as *mut T))
})
}

/// An iterator visiting all keys in order. The iterator element type is H.
#[inline]
pub fn keys<'a>(&'a self) -> impl Iterator<Item = H> + 'a {
self.handles.iter()
}
}

pub struct FreeIter<'a, H: 'a + HandleLike, T: 'a, P>
where
P: FnMut(&T) -> bool,
{
index: usize,
entries: &'a mut [Option<T>],
handles: &'a mut HandlePool<H>,
predicate: P,
}
/// An iterator visiting all entries in order. The iterator element type is &T.
#[inline]
pub fn values<'a>(&'a self) -> impl Iterator<Item = &T> + 'a {
self.handles
.iter()
.map(move |v| unsafe { self.entries.get_unchecked(v.index() as usize) })
}

impl<'a, H: 'a + HandleLike, T: 'a, P> Iterator for FreeIter<'a, H, T, P>
where
P: FnMut(&T) -> bool,
{
type Item = H;
/// An iterator visiting all entries in order. The iterator element type is &mut T.
#[inline]
pub fn values_mut<'a>(&'a mut self) -> impl Iterator<Item = &mut T> + 'a {
let entries = &mut self.entries;
self.handles.iter().map(move |v| unsafe {
let w = entries.get_unchecked_mut(v.index() as usize);
&mut *(w as *mut T)
})
}
}

fn next(&mut self) -> Option<Self::Item> {
impl<H: HandleLike, T: Sized> Drop for ObjectPool<H, T> {
fn drop(&mut self) {
unsafe {
for i in self.index..self.entries.len() {
let v = self.entries.get_unchecked_mut(i);

let free = if let Some(ref payload) = *v {
(self.predicate)(payload)
} else {
false
};

if free {
let handle = self.handles.free_at(i).unwrap();
*v = None;
return Some(handle);
}
for v in &self.handles {
::std::ptr::drop_in_place(&mut self.entries[v.index() as usize]);
}

None
self.entries.set_len(0);
}
}
}

#[cfg(test)]
mod test {
use super::super::Handle;
use super::*;

#[test]
fn basic() {
let mut set = ObjectPool::<Handle, i32>::new();

let e1 = set.create(3);
assert_eq!(set.get(e1), Some(&3));
assert_eq!(set.len(), 1);
assert_eq!(set.free(e1), Some(3));
assert_eq!(set.len(), 0);
assert_eq!(set.get(e1), None);
assert_eq!(set.free(e1), None);
assert_eq!(set.len(), 0);
}
}
11 changes: 11 additions & 0 deletions src/video/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,20 +113,27 @@
//!
//! ```rust
//! use crayon::video::prelude::*;
//! println!("0000");
//! let video = VideoSystem::headless(None).shared();
//!
//! println!("1111");
//!
//! // Declares the uniform variable layouts.
//! let mut uniforms = UniformVariableLayout::build()
//! .with("u_ModelViewMatrix", UniformVariableType::Matrix4f)
//! .with("u_MVPMatrix", UniformVariableType::Matrix4f)
//! .finish();
//!
//! println!("2222");
//!
//! // Declares the attributes.
//! let attributes = AttributeLayout::build()
//! .with(Attribute::Position, 3)
//! .with(Attribute::Normal, 3)
//! .finish();
//!
//! println!("333");
//!
//! let mut params = ShaderParams::default();
//! params.attributes = attributes;
//! params.uniforms = uniforms;
Expand All @@ -135,12 +142,16 @@
//! let vs = "..".into();
//! let fs = "..".into();
//!
//! println!("4444");
//! // Create a shader with initial shaders and render state. It encapusulates all the
//! // informations we need to configurate graphics pipeline before real drawing.
//! let shader = video.create_shader(params, vs, fs).unwrap();
//!
//! println!("45555");
//!
//! // Deletes shader object.
//! video.delete_shader(shader);
//! println!("666");
//! ```
//!
//! ### Texture Object
Expand Down
26 changes: 20 additions & 6 deletions tests/handle_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,41 @@ fn handle_set() {
// Spawn entities.
let e1 = set.create();
assert!(e1.is_valid());
assert!(set.is_alive(e1));
assert!(set.contains(e1));
assert_eq!(set.len(), 1);

let mut e2 = e1;
assert!(set.is_alive(e2));
assert!(set.contains(e2));
assert_eq!(set.len(), 1);

// Invalidate entities.
e2.invalidate();
assert!(!e2.is_valid());
assert!(!set.is_alive(e2));
assert!(set.is_alive(e1));
assert!(!set.contains(e2));
assert!(set.contains(e1));

// Free entities.
let e2 = e1;
set.free(e2);
assert!(!set.is_alive(e2));
assert!(!set.is_alive(e1));
assert!(!set.contains(e2));
assert!(!set.contains(e1));
assert_eq!(set.len(), 0);
}

#[test]
fn retain() {
let mut set: HandlePool<Handle> = HandlePool::new();
for _ in 0..10 {
set.create();
}

set.retain(|e| e.index() % 2 == 0);

for v in &set {
assert!(v.index() % 2 == 0);
}
}

#[test]
fn index_reuse() {
let mut set: HandlePool<Handle> = HandlePool::new();
Expand Down
Loading

0 comments on commit 9c28844

Please sign in to comment.