Created
November 9, 2025 19:24
-
-
Save evaporei/77b2b128ef8dfcfb920435535926fcb9 to your computer and use it in GitHub Desktop.
Set helpers for Odin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #+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