oldmap.rs 21.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11
//! A map type - **deprecated**, use `core::hashmap` instead
12
#[forbid(deprecated_mode)];
13

14
use core::container::{Container, Mutable, Map};
P
Patrick Walton 已提交
15
use core::cmp::Eq;
16 17 18 19 20 21
use core::hash::Hash;
use core::io::WriterUtil;
use core::io;
use core::ops;
use core::to_str::ToStr;
use core::mutable::Mut;
22
use core::prelude::*;
23 24 25
use core::to_bytes::IterBytes;
use core::uint;
use core::vec;
26

27
/// A convenience type to treat a hashmap as a set
28
pub type Set<K> = HashMap<K, ()>;
29

30
pub type HashMap<K, V> = chained::T<K, V>;
31

32
pub mod util {
33 34 35 36 37
    pub struct Rational {
        // : int::positive(*.den);
        num: int,
        den: int,
    }
B
Ben Blum 已提交
38

39
    pub pure fn rational_leq(x: Rational, y: Rational) -> bool {
B
Ben Blum 已提交
40 41 42 43 44 45 46
        // NB: Uses the fact that rationals have positive denominators WLOG:

        x.num * y.den <= y.num * x.den
    }
}


47 48
// FIXME (#2344): package this up and export it as a datatype usable for
// external code that doesn't want to pay the cost of a box.
49
pub mod chained {
50
    use super::util;
51 52 53 54

