// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use alloc::heap::{allocate, deallocate, EMPTY};
+use alloc::heap::{EMPTY, allocate, deallocate};
use cmp;
-use hash::{Hash, Hasher, BuildHasher};
+use hash::{BuildHasher, Hash, Hasher};
use intrinsics::needs_drop;
use marker;
use mem::{align_of, size_of};
#[unsafe_no_drop_flag]
pub struct RawTable<K, V> {
capacity: usize,
- size: usize,
- hashes: Unique<u64>,
+ size: usize,
+ hashes: Unique<u64>,
// Because K/V do not appear directly in any of the types in the struct,
// inform rustc that in fact instances of K and V are reachable from here.
- marker: marker::PhantomData<(K,V)>,
+ marker: marker::PhantomData<(K, V)>,
}
unsafe impl<K: Send, V: Send> Send for RawTable<K, V> {}
hash: *mut u64,
// We use *const to ensure covariance with respect to K and V
- key: *const K,
- val: *const V,
- _marker: marker::PhantomData<(K,V)>,
+ key: *const K,
+ val: *const V,
+ _marker: marker::PhantomData<(K, V)>,
}
-impl<K,V> Copy for RawBucket<K,V> {}
-impl<K,V> Clone for RawBucket<K,V> {
- fn clone(&self) -> RawBucket<K, V> { *self }
+impl<K, V> Copy for RawBucket<K, V> {}
+impl<K, V> Clone for RawBucket<K, V> {
+ fn clone(&self) -> RawBucket<K, V> {
+ *self
+ }
}
pub struct Bucket<K, V, M> {
- raw: RawBucket<K, V>,
- idx: usize,
- table: M
+ raw: RawBucket<K, V>,
+ idx: usize,
+ table: M,
}
-impl<K,V,M:Copy> Copy for Bucket<K,V,M> {}
-impl<K,V,M:Copy> Clone for Bucket<K,V,M> {
- fn clone(&self) -> Bucket<K,V,M> { *self }
+impl<K, V, M: Copy> Copy for Bucket<K, V, M> {}
+impl<K, V, M: Copy> Clone for Bucket<K, V, M> {
+ fn clone(&self) -> Bucket<K, V, M> {
+ *self
+ }
}
pub struct EmptyBucket<K, V, M> {
- raw: RawBucket<K, V>,
- idx: usize,
- table: M
+ raw: RawBucket<K, V>,
+ idx: usize,
+ table: M,
}
pub struct FullBucket<K, V, M> {
- raw: RawBucket<K, V>,
- idx: usize,
- table: M
+ raw: RawBucket<K, V>,
+ idx: usize,
+ table: M,
}
pub type EmptyBucketImm<'table, K, V> = EmptyBucket<K, V, &'table RawTable<K, V>>;
-pub type FullBucketImm<'table, K, V> = FullBucket<K, V, &'table RawTable<K, V>>;
+pub type FullBucketImm<'table, K, V> = FullBucket<K, V, &'table RawTable<K, V>>;
pub type EmptyBucketMut<'table, K, V> = EmptyBucket<K, V, &'table mut RawTable<K, V>>;
-pub type FullBucketMut<'table, K, V> = FullBucket<K, V, &'table mut RawTable<K, V>>;
+pub type FullBucketMut<'table, K, V> = FullBucket<K, V, &'table mut RawTable<K, V>>;
pub enum BucketState<K, V, M> {
Empty(EmptyBucket<K, V, M>),
impl SafeHash {
/// Peek at the hash value, which is guaranteed to be non-zero.
#[inline(always)]
- pub fn inspect(&self) -> u64 { self.hash }
+ pub fn inspect(&self) -> u64 {
+ self.hash
+ }
}
/// We need to remove hashes of 0. That's reserved for empty buckets.
/// This function wraps up `hash_keyed` to be the only way outside this
/// module to generate a SafeHash.
pub fn make_hash<T: ?Sized, S>(hash_state: &S, t: &T) -> SafeHash
- where T: Hash, S: BuildHasher
+ where T: Hash,
+ S: BuildHasher
{
let mut state = hash_state.build_hasher();
t.hash(&mut state);
unsafe fn offset(self, count: isize) -> RawBucket<K, V> {
RawBucket {
hash: self.hash.offset(count),
- key: self.key.offset(count),
- val: self.val.offset(count),
+ key: self.key.offset(count),
+ val: self.val.offset(count),
_marker: marker::PhantomData,
}
}
}
}
-impl<K, V, M> Deref for FullBucket<K, V, M> where M: Deref<Target=RawTable<K, V>> {
+impl<K, V, M> Deref for FullBucket<K, V, M>
+ where M: Deref<Target = RawTable<K, V>>
+{
type Target = RawTable<K, V>;
fn deref(&self) -> &RawTable<K, V> {
&self.table
}
}
-impl<K, V, M> Put<K, V> for Bucket<K, V, M> where M: Put<K, V> {
+impl<K, V, M> Put<K, V> for Bucket<K, V, M>
+ where M: Put<K, V>
+{
unsafe fn borrow_table_mut(&mut self) -> &mut RawTable<K, V> {
self.table.borrow_table_mut()
}
}
-impl<K, V, M> Put<K, V> for FullBucket<K, V, M> where M: Put<K, V> {
+impl<K, V, M> Put<K, V> for FullBucket<K, V, M>
+ where M: Put<K, V>
+{
unsafe fn borrow_table_mut(&mut self) -> &mut RawTable<K, V> {
self.table.borrow_table_mut()
}
}
-impl<K, V, M: Deref<Target=RawTable<K, V>>> Bucket<K, V, M> {
+impl<K, V, M: Deref<Target = RawTable<K, V>>> Bucket<K, V, M> {
pub fn new(table: M, hash: SafeHash) -> Bucket<K, V, M> {
Bucket::at_index(table, hash.inspect() as usize)
}
pub fn at_index(table: M, ib_index: usize) -> Bucket<K, V, M> {
// if capacity is 0, then the RawBucket will be populated with bogus pointers.
// This is an uncommon case though, so avoid it in release builds.
- debug_assert!(table.capacity() > 0, "Table should have capacity at this point");
+ debug_assert!(table.capacity() > 0,
+ "Table should have capacity at this point");
let ib_index = ib_index & (table.capacity() - 1);
Bucket {
- raw: unsafe {
- table.first_bucket_raw().offset(ib_index as isize)
- },
+ raw: unsafe { table.first_bucket_raw().offset(ib_index as isize) },
idx: ib_index,
- table: table
+ table: table,
}
}
Bucket {
raw: table.first_bucket_raw(),
idx: 0,
- table: table
+ table: table,
}
}
/// this module.
pub fn peek(self) -> BucketState<K, V, M> {
match unsafe { *self.raw.hash } {
- EMPTY_BUCKET =>
+ EMPTY_BUCKET => {
Empty(EmptyBucket {
raw: self.raw,
idx: self.idx,
- table: self.table
- }),
- _ =>
+ table: self.table,
+ })
+ }
+ _ => {
Full(FullBucket {
raw: self.raw,
idx: self.idx,
- table: self.table
+ table: self.table,
})
+ }
}
}
}
}
-impl<K, V, M: Deref<Target=RawTable<K, V>>> EmptyBucket<K, V, M> {
+impl<K, V, M: Deref<Target = RawTable<K, V>>> EmptyBucket<K, V, M> {
#[inline]
pub fn next(self) -> Bucket<K, V, M> {
let mut bucket = self.into_bucket();
Bucket {
raw: self.raw,
idx: self.idx,
- table: self.table
+ table: self.table,
}
}
let gap = EmptyBucket {
raw: self.raw,
idx: self.idx,
- table: ()
+ table: (),
};
match self.next().peek() {
Full(bucket) => {
Some(GapThenFull {
gap: gap,
- full: bucket
+ full: bucket,
})
}
- Empty(..) => None
+ Empty(..) => None,
}
}
}
-impl<K, V, M> EmptyBucket<K, V, M> where M: Put<K, V> {
+impl<K, V, M> EmptyBucket<K, V, M>
+ where M: Put<K, V>
+{
/// Puts given key and value pair, along with the key's hash,
/// into this bucket in the hashtable. Note how `self` is 'moved' into
/// this function, because this slot will no longer be empty when
/// the newly-filled slot in the hashtable.
///
/// Use `make_hash` to construct a `SafeHash` to pass to this function.
- pub fn put(mut self, hash: SafeHash, key: K, value: V)
- -> FullBucket<K, V, M> {
+ pub fn put(mut self, hash: SafeHash, key: K, value: V) -> FullBucket<K, V, M> {
unsafe {
*self.raw.hash = hash.inspect();
ptr::write(self.raw.key as *mut K, key);
self.table.borrow_table_mut().size += 1;
}
- FullBucket { raw: self.raw, idx: self.idx, table: self.table }
+ FullBucket {
+ raw: self.raw,
+ idx: self.idx,
+ table: self.table,
+ }
}
}
-impl<K, V, M: Deref<Target=RawTable<K, V>>> FullBucket<K, V, M> {
+impl<K, V, M: Deref<Target = RawTable<K, V>>> FullBucket<K, V, M> {
#[inline]
pub fn next(self) -> Bucket<K, V, M> {
let mut bucket = self.into_bucket();
Bucket {
raw: self.raw,
idx: self.idx,
- table: self.table
+ table: self.table,
}
}
#[inline]
pub fn hash(&self) -> SafeHash {
- unsafe {
- SafeHash {
- hash: *self.raw.hash
- }
- }
+ unsafe { SafeHash { hash: *self.raw.hash } }
}
/// Gets references to the key and value at a given index.
pub fn read(&self) -> (&K, &V) {
- unsafe {
- (&*self.raw.key,
- &*self.raw.val)
- }
+ unsafe { (&*self.raw.key, &*self.raw.val) }
}
}
unsafe {
*self.raw.hash = EMPTY_BUCKET;
- (
- EmptyBucket {
- raw: self.raw,
- idx: self.idx,
- table: self.table
- },
- ptr::read(self.raw.key),
- ptr::read(self.raw.val)
- )
+ (EmptyBucket {
+ raw: self.raw,
+ idx: self.idx,
+ table: self.table,
+ },
+ ptr::read(self.raw.key),
+ ptr::read(self.raw.val))
}
}
}
// This use of `Put` is misleading and restrictive, but safe and sufficient for our use cases
// where `M` is a full bucket or table reference type with mutable access to the table.
-impl<K, V, M> FullBucket<K, V, M> where M: Put<K, V> {
+impl<K, V, M> FullBucket<K, V, M>
+ where M: Put<K, V>
+{
pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) {
unsafe {
let old_hash = ptr::replace(self.raw.hash as *mut SafeHash, h);
- let old_key = ptr::replace(self.raw.key as *mut K, k);
- let old_val = ptr::replace(self.raw.val as *mut V, v);
+ let old_key = ptr::replace(self.raw.key as *mut K, k);
+ let old_val = ptr::replace(self.raw.val as *mut V, v);
(old_hash, old_key, old_val)
}
}
}
-impl<K, V, M> FullBucket<K, V, M> where M: Deref<Target=RawTable<K, V>> + DerefMut {
+impl<K, V, M> FullBucket<K, V, M>
+ where M: Deref<Target = RawTable<K, V>> + DerefMut
+{
/// Gets mutable references to the key and value at a given index.
pub fn read_mut(&mut self) -> (&mut K, &mut V) {
- unsafe {
- (&mut *(self.raw.key as *mut K),
- &mut *(self.raw.val as *mut V))
- }
+ unsafe { (&mut *(self.raw.key as *mut K), &mut *(self.raw.val as *mut V)) }
}
}
-impl<'t, K, V, M> FullBucket<K, V, M> where M: Deref<Target=RawTable<K, V>> + 't {
+impl<'t, K, V, M> FullBucket<K, V, M>
+ where M: Deref<Target = RawTable<K, V>> + 't
+{
/// Exchange a bucket state for immutable references into the table.
/// Because the underlying reference to the table is also consumed,
/// no further changes to the structure of the table are possible;
/// in exchange for this, the returned references have a longer lifetime
/// than the references returned by `read()`.
pub fn into_refs(self) -> (&'t K, &'t V) {
- unsafe {
- (&*self.raw.key,
- &*self.raw.val)
- }
+ unsafe { (&*self.raw.key, &*self.raw.val) }
}
}
-impl<'t, K, V, M> FullBucket<K, V, M> where M: Deref<Target=RawTable<K, V>> + DerefMut + 't {
+impl<'t, K, V, M> FullBucket<K, V, M>
+ where M: Deref<Target = RawTable<K, V>> + DerefMut + 't
+{
/// This works similarly to `into_refs`, exchanging a bucket state
/// for mutable references into the table.
pub fn into_mut_refs(self) -> (&'t mut K, &'t mut V) {
- unsafe {
- (&mut *(self.raw.key as *mut K),
- &mut *(self.raw.val as *mut V))
- }
+ unsafe { (&mut *(self.raw.key as *mut K), &mut *(self.raw.val as *mut V)) }
}
}
-impl<K, V, M> GapThenFull<K, V, M> where M: Deref<Target=RawTable<K, V>> {
+impl<K, V, M> GapThenFull<K, V, M>
+ where M: Deref<Target = RawTable<K, V>>
+{
#[inline]
pub fn full(&self) -> &FullBucket<K, V, M> {
&self.full
Some(self)
}
- Empty(..) => None
+ Empty(..) => None,
}
}
}
// from the start of a mallocated array.
#[inline]
fn calculate_offsets(hashes_size: usize,
- keys_size: usize, keys_align: usize,
+ keys_size: usize,
+ keys_align: usize,
vals_align: usize)
-> (usize, usize, bool) {
let keys_offset = round_up_to_next(hashes_size, keys_align);
// Returns a tuple of (minimum required malloc alignment, hash_offset,
// array_size), from the start of a mallocated array.
-fn calculate_allocation(hash_size: usize, hash_align: usize,
- keys_size: usize, keys_align: usize,
- vals_size: usize, vals_align: usize)
+fn calculate_allocation(hash_size: usize,
+ hash_align: usize,
+ keys_size: usize,
+ keys_align: usize,
+ vals_size: usize,
+ vals_align: usize)
-> (usize, usize, usize, bool) {
let hash_offset = 0;
- let (_, vals_offset, oflo) = calculate_offsets(hash_size,
- keys_size, keys_align,
- vals_align);
+ let (_, vals_offset, oflo) = calculate_offsets(hash_size, keys_size, keys_align, vals_align);
let (end_of_vals, oflo2) = vals_offset.overflowing_add(vals_size);
let align = cmp::max(hash_align, cmp::max(keys_align, vals_align));
#[test]
fn test_offset_calculation() {
- assert_eq!(calculate_allocation(128, 8, 15, 1, 4, 4), (8, 0, 148, false));
- assert_eq!(calculate_allocation(3, 1, 2, 1, 1, 1), (1, 0, 6, false));
- assert_eq!(calculate_allocation(6, 2, 12, 4, 24, 8), (8, 0, 48, false));
+ assert_eq!(calculate_allocation(128, 8, 15, 1, 4, 4),
+ (8, 0, 148, false));
+ assert_eq!(calculate_allocation(3, 1, 2, 1, 1, 1), (1, 0, 6, false));
+ assert_eq!(calculate_allocation(6, 2, 12, 4, 24, 8), (8, 0, 48, false));
assert_eq!(calculate_offsets(128, 15, 1, 4), (128, 144, false));
- assert_eq!(calculate_offsets(3, 2, 1, 1), (3, 5, false));
- assert_eq!(calculate_offsets(6, 12, 4, 8), (8, 24, false));
+ assert_eq!(calculate_offsets(3, 2, 1, 1), (3, 5, false));
+ assert_eq!(calculate_offsets(6, 12, 4, 8), (8, 24, false));
}
impl<K, V> RawTable<K, V> {
// No need for `checked_mul` before a more restrictive check performed
// later in this method.
let hashes_size = capacity * size_of::<u64>();
- let keys_size = capacity * size_of::< K >();
- let vals_size = capacity * size_of::< V >();
+ let keys_size = capacity * size_of::<K>();
+ let vals_size = capacity * size_of::<V>();
// Allocating hashmaps is a little tricky. We need to allocate three
// arrays, but since we know their sizes and alignments up front,
// This is great in theory, but in practice getting the alignment
// right is a little subtle. Therefore, calculating offsets has been
// factored out into a different function.
- let (malloc_alignment, hash_offset, size, oflo) =
- calculate_allocation(
- hashes_size, align_of::<u64>(),
- keys_size, align_of::< K >(),
- vals_size, align_of::< V >());
+ let (malloc_alignment, hash_offset, size, oflo) = calculate_allocation(hashes_size,
+ align_of::<u64>(),
+ keys_size,
+ align_of::<K>(),
+ vals_size,
+ align_of::<V>());
assert!(!oflo, "capacity overflow");
// One check for overflow that covers calculation and rounding of size.
- let size_of_bucket = size_of::<u64>().checked_add(size_of::<K>()).unwrap()
- .checked_add(size_of::<V>()).unwrap();
- assert!(size >= capacity.checked_mul(size_of_bucket)
- .expect("capacity overflow"),
+ let size_of_bucket = size_of::<u64>()
+ .checked_add(size_of::<K>())
+ .unwrap()
+ .checked_add(size_of::<V>())
+ .unwrap();
+ assert!(size >=
+ capacity.checked_mul(size_of_bucket)
+ .expect("capacity overflow"),
"capacity overflow");
let buffer = allocate(size, malloc_alignment);
- if buffer.is_null() { ::alloc::oom() }
+ if buffer.is_null() {
+ ::alloc::oom()
+ }
let hashes = buffer.offset(hash_offset as isize) as *mut u64;
RawTable {
capacity: capacity,
- size: 0,
- hashes: Unique::new(hashes),
- marker: marker::PhantomData,
+ size: 0,
+ hashes: Unique::new(hashes),
+ marker: marker::PhantomData,
}
}
let keys_size = self.capacity * size_of::<K>();
let buffer = *self.hashes as *const u8;
- let (keys_offset, vals_offset, oflo) =
- calculate_offsets(hashes_size,
- keys_size, align_of::<K>(),
- align_of::<V>());
+ let (keys_offset, vals_offset, oflo) = calculate_offsets(hashes_size,
+ keys_size,
+ align_of::<K>(),
+ align_of::<V>());
debug_assert!(!oflo, "capacity overflow");
unsafe {
RawBucket {
hash: *self.hashes,
- key: buffer.offset(keys_offset as isize) as *const K,
- val: buffer.offset(vals_offset as isize) as *const V,
+ key: buffer.offset(keys_offset as isize) as *const K,
+ val: buffer.offset(vals_offset as isize) as *const V,
_marker: marker::PhantomData,
}
}
fn raw_buckets(&self) -> RawBuckets<K, V> {
RawBuckets {
raw: self.first_bucket_raw(),
- hashes_end: unsafe {
- self.hashes.offset(self.capacity as isize)
- },
+ hashes_end: unsafe { self.hashes.offset(self.capacity as isize) },
marker: marker::PhantomData,
}
}
raw: raw_bucket.offset(self.capacity as isize),
hashes_end: raw_bucket.hash,
elems_left: self.size,
- marker: marker::PhantomData,
+ marker: marker::PhantomData,
}
}
}
if *self.raw.hash != EMPTY_BUCKET {
self.elems_left -= 1;
- return Some((
- ptr::read(self.raw.key),
- ptr::read(self.raw.val)
- ));
+ return Some((ptr::read(self.raw.key), ptr::read(self.raw.val)));
}
}
}
fn clone(&self) -> Iter<'a, K, V> {
Iter {
iter: self.iter.clone(),
- elems_left: self.elems_left
+ elems_left: self.elems_left,
}
}
}
/// Iterator over the entries in a table, consuming the table.
pub struct IntoIter<K, V> {
table: RawTable<K, V>,
- iter: RawBuckets<'static, K, V>
+ iter: RawBuckets<'static, K, V>,
}
unsafe impl<K: Sync, V: Sync> Sync for IntoIter<K, V> {}
fn next(&mut self) -> Option<(&'a K, &'a V)> {
self.iter.next().map(|bucket| {
self.elems_left -= 1;
- unsafe {
- (&*bucket.key,
- &*bucket.val)
- }
+ unsafe { (&*bucket.key, &*bucket.val) }
})
}
}
}
impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> {
- fn len(&self) -> usize { self.elems_left }
+ fn len(&self) -> usize {
+ self.elems_left
+ }
}
impl<'a, K, V> Iterator for IterMut<'a, K, V> {
fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
self.iter.next().map(|bucket| {
self.elems_left -= 1;
- unsafe {
- (&*bucket.key,
- &mut *(bucket.val as *mut V))
- }
+ unsafe { (&*bucket.key, &mut *(bucket.val as *mut V)) }
})
}
}
}
impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> {
- fn len(&self) -> usize { self.elems_left }
+ fn len(&self) -> usize {
+ self.elems_left
+ }
}
impl<K, V> Iterator for IntoIter<K, V> {
self.iter.next().map(|bucket| {
self.table.size -= 1;
unsafe {
- (
- SafeHash {
- hash: *bucket.hash,
- },
- ptr::read(bucket.key),
- ptr::read(bucket.val)
- )
+ (SafeHash { hash: *bucket.hash }, ptr::read(bucket.key), ptr::read(bucket.val))
}
})
}
}
}
impl<K, V> ExactSizeIterator for IntoIter<K, V> {
- fn len(&self) -> usize { self.table.size() }
+ fn len(&self) -> usize {
+ self.table.size()
+ }
}
impl<'a, K, V> Iterator for Drain<'a, K, V> {
self.iter.next().map(|bucket| {
self.table.size -= 1;
unsafe {
- (
- SafeHash {
- hash: ptr::replace(bucket.hash, EMPTY_BUCKET),
- },
- ptr::read(bucket.key),
- ptr::read(bucket.val)
- )
+ (SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) },
+ ptr::read(bucket.key),
+ ptr::read(bucket.val))
}
})
}
}
}
impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> {
- fn len(&self) -> usize { self.table.size() }
+ fn len(&self) -> usize {
+ self.table.size()
+ }
}
impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> {
// dropping empty tables such as on resize.
// Also avoid double drop of elements that have been already moved out.
unsafe {
- if needs_drop::<(K, V)>() { // avoid linear runtime for types that don't need drop
+ if needs_drop::<(K, V)>() {
+ // avoid linear runtime for types that don't need drop
for _ in self.rev_move_buckets() {}
}
}
let hashes_size = self.capacity * size_of::<u64>();
let keys_size = self.capacity * size_of::<K>();
let vals_size = self.capacity * size_of::<V>();
- let (align, _, size, oflo) =
- calculate_allocation(hashes_size, align_of::<u64>(),
- keys_size, align_of::<K>(),
- vals_size, align_of::<V>());
+ let (align, _, size, oflo) = calculate_allocation(hashes_size,
+ align_of::<u64>(),
+ keys_size,
+ align_of::<K>(),
+ vals_size,
+ align_of::<V>());
debug_assert!(!oflo, "should be impossible");