Skip to content
Merged
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
7 changes: 7 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ All types implement `json.Marshaler`/`json.Unmarshaler` and `sql.Scanner`. The `

When bumping the minimum Go version, the commit message should include `#minor` to trigger a minor version bump.

## Conventions

- **Zero-value style**: Use `var x T` instead of `x := T{}`; refer to this as "T's zero value" in prose.
- **Tests are the spec**: When modifying implementations, do not change tests. Treat test failures as implementation bugs.
- **Mathematical correctness**: Prefer mathematically correct semantics (e.g., vacuous truth for empty predicates).
- **Commit messages**: Use conventional commits (`feat:`, `fix:`, `docs:`, etc.).

## Testing

Tests use property-based state machine testing via `pgregory.net/rapid`. The state machine in `set_test.go` validates invariants across all set implementations. Tests run in parallel.
5 changes: 5 additions & 0 deletions examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,10 @@ func ExampleContainsSeq() {
ints.Add(3)
ints.Add(2)

if ContainsSeq(ints, slices.Values([]int{})) {
fmt.Println("Non-empty set contains empty sequence")
}

if ContainsSeq(ints, slices.Values([]int{3, 5})) {
fmt.Println("3 and 5 are present")
}
Expand All @@ -321,6 +325,7 @@ func ExampleContainsSeq() {
}
// Output:
// Empty set contains empty sequence
// Non-empty set contains empty sequence
// 3 and 5 are present
// 6 is not present
}
Expand Down
4 changes: 2 additions & 2 deletions map.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func (s *Map[M]) Clear() int {

// Add an element to the set. Returns true if the element was added, false if it was already present.
func (s *Map[M]) Add(m M) bool {
if s.Contains(m) {
if _, ok := s.set[m]; ok {
return false
}
s.set[m] = struct{}{}
Expand All @@ -68,7 +68,7 @@ func (s *Map[M]) Add(m M) bool {

// Remove an element from the set. Returns true if the element was removed, false if it was not present.
func (s *Map[M]) Remove(m M) bool {
if !s.Contains(m) {
if _, ok := s.set[m]; !ok {
return false
}
delete(s.set, m)
Expand Down
13 changes: 8 additions & 5 deletions set.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,19 +145,22 @@ func Equal[K comparable](a, b Set[K]) bool {
if a.Cardinality() != b.Cardinality() {
return false
}
return Subset(a, b) && Subset(b, a)
for k := range a.Iterator {
if !b.Contains(k) {
return false
}
}
return true
}

// ContainsSeq returns true if the set contains all elements in the sequence. Empty sets are considered to contain only empty sequences.
// ContainsSeq returns true if the set contains all elements in the sequence. Returns true for an empty sequence (vacuous truth).
func ContainsSeq[K comparable](s Set[K], seq iter.Seq[K]) bool {
noitems := true
for k := range seq {
noitems = false
if !s.Contains(k) {
return false
}
}
return (s.Cardinality() == 0 && noitems) || !noitems
return true
Comment thread
freeformz marked this conversation as resolved.
}

// Disjoint returns true if the two sets have no elements in common.
Expand Down
Loading