Skip to content

Commit 47ee7b9

Browse files
committed
do not allocate on creation
1 parent 1ad72ee commit 47ee7b9

File tree

1 file changed

+38
-16
lines changed

1 file changed

+38
-16
lines changed

src/lib.rs

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,13 @@ impl<K, V> LinkedHashMapEntry<K, V> {
100100
}
101101
}
102102

103+
unsafe fn drop_empty_entry_box<K, V>(the_box: *mut LinkedHashMapEntry<K, V>) {
104+
// Prevent compiler from trying to drop the un-initialized key and values in the node.
105+
let LinkedHashMapEntry { key, value, .. } = *Box::from_raw(the_box);
106+
mem::forget(key);
107+
mem::forget(value);
108+
}
109+
103110
impl<K: Hash + Eq, V> LinkedHashMap<K, V> {
104111
/// Creates a linked hash map.
105112
pub fn new() -> LinkedHashMap<K, V> { LinkedHashMap::with_map(HashMap::new()) }
@@ -112,15 +119,10 @@ impl<K: Hash + Eq, V> LinkedHashMap<K, V> {
112119

113120
impl<K: Hash + Eq, V, S: HashState> LinkedHashMap<K, V, S> {
114121
fn with_map(map: HashMap<KeyRef<K>, Box<LinkedHashMapEntry<K, V>>, S>) -> LinkedHashMap<K, V, S> {
115-
let map = LinkedHashMap {
122+
LinkedHashMap {
116123
map: map,
117-
head: unsafe{ Box::into_raw(Box::new(mem::uninitialized())) },
118-
};
119-
unsafe {
120-
(*map.head).next = map.head;
121-
(*map.head).prev = map.head;
124+
head: ptr::null_mut(),
122125
}
123-
return map;
124126
}
125127

126128
/// Creates an empty linked hash map with the given initial hash state.
@@ -161,6 +163,14 @@ impl<K: Hash + Eq, V, S: HashState> LinkedHashMap<K, V, S> {
161163
/// assert_eq!(map[&2], "b");
162164
/// ```
163165
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
166+
if self.head.is_null() {
167+
// allocate the guard node if not present
168+
unsafe {
169+
self.head = Box::into_raw(Box::new(mem::uninitialized()));
170+
(*self.head).next = self.head;
171+
(*self.head).prev = self.head;
172+
}
173+
}
164174
let (node_ptr, node_opt, old_val) = match self.map.get_mut(&KeyRef{k: &k}) {
165175
Some(node) => {
166176
let old_val = mem::replace(&mut node.value, v);
@@ -405,9 +415,12 @@ impl<K: Hash + Eq, V, S: HashState> LinkedHashMap<K, V, S> {
405415
/// Clear the map of all key-value pairs.
406416
pub fn clear(&mut self) {
407417
self.map.clear();
408-
unsafe {
409-
(*self.head).prev = self.head;
410-
(*self.head).next = self.head;
418+
// update the guard node if present
419+
if ! self.head.is_null() {
420+
unsafe {
421+
(*self.head).prev = self.head;
422+
(*self.head).next = self.head;
423+
}
411424
}
412425
}
413426

@@ -430,8 +443,13 @@ impl<K: Hash + Eq, V, S: HashState> LinkedHashMap<K, V, S> {
430443
/// assert_eq!(None, iter.next());
431444
/// ```
432445
pub fn iter(&self) -> Iter<K, V> {
446+
let head = if ! self.head.is_null() {
447+
unsafe { (*self.head).prev }
448+
} else {
449+
ptr::null_mut()
450+
};
433451
Iter {
434-
head: unsafe { (*self.head).prev },
452+
head: head,
435453
tail: self.head,
436454
remaining: self.len(),
437455
marker: marker::PhantomData,
@@ -459,8 +477,13 @@ impl<K: Hash + Eq, V, S: HashState> LinkedHashMap<K, V, S> {
459477
/// assert_eq!(&17, map.get(&"a").unwrap());
460478
/// ```
461479
pub fn iter_mut(&mut self) -> IterMut<K, V> {
480+
let head = if ! self.head.is_null() {
481+
unsafe { (*self.head).prev }
482+
} else {
483+
ptr::null_mut()
484+
};
462485
IterMut {
463-
head: unsafe { (*self.head).prev },
486+
head: head,
464487
tail: self.head,
465488
remaining: self.len(),
466489
marker: marker::PhantomData,
@@ -649,10 +672,9 @@ unsafe impl<K: Sync, V: Sync, S: Sync> Sync for LinkedHashMap<K, V, S> {}
649672
impl<K, V, S> Drop for LinkedHashMap<K, V, S> {
650673
fn drop(&mut self) {
651674
unsafe {
652-
// Prevent compiler from trying to drop the un-initialized field in the sigil node.
653-
let LinkedHashMapEntry { next: _, prev: _, key: k, value: v } = *Box::from_raw(self.head);
654-
mem::forget(k);
655-
mem::forget(v);
675+
if ! self.head.is_null() {
676+
drop_empty_entry_box(self.head);
677+
}
656678
}
657679
}
658680
}

0 commit comments

Comments
 (0)