    use core::io;
    use core::ops;
    use core::option;
55
    use core::prelude::*;
56 57
    use core::uint;
    use core::vec;
N
Niko Matsakis 已提交
58

G
Glenn Willen 已提交
59 60
    const initial_capacity: uint = 32u; // 2^5

B
Brian Anderson 已提交
61
    struct Entry<K, V> {
62 63 64
        hash: uint,
        key: K,
        value: V,
B
Brian Anderson 已提交
65
        mut next: Option<@Entry<K, V>>
N
Niko Matsakis 已提交
66 67
    }

68
    struct HashMap_<K, V> {
69
        mut count: uint,
B
Brian Anderson 已提交
70
        mut chains: ~[mut Option<@Entry<K,V>>]
71 72
    }

73
    pub type T<K, V> = @HashMap_<K, V>;
74

B
Brian Anderson 已提交
75 76 77 78
    enum SearchResult<K, V> {
        NotFound,
        FoundFirst(uint, @Entry<K,V>),
        FoundAfter(@Entry<K,V>, @Entry<K,V>)
N
Niko Matsakis 已提交
79 80
    }

B
Brian Anderson 已提交
81
    priv impl<K:Eq IterBytes Hash, V: Copy> T<K, V> {
82
        pure fn search_rem(k: &K, h: uint, idx: uint,
B
Brian Anderson 已提交
83
                           e_root: @Entry<K,V>) -> SearchResult<K,V> {
N
Niko Matsakis 已提交
84 85 86
            let mut e0 = e_root;
            let mut comp = 1u;   // for logging
            loop {
87
                match copy e0.next {
B
Brian Anderson 已提交
88
                  None => {
P
Paul Stansifer 已提交
89 90
                    debug!("search_tbl: absent, comp %u, hash %u, idx %u",
                           comp, h, idx);
B
Brian Anderson 已提交
91
                    return NotFound;
N
Niko Matsakis 已提交
92
                  }
B
Brian Anderson 已提交
93
                  Some(e1) => {
N
Niko Matsakis 已提交
94
                    comp += 1u;
95
                    unsafe {
96
                        if e1.hash == h && e1.key == *k {
97 98 99
                            debug!("search_tbl: present, comp %u, \
                                    hash %u, idx %u",
                                   comp, h, idx);
B
Brian Anderson 已提交
100
                            return FoundAfter(e0, e1);
101 102 103
                        } else {
                            e0 = e1;
                        }
N
Niko Matsakis 已提交
104 105 106 107 108 109
                    }
                  }
                }
            };
        }

B
Brian Anderson 已提交
110
        pure fn search_tbl(k: &K, h: uint) -> SearchResult<K,V> {
N
Niko Matsakis 已提交
111
            let idx = h % vec::len(self.chains);
112
            match copy self.chains[idx] {
B
Brian Anderson 已提交
113
              None => {
P
Paul Stansifer 已提交
114 115
                debug!("search_tbl: none, comp %u, hash %u, idx %u",
                       0u, h, idx);
B
Brian Anderson 已提交
116
                return NotFound;
N
Niko Matsakis 已提交
117
              }
B
Brian Anderson 已提交
118
              Some(e) => {
119
                unsafe {
120
                    if e.hash == h && e.key == *k {
121 122
                        debug!("search_tbl: present, comp %u, hash %u, \
                                idx %u", 1u, h, idx);
B
Brian Anderson 已提交
123
                        return FoundFirst(idx, e);
124 125 126
                    } else {
                        return self.search_rem(k, h, idx, e);
                    }
N
Niko Matsakis 已提交
127 128 129 130 131
                }
              }
            }
        }

N
Niko Matsakis 已提交
132
        fn rehash() {
133
            let n_old_chains = self.chains.len();
N
Niko Matsakis 已提交
134 135
            let n_new_chains: uint = uint::next_power_of_two(n_old_chains+1u);
            let new_chains = chains(n_new_chains);
B
Brian Anderson 已提交
136
            for self.each_entry |entry| {
N
Niko Matsakis 已提交
137 138
                let idx = entry.hash % n_new_chains;
                entry.next = new_chains[idx];
B
Brian Anderson 已提交
139
                new_chains[idx] = Some(entry);
N
Niko Matsakis 已提交
140
            }
141
            self.chains = move new_chains;
N
Niko Matsakis 已提交
142 143
        }

B
Brian Anderson 已提交
144
        pure fn each_entry(blk: fn(@Entry<K,V>) -> bool) {
145 146 147
            // n.b. we can't use vec::iter() here because self.chains
            // is stored in a mutable location.
            let mut i = 0u, n = self.chains.len();
N
Niko Matsakis 已提交
148 149 150
            while i < n {
                let mut chain = self.chains[i];
                loop {
151
                    chain = match chain {
B
Brian Anderson 已提交
152 153
                      None => break,
                      Some(entry) => {
N
Niko Matsakis 已提交
154
                        let next = entry.next;
B
Brian Anderson 已提交
155
                        if !blk(entry) { return; }
N
Niko Matsakis 已提交
156 157 158
                        next
                      }
                    }
159
                }
N
Niko Matsakis 已提交
160
                i += 1u;
161
            }
N
Niko Matsakis 已提交
162 163 164
        }
    }

165 166 167 168
    impl<K: Eq IterBytes Hash, V> T<K, V>: Container {
        pure fn len(&self) -> uint { self.count }
        pure fn is_empty(&self) -> bool { self.count == 0 }
    }
N
Niko Matsakis 已提交
169

170 171 172 173 174 175 176
    impl<K: Eq IterBytes Hash, V> T<K, V>: Mutable {
        fn clear(&mut self) {
            self.count = 0u;
            self.chains = chains(initial_capacity);
        }
    }

177
    impl<K:Eq IterBytes Hash Copy, V: Copy> T<K, V> {
178
        pure fn contains_key_ref(k: &K) -> bool {
179
            let hash = k.hash_keyed(0,0) as uint;
180
            match self.search_tbl(k, hash) {
B
Brian Anderson 已提交
181 182
              NotFound => false,
              FoundFirst(*) | FoundAfter(*) => true
N
Niko Matsakis 已提交
183 184 185
            }
        }

186
        fn insert(k: K, v: V) -> bool {
187
            let hash = k.hash_keyed(0,0) as uint;
188
            match self.search_tbl(&k, hash) {
B
Brian Anderson 已提交
189
              NotFound => {
N
Niko Matsakis 已提交
190 191 192
                self.count += 1u;
                let idx = hash % vec::len(self.chains);
                let old_chain = self.chains[idx];
B
Brian Anderson 已提交
193
                self.chains[idx] = Some(@Entry {
N
Niko Matsakis 已提交
194 195
                    hash: hash,
                    key: k,
196 197
                    value: v,
                    next: old_chain});
N
Niko Matsakis 已提交
198 199

                // consider rehashing if more 3/4 full
200
                let nchains = vec::len(self.chains);
201 202 203 204 205
                let load = util::Rational {
                    num: (self.count + 1u) as int,
                    den: nchains as int,
                };
                if !util::rational_leq(load, util::Rational {num:3, den:4}) {
N
Niko Matsakis 已提交
206 207 208
                    self.rehash();
                }

B
Brian Anderson 已提交
209
                return true;
N
Niko Matsakis 已提交
210
              }
B
Brian Anderson 已提交
211 212
              FoundFirst(idx, entry) => {
                self.chains[idx] = Some(@Entry {
213 214 215 216
                    hash: hash,
                    key: k,
                    value: v,
                    next: entry.next});
B
Brian Anderson 已提交
217
                return false;
N
Niko Matsakis 已提交
218
              }
B
Brian Anderson 已提交
219 220
              FoundAfter(prev, entry) => {
                prev.next = Some(@Entry {
221 222 223 224 225
                    hash: hash,
                    key: k,
                    value: v,
                    next: entry.next});
                return false;
N
Niko Matsakis 已提交
226
              }
227
            }
N
Niko Matsakis 已提交
228 229
        }

T
Tim Chevalier 已提交
230
        pure fn find(k: K) -> Option<V> {
231
            unsafe {
232
                match self.search_tbl(&k, k.hash_keyed(0,0) as uint) {
B
Brian Anderson 已提交
233 234 235
                  NotFound => None,
                  FoundFirst(_, entry) => Some(entry.value),
                  FoundAfter(_, entry) => Some(entry.value)
236
                }
N
Niko Matsakis 已提交
237 238
            }
        }
N
Niko Matsakis 已提交
239

240
        fn update_with_key(key: K, newval: V, ff: fn(K, V, V) -> V) -> bool {
K
Kevin Cantu 已提交
241
/*
242 243 244 245
            match self.find(key) {
                None            => return self.insert(key, val),
                Some(copy orig) => return self.insert(key, ff(key, orig, val))
            }
K
Kevin Cantu 已提交
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
*/

            let hash = key.hash_keyed(0,0) as uint;
            match self.search_tbl(&key, hash) {
              NotFound => {
                self.count += 1u;
                let idx = hash % vec::len(self.chains);
                let old_chain = self.chains[idx];
                self.chains[idx] = Some(@Entry {
                    hash: hash,
                    key: key,
                    value: newval,
                    next: old_chain});

                // consider rehashing if more 3/4 full
                let nchains = vec::len(self.chains);
262 263 264 265 266
                let load = util::Rational {
                    num: (self.count + 1u) as int,
                    den: nchains as int,
                };
                if !util::rational_leq(load, util::Rational {num:3, den:4}) {
K
Kevin Cantu 已提交
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
                    self.rehash();
                }

                return true;
              }
              FoundFirst(idx, entry) => {
                self.chains[idx] = Some(@Entry {
                    hash: hash,
                    key: key,
                    value: ff(key, entry.value, newval),
                    next: entry.next});
                return false;
              }
              FoundAfter(prev, entry) => {
                prev.next = Some(@Entry {
                    hash: hash,
                    key: key,
                    value: ff(key, entry.value, newval),
                    next: entry.next});
                return false;
              }
            }
        }

291 292
        fn update(key: K, newval: V, ff: fn(V, V) -> V) -> bool {
            return self.update_with_key(key, newval, |_k, v, v1| ff(v,v1));
293 294
        }

295
        pure fn get(k: K) -> V {
296 297
            let opt_v = self.find(k);
            if opt_v.is_none() {
298
                die!(fmt!("Key not found in table: %?", k));
299
            }
T
Tim Chevalier 已提交
300
            option::unwrap(move opt_v)
N
Niko Matsakis 已提交
301
        }
N
Niko Matsakis 已提交
302

T
Tim Chevalier 已提交
303
        fn remove(k: K) -> bool {
304
            match self.search_tbl(&k, k.hash_keyed(0,0) as uint) {
B
Brian Anderson 已提交
305 306
              NotFound => false,
              FoundFirst(idx, entry) => {
N
Niko Matsakis 已提交
307 308
                self.count -= 1u;
                self.chains[idx] = entry.next;
309
                true
N
Niko Matsakis 已提交
310
              }
B
Brian Anderson 已提交
311
              FoundAfter(eprev, entry) => {
N
Niko Matsakis 已提交
312 313
                self.count -= 1u;
                eprev.next = entry.next;
314
                true
N
Niko Matsakis 已提交
315 316 317
              }
            }
        }
N
Niko Matsakis 已提交
318

319
        pure fn each(blk: fn(key: K, value: V) -> bool) {
320 321 322
            self.each_ref(|k, v| blk(*k, *v))
        }

T
Tim Chevalier 已提交
323
        pure fn each_key(blk: fn(key: K) -> bool) {
324 325 326
            self.each_key_ref(|p| blk(*p))
        }

327
        pure fn each_ref(blk: fn(key: &K, value: &V) -> bool) {
B
Brian Anderson 已提交
328
            for self.each_entry |entry| {
329
                if !blk(&entry.key, &entry.value) { break; }
N
Niko Matsakis 已提交
330 331
            }
        }
N
Niko Matsakis 已提交
332

333
        pure fn each_key_ref(blk: fn(key: &K) -> bool) {
334 335
            self.each_ref(|k, _v| blk(k))
        }
N
Niko Matsakis 已提交
336

337
        pure fn each_value_ref(blk: fn(value: &V) -> bool) {
338 339
            self.each_ref(|_k, v| blk(v))
        }
N
Niko Matsakis 已提交
340
    }
N
Niko Matsakis 已提交
341

342
    impl<K:Eq IterBytes Hash Copy ToStr, V: ToStr Copy> T<K, V> {
343
        fn to_writer(wr: io::Writer) {
G
Glenn Willen 已提交
344
            if self.count == 0u {
345
                wr.write_str(~"{}");
B
Brian Anderson 已提交
346
                return;
G
Glenn Willen 已提交
347 348
            }

349
            wr.write_str(~"{ ");
G
Glenn Willen 已提交
350 351 352
            let mut first = true;
            for self.each_entry |entry| {
                if !first {
353
                    wr.write_str(~", ");
G
Glenn Willen 已提交
354 355 356
                }
                first = false;
                wr.write_str(entry.key.to_str());
357
                wr.write_str(~": ");
G
Glenn Willen 已提交
358 359
                wr.write_str((copy entry.value).to_str());
            };
360
            wr.write_str(~" }");
G
Glenn Willen 已提交
361
        }
362
    }
G
Glenn Willen 已提交
363

364
    impl<K:Eq IterBytes Hash Copy ToStr, V: ToStr Copy> T<K, V>: ToStr {
365 366 367 368 369
        pure fn to_str() -> ~str {
            unsafe {
                // Meh -- this should be safe
                do io::with_str_writer |wr| { self.to_writer(wr) }
            }
G
Glenn Willen 已提交
370 371 372
        }
    }

373 374 375 376 377 378 379
    impl<K:Eq IterBytes Hash Copy, V: Copy> T<K, V>: ops::Index<K, V> {
        pure fn index(&self, k: K) -> V {
            unsafe {
                self.get(k)
            }
        }
    }
380

B
Brian Anderson 已提交
381
    fn chains<K,V>(nchains: uint) -> ~[mut Option<@Entry<K,V>>] {
382
        vec::cast_to_mut(vec::from_elem(nchains, None))
N
Niko Matsakis 已提交
383 384
    }

385
    pub fn mk<K:Eq IterBytes Hash, V: Copy>() -> T<K,V> {
B
Brian Anderson 已提交
386
        let slf: T<K, V> = @HashMap_ {count: 0u,
387
                                      chains: chains(initial_capacity)};
388
        slf
N
Niko Matsakis 已提交
389 390 391
    }
}

N
Niko Matsakis 已提交
392
/*
393
Function: hashmap
N
Niko Matsakis 已提交
394 395 396

Construct a hashmap.
*/
397
pub fn HashMap<K:Eq IterBytes Hash Const, V: Copy>()
B
Brian Anderson 已提交
398
        -> HashMap<K, V> {
399
    chained::mk()
N
Niko Matsakis 已提交
400 401
}

402
/// Convenience function for adding keys to a hashmap with nil type keys
T
Tim Chevalier 已提交
403
pub fn set_add<K:Eq IterBytes Hash Const Copy>(set: Set<K>, key: K) -> bool {
404
    set.insert(key, ())
E
Eric Holk 已提交
405
}
406

407
/// Convert a set into a vector.
P
Patrick Walton 已提交
408
pub pure fn vec_from_set<T:Eq IterBytes Hash Copy>(s: Set<T>) -> ~[T] {
409
    do vec::build_sized(s.len()) |push| {
410 411 412 413
        for s.each_key() |k| {
            push(k);
        }
    }
414 415
}

416
/// Construct a hashmap from a vector
417
pub fn hash_from_vec<K: Eq IterBytes Hash Const Copy, V: Copy>(
B
Brian Anderson 已提交
418 419
    items: &[(K, V)]) -> HashMap<K, V> {
    let map = HashMap();
420 421
    for vec::each(items) |item| {
        match *item {
422
            (copy key, copy value) => {
423 424 425
                map.insert(key, value);
            }
        }
426 427 428 429
    }
    map
}

