Remove bitmap

This commit is contained in:
Stjepan Glavina 2016-11-14 20:26:49 +01:00
parent fcdbf80000
commit 821eac2764
2 changed files with 379 additions and 705 deletions

View File

@ -1,411 +0,0 @@
//! The internals of `VecArena`.
//!
//! `Bitmap` tracks occupied and vacant slots in `VecArena` and provides useful methods for e.g.
//! iterating over all occupied slots, or reserving additional slots.
use std::cmp;
use std::mem;
use std::ptr;
/// Returns the number of bits in one `usize` integer.
#[inline]
fn bits() -> usize {
mem::size_of::<usize>() * 8
}
/// Returns the number of `usize` integers required to store `len` bits.
#[inline]
fn blocks_for(len: usize) -> usize {
// Divide `len` by `bits()` and round up.
len / bits() + ((len % bits() > 0) as usize)
}
/// Given a valid `block` index and `offset` within it, returns the index of that slot as within
/// the whole bitmap.
#[inline]
fn slot_index(block: usize, offset: usize) -> usize {
block * bits() + offset
}
/// Given a slot `index` in the bitmap, returns it's block index and offset within the block.
#[inline]
fn block_and_offset(index: usize) -> (usize, usize) {
(index / bits(), index % bits())
}
/// Keeps track of occupied and vacant slots in `VecArena`.
///
/// It's implemented as an array of blocks, where every block tracks only a small contiguous chunk
/// of slots. More precisely: as many slots as there are bits in one `usize`.
///
/// All blocks which are not fully occupied, except the last one, are linked together to form a
/// doubly-linked list. This list allows finding a vacant slot to acquire in `O(1)` and releasing
/// an occupied slot in `O(1)`, assuming the bitmap doesn't grow to accommodate more slots.
///
/// A block consists of:
///
/// * a bit mask (one `usize`), in which zeros are for vacant slots and ones for occupied slots
/// * index of the successor block in the linked list
/// * index of the predecessor block in the linked list
///
/// The last block is tricky to handle because it might not have the same number of slots as other
/// blocks, so it gets special treatment in the implementation.
pub struct Bitmap {
/// Storage for the following sequences, in this order:
///
/// * bit masks
/// * indices to successor nodes
/// * indices to predecessor nodes
///
/// All three sequences are stored in this single contiguous array.
///
/// The most common and costly operation during the lifetime of a bitmap is testing
/// whether a slot is occupied. Storing bit masks close together improves cache
/// performance.
data: *mut usize,
/// Number of reserved slots.
len: usize,
/// Number of occupied slots.
occupied: usize,
/// Index of the first block in the linked list, or `!0` if the list is empty.
head: usize,
}
impl Bitmap {
/// Constructs a new `Bitmap` with zero slots.
#[inline]
pub fn new() -> Self {
let data = {
let mut vec = Vec::with_capacity(0);
let ptr = vec.as_mut_ptr();
mem::forget(vec);
ptr
};
Bitmap {
data: data,
len: 0,
occupied: 0,
head: !0,
}
}
/// Returns the number of reserved slots in the bitmap.
#[inline]
pub fn len(&self) -> usize {
self.len
}
/// Returns the number of occupied slots in the bitmap.
#[inline]
pub fn occupied(&self) -> usize {
self.occupied
}
/// Finds a vacant slot, marks as occupied, and returns its index.
///
/// # Panics
///
/// Panics if all slots are occupied.
pub fn acquire(&mut self) -> usize {
assert!(self.occupied < self.len, "no vacant slots to acquire, len = {}", self.len);
let block = if self.head == !0 {
// The list is empty, so try the last block.
blocks_for(self.len) - 1
} else {
// The list has a head. Take a vacant slot from the head block.
self.head
};
let index = unsafe {
// Find the rightmost zero bit in the mask. Taking the rightmost zero is always ok,
// even if this is the last block.
let offset = (!*self.mask(block)).trailing_zeros() as usize;
debug_assert!(offset < bits());
slot_index(block, offset)
};
self.acquire_at(index);
index
}
/// Marks the vacant slot at `index` as occupied.
///
/// # Panics
///
/// Panics if the slot is already occupied.
pub fn acquire_at(&mut self, index: usize) {
assert!(index < self.len, "`index` out of bounds");
let (block, offset) = block_and_offset(index);
unsafe {
// Mark the slot as occupied in the block's bit mask.
assert!(*self.mask(block) >> offset & 1 == 0, "occupied slot at `index`");
*self.mask(block) ^= 1 << offset;
// If the block has just become fully occupied, remove it from the list.
if block == self.head && *self.mask(block) == !0 {
let succ = *self.successor(block);
self.link_blocks(!0, succ);
self.head = succ;
}
self.occupied += 1;
}
}
/// Releases the occupied slot at `index`.
///
/// # Panics
///
/// Panics if the `index` is out of bounds or the slot is vacant.
pub fn release(&mut self, index: usize) {
assert!(index < self.len, "`index` out of bounds");
let (block, offset) = block_and_offset(index);
unsafe {
// Make sure we're not releasing a vacant slot.
assert!(*self.mask(block) >> offset & 1 == 1, "releasing a vacant slot");
self.occupied -= 1;
// If the block is fully occupied, insert it back into the list.
if *self.mask(block) == !0 {
let head = self.head;
self.link_blocks(!0, block);
self.link_blocks(block, head);
self.head = block;
}
// Mark the slot as vacant in the block's bit mask.
*self.mask(block) ^= 1 << offset;
}
}
/// Given the required minimal additional number of slots to reserve, returns the number of
/// slots to reserve in order to keep amortized time complexity.
fn amortized_reserve(&self, additional: usize) -> usize {
let len = self.len();
let required_len = len.checked_add(additional).expect("len overflow");
let double_len = len.checked_mul(2).expect("len overflow");
cmp::max(required_len, double_len) - len
}
/// Reserves at least `additional` more slots for new elements to be inserted. The arena may
/// reserve more space to avoid frequent reallocations.
///
/// # Panics
///
/// Panics if the new number of slots overflows `usize`.
pub fn reserve(&mut self, additional: usize) {
let amortized = self.amortized_reserve(additional);
self.reserve_exact(amortized);
}
/// Reserves exactly `additional` more slots for new elements to be inserted.
///
/// Note that the allocator may give the bitmap more space than it requests.
///
/// # Panics
///
/// Panics if the new number of slots overflows `usize`.
pub fn reserve_exact(&mut self, additional: usize) {
let old_blocks = blocks_for(self.len);
self.len = self.len.checked_add(additional).expect("len overflow");
let new_blocks = blocks_for(self.len);
if new_blocks == old_blocks {
// We can simply return.
// The higher unused bits of the last block are always zero anyway.
return;
}
unsafe {
// If the last block had some unused or vacant slots, push it into the linked list.
if old_blocks > 0 && *self.mask(old_blocks - 1) != !0 {
let head = self.head;
let last = old_blocks - 1;
self.link_blocks(last, head);
self.link_blocks(!0, last);
self.head = last;
}
// Allocate a new array.
let new_data = {
// Every block contains three `usize` integers, so we need `3 * new_blocks` of
// space.
let mut vec = Vec::with_capacity(3 * new_blocks);
let ptr = vec.as_mut_ptr();
mem::forget(vec);
ptr
};
// Copy the three old subarrays (bit masks, successor indices, predecessor indices)
// into the new array.
for i in 0..3 {
ptr::copy_nonoverlapping(
self.data.offset((old_blocks * i) as isize),
new_data.offset((new_blocks * i) as isize),
old_blocks);
}
// Deallocate the old array.
Vec::from_raw_parts(self.data, 0, 3 * old_blocks);
// Set the new bit masks to zero.
ptr::write_bytes(new_data.offset(old_blocks as isize), 0, new_blocks - old_blocks);
// Set the new data now because we're about to push blocks into the linked list.
self.data = new_data;
// If there are at least two new blocks, that means there is at least one new block
// that must be pushed into the linked list.
if old_blocks + 2 <= new_blocks {
let head = self.head;
self.link_blocks(new_blocks - 2, head);
self.link_blocks(!0, old_blocks);
self.head = old_blocks;
for block in old_blocks .. new_blocks - 2 {
self.link_blocks(block, block + 1);
}
}
}
}
/// Returns `true` if the slot at `index` is occupied.
#[inline]
pub fn is_occupied(&self, index: usize) -> bool {
assert!(index < self.len, "`index` out of bounds");
let (block, offset) = block_and_offset(index);
unsafe {
*self.mask(block) >> offset & 1 != 0
}
}
/// Returns an iterator over occupied slots.
#[inline]
pub fn iter(&self) -> Iter {
Iter {
bitmap: self,
index: 0,
}
}
#[cfg(debug_assertions)]
pub fn check_invariants(&self) {
// TODO
}
/// Links together blocks `a` and `b` so that `a` comes before `b` in the linked list.
#[inline]
unsafe fn link_blocks(&mut self, a: usize, b: usize) {
if a != !0 { *self.successor(a) = b; }
if b != !0 { *self.predecessor(b) = a; }
}
/// Returns the pointer to the bit mask of `block`.
#[inline]
unsafe fn mask(&self, block: usize) -> *mut usize {
self.data.offset(block as isize)
}
/// Returns the pointer to the index of the successor of `block`.
#[inline]
unsafe fn successor(&self, block: usize) -> *mut usize {
self.data.offset((blocks_for(self.len) + block) as isize)
}
/// Returns the pointer to the index of the predecessor of `block`.
#[inline]
unsafe fn predecessor(&self, block: usize) -> *mut usize {
self.data.offset((2 * blocks_for(self.len) + block) as isize)
}
/// Returns the next occupied slot starting from (and including) the specified `index`.
pub fn next_occupied(&self, mut index: usize) -> Option<usize> {
while index < self.len() {
let (block, offset) = block_and_offset(index);
let mask = unsafe { *self.mask(block) };
if mask != 0 {
for off in offset .. bits() {
if mask >> off & 1 == 1 {
return Some(slot_index(block, off));
}
}
}
index = slot_index(block + 1, 0);
}
None
}
/// Returns the previous occupied slot before the specified `index`.
pub fn previous_occupied(&self, mut index: usize) -> Option<usize> {
index = cmp::min(index, self.len());
loop {
let (block, offset) = block_and_offset(index);
let mask = unsafe { *self.mask(block) };
if mask != 0 {
for off in (0 .. offset).rev() {
if mask >> off & 1 == 1 {
return Some(slot_index(block, off));
}
}
}
if block == 0 {
break;
}
index = slot_index(block - 1, 0);
}
None
}
}
impl Drop for Bitmap {
fn drop(&mut self) {
unsafe {
Vec::from_raw_parts(self.data, 0, 3 * blocks_for(self.len));
}
}
}
/// Iterates over all occupied slots.
pub struct Iter<'a> {
/// The bitmap to iterate over.
bitmap: &'a Bitmap,
/// Index of the current slot.
index: usize,
}
impl<'a> Iterator for Iter<'a> {
type Item = usize;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.bitmap.next_occupied(self.index).map(|index| {
self.index = index + 1;
index
})
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let low = 0;
let high = self.bitmap.len() - self.index;
(low, Some(high))
}
#[inline]
fn count(self) -> usize {
self.bitmap.occupied
}
}

