Skip to content

Commit 0921bb4

Browse files
committed
Add Map library code.
1 parent e73de57 commit 0921bb4

File tree

10 files changed

+721
-1
lines changed

10 files changed

+721
-1
lines changed

LICENSE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright 2018 Joe Eli McIlvain
1+
Copyright 2019 Joe Eli McIlvain
22

33
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
44

manifest.savi

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
:manifest lib Map
2+
:sources "src/*.savi"
3+
4+
:manifest bin "spec"
5+
:copies Map
6+
:sources "spec/*.savi"
7+
8+
:dependency Spec v0
9+
:depends on Map

spec/Main.savi

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
:actor Main
2+
:new (env)
3+
Spec.Process.run(env, [
4+
Spec.Run(Map.Spec).new(env)
5+
Spec.Run(Map.Ordered.Spec).new(env)
6+
Spec.Run(Map.Readable.Spec).new(env)
7+
])

spec/Map.Spec.savi

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
:actor _MapElementExampleActor
2+
3+
:class Map.Spec
4+
:is Spec
5+
:const describes: "Map"
6+
7+
:fun new_map: Map(String, U64).new
8+
:fun new_actor_map: Map.ByIdentity(_MapElementExampleActor, U64).new
9+
10+
:it "stores and removes values at a given key"
11+
map = @new_map
12+
assert: map.size == 0
13+
assert error: map["example"]!
14+
assert: map.has_key("example").is_false
15+
assert: (map["example"] = 99) == 99
16+
assert: map.size == 1
17+
assert: map["example"]! == 99
18+
assert: map.has_key("example")
19+
assert: (map["example"] = 88) == 88
20+
assert: map.size == 1
21+
assert: map["example"]! == 88
22+
assert: map.has_key("example")
23+
assert: map.delete("example") <: None
24+
assert error: map["example"]!
25+
assert: map.has_key("example").is_false
26+
assert: map.size == 0
27+
28+
:it "stores values at actor keys by identity"
29+
foo = _MapElementExampleActor.new
30+
bar = _MapElementExampleActor.new
31+
baz = _MapElementExampleActor.new
32+
map = @new_actor_map
33+
map[foo] = 11
34+
map[bar] = 22
35+
map[baz] = 33
36+
assert: map[foo]! == 11
37+
assert: map[bar]! == 22
38+
assert: map[baz]! == 33
39+
40+
:it "can be cleared, removing all keys and values"
41+
map = @new_map
42+
map["foo"] = 11
43+
map["bar"] = 22
44+
map["baz"] = 33
45+
46+
assert: map.size == 3, map.clear
47+
assert: map.size == 0
48+
49+
:it "yields each key and value"
50+
map = @new_map
51+
map["foo"] = 11
52+
map["bar"] = 22
53+
map["baz"] = 33
54+
55+
copy = @new_map
56+
map.each -> (key, value | copy[key] = value)
57+
58+
assert: copy.size == 3
59+
assert: copy["foo"]! == 11
60+
assert: copy["bar"]! == 22
61+
assert: copy["baz"]! == 33
62+
63+
:it "yields each key and value until the criteria is met"
64+
map = @new_map
65+
map["foo"] = 11
66+
map["bar"] = 22
67+
map["baz"] = 33
68+
69+
this_key = ""
70+
found_it = map.each_until -> (key, value | this_key = key, value == 22)
71+
assert: found_it
72+
assert: this_key == "bar"
73+
74+
this_key = ""
75+
found_it = map.each_until -> (key, value | this_key = key, value == 33)
76+
assert: found_it
77+
assert: this_key == "baz"
78+
79+
this_key = ""
80+
found_it = map.each_until -> (key, value | this_key = key, value == 99)
81+
assert: found_it.is_false