430 431
#[cfg(test)]
mod tests {
432
    use core::option::None;
433 434
    use core::option;
    use core::uint;
435

436 437
    use super::*;

438 439
    #[test]
    fn test_simple() {
P
Paul Stansifer 已提交
440
        debug!("*** starting test_simple");
441 442
        pure fn eq_uint(x: &uint, y: &uint) -> bool { *x == *y }
        pure fn uint_id(x: &uint) -> uint { *x }
P
Paul Stansifer 已提交
443
        debug!("uint -> uint");
444 445
        let hm_uu: HashMap<uint, uint> =
            HashMap::<uint, uint>();
446 447 448 449 450 451 452 453 454 455
        assert (hm_uu.insert(10u, 12u));
        assert (hm_uu.insert(11u, 13u));
        assert (hm_uu.insert(12u, 14u));
        assert (hm_uu.get(11u) == 13u);
        assert (hm_uu.get(12u) == 14u);
        assert (hm_uu.get(10u) == 12u);
        assert (!hm_uu.insert(12u, 14u));
        assert (hm_uu.get(12u) == 14u);
        assert (!hm_uu.insert(12u, 12u));
        assert (hm_uu.get(12u) == 12u);
456 457 458
        let ten: ~str = ~"ten";
        let eleven: ~str = ~"eleven";
        let twelve: ~str = ~"twelve";
P
Paul Stansifer 已提交
459
        debug!("str -> uint");
460 461
        let hm_su: HashMap<~str, uint> =
            HashMap::<~str, uint>();
462
        assert (hm_su.insert(~"ten", 12u));
463
        assert (hm_su.insert(eleven, 13u));
464
        assert (hm_su.insert(~"twelve", 14u));
465
        assert (hm_su.get(eleven) == 13u);
466 467 468 469 470 471 472
        assert (hm_su.get(~"eleven") == 13u);
        assert (hm_su.get(~"twelve") == 14u);
        assert (hm_su.get(~"ten") == 12u);
        assert (!hm_su.insert(~"twelve", 14u));
        assert (hm_su.get(~"twelve") == 14u);
        assert (!hm_su.insert(~"twelve", 12u));
        assert (hm_su.get(~"twelve") == 12u);
P
Paul Stansifer 已提交
473
        debug!("uint -> str");
474 475
        let hm_us: HashMap<uint, ~str> =
            HashMap::<uint, ~str>();
476 477 478
        assert (hm_us.insert(10u, ~"twelve"));
        assert (hm_us.insert(11u, ~"thirteen"));
        assert (hm_us.insert(12u, ~"fourteen"));
479 480 481
        assert hm_us.get(11u) == ~"thirteen";
        assert hm_us.get(12u) == ~"fourteen";
        assert hm_us.get(10u) == ~"twelve";
482
        assert (!hm_us.insert(12u, ~"fourteen"));
483
        assert hm_us.get(12u) == ~"fourteen";
484
        assert (!hm_us.insert(12u, ~"twelve"));
485
        assert hm_us.get(12u) == ~"twelve";
P
Paul Stansifer 已提交
486
        debug!("str -> str");
487 488
        let hm_ss: HashMap<~str, ~str> =
            HashMap::<~str, ~str>();
489 490 491
        assert (hm_ss.insert(ten, ~"twelve"));
        assert (hm_ss.insert(eleven, ~"thirteen"));
        assert (hm_ss.insert(twelve, ~"fourteen"));
492 493 494
        assert hm_ss.get(~"eleven") == ~"thirteen";
        assert hm_ss.get(~"twelve") == ~"fourteen";
        assert hm_ss.get(~"ten") == ~"twelve";
495
        assert (!hm_ss.insert(~"twelve", ~"fourteen"));
496
        assert hm_ss.get(~"twelve") == ~"fourteen";
497
        assert (!hm_ss.insert(~"twelve", ~"twelve"));
498
        assert hm_ss.get(~"twelve") == ~"twelve";
P
Paul Stansifer 已提交
499
        debug!("*** finished test_simple");
500 501 502 503 504 505 506 507
    }


