2011-07-05 04:48:19 -05:00
|
|
|
// An "interner" is a data structure that associates values with uint tags and
|
|
|
|
// allows bidirectional lookup; i.e. given a value, one can easily find the
|
|
|
|
// type, and vice versa.
|
2011-07-06 13:26:26 -05:00
|
|
|
import std::vec;
|
2011-07-05 04:48:19 -05:00
|
|
|
import std::map;
|
|
|
|
import std::map::hashmap;
|
|
|
|
import std::map::hashfn;
|
|
|
|
import std::map::eqfn;
|
|
|
|
import std::option;
|
|
|
|
import std::option::none;
|
|
|
|
import std::option::some;
|
|
|
|
|
|
|
|
type interner[T] =
|
|
|
|
rec(hashmap[T, uint] map,
|
2011-07-06 13:26:26 -05:00
|
|
|
mutable vec[T] vect,
|
2011-07-05 04:48:19 -05:00
|
|
|
hashfn[T] hasher,
|
|
|
|
eqfn[T] eqer);
|
|
|
|
|
|
|
|
fn mk[T](hashfn[T] hasher, eqfn[T] eqer) -> interner[T] {
|
|
|
|
auto m = map::mk_hashmap[T, uint](hasher, eqer);
|
2011-07-06 13:26:26 -05:00
|
|
|
let vec[T] vect = [];
|
|
|
|
ret rec(map=m, mutable vect=vect, hasher=hasher, eqer=eqer);
|
2011-07-05 04:48:19 -05:00
|
|
|
}
|
|
|
|
fn intern[T](&interner[T] itr, &T val) -> uint {
|
|
|
|
alt (itr.map.find(val)) {
|
|
|
|
case (some(?idx)) { ret idx; }
|
|
|
|
case (none) {
|
2011-07-06 13:26:26 -05:00
|
|
|
auto new_idx = vec::len[T](itr.vect);
|
2011-07-05 04:48:19 -05:00
|
|
|
itr.map.insert(val, new_idx);
|
2011-07-06 13:26:26 -05:00
|
|
|
itr.vect += [val];
|
2011-07-05 04:48:19 -05:00
|
|
|
ret new_idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn get[T](&interner[T] itr, uint idx) -> T { ret itr.vect.(idx); }
|