Skip to content

Commit ff4075e

Browse files
killerswanbrson
authored andcommitted
Add improvements to insert_with_key
This commit adds a lower-level implementation of the generic `insert_with_key` which I expect to be faster. Now insert could be defined with insert_with_key, too, although I'm not sure we want to do that. This also clarifies the tests a bit and adds an `insert_with` function.
1 parent 7b13ef7 commit ff4075e

File tree

5 files changed

+132
-19
lines changed

5 files changed

+132
-19
lines changed

src/libstd/map.rs

Lines changed: 83 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,16 @@ pub trait Map<K:Eq IterBytes Hash Copy, V: Copy> {
3535
* If the map contains a value for the key, use the function
3636
* to set a new value.
3737
*/
38-
fn insert_with_key(ff: fn(K, V, V) -> V, key: K, value: V) -> bool;
38+
fn insert_with_key(key: K, newval: V, ff: fn(K, V, V) -> V) -> bool;
39+
40+
/**
41+
* Add a value to the map.
42+
*
43+
* If the map contains a value for the key, use the function
44+
* to set a new value. (Like insert_with_key, but with a function
45+
* of only values.)
46+
*/
47+
fn insert_with(key: K, newval: V, ff: fn(V, V) -> V) -> bool;
3948

4049
/// Returns true if the map contains a value for the specified key
4150
pure fn contains_key(key: K) -> bool;
@@ -272,12 +281,57 @@ pub mod chained {
272281
}
273282
}
274283

275-
fn insert_with_key(ff: fn(K, V, V) -> V, key: K, val: V) -> bool {
276-
// this can be optimized but first lets see if it compiles...
284+
fn insert_with_key(key: K, newval: V, ff: fn(K, V, V) -> V) -> bool {
285+
/*
277286
match self.find(key) {
278287
None => return self.insert(key, val),
279288
Some(copy orig) => return self.insert(key, ff(key, orig, val))
280289
}
290+
*/
291+
292+
let hash = key.hash_keyed(0,0) as uint;
293+
match self.search_tbl(&key, hash) {
294+
NotFound => {
295+
self.count += 1u;
296+
let idx = hash % vec::len(self.chains);
297+
let old_chain = self.chains[idx];
298+
self.chains[idx] = Some(@Entry {
299+
hash: hash,
300+
key: key,
301+
value: newval,
302+
next: old_chain});
303+
304+
// consider rehashing if more 3/4 full
305+
let nchains = vec::len(self.chains);
306+
let load = {num: (self.count + 1u) as int,
307+
den: nchains as int};
308+
if !util::rational_leq(load, {num:3, den:4}) {
309+
self.rehash();
310+
}
311+
312+
return true;
313+
}
314+
FoundFirst(idx, entry) => {
315+
self.chains[idx] = Some(@Entry {
316+
hash: hash,
317+
key: key,
318+
value: ff(key, entry.value, newval),
319+
next: entry.next});
320+
return false;
321+
}
322+
FoundAfter(prev, entry) => {
323+
prev.next = Some(@Entry {
324+
hash: hash,
325+
key: key,
326+
value: ff(key, entry.value, newval),
327+
next: entry.next});
328+
return false;
329+
}
330+
}
331+
}
332+
333+
fn insert_with(key: K, newval: V, ff: fn(V, V) -> V) -> bool {
334+
return self.insert_with_key(key, newval, |_k, v, v1| ff(v,v1));
281335
}
282336

283337
pure fn get(k: K) -> V {
@@ -463,12 +517,16 @@ impl<K: Eq IterBytes Hash Copy, V: Copy> @Mut<LinearMap<K, V>>:
463517
}
464518
}
465519

466-
fn insert_with_key(ff: fn(K, V, V) -> V, key: K, val: V) -> bool {
467-
match self.find(key) {
468-
None => return self.insert(key, val),
469-
Some(copy orig) => return self.insert(key, ff(key, orig, val)),
470-
}
471-
}
520+
fn insert_with_key(key: K, newval: V, ff: fn(K, V, V) -> V) -> bool {
521+
match self.find(key) {
522+
None => return self.insert(key, newval),
523+
Some(copy orig) => return self.insert(key, ff(key, orig, newval))
524+
}
525+
}
526+
527+
fn insert_with(key: K, newval: V, ff: fn(V, V) -> V) -> bool {
528+
return self.insert_with_key(key, newval, |_k, v, v1| ff(v,v1));
529+
}
472530

