README

#HashSet

A mutable hash set based on a Robin Hood hash table.

#Usage

#Create

You can create an empty set using HashSet([]) or construct it from entries using HashSet([...]).

///|
test {
let _set1 = @hashset.HashSet([1, 2, 3, 4, 5])
let _set2 : @hashset.HashSet[String] = HashSet([])
}

#Insert & Contain

You can use insert() to add a key to the set, and contains() to check whether a key exists.

///|
test {
let set : @hashset.HashSet[String] = HashSet([])
set.add("a")
@test.assert_eq(set.contains("a"), true)
}

#Remove

You can use remove() to remove a key.

///|
test {
let set = @hashset.from_array(["a", "b", "c"])
set.remove("a")
@test.assert_eq(set.contains("a"), false)
}

#Size & Capacity

You can use size() to get the number of keys in the set, or capacity() to get the current capacity.

///|
test {
let set = @hashset.from_array(["a", "b", "c"])
@test.assert_eq(set.length(), 3)
@test.assert_eq(set.capacity(), 8)
}

Similarly, you can use is_empty() to check whether the set is empty.

///|
test {
let set : @hashset.HashSet[Int] = HashSet([])
@test.assert_eq(set.is_empty(), true)
}

#Clear

You can use clear to remove all keys from the set, but the allocated memory will not change.

///|
test {
let set = @hashset.from_array(["a", "b", "c"])
set.clear()
@test.assert_eq(set.is_empty(), true)
}

#Iteration

You can use each() or eachi() to iterate through all keys.

///|
test {
let set = @hashset.from_array(["a", "b", "c"])
let arr = []
set.each(k => arr.push(k))
let arr2 = []
set.eachi((i, k) => arr2.push((i, k)))
}

#Add & Remove with Check

add_and_check() returns true if the element was newly added (not already present). remove_and_check() returns true if the element was actually removed.

///|
test {
let set = @hashset.from_array([1, 2, 3])
@test.assert_eq(set.add_and_check(4), true) // new element
@test.assert_eq(set.add_and_check(4), false) // already exists
@test.assert_eq(set.remove_and_check(4), true) // removed
@test.assert_eq(set.remove_and_check(4), false) // not present
}

#Retain

retain() keeps only elements that satisfy a predicate, removing the rest in place.

///|
test {
let set = @hashset.from_array([1, 2, 3, 4, 5])
set.retain(fn(x) { x % 2 == 0 })
@test.assert_eq(set.contains(1), false)
@test.assert_eq(set.contains(2), true)
}

#Copy

copy() creates a shallow clone of the set.

///|
test {
let set = @hashset.from_array([1, 2, 3])
let cloned = set.copy()
cloned.add(4)
@test.assert_eq(set.contains(4), false) // original unchanged
@test.assert_eq(cloned.contains(4), true)
}

#Iterators & Conversion

iter() returns an iterator. to_array() collects elements into an array. from_iter() constructs a set from an iterator.

///|
test {
let set = @hashset.from_array([1, 2, 3])
let arr = set.to_array()
arr.sort()
@test.assert_eq(arr, [1, 2, 3])
// from_iter
let set2 = @hashset.from_iter([4, 5, 6].iter())
@test.assert_eq(set2.length(), 3)
}

#Set Operations

union(), intersection(), difference(), and symmetric_difference() return new sets. These also have operator aliases: | (union), & (intersection), - (difference), ^ (symmetric difference).

///|
test {
let m1 = @hashset.from_array(["a", "b", "c"])
let m2 = @hashset.from_array(["b", "c", "d"])
fn to_sorted_array(set : @hashset.HashSet[String]) {
let arr = set.to_array()
arr.sort()
arr
}

@test.assert_eq(m1.union(m2) |> to_sorted_array, ["a", "b", "c", "d"])
@test.assert_eq(m1.intersection(m2) |> to_sorted_array, ["b", "c"])
@test.assert_eq(m1.difference(m2) |> to_sorted_array, ["a"])
@test.assert_eq(m1.symmetric_difference(m2) |> to_sorted_array, ["a", "d"])
// operator aliases
@test.assert_eq((m1 | m2) |> to_sorted_array, ["a", "b", "c", "d"])
@test.assert_eq((m1 & m2) |> to_sorted_array, ["b", "c"])
@test.assert_eq((m1 - m2) |> to_sorted_array, ["a"])
@test.assert_eq((m1 ^ m2) |> to_sorted_array, ["a", "d"])
}

