Skip to content

Commit

Permalink
Merge pull request #26 from life4/sets
Browse files Browse the repository at this point in the history
New package: sets
  • Loading branch information
orsinium authored Sep 19, 2023
2 parents fc597f7 + 98e66ea commit 881b521
Show file tree
Hide file tree
Showing 24 changed files with 1,098 additions and 12 deletions.
10 changes: 10 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ jobs:
- uses: actions/checkout@v3
- run: go test -v ./...

pytest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: "3.11"
- run: python3 -m pip install pytest
- run: python3 -m pytest ./scripts

golangci-lint:
runs-on: ubuntu-latest
steps:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ __pycache__/
.vscode
.swp
*~
.task
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,10 @@ codes := slices.MapAsync(

Genesis contains the following packages:

+ [🍞 slices](https://pkg.go.dev/github.com/life4/genesis/slices): generic functions for slices.
+ [🗺 maps](https://pkg.go.dev/github.com/life4/genesis/maps): generic functions for maps.
+ [📺 channels](https://pkg.go.dev/github.com/life4/genesis/channels): generic function for channels.
+ [🍞 slices](https://pkg.go.dev/github.com/life4/genesis/slices): generic functions for slices (`[]T`).
+ [🗺 maps](https://pkg.go.dev/github.com/life4/genesis/maps): generic functions for maps (`map[K]V`).
+ [📺 channels](https://pkg.go.dev/github.com/life4/genesis/channels): generic function for channels (`chan T`).
+ [⚙️ sets](https://pkg.go.dev/github.com/life4/genesis/sets): generic function for sets (`map[T]struct{}`).
+ [🛟 lambdas](https://pkg.go.dev/github.com/life4/genesis/lambdas): helper generic functions to work with `slices.Map` and similar.

See [📄 DOCUMENTATION](https://pkg.go.dev/github.com/life4/genesis) for more info.
8 changes: 8 additions & 0 deletions Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,16 @@ tasks:

test:
desc: Run go tests with coverage and timeout and without cache
cmds:
- task: test:go
- task: test:py

test:go:
cmds:
- go test -count 1 -cover -timeout 1s ./...

test:py:
cmds:
- python3 -m pytest ./scripts

docs:
Expand Down
2 changes: 1 addition & 1 deletion channels/doc.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Package channels provides generic functions for channels.
// 📺 Package channels provides generic functions for channels.
//
// # ☎️ Naming
//
Expand Down
2 changes: 1 addition & 1 deletion constraints/constraints.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package constraints defines a set of useful constraints to be used
// 🙅 Package constraints defines a set of useful constraints to be used
// with type parameters.
package constraints

Expand Down
1 change: 1 addition & 0 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ import (
_ "github.com/life4/genesis/channels"
_ "github.com/life4/genesis/lambdas"
_ "github.com/life4/genesis/maps"
_ "github.com/life4/genesis/sets"
_ "github.com/life4/genesis/slices"
)
2 changes: 1 addition & 1 deletion lambdas/doc.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Package lambdas provides helper generic functions.
// 🛟 Package lambdas provides helper generic functions.
//
// These functions are especially helpful in combination with other `genesis` packages.
package lambdas
2 changes: 1 addition & 1 deletion maps/doc.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Package maps provides generic functions for maps.
// 🗺 Package maps provides generic functions for maps.
//
// The package is inspired by the `Map` Elixir module.
package maps
2 changes: 1 addition & 1 deletion scripts/count_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def count_funcs(pkg: str) -> int:


total = 0
pkgs = ('channels', 'lambdas', 'maps', 'slices')
pkgs = ('channels', 'lambdas', 'maps', 'sets', 'slices')
for pkg in pkgs:
count = count_funcs(pkg)
print(f'{pkg}: {count}')
Expand Down
19 changes: 16 additions & 3 deletions scripts/test_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ def get_examples(pkg: str) -> Iterator[str]:
yield fname


@pytest.mark.parametrize('pkg', ['slices'])
@pytest.mark.parametrize('pkg', [
'slices',
'sets',
])
def test_all_have_examples(pkg: str) -> None:
"""Every function must have an example.
"""
Expand All @@ -64,6 +67,7 @@ def test_all_have_examples(pkg: str) -> None:
'slices',
'maps',
'lambdas',
'sets',
# channels need tests for context-aware versions
# 'channels',
])
Expand All @@ -73,12 +77,21 @@ def test_all_have_tests(pkg: str) -> None:
funcs = set(get_funcs(pkg))
tests = set(get_tests(pkg))
assert funcs
assert not funcs - tests
diff = funcs - tests
assert not diff


@pytest.mark.parametrize('func', get_funcs('slices'))
def test_slices_func_linked_in_docs(func: str) -> None:
"""Every function in the slices package must be listed in the package docs.
"""Every func in the slices package must be listed in the package docs.
"""
docs = Path('slices', 'doc.go').read_text()
assert f'// - [{func}](' in docs


@pytest.mark.parametrize('func', get_funcs('channels'))
def test_channels_func_linked_in_docs(func: str) -> None:
"""Every func in the channels package must be listed in the package docs.
"""
docs = Path('channels', 'doc.go').read_text()
assert f' [{func}]' in docs
3 changes: 3 additions & 0 deletions sets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# genesis/sets

Package sets provides generic functions for sets.
121 changes: 121 additions & 0 deletions sets/bool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package sets

// This file contains functions returning bool.

// Contains returns true if the given set contains the given element.
func Contains[S ~map[K]Z, K comparable](set S, item K) bool {
var found bool
_, found = set[item]
return found
}

// Disjoint returns true if the two given sets don't have any common elements.
func Disjoint[S1, S2 ~map[K]Z, K comparable](first S1, second S2) bool {
for k := range second {
_, common := first[k]
if common {
return false
}
}
return true
}

// DisjointMany returns true if the given sets don't have any common elements.
func DisjointMany[S ~map[K]Z, K comparable](sets ...S) bool {
union := make(map[K]Z)
for _, set := range sets {
for k := range set {
_, seen := union[k]
if seen {
return false
}
union[k] = Z{}
}
}
return true
}

// Empty returns true if the set has no elements
func Empty[S ~map[K]Z, K comparable](set S) bool {
return len(set) == 0
}

// Equal returns true if both given sets have the same elements.
func Equal[S1, S2 ~map[K]Z, K comparable](first S1, second S2) bool {
if len(first) != len(second) {
return false
}
for k := range second {
_, found := first[k]
if !found {
return false
}
}
return true
}

// EqualMany returns true if all the given sets have the same elements.
func EqualMany[S ~map[K]Z, K comparable](sets ...S) bool {
if len(sets) < 2 {
return true
}
first := sets[0]
lFirst := len(first)
for _, set := range sets {
if len(set) != lFirst {
return false
}
}
for _, set := range sets[1:] {
for k := range set {
_, found := first[k]
if !found {
return false
}
}
}
return true
}

// Intersect returns true if the two given sets have at least one common element.
func Intersect[S1, S2 ~map[K]Z, K comparable](first S1, second S2) bool {
for k := range second {
_, common := first[k]
if common {
return true
}
}
return false
}

// Subset returns true if the first set is a subset of the second one.
//
// One set is called a subset of another if all its elements are included in that set.
//
// This function is the same as [Superset] but with inversed argument order.
// Which one to use is a matter of readability.
func Subset[S1, S2 ~map[K]Z, K comparable](small S1, big S2) bool {
for k := range small {
_, found := big[k]
if !found {
return false
}
}
return true
}

// Superset returns true if the first set is a superset of the second one.
//
// One set is called a superset of another if it includes all elements of that set.
//
// This function is the same as [Subset] but with inversed argument order.
// Which one to use is a matter of readability.
func Superset[S1, S2 ~map[K]Z, K comparable](big S1, small S2) bool {
for k := range small {
_, found := big[k]
if !found {
return false
}
}
return true
}
Loading

0 comments on commit 881b521

Please sign in to comment.