Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reorganize collections #324

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
98 changes: 98 additions & 0 deletions collections/hashmap/hashmap.mbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright 2024 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// Create new hash map.
pub fn HashMap::new[K, V](~hasher : Option[(K) -> Int] = None) -> HashMap[K, V] {
HashMap(@robinhood_hash.new(~hasher))

Check warning on line 17 in collections/hashmap/hashmap.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashmap/hashmap.mbt#L17

Added line #L17 was not covered by tests
}

/// Create new hash map from array.
pub fn HashMap::from_array[K : Hash + Eq, V](
arr : Array[(K, V)]
) -> HashMap[K, V] {
HashMap(@robinhood_hash.from_array(arr))

Check warning on line 24 in collections/hashmap/hashmap.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashmap/hashmap.mbt#L24

Added line #L24 was not covered by tests
}

/// Set a key-value pair into hash map.
/// @alert unsafe "Panic if the hash map is full."
pub fn set[K : Hash + Eq, V](self : HashMap[K, V], key : K, value : V) -> Unit {
self.0.set(key, value)

Check warning on line 30 in collections/hashmap/hashmap.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashmap/hashmap.mbt#L30

Added line #L30 was not covered by tests
}

pub fn op_set[K : Hash + Eq, V](
self : HashMap[K, V],
key : K,
value : V
) -> Unit {
self.0[key] = value

Check warning on line 38 in collections/hashmap/hashmap.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashmap/hashmap.mbt#L38

Added line #L38 was not covered by tests
}

/// Get the value associated with a key.
pub fn get[K : Hash + Eq, V](self : HashMap[K, V], key : K) -> Option[V] {
self.0.get(key)

Check warning on line 43 in collections/hashmap/hashmap.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashmap/hashmap.mbt#L43

Added line #L43 was not covered by tests
}

pub fn op_get[K : Hash + Eq, V](self : HashMap[K, V], key : K) -> Option[V] {
self.0[key]

Check warning on line 47 in collections/hashmap/hashmap.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashmap/hashmap.mbt#L47

Added line #L47 was not covered by tests
}

/// Get the value associated with a key,
/// returns the provided default value if the key does not exist.
pub fn get_or_default[K : Hash + Eq, V](
self : HashMap[K, V],
key : K,
default : V
) -> V {
self.0.get_or_default(key, default)

Check warning on line 57 in collections/hashmap/hashmap.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashmap/hashmap.mbt#L57

Added line #L57 was not covered by tests
}

/// Check if the hash map contains a key.
pub fn contains[K : Hash + Eq, V](self : HashMap[K, V], key : K) -> Bool {
self.0.contains(key)

Check warning on line 62 in collections/hashmap/hashmap.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashmap/hashmap.mbt#L62

Added line #L62 was not covered by tests
}

/// Remove a key-value pair from hash map.
pub fn remove[K : Hash + Eq, V](self : HashMap[K, V], key : K) -> Unit {
self.0.remove(key)

Check warning on line 67 in collections/hashmap/hashmap.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashmap/hashmap.mbt#L67

Added line #L67 was not covered by tests
}

/// Get the number of key-value pairs in the map.
pub fn size[K, V](self : HashMap[K, V]) -> Int {
self.0.size()

Check warning on line 72 in collections/hashmap/hashmap.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashmap/hashmap.mbt#L72

Added line #L72 was not covered by tests
}

/// Get the capacity of the map.
pub fn capacity[K, V](self : HashMap[K, V]) -> Int {
self.0.capacity()

Check warning on line 77 in collections/hashmap/hashmap.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashmap/hashmap.mbt#L77

Added line #L77 was not covered by tests
}

/// Check if the hash map is empty.
pub fn is_empty[K, V](self : HashMap[K, V]) -> Bool {
self.0.is_empty()

Check warning on line 82 in collections/hashmap/hashmap.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashmap/hashmap.mbt#L82

Added line #L82 was not covered by tests
}

// Iterate over all key-value pairs of the map.
pub fn iter[K, V](self : HashMap[K, V], f : (K, V) -> Unit) -> Unit {
self.0.iter(f)

Check warning on line 87 in collections/hashmap/hashmap.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashmap/hashmap.mbt#L87

Added line #L87 was not covered by tests
}

// Iterate over all key-value pairs of the map, with index.
pub fn iteri[K, V](self : HashMap[K, V], f : (Int, K, V) -> Unit) -> Unit {
self.0.iteri(f)

Check warning on line 92 in collections/hashmap/hashmap.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashmap/hashmap.mbt#L92

Added line #L92 was not covered by tests
}

// Clears the map, removing all key-value pairs. Keeps the allocated space.
pub fn clear[K, V](self : HashMap[K, V]) -> Unit {
self.0.clear()

Check warning on line 97 in collections/hashmap/hashmap.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashmap/hashmap.mbt#L97

Added line #L97 was not covered by tests
}
2 changes: 1 addition & 1 deletion hashmap/hashmap.mbti → collections/hashmap/hashmap.mbti
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package moonbitlang/core/hashmap
package moonbitlang/core/collections/hashmap