#Set Predicates

is_subset(), is_superset(), and is_disjoint() test set relationships.

///|
test {
let small = @hashset.from_array([1, 2])
let big = @hashset.from_array([1, 2, 3, 4])
let other = @hashset.from_array([5, 6])
@test.assert_eq(small.is_subset(big), true)
@test.assert_eq(big.is_superset(small), true)
@test.assert_eq(small.is_disjoint(other), true)
@test.assert_eq(small.is_disjoint(big), false)
}

#
HashSet

type HashSet[K]

Mutable hash set, not thread safe.

Example

test {
let set = @hashset.HashSet([(3, "three"), (8, "eight"), (1, "one")])
set.add((4, "four"))
@test.assert_eq(set.contains((4, "four")), true)
}
impl BitAnd for HashSet[K]
impl BitOr for HashSet[K]
impl BitXOr for HashSet[K]
impl Default for HashSet[K]
impl Show for HashSet[K]
impl Sub for HashSet[K]
impl ToJson for HashSet[X]

#
HashSet::HashSet

#as_free_fn(of, deprecated="Use from_array instead")
#alias(of, deprecated="Use from_array instead")
#as_free_fn(from_array)
#alias(from_array)
fn[K : Hash + Eq] HashSet::HashSet(arr : ArrayView[K], capacity? : Int) -> HashSet[K]

Creates a hash set containing all elements from the given array. The optional capacity is treated as a minimum initial capacity and will be rounded up to the smallest power of 2 that can hold the requested capacity.

#
HashSet::add

#alias(insert, deprecated="`insert` is deprecated, use `add` instead")
fn[K : Hash + Eq] HashSet::add(self : HashSet[K], key : K) -> Unit

Insert a key into hash set.

Parameters:

  • self : The hash set to modify.
  • key : The key to insert. Must implement Hash and Eq traits.

Example:

test {
let set : @hashset.HashSet[String] = HashSet([])
set.add("key")
inspect(set.contains("key"), content="true")
set.add("key") // no effect since it already exists
inspect(set.length(), content="1")
}

#
HashSet::add_and_check

fn[K : Hash + Eq] HashSet::add_and_check(self : HashSet[K], key : K) -> Bool

Insert a key into the hash set and returns whether the key was successfully added.

Parameters:

  • self : The hash set to modify.
  • key : The key to insert. Must implement Hash and Eq traits.