spec/Ordered.Spec.savi

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
:class Map.Ordered.Spec
2+
:is Spec
3+
:const describes: "Map.Ordered"
4+
5+
:fun new_map: Map.Ordered(String, U64).new
6+
7+
:it "stores and removes values at a given key"
8+
map = @new_map
9+
assert: map.size == 0
10+
assert error: map["example"]!
11+
assert: map.has_key("example").is_false
12+
assert: (map["example"] = 99) == 99
13+
assert: map.size == 1
14+
assert: map["example"]! == 99
15+
assert: map.has_key("example")
16+
assert: (map["example"] = 88) == 88
17+
assert: map.size == 1
18+
assert: map["example"]! == 88
19+
assert: map.has_key("example")
20+
assert: map.delete("example") <: None
21+
assert error: map["example"]!
22+
assert: map.has_key("example").is_false
23+
assert: map.size == 0
24+
25+
:it "can be cleared, removing all keys and values"
26+
map = @new_map
27+
map["foo"] = 11
28+
map["bar"] = 22
29+
map["baz"] = 33
30+
31+
assert: map.size == 3, map.clear
32+
assert: map.size == 0
33+
34+
:it "yields each key and value (in insertion order)"
35+
map = @new_map
36+
map["foo"] = 11
37+
map["bar"] = 22
38+
map["baz"] = 33
39+
map["foo"] = 44
40+
map["baz"] = 55
41+
map["foo"] = 66
42+
43+
keys Array(String) = []
44+
values Array(U64) = []
45+
map.each -> (key, value | keys << key, values << value)
46+
47+
assert: keys == ["bar", "baz", "foo"]
48+
assert: values == [22, 55, 66]
49+
50+
:it "yields each key and value until the criteria is met"
51+
map = @new_map
52+
map["foo"] = 11
53+
map["bar"] = 22
54+
map["baz"] = 33
55+
56+
count = USize[0]
57+
key = ""
58+
found_it = map.each_until -> (k, v | count += 1, key = k, v == 22)
59+
assert: found_it
60+
assert: count == 2
61+
assert: key == "bar"
62+
63+
count = USize[0]
64+
key = ""
65+
found_it = map.each_until -> (k, v | count += 1, key = k, v == 33)
66+
assert: found_it
67+
assert: count == 3
68+
assert: key == "baz"
69+
70+
count = USize[0]
71+
key = ""
72+
found_it = map.each_until -> (k, v | count += 1, key = k, v == 99)
73+
assert: count == 3
74+
assert: key == "baz"
75+
assert: found_it.is_false

spec/Readable.Spec.savi

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
:class Map.Readable.Spec
2+
:is Spec
3+
:const describes: "Map.Readable"
4+
5+
:fun new_mutable_map: Map(String, U64).new
6+
7+
:: Create a mutable map, yield it to the caller for initialization,
8+
:: then return it as read-only using the Map.Readable trait as the type.
9+
:: This ensures that we are testing based only on the trait's methods,
10+
:: while still giving us a temporary time of mutability to initialize it.
11+
:fun build_map Map.Readable(String, U64)
12+
map = @new_mutable_map
13+
yield map
14+
map
15+
16+
:it "yields each key and each value (separately)"
17+
map = @build_map -> (map |
18+
map["foo"] = 11
19+
map["bar"] = 22
20+
map["baz"] = 33
21+
)
22+
23+
copy = @new_mutable_map
24+
map.each_key -> (key | try (copy[key] = map[key]!))
25+
26+
assert: copy.size == 3
27+
assert: copy["foo"]! == 11
28+
assert: copy["bar"]! == 22
29+
assert: copy["baz"]! == 33
30+
31+
total_value = U64[0]
32+
map.each_value -> (value | total_value += value)
33+
assert: total_value == 66
34+
35+
:it "yields each key and each value (separately) until the criteria is met"
36+
map = @build_map -> (map |
37+
map["foo"] = 11
38+
map["bar"] = 22
39+
map["baz"] = 33
40+
)
41+
42+
this_key = ""
43+
found_it = map.each_key_until -> (key | this_key = key, key.ends_with("o"))
44+
assert: found_it
45+
assert: this_key == "foo"
46+
47+
this_key = ""
48+
found_it = map.each_key_until -> (key | this_key = key, key.ends_with("z"))
49+
assert: found_it
50+
assert: this_key == "baz"
51+
52+
this_key = ""
53+
found_it = map.each_key_until -> (key | this_key = key, key.ends_with("x"))
54+
assert: found_it.is_false
55+
56+
:it "checks if any pair in the map meets the given condition"
57+
map = @build_map -> (map |
58+
map["foo"] = 11
59+
map["bar"] = 22
60+
map["baz"] = 33
61+
)
62+
63+
assert: map.has_any -> (key, value | key == "foo")
64+
assert: map.has_any -> (key, value | key == "food").is_false
65+
assert: map.has_any -> (key, value | value == 22)
66+
assert: map.has_any -> (key, value | value == 23).is_false
67+
68+
:it "checks if all pairs in the map meet the given condition"
69+
map = @build_map -> (map |
70+
map["foo"] = 11
71+
map["bar"] = 22
72+
map["baz"] = 33
73+
)
74+
75+
assert: map.has_all -> (key, value | key.size == 3)
76+
assert: map.has_all -> (key, value | key.starts_with("ba")).is_false
77+
assert: map.has_all -> (key, value | value < 50)
78+
assert: map.has_all -> (key, value | value < 30).is_false

0 commit comments

Comments
 (0)