Skip to content
This repository was archived by the owner on Feb 18, 2025. It is now read-only.

Commit f6a1023

Browse files
committed
stdlib: use Identity in HashMap and HashSet, add tests for special float values
works on #88
1 parent a74bef0 commit f6a1023

14 files changed

+166
-34
lines changed

dora/stdlib/collections.dora

+10-10
Original file line numberDiff line numberDiff line change
@@ -520,15 +520,15 @@ impl[T] Queue[T] {
520520
}
521521
}
522522

523-
@pub class HashMap[K: Hash + Equals, V] {
523+
@pub class HashMap[K: Hash + Identity + Equals, V] {
524524
inserted_and_deleted: BitSet,
525525
keys: Array[K],
526526
values: Array[V],
527527
entries: Int64,
528528
cap: Int64,
529529
}
530530

531-
impl[K: Hash + Equals, V] HashMap[K, V] {
531+
impl[K: Hash + Identity + Equals, V] HashMap[K, V] {
532532
@pub @static fun new(entries: (K, V)...): HashMap[K, V] {
533533
// BitSet.size == capacity * 2
534534
// [bit 0: inserted; bit 1: deleted] * capacity
@@ -561,7 +561,7 @@ impl[K: Hash + Equals, V] HashMap[K, V] {
561561
... .isLive(idx) {
562562
let current_key = self.keys.get(idx);
563563

564-
if current_key.hash() == hash && current_key.equals(key) {
564+
if current_key.hash() == hash && (current_key.identicalTo(key) || current_key.equals(key)) {
565565
let old_value = self.values.get(idx);
566566
self.values.set(idx, value);
567567
return Some[V](old_value);
@@ -607,7 +607,7 @@ impl[K: Hash + Equals, V] HashMap[K, V] {
607607
... .isLive(idx) {
608608
let current_key = self.keys.get(idx);
609609

610-
if current_key.hash() == hash && current_key.equals(key) {
610+
if current_key.hash() == hash && (current_key.identicalTo(key) || current_key.equals(key)) {
611611
return true;
612612
}
613613
idx = (idx + 1i64) & (self.cap - 1i64);
@@ -639,7 +639,7 @@ impl[K: Hash + Equals, V] HashMap[K, V] {
639639
... .isLive(idx) {
640640
let current_key = self.keys.get(idx);
641641

642-
if current_key.hash() == hash && current_key.equals(key) {
642+
if current_key.hash() == hash && (current_key.identicalTo(key) || current_key.equals(key)) {
643643
return Option[V]::Some(self.values.get(idx));
644644
}
645645
idx = (idx + 1i64) & (self.cap - 1i64);
@@ -667,7 +667,7 @@ impl[K: Hash + Equals, V] HashMap[K, V] {
667667
... .isLive(idx) {
668668
let current_key = self.keys.get(idx);
669669

670-
if current_key.hash() == hash && current_key.equals(key) {
670+
if current_key.hash() == hash && (current_key.identicalTo(key) || current_key.equals(key)) {
671671
let value = self.values.get(idx);
672672
self.inserted_and_deleted.insert(2i64 * idx + 1i64);
673673

@@ -780,12 +780,12 @@ impl[K: Hash + Equals, V] HashMap[K, V] {
780780
@pub fun iterator(): HashMapIterator[K, V] = HashMapIterator[K, V]::new(self);
781781
}
782782

783-
@pub class HashMapIterator[K: Hash + Equals, V] {
783+
@pub class HashMapIterator[K: Hash + Identity + Equals, V] {
784784
map: HashMap[K, V],
785785
idx: Int64,
786786
}
787787

788-
impl[K: Hash + Equals, V] HashMapIterator[K, V] {
788+
impl[K: Hash + Identity + Equals, V] HashMapIterator[K, V] {
789789
@pub @static fun new(map: HashMap[K, V]): HashMapIterator[K, V] = HashMapIterator[K, V](map, 0);
790790

791791
@pub fun next(): Option[(K, V)] {
@@ -804,11 +804,11 @@ impl[K: Hash + Equals, V] HashMapIterator[K, V] {
804804
}
805805
}
806806

807-
@pub class HashSet[K: Hash + Equals] {
807+
@pub class HashSet[K: Hash + Identity + Equals] {
808808
map: HashMap[K, ()],
809809
}
810810

811-
impl[K: Hash + Equals] HashSet[K] {
811+
impl[K: Hash + Identity + Equals] HashSet[K] {
812812
@pub @static fun new(keys: K...): HashSet[K] {
813813
let map: HashMap[K, ()] = HashMap[K, ()]::new();
814814

dora/stdlib/stdlib.dora

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
@pub use collections.{Array, BitSet, BitVec, HashMap, HashSet, List, Queue};
2-
@pub use traits.{Comparable, Default, Equals, Hash, Iterator, Zero};
2+
@pub use traits.{Comparable, Default, Equals, Hash, Identity, Iterator, Zero};
33
@pub use primitives.{Unit, Bool, Char, Float32, Float64, Int32, Int64, Option, range, Result};
44
@pub use rand.Random;
55
@pub use string.{CodepointIterator, String, StringBuffer, Stringable};

tests/generic/generic-hash-map-field.dora

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
class MyOwnType
22

3+
impl std::Identity for MyOwnType {
4+
fun identicalTo(other: MyOwnType): Bool = true;
5+
}
6+
37
impl std::Equals for MyOwnType {
48
fun equals(other: MyOwnType): Bool = true;
59
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
fun main(): Unit {
2+
float64();
3+
float32();
4+
}
5+
6+
fun float64(): Unit {
7+
let map = std::HashMap[Float64, String]::new((Float64::infinityPositive(), "a"), (Float64::infinityNegative(), "b"));
8+
9+
assert(map.size() == 2);
10+
assert(map.contains(Float64::infinityPositive()));
11+
assert(map.get(Float64::infinityPositive()).getOrPanic() == "a");
12+
assert(map.contains(Float64::infinityNegative()));
13+
assert(map.get(Float64::infinityNegative()).getOrPanic() == "b");
14+
}
15+
16+
fun float32(): Unit {
17+
let map = std::HashMap[Float32, String]::new((Float32::infinityPositive(), "a"), (Float32::infinityNegative(), "b"));
18+
19+
assert(map.size() == 2);
20+
assert(map.contains(Float32::infinityPositive()));
21+
assert(map.get(Float32::infinityPositive()).getOrPanic() == "a");
22+
assert(map.contains(Float32::infinityNegative()));
23+
assert(map.get(Float32::infinityNegative()).getOrPanic() == "b");
24+
}
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
fun main(): Unit {
2+
float64();
3+
float32();
4+
}
5+
6+
fun float64(): Unit {
7+
let map = std::HashMap[Float64, String]::new((Float64::notANumber(), "a"));
8+
9+
assert(map.size() == 1);
10+
assert(map.contains(Float64::notANumber()));
11+
assert(map.get(Float64::notANumber()).getOrPanic() == "a");
12+
}
13+
14+
fun float32(): Unit {
15+
let map = std::HashMap[Float32, String]::new((Float32::notANumber(), "a"));
16+
17+
assert(map.size() == 1);
18+
assert(map.contains(Float32::notANumber()));
19+
assert(map.get(Float32::notANumber()).getOrPanic() == "a");
20+
}
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
fun main(): Unit {
2+
float64();
3+
float32();
4+
}
5+
6+
fun float64(): Unit {
7+
let map = std::HashMap[Float64, String]::new((0.0, "a"));
8+
9+
assert(map.size() == 1);
10+
assert(map.contains(0.0));
11+
assert(map.get(0.0).getOrPanic() == "a");
12+
assert(map.contains(-0.0)); // FIXME: this only works by coincidence, because the hash function sucks
13+
assert(map.get(-0.0).getOrPanic() == "a"); // FIXME: this only works by coincidence, because the hash function sucks
14+
}
15+
16+
fun float32(): Unit {
17+
let map = std::HashMap[Float32, String]::new((0.0f32, "a"));
18+
19+
assert(map.size() == 1);
20+
assert(map.contains(0.0f32));
21+
assert(map.get(0.0f32).getOrPanic() == "a");
22+
assert(map.contains(-0.0f32).not()); // FIXME: should be true instead
23+
// assert(map.get(-0.0f32).getOrPanic() == "a"); // FIXME: should be true instead
24+
}

tests/stdlib/hashmap-contains.dora

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
fun main(): Unit {
2+
let map = std::HashMap[Int32, String]::new((1i32, "a"), (2i32, "b"), (3i32, "c"), (4i32, "d"));
3+
4+
assert(map.size() == 4);
5+
6+
assert(map.contains(1i32));
7+
assert(map.contains(2i32));
8+
assert(map.contains(3i32));
9+
assert(map.contains(4i32));
10+
assert(map.contains(0i32).not());
11+
12+
assert(map.get(1i32).getOrPanic() == "a");
13+
assert(map.get(2i32).getOrPanic() == "b");
14+
assert(map.get(3i32).getOrPanic() == "c");
15+
assert(map.get(4i32).getOrPanic() == "d");
16+
}
File renamed without changes.

tests/stdlib/hashmap3.dora

-15
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
fun main(): Unit {
2+
float64();
3+
float32();
4+
}
5+
6+
fun float64(): Unit {
7+
let set = std::HashSet[Float64]::new(Float64::infinityPositive(), Float64::infinityNegative());
8+
9+
assert(set.size() == 2);
10+
assert(set.contains(Float64::infinityPositive()));
11+
assert(set.contains(Float64::infinityNegative()));
12+
}
13+
14+
fun float32(): Unit {
15+
let set = std::HashSet[Float32]::new(Float32::infinityPositive(), Float32::infinityNegative());
16+
17+
assert(set.size() == 2);
18+
assert(set.contains(Float32::infinityPositive()));
19+
assert(set.contains(Float32::infinityNegative()));
20+
}
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
fun main(): Unit {
2+
float64();
3+
float32();
4+
}
5+
6+
fun float64(): Unit {
7+
let set = std::HashSet[Float64]::new(Float64::notANumber());
8+
9+
assert(set.size() == 1);
10+
assert(set.contains(Float64::notANumber()));
11+
}
12+
13+
fun float32(): Unit {
14+
let set = std::HashSet[Float32]::new(Float32::notANumber());
15+
16+
assert(set.size() == 1);
17+
assert(set.contains(Float32::notANumber()));
18+
}
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
fun main(): Unit {
2+
float64();
3+
float32();
4+
}
5+
6+
fun float64(): Unit {
7+
let set = std::HashSet[Float64]::new(0.0);
8+
9+
assert(set.size() == 1);
10+
assert(set.contains(0.0));
11+
assert(set.contains(-0.0)); // FIXME: this only works by coincidence, because the hash function sucks
12+
}
13+
14+
fun float32(): Unit {
15+
let set = std::HashSet[Float32]::new(0.0f32);
16+
17+
assert(set.size() == 1);
18+
assert(set.contains(0.0f32));
19+
assert(set.contains(-0.0f32).not()); // FIXME: should be true instead
20+
}

tests/stdlib/hashset-contains.dora

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
fun main(): Unit {
2+
let set = std::HashSet[Int32]::new(1i32, 10'000i32, 7i32);
3+
4+
assert(set.size() == 3);
5+
assert(set.contains(1i32));
6+
assert(set.contains(10'000i32));
7+
assert(set.contains(7i32));
8+
assert(set.contains(0i32).not());
9+
}

tests/stdlib/hashset3.dora

-8
This file was deleted.

0 commit comments

Comments
 (0)