mirror of https://github.com/golang/go.git
[dev.go2go] cmd/go2go: rewrite tests to use square bracket syntax
We can roll back this CL if we go back to parentheses. Change-Id: Ide85330f4c362dad6ae964c6cc1fd0fc6c8a6a60 Reviewed-on: https://go-review.googlesource.com/c/go/+/243162 Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
486b592393
commit
893c5ec17b
|
|
@ -109,7 +109,7 @@ func TestGO2PATH(t *testing.T) {
|
|||
|
||||
for _, dir := range dirs {
|
||||
t.Run(dir, func(t *testing.T) {
|
||||
cmd := exec.Command(testGo2go, "test")
|
||||
cmd := exec.Command(testGo2go, "-brackets", "test")
|
||||
cmd.Dir = filepath.Join(testTempDir, "testdata", "go2path", "src", dir)
|
||||
cmd.Env = append(os.Environ(), "GO2PATH="+filepath.Join(testTempDir, "testdata", "go2path"))
|
||||
t.Logf("running [%s test] in %s", testGo2go, cmd.Dir)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ package alg
|
|||
import "constraints"
|
||||
|
||||
// Max returns the maximum of two values of some ordered type.
|
||||
func Max(type T constraints.Ordered)(a, b T) T {
|
||||
func Max[type T constraints.Ordered](a, b T) T {
|
||||
if a < b {
|
||||
return b
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@ func Max(type T constraints.Ordered)(a, b T) T {
|
|||
}
|
||||
|
||||
// Min returns the minimum of two values of some ordered type.
|
||||
func Min(type T constraints.Ordered)(a, b T) T {
|
||||
func Min[type T constraints.Ordered](a, b T) T {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
|
||||
// ReadAll reads from c until the channel is closed or the context is
|
||||
// canceled, returning all the values read.
|
||||
func ReadAll(type Elem)(ctx context.Context, c <-chan Elem) []Elem {
|
||||
func ReadAll[type Elem](ctx context.Context, c <-chan Elem) []Elem {
|
||||
var r []Elem
|
||||
for {
|
||||
select {
|
||||
|
|
@ -30,7 +30,7 @@ func ReadAll(type Elem)(ctx context.Context, c <-chan Elem) []Elem {
|
|||
// Merge merges two channels into a single channel.
|
||||
// This will leave a goroutine running until either both channels are closed
|
||||
// or the context is canceled, at which point the returned channel is closed.
|
||||
func Merge(type Elem)(ctx context.Context, c1, c2 <-chan Elem) <-chan Elem {
|
||||
func Merge[type Elem](ctx context.Context, c1, c2 <-chan Elem) <-chan Elem {
|
||||
r := make(chan Elem)
|
||||
go func(ctx context.Context, c1, c2 <-chan Elem, r chan<- Elem) {
|
||||
defer close(r)
|
||||
|
|
@ -60,7 +60,7 @@ func Merge(type Elem)(ctx context.Context, c1, c2 <-chan Elem) <-chan Elem {
|
|||
// is sent on the returned channel. This will leave a goroutine running
|
||||
// until c is closed or the context is canceled, at which point the
|
||||
// returned channel is closed.
|
||||
func Filter(type Elem)(ctx context.Context, c <-chan Elem, f func(Elem) bool) <-chan Elem {
|
||||
func Filter[type Elem](ctx context.Context, c <-chan Elem, f func(Elem) bool) <-chan Elem {
|
||||
r := make(chan Elem)
|
||||
go func(ctx context.Context, c <-chan Elem, f func(Elem) bool, r chan<- Elem) {
|
||||
defer close(r)
|
||||
|
|
@ -84,7 +84,7 @@ func Filter(type Elem)(ctx context.Context, c <-chan Elem, f func(Elem) bool) <-
|
|||
// Sink returns a channel that discards all values sent to it.
|
||||
// This will leave a goroutine running until the context is canceled
|
||||
// or the returned channel is closed.
|
||||
func Sink(type Elem)(ctx context.Context) chan<- Elem {
|
||||
func Sink[type Elem](ctx context.Context) chan<- Elem {
|
||||
r := make(chan Elem)
|
||||
go func(ctx context.Context, r <-chan Elem) {
|
||||
for {
|
||||
|
|
@ -103,13 +103,13 @@ func Sink(type Elem)(ctx context.Context) chan<- Elem {
|
|||
|
||||
// An Exclusive is a value that may only be used by a single goroutine
|
||||
// at a time. This is implemented using channels rather than a mutex.
|
||||
type Exclusive(type Val) struct {
|
||||
type Exclusive[type Val] struct {
|
||||
c chan Val
|
||||
}
|
||||
|
||||
// MakeExclusive makes an initialized exclusive value.
|
||||
func MakeExclusive(type Val)(initial Val) *Exclusive(Val) {
|
||||
r := &Exclusive(Val){
|
||||
func MakeExclusive[type Val](initial Val) *Exclusive[Val] {
|
||||
r := &Exclusive[Val]{
|
||||
c: make(chan Val, 1),
|
||||
}
|
||||
r.c <- initial
|
||||
|
|
@ -118,14 +118,14 @@ func MakeExclusive(type Val)(initial Val) *Exclusive(Val) {
|
|||
|
||||
// Acquire acquires the exclusive value for private use.
|
||||
// It must be released using the Release method.
|
||||
func (e *Exclusive(Val)) Acquire() Val {
|
||||
func (e *Exclusive[Val]) Acquire() Val {
|
||||
return <-e.c
|
||||
}
|
||||
|
||||
// TryAcquire attempts to acquire the value. The ok result reports whether
|
||||
// the value was acquired. If the value is acquired, it must be released
|
||||
// using the Release method.
|
||||
func (e *Exclusive(Val)) TryAcquire() (v Val, ok bool) {
|
||||
func (e *Exclusive[Val]) TryAcquire() (v Val, ok bool) {
|
||||
select {
|
||||
case r := <-e.c:
|
||||
return r, true
|
||||
|
|
@ -136,7 +136,7 @@ func (e *Exclusive(Val)) TryAcquire() (v Val, ok bool) {
|
|||
|
||||
// Release updates and releases the value.
|
||||
// This method panics if the value has not been acquired.
|
||||
func (e *Exclusive(Val)) Release(v Val) {
|
||||
func (e *Exclusive[Val]) Release(v Val) {
|
||||
select {
|
||||
case e.c <- v:
|
||||
default:
|
||||
|
|
@ -152,23 +152,23 @@ func (e *Exclusive(Val)) Release(v Val) {
|
|||
//
|
||||
// This is a convenient way to exit a goroutine sending values when
|
||||
// the receiver stops reading them.
|
||||
func Ranger(type Elem)() (*Sender(Elem), *Receiver(Elem)) {
|
||||
func Ranger[type Elem]() (*Sender[Elem], *Receiver[Elem]) {
|
||||
c := make(chan Elem)
|
||||
d := make(chan struct{})
|
||||
s := &Sender(Elem){
|
||||
s := &Sender[Elem]{
|
||||
values: c,
|
||||
done: d,
|
||||
}
|
||||
r := &Receiver(Elem) {
|
||||
r := &Receiver[Elem] {
|
||||
values: c,
|
||||
done: d,
|
||||
}
|
||||
runtime.SetFinalizer(r, (*Receiver(Elem)).finalize)
|
||||
runtime.SetFinalizer(r, (*Receiver[Elem]).finalize)
|
||||
return s, r
|
||||
}
|
||||
|
||||
// A Sender is used to send values to a Receiver.
|
||||
type Sender(type Elem) struct {
|
||||
type Sender[type Elem] struct {
|
||||
values chan<- Elem
|
||||
done <-chan struct{}
|
||||
}
|
||||
|
|
@ -176,7 +176,7 @@ type Sender(type Elem) struct {
|
|||
// Send sends a value to the receiver. It reports whether the value was sent.
|
||||
// The value will not be sent if the context is closed or the receiver
|
||||
// is freed.
|
||||
func (s *Sender(Elem)) Send(ctx context.Context, v Elem) bool {
|
||||
func (s *Sender[Elem]) Send(ctx context.Context, v Elem) bool {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return false
|
||||
|
|
@ -189,19 +189,19 @@ func (s *Sender(Elem)) Send(ctx context.Context, v Elem) bool {
|
|||
|
||||
// Close tells the receiver that no more values will arrive.
|
||||
// After Close is called, the Sender may no longer be used.
|
||||
func (s *Sender(Elem)) Close() {
|
||||
func (s *Sender[Elem]) Close() {
|
||||
close(s.values)
|
||||
}
|
||||
|
||||
// A Receiver receives values from a Sender.
|
||||
type Receiver(type Elem) struct {
|
||||
type Receiver[type Elem] struct {
|
||||
values <-chan Elem
|
||||
done chan<- struct{}
|
||||
}
|
||||
|
||||
// Next returns the next value from the channel. The bool result indicates
|
||||
// whether the value is valid.
|
||||
func (r *Receiver(Elem)) Next(ctx context.Context) (v Elem, ok bool) {
|
||||
func (r *Receiver[Elem]) Next(ctx context.Context) (v Elem, ok bool) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case v, ok = <-r.values:
|
||||
|
|
@ -210,6 +210,6 @@ func (r *Receiver(Elem)) Next(ctx context.Context) (v Elem, ok bool) {
|
|||
}
|
||||
|
||||
// finalize is a finalizer for the receiver.
|
||||
func (r *Receiver(Elem)) finalize() {
|
||||
func (r *Receiver[Elem]) finalize() {
|
||||
close(r.done)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,31 +10,31 @@ import "errors"
|
|||
// A Graph is a collection of nodes. A node may have an arbitrary number
|
||||
// of edges. An edge connects two nodes. Both nodes and edges must be
|
||||
// comparable. This is an undirected simple graph.
|
||||
type Graph(type Node NodeC(Edge), Edge EdgeC(Node)) struct {
|
||||
type Graph[type Node NodeC[Edge], Edge EdgeC[Node]] struct {
|
||||
nodes []Node
|
||||
}
|
||||
|
||||
// NodeC is the contraints on a node in a graph, given the Edge type.
|
||||
type NodeC(type Edge) interface {
|
||||
type NodeC[type Edge] interface {
|
||||
comparable
|
||||
Edges() []Edge
|
||||
}
|
||||
|
||||
// Edgec is the constraints on an edge in a graph, given the Node type.
|
||||
type EdgeC(type Node) interface {
|
||||
type EdgeC[type Node] interface {
|
||||
comparable
|
||||
Nodes() (a, b Node)
|
||||
}
|
||||
|
||||
// New creates a new Graph from a collection of Nodes.
|
||||
func New(type Node NodeC(Edge), Edge EdgeC(Node))(nodes []Node) *Graph(Node, Edge) {
|
||||
return &Graph(Node, Edge){nodes: nodes}
|
||||
func New[type Node NodeC[Edge], Edge EdgeC[Node]](nodes []Node) *Graph[Node, Edge] {
|
||||
return &Graph[Node, Edge]{nodes: nodes}
|
||||
}
|
||||
|
||||
// nodePath holds the path to a node during ShortestPath.
|
||||
// This should ideally be a type defined inside ShortestPath,
|
||||
// but the translator tool doesn't support that.
|
||||
type nodePath(type Node NodeC(Edge), Edge EdgeC(Node)) struct {
|
||||
type nodePath[type Node NodeC[Edge], Edge EdgeC[Node]] struct {
|
||||
node Node
|
||||
path []Edge
|
||||
}
|
||||
|
|
@ -42,10 +42,10 @@ type nodePath(type Node NodeC(Edge), Edge EdgeC(Node)) struct {
|
|||
// ShortestPath returns the shortest path between two nodes,
|
||||
// as an ordered list of edges. If there are multiple shortest paths,
|
||||
// which one is returned is unpredictable.
|
||||
func (g *Graph(Node, Edge)) ShortestPath(from, to Node) ([]Edge, error) {
|
||||
func (g *Graph[Node, Edge]) ShortestPath(from, to Node) ([]Edge, error) {
|
||||
visited := make(map[Node]bool)
|
||||
visited[from] = true
|
||||
workqueue := [](nodePath(Node, Edge)){nodePath(Node, Edge){from, nil}}
|
||||
workqueue := []nodePath[Node, Edge]{nodePath[Node, Edge]{from, nil}}
|
||||
for len(workqueue) > 0 {
|
||||
current := workqueue
|
||||
workqueue = nil
|
||||
|
|
@ -62,7 +62,7 @@ func (g *Graph(Node, Edge)) ShortestPath(from, to Node) ([]Edge, error) {
|
|||
if a == to {
|
||||
return ve, nil
|
||||
}
|
||||
workqueue = append(workqueue, nodePath(Node, Edge){a, ve})
|
||||
workqueue = append(workqueue, nodePath[Node, Edge]{a, ve})
|
||||
visited[a] = true
|
||||
}
|
||||
}
|
||||
|
|
@ -74,29 +74,29 @@ func (g *Graph(Node, Edge)) ShortestPath(from, to Node) ([]Edge, error) {
|
|||
// GraphP is a version of Graph that uses pointers. This is for testing.
|
||||
// I'm not sure which approach will be better in practice, or whether
|
||||
// this indicates a problem with the draft design.
|
||||
type GraphP(type *Node NodeCP(Edge), *Edge EdgeCP(Node)) struct {
|
||||
type GraphP[type *Node NodeCP[Edge], *Edge EdgeCP[Node]] struct {
|
||||
nodes []*Node
|
||||
}
|
||||
|
||||
// NodeCP is the contraint on a Node in a GraphP.
|
||||
type NodeCP(type Edge) interface {
|
||||
type NodeCP[type Edge] interface {
|
||||
Edges() []*Edge
|
||||
}
|
||||
|
||||
// EdgeCP is the contraint on an Edge in a GraphP.
|
||||
type EdgeCP(type Node) interface {
|
||||
type EdgeCP[type Node] interface {
|
||||
Nodes() (a, b *Node)
|
||||
}
|
||||
|
||||
// NewP creates a new GraphP from a collection of Nodes.
|
||||
func NewP(type *Node NodeCP(Edge), *Edge EdgeCP(Node))(nodes []*Node) *GraphP(Node, Edge) {
|
||||
return &GraphP(Node, Edge){nodes: nodes}
|
||||
func NewP[type *Node NodeCP[Edge], *Edge EdgeCP[Node]](nodes []*Node) *GraphP[Node, Edge] {
|
||||
return &GraphP[Node, Edge]{nodes: nodes}
|
||||
}
|
||||
|
||||
// nodePathP holds the path to a node during ShortestPath.
|
||||
// This should ideally be a type defined inside ShortestPath,
|
||||
// but the translator tool doesn't support that.
|
||||
type nodePathP(type *Node NodeCP(Edge), *Edge EdgeCP(Node)) struct {
|
||||
type nodePathP[type *Node NodeCP[Edge], *Edge EdgeCP[Node]] struct {
|
||||
node *Node
|
||||
path []*Edge
|
||||
}
|
||||
|
|
@ -104,10 +104,10 @@ type nodePathP(type *Node NodeCP(Edge), *Edge EdgeCP(Node)) struct {
|
|||
// ShortestPath returns the shortest path between two nodes,
|
||||
// as an ordered list of edges. If there are multiple shortest paths,
|
||||
// which one is returned is unpredictable.
|
||||
func (g *GraphP(Node, Edge)) ShortestPath(from, to *Node) ([]*Edge, error) {
|
||||
func (g *GraphP[Node, Edge]) ShortestPath(from, to *Node) ([]*Edge, error) {
|
||||
visited := make(map[*Node]bool)
|
||||
visited[from] = true
|
||||
workqueue := [](nodePathP(Node, Edge)){nodePathP(Node, Edge){from, nil}}
|
||||
workqueue := [](nodePathP[Node, Edge]){nodePathP[Node, Edge]{from, nil}}
|
||||
for len(workqueue) > 0 {
|
||||
current := workqueue
|
||||
workqueue = nil
|
||||
|
|
@ -124,7 +124,7 @@ func (g *GraphP(Node, Edge)) ShortestPath(from, to *Node) ([]*Edge, error) {
|
|||
if a == to {
|
||||
return ve, nil
|
||||
}
|
||||
workqueue = append(workqueue, nodePathP(Node, Edge){a, ve})
|
||||
workqueue = append(workqueue, nodePathP[Node, Edge]{a, ve})
|
||||
visited[a] = true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ func TestShortestPath(t *testing.T) {
|
|||
mridx.index = idx
|
||||
nodes = append(nodes, mridx)
|
||||
}
|
||||
g := New(mazeRoom, mazeEdge)(nodes)
|
||||
g := New[mazeRoom, mazeEdge](nodes)
|
||||
path, err := g.ShortestPath(zork[11], zork[30])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -195,7 +195,7 @@ func TestShortestPathP(t *testing.T) {
|
|||
stop = mr
|
||||
}
|
||||
}
|
||||
g := NewP(mazeRoomP, mazeEdgeP)(nodes)
|
||||
g := NewP[mazeRoomP, mazeEdgeP](nodes)
|
||||
path, err := g.ShortestPath(start, stop)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
|
|||
|
|
@ -12,12 +12,12 @@ import (
|
|||
)
|
||||
|
||||
// orderedSlice is a slice of values of some ordered type.
|
||||
type orderedSlice(type Elem constraints.Ordered) []Elem
|
||||
type orderedSlice[type Elem constraints.Ordered] []Elem
|
||||
|
||||
// orderedSlice implements sort.Interface.
|
||||
|
||||
func (s orderedSlice(Elem)) Len() int { return len(s) }
|
||||
func (s orderedSlice(Elem)) Less(i, j int) bool {
|
||||
func (s orderedSlice[Elem]) Len() int { return len(s) }
|
||||
func (s orderedSlice[Elem]) Less(i, j int) bool {
|
||||
if s[i] < s[j] {
|
||||
return true
|
||||
}
|
||||
|
|
@ -27,25 +27,25 @@ func (s orderedSlice(Elem)) Less(i, j int) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
func (s orderedSlice(Elem)) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s orderedSlice[Elem]) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// OrderedSlice sorts a slice of any ordered type in ascending order.
|
||||
func OrderedSlice(type Elem constraints.Ordered)(s []Elem) {
|
||||
sort.Sort(orderedSlice(Elem)(s))
|
||||
func OrderedSlice[type Elem constraints.Ordered](s []Elem) {
|
||||
sort.Sort(orderedSlice[Elem](s))
|
||||
}
|
||||
|
||||
// sliceFn implements sort.Interface for a slice of any type with an
|
||||
// explicit less-than function.
|
||||
type sliceFn(type Elem) struct {
|
||||
type sliceFn[type Elem] struct {
|
||||
s []Elem
|
||||
less func(Elem, Elem) bool
|
||||
}
|
||||
|
||||
func (s sliceFn(Elem)) Len() int { return len(s.s) }
|
||||
func (s sliceFn(Elem)) Less(i, j int) bool { return s.less(s.s[i], s.s[j]) }
|
||||
func (s sliceFn(Elem)) Swap(i, j int) { s.s[i], s.s[j] = s.s[j], s.s[i] }
|
||||
func (s sliceFn[Elem]) Len() int { return len(s.s) }
|
||||
func (s sliceFn[Elem]) Less(i, j int) bool { return s.less(s.s[i], s.s[j]) }
|
||||
func (s sliceFn[Elem]) Swap(i, j int) { s.s[i], s.s[j] = s.s[j], s.s[i] }
|
||||
|
||||
// SliceFn sorts a slice of any type according to a less-than function.
|
||||
func SliceFn(type Elem)(s []Elem, less func(Elem, Elem) bool) {
|
||||
sort.Sort(sliceFn(Elem){s, less})
|
||||
func SliceFn[type Elem](s []Elem, less func(Elem, Elem) bool) {
|
||||
sort.Sort(sliceFn[Elem]{s, less})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ func TestSortOrderedStrings(t *testing.T) {
|
|||
testOrdered(t, strs, sort.Strings)
|
||||
}
|
||||
|
||||
func testOrdered(type Elem constraints.Ordered)(t *testing.T, s []Elem, sorter func([]Elem)) {
|
||||
func testOrdered[type Elem constraints.Ordered](t *testing.T, s []Elem, sorter func([]Elem)) {
|
||||
s1 := make([]Elem, len(s))
|
||||
copy(s1, s)
|
||||
s2 := make([]Elem, len(s))
|
||||
|
|
|
|||
|
|
@ -9,23 +9,23 @@ package list
|
|||
// perhaps with different type names.
|
||||
|
||||
// Element is an element of a linked list.
|
||||
type Element(type TElem) struct {
|
||||
type Element[type TElem] struct {
|
||||
// Next and previous pointers in the doubly-linked list of elements.
|
||||
// To simplify the implementation, internally a list l is implemented
|
||||
// as a ring, such that &l.root is both the next element of the last
|
||||
// list element (l.Back()) and the previous element of the first list
|
||||
// element (l.Front()).
|
||||
next, prev *Element(TElem)
|
||||
next, prev *Element[TElem]
|
||||
|
||||
// The list to which this element belongs.
|
||||
list *List(TElem)
|
||||
list *List[TElem]
|
||||
|
||||
// The value stored with this element.
|
||||
Value TElem
|
||||
}
|
||||
|
||||
// Next returns the next list element or nil.
|
||||
func (e *Element(TElem)) Next() *Element(TElem) {
|
||||
func (e *Element[TElem]) Next() *Element[TElem] {
|
||||
if p := e.next; e.list != nil && p != &e.list.root {
|
||||
return p
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ func (e *Element(TElem)) Next() *Element(TElem) {
|
|||
}
|
||||
|
||||
// Prev returns the previous list element or nil.
|
||||
func (e *Element(TElem)) Prev() *Element(TElem) {
|
||||
func (e *Element[TElem]) Prev() *Element[TElem] {
|
||||
if p := e.prev; e.list != nil && p != &e.list.root {
|
||||
return p
|
||||
}
|
||||
|
|
@ -42,13 +42,13 @@ func (e *Element(TElem)) Prev() *Element(TElem) {
|
|||
|
||||
// List represents a doubly linked list.
|
||||
// The zero value for List is an empty list ready to use.
|
||||
type List(type TElem) struct {
|
||||
root Element(TElem) // sentinel list element, only &root, root.prev, and root.next are used
|
||||
type List[type TElem] struct {
|
||||
root Element[TElem] // sentinel list element, only &root, root.prev, and root.next are used
|
||||
len int // current list length excluding (this) sentinel element
|
||||
}
|
||||
|
||||
// Init initializes or clears list l.
|
||||
func (l *List(TElem)) Init() *List(TElem) {
|
||||
func (l *List[TElem]) Init() *List[TElem] {
|
||||
l.root.next = &l.root
|
||||
l.root.prev = &l.root
|
||||
l.len = 0
|
||||
|
|
@ -56,14 +56,14 @@ func (l *List(TElem)) Init() *List(TElem) {
|
|||
}
|
||||
|
||||
// New returns an initialized list.
|
||||
func New(type TElem)() *List(TElem) { return new(List(TElem)).Init() }
|
||||
func New[type TElem]() *List[TElem] { return new(List[TElem]).Init() }
|
||||
|
||||
// Len returns the number of elements of list l.
|
||||
// The complexity is O(1).
|
||||
func (l *List(TElem)) Len() int { return l.len }
|
||||
func (l *List[TElem]) Len() int { return l.len }
|
||||
|
||||
// Front returns the first element of list l or nil if the list is empty.
|
||||
func (l *List(TElem)) Front() *Element(TElem) {
|
||||
func (l *List[TElem]) Front() *Element[TElem] {
|
||||
if l.len == 0 {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -71,7 +71,7 @@ func (l *List(TElem)) Front() *Element(TElem) {
|
|||
}
|
||||
|
||||
// Back returns the last element of list l or nil if the list is empty.
|
||||
func (l *List(TElem)) Back() *Element(TElem) {
|
||||
func (l *List[TElem]) Back() *Element[TElem] {
|
||||
if l.len == 0 {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -79,14 +79,14 @@ func (l *List(TElem)) Back() *Element(TElem) {
|
|||
}
|
||||
|
||||
// lazyInit lazily initializes a zero List value.
|
||||
func (l *List(TElem)) lazyInit() {
|
||||
func (l *List[TElem]) lazyInit() {
|
||||
if l.root.next == nil {
|
||||
l.Init()
|
||||
}
|
||||
}
|
||||
|
||||
// insert inserts e after at, increments l.len, and returns e.
|
||||
func (l *List(TElem)) insert(e, at *Element(TElem)) *Element(TElem) {
|
||||
func (l *List[TElem]) insert(e, at *Element[TElem]) *Element[TElem] {
|
||||
e.prev = at
|
||||
e.next = at.next
|
||||
e.prev.next = e
|
||||
|
|
@ -96,13 +96,13 @@ func (l *List(TElem)) insert(e, at *Element(TElem)) *Element(TElem) {
|
|||
return e
|
||||
}
|
||||
|
||||
// insertValue is a convenience wrapper for insert(&Element(TElem){Value: v}, at).
|
||||
func (l *List(TElem)) insertValue(v TElem, at *Element(TElem)) *Element(TElem) {
|
||||
return l.insert(&Element(TElem){Value: v}, at)
|
||||
// insertValue is a convenience wrapper for insert(&Element[TElem]{Value: v}, at).
|
||||
func (l *List[TElem]) insertValue(v TElem, at *Element[TElem]) *Element[TElem] {
|
||||
return l.insert(&Element[TElem]{Value: v}, at)
|
||||
}
|
||||
|
||||
// remove removes e from its list, decrements l.len, and returns e.
|
||||
func (l *List(TElem)) remove(e *Element(TElem)) *Element(TElem) {
|
||||
func (l *List[TElem]) remove(e *Element[TElem]) *Element[TElem] {
|
||||
e.prev.next = e.next
|
||||
e.next.prev = e.prev
|
||||
e.next = nil // avoid memory leaks
|
||||
|
|
@ -113,7 +113,7 @@ func (l *List(TElem)) remove(e *Element(TElem)) *Element(TElem) {
|
|||
}
|
||||
|
||||
// move moves e to next to at and returns e.
|
||||
func (l *List(TElem)) move(e, at *Element(TElem)) *Element(TElem) {
|
||||
func (l *List[TElem]) move(e, at *Element[TElem]) *Element[TElem] {
|
||||
if e == at {
|
||||
return e
|
||||
}
|
||||
|
|
@ -131,7 +131,7 @@ func (l *List(TElem)) move(e, at *Element(TElem)) *Element(TElem) {
|
|||
// Remove removes e from l if e is an element of list l.
|
||||
// It returns the element value e.Value.
|
||||
// The element must not be nil.
|
||||
func (l *List(TElem)) Remove(e *Element(TElem)) TElem {
|
||||
func (l *List[TElem]) Remove(e *Element[TElem]) TElem {
|
||||
if e.list == l {
|
||||
// if e.list == l, l must have been initialized when e was inserted
|
||||
// in l or l == nil (e is a zero Element) and l.remove will crash
|
||||
|
|
@ -141,13 +141,13 @@ func (l *List(TElem)) Remove(e *Element(TElem)) TElem {
|
|||
}
|
||||
|
||||
// PushFront inserts a new element e with value v at the front of list l and returns e.
|
||||
func (l *List(TElem)) PushFront(v TElem) *Element(TElem) {
|
||||
func (l *List[TElem]) PushFront(v TElem) *Element[TElem] {
|
||||
l.lazyInit()
|
||||
return l.insertValue(v, &l.root)
|
||||
}
|
||||
|
||||
// PushBack inserts a new element e with value v at the back of list l and returns e.
|
||||
func (l *List(TElem)) PushBack(v TElem) *Element(TElem) {
|
||||
func (l *List[TElem]) PushBack(v TElem) *Element[TElem] {
|
||||
l.lazyInit()
|
||||
return l.insertValue(v, l.root.prev)
|
||||
}
|
||||
|
|
@ -155,7 +155,7 @@ func (l *List(TElem)) PushBack(v TElem) *Element(TElem) {
|
|||
// InsertBefore inserts a new element e with value v immediately before mark and returns e.
|
||||
// If mark is not an element of l, the list is not modified.
|
||||
// The mark must not be nil.
|
||||
func (l *List(TElem)) InsertBefore(v TElem, mark *Element(TElem)) *Element(TElem) {
|
||||
func (l *List[TElem]) InsertBefore(v TElem, mark *Element[TElem]) *Element[TElem] {
|
||||
if mark.list != l {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -166,7 +166,7 @@ func (l *List(TElem)) InsertBefore(v TElem, mark *Element(TElem)) *Element(TElem
|
|||
// InsertAfter inserts a new element e with value v immediately after mark and returns e.
|
||||
// If mark is not an element of l, the list is not modified.
|
||||
// The mark must not be nil.
|
||||
func (l *List(TElem)) InsertAfter(v TElem, mark *Element(TElem)) *Element(TElem) {
|
||||
func (l *List[TElem]) InsertAfter(v TElem, mark *Element[TElem]) *Element[TElem] {
|
||||
if mark.list != l {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -177,7 +177,7 @@ func (l *List(TElem)) InsertAfter(v TElem, mark *Element(TElem)) *Element(TElem)
|
|||
// MoveToFront moves element e to the front of list l.
|
||||
// If e is not an element of l, the list is not modified.
|
||||
// The element must not be nil.
|
||||
func (l *List(TElem)) MoveToFront(e *Element(TElem)) {
|
||||
func (l *List[TElem]) MoveToFront(e *Element[TElem]) {
|
||||
if e.list != l || l.root.next == e {
|
||||
return
|
||||
}
|
||||
|
|
@ -188,7 +188,7 @@ func (l *List(TElem)) MoveToFront(e *Element(TElem)) {
|
|||
// MoveToBack moves element e to the back of list l.
|
||||
// If e is not an element of l, the list is not modified.
|
||||
// The element must not be nil.
|
||||
func (l *List(TElem)) MoveToBack(e *Element(TElem)) {
|
||||
func (l *List[TElem]) MoveToBack(e *Element[TElem]) {
|
||||
if e.list != l || l.root.prev == e {
|
||||
return
|
||||
}
|
||||
|
|
@ -199,7 +199,7 @@ func (l *List(TElem)) MoveToBack(e *Element(TElem)) {
|
|||
// MoveBefore moves element e to its new position before mark.
|
||||
// If e or mark is not an element of l, or e == mark, the list is not modified.
|
||||
// The element and mark must not be nil.
|
||||
func (l *List(TElem)) MoveBefore(e, mark *Element(TElem)) {
|
||||
func (l *List[TElem]) MoveBefore(e, mark *Element[TElem]) {
|
||||
if e.list != l || e == mark || mark.list != l {
|
||||
return
|
||||
}
|
||||
|
|
@ -209,7 +209,7 @@ func (l *List(TElem)) MoveBefore(e, mark *Element(TElem)) {
|
|||
// MoveAfter moves element e to its new position after mark.
|
||||
// If e or mark is not an element of l, or e == mark, the list is not modified.
|
||||
// The element and mark must not be nil.
|
||||
func (l *List(TElem)) MoveAfter(e, mark *Element(TElem)) {
|
||||
func (l *List[TElem]) MoveAfter(e, mark *Element[TElem]) {
|
||||
if e.list != l || e == mark || mark.list != l {
|
||||
return
|
||||
}
|
||||
|
|
@ -218,7 +218,7 @@ func (l *List(TElem)) MoveAfter(e, mark *Element(TElem)) {
|
|||
|
||||
// PushBackList inserts a copy of an other list at the back of list l.
|
||||
// The lists l and other may be the same. They must not be nil.
|
||||
func (l *List(TElem)) PushBackList(other *List(TElem)) {
|
||||
func (l *List[TElem]) PushBackList(other *List[TElem]) {
|
||||
l.lazyInit()
|
||||
for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() {
|
||||
l.insertValue(e.Value, l.root.prev)
|
||||
|
|
@ -227,7 +227,7 @@ func (l *List(TElem)) PushBackList(other *List(TElem)) {
|
|||
|
||||
// PushFrontList inserts a copy of an other list at the front of list l.
|
||||
// The lists l and other may be the same. They must not be nil.
|
||||
func (l *List(TElem)) PushFrontList(other *List(TElem)) {
|
||||
func (l *List[TElem]) PushFrontList(other *List[TElem]) {
|
||||
l.lazyInit()
|
||||
for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() {
|
||||
l.insertValue(e.Value, &l.root)
|
||||
|
|
@ -235,8 +235,8 @@ func (l *List(TElem)) PushFrontList(other *List(TElem)) {
|
|||
}
|
||||
|
||||
// Transform runs a transform function on a list returning a new list.
|
||||
func Transform(type TElem1, TElem2)(lst *List(TElem1), f func(TElem1) TElem2) *List(TElem2) {
|
||||
ret := New(TElem2)()
|
||||
func Transform[type TElem1, TElem2](lst *List[TElem1], f func(TElem1) TElem2) *List[TElem2] {
|
||||
ret := New[TElem2]()
|
||||
for p := lst.Front(); p != nil; p = p.Next() {
|
||||
ret.PushBack(f(p.Value))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func checkListLen(type TElem)(t *testing.T, l *List(TElem), len int) bool {
|
||||
func checkListLen[type TElem](t *testing.T, l *List[TElem], len int) bool {
|
||||
if n := l.Len(); n != len {
|
||||
t.Errorf("l.Len() = %d, want %d", n, len)
|
||||
return false
|
||||
|
|
@ -17,7 +17,7 @@ func checkListLen(type TElem)(t *testing.T, l *List(TElem), len int) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func checkListPointers(type TElem)(t *testing.T, l *List(TElem), es []*Element(TElem)) {
|
||||
func checkListPointers[type TElem](t *testing.T, l *List[TElem], es []*Element[TElem]) {
|
||||
root := &l.root
|
||||
|
||||
if !checkListLen(t, l, len(es)) {
|
||||
|
|
@ -36,7 +36,7 @@ func checkListPointers(type TElem)(t *testing.T, l *List(TElem), es []*Element(T
|
|||
// check internal and external prev/next connections
|
||||
for i, e := range es {
|
||||
prev := root
|
||||
Prev := (*Element(TElem))(nil)
|
||||
Prev := (*Element[TElem])(nil)
|
||||
if i > 0 {
|
||||
prev = es[i-1]
|
||||
Prev = prev
|
||||
|
|
@ -49,7 +49,7 @@ func checkListPointers(type TElem)(t *testing.T, l *List(TElem), es []*Element(T
|
|||
}
|
||||
|
||||
next := root
|
||||
Next := (*Element(TElem))(nil)
|
||||
Next := (*Element[TElem])(nil)
|
||||
if i < len(es)-1 {
|
||||
next = es[i+1]
|
||||
Next = next
|
||||
|
|
@ -65,64 +65,64 @@ func checkListPointers(type TElem)(t *testing.T, l *List(TElem), es []*Element(T
|
|||
|
||||
func TestList(t *testing.T) {
|
||||
l := New(string)()
|
||||
checkListPointers(t, l, []*(Element(string)){})
|
||||
checkListPointers(t, l, []*(Element[string]){})
|
||||
|
||||
// Single element list
|
||||
e := l.PushFront("a")
|
||||
checkListPointers(t, l, []*(Element(string)){e})
|
||||
checkListPointers(t, l, []*(Element[string]){e})
|
||||
l.MoveToFront(e)
|
||||
checkListPointers(t, l, []*(Element(string)){e})
|
||||
checkListPointers(t, l, []*(Element[string]){e})
|
||||
l.MoveToBack(e)
|
||||
checkListPointers(t, l, []*(Element(string)){e})
|
||||
checkListPointers(t, l, []*(Element[string]){e})
|
||||
l.Remove(e)
|
||||
checkListPointers(t, l, []*(Element(string)){})
|
||||
checkListPointers(t, l, []*(Element[string]){})
|
||||
|
||||
// Bigger list
|
||||
l2 := New(int)()
|
||||
l2 := New[int]()
|
||||
e2 := l2.PushFront(2)
|
||||
e1 := l2.PushFront(1)
|
||||
e3 := l2.PushBack(3)
|
||||
e4 := l2.PushBack(600)
|
||||
checkListPointers(t, l2, []*(Element(int)){e1, e2, e3, e4})
|
||||
checkListPointers(t, l2, []*(Element[int]){e1, e2, e3, e4})
|
||||
|
||||
l2.Remove(e2)
|
||||
checkListPointers(t, l2, []*(Element(int)){e1, e3, e4})
|
||||
checkListPointers(t, l2, []*(Element[int]){e1, e3, e4})
|
||||
|
||||
l2.MoveToFront(e3) // move from middle
|
||||
checkListPointers(t, l2, []*(Element(int)){e3, e1, e4})
|
||||
checkListPointers(t, l2, []*(Element[int]){e3, e1, e4})
|
||||
|
||||
l2.MoveToFront(e1)
|
||||
l2.MoveToBack(e3) // move from middle
|
||||
checkListPointers(t, l2, []*(Element(int)){e1, e4, e3})
|
||||
checkListPointers(t, l2, []*(Element[int]){e1, e4, e3})
|
||||
|
||||
l2.MoveToFront(e3) // move from back
|
||||
checkListPointers(t, l2, []*(Element(int)){e3, e1, e4})
|
||||
checkListPointers(t, l2, []*(Element[int]){e3, e1, e4})
|
||||
l2.MoveToFront(e3) // should be no-op
|
||||
checkListPointers(t, l2, []*(Element(int)){e3, e1, e4})
|
||||
checkListPointers(t, l2, []*(Element[int]){e3, e1, e4})
|
||||
|
||||
l2.MoveToBack(e3) // move from front
|
||||
checkListPointers(t, l2, []*(Element(int)){e1, e4, e3})
|
||||
checkListPointers(t, l2, []*(Element[int]){e1, e4, e3})
|
||||
l2.MoveToBack(e3) // should be no-op
|
||||
checkListPointers(t, l2, []*(Element(int)){e1, e4, e3})
|
||||
checkListPointers(t, l2, []*(Element[int]){e1, e4, e3})
|
||||
|
||||
e2 = l2.InsertBefore(2, e1) // insert before front
|
||||
checkListPointers(t, l2, []*(Element(int)){e2, e1, e4, e3})
|
||||
checkListPointers(t, l2, []*(Element[int]){e2, e1, e4, e3})
|
||||
l2.Remove(e2)
|
||||
e2 = l2.InsertBefore(2, e4) // insert before middle
|
||||
checkListPointers(t, l2, []*(Element(int)){e1, e2, e4, e3})
|
||||
checkListPointers(t, l2, []*(Element[int]){e1, e2, e4, e3})
|
||||
l2.Remove(e2)
|
||||
e2 = l2.InsertBefore(2, e3) // insert before back
|
||||
checkListPointers(t, l2, []*(Element(int)){e1, e4, e2, e3})
|
||||
checkListPointers(t, l2, []*(Element[int]){e1, e4, e2, e3})
|
||||
l2.Remove(e2)
|
||||
|
||||
e2 = l2.InsertAfter(2, e1) // insert after front
|
||||
checkListPointers(t, l2, []*(Element(int)){e1, e2, e4, e3})
|
||||
checkListPointers(t, l2, []*(Element[int]){e1, e2, e4, e3})
|
||||
l2.Remove(e2)
|
||||
e2 = l2.InsertAfter(2, e4) // insert after middle
|
||||
checkListPointers(t, l2, []*(Element(int)){e1, e4, e2, e3})
|
||||
checkListPointers(t, l2, []*(Element[int]){e1, e4, e2, e3})
|
||||
l2.Remove(e2)
|
||||
e2 = l2.InsertAfter(2, e3) // insert after back
|
||||
checkListPointers(t, l2, []*(Element(int)){e1, e4, e3, e2})
|
||||
checkListPointers(t, l2, []*(Element[int]){e1, e4, e3, e2})
|
||||
l2.Remove(e2)
|
||||
|
||||
// Check standard iteration.
|
||||
|
|
@ -135,15 +135,15 @@ func TestList(t *testing.T) {
|
|||
}
|
||||
|
||||
// Clear all elements by iterating
|
||||
var next *Element(int)
|
||||
var next *Element[int]
|
||||
for e := l2.Front(); e != nil; e = next {
|
||||
next = e.Next()
|
||||
l2.Remove(e)
|
||||
}
|
||||
checkListPointers(t, l2, []*(Element(int)){})
|
||||
checkListPointers(t, l2, []*(Element[int]){})
|
||||
}
|
||||
|
||||
func checkList(type TElem comparable)(t *testing.T, l *List(TElem), es []interface{}) {
|
||||
func checkList[type TElem comparable](t *testing.T, l *List[TElem], es []interface{}) {
|
||||
if !checkListLen(t, l, len(es)) {
|
||||
return
|
||||
}
|
||||
|
|
@ -159,8 +159,8 @@ func checkList(type TElem comparable)(t *testing.T, l *List(TElem), es []interfa
|
|||
}
|
||||
|
||||
func TestExtending(t *testing.T) {
|
||||
l1 := New(int)()
|
||||
l2 := New(int)()
|
||||
l1 := New[int]()
|
||||
l2 := New[int]()
|
||||
|
||||
l1.PushBack(1)
|
||||
l1.PushBack(2)
|
||||
|
|
@ -169,13 +169,13 @@ func TestExtending(t *testing.T) {
|
|||
l2.PushBack(4)
|
||||
l2.PushBack(5)
|
||||
|
||||
l3 := New(int)()
|
||||
l3 := New[int]()
|
||||
l3.PushBackList(l1)
|
||||
checkList(t, l3, []interface{}{1, 2, 3})
|
||||
l3.PushBackList(l2)
|
||||
checkList(t, l3, []interface{}{1, 2, 3, 4, 5})
|
||||
|
||||
l3 = New(int)()
|
||||
l3 = New[int]()
|
||||
l3.PushFrontList(l2)
|
||||
checkList(t, l3, []interface{}{4, 5})
|
||||
l3.PushFrontList(l1)
|
||||
|
|
@ -184,19 +184,19 @@ func TestExtending(t *testing.T) {
|
|||
checkList(t, l1, []interface{}{1, 2, 3})
|
||||
checkList(t, l2, []interface{}{4, 5})
|
||||
|
||||
l3 = New(int)()
|
||||
l3 = New[int]()
|
||||
l3.PushBackList(l1)
|
||||
checkList(t, l3, []interface{}{1, 2, 3})
|
||||
l3.PushBackList(l3)
|
||||
checkList(t, l3, []interface{}{1, 2, 3, 1, 2, 3})
|
||||
|
||||
l3 = New(int)()
|
||||
l3 = New[int]()
|
||||
l3.PushFrontList(l1)
|
||||
checkList(t, l3, []interface{}{1, 2, 3})
|
||||
l3.PushFrontList(l3)
|
||||
checkList(t, l3, []interface{}{1, 2, 3, 1, 2, 3})
|
||||
|
||||
l3 = New(int)()
|
||||
l3 = New[int]()
|
||||
l1.PushBackList(l3)
|
||||
checkList(t, l1, []interface{}{1, 2, 3})
|
||||
l1.PushFrontList(l3)
|
||||
|
|
@ -204,23 +204,23 @@ func TestExtending(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRemove(t *testing.T) {
|
||||
l := New(int)()
|
||||
l := New[int]()
|
||||
e1 := l.PushBack(1)
|
||||
e2 := l.PushBack(2)
|
||||
checkListPointers(t, l, []*(Element(int)){e1, e2})
|
||||
checkListPointers(t, l, []*(Element[int]){e1, e2})
|
||||
e := l.Front()
|
||||
l.Remove(e)
|
||||
checkListPointers(t, l, []*(Element(int)){e2})
|
||||
checkListPointers(t, l, []*(Element[int]){e2})
|
||||
l.Remove(e)
|
||||
checkListPointers(t, l, []*(Element(int)){e2})
|
||||
checkListPointers(t, l, []*(Element[int]){e2})
|
||||
}
|
||||
|
||||
func TestIssue4103(t *testing.T) {
|
||||
l1 := New(int)()
|
||||
l1 := New[int]()
|
||||
l1.PushBack(1)
|
||||
l1.PushBack(2)
|
||||
|
||||
l2 := New(int)()
|
||||
l2 := New[int]()
|
||||
l2.PushBack(3)
|
||||
l2.PushBack(4)
|
||||
|
||||
|
|
@ -237,7 +237,7 @@ func TestIssue4103(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestIssue6349(t *testing.T) {
|
||||
l := New(int)()
|
||||
l := New[int]()
|
||||
l.PushBack(1)
|
||||
l.PushBack(2)
|
||||
|
||||
|
|
@ -255,84 +255,84 @@ func TestIssue6349(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMove(t *testing.T) {
|
||||
l := New(int)()
|
||||
l := New[int]()
|
||||
e1 := l.PushBack(1)
|
||||
e2 := l.PushBack(2)
|
||||
e3 := l.PushBack(3)
|
||||
e4 := l.PushBack(4)
|
||||
|
||||
l.MoveAfter(e3, e3)
|
||||
checkListPointers(t, l, []*(Element(int)){e1, e2, e3, e4})
|
||||
checkListPointers(t, l, []*(Element[int]){e1, e2, e3, e4})
|
||||
l.MoveBefore(e2, e2)
|
||||
checkListPointers(t, l, []*(Element(int)){e1, e2, e3, e4})
|
||||
checkListPointers(t, l, []*(Element[int]){e1, e2, e3, e4})
|
||||
|
||||
l.MoveAfter(e3, e2)
|
||||
checkListPointers(t, l, []*(Element(int)){e1, e2, e3, e4})
|
||||
checkListPointers(t, l, []*(Element[int]){e1, e2, e3, e4})
|
||||
l.MoveBefore(e2, e3)
|
||||
checkListPointers(t, l, []*(Element(int)){e1, e2, e3, e4})
|
||||
checkListPointers(t, l, []*(Element[int]){e1, e2, e3, e4})
|
||||
|
||||
l.MoveBefore(e2, e4)
|
||||
checkListPointers(t, l, []*(Element(int)){e1, e3, e2, e4})
|
||||
checkListPointers(t, l, []*(Element[int]){e1, e3, e2, e4})
|
||||
e2, e3 = e3, e2
|
||||
|
||||
l.MoveBefore(e4, e1)
|
||||
checkListPointers(t, l, []*(Element(int)){e4, e1, e2, e3})
|
||||
checkListPointers(t, l, []*(Element[int]){e4, e1, e2, e3})
|
||||
e1, e2, e3, e4 = e4, e1, e2, e3
|
||||
|
||||
l.MoveAfter(e4, e1)
|
||||
checkListPointers(t, l, []*(Element(int)){e1, e4, e2, e3})
|
||||
checkListPointers(t, l, []*(Element[int]){e1, e4, e2, e3})
|
||||
e2, e3, e4 = e4, e2, e3
|
||||
|
||||
l.MoveAfter(e2, e3)
|
||||
checkListPointers(t, l, []*(Element(int)){e1, e3, e2, e4})
|
||||
checkListPointers(t, l, []*(Element[int]){e1, e3, e2, e4})
|
||||
e2, e3 = e3, e2
|
||||
}
|
||||
|
||||
// Test PushFront, PushBack, PushFrontList, PushBackList with uninitialized List
|
||||
func TestZeroList(t *testing.T) {
|
||||
var l1 = new(List(int))
|
||||
var l1 = new(List[int])
|
||||
l1.PushFront(1)
|
||||
checkList(t, l1, []interface{}{1})
|
||||
|
||||
var l2 = new(List(int))
|
||||
var l2 = new(List[int])
|
||||
l2.PushBack(1)
|
||||
checkList(t, l2, []interface{}{1})
|
||||
|
||||
var l3 = new(List(int))
|
||||
var l3 = new(List[int])
|
||||
l3.PushFrontList(l1)
|
||||
checkList(t, l3, []interface{}{1})
|
||||
|
||||
var l4 = new(List(int))
|
||||
var l4 = new(List[int])
|
||||
l4.PushBackList(l2)
|
||||
checkList(t, l4, []interface{}{1})
|
||||
}
|
||||
|
||||
// Test that a list l is not modified when calling InsertBefore with a mark that is not an element of l.
|
||||
func TestInsertBeforeUnknownMark(t *testing.T) {
|
||||
var l List(int)
|
||||
var l List[int]
|
||||
l.PushBack(1)
|
||||
l.PushBack(2)
|
||||
l.PushBack(3)
|
||||
l.InsertBefore(1, new(Element(int)))
|
||||
l.InsertBefore(1, new(Element[int]))
|
||||
checkList(t, &l, []interface{}{1, 2, 3})
|
||||
}
|
||||
|
||||
// Test that a list l is not modified when calling InsertAfter with a mark that is not an element of l.
|
||||
func TestInsertAfterUnknownMark(t *testing.T) {
|
||||
var l List(int)
|
||||
var l List[int]
|
||||
l.PushBack(1)
|
||||
l.PushBack(2)
|
||||
l.PushBack(3)
|
||||
l.InsertAfter(1, new(Element(int)))
|
||||
l.InsertAfter(1, new(Element[int]))
|
||||
checkList(t, &l, []interface{}{1, 2, 3})
|
||||
}
|
||||
|
||||
// Test that a list l is not modified when calling MoveAfter or MoveBefore with a mark that is not an element of l.
|
||||
func TestMoveUnknownMark(t *testing.T) {
|
||||
var l1 List(int)
|
||||
var l1 List[int]
|
||||
e1 := l1.PushBack(1)
|
||||
|
||||
var l2 List(int)
|
||||
var l2 List[int]
|
||||
e2 := l2.PushBack(2)
|
||||
|
||||
l1.MoveAfter(e1, e2)
|
||||
|
|
@ -346,7 +346,7 @@ func TestMoveUnknownMark(t *testing.T) {
|
|||
|
||||
// Test the Transform function.
|
||||
func TestTransform(t *testing.T) {
|
||||
l1 := New(int)()
|
||||
l1 := New[int]()
|
||||
l1.PushBack(1)
|
||||
l1.PushBack(2)
|
||||
l2 := Transform(l1, strconv.Itoa)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ type any interface{}
|
|||
|
||||
// Keys returns the keys of the map m.
|
||||
// The keys will be an indeterminate order.
|
||||
func Keys(type K comparable, V any)(m map[K]V) []K {
|
||||
func Keys[type K comparable, V any](m map[K]V) []K {
|
||||
r := make([]K, 0, len(m))
|
||||
for k := range m {
|
||||
r = append(r, k)
|
||||
|
|
@ -20,7 +20,7 @@ func Keys(type K comparable, V any)(m map[K]V) []K {
|
|||
|
||||
// Values returns the values of the map m.
|
||||
// The values will be in an indeterminate order.
|
||||
func Values(type K comparable, V any)(m map[K]V) []V {
|
||||
func Values[type K comparable, V any](m map[K]V) []V {
|
||||
r := make([]V, 0, len(m))
|
||||
for _, v := range m {
|
||||
r = append(r, v)
|
||||
|
|
@ -30,7 +30,7 @@ func Values(type K comparable, V any)(m map[K]V) []V {
|
|||
|
||||
// Equal reports whether two maps contain the same key/value pairs.
|
||||
// Values are compared using ==.
|
||||
func Equal(type K, V comparable)(m1, m2 map[K]V) bool {
|
||||
func Equal[type K, V comparable](m1, m2 map[K]V) bool {
|
||||
if len(m1) != len(m2) {
|
||||
return false
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ func Equal(type K, V comparable)(m1, m2 map[K]V) bool {
|
|||
}
|
||||
|
||||
// Copy returns a copy of m.
|
||||
func Copy(type K comparable, V any)(m map[K]V) map[K]V {
|
||||
func Copy[type K comparable, V any](m map[K]V) map[K]V {
|
||||
r := make(map[K]V, len(m))
|
||||
for k, v := range m {
|
||||
r[k] = v
|
||||
|
|
@ -53,7 +53,7 @@ func Copy(type K comparable, V any)(m map[K]V) map[K]V {
|
|||
|
||||
// Add adds all key/value pairs in m2 to m1. Keys in m2 that are already
|
||||
// present in m1 will be overwritten with the value in m2.
|
||||
func Add(type K comparable, V any)(m1, m2 map[K]V) {
|
||||
func Add[type K comparable, V any](m1, m2 map[K]V) {
|
||||
for k, v := range m2 {
|
||||
m1[k] = v
|
||||
}
|
||||
|
|
@ -61,7 +61,7 @@ func Add(type K comparable, V any)(m1, m2 map[K]V) {
|
|||
|
||||
// Sub removes all keys in m2 from m1. Keys in m2 that are not present
|
||||
// in m1 are ignored. The values in m2 are ignored.
|
||||
func Sub(type K comparable, V any)(m1, m2 map[K]V) {
|
||||
func Sub[type K comparable, V any](m1, m2 map[K]V) {
|
||||
for k := range m2 {
|
||||
delete(m1, k)
|
||||
}
|
||||
|
|
@ -69,7 +69,7 @@ func Sub(type K comparable, V any)(m1, m2 map[K]V) {
|
|||
|
||||
// Intersect removes all keys from m1 that are not present in m2.
|
||||
// Keys in m2 that are not in m1 are ignored. The values in m2 are ignored.
|
||||
func Intersect(type K comparable, V any)(m1, m2 map[K]V) {
|
||||
func Intersect[type K comparable, V any](m1, m2 map[K]V) {
|
||||
for k := range m1 {
|
||||
if _, ok := m2[k]; !ok {
|
||||
delete(m1, k)
|
||||
|
|
@ -78,7 +78,7 @@ func Intersect(type K comparable, V any)(m1, m2 map[K]V) {
|
|||
}
|
||||
|
||||
// Filter deletes any key/value pairs from m for which f returns false.
|
||||
func Filter(type K comparable, V any)(m map[K]V, f func(K, V) bool) {
|
||||
func Filter[type K comparable, V any](m map[K]V, f func(K, V) bool) {
|
||||
for k, v := range m {
|
||||
if !f(k, v) {
|
||||
delete(m, k)
|
||||
|
|
@ -87,7 +87,7 @@ func Filter(type K comparable, V any)(m map[K]V, f func(K, V) bool) {
|
|||
}
|
||||
|
||||
// TransformValues applies f to each value in m. The keys remain unchanged.
|
||||
func TransformValues(type K comparable, V any)(m map[K]V, f func(V) V) {
|
||||
func TransformValues[type K comparable, V any](m map[K]V, f func(V) V) {
|
||||
for k, v := range m {
|
||||
m[k] = f(v)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@ import (
|
|||
)
|
||||
|
||||
// Metric1 tracks metrics of values of some type.
|
||||
type Metric1(type T comparable) struct {
|
||||
type Metric1[type T comparable] struct {
|
||||
mu sync.Mutex
|
||||
m map[T]int
|
||||
}
|
||||
|
||||
// Add adds another instance of some value.
|
||||
func (m *Metric1(T)) Add(v T) {
|
||||
func (m *Metric1[T]) Add(v T) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if m.m == nil {
|
||||
|
|
@ -29,47 +29,47 @@ func (m *Metric1(T)) Add(v T) {
|
|||
}
|
||||
|
||||
// Count returns the number of instances we've seen of v.
|
||||
func (m *Metric1(T)) Count(v T) int {
|
||||
func (m *Metric1[T]) Count(v T) int {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
return m.m[v]
|
||||
}
|
||||
|
||||
// Metrics returns all the values we've seen, in an indeterminate order.
|
||||
func (m *Metric1(T)) Metrics() []T {
|
||||
func (m *Metric1[T]) Metrics() []T {
|
||||
return maps.Keys(m.m)
|
||||
}
|
||||
|
||||
type key2(type T1, T2 comparable) struct {
|
||||
type key2[type T1, T2 comparable] struct {
|
||||
f1 T1
|
||||
f2 T2
|
||||
}
|
||||
|
||||
// Metric2 tracks metrics of pairs of values.
|
||||
type Metric2(type T1, T2 comparable) struct {
|
||||
type Metric2[type T1, T2 comparable] struct {
|
||||
mu sync.Mutex
|
||||
m map[key2(T1, T2)]int
|
||||
m map[key2[T1, T2]]int
|
||||
}
|
||||
|
||||
// Add adds another instance of some pair of values.
|
||||
func (m *Metric2(T1, T2)) Add(v1 T1, v2 T2) {
|
||||
func (m *Metric2[T1, T2]) Add(v1 T1, v2 T2) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if m.m == nil {
|
||||
m.m = make(map[key2(T1, T2)]int)
|
||||
m.m = make(map[key2[T1, T2]]int)
|
||||
}
|
||||
m.m[key2(T1, T2){v1, v2}]++
|
||||
m.m[key2[T1, T2]{v1, v2}]++
|
||||
}
|
||||
|
||||
// Count returns the number of instances we've seen of v1/v2.
|
||||
func (m *Metric2(T1, T2)) Count(v1 T1, v2 T2) int {
|
||||
func (m *Metric2[T1, T2]) Count(v1 T1, v2 T2) int {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
return m.m[key2(T1, T2){v1, v2}]
|
||||
return m.m[key2[T1, T2]{v1, v2}]
|
||||
}
|
||||
|
||||
// Metrics returns all the values we've seen, in an indeterminate order.
|
||||
func (m *Metric2(T1, T2)) Metrics() (r1 []T1, r2 []T2) {
|
||||
func (m *Metric2[T1, T2]) Metrics() (r1 []T1, r2 []T2) {
|
||||
for _, k := range maps.Keys(m.m) {
|
||||
r1 = append(r1, k.f1)
|
||||
r2 = append(r2, k.f2)
|
||||
|
|
@ -77,37 +77,37 @@ func (m *Metric2(T1, T2)) Metrics() (r1 []T1, r2 []T2) {
|
|||
return r1, r2
|
||||
}
|
||||
|
||||
type key3(type T1, T2, T3 comparable) struct {
|
||||
type key3[type T1, T2, T3 comparable] struct {
|
||||
f1 T1
|
||||
f2 T2
|
||||
f3 T3
|
||||
}
|
||||
|
||||
// Metric3 tracks metrics of triplets of values.
|
||||
type Metric3(type T1, T2, T3 comparable) struct {
|
||||
type Metric3[type T1, T2, T3 comparable] struct {
|
||||
mu sync.Mutex
|
||||
m map[key3(T1, T2, T3)]int
|
||||
m map[key3[T1, T2, T3]]int
|
||||
}
|
||||
|
||||
// Add adds another instance of some triplet of values.
|
||||
func (m *Metric3(T1, T2, T3)) Add(v1 T1, v2 T2, v3 T3) {
|
||||
func (m *Metric3[T1, T2, T3]) Add(v1 T1, v2 T2, v3 T3) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if m.m == nil {
|
||||
m.m = make(map[key3(T1, T2, T3)]int)
|
||||
m.m = make(map[key3[T1, T2, T3]]int)
|
||||
}
|
||||
m.m[key3(T1, T2, T3){v1, v2, v3}]++
|
||||
m.m[key3[T1, T2, T3]{v1, v2, v3}]++
|
||||
}
|
||||
|
||||
// Count returns the number of instances we've seen of v1/v2/v3.
|
||||
func (m *Metric3(T1, T2, T3)) Count(v1 T1, v2 T2, v3 T3) int {
|
||||
func (m *Metric3[T1, T2, T3]) Count(v1 T1, v2 T2, v3 T3) int {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
return m.m[key3(T1, T2, T3){v1, v2, v3}]
|
||||
return m.m[key3[T1, T2, T3]{v1, v2, v3}]
|
||||
}
|
||||
|
||||
// Metrics returns all the values we've seen, in an indeterminate order.
|
||||
func (m *Metric3(T1, T2, T3)) Metrics() (r1 []T1, r2 []T2, r3 []T3) {
|
||||
func (m *Metric3[T1, T2, T3]) Metrics() (r1 []T1, r2 []T2, r3 []T3) {
|
||||
for k := range m.m {
|
||||
r1 = append(r1, k.f1)
|
||||
r2 = append(r2, k.f2)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import (
|
|||
type S struct{ a, b, c string }
|
||||
|
||||
func TestMetrics(t *testing.T) {
|
||||
m1 := Metric1(string){}
|
||||
m1 := Metric1[string]{}
|
||||
if got := m1.Count("a"); got != 0 {
|
||||
t.Errorf("Count(%q) = %d, want 0", "a", got)
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ func TestMetrics(t *testing.T) {
|
|||
t.Errorf("Metrics = %v, want %v", got, want)
|
||||
}
|
||||
|
||||
m2 := Metric2(int, float64){}
|
||||
m2 := Metric2[int, float64]{}
|
||||
m2.Add(1, 1)
|
||||
m2.Add(2, 2)
|
||||
m2.Add(3, 3)
|
||||
|
|
@ -46,7 +46,7 @@ func TestMetrics(t *testing.T) {
|
|||
t.Errorf("Metric2.Metrics first slice = %v, want %v", k2, w2)
|
||||
}
|
||||
|
||||
m3 := Metric3(string, S, S){}
|
||||
m3 := Metric3[string, S, S]{}
|
||||
m3.Add("a", S{"d", "e", "f"}, S{"g", "h", "i"})
|
||||
m3.Add("a", S{"d", "e", "f"}, S{"g", "h", "i"})
|
||||
m3.Add("a", S{"d", "e", "f"}, S{"g", "h", "i"})
|
||||
|
|
|
|||
|
|
@ -15,30 +15,30 @@ import (
|
|||
)
|
||||
|
||||
// Map is an ordered map.
|
||||
type Map(type K, V) struct {
|
||||
root *node(K, V)
|
||||
type Map[type K, V] struct {
|
||||
root *node[K, V]
|
||||
compare func(K, K) int
|
||||
}
|
||||
|
||||
// node is the type of a node in the binary tree.
|
||||
type node(type K, V) struct {
|
||||
type node[type K, V] struct {
|
||||
key K
|
||||
val V
|
||||
left, right *node(K, V)
|
||||
left, right *node[K, V]
|
||||
}
|
||||
|
||||
// New returns a new map. It takes a comparison function that compares two
|
||||
// keys and returns < 0 if the first is less, == 0 if they are equal,
|
||||
// > 0 if the first is greater.
|
||||
func New(type K, V)(compare func(K, K) int) *Map(K, V) {
|
||||
return &Map(K, V){compare: compare}
|
||||
func New[type K, V](compare func(K, K) int) *Map[K, V] {
|
||||
return &Map[K, V]{compare: compare}
|
||||
}
|
||||
|
||||
// NewOrdered returns a new map whose key is an ordered type.
|
||||
// This is like New, but does not require providing a compare function.
|
||||
// The map compare function uses the obvious key ordering.
|
||||
func NewOrdered(type K constraints.Ordered, V interface{})() *Map(K, V) {
|
||||
return New(K, V)(func(k1, k2 K) int {
|
||||
func NewOrdered[type K constraints.Ordered, V interface{}]() *Map[K, V] {
|
||||
return New[K, V](func(k1, k2 K) int {
|
||||
switch {
|
||||
case k1 < k2:
|
||||
return -1
|
||||
|
|
@ -52,7 +52,7 @@ func NewOrdered(type K constraints.Ordered, V interface{})() *Map(K, V) {
|
|||
|
||||
// find looks up key in the map, returning either a pointer to the slot of the
|
||||
// node holding key, or a pointer to the slot where should a node would go.
|
||||
func (m *Map(K, V)) find(key K) **node(K, V) {
|
||||
func (m *Map[K, V]) find(key K) **node[K, V] {
|
||||
pn := &m.root
|
||||
for *pn != nil {
|
||||
switch cmp := m.compare(key, (*pn).key); {
|
||||
|
|
@ -70,19 +70,19 @@ func (m *Map(K, V)) find(key K) **node(K, V) {
|
|||
// Insert inserts a new key/value into the map.
|
||||
// If the key is already present, the value is replaced.
|
||||
// Reports whether this is a new key.
|
||||
func (m *Map(K, V)) Insert(key K, val V) bool {
|
||||
func (m *Map[K, V]) Insert(key K, val V) bool {
|
||||
pn := m.find(key)
|
||||
if *pn != nil {
|
||||
(*pn).val = val
|
||||
return false
|
||||
}
|
||||
*pn = &node(K, V){key: key, val: val}
|
||||
*pn = &node[K, V]{key: key, val: val}
|
||||
return true
|
||||
}
|
||||
|
||||
// Find returns the value associated with a key, or the zero value
|
||||
// if not present. The found result reports whether the key was found.
|
||||
func (m *Map(K, V)) Find(key K) (V, bool) {
|
||||
func (m *Map[K, V]) Find(key K) (V, bool) {
|
||||
pn := m.find(key)
|
||||
if *pn == nil {
|
||||
var zero V
|
||||
|
|
@ -92,40 +92,40 @@ func (m *Map(K, V)) Find(key K) (V, bool) {
|
|||
}
|
||||
|
||||
// keyValue is a pair of key and value used while iterating.
|
||||
type keyValue(type K, V) struct {
|
||||
type keyValue[type K, V] struct {
|
||||
key K
|
||||
val V
|
||||
}
|
||||
|
||||
// iterate returns an iterator that traverses the map.
|
||||
func (m *Map(K, V)) Iterate() *Iterator(K, V) {
|
||||
sender, receiver := chans.Ranger(keyValue(K, V))()
|
||||
var f func(*node(K, V)) bool
|
||||
f = func(n *node(K, V)) bool {
|
||||
func (m *Map[K, V]) Iterate() *Iterator[K, V] {
|
||||
sender, receiver := chans.Ranger(keyValue[K, V])()
|
||||
var f func(*node[K, V]) bool
|
||||
f = func(n *node[K, V]) bool {
|
||||
if n == nil {
|
||||
return true
|
||||
}
|
||||
// Stop the traversal if Send fails, which means that
|
||||
// nothing is listening to the receiver.
|
||||
return f(n.left) &&
|
||||
sender.Send(context.Background(), keyValue(K, V){n.key, n.val}) &&
|
||||
sender.Send(context.Background(), keyValue[K, V]{n.key, n.val}) &&
|
||||
f(n.right)
|
||||
}
|
||||
go func() {
|
||||
f(m.root)
|
||||
sender.Close()
|
||||
}()
|
||||
return &Iterator(K, V){receiver}
|
||||
return &Iterator[K, V]{receiver}
|
||||
}
|
||||
|
||||
// Iterator is used to iterate over the map.
|
||||
type Iterator(type K, V) struct {
|
||||
r *chans.Receiver(keyValue(K, V))
|
||||
type Iterator[type K, V] struct {
|
||||
r *chans.Receiver[keyValue[K, V]]
|
||||
}
|
||||
|
||||
// Next returns the next key and value pair, and a boolean that reports
|
||||
// whether they are valid. If not valid, we have reached the end of the map.
|
||||
func (it *Iterator(K, V)) Next() (K, V, bool) {
|
||||
func (it *Iterator[K, V]) Next() (K, V, bool) {
|
||||
keyval, ok := it.r.Next(context.Background())
|
||||
if !ok {
|
||||
var zerok K
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
)
|
||||
|
||||
func TestMap(t *testing.T) {
|
||||
m := New([]byte, int)(bytes.Compare)
|
||||
m := New[[]byte, int](bytes.Compare)
|
||||
|
||||
if _, found := m.Find([]byte("a")); found {
|
||||
t.Errorf("unexpectedly found %q in empty map", []byte("a"))
|
||||
|
|
@ -45,7 +45,7 @@ func TestMap(t *testing.T) {
|
|||
t.Errorf("unexpectedly found %q", []byte("d"))
|
||||
}
|
||||
|
||||
gather := func(it *Iterator([]byte, int)) []int {
|
||||
gather := func(it *Iterator[[]byte, int]) []int {
|
||||
var r []int
|
||||
for {
|
||||
_, v, ok := it.Next()
|
||||
|
|
|
|||
|
|
@ -6,40 +6,40 @@
|
|||
package sets
|
||||
|
||||
// A Set is a set of elements of some type.
|
||||
type Set(type Elem comparable) struct {
|
||||
type Set[type Elem comparable] struct {
|
||||
m map[Elem]struct{}
|
||||
}
|
||||
|
||||
// Make makes a new set.
|
||||
func Make(type Elem comparable)() Set(Elem) {
|
||||
return Set(Elem){m: make(map[Elem]struct{})}
|
||||
func Make[type Elem comparable]() Set[Elem] {
|
||||
return Set[Elem]{m: make(map[Elem]struct{})}
|
||||
}
|
||||
|
||||
// Add adds an element to a set.
|
||||
func (s Set(Elem)) Add(v Elem) {
|
||||
func (s Set[Elem]) Add(v Elem) {
|
||||
s.m[v] = struct{}{}
|
||||
}
|
||||
|
||||
// Delete removes an element from a set. If the element is not present
|
||||
// in the set, this does nothing.
|
||||
func (s Set(Elem)) Delete(v Elem) {
|
||||
func (s Set[Elem]) Delete(v Elem) {
|
||||
delete(s.m, v)
|
||||
}
|
||||
|
||||
// Contains reports whether v is in the set.
|
||||
func (s Set(Elem)) Contains(v Elem) bool {
|
||||
func (s Set[Elem]) Contains(v Elem) bool {
|
||||
_, ok := s.m[v]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Len returns the number of elements in the set.
|
||||
func (s Set(Elem)) Len() int {
|
||||
func (s Set[Elem]) Len() int {
|
||||
return len(s.m)
|
||||
}
|
||||
|
||||
// Values returns the values in the set.
|
||||
// The values will be in an indeterminate order.
|
||||
func (s Set(Elem)) Values() []Elem {
|
||||
func (s Set[Elem]) Values() []Elem {
|
||||
r := make([]Elem, 0, len(s.m))
|
||||
for v := range s.m {
|
||||
r = append(r, v)
|
||||
|
|
@ -48,7 +48,7 @@ func (s Set(Elem)) Values() []Elem {
|
|||
}
|
||||
|
||||
// Equal reports whether two sets contain the same elements.
|
||||
func Equal(type Elem comparable)(s1, s2 Set(Elem)) bool {
|
||||
func Equal[type Elem comparable](s1, s2 Set[Elem]) bool {
|
||||
if len(s1.m) != len(s2.m) {
|
||||
return false
|
||||
}
|
||||
|
|
@ -61,8 +61,8 @@ func Equal(type Elem comparable)(s1, s2 Set(Elem)) bool {
|
|||
}
|
||||
|
||||
// Copy returns a copy of s.
|
||||
func (s Set(Elem)) Copy() Set(Elem) {
|
||||
r := Set(Elem){m: make(map[Elem]struct{}, len(s.m))}
|
||||
func (s Set[Elem]) Copy() Set[Elem] {
|
||||
r := Set[Elem]{m: make(map[Elem]struct{}, len(s.m))}
|
||||
for v := range s.m {
|
||||
r.m[v] = struct{}{}
|
||||
}
|
||||
|
|
@ -70,7 +70,7 @@ func (s Set(Elem)) Copy() Set(Elem) {
|
|||
}
|
||||
|
||||
// AddSet adds all the elements of s2 to s.
|
||||
func (s Set(Elem)) AddSet(s2 Set(Elem)) {
|
||||
func (s Set[Elem]) AddSet(s2 Set[Elem]) {
|
||||
for v := range s2.m {
|
||||
s.m[v] = struct{}{}
|
||||
}
|
||||
|
|
@ -78,7 +78,7 @@ func (s Set(Elem)) AddSet(s2 Set(Elem)) {
|
|||
|
||||
// SubSet removes all elements in s2 from s.
|
||||
// Values in s2 that are not in s are ignored.
|
||||
func (s Set(Elem)) SubSet(s2 Set(Elem)) {
|
||||
func (s Set[Elem]) SubSet(s2 Set[Elem]) {
|
||||
for v := range s2.m {
|
||||
delete(s.m, v)
|
||||
}
|
||||
|
|
@ -86,7 +86,7 @@ func (s Set(Elem)) SubSet(s2 Set(Elem)) {
|
|||
|
||||
// Intersect removes all elements from s that are not present in s2.
|
||||
// Values in s2 that are not in s are ignored.
|
||||
func (s Set(Elem)) Intersect(s2 Set(Elem)) {
|
||||
func (s Set[Elem]) Intersect(s2 Set[Elem]) {
|
||||
for v := range s.m {
|
||||
if !s2.Contains(v) {
|
||||
delete(s.m, v)
|
||||
|
|
@ -95,14 +95,14 @@ func (s Set(Elem)) Intersect(s2 Set(Elem)) {
|
|||
}
|
||||
|
||||
// Iterate calls f on every element in the set.
|
||||
func (s Set(Elem)) Iterate(f func(Elem)) {
|
||||
func (s Set[Elem]) Iterate(f func(Elem)) {
|
||||
for v := range s.m {
|
||||
f(v)
|
||||
}
|
||||
}
|
||||
|
||||
// Filter deletes any elements from s for which f returns false.
|
||||
func (s Set(Elem)) Filter(f func(Elem) bool) {
|
||||
func (s Set[Elem]) Filter(f func(Elem) bool) {
|
||||
for v := range s.m {
|
||||
if !f(v) {
|
||||
delete(s.m, v)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
)
|
||||
|
||||
func TestSet(t *testing.T) {
|
||||
s1 := Make(int)()
|
||||
s1 := Make[int]()
|
||||
if got := s1.Len(); got != 0 {
|
||||
t.Errorf("Len of empty set = %d, want 0", got)
|
||||
}
|
||||
|
|
@ -43,8 +43,8 @@ func TestSet(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestEqual(t *testing.T) {
|
||||
s1 := Make(string)()
|
||||
s2 := Make(string)()
|
||||
s1 := Make[string]()
|
||||
s2 := Make[string]()
|
||||
if !Equal(s1, s2) {
|
||||
t.Errorf("Equal(%v, %v) = false, want true", s1, s2)
|
||||
}
|
||||
|
|
@ -59,7 +59,7 @@ func TestEqual(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCopy(t *testing.T) {
|
||||
s1 := Make(float64)()
|
||||
s1 := Make[float64]()
|
||||
s1.Add(0)
|
||||
s2 := s1.Copy()
|
||||
if !Equal(s1, s2) {
|
||||
|
|
@ -72,10 +72,10 @@ func TestCopy(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAddSet(t *testing.T) {
|
||||
s1 := Make(int)()
|
||||
s1 := Make[int]()
|
||||
s1.Add(1)
|
||||
s1.Add(2)
|
||||
s2 := Make(int)()
|
||||
s2 := Make[int]()
|
||||
s2.Add(2)
|
||||
s2.Add(3)
|
||||
s1.AddSet(s2)
|
||||
|
|
@ -89,10 +89,10 @@ func TestAddSet(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSubSet(t *testing.T) {
|
||||
s1 := Make(int)()
|
||||
s1 := Make[int]()
|
||||
s1.Add(1)
|
||||
s1.Add(2)
|
||||
s2 := Make(int)()
|
||||
s2 := Make[int]()
|
||||
s2.Add(2)
|
||||
s2.Add(3)
|
||||
s1.SubSet(s2)
|
||||
|
|
@ -105,10 +105,10 @@ func TestSubSet(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestIntersect(t *testing.T) {
|
||||
s1 := Make(int)()
|
||||
s1 := Make[int]()
|
||||
s1.Add(1)
|
||||
s1.Add(2)
|
||||
s2 := Make(int)()
|
||||
s2 := Make[int]()
|
||||
s2.Add(2)
|
||||
s2.Add(3)
|
||||
s1.Intersect(s2)
|
||||
|
|
@ -121,7 +121,7 @@ func TestIntersect(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestIterate(t *testing.T) {
|
||||
s1 := Make(int)()
|
||||
s1 := Make[int]()
|
||||
s1.Add(1)
|
||||
s1.Add(2)
|
||||
s1.Add(3)
|
||||
|
|
@ -134,7 +134,7 @@ func TestIterate(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFilter(t *testing.T) {
|
||||
s1 := Make(int)()
|
||||
s1 := Make[int]()
|
||||
s1.Add(1)
|
||||
s1.Add(2)
|
||||
s1.Add(3)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import (
|
|||
|
||||
// Equal reports whether two slices are equal: the same length and all
|
||||
// elements equal. All floating point NaNs are considered equal.
|
||||
func Equal(type Elem comparable)(s1, s2 []Elem) bool {
|
||||
func Equal[type Elem comparable](s1, s2 []Elem) bool {
|
||||
if len(s1) != len(s2) {
|
||||
return false
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ func Equal(type Elem comparable)(s1, s2 []Elem) bool {
|
|||
|
||||
// EqualFn reports whether two slices are equal using a comparision
|
||||
// function on each element.
|
||||
func EqualFn(type Elem)(s1, s2 []Elem, eq func(Elem, Elem) bool) bool {
|
||||
func EqualFn[type Elem](s1, s2 []Elem, eq func(Elem, Elem) bool) bool {
|
||||
if len(s1) != len(s2) {
|
||||
return false
|
||||
}
|
||||
|
|
@ -45,7 +45,7 @@ func EqualFn(type Elem)(s1, s2 []Elem, eq func(Elem, Elem) bool) bool {
|
|||
}
|
||||
|
||||
// Map turns a []Elem1 to a []Elem2 using a mapping function.
|
||||
func Map(type Elem1, Elem2)(s []Elem1, f func(Elem1) Elem2) []Elem2 {
|
||||
func Map[type Elem1, Elem2](s []Elem1, f func(Elem1) Elem2) []Elem2 {
|
||||
r := make([]Elem2, len(s))
|
||||
for i, v := range s {
|
||||
r[i] = f(v)
|
||||
|
|
@ -55,7 +55,7 @@ func Map(type Elem1, Elem2)(s []Elem1, f func(Elem1) Elem2) []Elem2 {
|
|||
|
||||
// Reduce reduces a []Elem1 to a single value of type Elem2 using
|
||||
// a reduction function.
|
||||
func Reduce(type Elem1, Elem2)(s []Elem1, initializer Elem2, f func(Elem2, Elem1) Elem2) Elem2 {
|
||||
func Reduce[type Elem1, Elem2](s []Elem1, initializer Elem2, f func(Elem2, Elem1) Elem2) Elem2 {
|
||||
r := initializer
|
||||
for _, v := range s {
|
||||
r = f(r, v)
|
||||
|
|
@ -64,7 +64,7 @@ func Reduce(type Elem1, Elem2)(s []Elem1, initializer Elem2, f func(Elem2, Elem1
|
|||
}
|
||||
|
||||
// Filter filters values from a slice using a filter function.
|
||||
func Filter(type Elem)(s []Elem, f func(Elem) bool) []Elem {
|
||||
func Filter[type Elem](s []Elem, f func(Elem) bool) []Elem {
|
||||
var r []Elem
|
||||
for _, v := range s {
|
||||
if f(v) {
|
||||
|
|
@ -76,7 +76,7 @@ func Filter(type Elem)(s []Elem, f func(Elem) bool) []Elem {
|
|||
|
||||
// Max returns the maximum element in a slice of some ordered type.
|
||||
// If the slice is empty it returns the zero value of the element type.
|
||||
func Max(type Elem constraints.Ordered)(s []Elem) Elem {
|
||||
func Max[type Elem constraints.Ordered](s []Elem) Elem {
|
||||
if len(s) == 0 {
|
||||
var zero Elem
|
||||
return zero
|
||||
|
|
@ -86,7 +86,7 @@ func Max(type Elem constraints.Ordered)(s []Elem) Elem {
|
|||
|
||||
// Min returns the minimum element in a slice of some ordered type.
|
||||
// If the slice is empty it returns the zero value of the element type.
|
||||
func Min(type Elem constraints.Ordered)(s []Elem) Elem {
|
||||
func Min[type Elem constraints.Ordered](s []Elem) Elem {
|
||||
if len(s) == 0 {
|
||||
var zero Elem
|
||||
return zero
|
||||
|
|
@ -99,7 +99,7 @@ func Min(type Elem constraints.Ordered)(s []Elem) Elem {
|
|||
// of how to write it using generics. We used to write code like
|
||||
// this before append was added to the language, but we had to write
|
||||
// a separate copy for each type.
|
||||
func Append(type T)(s []T, t ...T) []T {
|
||||
func Append[type T](s []T, t ...T) []T {
|
||||
lens := len(s)
|
||||
tot := lens + len(t)
|
||||
if tot <= cap(s) {
|
||||
|
|
@ -116,7 +116,7 @@ func Append(type T)(s []T, t ...T) []T {
|
|||
// Copy copies values from t to s, stopping when either slice is full,
|
||||
// returning the number of values copied. This is like the predeclared
|
||||
// copy function; it's an example of how to write it using generics.
|
||||
func Copy(type T)(s, t []T) int {
|
||||
func Copy[type T](s, t []T) int {
|
||||
i := 0
|
||||
for ; i < len(s) && i < len(t); i++ {
|
||||
s[i] = t[i]
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ func TestEqual(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func offByOne(type Elem constraints.Integer)(a, b Elem) bool {
|
||||
func offByOne[type Elem constraints.Integer](a, b Elem) bool {
|
||||
return a == b + 1 || a == b - 1
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue