Skip to content

Commit 2b39ec5

Browse files
committed
no private types in public interfaces; backwards compatibility
1 parent a2f124d commit 2b39ec5

File tree

6 files changed

+332
-269
lines changed

6 files changed

+332
-269
lines changed

src/adaptive_hashing.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,19 @@
1010

1111
use std::hash::{BuildHasher, SipHasher, Hasher};
1212

13-
use RandomState;
13+
use sip_hash_state::SipHashState;
1414

1515
#[derive(Clone)]
1616
pub struct AdaptiveState {
17-
inner: Option<RandomState>
17+
inner: Option<SipHashState>
1818
}
1919

2020
impl AdaptiveState {
21+
#[inline]
22+
pub fn new() -> Self {
23+
Default::default()
24+
}
25+
2126
#[inline]
2227
pub fn new_fast() -> Self {
2328
AdaptiveState {
@@ -27,7 +32,7 @@ impl AdaptiveState {
2732

2833
#[inline]
2934
pub fn switch_to_safe_hashing(&mut self) {
30-
self.inner = Some(RandomState::new());
35+
self.inner = Some(SipHashState::new());
3136
}
3237

3338
pub fn uses_safe_hashing(&self) -> bool {

src/adaptive_map.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ use table::{
1717
RawTable,
1818
SafeHash
1919
};
20+
use internal_entry::InternalEntry;
21+
use entry::VacantEntryState::NeqElem;
22+
use entry::VacantEntryState::NoElem;
2023
use HashMap;
21-
use InternalEntry;
22-
use VacantEntryState::NeqElem;
23-
use VacantEntryState::NoElem;
2424
use search_hashed;
2525

2626
// Beyond this displacement, we switch to safe hashing or grow the table.
@@ -29,21 +29,22 @@ const DISPLACEMENT_THRESHOLD: usize = 128;
2929
// Otherwise, we grow the table.
3030
const LOAD_FACTOR_THRESHOLD: f32 = 0.625;
3131

32+
// Avoid problems with private types in public interfaces.
33+
pub type InternalEntryMut<'a, K: 'a, V: 'a> = InternalEntry<K, V, &'a mut RawTable<K, V>>;
34+
3235
// We have this trait, because specialization doesn't work for inherent impls yet.
3336
pub trait SafeguardedSearch<K, V> {
3437
// Method names are changed, because inherent methods shadow trait impl
3538
// methods.
36-
fn safeguarded_search(&mut self, key: &K, hash: SafeHash)
37-
-> InternalEntry<K, V, &mut RawTable<K, V>>;
39+
fn safeguarded_search(&mut self, key: &K, hash: SafeHash) -> InternalEntryMut<K, V>;
3840
}
3941

4042
impl<K, V, S> SafeguardedSearch<K, V> for HashMap<K, V, S>
4143
where K: Eq + Hash,
4244
S: BuildHasher
4345
{
4446
#[inline]
45-
default fn safeguarded_search(&mut self, key: &K, hash: SafeHash)
46-
-> InternalEntry<K, V, &mut RawTable<K, V>> {
47+
default fn safeguarded_search(&mut self, key: &K, hash: SafeHash) -> InternalEntryMut<K, V> {
4748
search_hashed(&mut self.table, hash, |k| k == key)
4849
}
4950
}
@@ -54,7 +55,7 @@ macro_rules! specialize {
5455
for HashMap<$key_type, V, AdaptiveState> {
5556
#[inline]
5657
fn safeguarded_search(&mut self, key: &$key_type, hash: SafeHash)
57-
-> InternalEntry<$key_type, V, &mut RawTable<$key_type, V>> {
58+
-> InternalEntryMut<$key_type, V> {
5859
let table_capacity = self.table.capacity();
5960
let entry = search_hashed(DerefMapToTable(self), hash, |k| k == key);
6061
match entry {

src/entry.rs

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::mem;
12+
13+
use table::{EmptyBucket, FullBucket, SafeHash, RawTable};
14+
use internal_entry::InternalEntry;
15+
use pop_internal;
16+
use robin_hood;
17+
18+
pub use self::Entry::*;
19+
pub use self::VacantEntryState::*;
20+
21+
/// A view into a single location in a map, which may be vacant or occupied.
22+
pub enum Entry<'a, K: 'a, V: 'a> {
23+
/// An occupied Entry.
24+
Occupied(OccupiedEntry<'a, K, V>),
25+
26+
/// A vacant Entry.
27+
Vacant(VacantEntry<'a, K, V>),
28+
}
29+
30+
/// A view into a single occupied location in a HashMap.
31+
pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
32+
key: Option<K>,
33+
elem: FullBucket<K, V, &'a mut RawTable<K, V>>,
34+
}
35+
36+
/// A view into a single empty location in a HashMap.
37+
pub struct VacantEntry<'a, K: 'a, V: 'a> {
38+
hash: SafeHash,
39+
key: K,
40+
elem: VacantEntryState<K, V, &'a mut RawTable<K, V>>,
41+
}
42+
43+
/// Possible states of a VacantEntry.
44+
pub enum VacantEntryState<K, V, M> {
45+
/// The index is occupied, but the key to insert has precedence,
46+
/// and will kick the current one out on insertion.
47+
NeqElem(FullBucket<K, V, M>, usize),
48+
/// The index is genuinely vacant.
49+
NoElem(EmptyBucket<K, V, M>),
50+
}
51+
52+
impl<'a, K, V> Entry<'a, K, V> {
53+
/// Returns the entry key
54+
///
55+
/// # Examples
56+
///
57+
/// ```
58+
/// use hashmap2::HashMap;
59+
///
60+
/// let mut map = HashMap::<String, u32>::new();
61+
///
62+
/// assert_eq!("hello", map.entry("hello".to_string()).key());
63+
/// ```
64+
pub fn key(&self) -> &K {
65+
match *self {
66+
Occupied(ref entry) => entry.key(),
67+
Vacant(ref entry) => entry.key(),
68+
}
69+
}
70+
71+
/// Ensures a value is in the entry by inserting the default if empty, and returns
72+
/// a mutable reference to the value in the entry.
73+
pub fn or_insert(self, default: V) -> &'a mut V {
74+
match self {
75+
Occupied(entry) => entry.into_mut(),
76+
Vacant(entry) => entry.insert(default),
77+
}
78+
}
79+
80+
/// Ensures a value is in the entry by inserting the result of the default function if empty,
81+
/// and returns a mutable reference to the value in the entry.
82+
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
83+
match self {
84+
Occupied(entry) => entry.into_mut(),
85+
Vacant(entry) => entry.insert(default()),
86+
}
87+
}
88+
}
89+
90+
impl<'a, K, V> OccupiedEntry<'a, K, V> {
91+
/// Gets a reference to the value in the entry.
92+
pub fn get(&self) -> &V {
93+
self.elem.read().1
94+
}
95+
96+
/// Gets a mutable reference to the value in the entry.
97+
pub fn get_mut(&mut self) -> &mut V {
98+
self.elem.read_mut().1
99+
}
100+
101+
/// Converts the OccupiedEntry into a mutable reference to the value in the entry
102+
/// with a lifetime bound to the map itself
103+
pub fn into_mut(self) -> &'a mut V {
104+
self.elem.into_mut_refs().1
105+
}
106+
107+
/// Sets the value of the entry, and returns the entry's old value
108+
pub fn insert(&mut self, mut value: V) -> V {
109+
let old_value = self.get_mut();
110+
mem::swap(&mut value, old_value);
111+
value
112+
}
113+
114+
/// Takes the value out of the entry, and returns it
115+
pub fn remove(self) -> V {
116+
pop_internal(self.elem).1
117+
}
118+
119+
/// Gets a reference to the entry key
120+
///
121+
/// # Examples
122+
///
123+
/// ```
124+
/// use hashmap2::HashMap;
125+
///
126+
/// let mut map = HashMap::new();
127+
///
128+
/// map.insert("foo".to_string(), 1);
129+
/// assert_eq!("foo", map.entry("foo".to_string()).key());
130+
/// ```
131+
pub fn key(&self) -> &K {
132+
self.elem.read().0
133+
}
134+
135+
/// Returns a key that was used for search.
136+
///
137+
/// The key was retained for further use.
138+
pub fn take_key(&mut self) -> Option<K> {
139+
self.key.take()
140+
}
141+
}
142+
143+
impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
144+
/// Sets the value of the entry with the VacantEntry's key,
145+
/// and returns a mutable reference to it
146+
pub fn insert(self, value: V) -> &'a mut V {
147+
match self.elem {
148+
NeqElem(bucket, ib) => {
149+
robin_hood(bucket, ib, self.hash, self.key, value)
150+
}
151+
NoElem(bucket) => {
152+
bucket.put(self.hash, self.key, value).into_mut_refs().1
153+
}
154+
}
155+
}
156+
157+
/// Gets a reference to the entry key
158+
///
159+
/// # Examples
160+
///
161+
/// ```
162+
/// use hashmap2::HashMap;
163+
///
164+
/// let mut map = HashMap::<String, u32>::new();
165+
///
166+
/// assert_eq!("foo", map.entry("foo".to_string()).key());
167+
/// ```
168+
pub fn key(&self) -> &K {
169+
&self.key
170+
}
171+
}
172+
173+
#[inline]
174+
pub fn from_internal<K, V>(internal: InternalEntry<K, V, &mut RawTable<K, V>>, key: Option<K>)
175+
-> Option<Entry<K, V>> {
176+
match internal {
177+
InternalEntry::Occupied { elem } => {
178+
Some(Entry::Occupied(OccupiedEntry {
179+
key: key,
180+
elem: elem
181+
}))
182+
}
183+
InternalEntry::Vacant { hash, elem } => {
184+
Some(Entry::Vacant(VacantEntry {
185+
hash: hash,
186+
key: key.unwrap(),
187+
elem: elem,
188+
}))
189+
}
190+
InternalEntry::TableIsEmpty => None
191+
}
192+
}
193+
194+
#[inline]
195+
pub fn occupied_elem<'a, 'r, K, V>(occupied: &'r mut OccupiedEntry<'a, K, V>)
196+
-> &'r mut FullBucket<K, V, &'a mut RawTable<K, V>> {
197+
&mut occupied.elem
198+
}

src/internal_entry.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use table::{FullBucket, SafeHash, RawTable};
12+
use entry::{self, VacantEntryState};
13+
use Entry;
14+
15+
pub enum InternalEntry<K, V, M> {
16+
Occupied {
17+
elem: FullBucket<K, V, M>,
18+
},
19+
Vacant {
20+
hash: SafeHash,
21+
elem: VacantEntryState<K, V, M>,
22+
},
23+
TableIsEmpty,
24+
}
25+
26+
impl<K, V, M> InternalEntry<K, V, M> {
27+
#[inline]
28+
pub fn into_occupied_bucket(self) -> Option<FullBucket<K, V, M>> {
29+
match self {
30+
InternalEntry::Occupied { elem } => Some(elem),
31+
_ => None,
32+
}
33+
}
34+
}
35+
36+
impl<'a, K, V> InternalEntry<K, V, &'a mut RawTable<K, V>> {
37+
#[inline]
38+
pub fn into_entry(self, key: K) -> Option<Entry<'a, K, V>> {
39+
entry::from_internal(self, Some(key))
40+
}
41+
}

0 commit comments

Comments
 (0)