Skip to content

Commit 085790a

Browse files
committed
More stdlib hashmap bits (plus some drive-by extras).
1 parent 7b91933 commit 085790a

File tree

3 files changed

+89
-34
lines changed

3 files changed

+89
-34
lines changed

src/lib/_int.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ fn ne(int x, int y) -> bool { ret x != y; }
1313
fn ge(int x, int y) -> bool { ret x >= y; }
1414
fn gt(int x, int y) -> bool { ret x > y; }
1515

16+
fn positive(int x) -> bool { ret x > 0; }
17+
fn negative(int x) -> bool { ret x < 0; }
18+
fn nonpositive(int x) -> bool { ret x <= 0; }
19+
fn nonnegative(int x) -> bool { ret x >= 0; }
20+
1621
iter range(mutable int lo, int hi) -> int {
1722
while (lo < hi) {
1823
put lo;

src/lib/map.rs

Lines changed: 76 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {
2626
let uint initial_capacity = 32u; // 2^5
2727
let util.rational load_factor = rec(num=3, den=4);
2828

29-
type bucket[V] = tag(nil(), deleted(), some(V));
29+
type bucket[K, V] = tag(nil(), deleted(), some(K, V));
30+
31+
fn make_buckets[K, V](uint nbkts) -> vec[mutable bucket[K, V]] {
32+
ret _vec.init_elt[mutable bucket[K, V]](nil[K, V](), nbkts);
33+
}
3034

3135
// Derive two hash functions from the one given by taking the upper
3236
// half and lower half of the uint bits. Our bucket probing
@@ -57,57 +61,93 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {
5761
ret hashl[K](hasher, nbkts, key) + i * hashr[K](hasher, nbkts, key);
5862
}
5963

64+
/**
65+
* We attempt to never call this with a full table. If we do, it
66+
* will fail.
67+
*/
68+
fn insert_common[K, V](hashfn[K] hasher,
69+
vec[mutable bucket[K, V]] bkts,
70+
uint nbkts,
71+
&K key,
72+
&V val)
73+
{
74+
let uint i = 0u;
75+
while (i < nbkts) {
76+
// FIXME (issue #94): as in find_common()
77+
let int j = (hash[K](hasher, nbkts, key, i)) as int;
78+
alt (bkts.(j)) {
79+
case (some[K, V](_, _)) {
80+
i += 1u;
81+
}
82+
case (_) {
83+
bkts.(j) = some[K, V](key, val);
84+
ret;
85+
}
86+
}
87+
}
88+
fail; // full table
89+
}
90+
6091
fn find_common[K, V](hashfn[K] hasher,
61-
vec[mutable bucket[V]] bkts,
92+
vec[mutable bucket[K, V]] bkts,
6293
uint nbkts,
6394
&K key)
6495
-> util.option[V]
6596
{
6697
let uint i = 0u;
6798
while (i < nbkts) {
68-
// Pending fix to issue #94, remove uint coercion.
99+
// FIXME (issue #94): Pending bugfix, remove uint coercion.
69100
let int j = (hash[K](hasher, nbkts, key, i)) as int;
70101
alt (bkts.(j)) {
71-
case (some[V](val)) {
102+
case (some[K, V](_, val)) {
72103
ret util.some[V](val);
73104
}
74-
case (nil[V]()) {
105+
case (nil[K, V]()) {
75106
ret util.none[V]();
76107
}
77-
case (deleted[V]()) {
108+
case (deleted[K, V]()) {
78109
i += 1u;
79110
}
80111
}
81112
}
82113
ret util.none[V]();
83114
}
84115

116+
117+
fn rehash[K, V](hashfn[K] hasher,
118+
vec[mutable bucket[K, V]] oldbkts, uint noldbkts,
119+
vec[mutable bucket[K, V]] newbkts, uint nnewbkts)
120+
{
121+
for (bucket[K, V] b in oldbkts) {
122+
alt (b) {
123+
case (some[K, V](k, v)) {
124+
insert_common[K, V](hasher, newbkts, nnewbkts, k, v);
125+
}
126+
case (_) { }
127+
}
128+
}
129+
}
130+
85131
obj hashmap[K, V](hashfn[K] hasher,
86132
eqfn[K] eqer,
87-
mutable vec[mutable bucket[V]] bkts,
133+
mutable vec[mutable bucket[K, V]] bkts,
88134
mutable uint nbkts,
89135
mutable uint nelts,
90136
util.rational lf)
91137
{
92138
fn insert(&K key, &V val) {
93-
// FIXME grow the table and rehash if we ought to.
94-
let uint i = 0u;
95-
while (i < nbkts) {
96-
// Issue #94, as in find_common()
97-
let int j = (hash[K](hasher, nbkts, key, i)) as int;
98-
alt (bkts.(j)) {
99-
case (some[V](_)) {
100-
i += 1u;
101-
}
102-
case (_) {
103-
bkts.(j) = some[V](val);
104-
nelts += 1u;
105-
ret;
106-
}
107-
}
139+
let util.rational load = rec(num=(nelts + 1u) as int, den=nbkts as int);
140+
if (!util.rational_leq(load, lf)) {
141+
let uint nnewbkts = _int.next_power_of_two(nbkts + 1u);
142+
143+
// FIXME (issue #94): Enforce our workaround to issue #94.
144+
check ((nnewbkts as int) > 0);
145+
146+
let vec[mutable bucket[K, V]] newbkts = make_buckets[K, V](nnewbkts);
147+
rehash[K, V](hasher, bkts, nbkts, newbkts, nnewbkts);
108148
}
109-
// full table, impossible unless growth is broken. remove after testing.
110-
fail;
149+
insert_common[K, V](hasher, bkts, nbkts, key, val);
150+
nelts += 1u;
111151
}
112152

113153
fn contains_key(&K key) -> bool {
@@ -131,29 +171,32 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] {
131171
fn remove(&K key) -> util.option[V] {
132172
let uint i = 0u;
133173
while (i < nbkts) {
134-
// Issue #94, as in find_common()
174+
// FIXME (issue #94): as in find_common()
135175
let int j = (hash[K](hasher, nbkts, key, i)) as int;
136176
alt (bkts.(j)) {
137-
case (some[V](val)) {
138-
bkts.(j) = deleted[V]();
177+
case (some[K, V](_, val)) {
178+
bkts.(j) = deleted[K, V]();
139179
ret util.some[V](val);
140180
}
141-
case (deleted[V]()) {
181+
case (deleted[K, V]()) {
142182
nelts += 1u;
143183
}
144-
case (nil[V]()) {
184+
case (nil[K, V]()) {
145185
ret util.none[V]();
146186
}
147187
}
148188
}
149189
ret util.none[V]();
150190
}
151191

152-
fn rehash() {}
192+
fn rehash() {
193+
let vec[mutable bucket[K, V]] newbkts = make_buckets[K, V](nbkts);
194+
rehash[K, V](hasher, bkts, nbkts, newbkts, nbkts);
195+
bkts = newbkts;
196+
}
153197
}
154198

155-
let vec[mutable bucket[V]] bkts =
156-
_vec.init_elt[mutable bucket[V]](nil[V](), initial_capacity);
199+
let vec[mutable bucket[K, V]] bkts = make_buckets[K, V](initial_capacity);
157200

158-
ret hashmap[K, V](hasher, eqer, bkts, 0u, 0u, load_factor);
201+
ret hashmap[K, V](hasher, eqer, bkts, initial_capacity, 0u, load_factor);
159202
}

src/lib/util.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,11 @@ fn id[T](T x) -> T {
1717
ret x;
1818
}
1919

20-
type rational = rec(int num, int den);
20+
/* FIXME (issue #141): See test/run-pass/constrained-type.rs. Uncomment
21+
* the constraint once fixed. */
22+
type rational = rec(int num, int den); // : _int.positive(*.den);
23+
24+
fn rational_leq(&rational x, &rational y) -> bool {
25+
// NB: Uses the fact that rationals have positive denominators WLOG.
26+
ret x.num * y.den <= y.num * x.den;
27+
}

0 commit comments

Comments
 (0)