    /**
    * Force map growth
    */
    #[test]
    fn test_growth() {
P
Paul Stansifer 已提交
508
        debug!("*** starting test_growth");
509
        let num_to_insert: uint = 64u;
510 511
        pure fn eq_uint(x: &uint, y: &uint) -> bool { *x == *y }
        pure fn uint_id(x: &uint) -> uint { *x }
P
Paul Stansifer 已提交
512
        debug!("uint -> uint");
513 514
        let hm_uu: HashMap<uint, uint> =
            HashMap::<uint, uint>();
515
        let mut i: uint = 0u;
516 517
        while i < num_to_insert {
            assert (hm_uu.insert(i, i * i));
P
Paul Stansifer 已提交
518
            debug!("inserting %u -> %u", i, i*i);
519 520
            i += 1u;
        }
P
Paul Stansifer 已提交
521
        debug!("-----");
522 523
        i = 0u;
        while i < num_to_insert {
P
Paul Stansifer 已提交
524
            debug!("get(%u) = %u", i, hm_uu.get(i));
525 526 527 528 529
            assert (hm_uu.get(i) == i * i);
            i += 1u;
        }
        assert (hm_uu.insert(num_to_insert, 17u));
        assert (hm_uu.get(num_to_insert) == 17u);
P
Paul Stansifer 已提交
530
        debug!("-----");
531 532
        i = 0u;
        while i < num_to_insert {
P
Paul Stansifer 已提交
533
            debug!("get(%u) = %u", i, hm_uu.get(i));
534 535 536
            assert (hm_uu.get(i) == i * i);
            i += 1u;
        }
P
Paul Stansifer 已提交
537
        debug!("str -> str");
538 539
        let hm_ss: HashMap<~str, ~str> =
            HashMap::<~str, ~str>();
540 541 542
        i = 0u;
        while i < num_to_insert {
            assert hm_ss.insert(uint::to_str(i, 2u), uint::to_str(i * i, 2u));
P
Paul Stansifer 已提交
543
            debug!("inserting \"%s\" -> \"%s\"",
544
                   uint::to_str(i, 2u),
P
Paul Stansifer 已提交
545
                   uint::to_str(i*i, 2u));
546 547
            i += 1u;
        }
P
Paul Stansifer 已提交
548
        debug!("-----");
549 550
        i = 0u;
        while i < num_to_insert {
P
Paul Stansifer 已提交
551
            debug!("get(\"%s\") = \"%s\"",
552
                   uint::to_str(i, 2u),
P
Paul Stansifer 已提交
553
                   hm_ss.get(uint::to_str(i, 2u)));
554
            assert hm_ss.get(uint::to_str(i, 2u)) == uint::to_str(i * i, 2u);
555 556 557 558
            i += 1u;
        }
        assert (hm_ss.insert(uint::to_str(num_to_insert, 2u),
                             uint::to_str(17u, 2u)));
559 560
        assert hm_ss.get(uint::to_str(num_to_insert, 2u)) ==
            uint::to_str(17u, 2u);
P
Paul Stansifer 已提交
561
        debug!("-----");
562 563
        i = 0u;
        while i < num_to_insert {
P
Paul Stansifer 已提交
564
            debug!("get(\"%s\") = \"%s\"",
565
                   uint::to_str(i, 2u),
P
Paul Stansifer 已提交
566
                   hm_ss.get(uint::to_str(i, 2u)));
567
            assert hm_ss.get(uint::to_str(i, 2u)) == uint::to_str(i * i, 2u);
568 569
            i += 1u;
        }
P
Paul Stansifer 已提交
570
        debug!("*** finished test_growth");
571 572 573 574
    }