View File

@ -1,54 +1,110 @@
//! A fast general-purpose object arena. //! A fast general-purpose object arena.
//! //!
//! This crate contains `VecArena`, which is an allocator that can hold objects of only one type. //! `Arena<T>` is basically just a `Vec<Option<T>>`, which allows you to:
//! It can allocate space for new objects and reclaim space upon removal of objects. The amount //!
//! of space to hold objects is dynamically expanded as needed. Inserting objects into an arena //! * Insert an object (reuse an existing `None` element, or append to the end)
//! is amortized `O(1)`, and removing is `O(1)`. //! * Remove object at a specified index
// TODO: An example of a doubly linked list? //! * Access object at a specified index
//!
//! It's useful in situations where you need to create complex graphs. For example:
//!
//! * Doubly linked lists
//! * Bidirectional trees
//! * Widget hierarchies in GUIs
//! * Graphs with circular references
//!
//! As a rule of thumb, if building a data structure using `Rc` and `RefCell` gets too messy or
//! costly, `Arena` might be a better choice.
use bitmap::Bitmap; use std::iter;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem; use std::mem;
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
use std::ptr; use std::slice;
use std::vec;
mod bitmap; #[derive(Clone)]
enum Slot<T> {
/// An arena that can insert and remove objects of a single type. Vacant(usize),
/// Occupied(T),
/// `VecArena<T>` resembles `Vec<Option<T>>` a lot because it holds an array of slots for
/// storing objects. A slot can be either occupied or vacant. Inserting a new object into an arena
/// involves finding a vacant slot and placing the object into the slot. Removing an object means
/// taking it out of the slot and marking it as vacant.
///
/// Internally, a bitmap is used instead of `Option`s to conserve space and improve cache
/// performance. Every indexing operation checks that an object really exists at the specified
/// index, otherwise it panics.
// TODO: Explain that arena[index] is equivalent to arena.get(index).unwrap() or
// arena.get_mut(index).unwrap()
// TODO: a bunch of examples, see the docs for Vec for inspiration.
pub struct VecArena<T> {
// TODO: Docs for these fields
slots: *const T,
bitmap: Bitmap,
marker: PhantomData<T>,
} }
impl<T> VecArena<T> { /// An object arena.
///
/// `Arena<T>` holds an array of slots for storing objects.
/// Every slot is always in one of two states: occupied or vacant.
///
/// Essentially, this is equivalent to `Vec<Option<T>>`.
///
/// # Insert and remove
///
/// When inserting a new object into arena, a vacant slot is found and then the object is placed
/// into the slot. If there are no vacant slots, the array is reallocated with bigger capacity.
/// The cost of insertion is amortized `O(1)`.
///
/// When removing an object, the slot containing it is marked as vacant and the object is returned.
/// The cost of removal is `O(1)`.
///
/// ```
/// use vec_arena::Arena;
///
/// let mut arena = Arena::new();
/// let a = arena.insert(10);
/// let b = arena.insert(20);
///
/// assert_eq!(a, 0); // 10 was placed at index 0
/// assert_eq!(b, 1); // 20 was placed at index 1
///
/// assert_eq!(arena.remove(a), Some(10));
/// assert_eq!(arena.get(a), None); // slot at index 0 is now vacant
///
/// assert_eq!(arena.insert(30), 0); // slot at index 0 is reused
/// ```
///
/// # Indexing
///
/// You can also access objects in an arena by index, just like you would in a `Vec`.
/// However, accessing a vacant slot by index or using an out-of-bounds index will result in panic.
///
/// ```
/// use vec_arena::Arena;
///
/// let mut arena = Arena::new();
/// let a = arena.insert(10);
/// let b = arena.insert(20);
///
/// assert_eq!(arena[a], 10);
/// assert_eq!(arena[b], 20);
///
/// arena[a] += arena[b];
/// assert_eq!(arena[a], 30);
/// ```
///
/// To access slots without fear of panicking, use `get` and `get_mut`, which return `Option`s.
pub struct Arena<T> {
slots: Vec<Slot<T>>,
len: usize,
head: usize,
}
impl<T> Arena<T> {
/// Constructs a new, empty arena. /// Constructs a new, empty arena.
/// ///
/// The arena will not allocate until objects are inserted into it. /// The arena will not allocate until objects are inserted into it.
///
/// # Examples
///
/// ```
/// use vec_arena::Arena;
///
/// let mut arena: Arena<i32> = Arena::new();
/// ```
#[inline]
pub fn new() -> Self { pub fn new() -> Self {
let slots = { Arena {
let mut vec = Vec::with_capacity(0); slots: Vec::new(),
let ptr = vec.as_mut_ptr(); len: 0,
mem::forget(vec); head: !0,
ptr
};
VecArena {
slots: slots,
bitmap: Bitmap::new(),
marker: PhantomData,
} }
} }
@ -56,231 +112,330 @@ impl<T> VecArena<T> {
/// ///
/// The arena will be able to hold exactly `capacity` objects without reallocating. /// The arena will be able to hold exactly `capacity` objects without reallocating.
/// If `capacity` is 0, the arena will not allocate. /// If `capacity` is 0, the arena will not allocate.
///
/// # Examples
///
/// ```
/// use vec_arena::Arena;
///
/// let mut arena = Arena::with_capacity(10);
///
/// assert_eq!(arena.len(), 0);
/// assert_eq!(arena.capacity(), 10);
///
/// // These inserts are done without reallocating...
/// for i in 0..10 {
/// arena.insert(i);
/// }
/// assert!(arena.capacity() == 10);
///
/// // ... but this one will reallocate.
/// arena.insert(11);
/// assert!(arena.capacity() > 10);
/// ```
#[inline]
pub fn with_capacity(cap: usize) -> Self { pub fn with_capacity(cap: usize) -> Self {
let mut arena = Self::new(); Arena {
arena.reserve_exact(cap); slots: Vec::with_capacity(cap),
arena len: 0,
head: !0,
}
} }
/// Returns the number of objects the arena can hold without reallocating. /// Returns the number of slots in the arena.
/// In other words, this is the number of slots. ///
/// # Examples
///
/// ```
/// use vec_arena::Arena;
///
/// let arena: Arena<i32> = Arena::with_capacity(10);
/// assert_eq!(arena.capacity(), 10);
/// ```
#[inline] #[inline]
pub fn capacity(&self) -> usize { pub fn capacity(&self) -> usize {
self.bitmap.len() self.slots.capacity()
} }
/// Returns the number of objects in the arena. /// Returns the number of occupied slots in the arena.
/// In other words, this is the number of occupied slots. ///
/// # Examples
///
/// ```
/// use vec_arena::Arena;
///
/// let mut arena = Arena::new();
/// assert_eq!(arena.len(), 0);
///
/// for i in 0..10 {
/// arena.insert(());
/// assert_eq!(arena.len(), i + 1);
/// }
/// ```
#[inline] #[inline]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.bitmap.occupied() self.len
} }
/// Returns `true` if the arena holds no objects. /// Returns `true` if all slots are vacant.
///
/// # Examples
///
/// ```
/// use vec_arena::Arena;
///
/// let mut arena = Arena::new();
/// assert!(arena.is_empty());
///
/// arena.insert(1);
/// assert!(!arena.is_empty());
/// ```
#[inline] #[inline]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.len() == 0 self.len == 0
} }
/// Inserts an object into the arena and returns the slot index in which it was stored. /// Inserts an object into the arena and returns the slot index it was stored in.
/// The arena will reallocate if it's full. /// The arena will reallocate if it's full.
///
/// # Examples
///
/// ```
/// use vec_arena::Arena;
///
/// let mut arena = Arena::new();
///
/// let a = arena.insert(1);
/// let b = arena.insert(2);
/// assert!(a != b);
/// ```
#[inline]
pub fn insert(&mut self, object: T) -> usize { pub fn insert(&mut self, object: T) -> usize {
if self.bitmap.occupied() == self.bitmap.len() { if self.head == !0 {
self.double(); let index = self.len;
self.slots.push(Slot::Occupied(object));
self.len += 1;
index
} else {
let index = self.head;
match self.slots[index] {
Slot::Vacant(next) => {
self.head = next;
self.slots[index] = Slot::Occupied(object);
},
Slot::Occupied(_) => unreachable!(),
}
index
} }
let index = self.bitmap.acquire();
unsafe {
ptr::write(self.slots.offset(index as isize) as *mut T, object);
}
index
}
/// Inserts an object into the vacant slot at `index`.
///
/// # Panics
///
/// Panics if `index` is out of bounds or the slot is already occupied.
pub fn insert_at(&mut self, index: usize, object: T) -> usize {
self.bitmap.acquire_at(index);
unsafe {
ptr::write(self.slots.offset(index as isize) as *mut T, object);
}
index
} }
/// Removes the object stored at `index` from the arena and returns it. /// Removes the object stored at `index` from the arena and returns it.
/// ///
/// # Panics /// `None` is returned in case the slot is vacant, or `index` is out of bounds.
/// ///
/// Panics if `index` is out of bounds or the slot is already vacant. /// # Examples
pub fn remove(&mut self, index: usize) -> T { ///
// `release` will panic if the index is out of bounds or the slot is already vacant. /// ```
self.bitmap.release(index); /// use vec_arena::Arena;
///
unsafe { /// let mut arena = Arena::new();
ptr::read(self.slots.offset(index as isize) as *mut T) /// let a = arena.insert("hello");
///
/// assert_eq!(arena.len(), 1);
/// assert_eq!(arena.remove(a), Some("hello"));
///
/// assert_eq!(arena.len(), 0);
/// assert_eq!(arena.remove(a), None);
/// ```
#[inline]
pub fn remove(&mut self, index: usize) -> Option<T> {
match self.slots.get_mut(index) {
None => None,
Some(&mut Slot::Vacant(_)) => None,
Some(slot @ &mut Slot::Occupied(_)) => {
if let Slot::Occupied(object) = mem::replace(slot, Slot::Vacant(self.head)) {
self.head = index;
self.len -= 1;
Some(object)
} else {
unreachable!();
}
}
} }
} }
/// Clears the arena, removing and dropping all objects it holds. Keeps the allocated memory /// Clears the arena, removing and dropping all objects it holds. Keeps the allocated memory
/// for reuse. /// for reuse.
///
/// # Examples
///
/// ```
/// use vec_arena::Arena;
///
/// let mut arena = Arena::new();
/// for i in 0..10 {
/// arena.insert(i);
/// }
///
/// assert_eq!(arena.len(), 10);
/// arena.clear();
/// assert_eq!(arena.len(), 0);
/// ```
#[inline]
pub fn clear(&mut self) { pub fn clear(&mut self) {
let mut arena = VecArena::with_capacity(self.capacity()); self.slots.clear();
mem::swap(self, &mut arena); self.len = 0;
self.head = !0;
} }
/// Returns a reference to the object stored at `index`. /// Returns a reference to the object stored at `index`, or `None` if it's out of bounds.
/// ///
/// # Panics /// # Examples
/// ///
/// Panics if `index` is out of bounds. /// ```
/// use vec_arena::Arena;
///
/// let mut arena = Arena::new();
/// let index = arena.insert("hello");
///
/// assert_eq!(arena.get(index), Some(&"hello"));
/// arena.remove(index);
/// assert_eq!(arena.get(index), None);
/// ```
#[inline] #[inline]
pub fn get(&self, index: usize) -> Option<&T> { pub fn get(&self, index: usize) -> Option<&T> {
if self.bitmap.is_occupied(index) { match self.slots.get(index) {
unsafe { Some(self.get_unchecked(index)) } None => None,
} else { Some(&Slot::Vacant(_)) => None,
None Some(&Slot::Occupied(ref object)) => Some(object),
} }
} }
/// Returns a mutable reference to the object stored at `index`. /// Returns a mutable reference to the object stored at `index`, or `None` if it's out of
/// bounds.
/// ///
/// # Panics /// # Examples
/// ///
/// Panics if `index` is out of bounds. /// ```
/// use vec_arena::Arena;
///
/// let mut arena = Arena::new();
/// let index = arena.insert(7);
///
/// assert_eq!(arena.get_mut(index), Some(&mut 7));
/// *arena.get_mut(index).unwrap() *= 10;
/// assert_eq!(arena.get_mut(index), Some(&mut 70));
/// ```
#[inline] #[inline]
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
if self.bitmap.is_occupied(index) { match self.slots.get_mut(index) {
unsafe { Some(self.get_unchecked_mut(index)) } None => None,
} else { Some(&mut Slot::Vacant(_)) => None,
None Some(&mut Slot::Occupied(ref mut object)) => Some(object),
} }
} }
/// Reserves capacity for at least `additional` more elements to be inserted. The arena may /// Reserves capacity for at least `additional` more objects to be inserted. The arena may
/// reserve more space to avoid frequent reallocations. /// reserve more space to avoid frequent reallocations.
/// ///
/// # Panics /// # Panics
/// ///
/// Panics if the new capacity overflows `usize`. /// Panics if the new capacity overflows `usize`.
///
/// # Examples
///
/// ```
/// use vec_arena::Arena;
///
/// let mut arena = Arena::new();
/// arena.insert("hello");
///
/// arena.reserve(10);
/// assert!(arena.capacity() >= 11);
/// ```
pub fn reserve(&mut self, additional: usize) { pub fn reserve(&mut self, additional: usize) {
let len = self.bitmap.len(); let vacant = self.slots.len() - self.len;
self.bitmap.reserve(additional); if additional > vacant {
unsafe { self.slots.reserve(additional - vacant);
self.reallocate(len);
} }
} }
/// Reserves the minimum capacity for exactly `additional` more elements to be inserted. /// Reserves the minimum capacity for exactly `additional` more objects to be inserted.
/// ///
/// Note that the allocator may give the arena more space than it requests. /// Note that the allocator may give the arena more space than it requests.
/// ///
/// # Panics /// # Panics
/// ///
/// Panics if the new capacity overflows `usize`. /// Panics if the new capacity overflows `usize`.
///
/// # Examples
///
/// ```
/// use vec_arena::Arena;
///
/// let mut arena = Arena::new();
/// arena.insert("hello");
///
/// arena.reserve_exact(10);
/// assert!(arena.capacity() >= 11);
/// ```
pub fn reserve_exact(&mut self, additional: usize) { pub fn reserve_exact(&mut self, additional: usize) {
let len = self.bitmap.len(); let vacant = self.slots.len() - self.len;
self.bitmap.reserve_exact(additional); if additional > vacant {
unsafe { self.slots.reserve_exact(additional - vacant);
self.reallocate(len);
} }
} }
/// Reallocates the object array because the bitmap was resized. /// Returns an iterator over occupied slots.
unsafe fn reallocate(&mut self, old_len: usize) { ///
let new_len = self.bitmap.len(); /// # Examples
///
// Allocate a new array. /// ```
let mut vec = Vec::with_capacity(new_len); /// use vec_arena::Arena;
let ptr = vec.as_mut_ptr(); ///
mem::forget(vec); /// let mut arena = Arena::new();
/// arena.insert(1);
// Copy data into the new array. /// arena.insert(2);
ptr::copy_nonoverlapping(self.slots, ptr, old_len); /// arena.insert(4);
///
// Deallocate the old array. /// let mut iterator = arena.iter();
Vec::from_raw_parts(self.slots as *mut T, 0, old_len); /// assert_eq!(iterator.next(), Some((0, &1)));
/// assert_eq!(iterator.next(), Some((1, &2)));
self.slots = ptr; /// assert_eq!(iterator.next(), Some((2, &4)));
} /// ```
/// Doubles the capacity of the arena.
#[cold]
#[inline(never)]
fn double(&mut self) {
let len = self.bitmap.len();
let elem_size = mem::size_of::<T>();
let new_len = if len == 0 {
if elem_size.checked_mul(4).is_some() {
4
} else {
1
}
} else {
len.checked_mul(2).expect("len overflow")
};
self.reserve_exact(new_len - len);
}
#[inline] #[inline]
pub fn iter(&self) -> Iter<T> { pub fn iter(&self) -> Iter<T> {
Iter { Iter { slots: self.slots.iter().enumerate() }
arena: self,
index: 0,
}
} }
/// Returns an iterator that returns mutable references to objects.
///
/// # Examples
///
/// ```
/// use vec_arena::Arena;
///
/// let mut arena = Arena::new();
/// arena.insert("zero".to_string());
/// arena.insert("one".to_string());
/// arena.insert("two".to_string());
///
/// for (index, object) in arena.iter_mut() {
/// *object = index.to_string() + " " + object;
/// }
///
/// let mut iterator = arena.iter();
/// assert_eq!(iterator.next(), Some((0, &"0 zero".to_string())));
/// assert_eq!(iterator.next(), Some((1, &"1 one".to_string())));
/// assert_eq!(iterator.next(), Some((2, &"2 two".to_string())));
/// ```
#[inline] #[inline]
pub fn iter_mut(&mut self) -> IterMut<T> { pub fn iter_mut(&mut self) -> IterMut<T> {
IterMut { IterMut { slots: self.slots.iter_mut().enumerate() }
slots: self.slots as *mut T,
bitmap: &self.bitmap,
index: 0,
marker: PhantomData,
}
}
#[inline]
pub fn drain(&mut self) -> Drain<T> {
Drain {
arena: self,
index: 0,
}
}
/// Returns a reference to the object at `index`, without bounds checking nor checking that
/// the object exists.
#[inline]
pub unsafe fn get_unchecked(&self, index: usize) -> &T {
&*self.slots.offset(index as isize)
}
/// Returns a mutable reference to the object at `index`, without bounds checking nor checking
/// that the object exists.
#[inline]
pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
&mut *(self.slots.offset(index as isize) as *mut T)
} }
} }
impl<T> Drop for VecArena<T> { impl<T> Index<usize> for Arena<T> {
fn drop(&mut self) {
unsafe {
// Drop all objects in the arena.
for index in self.bitmap.iter() {
ptr::drop_in_place(self.slots.offset(index as isize) as *mut T);
}
// Deallocate the old array.
Vec::from_raw_parts(self.slots as *mut T, 0, self.bitmap.len());
}
}
}
impl<T> Index<usize> for VecArena<T> {
type Output = T; type Output = T;
#[inline] #[inline]
@ -289,43 +444,32 @@ impl<T> Index<usize> for VecArena<T> {
} }
} }
impl<T> IndexMut<usize> for VecArena<T> { impl<T> IndexMut<usize> for Arena<T> {
#[inline] #[inline]
fn index_mut(&mut self, index: usize) -> &mut T { fn index_mut(&mut self, index: usize) -> &mut T {
self.get_mut(index).expect("vacant slot at `index`") self.get_mut(index).expect("vacant slot at `index`")
} }
} }
impl<T> Default for VecArena<T> { impl<T> Default for Arena<T> {
fn default() -> Self { fn default() -> Self {
VecArena::new() Arena::new()
} }
} }
impl<T: Clone> Clone for VecArena<T> { impl<T: Clone> Clone for Arena<T> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
let mut arena = VecArena::with_capacity(self.capacity()); Arena {
for index in self.bitmap.iter() { slots: self.slots.clone(),
let clone = unsafe { len: self.len,
self.get_unchecked(index).clone() head: self.head,
};
arena.insert_at(index, clone);
} }
arena
} }
} }
/// An iterator over the occupied slots in a `Arena`.
pub struct IntoIter<T> { pub struct IntoIter<T> {
slots: *const T, slots: iter::Enumerate<vec::IntoIter<Slot<T>>>,
bitmap: Bitmap,
index: usize,
marker: PhantomData<T>,
}
impl<T> Drop for IntoIter<T> {
fn drop(&mut self) {
while self.next().is_some() {}
}
} }
impl<T> Iterator for IntoIter<T> { impl<T> Iterator for IntoIter<T> {
@ -333,42 +477,28 @@ impl<T> Iterator for IntoIter<T> {
#[inline] #[inline]
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.bitmap.next_occupied(self.index).map(|index| { while let Some((index, slot)) = self.slots.next() {
self.index = index + 1; if let Slot::Occupied(object) = slot {
unsafe { return Some((index, object));
self.bitmap.release(index);
(index, ptr::read(self.slots.offset(index as isize)))
} }
}) }
} None
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let lower = 0;
let upper = self.bitmap.len() - self.index;
(lower, Some(upper))
} }
} }
impl<T> IntoIterator for VecArena<T> { impl<T> IntoIterator for Arena<T> {
type Item = (usize, T); type Item = (usize, T);
type IntoIter = IntoIter<T>; type IntoIter = IntoIter<T>;
fn into_iter(mut self) -> Self::IntoIter { #[inline]
let iter = IntoIter { fn into_iter(self) -> Self::IntoIter {
slots: self.slots, IntoIter { slots: self.slots.into_iter().enumerate() }
bitmap: mem::replace(&mut self.bitmap, Bitmap::new()),
index: 0,
marker: PhantomData,
};
mem::forget(self);
iter
} }
} }
/// An iterator over references to the occupied slots in a `Arena`.
pub struct Iter<'a, T: 'a> { pub struct Iter<'a, T: 'a> {
arena: &'a VecArena<T>, slots: iter::Enumerate<slice::Iter<'a, Slot<T>>>,
index: usize,
} }
impl<'a, T> Iterator for Iter<'a, T> { impl<'a, T> Iterator for Iter<'a, T> {
@ -376,27 +506,18 @@ impl<'a, T> Iterator for Iter<'a, T> {
#[inline] #[inline]
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.arena.bitmap.next_occupied(self.index).map(|index| { while let Some((index, slot)) = self.slots.next() {
self.index = index + 1; if let Slot::Occupied(ref object) = *slot {
unsafe { return Some((index, object));
(index, self.arena.get_unchecked(index))
} }
}) }
} None
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let lower = 0;
let upper = self.arena.capacity() - self.index;
(lower, Some(upper))
} }
} }
/// An iterator over mutable references to the occupied slots in a `Arena`.
pub struct IterMut<'a, T: 'a> { pub struct IterMut<'a, T: 'a> {
slots: *mut T, slots: iter::Enumerate<slice::IterMut<'a, Slot<T>>>,
bitmap: &'a Bitmap,
index: usize,
marker: PhantomData<&'a mut T>,
} }
impl<'a, T> Iterator for IterMut<'a, T> { impl<'a, T> Iterator for IterMut<'a, T> {
@ -404,46 +525,12 @@ impl<'a, T> Iterator for IterMut<'a, T> {
#[inline] #[inline]
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.bitmap.next_occupied(self.index).map(|index| { while let Some((index, slot)) = self.slots.next() {
self.index = index + 1; if let Slot::Occupied(ref mut object) = *slot {
unsafe { return Some((index, object));
(index, &mut *self.slots.offset(index as isize))
} }
}) }
} None
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let lower = 0;
let upper = self.bitmap.len() - self.index;
(lower, Some(upper))
}
}
pub struct Drain<'a, T: 'a> {
arena: &'a mut VecArena<T>,
index: usize,
}
impl<'a, T> Iterator for Drain<'a, T> {
type Item = (usize, T);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.arena.bitmap.next_occupied(self.index).map(|index| {
self.index = index + 1;
unsafe {
self.arena.bitmap.release(index);
(index, ptr::read(self.arena.slots.offset(index as isize)))
}
})
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let lower = 0;
let upper = self.arena.capacity() - self.index;
(lower, Some(upper))
} }
} }
@ -451,11 +538,9 @@ impl<'a, T> Iterator for Drain<'a, T> {
mod tests { mod tests {
use super::*; use super::*;
// TODO: test variance: https://github.com/rust-lang/rust/pull/30998/files
#[test] #[test]
fn it_works() { fn it_works() {
let mut arena = VecArena::new(); let mut arena = Arena::new();
for i in 0..10 { for i in 0..10 {
assert_eq!(arena.insert(()), i); assert_eq!(arena.insert(()), i);
assert!(arena[i] == ()); assert!(arena[i] == ());