// Values

Expand Down
7 changes: 7 additions & 0 deletions collections/hashmap/moon.pkg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"import": [
"moonbitlang/core/builtin",
"moonbitlang/core/coverage",
"moonbitlang/core/collections/robinhood_hash"
]
}
15 changes: 15 additions & 0 deletions collections/hashmap/types.mbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2024 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

type HashMap[K, V] @robinhood_hash.RobinhoodHash[K, V]
File renamed without changes.
170 changes: 170 additions & 0 deletions collections/hashset/hashset.mbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
// Copyright 2024 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// Create new hash set.
pub fn HashSet::new[K](~hasher : Option[(K) -> Int] = None) -> HashSet[K] {
HashSet(@robinhood_hash.new(~hasher))
}

/// Create new hash set from array.
pub fn HashSet::from_array[K : Hash + Eq](arr : Array[K]) -> HashSet[K] {
// Sadly we cannot do type casting from Array[K] to Array[(K, Unit)].
// And it would be computationally stupid to create a new array.
// So let's just do it the by hand.
let m = @robinhood_hash.new()
arr.iter(fn(e) { m.set(e, ()) })
HashSet(m)
}

/// Insert a key into hash set.
/// @alert unsafe "Panic if the hash set is full."
pub fn insert[K : Hash + Eq](self : HashSet[K], key : K) -> Unit {
self.0.set(key, ())
}

/// Check if the hash set contains a key.
pub fn contains[K : Hash + Eq](self : HashSet[K], key : K) -> Bool {
self.0.contains(key)
}

/// Remove a key from hash set.
pub fn remove[K : Hash + Eq](self : HashSet[K], key : K) -> Unit {
self.0.remove(key)

Check warning on line 43 in collections/hashset/hashset.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashset/hashset.mbt#L43

Added line #L43 was not covered by tests
}

/// Get the number of keys in the set.
pub fn size[K](self : HashSet[K]) -> Int {
self.0.size()
}

/// Get the capacity of the set.
pub fn capacity[K](self : HashSet[K]) -> Int {
self.0.capacity()

Check warning on line 53 in collections/hashset/hashset.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashset/hashset.mbt#L53

Added line #L53 was not covered by tests
}

/// Check if the hash set is empty.
pub fn is_empty[K](self : HashSet[K]) -> Bool {
self.0.is_empty()

Check warning on line 58 in collections/hashset/hashset.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashset/hashset.mbt#L58

Added line #L58 was not covered by tests
}

/// Iterate over all keys of the set.
pub fn iter[K](self : HashSet[K], f : (K) -> Unit) -> Unit {
self.0.iter(fn(k, _v) { f(k) })
}

/// Iterate over all keys of the set, with index.
pub fn iteri[K](self : HashSet[K], f : (Int, K) -> Unit) -> Unit {
self.0.iteri(fn(i, k, _v) { f(i, k) })

Check warning on line 68 in collections/hashset/hashset.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashset/hashset.mbt#L68

Added line #L68 was not covered by tests
}

/// Clears the set, removing all keys. Keeps the allocated space.
pub fn clear[K](self : HashSet[K]) -> Unit {
self.0.clear()

Check warning on line 73 in collections/hashset/hashset.mbt

View check run for this annotation

Codecov / codecov/patch

collections/hashset/hashset.mbt#L73

Added line #L73 was not covered by tests
}

/// Union of two hash sets.
/// Safety:
/// - If one of the HashSet has a custom hasher, the other HashSet must have the same hasher.
///
/// @alert unsafe "Panic if the hash set is full."
pub fn union[K : Hash + Eq](
self : HashSet[K],
other : HashSet[K]
) -> HashSet[K] {
let m = HashSet::new()
self.iter(fn(k) { m.insert(k) })
other.iter(fn(k) { m.insert(k) })
m
}

/// Intersection of two hash sets.
/// Safety:
/// - If one of the HashSet has a custom hasher, the other HashSet must have the same hasher.
pub fn intersection[K : Hash + Eq](
self : HashSet[K],
other : HashSet[K]
) -> HashSet[K] {
let m = HashSet::new(hasher=self.0.hasher())
self.iter(fn(k) { if other.contains(k) { m.insert(k) } })
m
}

/// Difference of two hash sets.
/// Safety:
/// - If one of the HashSet has a custom hasher, the other HashSet must have the same hasher.
pub fn difference[K : Hash + Eq](
self : HashSet[K],
other : HashSet[K]
) -> HashSet[K] {
let m = HashSet::new(hasher=self.0.hasher())
self.iter(fn(k) { if not(other.contains(k)) { m.insert(k) } })
m
}

/// Symmetric difference of two hash sets.
/// Safety:
/// - If one of the HashSet has a custom hasher, the other HashSet must have the same hasher.
pub fn symmetric_difference[K : Hash + Eq](
self : HashSet[K],
other : HashSet[K]
) -> HashSet[K] {
let m = HashSet::new(hasher=self.0.hasher())
self.iter(fn(k) { if not(other.contains(k)) { m.insert(k) } })
other.iter(fn(k) { if not(self.contains(k)) { m.insert(k) } })
m
}

