Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generics migration #237

Merged
merged 5 commits into from
Jan 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions containers/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,39 @@
// Serialization provides serializers (marshalers) and deserializers (unmarshalers).
package containers

import "github.com/emirpasic/gods/utils"
import (
"cmp"
"slices"

"github.com/emirpasic/gods/v2/utils"
)

// Container is base interface that all data structures implement.
type Container interface {
type Container[T any] interface {
Empty() bool
Size() int
Clear()
Values() []interface{}
Values() []T
String() string
}

// GetSortedValues returns sorted container's elements with respect to the passed comparator.
// Does not affect the ordering of elements within the container.
func GetSortedValues(container Container, comparator utils.Comparator) []interface{} {
func GetSortedValues[T cmp.Ordered](container Container[T]) []T {
values := container.Values()
if len(values) < 2 {
return values
}
slices.Sort(values)
return values
}

// GetSortedValuesFunc is the equivalent of GetSortedValues for containers of values that are not ordered.
func GetSortedValuesFunc[T any](container Container[T], comparator utils.Comparator[T]) []T {
values := container.Values()
if len(values) < 2 {
return values
}
utils.Sort(values, comparator)
slices.SortFunc(values, comparator)
return values
}
48 changes: 28 additions & 20 deletions containers/containers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,34 @@
package containers

import (
"cmp"
"fmt"
"github.com/emirpasic/gods/utils"
"strings"
"testing"
)

// For testing purposes
type ContainerTest struct {
values []interface{}
type ContainerTest[T any] struct {
values []T
}

func (container ContainerTest) Empty() bool {
func (container ContainerTest[T]) Empty() bool {
return len(container.values) == 0
}

func (container ContainerTest) Size() int {
func (container ContainerTest[T]) Size() int {
return len(container.values)
}

func (container ContainerTest) Clear() {
container.values = []interface{}{}
func (container ContainerTest[T]) Clear() {
container.values = []T{}
}

func (container ContainerTest) Values() []interface{} {
func (container ContainerTest[T]) Values() []T {
return container.values
}

func (container ContainerTest) String() string {
func (container ContainerTest[T]) String() string {
str := "ContainerTest\n"
var values []string
for _, value := range container.values {
Expand All @@ -45,24 +45,32 @@ func (container ContainerTest) String() string {
}

func TestGetSortedValuesInts(t *testing.T) {
container := ContainerTest{}
GetSortedValues(container, utils.IntComparator)
container.values = []interface{}{5, 1, 3, 2, 4}
values := GetSortedValues(container, utils.IntComparator)
container := ContainerTest[int]{}
GetSortedValues(container)
container.values = []int{5, 1, 3, 2, 4}
values := GetSortedValues(container)
for i := 1; i < container.Size(); i++ {
if values[i-1].(int) > values[i].(int) {
if values[i-1] > values[i] {
t.Errorf("Not sorted!")
}
}
}

func TestGetSortedValuesStrings(t *testing.T) {
container := ContainerTest{}
GetSortedValues(container, utils.StringComparator)
container.values = []interface{}{"g", "a", "d", "e", "f", "c", "b"}
values := GetSortedValues(container, utils.StringComparator)
type NotInt struct {
i int
}

func TestGetSortedValuesNotInts(t *testing.T) {
container := ContainerTest[NotInt]{}
GetSortedValuesFunc(container, func(x, y NotInt) int {
return cmp.Compare(x.i, y.i)
})
container.values = []NotInt{{5}, {1}, {3}, {2}, {4}}
values := GetSortedValuesFunc(container, func(x, y NotInt) int {
return cmp.Compare(x.i, y.i)
})
for i := 1; i < container.Size(); i++ {
if values[i-1].(string) > values[i].(string) {
if values[i-1].i > values[i].i {
t.Errorf("Not sorted!")
}
}
Expand Down
20 changes: 10 additions & 10 deletions containers/enumerable.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
package containers

// EnumerableWithIndex provides functions for ordered containers whose values can be fetched by an index.
type EnumerableWithIndex interface {
type EnumerableWithIndex[T any] interface {
// Each calls the given function once for each element, passing that element's index and value.
Each(func(index int, value interface{}))
Each(func(index int, value T))

// Map invokes the given function once for each element and returns a
// container containing the values returned by the given function.
Expand All @@ -18,22 +18,22 @@ type EnumerableWithIndex interface {

// Any passes each element of the container to the given function and
// returns true if the function ever returns true for any element.
Any(func(index int, value interface{}) bool) bool
Any(func(index int, value T) bool) bool

// All passes each element of the container to the given function and
// returns true if the function returns true for all elements.
All(func(index int, value interface{}) bool) bool
All(func(index int, value T) bool) bool

// Find passes each element of the container to the given function and returns
// the first (index,value) for which the function is true or -1,nil otherwise
// if no element matches the criteria.
Find(func(index int, value interface{}) bool) (int, interface{})
Find(func(index int, value T) bool) (int, T)
}

// EnumerableWithKey provides functions for ordered containers whose values whose elements are key/value pairs.
type EnumerableWithKey interface {
type EnumerableWithKey[K, V any] interface {
// Each calls the given function once for each element, passing that element's key and value.
Each(func(key interface{}, value interface{}))
Each(func(key K, value V))

// Map invokes the given function once for each element and returns a container
// containing the values returned by the given function as key/value pairs.
Expand All @@ -44,14 +44,14 @@ type EnumerableWithKey interface {

// Any passes each element of the container to the given function and
// returns true if the function ever returns true for any element.
Any(func(key interface{}, value interface{}) bool) bool
Any(func(key K, value V) bool) bool

// All passes each element of the container to the given function and
// returns true if the function returns true for all elements.
All(func(key interface{}, value interface{}) bool) bool
All(func(key K, value V) bool) bool

// Find passes each element of the container to the given function and returns
// the first (key,value) for which the function is true or nil,nil otherwise if no element
// matches the criteria.
Find(func(key interface{}, value interface{}) bool) (interface{}, interface{})
Find(func(key K, value V) bool) (K, V)
}
30 changes: 15 additions & 15 deletions containers/iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
package containers

// IteratorWithIndex is stateful iterator for ordered containers whose values can be fetched by an index.
type IteratorWithIndex interface {
type IteratorWithIndex[T any] interface {
// Next moves the iterator to the next element and returns true if there was a next element in the container.
// If Next() returns true, then next element's index and value can be retrieved by Index() and Value().
// If Next() was called for the first time, then it will point the iterator to the first element if it exists.
Expand All @@ -14,7 +14,7 @@ type IteratorWithIndex interface {

// Value returns the current element's value.
// Does not modify the state of the iterator.
Value() interface{}
Value() T

// Index returns the current element's index.
// Does not modify the state of the iterator.
Expand All @@ -33,11 +33,11 @@ type IteratorWithIndex interface {
// passed function, and returns true if there was a next element in the container.
// If NextTo() returns true, then next element's index and value can be retrieved by Index() and Value().
// Modifies the state of the iterator.
NextTo(func(index int, value interface{}) bool) bool
NextTo(func(index int, value T) bool) bool
}

// IteratorWithKey is a stateful iterator for ordered containers whose elements are key value pairs.
type IteratorWithKey interface {
type IteratorWithKey[K, V any] interface {
// Next moves the iterator to the next element and returns true if there was a next element in the container.
// If Next() returns true, then next element's key and value can be retrieved by Key() and Value().
// If Next() was called for the first time, then it will point the iterator to the first element if it exists.
Expand All @@ -46,11 +46,11 @@ type IteratorWithKey interface {

// Value returns the current element's value.
// Does not modify the state of the iterator.
Value() interface{}
Value() V

// Key returns the current element's key.
// Does not modify the state of the iterator.
Key() interface{}
Key() K

// Begin resets the iterator to its initial state (one-before-first)
// Call Next() to fetch the first element if any.
Expand All @@ -65,19 +65,19 @@ type IteratorWithKey interface {
// passed function, and returns true if there was a next element in the container.
// If NextTo() returns true, then next element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator.
NextTo(func(key interface{}, value interface{}) bool) bool
NextTo(func(key K, value V) bool) bool
}

// ReverseIteratorWithIndex is stateful iterator for ordered containers whose values can be fetched by an index.
//
// Essentially it is the same as IteratorWithIndex, but provides additional:
//
// Prev() function to enable traversal in reverse
// # Prev() function to enable traversal in reverse
//
// Last() function to move the iterator to the last element.
//
// End() function to move the iterator past the last element (one-past-the-end).
type ReverseIteratorWithIndex interface {
type ReverseIteratorWithIndex[T any] interface {
// Prev moves the iterator to the previous element and returns true if there was a previous element in the container.
// If Prev() returns true, then previous element's index and value can be retrieved by Index() and Value().
// Modifies the state of the iterator.
Expand All @@ -96,19 +96,19 @@ type ReverseIteratorWithIndex interface {
// passed function, and returns true if there was a next element in the container.
// If PrevTo() returns true, then next element's index and value can be retrieved by Index() and Value().
// Modifies the state of the iterator.
PrevTo(func(index int, value interface{}) bool) bool
PrevTo(func(index int, value T) bool) bool

IteratorWithIndex
IteratorWithIndex[T]
}

// ReverseIteratorWithKey is a stateful iterator for ordered containers whose elements are key value pairs.
//
// Essentially it is the same as IteratorWithKey, but provides additional:
//
// Prev() function to enable traversal in reverse
// # Prev() function to enable traversal in reverse
//
// Last() function to move the iterator to the last element.
type ReverseIteratorWithKey interface {
type ReverseIteratorWithKey[K, V any] interface {
// Prev moves the iterator to the previous element and returns true if there was a previous element in the container.
// If Prev() returns true, then previous element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator.
Expand All @@ -127,7 +127,7 @@ type ReverseIteratorWithKey interface {
// passed function, and returns true if there was a next element in the container.
// If PrevTo() returns true, then next element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator.
PrevTo(func(key interface{}, value interface{}) bool) bool
PrevTo(func(key K, value V) bool) bool

IteratorWithKey
IteratorWithKey[K, V]
}
9 changes: 5 additions & 4 deletions examples/arraylist/arraylist.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@
package main

import (
"github.com/emirpasic/gods/lists/arraylist"
"github.com/emirpasic/gods/utils"
"cmp"

"github.com/emirpasic/gods/v2/lists/arraylist"
)

// ArrayListExample to demonstrate basic usage of ArrayList
func main() {
list := arraylist.New()
list := arraylist.New[string]()
list.Add("a") // ["a"]
list.Add("c", "b") // ["a","c","b"]
list.Sort(utils.StringComparator) // ["a","b","c"]
list.Sort(cmp.Compare[string]) // ["a","b","c"]
_, _ = list.Get(0) // "a",true
_, _ = list.Get(100) // nil,false
_ = list.Contains("a", "b", "c") // true
Expand Down
4 changes: 2 additions & 2 deletions examples/arrayqueue/arrayqqueue.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

package main

import aq "github.com/emirpasic/gods/queues/arrayqueue"
import aq "github.com/emirpasic/gods/v2/queues/arrayqueue"

// ArrayQueueExample to demonstrate basic usage of ArrayQueue
func main() {
queue := aq.New() // empty
queue := aq.New[int]() // empty
queue.Enqueue(1) // 1
queue.Enqueue(2) // 1, 2
_ = queue.Values() // 1, 2 (FIFO order)
Expand Down
26 changes: 13 additions & 13 deletions examples/arraystack/arraystack.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@

package main

import "github.com/emirpasic/gods/stacks/arraystack"
import "github.com/emirpasic/gods/v2/stacks/arraystack"

// ArrayStackExample to demonstrate basic usage of ArrayStack
func main() {
stack := arraystack.New() // empty
stack.Push(1) // 1
stack.Push(2) // 1, 2
stack.Values() // 2, 1 (LIFO order)
_, _ = stack.Peek() // 2,true
_, _ = stack.Pop() // 2, true
_, _ = stack.Pop() // 1, true
_, _ = stack.Pop() // nil, false (nothing to pop)
stack.Push(1) // 1
stack.Clear() // empty
stack.Empty() // true
stack.Size() // 0
stack := arraystack.New[int]() // empty
stack.Push(1) // 1
stack.Push(2) // 1, 2
stack.Values() // 2, 1 (LIFO order)
_, _ = stack.Peek() // 2,true
_, _ = stack.Pop() // 2, true
_, _ = stack.Pop() // 1, true
_, _ = stack.Pop() // nil, false (nothing to pop)
stack.Push(1) // 1
stack.Clear() // empty
stack.Empty() // true
stack.Size() // 0
}
5 changes: 3 additions & 2 deletions examples/avltree/avltree.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ package main

import (
"fmt"
avl "github.com/emirpasic/gods/trees/avltree"

avl "github.com/emirpasic/gods/v2/trees/avltree"
)

// AVLTreeExample to demonstrate basic usage of AVLTree
func main() {
tree := avl.NewWithIntComparator() // empty(keys are of type int)
tree := avl.New[int, string]() // empty(keys are of type int)

tree.Put(1, "x") // 1->x
tree.Put(2, "b") // 1->x, 2->b (in order)
Expand Down
Loading