diff --git a/src/fake.rs b/src/fake.rs index 31f0662759ce..5b6352264746 100644 --- a/src/fake.rs +++ b/src/fake.rs @@ -13,6 +13,9 @@ pub use std::collections::hash_map::{Entry, RandomState}; pub struct HashMap(StdMap); + +use FailedAllocationError; + impl Deref for HashMap { type Target = StdMap; fn deref(&self) -> &Self::Target { @@ -39,7 +42,7 @@ impl HashMap { } #[inline] - pub fn try_with_capacity(capacity: usize) -> Result, ()> { + pub fn try_with_capacity(capacity: usize) -> Result, FailedAllocationError> { Ok(HashMap(StdMap::with_capacity(capacity))) } } @@ -50,12 +53,12 @@ impl HashMap S: BuildHasher { #[inline] - pub fn try_with_hasher(hash_builder: S) -> Result, ()> { + pub fn try_with_hasher(hash_builder: S) -> Result, FailedAllocationError> { Ok(HashMap(StdMap::with_hasher(hash_builder))) } #[inline] - pub fn try_with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Result, ()> { + pub fn try_with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Result, FailedAllocationError> { Ok(HashMap(StdMap::with_capacity_and_hasher(capacity, hash_builder))) } @@ -65,20 +68,20 @@ impl HashMap #[inline] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), ()> { + pub fn try_reserve(&mut self, additional: usize) -> Result<(), FailedAllocationError> { Ok(self.reserve(additional)) } - pub fn try_shrink_to_fit(&mut self) -> Result<(), ()> { + pub fn try_shrink_to_fit(&mut self) -> Result<(), FailedAllocationError> { Ok(self.shrink_to_fit()) } - pub fn try_entry(&mut self, key: K) -> Result, ()> { + pub fn try_entry(&mut self, key: K) -> Result, FailedAllocationError> { Ok(self.entry(key)) } #[inline] - pub fn try_insert(&mut self, k: K, v: V) -> Result, ()> { + pub fn try_insert(&mut self, k: K, v: V) -> Result, FailedAllocationError> { Ok(self.insert(k, v)) } } @@ -130,17 +133,17 @@ impl HashSet } #[inline] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), ()> { + pub fn try_reserve(&mut self, additional: usize) -> Result<(), FailedAllocationError> { Ok(self.reserve(additional)) } #[inline] - pub fn try_shrink_to_fit(&mut self) -> Result<(), ()> { + pub fn try_shrink_to_fit(&mut self) -> Result<(), FailedAllocationError> { Ok(self.shrink_to_fit()) } #[inline] - pub fn try_insert(&mut self, value: T) -> Result { + pub fn try_insert(&mut self, value: T) -> Result { Ok(self.insert(value)) } } diff --git a/src/hash_map.rs b/src/hash_map.rs index ae7d6af24be5..09e968b4c40d 100644 --- a/src/hash_map.rs +++ b/src/hash_map.rs @@ -23,6 +23,8 @@ use ops::{Deref, Index}; use super::table::{self, Bucket, EmptyBucket, FullBucket, FullBucketMut, RawTable, SafeHash}; use super::table::BucketState::{Empty, Full}; +use FailedAllocationError; + const MIN_NONZERO_RAW_CAPACITY: usize = 32; // must be a power of two static OOM_STR: &str = "out of memory whilst allocating hashmap"; @@ -614,7 +616,7 @@ impl HashMap { } #[inline] - pub fn try_with_capacity(capacity: usize) -> Result, ()> { + pub fn try_with_capacity(capacity: usize) -> Result, FailedAllocationError> { HashMap::try_with_capacity_and_hasher(capacity, Default::default()) } } @@ -644,7 +646,7 @@ impl HashMap /// map.insert(1, 2); /// ``` #[inline] - pub fn try_with_hasher(hash_builder: S) -> Result, ()> { + pub fn try_with_hasher(hash_builder: S) -> Result, FailedAllocationError> { Ok(HashMap { hash_builder, resize_policy: DefaultResizePolicy::new(), @@ -679,7 +681,7 @@ impl HashMap /// map.insert(1, 2); /// ``` #[inline] - pub fn try_with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Result, ()> { + pub fn try_with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Result, FailedAllocationError> { let resize_policy = DefaultResizePolicy::new(); let raw_cap = resize_policy.raw_capacity(capacity); Ok(HashMap { @@ -746,7 +748,7 @@ impl HashMap #[inline] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), ()> { + pub fn try_reserve(&mut self, additional: usize) -> Result<(), FailedAllocationError> { let remaining = self.capacity() - self.len(); // this can't overflow if remaining < additional { let min_cap = self.len().checked_add(additional).expect("reserve overflow"); @@ -763,7 +765,7 @@ impl HashMap #[cold] #[inline(never)] - fn try_resize(&mut self, new_raw_cap: usize) -> Result<(), ()> { + fn try_resize(&mut self, new_raw_cap: usize) -> Result<(), FailedAllocationError> { assert!(self.table.size() <= new_raw_cap); assert!(new_raw_cap.is_power_of_two() || new_raw_cap == 0); @@ -829,7 +831,7 @@ impl HashMap self.try_shrink_to_fit().expect(OOM_STR); } - pub fn try_shrink_to_fit(&mut self) -> Result<(), ()> { + pub fn try_shrink_to_fit(&mut self) -> Result<(), FailedAllocationError> { let new_raw_cap = self.resize_policy.raw_capacity(self.len()); if self.raw_capacity() != new_raw_cap { let old_table = replace(&mut self.table, RawTable::new(new_raw_cap)?); @@ -1002,7 +1004,7 @@ impl HashMap self.try_entry(key).expect(OOM_STR) } - pub fn try_entry(&mut self, key: K) -> Result, ()> { + pub fn try_entry(&mut self, key: K) -> Result, FailedAllocationError> { // Gotta resize now. self.try_reserve(1)?; let hash = self.make_hash(&key); @@ -1195,7 +1197,7 @@ impl HashMap } #[inline] - pub fn try_insert(&mut self, k: K, v: V) -> Result, ()> { + pub fn try_insert(&mut self, k: K, v: V) -> Result, FailedAllocationError> { let hash = self.make_hash(&k); self.try_reserve(1)?; Ok(self.insert_hashed_nocheck(hash, k, v)) diff --git a/src/lib.rs b/src/lib.rs index 3cbab53a9503..a29f5c1b0014 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,8 @@ pub mod hash_set; pub mod fake; +use std::{error, fmt}; + trait Recover { type Key; @@ -15,3 +17,20 @@ trait Recover { fn take(&mut self, key: &Q) -> Option; fn replace(&mut self, key: Self::Key) -> Option; } + +#[derive(Debug)] +pub struct FailedAllocationError { + reason: &'static str, +} + +impl error::Error for FailedAllocationError { + fn description(&self) -> &str { + self.reason + } +} + +impl fmt::Display for FailedAllocationError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.reason.fmt(f) + } +} diff --git a/src/table.rs b/src/table.rs index 9dfde51e39e8..cb8233562773 100644 --- a/src/table.rs +++ b/src/table.rs @@ -19,6 +19,7 @@ use ptr; use shim::{Unique, Shared}; use self::BucketState::*; +use FailedAllocationError; /// Integer type used for stored hash values. /// @@ -728,7 +729,7 @@ impl RawTable { /// Does not initialize the buckets. The caller should ensure they, /// at the very least, set every hash to EMPTY_BUCKET. - unsafe fn try_new_uninitialized(capacity: usize) -> Result, ()> { + unsafe fn try_new_uninitialized(capacity: usize) -> Result, FailedAllocationError> { if capacity == 0 { return Ok(RawTable { size: 0, @@ -757,8 +758,7 @@ impl RawTable { align_of::<(K, V)>()); if oflo { - // capacity overflow - return Err(()); + return Err(FailedAllocationError { reason: "capacity overflow when allocating RawTable" }); } // One check for overflow that covers calculation and rounding of size. @@ -768,12 +768,11 @@ impl RawTable { if let Some(cap_bytes) = cap_bytes { if size < cap_bytes { - // capacity overflow - return Err(()); + return Err(FailedAllocationError { reason: "capacity overflow when allocating RawTable" }); } } else { - // capacity overflow - return Err(()); + + return Err(FailedAllocationError { reason: "capacity overflow when allocating RawTable" }); } @@ -782,8 +781,8 @@ impl RawTable { let buffer = alloc(size, alignment); if buffer.is_null() { - // OOM - return Err(()) + + return Err(FailedAllocationError { reason: "out of memory when allocating RawTable" }); } let hashes = buffer.offset(hash_offset as isize) as *mut HashUint; @@ -817,7 +816,7 @@ impl RawTable { /// Creates a new raw table from a given capacity. All buckets are /// initially empty. - pub fn new(capacity: usize) -> Result, ()> { + pub fn new(capacity: usize) -> Result, FailedAllocationError> { unsafe { let ret = RawTable::try_new_uninitialized(capacity)?; ptr::write_bytes(ret.hashes.ptr(), 0, capacity);