    #[test]
    fn test_removal() {
P
Paul Stansifer 已提交
575
        debug!("*** starting test_removal");
576
        let num_to_insert: uint = 64u;
577 578
        let hm: HashMap<uint, uint> =
            HashMap::<uint, uint>();
579
        let mut i: uint = 0u;
580 581
        while i < num_to_insert {
            assert (hm.insert(i, i * i));
P
Paul Stansifer 已提交
582
            debug!("inserting %u -> %u", i, i*i);
583 584
            i += 1u;
        }
585
        assert (hm.len() == num_to_insert);
P
Paul Stansifer 已提交
586 587
        debug!("-----");
        debug!("removing evens");
588 589 590
        i = 0u;
        while i < num_to_insert {
            let v = hm.remove(i);
591
            assert v;
592 593
            i += 2u;
        }
594
        assert (hm.len() == num_to_insert / 2u);
P
Paul Stansifer 已提交
595
        debug!("-----");
596 597
        i = 1u;
        while i < num_to_insert {
P
Paul Stansifer 已提交
598
            debug!("get(%u) = %u", i, hm.get(i));
599 600 601
            assert (hm.get(i) == i * i);
            i += 2u;
        }
P
Paul Stansifer 已提交
602
        debug!("-----");
603 604
        i = 1u;
        while i < num_to_insert {
P
Paul Stansifer 已提交
605
            debug!("get(%u) = %u", i, hm.get(i));
606 607 608
            assert (hm.get(i) == i * i);
            i += 2u;
        }
P
Paul Stansifer 已提交
609
        debug!("-----");
610 611 612
        i = 0u;
        while i < num_to_insert {
            assert (hm.insert(i, i * i));
P
Paul Stansifer 已提交
613
            debug!("inserting %u -> %u", i, i*i);
614 615
            i += 2u;
        }
616
        assert (hm.len() == num_to_insert);
P
Paul Stansifer 已提交
617
        debug!("-----");
618 619
        i = 0u;
        while i < num_to_insert {
P
Paul Stansifer 已提交
620
            debug!("get(%u) = %u", i, hm.get(i));
621 622 623
            assert (hm.get(i) == i * i);
            i += 1u;
        }
P
Paul Stansifer 已提交
624
        debug!("-----");
625
        assert (hm.len() == num_to_insert);
626 627
        i = 0u;
        while i < num_to_insert {
P
Paul Stansifer 已提交
628
            debug!("get(%u) = %u", i, hm.get(i));
629 630 631
            assert (hm.get(i) == i * i);
            i += 1u;
        }
P
Paul Stansifer 已提交
632
        debug!("*** finished test_removal");
633 634 635 636
    }

