aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--METADATA10
-rw-r--r--README.md11
-rw-r--r--bitbucket-pipelines.yml7
-rw-r--r--go.mod4
-rw-r--r--go.sum2
-rw-r--r--makeset/core.go.in451
-rw-r--r--makeset/core_test.go.in680
-rw-r--r--makeset/intset.toml8
-rw-r--r--makeset/makeset.go186
-rw-r--r--makeset/nodeset.toml28
-rw-r--r--makeset/stringset.toml11
-rw-r--r--stringset.go25
-rw-r--r--stringset_test.go102
13 files changed, 74 insertions, 1451 deletions
diff --git a/METADATA b/METADATA
index e759a7f..2322b58 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,7 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update go-creachadair-stringset
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+
name: "go-creachadair-stringset"
description: "The stringset package implements a lightweight set-of-strings type based around Go\'s built-in map type."
third_party {
@@ -9,11 +13,11 @@ third_party {
type: GIT
value: "https://bitbucket.org/creachadair/stringset/"
}
- version: "v0.0.10"
+ version: "v0.0.11"
license_type: NOTICE
last_upgrade_date {
- year: 2022
+ year: 2023
month: 3
- day: 29
+ day: 15
}
}
diff --git a/README.md b/README.md
index f6b73ae..53afe50 100644
--- a/README.md
+++ b/README.md
@@ -6,14 +6,3 @@ http://godoc.org/bitbucket.org/creachadair/stringset
The `stringset` package implements a lightweight set-of-strings type based
around Go's built-in map type.
-
-## Generating the Code
-
-The `stringset` package is generated by the `makeset` program from source
-templates `core.go.in` (the main package source) and `core_test.go.in` (for the
-unit tests). To change the implementation, modify those templates and
-re-generate the package source by running:
-
-```shell
-go run ./makeset -config makeset/stringset.toml -output .
-```
diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml
index 8acd906..9a12ca0 100644
--- a/bitbucket-pipelines.yml
+++ b/bitbucket-pipelines.yml
@@ -16,8 +16,11 @@ definitions:
pipelines:
default: # run on each push
- step:
- image: golang:1.16
+ image: golang:1.17
<<: *Verify
- step:
- image: golang:1.17
+ image: golang:1.18
+ <<: *Verify
+ - step:
+ image: golang:1.19
<<: *Verify
diff --git a/go.mod b/go.mod
index 8b84500..c08e719 100644
--- a/go.mod
+++ b/go.mod
@@ -1,5 +1,3 @@
module bitbucket.org/creachadair/stringset
-go 1.16
-
-require github.com/BurntSushi/toml v0.4.1
+go 1.18
diff --git a/go.sum b/go.sum
index 4c4b384..e69de29 100644
--- a/go.sum
+++ b/go.sum
@@ -1,2 +0,0 @@
-github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=
-github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
diff --git a/makeset/core.go.in b/makeset/core.go.in
deleted file mode 100644
index 8f28a3c..0000000
--- a/makeset/core.go.in
+++ /dev/null
@@ -1,451 +0,0 @@
-{{/* The main source for the package, including doc comments. */ -}}
-// Package {{.Package}} implements a lightweight (finite) set of {{.Type}} values
-// based on Go's built-in map. A Set provides some convenience methods for
-// common set operations.
-//
-// A nil Set is ready for use as an empty set. The basic set methods (Diff,
-// Intersect, Union, IsSubset, Map, Choose, Partition) do not mutate their
-// arguments. There are also mutating operations (Add, Discard, Pop, Remove,
-// Update) that modify their receiver in-place.
-//
-// A Set can also be traversed and modified using the normal map operations.
-// Being a map, a Set is not safe for concurrent access by multiple goroutines
-// unless all the concurrent accesses are reads.
-package {{.Package}}
-
-import (
-{{range .Imports}}{{printf "%q" .}}
-{{end}}
-)
-
-{{if .Decl}}
-// {{.Type}} is the type of the elements of the set.
-type {{.Type}} {{.Decl}}{{end}}
-
-{{if .Less}}
-// isLess reports whether x is less than y in standard order.
-func isLess(x, y {{.Type}}) bool {
- {{.Less}}
-}{{end}}
-
-{{if .ToString}}func toString(x {{.Type}}) string {
- {{.ToString}}
-}{{end}}
-
-// A Set represents a set of {{.Type}} values. A nil Set is a valid
-// representation of an empty set.
-type Set map[{{.Type}}]struct{}
-
-// byElement satisfies sort.Interface to order values of type {{.Type}}.
-type byElement []{{.Type}}
-func(e byElement) Len() int { return len(e) }
-func (e byElement) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
-func (e byElement) Less(i, j int) bool {
- {{if .Less}}return isLess(e[i], e[j]){{else}}return e[i] < e[j]{{end}}
-}
-
-// String implements the fmt.Stringer interface. It renders s in standard set
-// notation, e.g., ø for an empty set, {a, b, c} for a nonempty one.
-func (s Set) String() string {
- if s.Empty() {
- return "ø"
- }
- elts := make([]string, len(s))
- for i, elt := range s.Elements() {
- elts[i] = {{if .ToString}}toString{{else}}fmt.Sprint{{end}}(elt)
- }
- return "{" + strings.Join(elts, ", ") + "}"
-}
-
-// New returns a new set containing exactly the specified elements.
-// Returns a non-nil empty Set if no elements are specified.
-func New(elts ...{{.Type}}) Set {
- set := make(Set, len(elts))
- for _, elt := range elts {
- set[elt] = struct{}{}
- }
- return set
-}
-
-// NewSize returns a new empty set pre-sized to hold at least n elements.
-// This is equivalent to make(Set, n) and will panic if n < 0.
-func NewSize(n int) Set { return make(Set, n) }
-
-// Len returns the number of elements in s.
-func (s Set) Len() int { return len(s) }
-
-// Elements returns an ordered slice of the elements in s.
-func (s Set) Elements() []{{.Type}} {
- elts := s.Unordered()
- sort.Sort(byElement(elts))
- return elts
-}
-
-// Unordered returns an unordered slice of the elements in s.
-func (s Set) Unordered() []{{.Type}} {
- if len(s) == 0 {
- return nil
- }
- elts := make([]{{.Type}}, 0, len(s))
- for elt := range s {
- elts = append(elts, elt)
- }
- return elts
-}
-
-// Clone returns a new Set distinct from s, containing the same elements.
-func (s Set) Clone() Set {
- var c Set
- c.Update(s)
- return c
-}
-
-// ContainsAny reports whether s contains one or more of the given elements.
-// It is equivalent in meaning to
-// s.Intersects({{.Package}}.New(elts...))
-// but does not construct an intermediate set.
-func (s Set) ContainsAny(elts ...{{.Type}}) bool {
- for _, key := range elts {
- if _, ok := s[key]; ok {
- return true
- }
- }
- return false
-}
-
-// Contains reports whether s contains (all) the given elements.
-// It is equivalent in meaning to
-// New(elts...).IsSubset(s)
-// but does not construct an intermediate set.
-func (s Set) Contains(elts ...{{.Type}}) bool {
- for _, elt := range elts {
- if _, ok := s[elt]; !ok {
- return false
- }
- }
- return true
-}
-
-// IsSubset reports whether s is a subset of s2, s ⊆ s2.
-func (s Set) IsSubset(s2 Set) bool {
- if s.Empty() {
- return true
- } else if len(s) > len(s2) {
- return false
- }
- for k := range s {
- if _, ok := s2[k]; !ok {
- return false
- }
- }
- return true
-}
-
-// Equals reports whether s is equal to s2, having exactly the same elements.
-func (s Set) Equals(s2 Set) bool { return len(s) == len(s2) && s.IsSubset(s2) }
-
-// Empty reports whether s is empty.
-func (s Set) Empty() bool { return len(s) == 0 }
-
-// Intersects reports whether the intersection s ∩ s2 is non-empty, without
-// explicitly constructing the intersection.
-func (s Set) Intersects(s2 Set) bool {
- a, b := s, s2
- if len(b) < len(a) {
- a, b = b, a // Iterate over the smaller set
- }
- for k := range a {
- if _, ok := b[k]; ok {
- return true
- }
- }
- return false
-}
-
-// Union constructs the union s ∪ s2.
-func (s Set) Union(s2 Set) Set {
- if s.Empty() {
- return s2
- } else if s2.Empty() {
- return s
- }
- set := make(Set)
- for k := range s {
- set[k] = struct{}{}
- }
- for k := range s2 {
- set[k] = struct{}{}
- }
- return set
-}
-
-// Intersect constructs the intersection s ∩ s2.
-func (s Set) Intersect(s2 Set) Set {
- if s.Empty() || s2.Empty() {
- return nil
- }
- set := make(Set)
- for k := range s {
- if _, ok := s2[k]; ok {
- set[k] = struct{}{}
- }
- }
- if len(set) == 0 {
- return nil
- }
- return set
-}
-
-// Diff constructs the set difference s \ s2.
-func (s Set) Diff(s2 Set) Set {
- if s.Empty() || s2.Empty() {
- return s
- }
- set := make(Set)
- for k := range s {
- if _, ok := s2[k]; !ok {
- set[k] = struct{}{}
- }
- }
- if len(set) == 0 {
- return nil
- }
- return set
-}
-
-// SymDiff constructs the symmetric difference s ∆ s2.
-// It is equivalent in meaning to (s ∪ s2) \ (s ∩ s2).
-func (s Set) SymDiff(s2 Set) Set {
- return s.Union(s2).Diff(s.Intersect(s2))
-}
-
-// Update adds the elements of s2 to *s in-place, and reports whether anything
-// was added.
-// If *s == nil and s2 ≠ ø, a new set is allocated that is a copy of s2.
-func (s *Set) Update(s2 Set) bool {
- in := len(*s)
- if *s == nil && len(s2) > 0 {
- *s = make(Set)
- }
- for k := range s2 {
- (*s)[k] = struct{}{}
- }
- return len(*s) != in
-}
-
-// Add adds the specified elements to *s in-place and reports whether anything
-// was added. If *s == nil, a new set equivalent to New(ss...) is stored in *s.
-func (s *Set) Add(ss ...{{.Type}}) bool {
- in := len(*s)
- if *s == nil {
- *s = make(Set)
- }
- for _, key := range ss {
- (*s)[key] = struct{}{}
- }
- return len(*s) != in
-}
-
-// Remove removes the elements of s2 from s in-place and reports whether
-// anything was removed.
-//
-// Equivalent to s = s.Diff(s2), but does not allocate a new set.
-func (s Set) Remove(s2 Set) bool {
- in := s.Len()
- if !s.Empty() {
- for k := range s2 {
- delete(s, k)
- }
- }
- return s.Len() != in
-}
-
-// Discard removes the elements of elts from s in-place and reports whether
-// anything was removed.
-//
-// Equivalent to s.Remove(New(elts...)), but does not allocate an intermediate
-// set for ss.
-func (s Set) Discard(elts ...{{.Type}}) bool {
- in := s.Len()
- if !s.Empty() {
- for _, elt := range elts {
- delete(s, elt)
- }
- }
- return s.Len() != in
-}
-
-// Index returns the first offset of needle in elts, if it occurs; otherwise -1.
-func Index(needle {{.Type}}, elts []{{.Type}}) int {
- for i, elt := range elts {
- if elt == needle {
- return i
- }
- }
- return -1
-}
-
-// Contains reports whether v contains s, for v having type Set, []{{.Type}},
-// map[{{.Type}}]T, or Keyer. It returns false if v's type does not have one of
-// these forms.
-func Contains(v interface{}, s {{.Type}}) bool {
- switch t := v.(type) {
- case []{{.Type}}:
- return Index(s, t) >= 0
- case Set:
- return t.Contains(s)
- case Keyer:
- return Index(s, t.Keys()) >= 0
- }
- if m := reflect.ValueOf(v); m.IsValid() && m.Kind() == reflect.Map && m.Type().Key() == refType {
- return m.MapIndex(reflect.ValueOf(s)).IsValid()
- }
- return false
-}
-
-// A Keyer implements a Keys method that returns the keys of a collection such
-// as a map or a Set.
-type Keyer interface {
- // Keys returns the keys of the receiver, which may be nil.
- Keys() []{{.Type}}
-}
-
-var refType = reflect.TypeOf((*{{.Type}})(nil)).Elem()
-
-// FromKeys returns a Set of {{.Type}}s from v, which must either be a {{.Type}},
-// a []{{.Type}}, a map[{{.Type}}]T, or a Keyer. It returns nil if v's type does
-// not have one of these forms.
-func FromKeys(v interface{}) Set {
- var result Set
- switch t := v.(type) {
- case {{.Type}}:
- return New(t)
- case []{{.Type}}:
- for _, key := range t {
- result.Add(key)
- }
- return result
- case map[{{.Type}}]struct{}: // includes Set
- for key := range t {
- result.Add(key)
- }
- return result
- case Keyer:
- return New(t.Keys()...)
- case nil:
- return nil
- }
- m := reflect.ValueOf(v)
- if m.Kind() != reflect.Map || m.Type().Key() != refType {
- return nil
- }
- for _, key := range m.MapKeys() {
- result.Add(key.Interface().({{.Type}}))
- }
- return result
-}
-
-// FromIndexed returns a Set constructed from the values of f(i) for
-// each 0 ≤ i < n. If n ≤ 0 the result is nil.
-func FromIndexed(n int, f func(int) {{.Type}}) Set {
- var set Set
- for i := 0; i < n; i++ {
- set.Add(f(i))
- }
- return set
-}
-
-// FromValues returns a Set of the values from v, which has type map[T]{{.Type}}.
-// Returns the empty set if v does not have a type of this form.
-func FromValues(v interface{}) Set {
- if t := reflect.TypeOf(v); t == nil || t.Kind() != reflect.Map || t.Elem() != refType {
- return nil
- }
- var set Set
- m := reflect.ValueOf(v)
- for _, key := range m.MapKeys() {
- set.Add(m.MapIndex(key).Interface().({{.Type}}))
- }
- return set
-}
-
-{{if .Transforms}}
-// Map returns the Set that results from applying f to each element of s.
-func (s Set) Map(f func({{.Type}}) {{.Type}}) Set {
- var out Set
- for k := range s {
- out.Add(f(k))
- }
- return out
-}
-
-// Each applies f to each element of s.
-func (s Set) Each(f func({{.Type}})) {
- for k := range s {
- f(k)
- }
-}
-
-// Select returns the subset of s for which f returns true.
-func (s Set) Select(f func({{.Type}}) bool) Set {
- var out Set
- for k := range s {
- if f(k) {
- out.Add(k)
- }
- }
- return out
-}
-
-// Partition returns two disjoint sets, yes containing the subset of s for
-// which f returns true and no containing the subset for which f returns false.
-func (s Set) Partition(f func({{.Type}}) bool) (yes, no Set) {
- for k := range s {
- if f(k) {
- yes.Add(k)
- } else {
- no.Add(k)
- }
- }
- return
-}
-
-// Choose returns an element of s for which f returns true, if one exists. The
-// second result reports whether such an element was found.
-// If f == nil, chooses an arbitrary element of s. The element chosen is not
-// guaranteed to be the same across repeated calls.
-func (s Set) Choose(f func({{.Type}}) bool) ({{.Type}}, bool) {
- if f == nil {
- for k := range s {
- return k, true
- }
- }
- for k := range s {
- if f(k) {
- return k, true
- }
- }
- return {{.Zero}}, false
-}
-
-// Pop removes and returns an element of s for which f returns true, if one
-// exists (essentially Choose + Discard). The second result reports whether
-// such an element was found. If f == nil, pops an arbitrary element of s.
-func (s Set) Pop(f func({{.Type}}) bool) ({{.Type}}, bool) {
- if v, ok := s.Choose(f); ok {
- delete(s, v)
- return v, true
- }
- return {{.Zero}}, false
-}
-
-// Count returns the number of elements of s for which f returns true.
-func (s Set) Count(f func({{.Type}}) bool) (n int) {
- for k := range s {
- if f(k) {
- n++
- }
- }
- return
-}
-{{end}}{{/* transforms */}}
diff --git a/makeset/core_test.go.in b/makeset/core_test.go.in
deleted file mode 100644
index a688f5a..0000000
--- a/makeset/core_test.go.in
+++ /dev/null
@@ -1,680 +0,0 @@
-{{/* Generated unit tests from the config examples. */ -}}
-package {{.Package}}
-
-import (
- "reflect"
- "testing"
-
-{{range .TestImports}}{{printf "%q" .}}
-{{end}}
-)
-
-// testValues contains an ordered sequence of ten set keys used for testing.
-// The order of the keys must reflect the expected order of key listings.
-var testValues = [10]{{.Type}}{
-{{range .TestValues}} {{.}},
-{{end}}
-}
-
-func testKeys(ixs ...int) (keys []{{.Type}}) {
- for _, i := range ixs {
- keys = append(keys, testValues[i])
- }
- return
-}
-
-func testSet(ixs ...int) Set { return New(testKeys(ixs...)...) }
-
-func keyPos(key {{.Type}}) int {
- for i, v := range testValues {
- if v == key {
- return i
- }
- }
- return -1
-}
-
-func TestEmptiness(t *testing.T) {
- var s Set
- if !s.Empty() {
- t.Errorf("nil Set is not reported empty: %v", s)
- }
-
- s = New()
- if !s.Empty() {
- t.Errorf("Empty Set is not reported empty: %v", s)
- }
- if s == nil {
- t.Error("New() unexpectedly returned nil")
- }
-
- if s := testSet(0); s.Empty() {
- t.Errorf("Nonempty Set is reported empty: %v", s)
- }
-}
-
-func TestClone(t *testing.T) {
- a := New(testValues[:]...)
- b := testSet(1, 8, 5)
- c := a.Clone()
- c.Remove(b)
- if c.Equals(a) {
- t.Errorf("Unexpected equality: %v == %v", a, c)
- } else {
- t.Logf("%v.Clone().Remove(%v) == %v", a, b, c)
- }
- c.Update(b)
- if !c.Equals(a) {
- t.Errorf("Unexpected inequality: %v != %v", a, c)
- }
-
- var s Set
- if got := s.Clone(); got != nil {
- t.Errorf("Clone of nil set: got %v, want nil", got)
- }
-}
-
-func TestUniqueness(t *testing.T) {
- // Sets should not contain duplicates. Obviously this is impossible with
- // the map implementation, but other representations are viable.
- s := testSet(0, 5, 1, 2, 1, 3, 8, 4, 9, 4, 4, 6, 7, 2, 0, 0, 1, 4, 8, 4, 9)
- if got, want := s.Len(), len(testValues); got != want {
- t.Errorf("s.Len(): got %d, want %d [%v]", got, want, s)
- }
-
- // Keys should come out sorted.
- if got := s.Elements(); !reflect.DeepEqual(got, testValues[:]) {
- t.Errorf("s.Elements():\n got %+v,\nwant %+v", got, testValues)
- }
-}
-
-func TestMembership(t *testing.T) {
- s := testSet(0, 1, 2, 3, 4)
- for i, v := range testValues {
- if got, want := s.ContainsAny(v), i < 5; got != want {
- t.Errorf("s.ContainsAny(%v): got %v, want %v", v, got, want)
- }
- }
-
-{{if .Transforms}}
- // Test non-mutating selection.
- if got, ok := s.Choose(func(s {{.Type}}) bool {
- return s == testValues[0]
- }); !ok {
- t.Error("Choose(0): missing element")
- } else {
- t.Logf("Found %v for element 0", got)
- }
- if got, ok := s.Choose(func({{.Type}}) bool { return false }); ok {
- t.Errorf(`Choose(impossible): got %v, want {{.Zero}}`, got)
- }
- if got, ok := New().Choose(nil); ok {
- t.Errorf(`Choose(nil): got %v, want {{.Zero}}`, got)
- }
-
- // Test mutating selection.
- if got, ok := s.Pop(func(s {{.Type}}) bool {
- return s == testValues[1]
- }); !ok {
- t.Error("Pop(1): missing element")
- } else {
- t.Logf("Found %v for element 1", got)
- }
- // A popped item is removed from the set.
- if len(s) != 4 {
- t.Errorf("Length after pop: got %d, want %d", len(s), 4)
- }
- // Pop of a nonexistent key returns not-found.
- if got, ok := s.Pop(func({{.Type}}) bool { return false }); ok {
- t.Errorf(`Pop(impossible): got %v, want {{.Zero}}`, got)
- }
- // Pop from an empty set returns not-found.
- if got, ok := New().Pop(nil); ok {
- t.Errorf(`Pop(nil) on empty: got %v, want {{.Zero}}`, got)
- }{{end}}
-}
-
-func TestContainsAny(t *testing.T) {
- set := New(testValues[2:]...)
- tests := []struct {
- keys []{{.Type}}
- want bool
- }{
- {nil, false},
- {[]{{.Type}}{}, false},
- {testKeys(0), false},
- {testKeys(1), false},
- {testKeys(0, 1), false},
- {testKeys(7), true},
- {testKeys(8, 3, 4, 9), true},
- {testKeys(0, 7, 1, 0), true},
- }
- t.Logf("Test set: %v", set)
- for _, test := range tests {
- got := set.ContainsAny(test.keys...)
- if got != test.want {
- t.Errorf("ContainsAny(%+v): got %v, want %v", test.keys, got, test.want)
- }
- }
-}
-
-func TestContainsAll(t *testing.T) {
- //set := New("a", "e", "i", "y")
- set := New(testValues[2:]...)
- tests := []struct {
- keys []{{.Type}}
- want bool
- }{
- {nil, true},
- {[]{{.Type}}{}, true},
- {testKeys(2, 4, 6), true},
- {testKeys(1, 3, 5, 7), false},
- {testKeys(0), false},
- {testKeys(5, 5, 5), true},
- }
- t.Logf("Test set: %v", set)
- for _, test := range tests {
- got := set.Contains(test.keys...)
- if got != test.want {
- t.Errorf("Contains(%+v): got %v, want %v", test.keys, got, test.want)
- }
- }
-}
-
-func TestIsSubset(t *testing.T) {
- var empty Set
- key := testSet(0, 2, 6, 7, 9)
- for _, test := range [][]{{.Type}}{
- {}, testKeys(2, 6), testKeys(0, 7, 9),
- } {
- probe := New(test...)
- if !probe.IsSubset(key) {
- t.Errorf("IsSubset %+v ⊂ %+v is false", probe, key)
- }
- if !empty.IsSubset(probe) { // ø is a subset of everything, including itself.
- t.Errorf("IsSubset ø ⊂ %+v is false", probe)
- }
- }
-}
-
-func TestNotSubset(t *testing.T) {
- tests := []struct {
- probe, key Set
- }{
- {testSet(0), New()},
- {testSet(0), testSet(1)},
- {testSet(0, 1), testSet(1)},
- {testSet(0, 2, 1), testSet(0, 2, 3)},
- }
- for _, test := range tests {
- if test.probe.IsSubset(test.key) {
- t.Errorf("IsSubset %+v ⊂ %+v is true", test.probe, test.key)
- }
- }
-}
-
-func TestEquality(t *testing.T) {
- nat := New(testValues[:]...)
- odd := testSet(1, 3, 4, 5, 8)
- tests := []struct {
- left, right Set
- eq bool
- }{
- {nil, nil, true},
- {nat, nat, true}, // Equality with the same value
- {testSet(0), testSet(0), true}, // Equality with Different values
- {testSet(0), nil, false},
- {nat, odd, false},
- {nil, testSet(0), false},
- {testSet(0), testSet(1), false},
-
- // Various set operations...
- {nat.Intersect(odd), odd, true},
- {odd, nat.Intersect(odd), true},
- {odd.Intersect(nat), odd, true},
- {odd, odd.Intersect(nat), true},
- {nat.Intersect(nat), nat, true},
- {nat, nat.Intersect(nat), true},
- {nat.Union(odd), nat, true},
- {nat, nat.Union(odd), true},
- {odd.Diff(nat), odd, false},
- {odd, odd.Diff(nat), false},
- {odd.Diff(nat), nil, true},
- {nil, odd.Diff(nat), true},
-
- {testSet(0, 1, 2).Diff(testSet(2, 5, 6)), testSet(1).Union(testSet(0)), true},
- }
- for _, test := range tests {
- if got := test.left.Equals(test.right); got != test.eq {
- t.Errorf("%v.Equals(%v): got %v, want %v", test.left, test.right, got, test.eq)
- }
- }
-}
-
-func TestUnion(t *testing.T) {
- vkeys := testKeys(0, 4)
- vowels := testSet(4, 0)
- consonants := testSet(1, 2, 3, 5, 6, 7, 8, 9)
-
- if got := vowels.Union(nil).Elements(); !reflect.DeepEqual(got, vkeys) {
- t.Errorf("Vowels ∪ ø: got %+v, want %+v", got, vkeys)
- }
- if got := New().Union(vowels).Elements(); !reflect.DeepEqual(got, vkeys) {
- t.Errorf("ø ∪ Vowels: got %+v, want %+v", got, vkeys)
- }
-
- if got, want := vowels.Union(consonants).Elements(), testValues[:]; !reflect.DeepEqual(got, want) {
- t.Errorf("Vowels ∪ Consonants: got %+v, want %+v", got, want)
- }
-}
-
-func TestIntersect(t *testing.T) {
- empty := New()
- nat := New(testValues[:]...)
- odd := testSet(1, 3, 5, 7, 9)
- prime := testSet(2, 3, 5, 7)
-
- tests := []struct {
- left, right Set
- want []{{.Type}}
- }{
- {empty, empty, nil},
- {empty, nat, nil},
- {nat, empty, nil},
- {nat, nat, testValues[:]},
- {nat, odd, testKeys(1, 3, 5, 7, 9)},
- {odd, nat, testKeys(1, 3, 5, 7, 9)},
- {odd, prime, testKeys(3, 5, 7)},
- {prime, nat, testKeys(2, 3, 5, 7)},
- }
- for _, test := range tests {
- got := test.left.Intersect(test.right).Elements()
- if !reflect.DeepEqual(got, test.want) {
- t.Errorf("%v ∩ %v: got %+v, want %+v", test.left, test.right, got, test.want)
- } else if want, ok := len(test.want) != 0, test.left.Intersects(test.right); ok != want {
- t.Errorf("%+v.Intersects(%+v): got %v, want %v", test.left, test.right, ok, want)
- }
- }
-}
-
-func TestDiff(t *testing.T) {
- empty := New()
- nat := New(testValues[:]...)
- odd := testSet(1, 3, 5, 7, 9)
- prime := testSet(2, 3, 5, 7)
-
- tests := []struct {
- left, right Set
- want []{{.Type}}
- }{
- {empty, empty, nil},
- {empty, nat, nil},
- {nat, empty, testValues[:]},
- {nat, nat, nil},
- {nat, odd, testKeys(0, 2, 4, 6, 8)},
- {odd, nat, nil},
- {odd, prime, testKeys(1, 9)},
- {prime, nat, nil},
- }
- for _, test := range tests {
- got := test.left.Diff(test.right).Elements()
- if !reflect.DeepEqual(got, test.want) {
- t.Errorf("%v \\ %v: got %+q, want %+q", test.left, test.right, got, test.want)
- }
- }
-}
-
-func TestSymDiff(t *testing.T) {
- a := testSet(0, 1, 2, 3, 4)
- b := testSet(0, 4, 5, 6, 7)
- c := testSet(3, 4, 8, 9)
- empty := New()
-
- tests := []struct {
- left, right Set
- want []{{.Type}}
- }{
- {empty, empty, nil},
- {empty, a, a.Elements()},
- {b, empty, b.Elements()},
- {a, a, nil},
- {a, b, testKeys(1, 2, 3, 5, 6, 7)},
- {b, a, testKeys(1, 2, 3, 5, 6, 7)},
- {a, c, testKeys(0, 1, 2, 8, 9)},
- {c, a, testKeys(0, 1, 2, 8, 9)},
- {c, b, testKeys(0, 3, 5, 6, 7, 8, 9)},
- }
- for _, test := range tests {
- got := test.left.SymDiff(test.right).Elements()
- if !reflect.DeepEqual(got, test.want) {
- t.Errorf("%v ∆ %v: got %+v, want %+v", test.left, test.right, got, test.want)
- }
- }
-}
-
-func TestUpdate(t *testing.T) {
- tests := []struct {
- before, update Set
- want []{{.Type}}
- changed bool
- }{
- {nil, nil, nil, false},
- {nil, testSet(0), testKeys(0), true},
- {testSet(1), nil, testKeys(1), false},
- {testSet(2, 3), testSet(4, 4, 3), testKeys(2, 3, 4), true},
- }
- for _, test := range tests {
- ok := test.before.Update(test.update)
- if got := test.before.Elements(); !reflect.DeepEqual(got, test.want) {
- t.Errorf("Update %v: got %+v, want %+q", test.before, got, test.want)
- }
- if ok != test.changed {
- t.Errorf("Update %v reported change=%v, want %v", test.before, ok, test.changed)
- }
- }
-}
-
-func TestAdd(t *testing.T) {
- tests := []struct {
- before Set
- update, want []{{.Type}}
- changed bool
- }{
- {nil, nil, nil, false},
- {nil, testKeys(0), testKeys(0), true},
- {testSet(1), nil, testKeys(1), false},
- {testSet(0, 1), testKeys(2, 2, 1), testKeys(0, 1, 2), true},
- }
- for _, test := range tests {
- ok := test.before.Add(test.update...)
- if got := test.before.Elements(); !reflect.DeepEqual(got, test.want) {
- t.Errorf("Add %v: got %+v, want %+v", test.before, got, test.want)
- }
- if ok != test.changed {
- t.Errorf("Add %v reported change=%v, want %v", test.before, ok, test.changed)
- }
- }
-}
-
-func TestRemove(t *testing.T) {
- tests := []struct {
- before, update Set
- want []{{.Type}}
- changed bool
- }{
- {nil, nil, nil, false},
- {nil, testSet(0), nil, false},
- {testSet(5), nil, testKeys(5), false},
- {testSet(3, 9), testSet(5, 1, 9), testKeys(3), true},
- {testSet(0, 1, 2), testSet(4, 6), testKeys(0, 1, 2), false},
- }
- for _, test := range tests {
- ok := test.before.Remove(test.update)
- if got := test.before.Elements(); !reflect.DeepEqual(got, test.want) {
- t.Errorf("Remove %v: got %+v, want %+v", test.before, got, test.want)
- }
- if ok != test.changed {
- t.Errorf("Remove %v reported change=%v, want %v", test.before, ok, test.changed)
- }
- }
-}
-
-func TestDiscard(t *testing.T) {
- tests := []struct {
- before Set
- update, want []{{.Type}}
- changed bool
- }{
- {nil, nil, nil, false},
- {nil, testKeys(0), nil, false},
- {testSet(1), nil, testKeys(1), false},
- {testSet(0, 1), testKeys(2, 2, 1), testKeys(0), true},
- {testSet(0, 1, 2), testKeys(3, 4), testKeys(0, 1, 2), false},
- }
- for _, test := range tests {
- ok := test.before.Discard(test.update...)
- if got := test.before.Elements(); !reflect.DeepEqual(got, test.want) {
- t.Errorf("Discard %v: got %+v, want %+v", test.before, got, test.want)
- }
- if ok != test.changed {
- t.Errorf("Discard %v reported change=%v, want %v", test.before, ok, test.changed)
- }
- }
-}
-
-{{if .Transforms}}
-func TestMap(t *testing.T) {
- in := New(testValues[:]...)
- got := make([]{{.Type}}, len(testValues))
- out := in.Map(func(s {{.Type}}) {{.Type}} {
- if p := keyPos(s); p < 0 {
- t.Errorf("Unknown input key %v", s)
- } else {
- got[p] = s
- }
- return s
- })
- if !reflect.DeepEqual(got, testValues[:]) {
- t.Errorf("Incomplete mapping:\n got %+v\nwant %+v", got, testValues)
- }
- if !out.Equals(in) {
- t.Errorf("Incorrect mapping:\n got %v\nwant %v", out, in)
- }
-}
-
-func TestEach(t *testing.T) {
- in := New(testValues[:]...)
- saw := make(map[{{.Type}}]int)
- in.Each(func(name {{.Type}}) {
- saw[name]++
- })
- for want := range in {
- if saw[want] != 1 {
- t.Errorf("Saw [%v] %d times, wanted 1", want, saw[want])
- }
- }
- for got, n := range saw {
- if _, ok := in[got]; !ok {
- t.Errorf("Saw [%v] %d times, wanted 0", got, n)
- }
- }
-}
-
-func TestSelection(t *testing.T) {
- in := New(testValues[:]...)
- want := testSet(0, 2, 4, 6, 8)
- if got := in.Select(func(s {{.Type}}) bool {
- pos := keyPos(s)
- return pos >= 0 && pos%2 == 0
- }); !got.Equals(want) {
- t.Errorf("%v.Select(evens): got %v, want %v", in, got, want)
- }
- if got := New().Select(func({{.Type}}) bool { return true }); !got.Empty() {
- t.Errorf("%v.Select(true): got %v, want empty", New(), got)
- }
- if got := in.Select(func({{.Type}}) bool { return false }); !got.Empty() {
- t.Errorf("%v.Select(false): got %v, want empty", in, got)
- }
-}
-
-func TestPartition(t *testing.T) {
- in := New(testValues[:]...)
- tests := []struct {
- in, left, right Set
- f func({{.Type}}) bool
- desc string
- }{
- {testSet(0, 1), testSet(0, 1), nil,
- func({{.Type}}) bool { return true },
- "all true",
- },
- {testSet(0, 1), nil, testSet(0, 1),
- func({{.Type}}) bool { return false },
- "all false",
- },
- {in,
- testSet(0, 1, 2, 3, 4),
- testSet(5, 6, 7, 8, 9),
- func(s {{.Type}}) bool { return keyPos(s) < 5 },
- "pos(s) < 5",
- },
- {in,
- testSet(1, 3, 5, 7, 9), // odd
- testSet(0, 2, 4, 6, 8), // even
- func(s {{.Type}}) bool { return keyPos(s)%2 == 1 },
- "odd/even",
- },
- }
- for _, test := range tests {
- gotLeft, gotRight := test.in.Partition(test.f)
- if !gotLeft.Equals(test.left) {
- t.Errorf("Partition %s left: got %v, want %v", test.desc, gotLeft, test.left)
- }
- if !gotRight.Equals(test.right) {
- t.Errorf("Partition %s right: got %v, want %v", test.desc, gotRight, test.right)
- }
- t.Logf("Partition %v %s\n\t left: %v\n\tright: %v", test.in, test.desc, gotLeft, gotRight)
- }
-}
-{{end}}
-
-func TestIndex(t *testing.T) {
- tests := []struct {
- needle {{.Type}}
- keys []{{.Type}}
- want int
- }{
- {testValues[0], nil, -1},
- {testValues[1], []{{.Type}}{}, -1},
- {testValues[2], testKeys(0, 1), -1},
- {testValues[0], testKeys(0, 1), 0},
- {testValues[1], testKeys(0, 1), 1},
- {testValues[2], testKeys(0, 2, 1, 2), 1},
- {testValues[9], testKeys(0, 2, 1, 9, 6), 3},
- {testValues[4], testKeys(0, 2, 4, 9, 4), 2},
- }
- for _, test := range tests {
- got := Index(test.needle, test.keys)
- if got != test.want {
- t.Errorf("Index(%+v, %+v): got %d, want %d", test.needle, test.keys, got, test.want)
- }
- }
-}
-
-type keyer []{{.Type}}
-
-func (k keyer) Keys() []{{.Type}} {
- p := make([]{{.Type}}, len(k))
- copy(p, k)
- return p
-}
-
-type uniq int
-
-func TestFromValues(t *testing.T) {
- tests := []struct {
- input interface{}
- want []{{.Type}}
- }{
- {nil, nil},
- {map[float64]{{.Type}}{}, nil},
- {map[int]{{.Type}}{1: testValues[1], 2: testValues[2], 3: testValues[2]}, testKeys(1, 2)},
- {map[string]{{.Type}}{"foo": testValues[4], "baz": testValues[4]}, testKeys(4)},
- {map[int]uniq{1: uniq(2), 3: uniq(4), 5: uniq(6)}, nil},
- {map[*int]{{.Type}}{nil: testValues[0]}, testKeys(0)},
- }
- for _, test := range tests {
- got := FromValues(test.input)
- want := New(test.want...)
- if !got.Equals(want) {
- t.Errorf("MapValues %v: got %v, want %v", test.input, got, want)
- }
- }
-}
-
-func TestFromKeys(t *testing.T) {
- tests := []struct {
- input interface{}
- want Set
- }{
- {3.5, nil}, // unkeyable type
- {map[uniq]uniq{1: 1}, nil}, // unkeyable type
- {nil, nil}, // empty
- {[]string{}, nil}, // empty
- {map[{{.Type}}]float64{}, nil}, // empty
- {testValues[0], testSet(0)},
- {testKeys(0, 1, 0, 0), testSet(0, 1)},
- {map[{{.Type}}]int{testValues[0]: 1, testValues[1]: 2}, testSet(0, 1)},
- {keyer(testValues[:3]), testSet(0, 1, 2)},
- {testSet(4, 7, 8), testSet(4, 7, 8)},
- {map[{{.Type}}]struct{}{testValues[2]: {}, testValues[7]: {}}, testSet(2, 7)},
- }
- for _, test := range tests {
- got := FromKeys(test.input)
- if !got.Equals(test.want) {
- t.Errorf("FromKeys %v: got %v, want %v", test.input, got, test.want)
- }
- }
-}
-
-func TestContainsFunc(t *testing.T) {
- tests := []struct {
- input interface{}
- needle {{.Type}}
- want bool
- }{
- {[]{{.Type}}(nil), testValues[0], false},
- {[]{{.Type}}{}, testValues[0], false},
- {testKeys(0), testValues[0], true},
- {testKeys(1), testValues[0], false},
- {testKeys(0, 1, 9, 2), testValues[0], true},
-
- {map[{{.Type}}]int(nil), testValues[2], false},
- {map[{{.Type}}]int{}, testValues[2], false},
- {map[{{.Type}}]int{testValues[2]: 1}, testValues[2], true},
- {map[{{.Type}}]int{testValues[3]: 3}, testValues[2], false},
- {map[{{.Type}}]float32{testValues[2]: 1, testValues[4]: 2}, testValues[2], true},
- {map[{{.Type}}]float32{testValues[5]: 0, testValues[6]: 1, testValues[7]: 2, testValues[8]: 3}, testValues[2], false},
-
- {Set(nil), testValues[3], false},
- {New(), testValues[3], false},
- {New(testValues[3]), testValues[3], true},
- {New(testValues[5]), testValues[3], false},
- {testSet(0, 1), testValues[3], false},
- {testSet(0, 3, 1), testValues[3], true},
-
- {keyer(nil), testValues[9], false},
- {keyer{}, testValues[9], false},
- {keyer{testValues[9]}, testValues[9], true},
- {keyer{testValues[0]}, testValues[9], false},
- {keyer(testKeys(0, 6, 9)), testValues[9], true},
- {keyer(testKeys(0, 6, 7)), testValues[9], false},
- }
- for _, test := range tests {
- got := Contains(test.input, test.needle)
- if got != test.want {
- t.Errorf("Contains(%+v, %v): got %v, want %v", test.input, test.needle, got, test.want)
- }
- }
-}
-
-func TestFromIndexed(t *testing.T) {
- tests := []struct {
- input []int
- want Set
- }{
- {nil, nil},
- {[]int{}, nil},
- {[]int{0}, testSet(0)},
- {[]int{1, 8, 2, 9}, testSet(1, 2, 8, 9)},
- {[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, New(testValues[:]...)},
- }
- for _, test := range tests {
- got := FromIndexed(len(test.input), func(i int) {{.Type}} {
- return testValues[test.input[i]]
- })
- if !got.Equals(test.want) {
- t.Errorf("FromIndexed(%d, <...>): got %v, want %v", len(test.input), got, test.want)
- }
- }
-}
diff --git a/makeset/intset.toml b/makeset/intset.toml
deleted file mode 100644
index e5ff5c4..0000000
--- a/makeset/intset.toml
+++ /dev/null
@@ -1,8 +0,0 @@
-desc = "A set of int values."
-type = "int"
-package = "intset"
-zero = "0"
-toString = 'return strconv.Itoa(x)'
-imports = ["strconv"]
-transforms = true
-testValues = [0, 1, 2, 3, 5, 7, 11, 13, 17, 19]
diff --git a/makeset/makeset.go b/makeset/makeset.go
deleted file mode 100644
index 81deffe..0000000
--- a/makeset/makeset.go
+++ /dev/null
@@ -1,186 +0,0 @@
-// Program makeset generates source code for a set package. The type of the
-// elements of the set is determined by a TOML configuration stored in a file
-// named by the -config flag.
-//
-// Usage:
-// go run makeset.go -output $DIR -config config.toml
-//
-package main
-
-import (
- "bytes"
- "errors"
- "flag"
- "fmt"
- "go/format"
- "log"
- "os"
- "path/filepath"
- "sort"
- "text/template"
-
- "github.com/BurntSushi/toml"
-
- _ "embed"
-)
-
-// A Config describes the nature of the set to be constructed.
-type Config struct {
- // A human-readable description of the set this config defines.
- // This is ignored by the code generator, but may serve as documentation.
- Desc string
-
- // The name of the resulting set package, e.g., "intset" (required).
- Package string
-
- // The name of the type contained in the set, e.g., "int" (required).
- Type string
-
- // The spelling of the zero value for the set type, e.g., "0" (required).
- Zero string
-
- // If set, a type definition is added to the package mapping Type to this
- // structure, e.g., "struct { ... }". You may prefix Decl with "=" to
- // generate a type alias (this requires Go ≥ 1.9).
- Decl string
-
- // If set, the body of a function with signature func(x, y Type) bool
- // reporting whether x is less than y.
- //
- // For example:
- // if x[0] == y[0] {
- // return x[1] < y[1]
- // }
- // return x[0] < y[0]
- Less string
-
- // If set, the body of a function with signature func(x Type) string that
- // converts x to a human-readable string.
- //
- // For example:
- // return strconv.Itoa(x)
- ToString string
-
- // If set, additional packages to import in the generated code.
- Imports []string
-
- // If set, additional packages to import in the test.
- TestImports []string
-
- // If true, include transformations, e.g., Map, Partition, Each.
- Transforms bool
-
- // A list of exactly ten ordered test values used for the construction of
- // unit tests. If omitted, unit tests are not generated.
- TestValues []interface{} `json:"testValues,omitempty"`
-}
-
-func (c *Config) validate() error {
- if c.Package == "" {
- return errors.New("invalid: missing package name")
- } else if c.Type == "" {
- return errors.New("invalid: missing type name")
- } else if c.Zero == "" {
- return errors.New("invalid: missing zero value")
- }
- return nil
-}
-
-var (
- configPath = flag.String("config", "", "Path of configuration file (required)")
- outDir = flag.String("output", "", "Output directory path (required)")
-
- baseImports = []string{"reflect", "sort", "strings"}
-
- //go:embed core.go.in
- mainSrc string
-
- //go:embed core_test.go.in
- testSrc string
-)
-
-func main() {
- flag.Parse()
- switch {
- case *outDir == "":
- log.Fatal("You must specify a non-empty -output directory")
- case *configPath == "":
- log.Fatal("You must specify a non-empty -config path")
- }
- conf, err := readConfig(*configPath)
- if err != nil {
- log.Fatalf("Error loading configuration: %v", err)
- }
- if len(conf.TestValues) > 0 && len(conf.TestValues) != 10 {
- log.Fatalf("Wrong number of test values (%d); exactly 10 are required", len(conf.TestValues))
- }
- if err := os.MkdirAll(*outDir, 0755); err != nil {
- log.Fatalf("Unable to create output directory: %v", err)
- }
-
- mainT, err := template.New("main").Parse(mainSrc)
- if err != nil {
- log.Fatalf("Invalid main source template: %v", err)
- }
- testT, err := template.New("test").Parse(testSrc)
- if err != nil {
- log.Fatalf("Invalid test source template: %v", err)
- }
-
- mainPath := filepath.Join(*outDir, conf.Package+".go")
- if err := generate(mainT, conf, mainPath); err != nil {
- log.Fatal(err)
- }
- if len(conf.TestValues) != 0 {
- testPath := filepath.Join(*outDir, conf.Package+"_test.go")
- if err := generate(testT, conf, testPath); err != nil {
- log.Fatal(err)
- }
- }
-}
-
-// readConfig loads a configuration from the specified path and reports whether
-// it is valid.
-func readConfig(path string) (*Config, error) {
- data, err := os.ReadFile(path)
- if err != nil {
- return nil, err
- }
- var c Config
- if err := toml.Unmarshal(data, &c); err != nil {
- return nil, err
- }
-
- // Deduplicate the import list, including all those specified by the
- // configuration as well as those needed by the static code.
- imps := make(map[string]bool)
- for _, pkg := range baseImports {
- imps[pkg] = true
- }
- for _, pkg := range c.Imports {
- imps[pkg] = true
- }
- if c.ToString == "" {
- imps["fmt"] = true // for fmt.Sprint
- }
- c.Imports = make([]string, 0, len(imps))
- for pkg := range imps {
- c.Imports = append(c.Imports, pkg)
- }
- sort.Strings(c.Imports)
- return &c, c.validate()
-}
-
-// generate renders source text from t using the values in c, formats the
-// output as Go source, and writes the result to path.
-func generate(t *template.Template, c *Config, path string) error {
- var buf bytes.Buffer
- if err := t.Execute(&buf, c); err != nil {
- return fmt.Errorf("generating source for %q: %v", path, err)
- }
- src, err := format.Source(buf.Bytes())
- if err != nil {
- return fmt.Errorf("formatting source for %q: %v", path, err)
- }
- return os.WriteFile(path, src, 0644)
-}
diff --git a/makeset/nodeset.toml b/makeset/nodeset.toml
deleted file mode 100644
index fd0f733..0000000
--- a/makeset/nodeset.toml
+++ /dev/null
@@ -1,28 +0,0 @@
-desc = "A set of Go AST nodes from the go/ast package."
-package = "nodeset"
-type = "ast.Node"
-zero = "nil"
-
-less = """
-if x.Pos() == y.Pos() {
- return x.End() > y.End()
-}
-return x.Pos() < y.Pos()
-"""
-
-imports = ["go/ast"]
-testImports = ["go/ast"]
-transforms = true
-
-testValues = [
- '&ast.Ident{Name: "amy", NamePos: 1}',
- '&ast.Ident{Name: "basil", NamePos: 3}',
- '&ast.Ident{Name: "clara", NamePos: 5}',
- '&ast.Ident{Name: "desmond", NamePos: 9}',
- '&ast.Ident{Name: "ernest", NamePos: 10}',
- '&ast.Ident{Name: "fanny", NamePos: 12}',
- '&ast.Ident{Name: "george", NamePos: 14}',
- '&ast.Ident{Name: "hector", NamePos: 17}',
- '&ast.Ident{Name: "ida", NamePos: 19}',
- '&ast.Ident{Name: "james", NamePos: 25}',
-]
diff --git a/makeset/stringset.toml b/makeset/stringset.toml
deleted file mode 100644
index 400758b..0000000
--- a/makeset/stringset.toml
+++ /dev/null
@@ -1,11 +0,0 @@
-desc = "A set of strings, the main package of this module."
-package = "stringset"
-type = "string"
-zero = '""'
-transforms = true
-toString = "return strconv.Quote(x)"
-imports = ["strconv"]
-testValues = [
- '"eight"', '"five"', '"four"', '"nine"', '"one"',
- '"seven"', '"six"', '"ten"', '"three"', '"two"'
-]
diff --git a/stringset.go b/stringset.go
index e202df6..7cca903 100644
--- a/stringset.go
+++ b/stringset.go
@@ -19,23 +19,10 @@ import (
"strings"
)
-func toString(x string) string {
- return strconv.Quote(x)
-}
-
// A Set represents a set of string values. A nil Set is a valid
// representation of an empty set.
type Set map[string]struct{}
-// byElement satisfies sort.Interface to order values of type string.
-type byElement []string
-
-func (e byElement) Len() int { return len(e) }
-func (e byElement) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
-func (e byElement) Less(i, j int) bool {
- return e[i] < e[j]
-}
-
// String implements the fmt.Stringer interface. It renders s in standard set
// notation, e.g., ø for an empty set, {a, b, c} for a nonempty one.
func (s Set) String() string {
@@ -44,7 +31,7 @@ func (s Set) String() string {
}
elts := make([]string, len(s))
for i, elt := range s.Elements() {
- elts[i] = toString(elt)
+ elts[i] = strconv.Quote(elt)
}
return "{" + strings.Join(elts, ", ") + "}"
}
@@ -69,7 +56,7 @@ func (s Set) Len() int { return len(s) }
// Elements returns an ordered slice of the elements in s.
func (s Set) Elements() []string {
elts := s.Unordered()
- sort.Sort(byElement(elts))
+ sort.Strings(elts)
return elts
}
@@ -94,7 +81,9 @@ func (s Set) Clone() Set {
// ContainsAny reports whether s contains one or more of the given elements.
// It is equivalent in meaning to
-// s.Intersects(stringset.New(elts...))
+//
+// s.Intersects(stringset.New(elts...))
+//
// but does not construct an intermediate set.
func (s Set) ContainsAny(elts ...string) bool {
for _, key := range elts {
@@ -107,7 +96,9 @@ func (s Set) ContainsAny(elts ...string) bool {
// Contains reports whether s contains (all) the given elements.
// It is equivalent in meaning to
-// New(elts...).IsSubset(s)
+//
+// New(elts...).IsSubset(s)
+//
// but does not construct an intermediate set.
func (s Set) Contains(elts ...string) bool {
for _, elt := range elts {
diff --git a/stringset_test.go b/stringset_test.go
index 940fd66..7e0becc 100644
--- a/stringset_test.go
+++ b/stringset_test.go
@@ -1,8 +1,10 @@
-package stringset
+package stringset_test
import (
"reflect"
"testing"
+
+ "bitbucket.org/creachadair/stringset"
)
// testValues contains an ordered sequence of ten set keys used for testing.
@@ -27,7 +29,9 @@ func testKeys(ixs ...int) (keys []string) {
return
}
-func testSet(ixs ...int) Set { return New(testKeys(ixs...)...) }
+func testSet(ixs ...int) stringset.Set {
+ return stringset.New(testKeys(ixs...)...)
+}
func keyPos(key string) int {
for i, v := range testValues {
@@ -39,12 +43,12 @@ func keyPos(key string) int {
}
func TestEmptiness(t *testing.T) {
- var s Set
+ var s stringset.Set
if !s.Empty() {
t.Errorf("nil Set is not reported empty: %v", s)
}
- s = New()
+ s = stringset.New()
if !s.Empty() {
t.Errorf("Empty Set is not reported empty: %v", s)
}
@@ -58,7 +62,7 @@ func TestEmptiness(t *testing.T) {
}
func TestClone(t *testing.T) {
- a := New(testValues[:]...)
+ a := stringset.New(testValues[:]...)
b := testSet(1, 8, 5)
c := a.Clone()
c.Remove(b)
@@ -72,7 +76,7 @@ func TestClone(t *testing.T) {
t.Errorf("Unexpected inequality: %v != %v", a, c)
}
- var s Set
+ var s stringset.Set
if got := s.Clone(); got != nil {
t.Errorf("Clone of nil set: got %v, want nil", got)
}
@@ -111,7 +115,7 @@ func TestMembership(t *testing.T) {
if got, ok := s.Choose(func(string) bool { return false }); ok {
t.Errorf(`Choose(impossible): got %v, want ""`, got)
}
- if got, ok := New().Choose(nil); ok {
+ if got, ok := stringset.New().Choose(nil); ok {
t.Errorf(`Choose(nil): got %v, want ""`, got)
}
@@ -132,13 +136,13 @@ func TestMembership(t *testing.T) {
t.Errorf(`Pop(impossible): got %v, want ""`, got)
}
// Pop from an empty set returns not-found.
- if got, ok := New().Pop(nil); ok {
+ if got, ok := stringset.New().Pop(nil); ok {
t.Errorf(`Pop(nil) on empty: got %v, want ""`, got)
}
}
func TestContainsAny(t *testing.T) {
- set := New(testValues[2:]...)
+ set := stringset.New(testValues[2:]...)
tests := []struct {
keys []string
want bool
@@ -163,7 +167,7 @@ func TestContainsAny(t *testing.T) {
func TestContainsAll(t *testing.T) {
//set := New("a", "e", "i", "y")
- set := New(testValues[2:]...)
+ set := stringset.New(testValues[2:]...)
tests := []struct {
keys []string
want bool
@@ -185,12 +189,12 @@ func TestContainsAll(t *testing.T) {
}
func TestIsSubset(t *testing.T) {
- var empty Set
+ var empty stringset.Set
key := testSet(0, 2, 6, 7, 9)
for _, test := range [][]string{
{}, testKeys(2, 6), testKeys(0, 7, 9),
} {
- probe := New(test...)
+ probe := stringset.New(test...)
if !probe.IsSubset(key) {
t.Errorf("IsSubset %+v ⊂ %+v is false", probe, key)
}
@@ -202,9 +206,9 @@ func TestIsSubset(t *testing.T) {
func TestNotSubset(t *testing.T) {
tests := []struct {
- probe, key Set
+ probe, key stringset.Set
}{
- {testSet(0), New()},
+ {testSet(0), stringset.New()},
{testSet(0), testSet(1)},
{testSet(0, 1), testSet(1)},
{testSet(0, 2, 1), testSet(0, 2, 3)},
@@ -217,10 +221,10 @@ func TestNotSubset(t *testing.T) {
}
func TestEquality(t *testing.T) {
- nat := New(testValues[:]...)
+ nat := stringset.New(testValues[:]...)
odd := testSet(1, 3, 4, 5, 8)
tests := []struct {
- left, right Set
+ left, right stringset.Set
eq bool
}{
{nil, nil, true},
@@ -262,7 +266,7 @@ func TestUnion(t *testing.T) {
if got := vowels.Union(nil).Elements(); !reflect.DeepEqual(got, vkeys) {
t.Errorf("Vowels ∪ ø: got %+v, want %+v", got, vkeys)
}
- if got := New().Union(vowels).Elements(); !reflect.DeepEqual(got, vkeys) {
+ if got := stringset.New().Union(vowels).Elements(); !reflect.DeepEqual(got, vkeys) {
t.Errorf("ø ∪ Vowels: got %+v, want %+v", got, vkeys)
}
@@ -272,13 +276,13 @@ func TestUnion(t *testing.T) {
}
func TestIntersect(t *testing.T) {
- empty := New()
- nat := New(testValues[:]...)
+ empty := stringset.New()
+ nat := stringset.New(testValues[:]...)
odd := testSet(1, 3, 5, 7, 9)
prime := testSet(2, 3, 5, 7)
tests := []struct {
- left, right Set
+ left, right stringset.Set
want []string
}{
{empty, empty, nil},
@@ -301,13 +305,13 @@ func TestIntersect(t *testing.T) {
}
func TestDiff(t *testing.T) {
- empty := New()
- nat := New(testValues[:]...)
+ empty := stringset.New()
+ nat := stringset.New(testValues[:]...)
odd := testSet(1, 3, 5, 7, 9)
prime := testSet(2, 3, 5, 7)
tests := []struct {
- left, right Set
+ left, right stringset.Set
want []string
}{
{empty, empty, nil},
@@ -331,10 +335,10 @@ func TestSymDiff(t *testing.T) {
a := testSet(0, 1, 2, 3, 4)
b := testSet(0, 4, 5, 6, 7)
c := testSet(3, 4, 8, 9)
- empty := New()
+ empty := stringset.New()
tests := []struct {
- left, right Set
+ left, right stringset.Set
want []string
}{
{empty, empty, nil},
@@ -357,7 +361,7 @@ func TestSymDiff(t *testing.T) {
func TestUpdate(t *testing.T) {
tests := []struct {
- before, update Set
+ before, update stringset.Set
want []string
changed bool
}{
@@ -379,7 +383,7 @@ func TestUpdate(t *testing.T) {
func TestAdd(t *testing.T) {
tests := []struct {
- before Set
+ before stringset.Set
update, want []string
changed bool
}{
@@ -401,7 +405,7 @@ func TestAdd(t *testing.T) {
func TestRemove(t *testing.T) {
tests := []struct {
- before, update Set
+ before, update stringset.Set
want []string
changed bool
}{
@@ -424,7 +428,7 @@ func TestRemove(t *testing.T) {
func TestDiscard(t *testing.T) {
tests := []struct {
- before Set
+ before stringset.Set
update, want []string
changed bool
}{
@@ -446,7 +450,7 @@ func TestDiscard(t *testing.T) {
}
func TestMap(t *testing.T) {
- in := New(testValues[:]...)
+ in := stringset.New(testValues[:]...)
got := make([]string, len(testValues))
out := in.Map(func(s string) string {
if p := keyPos(s); p < 0 {
@@ -465,7 +469,7 @@ func TestMap(t *testing.T) {
}
func TestEach(t *testing.T) {
- in := New(testValues[:]...)
+ in := stringset.New(testValues[:]...)
saw := make(map[string]int)
in.Each(func(name string) {
saw[name]++
@@ -483,7 +487,7 @@ func TestEach(t *testing.T) {
}
func TestSelection(t *testing.T) {
- in := New(testValues[:]...)
+ in := stringset.New(testValues[:]...)
want := testSet(0, 2, 4, 6, 8)
if got := in.Select(func(s string) bool {
pos := keyPos(s)
@@ -491,8 +495,8 @@ func TestSelection(t *testing.T) {
}); !got.Equals(want) {
t.Errorf("%v.Select(evens): got %v, want %v", in, got, want)
}
- if got := New().Select(func(string) bool { return true }); !got.Empty() {
- t.Errorf("%v.Select(true): got %v, want empty", New(), got)
+ if got := stringset.New().Select(func(string) bool { return true }); !got.Empty() {
+ t.Errorf("%v.Select(true): got %v, want empty", stringset.New(), got)
}
if got := in.Select(func(string) bool { return false }); !got.Empty() {
t.Errorf("%v.Select(false): got %v, want empty", in, got)
@@ -500,9 +504,9 @@ func TestSelection(t *testing.T) {
}
func TestPartition(t *testing.T) {
- in := New(testValues[:]...)
+ in := stringset.New(testValues[:]...)
tests := []struct {
- in, left, right Set
+ in, left, right stringset.Set
f func(string) bool
desc string
}{
@@ -555,7 +559,7 @@ func TestIndex(t *testing.T) {
{testValues[4], testKeys(0, 2, 4, 9, 4), 2},
}
for _, test := range tests {
- got := Index(test.needle, test.keys)
+ got := stringset.Index(test.needle, test.keys)
if got != test.want {
t.Errorf("Index(%+v, %+v): got %d, want %d", test.needle, test.keys, got, test.want)
}
@@ -585,8 +589,8 @@ func TestFromValues(t *testing.T) {
{map[*int]string{nil: testValues[0]}, testKeys(0)},
}
for _, test := range tests {
- got := FromValues(test.input)
- want := New(test.want...)
+ got := stringset.FromValues(test.input)
+ want := stringset.New(test.want...)
if !got.Equals(want) {
t.Errorf("MapValues %v: got %v, want %v", test.input, got, want)
}
@@ -596,7 +600,7 @@ func TestFromValues(t *testing.T) {
func TestFromKeys(t *testing.T) {
tests := []struct {
input interface{}
- want Set
+ want stringset.Set
}{
{3.5, nil}, // unkeyable type
{map[uniq]uniq{1: 1}, nil}, // unkeyable type
@@ -611,7 +615,7 @@ func TestFromKeys(t *testing.T) {
{map[string]struct{}{testValues[2]: {}, testValues[7]: {}}, testSet(2, 7)},
}
for _, test := range tests {
- got := FromKeys(test.input)
+ got := stringset.FromKeys(test.input)
if !got.Equals(test.want) {
t.Errorf("FromKeys %v: got %v, want %v", test.input, got, test.want)
}
@@ -637,10 +641,10 @@ func TestContainsFunc(t *testing.T) {
{map[string]float32{testValues[2]: 1, testValues[4]: 2}, testValues[2], true},
{map[string]float32{testValues[5]: 0, testValues[6]: 1, testValues[7]: 2, testValues[8]: 3}, testValues[2], false},
- {Set(nil), testValues[3], false},
- {New(), testValues[3], false},
- {New(testValues[3]), testValues[3], true},
- {New(testValues[5]), testValues[3], false},
+ {stringset.Set(nil), testValues[3], false},
+ {stringset.New(), testValues[3], false},
+ {stringset.New(testValues[3]), testValues[3], true},
+ {stringset.New(testValues[5]), testValues[3], false},
{testSet(0, 1), testValues[3], false},
{testSet(0, 3, 1), testValues[3], true},
@@ -652,7 +656,7 @@ func TestContainsFunc(t *testing.T) {
{keyer(testKeys(0, 6, 7)), testValues[9], false},
}
for _, test := range tests {
- got := Contains(test.input, test.needle)
+ got := stringset.Contains(test.input, test.needle)
if got != test.want {
t.Errorf("Contains(%+v, %v): got %v, want %v", test.input, test.needle, got, test.want)
}
@@ -662,16 +666,16 @@ func TestContainsFunc(t *testing.T) {
func TestFromIndexed(t *testing.T) {
tests := []struct {
input []int
- want Set
+ want stringset.Set
}{
{nil, nil},
{[]int{}, nil},
{[]int{0}, testSet(0)},
{[]int{1, 8, 2, 9}, testSet(1, 2, 8, 9)},
- {[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, New(testValues[:]...)},
+ {[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, stringset.New(testValues[:]...)},
}
for _, test := range tests {
- got := FromIndexed(len(test.input), func(i int) string {
+ got := stringset.FromIndexed(len(test.input), func(i int) string {
return testValues[test.input[i]]
})
if !got.Equals(test.want) {