Skip to content

Commit 426fe21

Browse files
committed
HashMap<KeyRef<K>, *mut LinkedHashMapEntry<K, V>>
1 parent 98f4cb4 commit 426fe21

File tree

1 file changed

+52
-39
lines changed

1 file changed

+52
-39
lines changed

src/lib.rs

Lines changed: 52 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ struct LinkedHashMapEntry<K, V> {
5757

5858
/// A linked hash map.
5959
pub struct LinkedHashMap<K, V, S = hash_map::RandomState> {
60-
map: HashMap<KeyRef<K>, Box<LinkedHashMapEntry<K, V>>, S>,
60+
map: HashMap<KeyRef<K>, *mut LinkedHashMapEntry<K, V>, S>,
6161
head: *mut LinkedHashMapEntry<K, V>,
6262
free: *mut LinkedHashMapEntry<K, V>,
6363
}
@@ -121,6 +121,16 @@ impl<K: Hash + Eq, V> LinkedHashMap<K, V> {
121121
}
122122

123123
impl<K, V, S> LinkedHashMap<K, V, S> {
124+
// Caller must check `!self.head.is_null()`
125+
unsafe fn drop_entries(&mut self) {
126+
let mut cur = (*self.head).next;
127+
while cur != self.head {
128+
let next = (*cur).next;
129+
Box::from_raw(cur);
130+
cur = next;
131+
}
132+
}
133+
124134
fn clear_free_list(&mut self) {
125135
unsafe {
126136
let mut free = self.free;
@@ -135,7 +145,7 @@ impl<K, V, S> LinkedHashMap<K, V, S> {
135145
}
136146

137147
impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
138-
fn with_map(map: HashMap<KeyRef<K>, Box<LinkedHashMapEntry<K, V>>, S>) -> Self {
148+
fn with_map(map: HashMap<KeyRef<K>, *mut LinkedHashMapEntry<K, V>, S>) -> Self {
139149
LinkedHashMap {
140150
map: map,
141151
head: ptr::null_mut(),
@@ -192,38 +202,36 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
192202
(*self.head).prev = self.head;
193203
}
194204
}
195-
let (node_ptr, node_opt, old_val) = match self.map.get_mut(&KeyRef{k: &k}) {
205+
let (node, old_val) = match self.map.get(&KeyRef{k: &k}) {
196206
Some(node) => {
197-
let old_val = mem::replace(&mut node.value, v);
198-
let node_ptr: *mut LinkedHashMapEntry<K, V> = &mut **node;
199-
(node_ptr, None, Some(old_val))
207+
let old_val = unsafe { ptr::replace(&mut (**node).value, v) };
208+
(*node, Some(old_val))
200209
}
201210
None => {
202-
let mut node = if self.free.is_null() {
203-
Box::new(LinkedHashMapEntry::new(k, v))
211+
let node = if self.free.is_null() {
212+
Box::into_raw(Box::new(LinkedHashMapEntry::new(k, v)))
204213
} else {
205214
// use a recycled box
206215
unsafe {
207216
let free = self.free;
208217
self.free = (*free).next;
209218
ptr::write(free, LinkedHashMapEntry::new(k, v));
210-
Box::from_raw(free)
219+
free
211220
}
212221
};
213-
let node_ptr: *mut LinkedHashMapEntry<K, V> = &mut *node;
214-
(node_ptr, Some(node), None)
222+
(node, None)
215223
}
216224
};
217-
match node_opt {
218-
None => {
225+
match old_val {
226+
Some(_) => {
219227
// Existing node, just update LRU position
220-
self.detach(node_ptr);
221-
self.attach(node_ptr);
228+
self.detach(node);
229+
self.attach(node);
222230
}
223-
Some(node) => {
224-
let keyref = unsafe { &(*node_ptr).key };
231+
None => {
232+
let keyref = unsafe { &(*node).key };
225233
self.map.insert(KeyRef{k: keyref}, node);
226-
self.attach(node_ptr);
234+
self.attach(node);
227235
}
228236
}
229237
old_val
@@ -251,7 +259,7 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
251259
/// assert_eq!(map.get(&2), Some(&"c"));
252260
/// ```
253261
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> where K: Borrow<Q>, Q: Eq + Hash {
254-
self.map.get(Qey::from_ref(k)).map(|e| &e.value)
262+
self.map.get(Qey::from_ref(k)).map(|e| unsafe { &(**e).value })
255263
}
256264

257265
/// Returns the mutable reference corresponding to the key in the map.
@@ -269,7 +277,7 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
269277
/// assert_eq!(map.get(&1), Some(&"c"));
270278
/// ```
271279
pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V> where K: Borrow<Q>, Q: Eq + Hash {
272-
self.map.get_mut(Qey::from_ref(k)).map(|e| &mut e.value)
280+
self.map.get(Qey::from_ref(k)).map(|e| unsafe { &mut (**e).value })
273281
}
274282

275283
/// Returns the value corresponding to the key in the map.
@@ -292,11 +300,10 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
292300
/// assert_eq!((&2, &"b"), map.iter().rev().next().unwrap());
293301
/// ```
294302
pub fn get_refresh<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V> where K: Borrow<Q>, Q: Eq + Hash {
295-
let (value, node_ptr_opt) = match self.map.get_mut(Qey::from_ref(k)) {
303+
let (value, node_ptr_opt) = match self.map.get(Qey::from_ref(k)) {
296304
None => (None, None),
297305
Some(node) => {
298-
let node_ptr: *mut LinkedHashMapEntry<K, V> = &mut **node;
299-
(Some(unsafe { &mut(*node_ptr).value }), Some(node_ptr))
306+
(Some(unsafe { &mut (**node).value }), Some(*node))
300307
}
301308
};
302309
if let Some(node_ptr) = node_ptr_opt {
@@ -323,17 +330,15 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
323330
/// ```
324331
pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V> where K: Borrow<Q>, Q: Eq + Hash {
325332
let removed = self.map.remove(Qey::from_ref(k));
326-
removed.map(|mut node| {
327-
let node_ptr: *mut LinkedHashMapEntry<K,V> = &mut *node;
328-
self.detach(node_ptr);
333+
removed.map(|node| {
334+
self.detach(node);
329335
unsafe {
330336
// add to free list
331-
(*node_ptr).next = self.free;
332-
self.free = node_ptr;
333-
// forget the box but drop the key and return the value
334-
mem::forget(node);
335-
drop(ptr::read(&(*node_ptr).key));
336-
ptr::read(&(*node_ptr).value)
337+
(*node).next = self.free;
338+
self.free = node;
339+
// drop the key and return the value
340+
drop(ptr::read(&(*node).key));
341+
ptr::read(&(*node).value)
337342
}
338343
})
339344
}
@@ -373,7 +378,10 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
373378
self.detach(lru);
374379
return self.map
375380
.remove(&KeyRef{k: unsafe { &(*lru).key }})
376-
.map(|e| { let e = *e; (e.key, e.value) })
381+
.map(|e| {
382+
let e = *unsafe { Box::from_raw(e) };
383+
(e.key, e.value)
384+
})
377385
}
378386
None
379387
}
@@ -394,7 +402,7 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
394402
if self.len() > 0 {
395403
let lru = unsafe { (*self.head).prev };
396404
return self.map.get(&KeyRef{k: unsafe { &(*lru).key }})
397-
.map(|e| (&e.key, &e.value))
405+
.map(|e| unsafe { (&(**e).key, &(**e).value) })
398406
}
399407
None
400408
}
@@ -419,7 +427,10 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
419427
self.detach(mru);
420428
return self.map
421429
.remove(&KeyRef{k: unsafe { &(*mru).key }})
422-
.map(|e| { let e = *e; (e.key, e.value) })
430+
.map(|e| {
431+
let e = *unsafe { Box::from_raw(e) };
432+
(e.key, e.value)
433+
})
423434
}
424435
None
425436
}
@@ -440,7 +451,7 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
440451
if self.len() > 0 {
441452
let mru = unsafe { (*self.head).next };
442453
return self.map.get(&KeyRef{k: unsafe { &(*mru).key }})
443-
.map(|e| (&e.key, &e.value))
454+
.map(|e| unsafe { (&(**e).key, &(**e).value) })
444455
}
445456
None
446457
}
@@ -457,6 +468,7 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
457468
// update the guard node if present
458469
if ! self.head.is_null() {
459470
unsafe {
471+
self.drop_entries();
460472
(*self.head).prev = self.head;
461473
(*self.head).next = self.head;
462474
}
@@ -720,12 +732,13 @@ unsafe impl<K: Sync, V: Sync, S: Sync> Sync for LinkedHashMap<K, V, S> {}
720732

721733
impl<K, V, S> Drop for LinkedHashMap<K, V, S> {
722734
fn drop(&mut self) {
723-
unsafe {
724-
if ! self.head.is_null() {
735+
if !self.head.is_null() {
736+
unsafe {
737+
self.drop_entries();
725738
drop_empty_entry_box(self.head);
726739
}
727-
self.clear_free_list();
728740
}
741+
self.clear_free_list();
729742
}
730743
}
731744

0 commit comments

Comments
 (0)