Returns true if the key was successfully added (i.e., it wasn't already present), false if the key already existed in the set.

Example:

test {
let set : @hashset.HashSet[String] = HashSet([])
inspect(set.add_and_check("key"), content="true") // First insertion
inspect(set.add_and_check("key"), content="false") // Already exists
inspect(set.length(), content="1")
}

#
HashSet::capacity

fn[K] HashSet::capacity(self : HashSet[K]) -> Int

Returns the current capacity of the internal storage.

#
HashSet::clear

fn[K] HashSet::clear(self : HashSet[K]) -> Unit

Clears the set, removing all keys. Keeps the allocated space.

#
HashSet::contains

fn[K : Hash + Eq] HashSet::contains(self : HashSet[K], key : K) -> Bool

Returns true if the set contains the given key.

#
HashSet::copy

#alias(clone, deprecated="`clone` is deprecated, use `copy` instead")
fn[K] HashSet::copy(self : HashSet[K]) -> HashSet[K]

Copy the set, creating a new set with the same keys.

#
HashSet::difference

fn[K : Hash + Eq] HashSet::difference(self : HashSet[K], other : HashSet[K]) -> HashSet[K]

Returns a new set containing elements in self that are not in other.

#
HashSet::each

fn[K] HashSet::each(self : HashSet[K], f : (K) -> Unit raise?) -> Unit raise?

Calls f on each element in the set.

#
HashSet::eachi

fn[K] HashSet::eachi(self : HashSet[K], f : (Int, K) -> Unit raise?) -> Unit raise?

Calls f on each element with its index (0-based).

#
HashSet::from_iter

#as_free_fn(from_iterator, deprecated="Use HashSet::from_iter instead.")
#alias(from_iterator, deprecated="`from_iterator` is deprecated, use `from_iter` instead")
#as_free_fn
fn[K : Hash + Eq] HashSet::from_iter(iter : Iter[K]) -> HashSet[K]

Creates a hash set from an iterator of keys.

#
HashSet::intersection

fn[K : Hash + Eq] HashSet::intersection(self : HashSet[K], other : HashSet[K]) -> HashSet[K]

Returns a new set containing only elements present in both sets.

#
HashSet::is_disjoint

fn[K : Hash + Eq] HashSet::is_disjoint(self : HashSet[K], other : HashSet[K]) -> Bool

Returns true if the two sets have no elements in common.

#
HashSet::is_empty

fn[K] HashSet::is_empty(self : HashSet[K]) -> Bool

Returns true if the set contains no elements.

#
HashSet::is_subset

fn[K : Hash + Eq] HashSet::is_subset(self : HashSet[K], other : HashSet[K]) -> Bool

Returns true if every element of self is also in other.

#
HashSet::is_superset

fn[K : Hash + Eq] HashSet::is_superset(self : HashSet[K], other : HashSet[K]) -> Bool

Returns true if every element of other is also in self.

#
HashSet::iter

#alias(iterator, deprecated="`iterator` is deprecated, use `iter` instead")
fn[K] HashSet::iter(self : HashSet[K]) -> Iter[K]

Returns an iterator over the elements of the set.

#
HashSet::land

fn[K : Hash + Eq] HashSet::land(self : HashSet[K], other : HashSet[K]) -> HashSet[K]

#
HashSet::length

#alias(size, deprecated="`size` is deprecated, use `length` instead")
fn[K] HashSet::length(self : HashSet[K]) -> Int

Returns the number of elements in the set.

#
HashSet::lor

fn[K : Hash + Eq] HashSet::lor(self : HashSet[K], other : HashSet[K]) -> HashSet[K]

#
HashSet::lxor

fn[K : Hash + Eq] HashSet::lxor(self : HashSet[K], other : HashSet[K]) -> HashSet[K]

#
HashSet::new

#as_free_fn(deprecated="Use `HashSet([], capacity=...)` instead")
#deprecated("Use `HashSet([], capacity=...)` instead")
fn[K] HashSet::new(capacity? : Int) -> HashSet[K]

Creates an empty hash set with an optional initial capacity.

Deprecated: use HashSet([], capacity=...) instead.

#
HashSet::remove

fn[K : Hash + Eq] HashSet::remove(self : HashSet[K], key : K) -> Unit

Remove a key from hash set. If the key exists in the set, removes it and adjusts the probe sequence length (PSL) of subsequent entries to maintain the Robin Hood hashing invariant. If the key does not exist, the set remains unchanged.

Parameters:

  • self : The hash set to remove the key from.
  • key : The key to remove from the set.

Example:

test {
let set = @hashset.from_array(["a", "b"])
set.remove("a")
inspect(set.contains("a"), content="false")
inspect(set.length(), content="1")
}

#
HashSet::remove_and_check

fn[K : Hash + Eq] HashSet::remove_and_check(self : HashSet[K], key : K) -> Bool

Remove a key from the hash set and returns whether the key was successfully removed.

Parameters:

  • self : The hash set to modify.
  • key : The key to remove. Must implement Hash and Eq traits.

Returns true if the key was successfully removed (i.e., it was present), false if the key didn't exist in the set.

Example:

test {
let set = @hashset.from_array(["a", "b"])
inspect(set.remove_and_check("a"), content="true") // Successfully removed
inspect(set.remove_and_check("a"), content="false") // Already removed
inspect(set.length(), content="1")
}

#
HashSet::retain

fn[K] HashSet::retain(self : HashSet[K], f : (K) -> Bool) -> Unit

Removes all elements for which the predicate returns false.

#
HashSet::sub

fn[K : Hash + Eq] HashSet::sub(self : HashSet[K], other : HashSet[K]) -> HashSet[K]

#
HashSet::symmetric_difference

fn[K : Hash + Eq] HashSet::symmetric_difference(self : HashSet[K], other : HashSet[K]) -> HashSet[K]

Symmetric difference of two hash sets.

#
HashSet::to_array

fn[K] HashSet::to_array(self : HashSet[K]) -> Array[K]

Converts the hash set to an array.

#
HashSet::union

fn[K : Hash + Eq] HashSet::union(self : HashSet[K], other : HashSet[K]) -> HashSet[K]

Returns a new set containing all elements from both sets.