diff --git a/src/libstd/map.rs b/src/libstd/map.rs index 966991e8236..998fc55afe8 100644 --- a/src/libstd/map.rs +++ b/src/libstd/map.rs @@ -69,6 +69,8 @@ iface map { // FIXME: package this up and export it as a datatype usable for // external code that doesn't want to pay the cost of a box. (#2344) mod chained { + export t, mk, hashmap; + type entry = { hash: uint, key: K, @@ -94,186 +96,172 @@ mod chained { found_after(@entry, @entry) } - fn search_rem( - tbl: t, k: K, h: uint, idx: uint, - e_root: @entry) -> search_result { - let mut e0 = e_root; - let mut comp = 1u; // for logging - loop { - alt e0.next { - absent { - #debug("search_tbl: absent, comp %u, hash %u, idx %u", - comp, h, idx); - ret not_found; - } - present(e1) { - comp += 1u; - let e1_key = e1.key; // Satisfy alias checker. - if e1.hash == h && tbl.eqer(e1_key, k) { - #debug("search_tbl: present, comp %u, hash %u, idx %u", - comp, h, idx); - ret found_after(e0, e1); - } else { - e0 = e1; - } - } - } - }; - } - - fn search_tbl( - tbl: t, k: K, h: uint) -> search_result { - let idx = h % vec::len(tbl.chains); - alt tbl.chains[idx] { - absent { - #debug("search_tbl: absent, comp %u, hash %u, idx %u", - 0u, h, idx); - ret not_found; - } - present(e) { - // FIXME: This copy of the key is not good for perf - if e.hash == h && tbl.eqer(copy e.key, k) { - #debug("search_tbl: present, comp %u, hash %u, idx %u", - 1u, h, idx); - ret found_first(idx, e); - } else { - ret search_rem(tbl, k, h, idx, e); - } - } - } - } - - fn insert(tbl: t, k: K, v: V) -> bool { - let hash = tbl.hasher(k); - alt search_tbl(tbl, k, hash) { - not_found { - tbl.count += 1u; - let idx = hash % vec::len(tbl.chains); - let old_chain = tbl.chains[idx]; - tbl.chains[idx] = present(@{ - hash: hash, - key: k, - mut value: v, - mut next: old_chain}); - ret true; - } - found_first(_, entry) { - entry.value = v; - ret false; - } - found_after(_, entry) { - entry.value = v; - ret false - } - } - } - - fn get(tbl: t, k: K) -> core::option { - alt search_tbl(tbl, k, tbl.hasher(k)) { - not_found { - ret core::option::none; - } - - found_first(_, entry) { - ret core::option::some(entry.value); - } - - found_after(_, entry) { - ret core::option::some(entry.value); - } - } - } - - fn remove(tbl: t, k: K) -> core::option { - alt search_tbl(tbl, k, tbl.hasher(k)) { - not_found { - ret core::option::none; - } - - found_first(idx, entry) { - tbl.count -= 1u; - tbl.chains[idx] = entry.next; - ret core::option::some(entry.value); - } - - found_after(eprev, entry) { - tbl.count -= 1u; - eprev.next = entry.next; - ret core::option::some(entry.value); - } - } - } - - fn chains(nchains: uint) -> [mut chain] { - ret vec::to_mut(vec::from_elem(nchains, absent)); - } - - fn each_entry(tbl: t, - blk: fn(@entry) -> bool) { - let mut i = 0u, n = vec::len(tbl.chains); - while i < n { - let mut chain = tbl.chains[i]; + impl private_methods for t { + fn search_rem(k: K, h: uint, idx: uint, + e_root: @entry) -> search_result { + let mut e0 = e_root; + let mut comp = 1u; // for logging loop { - chain = alt chain { - absent { break; } - present(entry) { - let next = entry.next; - if !blk(entry) { ret; } - next + alt e0.next { + absent { + #debug("search_tbl: absent, comp %u, hash %u, idx %u", + comp, h, idx); + ret not_found; + } + present(e1) { + comp += 1u; + let e1_key = e1.key; // Satisfy alias checker. + if e1.hash == h && self.eqer(e1_key, k) { + #debug("search_tbl: present, comp %u, \ + hash %u, idx %u", + comp, h, idx); + ret found_after(e0, e1); + } else { + e0 = e1; + } } } + }; + } + + fn search_tbl(k: K, h: uint) -> search_result { + let idx = h % vec::len(self.chains); + alt self.chains[idx] { + absent { + #debug("search_tbl: absent, comp %u, hash %u, idx %u", + 0u, h, idx); + ret not_found; + } + present(e) { + // FIXME: This copy of the key is not good for perf + if e.hash == h && self.eqer(copy e.key, k) { + #debug("search_tbl: present, comp %u, hash %u, idx %u", + 1u, h, idx); + ret found_first(idx, e); + } else { + ret self.search_rem(k, h, idx, e); + } + } } - i += 1u; } - } - fn rehash(tbl: t) { - let n_old_chains = vec::len(tbl.chains); - let n_new_chains: uint = uint::next_power_of_two(n_old_chains + 1u); - let new_chains = chains(n_new_chains); - for each_entry(tbl) {|entry| - let idx = entry.hash % n_new_chains; - entry.next = new_chains[idx]; - new_chains[idx] = present(entry); + fn rehash() { + let n_old_chains = vec::len(self.chains); + let n_new_chains: uint = uint::next_power_of_two(n_old_chains+1u); + let new_chains = chains(n_new_chains); + for self.each_entry {|entry| + let idx = entry.hash % n_new_chains; + entry.next = new_chains[idx]; + new_chains[idx] = present(entry); + } + self.chains = new_chains; } - tbl.chains = new_chains; - } - fn each(tbl: t, blk: fn(K,V) -> bool) { - for each_entry(tbl) {|entry| - if !blk(copy entry.key, copy entry.value) { break; } + fn each_entry(blk: fn(@entry) -> bool) { + let mut i = 0u, n = vec::len(self.chains); + while i < n { + let mut chain = self.chains[i]; + loop { + chain = alt chain { + absent { break; } + present(entry) { + let next = entry.next; + if !blk(entry) { ret; } + next + } + } + } + i += 1u; + } } } impl hashmap of map for t { fn size() -> uint { self.count } + fn contains_key(k: K) -> bool { + let hash = self.hasher(k); + alt self.search_tbl(k, hash) { + not_found {false} + found_first(*) | found_after(*) {true} + } + } + fn insert(k: K, v: V) -> bool { - let grew = insert(self, k, v); - if grew { + let hash = self.hasher(k); + alt self.search_tbl(k, hash) { + not_found { + self.count += 1u; + let idx = hash % vec::len(self.chains); + let old_chain = self.chains[idx]; + self.chains[idx] = present(@{ + hash: hash, + key: k, + mut value: v, + mut next: old_chain}); + + // consider rehashing if more 3/4 full let nchains = vec::len(self.chains); let load = {num: (self.count + 1u) as int, den: nchains as int}; - // Structural consts would be nice. This is a const 3/4 - // load factor that we compare against. - if !util::rational_leq(load, {num:3, den:4}) { rehash(self); } + if !util::rational_leq(load, {num:3, den:4}) { + self.rehash(); + } + + ret true; + } + found_first(_, entry) { + entry.value = v; + ret false; + } + found_after(_, entry) { + entry.value = v; + ret false + } } - grew } - fn contains_key(k: K) -> bool { option::is_some(get(self, k)) } + fn find(k: K) -> option { + alt self.search_tbl(k, self.hasher(k)) { + not_found {none} + found_first(_, entry) {some(entry.value)} + found_after(_, entry) {some(entry.value)} + } + } - fn get(k: K) -> V { option::get(get(self, k)) } + fn get(k: K) -> V { + option::get(self.find(k)) + } - fn find(k: K) -> option { get(self, k) } + fn remove(k: K) -> option { + alt self.search_tbl(k, self.hasher(k)) { + not_found {none} + found_first(idx, entry) { + self.count -= 1u; + self.chains[idx] = entry.next; + some(entry.value) + } + found_after(eprev, entry) { + self.count -= 1u; + eprev.next = entry.next; + some(entry.value) + } + } + } - fn remove(k: K) -> option { remove(self, k) } + fn each(blk: fn(K,V) -> bool) { + for self.each_entry { |entry| + if !blk(copy entry.key, copy entry.value) { break; } + } + } - fn each(blk: fn(K, V) -> bool) { each(self, blk); } + fn each_key(blk: fn(K) -> bool) { self.each { |k, _v| blk(k)} } - fn each_key(blk: fn(K) -> bool) { each(self) { |k, _v| blk(k)} } + fn each_value(blk: fn(V) -> bool) { self.each { |_k, v| blk(v)} } + } - fn each_value(blk: fn(V) -> bool) { each(self) { |_k, v| blk(v)} } + fn chains(nchains: uint) -> [mut chain] { + ret vec::to_mut(vec::from_elem(nchains, absent)); } fn mk(hasher: hashfn, eqer: eqfn) -> t {