473531
fn remove(key: K) -> bool {
474532
do self.borrow_mut |p| {
@@ -778,20 +836,30 @@ mod tests {
778836
fn test_insert_with_key() {
779837
let map = map::HashMap::<~str, uint>();
780838
781-
fn inc(k: ~str, v0: uint, v1: uint) -> uint {
839+
// given a new key, initialize it with this new count, given
840+
// given an existing key, add more to its count
841+
fn addMoreToCount(_k: ~str, v0: uint, v1: uint) -> uint {
842+
v0 + v1
843+
}
844+
845+
fn addMoreToCount_simple(v0: uint, v1: uint) -> uint {
782846
v0 + v1
783847
}
784848
785-
map.insert_with_key(inc, ~"cat", 1);
786-
map.insert_with_key(inc, ~"mongoose", 1);
787-
map.insert_with_key(inc, ~"cat", 7);
788-
map.insert_with_key(inc, ~"ferret", 3);
789-
map.insert_with_key(inc, ~"cat", 2);
849+
// count the number of several types of animal,
850+
// adding in groups as we go
851+
map.insert_with(~"cat", 1, addMoreToCount_simple);
852+
map.insert_with_key(~"mongoose", 1, addMoreToCount);
853+
map.insert_with(~"cat", 7, addMoreToCount_simple);
854+
map.insert_with_key(~"ferret", 3, addMoreToCount);
855+
map.insert_with_key(~"cat", 2, addMoreToCount);
790856

857+
// check the total counts
791858
assert 10 == option::get(map.find(~"cat"));
792859
assert 3 == option::get(map.find(~"ferret"));
793860
assert 1 == option::get(map.find(~"mongoose"));
794861

862+
// sadly, no mythical animals were counted!
795863
assert None == map.find(~"unicorn");
796864
}
797865
}

src/libstd/smallintmap.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,17 @@ impl<V: Copy> SmallIntMap<V>: map::Map<uint, V> {
103103
pure fn find(key: uint) -> Option<V> { find(self, key) }
104104
fn rehash() { fail }
105105

106-
fn insert_with_key(ff: fn(uint, V, V) -> V, key: uint, val: V) -> bool {
106+
fn insert_with_key(key: uint, val: V, ff: fn(uint, V, V) -> V) -> bool {
107107
match self.find(key) {
108108
None => return self.insert(key, val),
109109
Some(copy orig) => return self.insert(key, ff(key, orig, val)),
110110
}
111111
}
112112

113+
fn insert_with(key: uint, newval: V, ff: fn(V, V) -> V) -> bool {
114+
return self.insert_with_key(key, newval, |_k, v, v1| ff(v,v1));
115+
}
116+
113117
pure fn each(it: fn(key: uint, value: V) -> bool) {
114118
self.each_ref(|k, v| it(*k, *v))
115119
}
@@ -149,3 +153,37 @@ impl<V: Copy> SmallIntMap<V>: ops::Index<uint, V> {
149153
pub fn as_map<V: Copy>(s: SmallIntMap<V>) -> map::Map<uint, V> {
150154
s as map::Map::<uint, V>
151155
}
156+
157+
#[cfg(test)]
158+
mod tests {
159+
160+
#[test]
161+
fn test_insert_with_key() {
162+
let map: SmallIntMap<uint> = mk();
163+
164+
// given a new key, initialize it with this new count, given
165+
// given an existing key, add more to its count
166+
fn addMoreToCount(_k: uint, v0: uint, v1: uint) -> uint {
167+
v0 + v1
168+
}
169+
170+
fn addMoreToCount_simple(v0: uint, v1: uint) -> uint {
171+
v0 + v1
172+
}
173+
174+
// count integers
175+
map.insert_with(3, 1, addMoreToCount_simple);
176+
map.insert_with_key(9, 1, addMoreToCount);
177+
map.insert_with(3, 7, addMoreToCount_simple);
178+
map.insert_with_key(5, 3, addMoreToCount);
179+
map.insert_with_key(3, 2, addMoreToCount);
180+
181+
// check the total counts
182+
assert 10 == option::get(map.find(3));
183+
assert 3 == option::get(map.find(5));
184+
assert 1 == option::get(map.find(9));
185+
186+
// sadly, no sevens were counted
187+
assert None == map.find(7);
188+
}
189+
}

src/test/bench/shootout-k-nucleotide-pipes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ fn find(mm: HashMap<~[u8], uint>, key: ~str) -> uint {
6969
// given a map, increment the counter for a key
7070
fn update_freq(mm: HashMap<~[u8], uint>, key: &[u8]) {
7171
let key = vec::slice(key, 0, key.len());
72-
mm.insert_with_key(|k,v,v1| {v + v1}, key, 1);
72+
mm.insert_with(key, 1, |v,v1| { v+v1 });
7373
}
7474

7575
// given a ~[u8], for each window call a function

src/test/bench/shootout-k-nucleotide.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ fn find(mm: HashMap<~[u8], uint>, key: ~str) -> uint {
6666
// given a map, increment the counter for a key
6767
fn update_freq(mm: HashMap<~[u8], uint>, key: &[u8]) {
6868
let key = vec::slice(key, 0, key.len());
69-
mm.insert_with_key(|k,v,v1| {v + v1}, key, 1);
69+
mm.insert_with(key, 1, |v,v1| { v+v1 });
7070
}
7171

7272
// given a ~[u8], for each window call a function

src/test/run-pass/class-impl-very-parameterized-trait.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,20 @@ impl<T: Copy> cat<T> : Map<int, T> {
6161
else { None }
6262
}
6363

64-
fn insert_with_key(ff: fn(+k: int, +v0: T, +v1: T) -> T, +key: int, +val: T) -> bool {
64+
fn insert_with_key(+key: int, +val: T, ff: fn(+k: int, +v0: T, +v1: T) -> T) -> bool {
6565
match self.find(key) {
6666
None => return self.insert(key, val),
6767
Some(copy orig) => return self.insert(key, ff(key, orig, val))
6868
}
6969
}
7070

71+
fn insert_with(+key: int, +val: T, ff: fn(+v0: T, +v1: T) -> T) -> bool {
72+
match self.find(key) {
73+
None => return self.insert(key, val),
74+
Some(copy orig) => return self.insert(key, ff(orig, val))
75+
}
76+
}
77+
7178

7279
fn remove(+k:int) -> bool {
7380
match self.find(k) {

0 commit comments

Comments
 (0)