test "union" {
let m1 : HashSet[String] = HashSet::["a", "b", "c"]
let m2 : HashSet[String] = HashSet::["b", "c", "d"]
let m = m1.union(m2)
@assertion.assert_eq(m.size(), 4)?
@assertion.assert_true(m.contains("a"))?
@assertion.assert_true(m.contains("b"))?
@assertion.assert_true(m.contains("c"))?
@assertion.assert_true(m.contains("d"))?
}

test "intersection" {
let m1 : HashSet[String] = HashSet::["a", "b", "c"]
let m2 : HashSet[String] = HashSet::["b", "c", "d"]
let m = m1.intersection(m2)
@assertion.assert_eq(m.size(), 2)?
@assertion.assert_false(m.contains("a"))?
@assertion.assert_true(m.contains("b"))?
@assertion.assert_true(m.contains("c"))?
@assertion.assert_false(m.contains("d"))?
}

test "difference" {
let m1 : HashSet[String] = HashSet::["a", "b", "c"]
let m2 : HashSet[String] = HashSet::["b", "c", "d"]
let m = m1.difference(m2)
@assertion.assert_eq(m.size(), 1)?
@assertion.assert_true(m.contains("a"))?
@assertion.assert_false(m.contains("b"))?
@assertion.assert_false(m.contains("c"))?
@assertion.assert_false(m.contains("d"))?
}

test "symmetric_difference" {
let m1 : HashSet[String] = HashSet::["a", "b", "c"]
let m2 : HashSet[String] = HashSet::["b", "c", "d"]
let m = m1.symmetric_difference(m2)
@assertion.assert_eq(m.size(), 2)?
@assertion.assert_true(m.contains("a"))?
@assertion.assert_false(m.contains("b"))?
@assertion.assert_false(m.contains("c"))?
@assertion.assert_true(m.contains("d"))?
}
2 changes: 1 addition & 1 deletion hashset/hashset.mbti → collections/hashset/hashset.mbti
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package moonbitlang/core/hashset
package moonbitlang/core/collections/hashset

// Values

Expand Down
9 changes: 4 additions & 5 deletions hashset/moon.pkg.json → collections/hashset/moon.pkg.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
{
"import": [
"moonbitlang/core/builtin",
"moonbitlang/core/int",
"moonbitlang/core/list",
"moonbitlang/core/array",
"moonbitlang/core/string",
"moonbitlang/core/coverage",
"moonbitlang/core/collections/robinhood_hash",
"moonbitlang/core/assertion",
"moonbitlang/core/coverage"
"moonbitlang/core/string",
"moonbitlang/core/array"
]
}
15 changes: 15 additions & 0 deletions collections/hashset/types.mbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2024 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

type HashSet[K] @robinhood_hash.RobinhoodHash[K, Unit]
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -70,29 +70,26 @@ fn remove[K : Eq, V](self : Bucket[K, V], key : K) -> Option[Bucket[K, V]] {
/// Get the size of a bucket
fn size[K, V](self : Bucket[K, V]) -> Int {
loop self, 1 {
Just_One(_), acc => acc
More(_,_, rest), acc => continue rest, acc + 1
}
Just_One(_), acc => acc
More(_, _, rest), acc => continue rest, acc + 1
}
}

test "Bucket" {
let b0 : Bucket[_] = Just_One(0, 0)
inspect((b0.find(0),b0.find(1),b0.size()), ~content="(Some(0), None, 1)")?
inspect((b0.find(0), b0.find(1), b0.size()), content="(Some(0), None, 1)")?
let b1 = b0.add(1, 1)
inspect((b1.find(0),b1.find(1),b1.size()), ~content="(Some(0), Some(1), 2)")?
inspect((b1.find(0), b1.find(1), b1.size()), content="(Some(0), Some(1), 2)")?
let b2 = b1.add(0, 2)
inspect((b2.find(0),b2.find(1),b2.size()), ~content="(Some(2), Some(1), 2)")?
inspect((b2.find(0), b2.find(1), b2.size()), content="(Some(2), Some(1), 2)")?
let b3 = b2.remove(0)
{
let b1 = b3.unwrap()
inspect((b1.find(0),b1.find(1)), ~content="(None, Some(1))")?
inspect((b1.find(0), b1.find(1)), content="(None, Some(1))")?
}
let b4 = b2.remove(1)
{
let b1 = b4.unwrap() // b4 ? --> return Option instead of Result
inspect((b1.find(0),b1.find(1)), ~content="(Some(2), None)")?
}

let b1 = b4.unwrap() // b4 ? --> return Option instead of Result
inspect((b1.find(0), b1.find(1)), content="(Some(2), None)")?
}

/// Iterate through elements of a bucket
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package moonbitlang/core/immutable_hashmap
package moonbitlang/core/collections/immutable_hashmap

// Values

Expand Down
Loading
Loading