Skip to content

Instantly share code, notes, and snippets.

@evaporei
Created November 9, 2025 19:24
Show Gist options
  • Select an option

  • Save evaporei/77b2b128ef8dfcfb920435535926fcb9 to your computer and use it in GitHub Desktop.

Select an option

Save evaporei/77b2b128ef8dfcfb920435535926fcb9 to your computer and use it in GitHub Desktop.
Set helpers for Odin
#+feature dynamic-literals
// Set helpers
package venn
import te "core:testing"
// Returns whether `a` is equal to `b`
eq :: proc(a: map[$T]struct{}, b: map[T]struct{}) -> bool {
if len(a) != len(b) do return false
for k, _ in a do if !(k in b) do return false
return true
}
@(test)
eq_test :: proc(t: ^te.T) {
a := map[int]struct{} {
1 = {},
2 = {},
3 = {},
}; defer delete(a)
b := map[int]struct{} {
2 = {},
3 = {},
4 = {},
5 = {},
}; defer delete(b)
// same as `a`
c := map[int]struct{} {
1 = {},
2 = {},
3 = {},
}; defer delete(c)
te.expect(t, eq(a, c))
te.expect(t, !eq(a, b))
te.expect(t, !eq(b, c))
}
// Returns values that are in `a` or `b`
union_ :: proc(a: map[$T]struct{}, b: map[T]struct{}) -> (c: map[T]struct{}) {
reserve(&c, len(a) + len(b))
for k, v in a do c[k] = v
for k, v in b do c[k] = v
return
}
@(test)
union_test :: proc(t: ^te.T) {
a := map[int]struct{} {
1 = {},
2 = {},
3 = {},
}; defer delete(a)
b := map[int]struct{} {
2 = {},
3 = {},
4 = {},
5 = {},
}; defer delete(b)
exp_c := map[int]struct{} {
1 = {},
2 = {},
3 = {},
4 = {},
5 = {},
}; defer delete(exp_c)
c := union_(a, b); defer delete(c)
for exp_k, _ in exp_c do te.expect(t, exp_k in c)
te.expect(t, len(c) == len(exp_c))
}
// Returns values that are in `a` but not in `b`
diff :: proc(a: map[$T]struct{}, b: map[T]struct{}) -> (c: map[T]struct{}) {
reserve(&c, len(a))
for k, v in a do if !(k in b) do c[k] = v
return
}
@(test)
diff_test :: proc(t: ^te.T) {
a := map[int]struct{} {
1 = {},
2 = {},
3 = {},
}; defer delete(a)
b := map[int]struct{} {
2 = {},
3 = {},
4 = {},
5 = {},
}; defer delete(b)
exp_c := map[int]struct{} {
1 = {},
}; defer delete(exp_c)
c := diff(a, b); defer delete(c)
for exp_k, _ in exp_c do te.expect(t, exp_k in c)
te.expect(t, len(c) == len(exp_c))
}
// Returns values that are both in `a` and `b`
intersection :: proc(a: map[$T]struct{}, b: map[T]struct{}) -> (c: map[T]struct{}) {
reserve(&c, len(a))
for k, v in a do if k in b do c[k] = v
return
}
@(test)
intersection_test :: proc(t: ^te.T) {
a := map[int]struct{} {
1 = {},
2 = {},
3 = {},
}; defer delete(a)
b := map[int]struct{} {
2 = {},
3 = {},
4 = {},
5 = {},
}; defer delete(b)
exp_c := map[int]struct{} {
2 = {},
3 = {},
}; defer delete(exp_c)
c := intersection(a, b); defer delete(c)
for exp_k, _ in exp_c do te.expect(t, exp_k in c)
te.expect(t, len(c) == len(exp_c))
}
// Returns `true` if `a` has no elements in common with `b`.
// This is equivalent to checking for an empty intersection.
is_disjoint :: proc(a: map[$T]struct{}, b: map[T]struct{}) -> bool {
if len(a) <= len(b) {
for k, _ in a do if k in b do return false
} else {
for k, _ in b do if k in a do return false
}
return true
}
@(test)
is_disjoint_test :: proc(t: ^te.T) {
a := map[int]struct{} {
1 = {},
2 = {},
3 = {},
}; defer delete(a)
b := map[int]struct{}{}; defer delete(b)
te.expect(t, is_disjoint(a, b))
b[4] = {}
te.expect(t, is_disjoint(a, b))
b[1] = {}
te.expect(t, !is_disjoint(a, b))
}
// Returns `true` if `a` is a subset of `b`,
// i.e., `b` contains at least all the values in `a`.
is_subset :: proc(a: map[$T]struct{}, b: map[T]struct{}) -> bool {
if len(a) <= len(b) {
for k, _ in a do if !(k in b) do return false
return true
}
return false
}
@(test)
is_subset_test :: proc(t: ^te.T) {
subset := map[int]struct{}{}; defer delete(subset)
super := map[int]struct{} {
1 = {},
2 = {},
3 = {},
}; defer delete(super)
te.expect(t, is_subset(subset, super))
subset[2] = {}
te.expect(t, is_subset(subset, super))
subset[4] = {}
te.expect(t, !is_subset(subset, super))
}
// Returns `true` if `a` is a superset of `b`,
// i.e., `a` contains at least all the values in `b`.
is_superset :: proc(a: map[$T]struct{}, b: map[T]struct{}) -> bool {
return is_subset(b, a)
}
@(test)
is_superset_test :: proc(t: ^te.T) {
subset := map[int]struct{} {
1 = {},
2 = {},
}; defer delete(subset)
superset := map[int]struct{}{}; defer delete(superset)
te.expect(t, !is_superset(superset, subset))
superset[0] = {}
superset[1] = {}
te.expect(t, !is_superset(superset, subset))
superset[2] = {}
te.expect(t, is_superset(superset, subset))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment