mirror of
https://github.com/emirpasic/gods
synced 2024-11-08 13:10:26 +00:00
- linkedhashset implementation + iterator + serialization + tests + example + enumerable + documentation
This commit is contained in:
parent
413aad0304
commit
b5b20b02b3
23
examples/linkedhashset/linkedhashset.go
Normal file
23
examples/linkedhashset/linkedhashset.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (c) 2015, Emir Pasic. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/emirpasic/gods/sets/linkedhashset"
|
||||||
|
|
||||||
|
// LinkedHashSetExample to demonstrate basic usage of LinkedHashSet
|
||||||
|
func main() {
|
||||||
|
set := linkedhashset.New() // empty
|
||||||
|
set.Add(5) // 5
|
||||||
|
set.Add(4, 4, 3, 2, 1) // 5, 4, 3, 2, 1 (in insertion-order, duplicates ignored)
|
||||||
|
set.Remove(4) // 5, 3, 2, 1 (in insertion-order)
|
||||||
|
set.Remove(2, 3) // 5, 1 (in insertion-order)
|
||||||
|
set.Contains(1) // true
|
||||||
|
set.Contains(1, 5) // true
|
||||||
|
set.Contains(1, 6) // false
|
||||||
|
_ = set.Values() // []int{5, 1} (in insertion-order)
|
||||||
|
set.Clear() // empty
|
||||||
|
set.Empty() // true
|
||||||
|
set.Size() // 0
|
||||||
|
}
|
79
sets/linkedhashset/enumerable.go
Normal file
79
sets/linkedhashset/enumerable.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// Copyright (c) 2015, Emir Pasic. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package linkedhashset
|
||||||
|
|
||||||
|
import "github.com/emirpasic/gods/containers"
|
||||||
|
|
||||||
|
func assertEnumerableImplementation() {
|
||||||
|
var _ containers.EnumerableWithIndex = (*Set)(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each calls the given function once for each element, passing that element's index and value.
|
||||||
|
func (set *Set) Each(f func(index int, value interface{})) {
|
||||||
|
iterator := set.Iterator()
|
||||||
|
for iterator.Next() {
|
||||||
|
f(iterator.Index(), iterator.Value())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map invokes the given function once for each element and returns a
|
||||||
|
// container containing the values returned by the given function.
|
||||||
|
func (set *Set) Map(f func(index int, value interface{}) interface{}) *Set {
|
||||||
|
newSet := New()
|
||||||
|
iterator := set.Iterator()
|
||||||
|
for iterator.Next() {
|
||||||
|
newSet.Add(f(iterator.Index(), iterator.Value()))
|
||||||
|
}
|
||||||
|
return newSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select returns a new container containing all elements for which the given function returns a true value.
|
||||||
|
func (set *Set) Select(f func(index int, value interface{}) bool) *Set {
|
||||||
|
newSet := New()
|
||||||
|
iterator := set.Iterator()
|
||||||
|
for iterator.Next() {
|
||||||
|
if f(iterator.Index(), iterator.Value()) {
|
||||||
|
newSet.Add(iterator.Value())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any passes each element of the container to the given function and
|
||||||
|
// returns true if the function ever returns true for any element.
|
||||||
|
func (set *Set) Any(f func(index int, value interface{}) bool) bool {
|
||||||
|
iterator := set.Iterator()
|
||||||
|
for iterator.Next() {
|
||||||
|
if f(iterator.Index(), iterator.Value()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// All passes each element of the container to the given function and
|
||||||
|
// returns true if the function returns true for all elements.
|
||||||
|
func (set *Set) All(f func(index int, value interface{}) bool) bool {
|
||||||
|
iterator := set.Iterator()
|
||||||
|
for iterator.Next() {
|
||||||
|
if !f(iterator.Index(), iterator.Value()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
func (set *Set) Find(f func(index int, value interface{}) bool) (int, interface{}) {
|
||||||
|
iterator := set.Iterator()
|
||||||
|
for iterator.Next() {
|
||||||
|
if f(iterator.Index(), iterator.Value()) {
|
||||||
|
return iterator.Index(), iterator.Value()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1, nil
|
||||||
|
}
|
77
sets/linkedhashset/iterator.go
Normal file
77
sets/linkedhashset/iterator.go
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// Copyright (c) 2015, Emir Pasic. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package linkedhashset
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/emirpasic/gods/containers"
|
||||||
|
"github.com/emirpasic/gods/lists/doublylinkedlist"
|
||||||
|
)
|
||||||
|
|
||||||
|
func assertIteratorImplementation() {
|
||||||
|
var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterator holding the iterator's state
|
||||||
|
type Iterator struct {
|
||||||
|
iterator doublylinkedlist.Iterator
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterator returns a stateful iterator whose values can be fetched by an index.
|
||||||
|
func (set *Set) Iterator() Iterator {
|
||||||
|
return Iterator{iterator: set.list.Iterator()}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
// Modifies the state of the iterator.
|
||||||
|
func (iterator *Iterator) Next() bool {
|
||||||
|
return iterator.iterator.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
func (iterator *Iterator) Prev() bool {
|
||||||
|
return iterator.iterator.Prev()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns the current element's value.
|
||||||
|
// Does not modify the state of the iterator.
|
||||||
|
func (iterator *Iterator) Value() interface{} {
|
||||||
|
return iterator.iterator.Value()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Index returns the current element's index.
|
||||||
|
// Does not modify the state of the iterator.
|
||||||
|
func (iterator *Iterator) Index() int {
|
||||||
|
return iterator.iterator.Index()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Begin resets the iterator to its initial state (one-before-first)
|
||||||
|
// Call Next() to fetch the first element if any.
|
||||||
|
func (iterator *Iterator) Begin() {
|
||||||
|
iterator.iterator.Begin()
|
||||||
|
}
|
||||||
|
|
||||||
|
// End moves the iterator past the last element (one-past-the-end).
|
||||||
|
// Call Prev() to fetch the last element if any.
|
||||||
|
func (iterator *Iterator) End() {
|
||||||
|
iterator.iterator.End()
|
||||||
|
}
|
||||||
|
|
||||||
|
// First moves the iterator to the first element and returns true if there was a first element in the container.
|
||||||
|
// If First() returns true, then first element's index and value can be retrieved by Index() and Value().
|
||||||
|
// Modifies the state of the iterator.
|
||||||
|
func (iterator *Iterator) First() bool {
|
||||||
|
return iterator.iterator.First()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last moves the iterator to the last element and returns true if there was a last element in the container.
|
||||||
|
// If Last() returns true, then last element's index and value can be retrieved by Index() and Value().
|
||||||
|
// Modifies the state of the iterator.
|
||||||
|
func (iterator *Iterator) Last() bool {
|
||||||
|
return iterator.iterator.Last()
|
||||||
|
}
|
118
sets/linkedhashset/linkedhashset.go
Normal file
118
sets/linkedhashset/linkedhashset.go
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
// Copyright (c) 2015, Emir Pasic. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package linkedhashset implements a set that preserves insertion-order and is backed a hash tables to store values and doubly-linked list to store ordering.
|
||||||
|
//
|
||||||
|
// Note that insertion-order is not affected if an element is re-inserted into the set.
|
||||||
|
//
|
||||||
|
// Structure is not thread safe.
|
||||||
|
//
|
||||||
|
// References: http://en.wikipedia.org/wiki/Set_%28abstract_data_type%29
|
||||||
|
package linkedhashset
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/emirpasic/gods/lists/doublylinkedlist"
|
||||||
|
"github.com/emirpasic/gods/sets"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func assertSetImplementation() {
|
||||||
|
var _ sets.Set = (*Set)(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set holds elements in go's native map
|
||||||
|
type Set struct {
|
||||||
|
items map[interface{}]struct{}
|
||||||
|
list *doublylinkedlist.List
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemExists = struct{}{}
|
||||||
|
|
||||||
|
// New instantiates a new empty set
|
||||||
|
func New() *Set {
|
||||||
|
return &Set{
|
||||||
|
items: make(map[interface{}]struct{}),
|
||||||
|
list: doublylinkedlist.New(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds the items (one or more) to the set.
|
||||||
|
// Note that insertion-order is not affected if an element is re-inserted into the set.
|
||||||
|
func (set *Set) Add(items ...interface{}) {
|
||||||
|
for _, item := range items {
|
||||||
|
|
||||||
|
if _, contains := set.items[item]; contains {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
set.items[item] = itemExists
|
||||||
|
set.list.Append(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove removes the items (one or more) from the set.
|
||||||
|
// Slow operation, worst-case O(n^2).
|
||||||
|
func (set *Set) Remove(items ...interface{}) {
|
||||||
|
for _, item := range items {
|
||||||
|
|
||||||
|
if _, contains := set.items[item]; !contains {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(set.items, item)
|
||||||
|
index := set.list.IndexOf(item)
|
||||||
|
set.list.Remove(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contains check if items (one or more) are present in the set.
|
||||||
|
// All items have to be present in the set for the method to return true.
|
||||||
|
// Returns true if no arguments are passed at all, i.e. set is always superset of empty set.
|
||||||
|
func (set *Set) Contains(items ...interface{}) bool {
|
||||||
|
for _, item := range items {
|
||||||
|
if _, contains := set.items[item]; !contains {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty returns true if set does not contain any elements.
|
||||||
|
func (set *Set) Empty() bool {
|
||||||
|
return set.Size() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns number of elements within the set.
|
||||||
|
func (set *Set) Size() int {
|
||||||
|
return set.list.Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear clears all values in the set.
|
||||||
|
func (set *Set) Clear() {
|
||||||
|
set.items = make(map[interface{}]struct{})
|
||||||
|
set.list.Clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Values returns all items in the set.
|
||||||
|
func (set *Set) Values() []interface{} {
|
||||||
|
values := make([]interface{}, set.Size())
|
||||||
|
it := set.Iterator()
|
||||||
|
for it.Next() {
|
||||||
|
values[it.Index()] = it.Value()
|
||||||
|
}
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string representation of container
|
||||||
|
func (set *Set) String() string {
|
||||||
|
str := "LinkedHashSet\n"
|
||||||
|
items := []string{}
|
||||||
|
it := set.Iterator()
|
||||||
|
for it.Next() {
|
||||||
|
items = append(items, fmt.Sprintf("%v", it.Value()))
|
||||||
|
}
|
||||||
|
str += strings.Join(items, ", ")
|
||||||
|
return str
|
||||||
|
}
|
498
sets/linkedhashset/linkedhashset_test.go
Normal file
498
sets/linkedhashset/linkedhashset_test.go
Normal file
@ -0,0 +1,498 @@
|
|||||||
|
// Copyright (c) 2015, Emir Pasic. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package linkedhashset
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSetAdd(t *testing.T) {
|
||||||
|
set := New()
|
||||||
|
set.Add()
|
||||||
|
set.Add(1)
|
||||||
|
set.Add(2)
|
||||||
|
set.Add(2, 3)
|
||||||
|
set.Add()
|
||||||
|
if actualValue := set.Empty(); actualValue != false {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, false)
|
||||||
|
}
|
||||||
|
if actualValue := set.Size(); actualValue != 3 {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetContains(t *testing.T) {
|
||||||
|
set := New()
|
||||||
|
set.Add(3, 1, 2)
|
||||||
|
set.Add(2, 3)
|
||||||
|
set.Add()
|
||||||
|
if actualValue := set.Contains(); actualValue != true {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, true)
|
||||||
|
}
|
||||||
|
if actualValue := set.Contains(1); actualValue != true {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, true)
|
||||||
|
}
|
||||||
|
if actualValue := set.Contains(1, 2, 3); actualValue != true {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, true)
|
||||||
|
}
|
||||||
|
if actualValue := set.Contains(1, 2, 3, 4); actualValue != false {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetRemove(t *testing.T) {
|
||||||
|
set := New()
|
||||||
|
set.Add(3, 1, 2)
|
||||||
|
set.Remove()
|
||||||
|
if actualValue := set.Size(); actualValue != 3 {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, 3)
|
||||||
|
}
|
||||||
|
set.Remove(1)
|
||||||
|
if actualValue := set.Size(); actualValue != 2 {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, 2)
|
||||||
|
}
|
||||||
|
set.Remove(3)
|
||||||
|
set.Remove(3)
|
||||||
|
set.Remove()
|
||||||
|
set.Remove(2)
|
||||||
|
if actualValue := set.Size(); actualValue != 0 {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetEach(t *testing.T) {
|
||||||
|
set := New()
|
||||||
|
set.Add("c", "a", "b")
|
||||||
|
set.Each(func(index int, value interface{}) {
|
||||||
|
switch index {
|
||||||
|
case 0:
|
||||||
|
if actualValue, expectedValue := value, "c"; actualValue != expectedValue {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, expectedValue)
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
if actualValue, expectedValue := value, "a"; actualValue != expectedValue {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, expectedValue)
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
if actualValue, expectedValue := value, "b"; actualValue != expectedValue {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, expectedValue)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Errorf("Too many")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetMap(t *testing.T) {
|
||||||
|
set := New()
|
||||||
|
set.Add("c", "a", "b")
|
||||||
|
mappedSet := set.Map(func(index int, value interface{}) interface{} {
|
||||||
|
return "mapped: " + value.(string)
|
||||||
|
})
|
||||||
|
if actualValue, expectedValue := mappedSet.Contains("mapped: c", "mapped: b", "mapped: a"), true; actualValue != expectedValue {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, expectedValue)
|
||||||
|
}
|
||||||
|
if actualValue, expectedValue := mappedSet.Contains("mapped: c", "mapped: b", "mapped: x"), false; actualValue != expectedValue {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, expectedValue)
|
||||||
|
}
|
||||||
|
if mappedSet.Size() != 3 {
|
||||||
|
t.Errorf("Got %v expected %v", mappedSet.Size(), 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetSelect(t *testing.T) {
|
||||||
|
set := New()
|
||||||
|
set.Add("c", "a", "b")
|
||||||
|
selectedSet := set.Select(func(index int, value interface{}) bool {
|
||||||
|
return value.(string) >= "a" && value.(string) <= "b"
|
||||||
|
})
|
||||||
|
if actualValue, expectedValue := selectedSet.Contains("a", "b"), true; actualValue != expectedValue {
|
||||||
|
fmt.Println("A: ", selectedSet.Contains("b"))
|
||||||
|
t.Errorf("Got %v (%v) expected %v (%v)", actualValue, selectedSet.Values(), expectedValue, "[a b]")
|
||||||
|
}
|
||||||
|
if actualValue, expectedValue := selectedSet.Contains("a", "b", "c"), false; actualValue != expectedValue {
|
||||||
|
t.Errorf("Got %v (%v) expected %v (%v)", actualValue, selectedSet.Values(), expectedValue, "[a b]")
|
||||||
|
}
|
||||||
|
if selectedSet.Size() != 2 {
|
||||||
|
t.Errorf("Got %v expected %v", selectedSet.Size(), 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetAny(t *testing.T) {
|
||||||
|
set := New()
|
||||||
|
set.Add("c", "a", "b")
|
||||||
|
any := set.Any(func(index int, value interface{}) bool {
|
||||||
|
return value.(string) == "c"
|
||||||
|
})
|
||||||
|
if any != true {
|
||||||
|
t.Errorf("Got %v expected %v", any, true)
|
||||||
|
}
|
||||||
|
any = set.Any(func(index int, value interface{}) bool {
|
||||||
|
return value.(string) == "x"
|
||||||
|
})
|
||||||
|
if any != false {
|
||||||
|
t.Errorf("Got %v expected %v", any, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetAll(t *testing.T) {
|
||||||
|
set := New()
|
||||||
|
set.Add("c", "a", "b")
|
||||||
|
all := set.All(func(index int, value interface{}) bool {
|
||||||
|
return value.(string) >= "a" && value.(string) <= "c"
|
||||||
|
})
|
||||||
|
if all != true {
|
||||||
|
t.Errorf("Got %v expected %v", all, true)
|
||||||
|
}
|
||||||
|
all = set.All(func(index int, value interface{}) bool {
|
||||||
|
return value.(string) >= "a" && value.(string) <= "b"
|
||||||
|
})
|
||||||
|
if all != false {
|
||||||
|
t.Errorf("Got %v expected %v", all, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetFind(t *testing.T) {
|
||||||
|
set := New()
|
||||||
|
set.Add("c", "a", "b")
|
||||||
|
foundIndex, foundValue := set.Find(func(index int, value interface{}) bool {
|
||||||
|
return value.(string) == "c"
|
||||||
|
})
|
||||||
|
if foundValue != "c" || foundIndex != 0 {
|
||||||
|
t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, "c", 0)
|
||||||
|
}
|
||||||
|
foundIndex, foundValue = set.Find(func(index int, value interface{}) bool {
|
||||||
|
return value.(string) == "x"
|
||||||
|
})
|
||||||
|
if foundValue != nil || foundIndex != -1 {
|
||||||
|
t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetChaining(t *testing.T) {
|
||||||
|
set := New()
|
||||||
|
set.Add("c", "a", "b")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetIteratorPrevOnEmpty(t *testing.T) {
|
||||||
|
set := New()
|
||||||
|
it := set.Iterator()
|
||||||
|
for it.Prev() {
|
||||||
|
t.Errorf("Shouldn't iterate on empty set")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetIteratorNext(t *testing.T) {
|
||||||
|
set := New()
|
||||||
|
set.Add("c", "a", "b")
|
||||||
|
it := set.Iterator()
|
||||||
|
count := 0
|
||||||
|
for it.Next() {
|
||||||
|
count++
|
||||||
|
index := it.Index()
|
||||||
|
value := it.Value()
|
||||||
|
switch index {
|
||||||
|
case 0:
|
||||||
|
if actualValue, expectedValue := value, "c"; actualValue != expectedValue {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, expectedValue)
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
if actualValue, expectedValue := value, "a"; actualValue != expectedValue {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, expectedValue)
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
if actualValue, expectedValue := value, "b"; actualValue != expectedValue {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, expectedValue)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Errorf("Too many")
|
||||||
|
}
|
||||||
|
if actualValue, expectedValue := index, count-1; actualValue != expectedValue {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, expectedValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if actualValue, expectedValue := count, 3; actualValue != expectedValue {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, expectedValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetIteratorPrev(t *testing.T) {
|
||||||
|
set := New()
|
||||||
|
set.Add("c", "a", "b")
|
||||||
|
it := set.Iterator()
|
||||||
|
for it.Prev() {
|
||||||
|
}
|
||||||
|
count := 0
|
||||||
|
for it.Next() {
|
||||||
|
count++
|
||||||
|
index := it.Index()
|
||||||
|
value := it.Value()
|
||||||
|
switch index {
|
||||||
|
case 0:
|
||||||
|
if actualValue, expectedValue := value, "c"; actualValue != expectedValue {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, expectedValue)
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
if actualValue, expectedValue := value, "a"; actualValue != expectedValue {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, expectedValue)
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
if actualValue, expectedValue := value, "b"; actualValue != expectedValue {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, expectedValue)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Errorf("Too many")
|
||||||
|
}
|
||||||
|
if actualValue, expectedValue := index, count-1; actualValue != expectedValue {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, expectedValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if actualValue, expectedValue := count, 3; actualValue != expectedValue {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, expectedValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetIteratorBegin(t *testing.T) {
|
||||||
|
set := New()
|
||||||
|
it := set.Iterator()
|
||||||
|
it.Begin()
|
||||||
|
set.Add("a", "b", "c")
|
||||||
|
for it.Next() {
|
||||||
|
}
|
||||||
|
it.Begin()
|
||||||
|
it.Next()
|
||||||
|
if index, value := it.Index(), it.Value(); index != 0 || value != "a" {
|
||||||
|
t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "a")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetIteratorEnd(t *testing.T) {
|
||||||
|
set := New()
|
||||||
|
it := set.Iterator()
|
||||||
|
|
||||||
|
if index := it.Index(); index != -1 {
|
||||||
|
t.Errorf("Got %v expected %v", index, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
it.End()
|
||||||
|
if index := it.Index(); index != 0 {
|
||||||
|
t.Errorf("Got %v expected %v", index, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
set.Add("a", "b", "c")
|
||||||
|
it.End()
|
||||||
|
if index := it.Index(); index != set.Size() {
|
||||||
|
t.Errorf("Got %v expected %v", index, set.Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
it.Prev()
|
||||||
|
if index, value := it.Index(), it.Value(); index != set.Size()-1 || value != "c" {
|
||||||
|
t.Errorf("Got %v,%v expected %v,%v", index, value, set.Size()-1, "c")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetIteratorFirst(t *testing.T) {
|
||||||
|
set := New()
|
||||||
|
set.Add("a", "b", "c")
|
||||||
|
it := set.Iterator()
|
||||||
|
if actualValue, expectedValue := it.First(), true; actualValue != expectedValue {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, expectedValue)
|
||||||
|
}
|
||||||
|
if index, value := it.Index(), it.Value(); index != 0 || value != "a" {
|
||||||
|
t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "a")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetIteratorLast(t *testing.T) {
|
||||||
|
set := New()
|
||||||
|
set.Add("a", "b", "c")
|
||||||
|
it := set.Iterator()
|
||||||
|
if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, expectedValue)
|
||||||
|
}
|
||||||
|
if index, value := it.Index(), it.Value(); index != 2 || value != "c" {
|
||||||
|
t.Errorf("Got %v,%v expected %v,%v", index, value, 3, "c")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetSerialization(t *testing.T) {
|
||||||
|
set := New()
|
||||||
|
set.Add("a", "b", "c")
|
||||||
|
|
||||||
|
var err error
|
||||||
|
assert := func() {
|
||||||
|
if actualValue, expectedValue := set.Size(), 3; actualValue != expectedValue {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, expectedValue)
|
||||||
|
}
|
||||||
|
if actualValue := set.Contains("a", "b", "c"); actualValue != true {
|
||||||
|
t.Errorf("Got %v expected %v", actualValue, true)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Got error %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert()
|
||||||
|
|
||||||
|
json, err := set.ToJSON()
|
||||||
|
assert()
|
||||||
|
|
||||||
|
err = set.FromJSON(json)
|
||||||
|
assert()
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkContains(b *testing.B, set *Set, size int) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
for n := 0; n < size; n++ {
|
||||||
|
set.Contains(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkAdd(b *testing.B, set *Set, size int) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
for n := 0; n < size; n++ {
|
||||||
|
set.Add(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkRemove(b *testing.B, set *Set, size int) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
for n := 0; n < size; n++ {
|
||||||
|
set.Remove(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkHashSetContains100(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
size := 100
|
||||||
|
set := New()
|
||||||
|
for n := 0; n < size; n++ {
|
||||||
|
set.Add(n)
|
||||||
|
}
|
||||||
|
b.StartTimer()
|
||||||
|
benchmarkContains(b, set, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkHashSetContains1000(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
size := 1000
|
||||||
|
set := New()
|
||||||
|
for n := 0; n < size; n++ {
|
||||||
|
set.Add(n)
|
||||||
|
}
|
||||||
|
b.StartTimer()
|
||||||
|
benchmarkContains(b, set, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkHashSetContains10000(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
size := 10000
|
||||||
|
set := New()
|
||||||
|
for n := 0; n < size; n++ {
|
||||||
|
set.Add(n)
|
||||||
|
}
|
||||||
|
b.StartTimer()
|
||||||
|
benchmarkContains(b, set, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkHashSetContains100000(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
size := 100000
|
||||||
|
set := New()
|
||||||
|
for n := 0; n < size; n++ {
|
||||||
|
set.Add(n)
|
||||||
|
}
|
||||||
|
b.StartTimer()
|
||||||
|
benchmarkContains(b, set, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkHashSetAdd100(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
size := 100
|
||||||
|
set := New()
|
||||||
|
b.StartTimer()
|
||||||
|
benchmarkAdd(b, set, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkHashSetAdd1000(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
size := 1000
|
||||||
|
set := New()
|
||||||
|
for n := 0; n < size; n++ {
|
||||||
|
set.Add(n)
|
||||||
|
}
|
||||||
|
b.StartTimer()
|
||||||
|
benchmarkAdd(b, set, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkHashSetAdd10000(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
size := 10000
|
||||||
|
set := New()
|
||||||
|
for n := 0; n < size; n++ {
|
||||||
|
set.Add(n)
|
||||||
|
}
|
||||||
|
b.StartTimer()
|
||||||
|
benchmarkAdd(b, set, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkHashSetAdd100000(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
size := 100000
|
||||||
|
set := New()
|
||||||
|
for n := 0; n < size; n++ {
|
||||||
|
set.Add(n)
|
||||||
|
}
|
||||||
|
b.StartTimer()
|
||||||
|
benchmarkAdd(b, set, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkHashSetRemove100(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
size := 100
|
||||||
|
set := New()
|
||||||
|
for n := 0; n < size; n++ {
|
||||||
|
set.Add(n)
|
||||||
|
}
|
||||||
|
b.StartTimer()
|
||||||
|
benchmarkRemove(b, set, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkHashSetRemove1000(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
size := 1000
|
||||||
|
set := New()
|
||||||
|
for n := 0; n < size; n++ {
|
||||||
|
set.Add(n)
|
||||||
|
}
|
||||||
|
b.StartTimer()
|
||||||
|
benchmarkRemove(b, set, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkHashSetRemove10000(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
size := 10000
|
||||||
|
set := New()
|
||||||
|
for n := 0; n < size; n++ {
|
||||||
|
set.Add(n)
|
||||||
|
}
|
||||||
|
b.StartTimer()
|
||||||
|
benchmarkRemove(b, set, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkHashSetRemove100000(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
size := 100000
|
||||||
|
set := New()
|
||||||
|
for n := 0; n < size; n++ {
|
||||||
|
set.Add(n)
|
||||||
|
}
|
||||||
|
b.StartTimer()
|
||||||
|
benchmarkRemove(b, set, size)
|
||||||
|
}
|
31
sets/linkedhashset/serialization.go
Normal file
31
sets/linkedhashset/serialization.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// Copyright (c) 2015, Emir Pasic. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package linkedhashset
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/emirpasic/gods/containers"
|
||||||
|
)
|
||||||
|
|
||||||
|
func assertSerializationImplementation() {
|
||||||
|
var _ containers.JSONSerializer = (*Set)(nil)
|
||||||
|
var _ containers.JSONDeserializer = (*Set)(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToJSON outputs the JSON representation of list's elements.
|
||||||
|
func (set *Set) ToJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(set.Values())
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromJSON populates list's elements from the input JSON representation.
|
||||||
|
func (set *Set) FromJSON(data []byte) error {
|
||||||
|
elements := []interface{}{}
|
||||||
|
err := json.Unmarshal(data, &elements)
|
||||||
|
if err == nil {
|
||||||
|
set.Clear()
|
||||||
|
set.Add(elements...)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user