    #[test]
    fn test_contains_key() {
637
        let key = ~"k";
638
        let map = HashMap::<~str, ~str>();
639
        assert (!map.contains_key_ref(&key));
640
        map.insert(key, ~"val");
641
        assert (map.contains_key_ref(&key));
642 643 644 645
    }

    #[test]
    fn test_find() {
646
        let key = ~"k";
647
        let map = HashMap::<~str, ~str>();
B
Brian Anderson 已提交
648
        assert (option::is_none(&map.find(key)));
649
        map.insert(key, ~"val");
650
        assert (option::get(map.find(key)) == ~"val");
651
    }
652

G
Glenn Willen 已提交
653 654
    #[test]
    fn test_clear() {
655
        let key = ~"k";
656
        let mut map = HashMap::<~str, ~str>();
657
        map.insert(key, ~"val");
658
        assert (map.len() == 1);
659
        assert (map.contains_key_ref(&key));
G
Glenn Willen 已提交
660
        map.clear();
661
        assert (map.len() == 0);
662
        assert (!map.contains_key_ref(&key));
G
Glenn Willen 已提交
663 664
    }

665 666
    #[test]
    fn test_hash_from_vec() {
667
        let map = hash_from_vec(~[
668 669 670
            (~"a", 1),
            (~"b", 2),
            (~"c", 3)
671
        ]);
672
        assert map.len() == 3u;
673 674 675
        assert map.get(~"a") == 1;
        assert map.get(~"b") == 2;
        assert map.get(~"c") == 3;
676
    }
K
Kevin Cantu 已提交
677 678

    #[test]
679
    fn test_update_with_key() {
680
        let map = HashMap::<~str, uint>();
K
Kevin Cantu 已提交
681

K
Kevin Cantu 已提交
682 683 684 685 686 687 688
        // given a new key, initialize it with this new count, given
        // given an existing key, add more to its count
        fn addMoreToCount(_k: ~str, v0: uint, v1: uint) -> uint {
            v0 + v1
        }

        fn addMoreToCount_simple(v0: uint, v1: uint) -> uint {
K
Kevin Cantu 已提交
689 690 691
            v0 + v1
        }

K
Kevin Cantu 已提交
692 693
        // count the number of several types of animal,
        // adding in groups as we go
694 695 696 697 698
        map.update(~"cat",      1, addMoreToCount_simple);
        map.update_with_key(~"mongoose", 1, addMoreToCount);
        map.update(~"cat",      7, addMoreToCount_simple);
        map.update_with_key(~"ferret",   3, addMoreToCount);
        map.update_with_key(~"cat",      2, addMoreToCount);
K
Kevin Cantu 已提交
699

K
Kevin Cantu 已提交
700
        // check the total counts
K
Kevin Cantu 已提交
701 702 703 704
        assert 10 == option::get(map.find(~"cat"));
        assert  3 == option::get(map.find(~"ferret"));
        assert  1 == option::get(map.find(~"mongoose"));

K
Kevin Cantu 已提交
705
        // sadly, no mythical animals were counted!
K
Kevin Cantu 已提交
706 707
        assert None == map.find(~"unicorn");
    }
E
Erick Tryzelaar 已提交
708
}