Skip to content

Commit 393a409

Browse files
committed
Add pop() and swap() to the Map trait
1 parent 4b6864f commit 393a409

File tree

6 files changed

+187
-83
lines changed

6 files changed

+187
-83
lines changed

src/libcore/container.rs

+8
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ pub trait Map<K, V>: Mutable {
5555
/// Remove a key-value pair from the map. Return true if the key
5656
/// was present in the map, otherwise false.
5757
fn remove(&mut self, key: &K) -> bool;
58+
59+
/// Insert a key-value pair from the map. If the key already had a value
60+
/// present in the map, that value is returned. Otherwise None is returned.
61+
fn swap(&mut self, k: K, v: V) -> Option<V>;
62+
63+
/// Removes a key from the map, returning the value at the key if the key
64+
/// was previously in the map.
65+
fn pop(&mut self, k: &K) -> Option<V>;
5866
}
5967

6068
pub trait Set<T>: Mutable {

src/libcore/hashmap.rs

+30-35
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ use rand::RngUtil;
2424
use rand;
2525
use uint;
2626
use vec;
27-
use util::unreachable;
2827
use kinds::Copy;
28+
use util::{replace, unreachable};
2929

3030
static INITIAL_CAPACITY: uint = 32u; // 2^5
3131

@@ -204,7 +204,7 @@ priv impl<K:Hash + Eq,V> HashMap<K, V> {
204204
/// Inserts the key value pair into the buckets.
205205
/// Assumes that there will be a bucket.
206206
/// True if there was no previous entry with that key
207-
fn insert_internal(&mut self, hash: uint, k: K, v: V) -> bool {
207+
fn insert_internal(&mut self, hash: uint, k: K, v: V) -> Option<V> {
208208
match self.bucket_for_key_with_hash(hash, &k) {
209209
TableFull => { fail!(~"Internal logic error"); }
210210
FoundHole(idx) => {
@@ -213,14 +213,19 @@ priv impl<K:Hash + Eq,V> HashMap<K, V> {
213213
self.buckets[idx] = Some(Bucket{hash: hash, key: k,
214214
value: v});
215215
self.size += 1;
216-
true
216+
None
217217
}
218218
FoundEntry(idx) => {
219219
debug!("insert overwrite (%?->%?) at idx %?, hash %?",
220220
k, v, idx, hash);
221-
self.buckets[idx] = Some(Bucket{hash: hash, key: k,
222-
value: v});
223-
false
221+
match self.buckets[idx] {
222+
None => { fail!(~"insert_internal: Internal logic error") }
223+
Some(ref mut b) => {
224+
b.hash = hash;
225+
b.key = k;
226+
Some(replace(&mut b.value, v))
227+
}
228+
}
224229
}
225230
}
226231
}
@@ -361,6 +366,20 @@ impl<K:Hash + Eq,V> Map<K, V> for HashMap<K, V> {
361366
/// key is replaced by the new value. Return true if the key did
362367
/// not already exist in the map.
363368
fn insert(&mut self, k: K, v: V) -> bool {
369+
self.swap(k, v).is_none()
370+
}
371+
372+
/// Remove a key-value pair from the map. Return true if the key
373+
/// was present in the map, otherwise false.
374+
fn remove(&mut self, k: &K) -> bool {
375+
self.pop(k).is_some()
376+
}
377+
378+
/// Insert a key-value pair from the map. If the key already had a value
379+
/// present in the map, that value is returned. Otherwise None is returned.
380+
fn swap(&mut self, k: K, v: V) -> Option<V> {
381+
// this could be faster.
382+
364383
if self.size >= self.resize_at {
365384
// n.b.: We could also do this after searching, so
366385
// that we do not resize if this call to insert is
@@ -375,10 +394,11 @@ impl<K:Hash + Eq,V> Map<K, V> for HashMap<K, V> {
375394
self.insert_internal(hash, k, v)
376395
}
377396
378-
/// Remove a key-value pair from the map. Return true if the key
379-
/// was present in the map, otherwise false.
380-
fn remove(&mut self, k: &K) -> bool {
381-
self.pop(k).is_some()
397+
/// Removes a key from the map, returning the value at the key if the key
398+
/// was previously in the map.
399+
fn pop(&mut self, k: &K) -> Option<V> {
400+
let hash = k.hash_keyed(self.k0, self.k1) as uint;
401+
self.pop_internal(hash, k)
382402
}
383403
}
384404
@@ -402,31 +422,6 @@ pub impl<K: Hash + Eq, V> HashMap<K, V> {
402422
}
403423
}
404424
405-
fn pop(&mut self, k: &K) -> Option<V> {
406-
let hash = k.hash_keyed(self.k0, self.k1) as uint;
407-
self.pop_internal(hash, k)
408-
}
409-
410-
fn swap(&mut self, k: K, v: V) -> Option<V> {
411-
// this could be faster.
412-
let hash = k.hash_keyed(self.k0, self.k1) as uint;
413-
let old_value = self.pop_internal(hash, &k);
414-
415-
if self.size >= self.resize_at {
416-
// n.b.: We could also do this after searching, so
417-
// that we do not resize if this call to insert is
418-
// simply going to update a key in place. My sense
419-
// though is that it's worse to have to search through
420-
// buckets to find the right spot twice than to just
421-
// resize in this corner case.
422-
self.expand();
423-
}
424-
425-
self.insert_internal(hash, k, v);
426-
427-
old_value
428-
}
429-
430425
/// Return the value corresponding to the key in the map, or insert
431426
/// and return the value if it doesn't exist.
432427
fn find_or_insert<'a>(&'a mut self, k: K, v: V) -> &'a V {

src/libcore/trie.rs

+54-21
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//! An ordered map and set for integer keys implemented as a radix trie
1212
1313
use prelude::*;
14+
use util::{swap, replace};
1415

1516
// FIXME: #5244: need to manually update the TrieNode constructor
1617
static SHIFT: uint = 4;
@@ -110,21 +111,33 @@ impl<T> Map<uint, T> for TrieMap<T> {
110111
/// not already exist in the map.
111112
#[inline(always)]
112113
fn insert(&mut self, key: uint, value: T) -> bool {
113-
let ret = insert(&mut self.root.count,
114-
&mut self.root.children[chunk(key, 0)],
115-
key, value, 1);
116-
if ret { self.length += 1 }
117-
ret
114+
self.swap(key, value).is_none()
118115
}
119116

120117
/// Remove a key-value pair from the map. Return true if the key
121118
/// was present in the map, otherwise false.
122119
#[inline(always)]
123120
fn remove(&mut self, key: &uint) -> bool {
121+
self.pop(key).is_some()
122+
}
123+
124+
/// Insert a key-value pair from the map. If the key already had a value
125+
/// present in the map, that value is returned. Otherwise None is returned.
126+
fn swap(&mut self, key: uint, value: T) -> Option<T> {
127+
let ret = insert(&mut self.root.count,
128+
&mut self.root.children[chunk(key, 0)],
129+
key, value, 1);
130+
if ret.is_none() { self.length += 1 }
131+
ret
132+
}
133+
134+
/// Removes a key from the map, returning the value at the key if the key
135+
/// was previously in the map.
136+
fn pop(&mut self, key: &uint) -> Option<T> {
124137
let ret = remove(&mut self.root.count,
125138
&mut self.root.children[chunk(*key, 0)],
126139
*key, 1);
127-
if ret { self.length -= 1 }
140+
if ret.is_some() { self.length -= 1 }
128141
ret
129142
}
130143
}
@@ -289,61 +302,65 @@ fn find_mut<'r, T>(child: &'r mut Child<T>, key: uint, idx: uint)
289302
}
290303

291304
fn insert<T>(count: &mut uint, child: &mut Child<T>, key: uint, value: T,
292-
idx: uint) -> bool {
305+
idx: uint) -> Option<T> {
293306
let mut tmp = Nothing;
294-
tmp <-> *child;
295-
let mut added = false;
307+
let ret;
308+
swap(&mut tmp, child);
296309

297310
*child = match tmp {
298311
External(stored_key, stored_value) => {
299312
if stored_key == key {
313+
ret = Some(stored_value);
300314
External(stored_key, value)
301315
} else {
302316
// conflict - split the node
303317
let mut new = ~TrieNode::new();
304318
insert(&mut new.count,
305319
&mut new.children[chunk(stored_key, idx)],
306320
stored_key, stored_value, idx + 1);
307-
insert(&mut new.count, &mut new.children[chunk(key, idx)], key,
308-
value, idx + 1);
309-
added = true;
321+
ret = insert(&mut new.count, &mut new.children[chunk(key, idx)],
322+
key, value, idx + 1);
310323
Internal(new)
311324
}
312325
}
313326
Internal(x) => {
314327
let mut x = x;
315-
added = insert(&mut x.count, &mut x.children[chunk(key, idx)], key,
316-
value, idx + 1);
328+
ret = insert(&mut x.count, &mut x.children[chunk(key, idx)], key,
329+
value, idx + 1);
317330
Internal(x)
318331
}
319332
Nothing => {
320333
*count += 1;
321-
added = true;
334+
ret = None;
322335
External(key, value)
323336
}
324337
};
325-
added
338+
return ret;
326339
}
327340

328341
fn remove<T>(count: &mut uint, child: &mut Child<T>, key: uint,
329-
idx: uint) -> bool {
342+
idx: uint) -> Option<T> {
330343
let (ret, this) = match *child {
331-
External(stored, _) => {
332-
if stored == key { (true, true) } else { (false, false) }
344+
External(stored, _) if stored == key => {
345+
match replace(child, Nothing) {
346+
External(_, value) => (Some(value), true),
347+
_ => fail!()
348+
}
333349
}
350+
External(*) => (None, false),
334351
Internal(ref mut x) => {
335352
let ret = remove(&mut x.count, &mut x.children[chunk(key, idx)],
336353
key, idx + 1);
337354
(ret, x.count == 0)
338355
}
339-
Nothing => (false, false)
356+
Nothing => (None, false)
340357
};
341358

342359
if this {
343360
*child = Nothing;
344361
*count -= 1;
345362
}
346-
ret
363+
return ret;
347364
}
348365

349366
#[cfg(test)]
@@ -516,4 +533,20 @@ mod tests {
516533
i += 1;
517534
}
518535
}
536+
537+
#[test]
538+
fn test_swap() {
539+
let mut m = TrieMap::new();
540+
assert!(m.swap(1, 2) == None);
541+
assert!(m.swap(1, 3) == Some(2));
542+
assert!(m.swap(1, 4) == Some(3));
543+
}
544+
545+
#[test]
546+
fn test_pop() {
547+
let mut m = TrieMap::new();
548+
m.insert(1, 2);
549+
assert!(m.pop(&1) == Some(2));
550+
assert!(m.pop(&1) == None);
551+
}
519552
}

src/libstd/smallintmap.rs

+36-4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use core::container::{Container, Mutable, Map, Set};
1717
use core::old_iter::{BaseIter};
1818
use core::option::{Some, None};
19+
use core::util::replace;
1920

2021
pub struct SmallIntMap<T> {
2122
priv v: ~[Option<T>],
@@ -119,12 +120,27 @@ impl<V> Map<uint, V> for SmallIntMap<V> {
119120
/// Remove a key-value pair from the map. Return true if the key
120121
/// was present in the map, otherwise false.
121122
fn remove(&mut self, key: &uint) -> bool {
123+
self.pop(key).is_some()
124+
}
125+
126+
/// Insert a key-value pair from the map. If the key already had a value
127+
/// present in the map, that value is returned. Otherwise None is returned.
128+
fn swap(&mut self, key: uint, value: V) -> Option<V> {
129+
match self.find_mut(&key) {
130+
Some(loc) => { return Some(replace(loc, value)); }
131+
None => ()
132+
}
133+
self.insert(key, value);
134+
return None;
135+
}
136+
137+
/// Removes a key from the map, returning the value at the key if the key
138+
/// was previously in the map.
139+
fn pop(&mut self, key: &uint) -> Option<V> {
122140
if *key >= self.v.len() {
123-
return false;
141+
return None;
124142
}
125-
let removed = self.v[*key].is_some();
126-
self.v[*key] = None;
127-
removed
143+
replace(&mut self.v[*key], None)
128144
}
129145
}
130146

@@ -237,4 +253,20 @@ mod tests {
237253
// sadly, no sevens were counted
238254
assert!(map.find(&7).is_none());
239255
}
256+
257+
#[test]
258+
fn test_swap() {
259+
let mut m = SmallIntMap::new();
260+
assert!(m.swap(1, 2) == None);
261+
assert!(m.swap(1, 3) == Some(2));
262+
assert!(m.swap(1, 4) == Some(3));
263+
}
264+
265+
#[test]
266+
fn test_pop() {
267+
let mut m = SmallIntMap::new();
268+
m.insert(1, 2);
269+
assert!(m.pop(&1) == Some(2));
270+
assert!(m.pop(&1) == None);
271+
}
240272
}

0 commit comments

Comments
 (0)