From 8dab13c925024f329b774c80a33a11f08b427387 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 23 Mar 2016 05:40:01 +0100 Subject: [PATCH 001/320] - expose the root of the red-black tree to allow custom tree traversal --- trees/redblacktree/redblacktree.go | 282 ++++++++++++++--------------- 1 file changed, 141 insertions(+), 141 deletions(-) diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 42a85534..6e527fe9 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -49,18 +49,18 @@ const ( ) type Tree struct { - root *node + Root *Node size int comparator utils.Comparator } -type node struct { - key interface{} - value interface{} +type Node struct { + Key interface{} + Value interface{} color color - left *node - right *node - parent *node + Left *Node + Right *Node + Parent *Node } // Instantiates a red-black tree with the custom comparator. @@ -81,35 +81,35 @@ func NewWithStringComparator() *Tree { // Inserts node into the tree. // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree) Put(key interface{}, value interface{}) { - insertedNode := &node{key: key, value: value, color: red} - if tree.root == nil { - tree.root = insertedNode + insertedNode := &Node{Key: key, Value: value, color: red} + if tree.Root == nil { + tree.Root = insertedNode } else { - node := tree.root + node := tree.Root loop := true for loop { - compare := tree.comparator(key, node.key) + compare := tree.comparator(key, node.Key) switch { case compare == 0: - node.value = value + node.Value = value return case compare < 0: - if node.left == nil { - node.left = insertedNode + if node.Left == nil { + node.Left = insertedNode loop = false } else { - node = node.left + node = node.Left } case compare > 0: - if node.right == nil { - node.right = insertedNode + if node.Right == nil { + node.Right = insertedNode loop = false } else { - node = node.right + node = node.Right } } } - insertedNode.parent = node + insertedNode.Parent = node } tree.insertCase1(insertedNode) tree.size += 1 @@ -121,7 +121,7 @@ func (tree *Tree) Put(key interface{}, value interface{}) { func (tree *Tree) Get(key interface{}) (value interface{}, found bool) { node := tree.lookup(key) if node != nil { - return node.value, true + return node.Value, true } return nil, false } @@ -129,29 +129,29 @@ func (tree *Tree) Get(key interface{}) (value interface{}, found bool) { // Remove the node from the tree by key. // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree) Remove(key interface{}) { - var child *node + var child *Node node := tree.lookup(key) if node == nil { return } - if node.left != nil && node.right != nil { - pred := node.left.maximumNode() - node.key = pred.key - node.value = pred.value + if node.Left != nil && node.Right != nil { + pred := node.Left.maximumNode() + node.Key = pred.Key + node.Value = pred.Value node = pred } - if node.left == nil || node.right == nil { - if node.right == nil { - child = node.left + if node.Left == nil || node.Right == nil { + if node.Right == nil { + child = node.Left } else { - child = node.right + child = node.Right } if node.color == black { node.color = nodeColor(child) tree.deleteCase1(node) } tree.replaceNode(node, child) - if node.parent == nil && child != nil { + if node.Parent == nil && child != nil { child.color = black } } @@ -172,7 +172,7 @@ func (tree *Tree) Size() int { func (tree *Tree) Keys() []interface{} { keys := make([]interface{}, tree.size) for i, node := range tree.inOrder() { - keys[i] = node.key + keys[i] = node.Key } return keys } @@ -181,48 +181,48 @@ func (tree *Tree) Keys() []interface{} { func (tree *Tree) Values() []interface{} { values := make([]interface{}, tree.size) for i, node := range tree.inOrder() { - values[i] = node.value + values[i] = node.Value } return values } // Removes all nodes from the tree. func (tree *Tree) Clear() { - tree.root = nil + tree.Root = nil tree.size = 0 } func (tree *Tree) String() string { str := "RedBlackTree\n" if !tree.Empty() { - output(tree.root, "", true, &str) + output(tree.Root, "", true, &str) } return str } -func (node *node) String() string { - return fmt.Sprintf("%v", node.key) +func (node *Node) String() string { + return fmt.Sprintf("%v", node.Key) } // Returns all nodes in order -func (tree *Tree) inOrder() []*node { - nodes := make([]*node, tree.size) +func (tree *Tree) inOrder() []*Node { + nodes := make([]*Node, tree.size) if tree.size > 0 { - current := tree.root + current := tree.Root stack := linkedliststack.New() done := false count := 0 for !done { if current != nil { stack.Push(current) - current = current.left + current = current.Left } else { if !stack.Empty() { currentPop, _ := stack.Pop() - current = currentPop.(*node) + current = currentPop.(*Node) nodes[count] = current count += 1 - current = current.right + current = current.Right } else { done = true } @@ -232,15 +232,15 @@ func (tree *Tree) inOrder() []*node { return nodes } -func output(node *node, prefix string, isTail bool, str *string) { - if node.right != nil { +func output(node *Node, prefix string, isTail bool, str *string) { + if node.Right != nil { newPrefix := prefix if isTail { newPrefix += "│ " } else { newPrefix += " " } - output(node.right, newPrefix, false, str) + output(node.Right, newPrefix, false, str) } *str += prefix if isTail { @@ -249,114 +249,114 @@ func output(node *node, prefix string, isTail bool, str *string) { *str += "┌── " } *str += node.String() + "\n" - if node.left != nil { + if node.Left != nil { newPrefix := prefix if isTail { newPrefix += " " } else { newPrefix += "│ " } - output(node.left, newPrefix, true, str) + output(node.Left, newPrefix, true, str) } } -func (tree *Tree) lookup(key interface{}) *node { - node := tree.root +func (tree *Tree) lookup(key interface{}) *Node { + node := tree.Root for node != nil { - compare := tree.comparator(key, node.key) + compare := tree.comparator(key, node.Key) switch { case compare == 0: return node case compare < 0: - node = node.left + node = node.Left case compare > 0: - node = node.right + node = node.Right } } return nil } -func (node *node) grandparent() *node { - if node != nil && node.parent != nil { - return node.parent.parent +func (node *Node) grandparent() *Node { + if node != nil && node.Parent != nil { + return node.Parent.Parent } return nil } -func (node *node) uncle() *node { - if node == nil || node.parent == nil || node.parent.parent == nil { +func (node *Node) uncle() *Node { + if node == nil || node.Parent == nil || node.Parent.Parent == nil { return nil } - return node.parent.sibling() + return node.Parent.sibling() } -func (node *node) sibling() *node { - if node == nil || node.parent == nil { +func (node *Node) sibling() *Node { + if node == nil || node.Parent == nil { return nil } - if node == node.parent.left { - return node.parent.right + if node == node.Parent.Left { + return node.Parent.Right } else { - return node.parent.left + return node.Parent.Left } } -func (tree *Tree) rotateLeft(node *node) { - right := node.right +func (tree *Tree) rotateLeft(node *Node) { + right := node.Right tree.replaceNode(node, right) - node.right = right.left - if right.left != nil { - right.left.parent = node + node.Right = right.Left + if right.Left != nil { + right.Left.Parent = node } - right.left = node - node.parent = right + right.Left = node + node.Parent = right } -func (tree *Tree) rotateRight(node *node) { - left := node.left +func (tree *Tree) rotateRight(node *Node) { + left := node.Left tree.replaceNode(node, left) - node.left = left.right - if left.right != nil { - left.right.parent = node + node.Left = left.Right + if left.Right != nil { + left.Right.Parent = node } - left.right = node - node.parent = left + left.Right = node + node.Parent = left } -func (tree *Tree) replaceNode(old *node, new *node) { - if old.parent == nil { - tree.root = new +func (tree *Tree) replaceNode(old *Node, new *Node) { + if old.Parent == nil { + tree.Root = new } else { - if old == old.parent.left { - old.parent.left = new + if old == old.Parent.Left { + old.Parent.Left = new } else { - old.parent.right = new + old.Parent.Right = new } } if new != nil { - new.parent = old.parent + new.Parent = old.Parent } } -func (tree *Tree) insertCase1(node *node) { - if node.parent == nil { +func (tree *Tree) insertCase1(node *Node) { + if node.Parent == nil { node.color = black } else { tree.insertCase2(node) } } -func (tree *Tree) insertCase2(node *node) { - if nodeColor(node.parent) == black { +func (tree *Tree) insertCase2(node *Node) { + if nodeColor(node.Parent) == black { return } tree.insertCase3(node) } -func (tree *Tree) insertCase3(node *node) { +func (tree *Tree) insertCase3(node *Node) { uncle := node.uncle() if nodeColor(uncle) == red { - node.parent.color = black + node.Parent.color = black uncle.color = black node.grandparent().color = red tree.insertCase1(node.grandparent()) @@ -365,121 +365,121 @@ func (tree *Tree) insertCase3(node *node) { } } -func (tree *Tree) insertCase4(node *node) { +func (tree *Tree) insertCase4(node *Node) { grandparent := node.grandparent() - if node == node.parent.right && node.parent == grandparent.left { - tree.rotateLeft(node.parent) - node = node.left - } else if node == node.parent.left && node.parent == grandparent.right { - tree.rotateRight(node.parent) - node = node.right + if node == node.Parent.Right && node.Parent == grandparent.Left { + tree.rotateLeft(node.Parent) + node = node.Left + } else if node == node.Parent.Left && node.Parent == grandparent.Right { + tree.rotateRight(node.Parent) + node = node.Right } tree.insertCase5(node) } -func (tree *Tree) insertCase5(node *node) { - node.parent.color = black +func (tree *Tree) insertCase5(node *Node) { + node.Parent.color = black grandparent := node.grandparent() grandparent.color = red - if node == node.parent.left && node.parent == grandparent.left { + if node == node.Parent.Left && node.Parent == grandparent.Left { tree.rotateRight(grandparent) - } else if node == node.parent.right && node.parent == grandparent.right { + } else if node == node.Parent.Right && node.Parent == grandparent.Right { tree.rotateLeft(grandparent) } } -func (node *node) maximumNode() *node { +func (node *Node) maximumNode() *Node { if node == nil { return nil } - for node.right != nil { - node = node.right + for node.Right != nil { + node = node.Right } return node } -func (tree *Tree) deleteCase1(node *node) { - if node.parent == nil { +func (tree *Tree) deleteCase1(node *Node) { + if node.Parent == nil { return } else { tree.deleteCase2(node) } } -func (tree *Tree) deleteCase2(node *node) { +func (tree *Tree) deleteCase2(node *Node) { sibling := node.sibling() if nodeColor(sibling) == red { - node.parent.color = red + node.Parent.color = red sibling.color = black - if node == node.parent.left { - tree.rotateLeft(node.parent) + if node == node.Parent.Left { + tree.rotateLeft(node.Parent) } else { - tree.rotateRight(node.parent) + tree.rotateRight(node.Parent) } } tree.deleteCase3(node) } -func (tree *Tree) deleteCase3(node *node) { +func (tree *Tree) deleteCase3(node *Node) { sibling := node.sibling() - if nodeColor(node.parent) == black && + if nodeColor(node.Parent) == black && nodeColor(sibling) == black && - nodeColor(sibling.left) == black && - nodeColor(sibling.right) == black { + nodeColor(sibling.Left) == black && + nodeColor(sibling.Right) == black { sibling.color = red - tree.deleteCase1(node.parent) + tree.deleteCase1(node.Parent) } else { tree.deleteCase4(node) } } -func (tree *Tree) deleteCase4(node *node) { +func (tree *Tree) deleteCase4(node *Node) { sibling := node.sibling() - if nodeColor(node.parent) == red && + if nodeColor(node.Parent) == red && nodeColor(sibling) == black && - nodeColor(sibling.left) == black && - nodeColor(sibling.right) == black { + nodeColor(sibling.Left) == black && + nodeColor(sibling.Right) == black { sibling.color = red - node.parent.color = black + node.Parent.color = black } else { tree.deleteCase5(node) } } -func (tree *Tree) deleteCase5(node *node) { +func (tree *Tree) deleteCase5(node *Node) { sibling := node.sibling() - if node == node.parent.left && + if node == node.Parent.Left && nodeColor(sibling) == black && - nodeColor(sibling.left) == red && - nodeColor(sibling.right) == black { + nodeColor(sibling.Left) == red && + nodeColor(sibling.Right) == black { sibling.color = red - sibling.left.color = black + sibling.Left.color = black tree.rotateRight(sibling) - } else if node == node.parent.right && + } else if node == node.Parent.Right && nodeColor(sibling) == black && - nodeColor(sibling.right) == red && - nodeColor(sibling.left) == black { + nodeColor(sibling.Right) == red && + nodeColor(sibling.Left) == black { sibling.color = red - sibling.right.color = black + sibling.Right.color = black tree.rotateLeft(sibling) } tree.deleteCase6(node) } -func (tree *Tree) deleteCase6(node *node) { +func (tree *Tree) deleteCase6(node *Node) { sibling := node.sibling() - sibling.color = nodeColor(node.parent) - node.parent.color = black - if node == node.parent.left && nodeColor(sibling.right) == red { - sibling.right.color = black - tree.rotateLeft(node.parent) - } else if nodeColor(sibling.left) == red { - sibling.left.color = black - tree.rotateRight(node.parent) + sibling.color = nodeColor(node.Parent) + node.Parent.color = black + if node == node.Parent.Left && nodeColor(sibling.Right) == red { + sibling.Right.color = black + tree.rotateLeft(node.Parent) + } else if nodeColor(sibling.Left) == red { + sibling.Left.color = black + tree.rotateRight(node.Parent) } } -func nodeColor(node *node) color { +func nodeColor(node *Node) color { if node == nil { return black } From 87ab028182a904fcf9bd7d79cdf605aafb82841c Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 23 Mar 2016 06:22:23 +0100 Subject: [PATCH 002/320] - update documentation to account for changes in the red-black tree (exposing root) --- README.md | 65 ++++++--------- examples/redblacktree.go | 12 +-- examples/redblacktreeextended.go | 135 +++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+), 46 deletions(-) create mode 100644 examples/redblacktreeextended.go diff --git a/README.md b/README.md index ff6ad5bd..b26838cf 100644 --- a/README.md +++ b/README.md @@ -39,19 +39,18 @@ type Interface interface { Clear() Values() []interface{} } - ``` Container specific operations: ```go -// Returns sorted container's elements with respect to the passed comparator. +// Returns sorted container's elements with respect to the passed comparator. // Does not effect the ordering of elements within the container. // Uses timsort. func GetSortedValues(container Interface, comparator utils.Comparator) []interface{} { ``` -####Sets +####Sets A set is a data structure that can store elements and no repeated values. It is a computer implementation of the mathematical concept of a finite set. Unlike most other collection types, rather than retrieving a specific element from a set, one typically tests an element for membership in a set. This structed is often used to ensure that no duplicates are present in a collection. @@ -96,8 +95,6 @@ func main() { set.Empty() // true set.Size() // 0 } - - ``` #####TreeSet @@ -125,7 +122,6 @@ func main() { set.Empty() // true set.Size() // 0 } - ``` ####Lists @@ -220,8 +216,6 @@ func main() { list.Add("a") // ["a"] list.Clear() // [] } - - ``` #####DoublyLinkedList @@ -257,8 +251,6 @@ func main() { list.Add("a") // ["a"] list.Clear() // [] } - - ``` @@ -279,14 +271,13 @@ type Interface interface { // Clear() // Values() []interface{} } - ``` #####LinkedListStack -This stack structure is based on a linked list, i.e. each previous element has a point to the next. +This stack structure is based on a linked list, i.e. each previous element has a point to the next. -All operations are guaranted constant time performance, except _Values()_, which is as always of linear time performance. +All operations are guaranteed constant time performance, except _Values()_, which is as always of linear time performance. ```go package main @@ -307,7 +298,6 @@ func main() { stack.Empty() // true stack.Size() // 0 } - ``` #####ArrayStack @@ -335,8 +325,6 @@ func main() { stack.Empty() // true stack.Size() // 0 } - - ``` ####Maps @@ -361,7 +349,7 @@ type Interface interface { #####HashMap -Map structure based on hash tables, more exactly, Go's map. Keys are unordered. +Map structure based on hash tables, more exactly, Go's map. Keys are unordered. All operations are guaranted constant time performance, except _Key()_ and _Values()_ retrieval that of linear time performance. @@ -384,12 +372,11 @@ func main() { m.Empty() // true m.Size() // 0 } - ``` #####TreeMap -Map structure based on our red-black tree implementation. Keys are ordered with respect to the passed comparator. +Map structure based on our red-black tree implementation. Keys are ordered with respect to the passed comparator. _Put()_, _Get()_ and _Remove()_ are guaranteed log(n) time performance. @@ -414,8 +401,6 @@ func main() { m.Empty() // true m.Size() // 0 } - - ``` ####Trees @@ -432,7 +417,7 @@ type Interface interface { // Values() []interface{} } ``` - + #####RedBlackTree A red–black tree is a binary search tree with an extra bit of data per node, its color, which can be either red or black. The extra bit of storage ensures an approximately balanced tree by constraining how nodes are colored from any path from the root to the leaf. Thus, it is a data structure which is a type of self-balancing binary search tree. @@ -487,9 +472,10 @@ func main() { tree.Empty() // true tree.Size() // 0 } - ``` +Extending the red-black tree's functionality has been demonstrated in the following [example](https://github.com/emirpasic/gods/blob/master/examples/redblacktreeextended.go). + #####BinaryHeap A binary heap is a heap data structure created using a binary tree. It can be seen as a binary tree with two additional constraints: @@ -558,7 +544,7 @@ Return values: -1, if a < b 0, if a == b 1, if a > b - + Comparator signature: type Comparator func(a, b interface{}) int @@ -640,13 +626,13 @@ func byID(a, b interface{}) int { } func main() { - set := treeset.NewWith(byID) + set := treeset.NewWith(byID) set.Add(User{2, "Second"}) set.Add(User{3, "Third"}) set.Add(User{1, "First"}) set.Add(User{4, "Fourth"}) - + fmt.Println(set) // {1 First}, {2 Second}, {3 Third}, {4 Fourth} } ``` @@ -670,38 +656,37 @@ func main() { strings = append(strings, "c") // ["d","a",b","c"] utils.Sort(strings, utils.StringComparator) // ["a","b","c","d"] } - ``` ## Motivations -Collections and data structures found in other languages: Java Collections, C++ Standard Template Library (STL) containers, Qt Containers, etc. +Collections and data structures found in other languages: Java Collections, C++ Standard Template Library (STL) containers, Qt Containers, etc. ## Goals -**Fast algorithms**: +**Fast algorithms**: - Based on decades of knowledge and experiences of other libraries mentioned above. -**Memory efficient algorithms**: - +**Memory efficient algorithms**: + - Avoiding to consume memory by using optimal algorithms and data structures for the given set of problems, e.g. red-black tree in case of TreeMap to avoid keeping redundant sorted array of keys in memory. -**Easy to use library**: - - - Well-structued library with minimalistic set of atomic operations from which more complex operations can be crafted. +**Easy to use library**: + + - Well-structured library with minimalistic set of atomic operations from which more complex operations can be crafted. + +**Stable library**: -**Stable library**: - - Only additions are permitted keeping the library backward compatible. -**Solid documentation and examples**: - +**Solid documentation and examples**: + - Learning by example. -**Production ready**: +**Production ready**: - - Still waiting for the project to mature and be used in some heavy back-end tasks. + - Used in production. There is often a tug of war between speed and memory when crafting algorithms. We choose to optimize for speed in most cases within reasonable limits on memory consumption. diff --git a/examples/redblacktree.go b/examples/redblacktree.go index a5c54ec8..8dab4a6d 100644 --- a/examples/redblacktree.go +++ b/examples/redblacktree.go @@ -31,7 +31,7 @@ import ( rbt "github.com/emirpasic/gods/trees/redblacktree" ) -func RedBlacTtreeExample() { +func RedBlackTreeExample() { tree := rbt.NewWithIntComparator() // empty(keys are of type int) tree.Put(1, "x") // 1->x @@ -46,11 +46,11 @@ func RedBlacTtreeExample() { // // RedBlackTree // │ ┌── 6 - // │ ┌── 5 - // │ ┌── 4 - // │ │ └── 3 - // └── 2 - // └── 1 + // │ ┌── 5 + // │ ┌── 4 + // │ │ └── 3 + // └── 2 + // └── 1 _ = tree.Values() // []interface {}{"a", "b", "c", "d", "e", "f"} (in order) _ = tree.Keys() // []interface {}{1, 2, 3, 4, 5, 6} (in order) diff --git a/examples/redblacktreeextended.go b/examples/redblacktreeextended.go new file mode 100644 index 00000000..fbb8d6cc --- /dev/null +++ b/examples/redblacktreeextended.go @@ -0,0 +1,135 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package examples + +import ( + "fmt" + rbt "github.com/emirpasic/gods/trees/redblacktree" +) + +type RedBlackTreeExtended struct { + *rbt.Tree +} + +func (tree *RedBlackTreeExtended) GetMin() (value interface{}, found bool) { + node, found := tree.getMinFromNode(tree.Root) + if node != nil { + return node.Value, found + } else { + return nil, false + } +} + +func (tree *RedBlackTreeExtended) GetMax() (value interface{}, found bool) { + node, found := tree.getMaxFromNode(tree.Root) + if node != nil { + return node.Value, found + } else { + return nil, false + } +} + +func (tree *RedBlackTreeExtended) RemoveMin() (value interface{}, deleted bool) { + node, found := tree.getMinFromNode(tree.Root) + if found { + tree.Remove(node.Key) + return node.Value, found + } else { + return nil, false + } +} + +func (tree *RedBlackTreeExtended) RemoveMax() (value interface{}, deleted bool) { + node, found := tree.getMaxFromNode(tree.Root) + if found { + tree.Remove(node.Key) + return node.Value, found + } else { + return nil, false + } +} + +func (tree *RedBlackTreeExtended) getMinFromNode(node *rbt.Node) (foundNode *rbt.Node, found bool) { + if node == nil { + return nil, false + } + if node.Left == nil { + return node, true + } else { + return tree.getMinFromNode(node.Left) + } +} + +func (tree *RedBlackTreeExtended) getMaxFromNode(node *rbt.Node) (foundNode *rbt.Node, found bool) { + if node == nil { + return nil, false + } + if node.Right == nil { + return node, true + } else { + return tree.getMaxFromNode(node.Right) + } +} + +func print(tree *RedBlackTreeExtended) { + max, _ := tree.GetMax() + min, _ := tree.GetMin() + fmt.Printf("Value for max key: %v \n", max) + fmt.Printf("Value for min key: %v \n", min) + fmt.Println(tree) +} + +func RedBlackTreeExtendedExample() { + tree := RedBlackTreeExtended{rbt.NewWithIntComparator()} + + tree.Put(1, "a") // 1->x (in order) + tree.Put(2, "b") // 1->x, 2->b (in order) + tree.Put(3, "c") // 1->x, 2->b, 3->c (in order) + tree.Put(4, "d") // 1->x, 2->b, 3->c, 4->d (in order) + tree.Put(5, "e") // 1->x, 2->b, 3->c, 4->d, 5->e (in order) + + print(&tree) + // Value for max key: e + // Value for min key: a + // RedBlackTree + // │ ┌── 5 + // │ ┌── 4 + // │ │ └── 3 + // └── 2 + // └── 1 + + tree.RemoveMin() // 2->b, 3->c, 4->d, 5->e (in order) + tree.RemoveMax() // 2->b, 3->c, 4->d (in order) + tree.RemoveMin() // 3->c, 4->d (in order) + tree.RemoveMax() // 3->c (in order) + + print(&tree) + // Value for max key: c + // Value for min key: c + // RedBlackTree + // └── 3 +} From f7f48e7628930320e2807238c48776e495dcab77 Mon Sep 17 00:00:00 2001 From: otnt Date: Sun, 27 Mar 2016 01:51:09 -0400 Subject: [PATCH 003/320] add ceiling and floor function to redblacktree --- trees/redblacktree/redblacktree.go | 60 ++++++++++++++++++++++- trees/redblacktree/redblacktree_test.go | 64 +++++++++++++++++++++++++ 2 files changed, 123 insertions(+), 1 deletion(-) diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 6e527fe9..fd73c8a0 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -116,7 +116,7 @@ func (tree *Tree) Put(key interface{}, value interface{}) { } // Searches the node in the tree by key and returns its value or nil if key is not found in tree. -// Second return parameter is true if key was found, otherwise false. +// return parameter is true if key was found, otherwise false. // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree) Get(key interface{}) (value interface{}, found bool) { node := tree.lookup(key) @@ -126,6 +126,64 @@ func (tree *Tree) Get(key interface{}) (value interface{}, found bool) { return nil, false } +// Find ceiling node of the input key, return its key and value or nil if no ceiling is found. +// Third return parameter is true if ceiling was found, otherwise false. +// Ceiling node is defined as the smallest node that is larger than or equal to the given node. +// A ceiling node may not be found, either because the tree is empty, or because +// all nodes in the tree is smaller than the given node. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (tree *Tree) Ceiling(key interface{}) (ceilingKey interface{}, value interface{}, found bool) { + ceiling := &Node{} + found = false + + node := tree.Root + for node != nil { + compare := tree.comparator(key, node.Key) + switch { + case compare == 0: + return node.Key, node.Value, true + case compare < 0: + ceiling, found = node, true + node = node.Left + case compare > 0: + node = node.Right + } + } + if found { + return ceiling.Key, ceiling.Value, true + } + return nil, nil, false +} + +// Find floor node of the input key, return its key and value or nil if no ceiling is found. +// Third return parameter is true if floor was found, otherwise false. +// Floor node is defined as the largest node that is smaller than or equal to the given node. +// A floor node may not be found, either because the tree is empty, or because +// all nodes in the tree is larger than the given node. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (tree *Tree) Floor(key interface{}) (floorKey interface{}, value interface{}, found bool) { + floor := &Node{} + found = false + + node := tree.Root + for node != nil { + compare := tree.comparator(key, node.Key) + switch { + case compare == 0: + return node.Key, node.Value, true + case compare < 0: + node = node.Left + case compare > 0: + floor, found = node, true + node = node.Right + } + } + if found { + return floor.Key, floor.Value, true + } + return nil, nil, false +} + // Remove the node from the tree by key. // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree) Remove(key interface{}) { diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 58fe60fe..af2f3366 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -160,6 +160,70 @@ func TestRedBlackTree(t *testing.T) { } +func TestCeiling(t *testing.T) { + + tree := NewWithIntComparator() + + //key-value to insert + tree.Put(1, "a") + tree.Put(2, "b") + tree.Put(4, "d") + tree.Put(6, "f") + tree.Put(7, "g") + + //ceiling map + ceilingMap := [][]interface{}{ + {0, 1, true}, + {1, 1, true}, + {2, 2, true}, + {3, 4, true}, + {4, 4, true}, + {5, 6, true}, + {6, 6, true}, + {7, 7, true}, + {8, nil, false}, + } + for _, test := range ceilingMap { + actualKey, _, actualFound := tree.Ceiling(test[0]) + if actualKey != test[1] || actualFound != test[2] { + t.Errorf("Got (%v, %v) expected (%v, %v)", + actualKey, actualFound, test[1], test[2]) + } + } +} + +func TestFloor(t *testing.T) { + + tree := NewWithIntComparator() + + //key-value to insert + tree.Put(1, "a") + tree.Put(2, "b") + tree.Put(4, "d") + tree.Put(6, "f") + tree.Put(7, "g") + + //ceiling map + ceilingMap := [][]interface{}{ + {0, nil, false}, + {1, 1, true}, + {2, 2, true}, + {3, 2, true}, + {4, 4, true}, + {5, 4, true}, + {6, 6, true}, + {7, 7, true}, + {8, 7, true}, + } + for _, test := range ceilingMap { + actualKey, _, actualFound := tree.Floor(test[0]) + if actualKey != test[1] || actualFound != test[2] { + t.Errorf("Got (%v, %v) expected (%v, %v)", + actualKey, actualFound, test[1], test[2]) + } + } +} + func BenchmarkRedBlackTree(b *testing.B) { for i := 0; i < b.N; i++ { tree := NewWithIntComparator() From 9ad5e914f65d42d39a11273259993ebf54f24d7f Mon Sep 17 00:00:00 2001 From: otnt Date: Sun, 27 Mar 2016 01:53:17 -0400 Subject: [PATCH 004/320] modify comment --- trees/redblacktree/redblacktree.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index fd73c8a0..4ef4d140 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -116,7 +116,7 @@ func (tree *Tree) Put(key interface{}, value interface{}) { } // Searches the node in the tree by key and returns its value or nil if key is not found in tree. -// return parameter is true if key was found, otherwise false. +// Second return parameter is true if key was found, otherwise false. // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree) Get(key interface{}) (value interface{}, found bool) { node := tree.lookup(key) From a8ae25bd2edfa6bb72c3bd875dd8467c2c3870b0 Mon Sep 17 00:00:00 2001 From: OTNT Date: Sun, 27 Mar 2016 01:58:45 -0400 Subject: [PATCH 005/320] Update redblacktree_test.go Fix name mismatch. --- trees/redblacktree/redblacktree_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index af2f3366..0f77f41e 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -203,8 +203,8 @@ func TestFloor(t *testing.T) { tree.Put(6, "f") tree.Put(7, "g") - //ceiling map - ceilingMap := [][]interface{}{ + //floor map + floorMap := [][]interface{}{ {0, nil, false}, {1, 1, true}, {2, 2, true}, @@ -215,7 +215,7 @@ func TestFloor(t *testing.T) { {7, 7, true}, {8, 7, true}, } - for _, test := range ceilingMap { + for _, test := range floorMap { actualKey, _, actualFound := tree.Floor(test[0]) if actualKey != test[1] || actualFound != test[2] { t.Errorf("Got (%v, %v) expected (%v, %v)", From 5b1fc475815e87a99b1c401a6d8ad947ec1c5285 Mon Sep 17 00:00:00 2001 From: otnt Date: Sun, 27 Mar 2016 21:42:00 -0400 Subject: [PATCH 006/320] move Ceiling and Floor function to redblacktreeextend --- examples/redblacktreeextended.go | 88 +++++++++++++++++++++++++ trees/redblacktree/redblacktree.go | 63 ++---------------- trees/redblacktree/redblacktree_test.go | 64 ------------------ 3 files changed, 93 insertions(+), 122 deletions(-) diff --git a/examples/redblacktreeextended.go b/examples/redblacktreeextended.go index fbb8d6cc..df148f3d 100644 --- a/examples/redblacktreeextended.go +++ b/examples/redblacktreeextended.go @@ -103,6 +103,66 @@ func print(tree *RedBlackTreeExtended) { fmt.Println(tree) } +// Find ceiling node of the input key, return its key and value or nil if no ceiling is found. +// Third return parameter is true if ceiling was found, otherwise false. +// Ceiling node is defined as the smallest node that is larger than or equal to the given node. +// A ceiling node may not be found, either because the tree is empty, or because +// all nodes in the tree is smaller than the given node. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (tree *RedBlackTreeExtended) Ceiling(key interface{}) (ceilingKey interface{}, value interface{}, found bool) { + var ceiling *rbt.Node + found = false + comparator := tree.Comparator() + + node := tree.Root + for node != nil { + compare := comparator(key, node.Key) + switch { + case compare == 0: + return node.Key, node.Value, true + case compare < 0: + ceiling, found = node, true + node = node.Left + case compare > 0: + node = node.Right + } + } + if found { + return ceiling.Key, ceiling.Value, true + } + return nil, nil, false +} + +// Find floor node of the input key, return its key and value or nil if no ceiling is found. +// Third return parameter is true if floor was found, otherwise false. +// Floor node is defined as the largest node that is smaller than or equal to the given node. +// A floor node may not be found, either because the tree is empty, or because +// all nodes in the tree is larger than the given node. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (tree *RedBlackTreeExtended) Floor(key interface{}) (floorKey interface{}, value interface{}, found bool) { + var floor *rbt.Node + found = false + comparator := tree.Comparator() + + node := tree.Root + for node != nil { + compare := comparator(key, node.Key) + switch { + case compare == 0: + return node.Key, node.Value, true + case compare < 0: + node = node.Left + case compare > 0: + floor, found = node, true + node = node.Right + } + } + if found { + return floor.Key, floor.Value, true + } + return nil, nil, false +} + func RedBlackTreeExtendedExample() { tree := RedBlackTreeExtended{rbt.NewWithIntComparator()} @@ -132,4 +192,32 @@ func RedBlackTreeExtendedExample() { // Value for min key: c // RedBlackTree // └── 3 + + /* + * Ceiling and Floor functions + */ + tree = RedBlackTreeExtended{rbt.NewWithIntComparator()} + tree.Put(1, "a") + tree.Put(2, "b") + tree.Put(4, "d") + tree.Put(6, "f") + tree.Put(7, "g") + + //index, ceiling, floor + testValues := [][]interface{}{ + {0, 1, nil}, + {1, 1, 1}, + {2, 2, 2}, + {3, 4, 2}, + {4, 4, 4}, + {5, 6, 4}, + {6, 6, 6}, + {7, 7, 7}, + {8, nil, 7}, + } + for _, tt := range testValues { + actualCeiling, _, _ := tree.Ceiling(tt[0]) + actualFloor, _, _ := tree.Floor(tt[0]) + fmt.Printf("test key %d, expected (%d, %d), actual (%d, %d)\n", tt[0], tt[1], tt[2], actualCeiling, actualFloor) + } } diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 4ef4d140..fe56a6cf 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -126,64 +126,6 @@ func (tree *Tree) Get(key interface{}) (value interface{}, found bool) { return nil, false } -// Find ceiling node of the input key, return its key and value or nil if no ceiling is found. -// Third return parameter is true if ceiling was found, otherwise false. -// Ceiling node is defined as the smallest node that is larger than or equal to the given node. -// A ceiling node may not be found, either because the tree is empty, or because -// all nodes in the tree is smaller than the given node. -// Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *Tree) Ceiling(key interface{}) (ceilingKey interface{}, value interface{}, found bool) { - ceiling := &Node{} - found = false - - node := tree.Root - for node != nil { - compare := tree.comparator(key, node.Key) - switch { - case compare == 0: - return node.Key, node.Value, true - case compare < 0: - ceiling, found = node, true - node = node.Left - case compare > 0: - node = node.Right - } - } - if found { - return ceiling.Key, ceiling.Value, true - } - return nil, nil, false -} - -// Find floor node of the input key, return its key and value or nil if no ceiling is found. -// Third return parameter is true if floor was found, otherwise false. -// Floor node is defined as the largest node that is smaller than or equal to the given node. -// A floor node may not be found, either because the tree is empty, or because -// all nodes in the tree is larger than the given node. -// Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *Tree) Floor(key interface{}) (floorKey interface{}, value interface{}, found bool) { - floor := &Node{} - found = false - - node := tree.Root - for node != nil { - compare := tree.comparator(key, node.Key) - switch { - case compare == 0: - return node.Key, node.Value, true - case compare < 0: - node = node.Left - case compare > 0: - floor, found = node, true - node = node.Right - } - } - if found { - return floor.Key, floor.Value, true - } - return nil, nil, false -} - // Remove the node from the tree by key. // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree) Remove(key interface{}) { @@ -250,6 +192,11 @@ func (tree *Tree) Clear() { tree.size = 0 } +// Return comparator of the tree +func (tree *Tree) Comparator() utils.Comparator { + return tree.comparator +} + func (tree *Tree) String() string { str := "RedBlackTree\n" if !tree.Empty() { diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index af2f3366..58fe60fe 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -160,70 +160,6 @@ func TestRedBlackTree(t *testing.T) { } -func TestCeiling(t *testing.T) { - - tree := NewWithIntComparator() - - //key-value to insert - tree.Put(1, "a") - tree.Put(2, "b") - tree.Put(4, "d") - tree.Put(6, "f") - tree.Put(7, "g") - - //ceiling map - ceilingMap := [][]interface{}{ - {0, 1, true}, - {1, 1, true}, - {2, 2, true}, - {3, 4, true}, - {4, 4, true}, - {5, 6, true}, - {6, 6, true}, - {7, 7, true}, - {8, nil, false}, - } - for _, test := range ceilingMap { - actualKey, _, actualFound := tree.Ceiling(test[0]) - if actualKey != test[1] || actualFound != test[2] { - t.Errorf("Got (%v, %v) expected (%v, %v)", - actualKey, actualFound, test[1], test[2]) - } - } -} - -func TestFloor(t *testing.T) { - - tree := NewWithIntComparator() - - //key-value to insert - tree.Put(1, "a") - tree.Put(2, "b") - tree.Put(4, "d") - tree.Put(6, "f") - tree.Put(7, "g") - - //ceiling map - ceilingMap := [][]interface{}{ - {0, nil, false}, - {1, 1, true}, - {2, 2, true}, - {3, 2, true}, - {4, 4, true}, - {5, 4, true}, - {6, 6, true}, - {7, 7, true}, - {8, 7, true}, - } - for _, test := range ceilingMap { - actualKey, _, actualFound := tree.Floor(test[0]) - if actualKey != test[1] || actualFound != test[2] { - t.Errorf("Got (%v, %v) expected (%v, %v)", - actualKey, actualFound, test[1], test[2]) - } - } -} - func BenchmarkRedBlackTree(b *testing.B) { for i := 0; i < b.N; i++ { tree := NewWithIntComparator() From 932f9b3f1ef3815d6848878da94ec32a32efc407 Mon Sep 17 00:00:00 2001 From: otnt Date: Sun, 27 Mar 2016 21:55:51 -0400 Subject: [PATCH 007/320] Ceiling and Floor function have two return parameter instead of three --- examples/redblacktreeextended.go | 36 +++++++++++++++++--------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/examples/redblacktreeextended.go b/examples/redblacktreeextended.go index df148f3d..ecfe421f 100644 --- a/examples/redblacktreeextended.go +++ b/examples/redblacktreeextended.go @@ -103,14 +103,15 @@ func print(tree *RedBlackTreeExtended) { fmt.Println(tree) } -// Find ceiling node of the input key, return its key and value or nil if no ceiling is found. -// Third return parameter is true if ceiling was found, otherwise false. +// Find ceiling node of the input key, return the ceiling node or nil if no ceiling is found. +// Second return parameter is true if ceiling was found, otherwise false. +// // Ceiling node is defined as the smallest node that is larger than or equal to the given node. // A ceiling node may not be found, either because the tree is empty, or because // all nodes in the tree is smaller than the given node. +// // Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *RedBlackTreeExtended) Ceiling(key interface{}) (ceilingKey interface{}, value interface{}, found bool) { - var ceiling *rbt.Node +func (tree *RedBlackTreeExtended) Ceiling(key interface{}) (ceiling *rbt.Node, found bool) { found = false comparator := tree.Comparator() @@ -119,7 +120,7 @@ func (tree *RedBlackTreeExtended) Ceiling(key interface{}) (ceilingKey interface compare := comparator(key, node.Key) switch { case compare == 0: - return node.Key, node.Value, true + return node, true case compare < 0: ceiling, found = node, true node = node.Left @@ -128,19 +129,20 @@ func (tree *RedBlackTreeExtended) Ceiling(key interface{}) (ceilingKey interface } } if found { - return ceiling.Key, ceiling.Value, true + return ceiling, true } - return nil, nil, false + return nil, false } -// Find floor node of the input key, return its key and value or nil if no ceiling is found. -// Third return parameter is true if floor was found, otherwise false. +// Find floor node of the input key, return the floor node or nil if no ceiling is found. +// Second return parameter is true if floor was found, otherwise false. +// // Floor node is defined as the largest node that is smaller than or equal to the given node. // A floor node may not be found, either because the tree is empty, or because // all nodes in the tree is larger than the given node. +// // Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *RedBlackTreeExtended) Floor(key interface{}) (floorKey interface{}, value interface{}, found bool) { - var floor *rbt.Node +func (tree *RedBlackTreeExtended) Floor(key interface{}) (floor *rbt.Node, found bool) { found = false comparator := tree.Comparator() @@ -149,7 +151,7 @@ func (tree *RedBlackTreeExtended) Floor(key interface{}) (floorKey interface{}, compare := comparator(key, node.Key) switch { case compare == 0: - return node.Key, node.Value, true + return node, true case compare < 0: node = node.Left case compare > 0: @@ -158,9 +160,9 @@ func (tree *RedBlackTreeExtended) Floor(key interface{}) (floorKey interface{}, } } if found { - return floor.Key, floor.Value, true + return floor, true } - return nil, nil, false + return nil, false } func RedBlackTreeExtendedExample() { @@ -216,8 +218,8 @@ func RedBlackTreeExtendedExample() { {8, nil, 7}, } for _, tt := range testValues { - actualCeiling, _, _ := tree.Ceiling(tt[0]) - actualFloor, _, _ := tree.Floor(tt[0]) - fmt.Printf("test key %d, expected (%d, %d), actual (%d, %d)\n", tt[0], tt[1], tt[2], actualCeiling, actualFloor) + actualCeiling, _ := tree.Ceiling(tt[0]) + actualFloor, _ := tree.Floor(tt[0]) + fmt.Printf("test key %d, expected (%d, %d), actual (%d, %d)\n", tt[0], tt[1], tt[2], actualCeiling.Key, actualFloor.Key) } } From 351cf24f70a23654f9e5898197fe524f3d5a5a20 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 28 Mar 2016 06:57:04 +0200 Subject: [PATCH 008/320] expose comparator in redblacktree --- trees/redblacktree/redblacktree.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 6e527fe9..507b8d17 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -51,7 +51,7 @@ const ( type Tree struct { Root *Node size int - comparator utils.Comparator + Comparator utils.Comparator } type Node struct { @@ -65,17 +65,17 @@ type Node struct { // Instantiates a red-black tree with the custom comparator. func NewWith(comparator utils.Comparator) *Tree { - return &Tree{comparator: comparator} + return &Tree{Comparator: comparator} } // Instantiates a red-black tree with the IntComparator, i.e. keys are of type int. func NewWithIntComparator() *Tree { - return &Tree{comparator: utils.IntComparator} + return &Tree{Comparator: utils.IntComparator} } // Instantiates a red-black tree with the StringComparator, i.e. keys are of type string. func NewWithStringComparator() *Tree { - return &Tree{comparator: utils.StringComparator} + return &Tree{Comparator: utils.StringComparator} } // Inserts node into the tree. @@ -88,7 +88,7 @@ func (tree *Tree) Put(key interface{}, value interface{}) { node := tree.Root loop := true for loop { - compare := tree.comparator(key, node.Key) + compare := tree.Comparator(key, node.Key) switch { case compare == 0: node.Value = value @@ -263,7 +263,7 @@ func output(node *Node, prefix string, isTail bool, str *string) { func (tree *Tree) lookup(key interface{}) *Node { node := tree.Root for node != nil { - compare := tree.comparator(key, node.Key) + compare := tree.Comparator(key, node.Key) switch { case compare == 0: return node From 7ecff11d2d84a3df7cd1d8676e0f2690de4fa2f3 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 28 Mar 2016 07:17:39 +0200 Subject: [PATCH 009/320] - revert, build failing --- examples/redblacktreeextended.go | 90 ------------------------------ trees/redblacktree/redblacktree.go | 17 ++---- 2 files changed, 6 insertions(+), 101 deletions(-) diff --git a/examples/redblacktreeextended.go b/examples/redblacktreeextended.go index ecfe421f..fbb8d6cc 100644 --- a/examples/redblacktreeextended.go +++ b/examples/redblacktreeextended.go @@ -103,68 +103,6 @@ func print(tree *RedBlackTreeExtended) { fmt.Println(tree) } -// Find ceiling node of the input key, return the ceiling node or nil if no ceiling is found. -// Second return parameter is true if ceiling was found, otherwise false. -// -// Ceiling node is defined as the smallest node that is larger than or equal to the given node. -// A ceiling node may not be found, either because the tree is empty, or because -// all nodes in the tree is smaller than the given node. -// -// Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *RedBlackTreeExtended) Ceiling(key interface{}) (ceiling *rbt.Node, found bool) { - found = false - comparator := tree.Comparator() - - node := tree.Root - for node != nil { - compare := comparator(key, node.Key) - switch { - case compare == 0: - return node, true - case compare < 0: - ceiling, found = node, true - node = node.Left - case compare > 0: - node = node.Right - } - } - if found { - return ceiling, true - } - return nil, false -} - -// Find floor node of the input key, return the floor node or nil if no ceiling is found. -// Second return parameter is true if floor was found, otherwise false. -// -// Floor node is defined as the largest node that is smaller than or equal to the given node. -// A floor node may not be found, either because the tree is empty, or because -// all nodes in the tree is larger than the given node. -// -// Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *RedBlackTreeExtended) Floor(key interface{}) (floor *rbt.Node, found bool) { - found = false - comparator := tree.Comparator() - - node := tree.Root - for node != nil { - compare := comparator(key, node.Key) - switch { - case compare == 0: - return node, true - case compare < 0: - node = node.Left - case compare > 0: - floor, found = node, true - node = node.Right - } - } - if found { - return floor, true - } - return nil, false -} - func RedBlackTreeExtendedExample() { tree := RedBlackTreeExtended{rbt.NewWithIntComparator()} @@ -194,32 +132,4 @@ func RedBlackTreeExtendedExample() { // Value for min key: c // RedBlackTree // └── 3 - - /* - * Ceiling and Floor functions - */ - tree = RedBlackTreeExtended{rbt.NewWithIntComparator()} - tree.Put(1, "a") - tree.Put(2, "b") - tree.Put(4, "d") - tree.Put(6, "f") - tree.Put(7, "g") - - //index, ceiling, floor - testValues := [][]interface{}{ - {0, 1, nil}, - {1, 1, 1}, - {2, 2, 2}, - {3, 4, 2}, - {4, 4, 4}, - {5, 6, 4}, - {6, 6, 6}, - {7, 7, 7}, - {8, nil, 7}, - } - for _, tt := range testValues { - actualCeiling, _ := tree.Ceiling(tt[0]) - actualFloor, _ := tree.Floor(tt[0]) - fmt.Printf("test key %d, expected (%d, %d), actual (%d, %d)\n", tt[0], tt[1], tt[2], actualCeiling.Key, actualFloor.Key) - } } diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 12343615..6e527fe9 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -51,7 +51,7 @@ const ( type Tree struct { Root *Node size int - Comparator utils.Comparator + comparator utils.Comparator } type Node struct { @@ -65,17 +65,17 @@ type Node struct { // Instantiates a red-black tree with the custom comparator. func NewWith(comparator utils.Comparator) *Tree { - return &Tree{Comparator: comparator} + return &Tree{comparator: comparator} } // Instantiates a red-black tree with the IntComparator, i.e. keys are of type int. func NewWithIntComparator() *Tree { - return &Tree{Comparator: utils.IntComparator} + return &Tree{comparator: utils.IntComparator} } // Instantiates a red-black tree with the StringComparator, i.e. keys are of type string. func NewWithStringComparator() *Tree { - return &Tree{Comparator: utils.StringComparator} + return &Tree{comparator: utils.StringComparator} } // Inserts node into the tree. @@ -88,7 +88,7 @@ func (tree *Tree) Put(key interface{}, value interface{}) { node := tree.Root loop := true for loop { - compare := tree.Comparator(key, node.Key) + compare := tree.comparator(key, node.Key) switch { case compare == 0: node.Value = value @@ -192,11 +192,6 @@ func (tree *Tree) Clear() { tree.size = 0 } -// Return comparator of the tree -func (tree *Tree) Comparator() utils.Comparator { - return tree.comparator -} - func (tree *Tree) String() string { str := "RedBlackTree\n" if !tree.Empty() { @@ -268,7 +263,7 @@ func output(node *Node, prefix string, isTail bool, str *string) { func (tree *Tree) lookup(key interface{}) *Node { node := tree.Root for node != nil { - compare := tree.Comparator(key, node.Key) + compare := tree.comparator(key, node.Key) switch { case compare == 0: return node From 60c53a79f09babb55ecb7efab62ff2b748e3d12a Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 28 Mar 2016 07:54:17 +0200 Subject: [PATCH 010/320] - expose Comparator in redblacktree and include @otnt changes --- examples/redblacktreeextended.go | 84 ++++++++++++++++++++++++++++++ trees/redblacktree/redblacktree.go | 12 ++--- 2 files changed, 90 insertions(+), 6 deletions(-) diff --git a/examples/redblacktreeextended.go b/examples/redblacktreeextended.go index fbb8d6cc..17855c9b 100644 --- a/examples/redblacktreeextended.go +++ b/examples/redblacktreeextended.go @@ -95,6 +95,64 @@ func (tree *RedBlackTreeExtended) getMaxFromNode(node *rbt.Node) (foundNode *rbt } } +// Find ceiling node of the input key, return the ceiling node or nil if no ceiling is found. +// Second return parameter is true if ceiling was found, otherwise false. +// +// Ceiling node is defined as the smallest node that is larger than or equal to the given node. +// A ceiling node may not be found, either because the tree is empty, or because +// all nodes in the tree is smaller than the given node. +// +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (tree *RedBlackTreeExtended) Ceiling(key interface{}) (ceiling *rbt.Node, found bool) { + found = false + node := tree.Root + for node != nil { + compare := tree.Comparator(key, node.Key) + switch { + case compare == 0: + return node, true + case compare < 0: + ceiling, found = node, true + node = node.Left + case compare > 0: + node = node.Right + } + } + if found { + return ceiling, true + } + return nil, false +} + +// Find floor node of the input key, return the floor node or nil if no ceiling is found. +// Second return parameter is true if floor was found, otherwise false. +// +// Floor node is defined as the largest node that is smaller than or equal to the given node. +// A floor node may not be found, either because the tree is empty, or because +// all nodes in the tree is larger than the given node. +// +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (tree *RedBlackTreeExtended) Floor(key interface{}) (floor *rbt.Node, found bool) { + found = false + node := tree.Root + for node != nil { + compare := tree.Comparator(key, node.Key) + switch { + case compare == 0: + return node, true + case compare < 0: + node = node.Left + case compare > 0: + floor, found = node, true + node = node.Right + } + } + if found { + return floor, true + } + return nil, false +} + func print(tree *RedBlackTreeExtended) { max, _ := tree.GetMax() min, _ := tree.GetMin() @@ -132,4 +190,30 @@ func RedBlackTreeExtendedExample() { // Value for min key: c // RedBlackTree // └── 3 + + // Ceiling and Floor functions + tree = RedBlackTreeExtended{rbt.NewWithIntComparator()} + tree.Put(1, "a") + tree.Put(2, "b") + tree.Put(4, "d") + tree.Put(6, "f") + tree.Put(7, "g") + + //index, ceiling, floor + testValues := [][]interface{}{ + {0, 1, nil}, + {1, 1, 1}, + {2, 2, 2}, + {3, 4, 2}, + {4, 4, 4}, + {5, 6, 4}, + {6, 6, 6}, + {7, 7, 7}, + {8, nil, 7}, + } + for _, tt := range testValues { + actualCeiling, _ := tree.Ceiling(tt[0]) + actualFloor, _ := tree.Floor(tt[0]) + fmt.Printf("test key %d, expected (%d, %d), actual (%d, %d)\n", tt[0], tt[1], tt[2], actualCeiling.Key, actualFloor.Key) + } } diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 6e527fe9..507b8d17 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -51,7 +51,7 @@ const ( type Tree struct { Root *Node size int - comparator utils.Comparator + Comparator utils.Comparator } type Node struct { @@ -65,17 +65,17 @@ type Node struct { // Instantiates a red-black tree with the custom comparator. func NewWith(comparator utils.Comparator) *Tree { - return &Tree{comparator: comparator} + return &Tree{Comparator: comparator} } // Instantiates a red-black tree with the IntComparator, i.e. keys are of type int. func NewWithIntComparator() *Tree { - return &Tree{comparator: utils.IntComparator} + return &Tree{Comparator: utils.IntComparator} } // Instantiates a red-black tree with the StringComparator, i.e. keys are of type string. func NewWithStringComparator() *Tree { - return &Tree{comparator: utils.StringComparator} + return &Tree{Comparator: utils.StringComparator} } // Inserts node into the tree. @@ -88,7 +88,7 @@ func (tree *Tree) Put(key interface{}, value interface{}) { node := tree.Root loop := true for loop { - compare := tree.comparator(key, node.Key) + compare := tree.Comparator(key, node.Key) switch { case compare == 0: node.Value = value @@ -263,7 +263,7 @@ func output(node *Node, prefix string, isTail bool, str *string) { func (tree *Tree) lookup(key interface{}) *Node { node := tree.Root for node != nil { - compare := tree.comparator(key, node.Key) + compare := tree.Comparator(key, node.Key) switch { case compare == 0: return node From f9305332a4a3048d4d0c9fdeb3ce29adf805b0b4 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 28 Mar 2016 08:01:46 +0200 Subject: [PATCH 011/320] - expose comparator in binary heap - fix comment --- containers/containers.go | 2 +- trees/binaryheap/binaryheap.go | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/containers/containers.go b/containers/containers.go index 96d3e073..48e9b15f 100644 --- a/containers/containers.go +++ b/containers/containers.go @@ -37,7 +37,7 @@ type Interface interface { Values() []interface{} } -// Returns sorted container's elements using with respect to the passed comparator. +// Returns sorted container's elements with respect to the passed comparator. // Does not effect the ordering of elements within the container. // Uses timsort. func GetSortedValues(container Interface, comparator utils.Comparator) []interface{} { diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index 346d787a..79f91b1b 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -45,22 +45,22 @@ func assertInterfaceImplementation() { type Heap struct { list *arraylist.List - comparator utils.Comparator + Comparator utils.Comparator } // Instantiates a new empty heap tree with the custom comparator. func NewWith(comparator utils.Comparator) *Heap { - return &Heap{list: arraylist.New(), comparator: comparator} + return &Heap{list: arraylist.New(), Comparator: comparator} } // Instantiates a new empty heap with the IntComparator, i.e. elements are of type int. func NewWithIntComparator() *Heap { - return &Heap{list: arraylist.New(), comparator: utils.IntComparator} + return &Heap{list: arraylist.New(), Comparator: utils.IntComparator} } // Instantiates a new empty heap with the StringComparator, i.e. elements are of type string. func NewWithStringComparator() *Heap { - return &Heap{list: arraylist.New(), comparator: utils.StringComparator} + return &Heap{list: arraylist.New(), Comparator: utils.StringComparator} } // Pushes a value onto the heap and bubbles it up accordingly. @@ -129,12 +129,12 @@ func (heap *Heap) bubbleDown() { smallerIndex := leftIndex leftValue, _ := heap.list.Get(leftIndex) rightValue, _ := heap.list.Get(rightIndex) - if rightIndex < size && heap.comparator(leftValue, rightValue) > 0 { + if rightIndex < size && heap.Comparator(leftValue, rightValue) > 0 { smallerIndex = rightIndex } indexValue, _ := heap.list.Get(index) smallerValue, _ := heap.list.Get(smallerIndex) - if heap.comparator(indexValue, smallerValue) > 0 { + if heap.Comparator(indexValue, smallerValue) > 0 { heap.list.Swap(index, smallerIndex) } else { break @@ -151,7 +151,7 @@ func (heap *Heap) bubbleUp() { for parentIndex := (index - 1) >> 1; index > 0; parentIndex = (index - 1) >> 1 { indexValue, _ := heap.list.Get(index) parentValue, _ := heap.list.Get(parentIndex) - if heap.comparator(parentValue, indexValue) <= 0 { + if heap.Comparator(parentValue, indexValue) <= 0 { break } heap.list.Swap(index, parentIndex) From 6bfa9f318d6341686712b65c50b76b239fa93de0 Mon Sep 17 00:00:00 2001 From: Vlad Alexandru Ionescu Date: Tue, 19 Apr 2016 21:38:32 +0100 Subject: [PATCH 012/320] Add ability to get leftmost (minimum) and rightmost (maximum) keys in treemap. --- maps/treemap/treemap.go | 10 ++++++++ maps/treemap/treemap_test.go | 34 ++++++++++++++++---------- trees/redblacktree/redblacktree.go | 38 ++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 12 deletions(-) diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index 6386d69a..06d61859 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -73,6 +73,16 @@ func (m *Map) Get(key interface{}) (value interface{}, found bool) { return m.tree.Get(key) } +// Returns the left-most element in the tree map (minimum). +func (m *Map) Left() (key interface{}) { + return m.tree.Left() +} + +// Returns the right-most element in the tree map (maximum). +func (m *Map) Right() (key interface{}) { + return m.tree.Right() +} + // Remove the element from the map by key. // Key should adhere to the comparator's type assertion, otherwise method panics. func (m *Map) Remove(key interface{}) { diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 03fb23c5..9bdfd633 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -51,13 +51,23 @@ func TestTreeMap(t *testing.T) { } // test Keys() - if actualValue, expactedValue := fmt.Sprintf("%d%d%d%d%d%d%d", m.Keys()...), "1234567"; actualValue != expactedValue { - t.Errorf("Got %v expected %v", actualValue, expactedValue) + if actualValue, expectedValue := fmt.Sprintf("%d%d%d%d%d%d%d", m.Keys()...), "1234567"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } // test Values() - if actualValue, expactedValue := fmt.Sprintf("%s%s%s%s%s%s%s", m.Values()...), "abcdefg"; actualValue != expactedValue { - t.Errorf("Got %v expected %v", actualValue, expactedValue) + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s", m.Values()...), "abcdefg"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + // test Left() + if actualValue, expectedValue := fmt.Sprintf("%d", m.Left()), "1"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + // test Right() + if actualValue, expectedValue := fmt.Sprintf("%d", m.Right()), "7"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } // key,expectedValue,expectedFound @@ -88,13 +98,13 @@ func TestTreeMap(t *testing.T) { m.Remove(5) // Test Keys() - if actualValue, expactedValue := fmt.Sprintf("%d%d%d%d", m.Keys()...), "1234"; actualValue != expactedValue { - t.Errorf("Got %v expected %v", actualValue, expactedValue) + if actualValue, expectedValue := fmt.Sprintf("%d%d%d%d", m.Keys()...), "1234"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } // test Values() - if actualValue, expactedValue := fmt.Sprintf("%s%s%s%s", m.Values()...), "abcd"; actualValue != expactedValue { - t.Errorf("Got %v expected %v", actualValue, expactedValue) + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", m.Values()...), "abcd"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } // Test Size() @@ -130,13 +140,13 @@ func TestTreeMap(t *testing.T) { m.Remove(2) // Test Keys() - if actualValue, expactedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expactedValue { - t.Errorf("Got %v expected %v", actualValue, expactedValue) + if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } // test Values() - if actualValue, expactedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expactedValue { - t.Errorf("Got %v expected %v", actualValue, expactedValue) + if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } // Test Size() diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 507b8d17..67f83b29 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -186,6 +186,24 @@ func (tree *Tree) Values() []interface{} { return values } +// Returns the left-most key. +func (tree *Tree) Left() interface{} { + left := tree.leftNode() + if left == nil { + return nil + } + return left.Key +} + +// Returns the right-most key. +func (tree *Tree) Right() interface{} { + right := tree.rightNode() + if right == nil { + return nil + } + return right.Key +} + // Removes all nodes from the tree. func (tree *Tree) Clear() { tree.Root = nil @@ -232,6 +250,26 @@ func (tree *Tree) inOrder() []*Node { return nodes } +func (tree *Tree) leftNode() *Node { + var parent *Node + current := tree.Root + for current != nil { + parent = current + current = current.Left + } + return parent +} + +func (tree *Tree) rightNode() *Node { + var parent *Node + current := tree.Root + for current != nil { + parent = current + current = current.Right + } + return parent +} + func output(node *Node, prefix string, isTail bool, str *string) { if node.Right != nil { newPrefix := prefix From 160299d0f773c9211fc0d4fd3b87cbba726fd758 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 12 Jun 2016 15:04:33 +0200 Subject: [PATCH 013/320] - fix spelling mistake everywhere (expacted -> expected) and go vet/fmt --- maps/hashmap/hashmap_test.go | 24 ++++++++++++------------ sets/hashset/hashset_test.go | 4 ++-- sets/treeset/treeset_test.go | 4 ++-- trees/redblacktree/redblacktree_test.go | 24 ++++++++++++------------ 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/maps/hashmap/hashmap_test.go b/maps/hashmap/hashmap_test.go index 31c026b4..3c28d1c2 100644 --- a/maps/hashmap/hashmap_test.go +++ b/maps/hashmap/hashmap_test.go @@ -51,13 +51,13 @@ func TestHashMap(t *testing.T) { } // test Keys() - if actualValue, expactedValue := m.Keys(), []interface{}{1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expactedValue) { - t.Errorf("Got %v expected %v", actualValue, expactedValue) + if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } // test Values() - if actualValue, expactedValue := m.Values(), []interface{}{"a", "b", "c", "d", "e", "f", "g"}; !sameElements(actualValue, expactedValue) { - t.Errorf("Got %v expected %v", actualValue, expactedValue) + if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "e", "f", "g"}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } // key,expectedValue,expectedFound @@ -88,13 +88,13 @@ func TestHashMap(t *testing.T) { m.Remove(5) // test Keys() - if actualValue, expactedValue := m.Keys(), []interface{}{1, 2, 3, 4}; !sameElements(actualValue, expactedValue) { - t.Errorf("Got %v expected %v", actualValue, expactedValue) + if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } // test Values() - if actualValue, expactedValue := m.Values(), []interface{}{"a", "b", "c", "d"}; !sameElements(actualValue, expactedValue) { - t.Errorf("Got %v expected %v", actualValue, expactedValue) + if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d"}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } // Test Size() if actualValue := m.Size(); actualValue != 4 { @@ -129,13 +129,13 @@ func TestHashMap(t *testing.T) { m.Remove(2) // Test Keys() - if actualValue, expactedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expactedValue { - t.Errorf("Got %v expected %v", actualValue, expactedValue) + if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } // test Values() - if actualValue, expactedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expactedValue { - t.Errorf("Got %v expected %v", actualValue, expactedValue) + if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } // Test Size() diff --git a/sets/hashset/hashset_test.go b/sets/hashset/hashset_test.go index d38006e0..036f80d6 100644 --- a/sets/hashset/hashset_test.go +++ b/sets/hashset/hashset_test.go @@ -70,8 +70,8 @@ func TestHashSet(t *testing.T) { set.Remove() set.Remove(1) - if actualValue, expactedValues := fmt.Sprintf("%d%d", set.Values()...), [2]string{"23", "32"}; actualValue != expactedValues[0] && actualValue != expactedValues[1] { - t.Errorf("Got %v expected %v", actualValue, expactedValues) + if actualValue, expectedValues := fmt.Sprintf("%d%d", set.Values()...), [2]string{"23", "32"}; actualValue != expectedValues[0] && actualValue != expectedValues[1] { + t.Errorf("Got %v expected %v", actualValue, expectedValues) } if actualValue := set.Contains(1); actualValue != false { diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index 4ad42652..b033a7ba 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -61,8 +61,8 @@ func TestTreeSet(t *testing.T) { // repeat 10 time since map in golang has a random iteration order each time and we want to make sure that the set is ordered for i := 1; i <= 10; i++ { - if actualValue, expactedValue := fmt.Sprintf("%d%d%d", set.Values()...), "123"; actualValue != expactedValue { - t.Errorf("Got %v expected %v", actualValue, expactedValue) + if actualValue, expectedValue := fmt.Sprintf("%d%d%d", set.Values()...), "123"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 58fe60fe..050bca56 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -51,13 +51,13 @@ func TestRedBlackTree(t *testing.T) { } // test Keys() - if actualValue, expactedValue := fmt.Sprintf("%d%d%d%d%d%d%d", tree.Keys()...), "1234567"; actualValue != expactedValue { - t.Errorf("Got %v expected %v", actualValue, expactedValue) + if actualValue, expectedValue := fmt.Sprintf("%d%d%d%d%d%d%d", tree.Keys()...), "1234567"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } // test Values() - if actualValue, expactedValue := fmt.Sprintf("%s%s%s%s%s%s%s", tree.Values()...), "abcdefg"; actualValue != expactedValue { - t.Errorf("Got %v expected %v", actualValue, expactedValue) + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s", tree.Values()...), "abcdefg"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } // key,expectedValue,expectedFound @@ -88,13 +88,13 @@ func TestRedBlackTree(t *testing.T) { tree.Remove(5) // Test Keys() - if actualValue, expactedValue := fmt.Sprintf("%d%d%d%d", tree.Keys()...), "1234"; actualValue != expactedValue { - t.Errorf("Got %v expected %v", actualValue, expactedValue) + if actualValue, expectedValue := fmt.Sprintf("%d%d%d%d", tree.Keys()...), "1234"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } // test Values() - if actualValue, expactedValue := fmt.Sprintf("%s%s%s%s", tree.Values()...), "abcd"; actualValue != expactedValue { - t.Errorf("Got %v expected %v", actualValue, expactedValue) + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", tree.Values()...), "abcd"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } // Test Size() @@ -130,13 +130,13 @@ func TestRedBlackTree(t *testing.T) { tree.Remove(2) // Test Keys() - if actualValue, expactedValue := fmt.Sprintf("%s", tree.Keys()), "[]"; actualValue != expactedValue { - t.Errorf("Got %v expected %v", actualValue, expactedValue) + if actualValue, expectedValue := fmt.Sprintf("%s", tree.Keys()), "[]"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } // test Values() - if actualValue, expactedValue := fmt.Sprintf("%s", tree.Values()), "[]"; actualValue != expactedValue { - t.Errorf("Got %v expected %v", actualValue, expactedValue) + if actualValue, expectedValue := fmt.Sprintf("%s", tree.Values()), "[]"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } // Test Size() From d13e3d6b6a9f8e541162c9ba7ede1d4ac5b687cd Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 13 Jun 2016 00:52:16 +0200 Subject: [PATCH 014/320] - Add Left(), Right(), Floor() and Ceiling() function to the red black tree with test and documentation update --- README.md | 6 ++ examples/redblacktreeextended.go | 84 ------------------- trees/redblacktree/redblacktree.go | 106 +++++++++++++++++------- trees/redblacktree/redblacktree_test.go | 56 +++++++++++++ 4 files changed, 136 insertions(+), 116 deletions(-) diff --git a/README.md b/README.md index b26838cf..0d22bfa9 100644 --- a/README.md +++ b/README.md @@ -471,6 +471,12 @@ func main() { tree.Clear() // empty tree.Empty() // true tree.Size() // 0 + + // Other: + tree.Left() // gets the left-most (min) node + tree.Right() // get the right-most (max) node + tree.Floor(1) // get the floor node + tree.Ceiling(1) // get the ceiling node } ``` diff --git a/examples/redblacktreeextended.go b/examples/redblacktreeextended.go index 17855c9b..fbb8d6cc 100644 --- a/examples/redblacktreeextended.go +++ b/examples/redblacktreeextended.go @@ -95,64 +95,6 @@ func (tree *RedBlackTreeExtended) getMaxFromNode(node *rbt.Node) (foundNode *rbt } } -// Find ceiling node of the input key, return the ceiling node or nil if no ceiling is found. -// Second return parameter is true if ceiling was found, otherwise false. -// -// Ceiling node is defined as the smallest node that is larger than or equal to the given node. -// A ceiling node may not be found, either because the tree is empty, or because -// all nodes in the tree is smaller than the given node. -// -// Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *RedBlackTreeExtended) Ceiling(key interface{}) (ceiling *rbt.Node, found bool) { - found = false - node := tree.Root - for node != nil { - compare := tree.Comparator(key, node.Key) - switch { - case compare == 0: - return node, true - case compare < 0: - ceiling, found = node, true - node = node.Left - case compare > 0: - node = node.Right - } - } - if found { - return ceiling, true - } - return nil, false -} - -// Find floor node of the input key, return the floor node or nil if no ceiling is found. -// Second return parameter is true if floor was found, otherwise false. -// -// Floor node is defined as the largest node that is smaller than or equal to the given node. -// A floor node may not be found, either because the tree is empty, or because -// all nodes in the tree is larger than the given node. -// -// Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *RedBlackTreeExtended) Floor(key interface{}) (floor *rbt.Node, found bool) { - found = false - node := tree.Root - for node != nil { - compare := tree.Comparator(key, node.Key) - switch { - case compare == 0: - return node, true - case compare < 0: - node = node.Left - case compare > 0: - floor, found = node, true - node = node.Right - } - } - if found { - return floor, true - } - return nil, false -} - func print(tree *RedBlackTreeExtended) { max, _ := tree.GetMax() min, _ := tree.GetMin() @@ -190,30 +132,4 @@ func RedBlackTreeExtendedExample() { // Value for min key: c // RedBlackTree // └── 3 - - // Ceiling and Floor functions - tree = RedBlackTreeExtended{rbt.NewWithIntComparator()} - tree.Put(1, "a") - tree.Put(2, "b") - tree.Put(4, "d") - tree.Put(6, "f") - tree.Put(7, "g") - - //index, ceiling, floor - testValues := [][]interface{}{ - {0, 1, nil}, - {1, 1, 1}, - {2, 2, 2}, - {3, 4, 2}, - {4, 4, 4}, - {5, 6, 4}, - {6, 6, 6}, - {7, 7, 7}, - {8, nil, 7}, - } - for _, tt := range testValues { - actualCeiling, _ := tree.Ceiling(tt[0]) - actualFloor, _ := tree.Floor(tt[0]) - fmt.Printf("test key %d, expected (%d, %d), actual (%d, %d)\n", tt[0], tt[1], tt[2], actualCeiling.Key, actualFloor.Key) - } } diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 67f83b29..2fe165b2 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -186,22 +186,84 @@ func (tree *Tree) Values() []interface{} { return values } -// Returns the left-most key. -func (tree *Tree) Left() interface{} { - left := tree.leftNode() - if left == nil { - return nil +// Returns the left-most (min) node or nil if tree is empty. +func (tree *Tree) Left() *Node { + var parent *Node + current := tree.Root + for current != nil { + parent = current + current = current.Left } - return left.Key + return parent } -// Returns the right-most key. -func (tree *Tree) Right() interface{} { - right := tree.rightNode() - if right == nil { - return nil +// Returns the right-most (max) node or nil if tree is empty. +func (tree *Tree) Right() *Node { + var parent *Node + current := tree.Root + for current != nil { + parent = current + current = current.Right + } + return parent +} + +// Find floor node of the input key, return the floor node or nil if no ceiling is found. +// Second return parameter is true if floor was found, otherwise false. +// +// Floor node is defined as the largest node that is smaller than or equal to the given node. +// A floor node may not be found, either because the tree is empty, or because +// all nodes in the tree is larger than the given node. +// +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (tree *Tree) Floor(key interface{}) (floor *Node, found bool) { + found = false + node := tree.Root + for node != nil { + compare := tree.Comparator(key, node.Key) + switch { + case compare == 0: + return node, true + case compare < 0: + node = node.Left + case compare > 0: + floor, found = node, true + node = node.Right + } + } + if found { + return floor, true + } + return nil, false +} + +// Find ceiling node of the input key, return the ceiling node or nil if no ceiling is found. +// Second return parameter is true if ceiling was found, otherwise false. +// +// Ceiling node is defined as the smallest node that is larger than or equal to the given node. +// A ceiling node may not be found, either because the tree is empty, or because +// all nodes in the tree is smaller than the given node. +// +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (tree *Tree) Ceiling(key interface{}) (ceiling *Node, found bool) { + found = false + node := tree.Root + for node != nil { + compare := tree.Comparator(key, node.Key) + switch { + case compare == 0: + return node, true + case compare < 0: + ceiling, found = node, true + node = node.Left + case compare > 0: + node = node.Right + } } - return right.Key + if found { + return ceiling, true + } + return nil, false } // Removes all nodes from the tree. @@ -250,26 +312,6 @@ func (tree *Tree) inOrder() []*Node { return nodes } -func (tree *Tree) leftNode() *Node { - var parent *Node - current := tree.Root - for current != nil { - parent = current - current = current.Left - } - return parent -} - -func (tree *Tree) rightNode() *Node { - var parent *Node - current := tree.Root - for current != nil { - parent = current - current = current.Right - } - return parent -} - func output(node *Node, prefix string, isTail bool, str *string) { if node.Right != nil { newPrefix := prefix diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 050bca56..20a287c2 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -60,6 +60,38 @@ func TestRedBlackTree(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } + // test Left() + if actualValue, expectedValue := fmt.Sprintf("%d", tree.Left().Key), "1"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := fmt.Sprintf("%s", tree.Left().Value), "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + // test Right() + if actualValue, expectedValue := fmt.Sprintf("%d", tree.Right().Key), "7"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := fmt.Sprintf("%s", tree.Right().Value), "g"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + // test Floor() + if node, found := tree.Floor(4); node.Key != 4 || !found { + t.Errorf("Got %v expected %v", node.Key, 4) + } + if node, found := tree.Floor(0); node != nil || found { + t.Errorf("Got %v expected %v", node, "") + } + + // test Ceiling() + if node, found := tree.Ceiling(4); node.Key != 4 || !found { + t.Errorf("Got %v expected %v", node.Key, 4) + } + if node, found := tree.Ceiling(8); node != nil || found { + t.Errorf("Got %v expected %v", node, "") + } + // key,expectedValue,expectedFound tests1 := [][]interface{}{ {1, "a", true}, @@ -97,6 +129,11 @@ func TestRedBlackTree(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } + // test Values() + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", tree.Values()...), "abcd"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + // Test Size() if actualValue := tree.Size(); actualValue != 4 { t.Errorf("Got %v expected %v", actualValue, 7) @@ -158,6 +195,25 @@ func TestRedBlackTree(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, true) } + // test Left() + if actualValue, expectedValue := fmt.Sprintf("%s", tree.Left()), ""; actualValue != expectedValue { + t.Errorf("Got %s expected %s", actualValue, expectedValue) + } + + // test Right() + if actualValue, expectedValue := fmt.Sprintf("%s", tree.Right()), ""; actualValue != expectedValue { + t.Errorf("Got %s expected %s", actualValue, expectedValue) + } + + // test Floor() + if node, found := tree.Floor(1); node != nil || found { + t.Errorf("Got %v expected %v", node, "") + } + + // test Ceiling() + if node, found := tree.Ceiling(1); node != nil || found { + t.Errorf("Got %v expected %v", node, "") + } } func BenchmarkRedBlackTree(b *testing.B) { From 16d751cd27416f35bc28dda7167cf9a9d987a445 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 13 Jun 2016 01:05:07 +0200 Subject: [PATCH 015/320] - Add Min() and Max() function to the tree map with test and documentation update --- README.md | 4 ++++ maps/treemap/treemap.go | 28 ++++++++++++++++++---------- maps/treemap/treemap_test.go | 21 +++++++++++++++------ 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 0d22bfa9..443c37d3 100644 --- a/README.md +++ b/README.md @@ -400,6 +400,10 @@ func main() { m.Clear() // empty m.Empty() // true m.Size() // 0 + + // Other: + m.Min() // Returns the minimum key and its value from map. + m.Max() // Returns the maximum key and its value from map. } ``` diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index 06d61859..6d228cbb 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -73,16 +73,6 @@ func (m *Map) Get(key interface{}) (value interface{}, found bool) { return m.tree.Get(key) } -// Returns the left-most element in the tree map (minimum). -func (m *Map) Left() (key interface{}) { - return m.tree.Left() -} - -// Returns the right-most element in the tree map (maximum). -func (m *Map) Right() (key interface{}) { - return m.tree.Right() -} - // Remove the element from the map by key. // Key should adhere to the comparator's type assertion, otherwise method panics. func (m *Map) Remove(key interface{}) { @@ -114,6 +104,24 @@ func (m *Map) Clear() { m.tree.Clear() } +// Returns the minimum key and its value from the tree map. +// Returns nil, nil if map is empty. +func (m *Map) Min() (key interface{}, value interface{}) { + if node := m.tree.Left(); node != nil { + return node.Key, node.Value + } + return nil, nil +} + +// Returns the maximum key and its value from the tree map. +// Returns nil, nil if map is empty. +func (m *Map) Max() (key interface{}, value interface{}) { + if node := m.tree.Right(); node != nil { + return node.Key, node.Value + } + return nil, nil +} + func (m *Map) String() string { str := "TreeMap\n" str += m.tree.String() diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 9bdfd633..c48c4546 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -60,14 +60,14 @@ func TestTreeMap(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - // test Left() - if actualValue, expectedValue := fmt.Sprintf("%d", m.Left()), "1"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) + // test Min() + if key, value := m.Min(); key != 1 || value != "a" { + t.Errorf("Got %v expected %v", key, 1) } - // test Right() - if actualValue, expectedValue := fmt.Sprintf("%d", m.Right()), "7"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) + // test Max() + if key, value := m.Max(); key != 7 || value != "g" { + t.Errorf("Got %v expected %v", key, 7) } // key,expectedValue,expectedFound @@ -168,6 +168,15 @@ func TestTreeMap(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, true) } + // test Min() + if key, value := m.Min(); key != nil || value != nil { + t.Errorf("Got %v expected %v", key, nil) + } + + // test Max() + if key, value := m.Max(); key != nil || value != nil { + t.Errorf("Got %v expected %v", key, nil) + } } func BenchmarkTreeMap(b *testing.B) { From c7abdd28b35b670f506d5746cf14f871d98abd17 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 21 Jun 2016 02:22:20 +0200 Subject: [PATCH 016/320] - add insert for list and arraylist --- README.md | 3 +++ lists/arraylist/arraylist.go | 28 +++++++++++++++++++++++++++- lists/arraylist/arraylist_test.go | 14 ++++++++++++++ lists/lists.go | 1 + 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 443c37d3..40954451 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ type Interface interface { Contains(elements ...interface{}) bool Sort(comparator utils.Comparator) Swap(index1, index2 int) + Insert(index int, elements ...interface{}) containers.Interface // Empty() bool @@ -180,6 +181,8 @@ func main() { _ = list.Size() // 0 list.Add("a") // ["a"] list.Clear() // [] + list.Insert(0, "b") // ["b"] + list.Insert(0, "a") // ["a","b"] } ``` diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index f98b5e5f..c3b9f0ff 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -149,6 +149,32 @@ func (list *List) Swap(i, j int) { } } +// Inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right. +// Does not do anything if position is negative or bigger than list's size +// Note: position equal to list's size is valid, i.e. append. +func (list *List) Insert(index int, elements ...interface{}) { + + if !list.withinRange(index) { + // Append + if index == list.size { + list.Add(elements...) + } + return + } + + l := len(elements) + list.growBy(l) + list.size += l + // Shift old to right + for i := list.size - 1; i >= index+l; i-- { + list.elements[i] = list.elements[i-l] + } + // Insert new + for i, element := range elements { + list.elements[index+i] = element + } +} + func (list *List) String() string { str := "ArrayList\n" values := []string{} @@ -161,7 +187,7 @@ func (list *List) String() string { // Check that the index is withing bounds of the list func (list *List) withinRange(index int) bool { - return index >= 0 && index < list.size && list.size != 0 + return index >= 0 && index < list.size } func (list *List) resize(cap int) { diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 4eb239fa..ab07f677 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -27,6 +27,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package arraylist import ( + "fmt" "github.com/emirpasic/gods/utils" "testing" ) @@ -120,6 +121,19 @@ func TestArrayList(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, true) } + list.Insert(0, "h") + list.Insert(0, "e") + list.Insert(1, "f") + list.Insert(2, "g") + list.Insert(4, "i") + list.Insert(0, "a", "b") + list.Insert(list.Size(), "j", "k") + list.Insert(2, "c", "d") + + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s%s", list.Values()...), "abcdefghijk"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } func BenchmarkArrayList(b *testing.B) { diff --git a/lists/lists.go b/lists/lists.go index 7e03285f..7de3cb0f 100644 --- a/lists/lists.go +++ b/lists/lists.go @@ -30,6 +30,7 @@ type Interface interface { Contains(elements ...interface{}) bool Sort(comparator utils.Comparator) Swap(index1, index2 int) + Insert(index int, elements ...interface{}) containers.Interface // Empty() bool From 875dab737f96fda02977a735413d701c4d906c59 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 21 Jun 2016 03:15:02 +0200 Subject: [PATCH 017/320] - add insert for singlylinkedlist --- README.md | 2 + lists/singlylinkedlist/singlylinkedlist.go | 47 ++++++++++++++++++- .../singlylinkedlist/singlylinkedlist_test.go | 14 ++++++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 40954451..66dda496 100644 --- a/README.md +++ b/README.md @@ -218,6 +218,8 @@ func main() { _ = list.Size() // 0 list.Add("a") // ["a"] list.Clear() // [] + list.Insert(0, "b") // ["b"] + list.Insert(0, "a") // ["a","b"] } ``` diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index a9b4d636..e4730aeb 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -223,6 +223,51 @@ func (list *List) Swap(i, j int) { } } +// Inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right. +// Does not do anything if position is negative or bigger than list's size +// Note: position equal to list's size is valid, i.e. append. +func (list *List) Insert(index int, values ...interface{}) { + + if !list.withinRange(index) { + // Append + if index == list.size { + list.Add(values...) + } + fmt.Println(list.Values()) + return + } + + list.size += len(values) + + var beforeElement *element + foundElement := list.first + for e := 0; e != index; e, foundElement = e+1, foundElement.next { + beforeElement = foundElement + } + + if foundElement == list.first { + oldNextElement := list.first + for i, value := range values { + newElement := &element{value: value} + if i == 0 { + list.first = newElement + } else { + beforeElement.next = newElement + } + beforeElement = newElement + } + beforeElement.next = oldNextElement + } else { + oldNextElement := beforeElement.next + for _, value := range values { + newElement := &element{value: value} + beforeElement.next = newElement + beforeElement = newElement + } + beforeElement.next = oldNextElement + } +} + func (list *List) String() string { str := "SinglyLinkedList\n" values := []string{} @@ -235,5 +280,5 @@ func (list *List) String() string { // Check that the index is withing bounds of the list func (list *List) withinRange(index int) bool { - return index >= 0 && index < list.size && list.size != 0 + return index >= 0 && index < list.size } diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index 4956507a..df084665 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -27,6 +27,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package singlylinkedlist import ( + "fmt" "github.com/emirpasic/gods/utils" "testing" ) @@ -122,6 +123,19 @@ func TestSinglyLinkedList(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, true) } + list.Insert(0, "h") + list.Insert(0, "e") + list.Insert(1, "f") + list.Insert(2, "g") + list.Insert(4, "i") + list.Insert(0, "a", "b") + list.Insert(list.Size(), "j", "k") + list.Insert(2, "c", "d") + + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s%s", list.Values()...), "abcdefghijk"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } func BenchmarkSinglyLinkedList(b *testing.B) { From dd0fbaa365a36d9072dcc883b6f1775e26925a98 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 21 Jun 2016 03:29:29 +0200 Subject: [PATCH 018/320] - add insert for doublylinkedlist --- README.md | 2 + lists/doublylinkedlist/doublylinkedlist.go | 54 +++++++++++++++++++ .../doublylinkedlist/doublylinkedlist_test.go | 14 +++++ 3 files changed, 70 insertions(+) diff --git a/README.md b/README.md index 66dda496..6897e396 100644 --- a/README.md +++ b/README.md @@ -255,6 +255,8 @@ func main() { _ = list.Size() // 0 list.Add("a") // ["a"] list.Clear() // [] + list.Insert(0, "b") // ["b"] + list.Insert(0, "a") // ["a","b"] } ``` diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index ed40eebf..b948d8bb 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -244,6 +244,60 @@ func (list *List) Swap(i, j int) { } } +// Inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right. +// Does not do anything if position is negative or bigger than list's size +// Note: position equal to list's size is valid, i.e. append. +func (list *List) Insert(index int, values ...interface{}) { + + if !list.withinRange(index) { + // Append + if index == list.size { + list.Add(values...) + } + fmt.Println(list.Values()) + return + } + + list.size += len(values) + + var beforeElement *element + var foundElement *element + // determine traversal direction, last to first or first to last + if list.size-index < index { + foundElement = list.last + for e := list.size - 1; e != index; e, foundElement = e-1, foundElement.prev { + beforeElement = foundElement.prev + } + } else { + foundElement = list.first + for e := 0; e != index; e, foundElement = e+1, foundElement.next { + beforeElement = foundElement + } + } + + if foundElement == list.first { + oldNextElement := list.first + for i, value := range values { + newElement := &element{value: value} + if i == 0 { + list.first = newElement + } else { + beforeElement.next = newElement + } + beforeElement = newElement + } + beforeElement.next = oldNextElement + } else { + oldNextElement := beforeElement.next + for _, value := range values { + newElement := &element{value: value} + beforeElement.next = newElement + beforeElement = newElement + } + beforeElement.next = oldNextElement + } +} + func (list *List) String() string { str := "DoublyLinkedList\n" values := []string{} diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 0c78c7ba..528b00fc 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -27,6 +27,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package doublylinkedlist import ( + "fmt" "github.com/emirpasic/gods/utils" "testing" ) @@ -122,6 +123,19 @@ func TestDoublyLinkedList(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, true) } + list.Insert(0, "h") + list.Insert(0, "e") + list.Insert(1, "f") + list.Insert(2, "g") + list.Insert(4, "i") + list.Insert(0, "a", "b") + list.Insert(list.Size(), "j", "k") + list.Insert(2, "c", "d") + + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s%s", list.Values()...), "abcdefghijk"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } func BenchmarkDoublyLinkedList(b *testing.B) { From 56b8a594888a2a02f77b46333242e56a09aedc2b Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 21 Jun 2016 03:39:47 +0200 Subject: [PATCH 019/320] - update all lists to use "value" terminology for coherence, e.g. Add(values...) rather than Add(elements...) --- README.md | 12 +++++----- lists/arraylist/arraylist.go | 26 +++++++++++----------- lists/doublylinkedlist/doublylinkedlist.go | 2 +- lists/lists.go | 6 ++--- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 6897e396..deed77be 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ func main() { ####Lists -A list is a data structure that can store elements and may have repeated values. There is no ordering in a list. The user can access and remove an element by the index position. +A list is a data structure that can store values and may have repeated values. There is no ordering in a list. The user can access and remove a value by the index position. All lists implement the list interface with the following methods: @@ -134,11 +134,11 @@ All lists implement the list interface with the following methods: type Interface interface { Get(index int) (interface{}, bool) Remove(index int) - Add(elements ...interface{}) - Contains(elements ...interface{}) bool + Add(values ...interface{}) + Contains(values ...interface{}) bool Sort(comparator utils.Comparator) Swap(index1, index2 int) - Insert(index int, elements ...interface{}) + Insert(index int, values ...interface{}) containers.Interface // Empty() bool @@ -188,7 +188,7 @@ func main() { #####SinglyLinkedList -This structure implements the _List_ interface and is a linked data structure where each element points to the next in the list. +This structure implements the _List_ interface and is a linked data structure where each value points to the next in the list. Direct access method _Get(index)_ and _Remove()_ are of linear performance. _Append_ and _Prepend_ are of constant time performance. Checking with _Contains()_ is of quadratic complexity. @@ -225,7 +225,7 @@ func main() { #####DoublyLinkedList -This structure implements the _List_ interface and is a linked data structure where each element points to the next and previous element in the list. +This structure implements the _List_ interface and is a linked data structure where each value points to the next and previous element in the list. Direct access method _Get(index)_ and _Remove()_ are of linear performance. _Append_ and _Prepend_ are of constant time performance. Checking with _Contains()_ is of quadratic complexity. diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index c3b9f0ff..278f153a 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -57,10 +57,10 @@ func New() *List { } // Appends a value at the end of the list -func (list *List) Add(elements ...interface{}) { - list.growBy(len(elements)) - for _, element := range elements { - list.elements[list.size] = element +func (list *List) Add(values ...interface{}) { + list.growBy(len(values)) + for _, value := range values { + list.elements[list.size] = value list.size += 1 } } @@ -94,12 +94,12 @@ func (list *List) Remove(index int) { // All elements have to be present in the set for the method to return true. // Performance time complexity of n^2. // Returns true if no arguments are passed at all, i.e. set is always super-set of empty set. -func (list *List) Contains(elements ...interface{}) bool { +func (list *List) Contains(values ...interface{}) bool { - for _, searchElement := range elements { + for _, searchValue := range values { found := false for _, element := range list.elements { - if element == searchElement { + if element == searchValue { found = true break } @@ -142,7 +142,7 @@ func (list *List) Sort(comparator utils.Comparator) { utils.Sort(list.elements[:list.size], comparator) } -// Swaps values of two elements at the given indices. +// Swaps the two values at the specified positions. func (list *List) Swap(i, j int) { if list.withinRange(i) && list.withinRange(j) { list.elements[i], list.elements[j] = list.elements[j], list.elements[i] @@ -152,17 +152,17 @@ func (list *List) Swap(i, j int) { // Inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right. // Does not do anything if position is negative or bigger than list's size // Note: position equal to list's size is valid, i.e. append. -func (list *List) Insert(index int, elements ...interface{}) { +func (list *List) Insert(index int, values ...interface{}) { if !list.withinRange(index) { // Append if index == list.size { - list.Add(elements...) + list.Add(values...) } return } - l := len(elements) + l := len(values) list.growBy(l) list.size += l // Shift old to right @@ -170,8 +170,8 @@ func (list *List) Insert(index int, elements ...interface{}) { list.elements[i] = list.elements[i-l] } // Insert new - for i, element := range elements { - list.elements[index+i] = element + for i, value := range values { + list.elements[index+i] = value } } diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index b948d8bb..b679797c 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -310,5 +310,5 @@ func (list *List) String() string { // Check that the index is withing bounds of the list func (list *List) withinRange(index int) bool { - return index >= 0 && index < list.size && list.size != 0 + return index >= 0 && index < list.size } diff --git a/lists/lists.go b/lists/lists.go index 7de3cb0f..5a83a4c2 100644 --- a/lists/lists.go +++ b/lists/lists.go @@ -26,11 +26,11 @@ import ( type Interface interface { Get(index int) (interface{}, bool) Remove(index int) - Add(elements ...interface{}) - Contains(elements ...interface{}) bool + Add(values ...interface{}) + Contains(values ...interface{}) bool Sort(comparator utils.Comparator) Swap(index1, index2 int) - Insert(index int, elements ...interface{}) + Insert(index int, values ...interface{}) containers.Interface // Empty() bool From 04706e8d03ffb3229c2e9fdd972c4d74a4604791 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 21 Jun 2016 05:31:00 +0200 Subject: [PATCH 020/320] - start on enumarables (arraylist implemented) --- enumerable/enumerable.go | 57 ++++++++++++++++++++++++++++++++++++ lists/arraylist/arraylist.go | 54 ++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 enumerable/enumerable.go diff --git a/enumerable/enumerable.go b/enumerable/enumerable.go new file mode 100644 index 00000000..9e76e43c --- /dev/null +++ b/enumerable/enumerable.go @@ -0,0 +1,57 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// Enumerable functions for ordered containers. +// Ruby's enumerable inspired package. + +package enumerable + +import "github.com/emirpasic/gods/containers" + +type Interface interface { + // Calls the given function once for each element, passing that element's index(key) and value. + Each(func(index interface{}, value interface{})) + + // Invokes the given function once for each element and returns a + // container containing the values returned by the given function. + Map(func(index interface{}, value interface{}) interface{}) containers.Interface + + // Returns a new container containing all elements for which the given function returns a true value. + Select(func(index interface{}, value interface{}) bool) containers.Interface + + // Passes each element of the collection to the given function and + // returns true if the function ever returns true for any element. + Any(func(index interface{}, value interface{}) bool) bool + + // Passes each element of the collection to the given function and + // returns true if the function returns true for all elements. + All(func(index interface{}, value interface{}) bool) bool + + // Passes each element of the collection to the given function and returns + // the first for which the function is true or nil,nil otherwise if no element + // matches the criteria. + Find(func(index interface{}, value interface{}) bool) (index interface{}, value interface{}) +} diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index 278f153a..60d25f90 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -32,6 +32,8 @@ package arraylist import ( "fmt" + "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/enumerable" "github.com/emirpasic/gods/lists" "github.com/emirpasic/gods/utils" "strings" @@ -39,6 +41,7 @@ import ( func assertInterfaceImplementation() { var _ lists.Interface = (*List)(nil) + var _ enumerable.Interface = (*List)(nil) } type List struct { @@ -175,6 +178,57 @@ func (list *List) Insert(index int, values ...interface{}) { } } +func (list *List) Each(f func(index interface{}, value interface{})) { + for i := 0; i < list.size; i++ { + f(i, list.elements[i]) + } +} + +func (list *List) Map(f func(index interface{}, value interface{}) interface{}) containers.Interface { + newList := &List{} + for i := 0; i < list.size; i++ { + newList.Add(f(i, list.elements[i])) + } + return newList +} + +func (list *List) Select(f func(index interface{}, value interface{}) bool) containers.Interface { + newList := &List{} + for i := 0; i < list.size; i++ { + if f(i, list.elements[i]) { + newList.Add(list.elements[i]) + } + } + return newList +} + +func (list *List) Any(f func(index interface{}, value interface{}) bool) bool { + for i := 0; i < list.size; i++ { + if f(i, list.elements[i]) { + return true + } + } + return false +} + +func (list *List) All(f func(index interface{}, value interface{}) bool) bool { + for i := 0; i < list.size; i++ { + if !f(i, list.elements[i]) { + return false + } + } + return true +} + +func (list *List) Find(f func(index interface{}, value interface{}) bool) (index interface{}, value interface{}) { + for i := 0; i < list.size; i++ { + if f(i, list.elements[i]) { + return i, list.elements[i] + } + } + return nil, nil +} + func (list *List) String() string { str := "ArrayList\n" values := []string{} From 69dacb6c69a762c4f1a3090a30b8e7b85da562bd Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 00:05:22 +0200 Subject: [PATCH 021/320] - remove debugging info --- lists/doublylinkedlist/doublylinkedlist.go | 1 - lists/singlylinkedlist/singlylinkedlist.go | 1 - 2 files changed, 2 deletions(-) diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index b679797c..2a97756b 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -254,7 +254,6 @@ func (list *List) Insert(index int, values ...interface{}) { if index == list.size { list.Add(values...) } - fmt.Println(list.Values()) return } diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index e4730aeb..f993c39b 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -233,7 +233,6 @@ func (list *List) Insert(index int, values ...interface{}) { if index == list.size { list.Add(values...) } - fmt.Println(list.Values()) return } From 3b3edfc5394cbae2e579161cb3f479b0390410a4 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 03:09:48 +0200 Subject: [PATCH 022/320] - naming conventions (calling interfaces by what they are) --- containers/containers.go | 4 +-- {enumerable => containers}/enumerable.go | 10 +++---- containers/iterator.go | 35 ++++++++++++++++++++++ lists/arraylist/arraylist.go | 32 ++++++++++++++++---- lists/doublylinkedlist/doublylinkedlist.go | 2 +- lists/lists.go | 4 +-- lists/singlylinkedlist/singlylinkedlist.go | 2 +- maps/hashmap/hashmap.go | 2 +- maps/maps.go | 4 +-- maps/treemap/treemap.go | 2 +- sets/hashset/hashset.go | 2 +- sets/sets.go | 4 +-- sets/treeset/treeset.go | 2 +- stacks/arraystack/arraystack.go | 2 +- stacks/linkedliststack/linkedliststack.go | 2 +- stacks/stacks.go | 4 +-- trees/binaryheap/binaryheap.go | 2 +- trees/redblacktree/redblacktree.go | 2 +- trees/trees.go | 4 +-- 19 files changed, 87 insertions(+), 34 deletions(-) rename {enumerable => containers}/enumerable.go (90%) create mode 100644 containers/iterator.go diff --git a/containers/containers.go b/containers/containers.go index 48e9b15f..2da6c26a 100644 --- a/containers/containers.go +++ b/containers/containers.go @@ -30,7 +30,7 @@ package containers import "github.com/emirpasic/gods/utils" -type Interface interface { +type Container interface { Empty() bool Size() int Clear() @@ -40,7 +40,7 @@ type Interface interface { // Returns sorted container's elements with respect to the passed comparator. // Does not effect the ordering of elements within the container. // Uses timsort. -func GetSortedValues(container Interface, comparator utils.Comparator) []interface{} { +func GetSortedValues(container Container, comparator utils.Comparator) []interface{} { values := container.Values() if len(values) < 2 { return values diff --git a/enumerable/enumerable.go b/containers/enumerable.go similarity index 90% rename from enumerable/enumerable.go rename to containers/enumerable.go index 9e76e43c..bb736abc 100644 --- a/enumerable/enumerable.go +++ b/containers/enumerable.go @@ -27,20 +27,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Enumerable functions for ordered containers. // Ruby's enumerable inspired package. -package enumerable +package containers -import "github.com/emirpasic/gods/containers" - -type Interface interface { +type Enumerable interface { // Calls the given function once for each element, passing that element's index(key) and value. Each(func(index interface{}, value interface{})) // Invokes the given function once for each element and returns a // container containing the values returned by the given function. - Map(func(index interface{}, value interface{}) interface{}) containers.Interface + Map(func(index interface{}, value interface{}) interface{}) Container // Returns a new container containing all elements for which the given function returns a true value. - Select(func(index interface{}, value interface{}) bool) containers.Interface + Select(func(index interface{}, value interface{}) bool) Container // Passes each element of the collection to the given function and // returns true if the function ever returns true for any element. diff --git a/containers/iterator.go b/containers/iterator.go new file mode 100644 index 00000000..513a04fd --- /dev/null +++ b/containers/iterator.go @@ -0,0 +1,35 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// Stateful iterator pattern for ordered containers. + +package containers + +type Iterator interface { + Next() bool + Value() interface{} + Index() interface{} +} diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index 60d25f90..ca01d415 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -33,15 +33,15 @@ package arraylist import ( "fmt" "github.com/emirpasic/gods/containers" - "github.com/emirpasic/gods/enumerable" "github.com/emirpasic/gods/lists" "github.com/emirpasic/gods/utils" "strings" ) func assertInterfaceImplementation() { - var _ lists.Interface = (*List)(nil) - var _ enumerable.Interface = (*List)(nil) + var _ lists.List = (*List)(nil) + var _ containers.Enumerable = (*List)(nil) + var _ containers.Iterator = (*Iterator)(nil) } type List struct { @@ -49,6 +49,27 @@ type List struct { size int } +type Iterator struct { + list *List + current int +} + +func (list *List) Iterator() Iterator { + return Iterator{list: list, current: 0} +} + +func (iterator *Iterator) Next() bool { + return false +} + +func (iterator *Iterator) Value() interface{} { + return nil +} + +func (iterator *Iterator) Index() interface{} { + return nil +} + const ( GROWTH_FACTOR = float32(2.0) // growth by 100% SHRINK_FACTOR = float32(0.25) // shrink when size is 25% of capacity (0 means never shrink) @@ -184,7 +205,7 @@ func (list *List) Each(f func(index interface{}, value interface{})) { } } -func (list *List) Map(f func(index interface{}, value interface{}) interface{}) containers.Interface { +func (list *List) Map(f func(index interface{}, value interface{}) interface{}) containers.Container { newList := &List{} for i := 0; i < list.size; i++ { newList.Add(f(i, list.elements[i])) @@ -192,7 +213,7 @@ func (list *List) Map(f func(index interface{}, value interface{}) interface{}) return newList } -func (list *List) Select(f func(index interface{}, value interface{}) bool) containers.Interface { +func (list *List) Select(f func(index interface{}, value interface{}) bool) containers.Container { newList := &List{} for i := 0; i < list.size; i++ { if f(i, list.elements[i]) { @@ -270,5 +291,4 @@ func (list *List) shrink() { if list.size <= int(float32(currentCapacity)*SHRINK_FACTOR) { list.resize(list.size) } - } diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 2a97756b..281bda1c 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -38,7 +38,7 @@ import ( ) func assertInterfaceImplementation() { - var _ lists.Interface = (*List)(nil) + var _ lists.List = (*List)(nil) } type List struct { diff --git a/lists/lists.go b/lists/lists.go index 5a83a4c2..8bc05757 100644 --- a/lists/lists.go +++ b/lists/lists.go @@ -23,7 +23,7 @@ import ( "github.com/emirpasic/gods/utils" ) -type Interface interface { +type List interface { Get(index int) (interface{}, bool) Remove(index int) Add(values ...interface{}) @@ -32,7 +32,7 @@ type Interface interface { Swap(index1, index2 int) Insert(index int, values ...interface{}) - containers.Interface + containers.Container // Empty() bool // Size() int // Clear() diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index f993c39b..47ab9b20 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -38,7 +38,7 @@ import ( ) func assertInterfaceImplementation() { - var _ lists.Interface = (*List)(nil) + var _ lists.List = (*List)(nil) } type List struct { diff --git a/maps/hashmap/hashmap.go b/maps/hashmap/hashmap.go index 247cc016..3033f6bf 100644 --- a/maps/hashmap/hashmap.go +++ b/maps/hashmap/hashmap.go @@ -37,7 +37,7 @@ import ( ) func assertInterfaceImplementation() { - var _ maps.Interface = (*Map)(nil) + var _ maps.Map = (*Map)(nil) } type Map struct { diff --git a/maps/maps.go b/maps/maps.go index eddcc20e..22fcf73b 100644 --- a/maps/maps.go +++ b/maps/maps.go @@ -28,13 +28,13 @@ package maps import "github.com/emirpasic/gods/containers" -type Interface interface { +type Map interface { Put(key interface{}, value interface{}) Get(key interface{}) (value interface{}, found bool) Remove(key interface{}) Keys() []interface{} - containers.Interface + containers.Container // Empty() bool // Size() int // Clear() diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index 6d228cbb..d0fc742f 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -38,7 +38,7 @@ import ( ) func assertInterfaceImplementation() { - var _ maps.Interface = (*Map)(nil) + var _ maps.Map = (*Map)(nil) } type Map struct { diff --git a/sets/hashset/hashset.go b/sets/hashset/hashset.go index dfd1069f..54d219be 100644 --- a/sets/hashset/hashset.go +++ b/sets/hashset/hashset.go @@ -37,7 +37,7 @@ import ( ) func assertInterfaceImplementation() { - var _ sets.Interface = (*Set)(nil) + var _ sets.Set = (*Set)(nil) } type Set struct { diff --git a/sets/sets.go b/sets/sets.go index 2a6e2dc1..6ced9039 100644 --- a/sets/sets.go +++ b/sets/sets.go @@ -20,12 +20,12 @@ package sets import "github.com/emirpasic/gods/containers" -type Interface interface { +type Set interface { Add(elements ...interface{}) Remove(elements ...interface{}) Contains(elements ...interface{}) bool - containers.Interface + containers.Container // Empty() bool // Size() int // Clear() diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 9236eb1d..da6d7d9b 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -31,7 +31,7 @@ import ( ) func assertInterfaceImplementation() { - var _ sets.Interface = (*Set)(nil) + var _ sets.Set = (*Set)(nil) } type Set struct { diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index bb3a89da..407cdf0d 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -38,7 +38,7 @@ import ( ) func assertInterfaceImplementation() { - var _ stacks.Interface = (*Stack)(nil) + var _ stacks.Stack = (*Stack)(nil) } type Stack struct { diff --git a/stacks/linkedliststack/linkedliststack.go b/stacks/linkedliststack/linkedliststack.go index bf96b4c8..5cc08e62 100644 --- a/stacks/linkedliststack/linkedliststack.go +++ b/stacks/linkedliststack/linkedliststack.go @@ -39,7 +39,7 @@ import ( ) func assertInterfaceImplementation() { - var _ stacks.Interface = (*Stack)(nil) + var _ stacks.Stack = (*Stack)(nil) } type Stack struct { diff --git a/stacks/stacks.go b/stacks/stacks.go index fe9abbbf..1f504be6 100644 --- a/stacks/stacks.go +++ b/stacks/stacks.go @@ -28,12 +28,12 @@ package stacks import "github.com/emirpasic/gods/containers" -type Interface interface { +type Stack interface { Push(value interface{}) Pop() (value interface{}, ok bool) Peek() (value interface{}, ok bool) - containers.Interface + containers.Container // Empty() bool // Size() int // Clear() diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index 79f91b1b..9320fc43 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -40,7 +40,7 @@ import ( ) func assertInterfaceImplementation() { - var _ trees.Interface = (*Heap)(nil) + var _ trees.Tree = (*Heap)(nil) } type Heap struct { diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 2fe165b2..3811fb2c 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -39,7 +39,7 @@ import ( ) func assertInterfaceImplementation() { - var _ trees.Interface = (*Tree)(nil) + var _ trees.Tree = (*Tree)(nil) } type color bool diff --git a/trees/trees.go b/trees/trees.go index 3714bee0..0a021dd8 100644 --- a/trees/trees.go +++ b/trees/trees.go @@ -28,8 +28,8 @@ package trees import "github.com/emirpasic/gods/containers" -type Interface interface { - containers.Interface +type Tree interface { + containers.Container // Empty() bool // Size() int // Clear() From 342ccbef84f6e9455423452a681fa44d43848761 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 03:15:08 +0200 Subject: [PATCH 023/320] - naming conventions (calling interfaces by what they are) --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index deed77be..6d6b9488 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Implementation of various data structures in Go. All data structures implement the container interface with the following methods: ```go -type Interface interface { +type Container interface { Empty() bool Size() int Clear() @@ -47,7 +47,7 @@ Container specific operations: // Returns sorted container's elements with respect to the passed comparator. // Does not effect the ordering of elements within the container. // Uses timsort. -func GetSortedValues(container Interface, comparator utils.Comparator) []interface{} { +func GetSortedValues(container Container, comparator utils.Comparator) []interface{} { ``` ####Sets @@ -57,12 +57,12 @@ A set is a data structure that can store elements and no repeated values. It is All sets implement the set interface with the following methods: ```go -type Interface interface { +type Set interface { Add(elements ...interface{}) Remove(elements ...interface{}) Contains(elements ...interface{}) bool - containers.Interface + containers.Container // Empty() bool // Size() int // Clear() @@ -131,7 +131,7 @@ A list is a data structure that can store values and may have repeated values. T All lists implement the list interface with the following methods: ```go -type Interface interface { +type List interface { Get(index int) (interface{}, bool) Remove(index int) Add(values ...interface{}) @@ -140,7 +140,7 @@ type Interface interface { Swap(index1, index2 int) Insert(index int, values ...interface{}) - containers.Interface + containers.Container // Empty() bool // Size() int // Clear() @@ -267,12 +267,12 @@ The stack interface represents a last-in-first-out (LIFO) collection of objects. All stacks implement the stack interface with the following methods: ```go -type Interface interface { +type Stack interface { Push(value interface{}) Pop() (value interface{}, ok bool) Peek() (value interface{}, ok bool) - containers.Interface + containers.Container // Empty() bool // Size() int // Clear() @@ -340,13 +340,13 @@ Structure that maps keys to values. A map cannot contain duplicate keys and each All maps implement the map interface with the following methods: ```go -type Interface interface { +type Map interface { Put(key interface{}, value interface{}) Get(key interface{}) (value interface{}, found bool) Remove(key interface{}) Keys() []interface{} - containers.Interface + containers.Container // Empty() bool // Size() int // Clear() @@ -420,8 +420,8 @@ A tree is a widely used data data structure that simulates a hierarchical tree s All trees implement the tree interface with the following methods: ```go -type Interface interface { - containers.Interface +type Tree interface { + containers.Container // Empty() bool // Size() int // Clear() From 8eefb7e191f62f365db38208dd7293b14f191ea5 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 03:27:43 +0200 Subject: [PATCH 024/320] Update .travis.yml --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index ff2c2cd1..5cae7fe7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,3 +2,6 @@ language: go go: - 1.4 - tip +branches: + except: + - master From 67a965af0c6cea0c9058846048084856e9d699d5 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 03:34:53 +0200 Subject: [PATCH 025/320] Update .travis.yml --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5cae7fe7..ff2c2cd1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,3 @@ language: go go: - 1.4 - tip -branches: - except: - - master From 6fefe7cc249372bdb5f3db7a099da116e842a28c Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 03:42:35 +0200 Subject: [PATCH 026/320] - iterator tests - container_test fix --- containers/containers_test.go | 14 +++++++------- lists/arraylist/arraylist.go | 23 ++++++++++++----------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/containers/containers_test.go b/containers/containers_test.go index bef88f42..a2da7193 100644 --- a/containers/containers_test.go +++ b/containers/containers_test.go @@ -34,28 +34,28 @@ import ( ) // For testing purposes -type Container struct { +type ContainerTest struct { values []interface{} } -func (container Container) Empty() bool { +func (container ContainerTest) Empty() bool { return len(container.values) == 0 } -func (container Container) Size() int { +func (container ContainerTest) Size() int { return len(container.values) } -func (container Container) Clear() { +func (container ContainerTest) Clear() { container.values = []interface{}{} } -func (container Container) Values() []interface{} { +func (container ContainerTest) Values() []interface{} { return container.values } func TestGetSortedValuesInts(t *testing.T) { - container := Container{} + container := ContainerTest{} container.values = []interface{}{5, 1, 3, 2, 4} values := GetSortedValues(container, utils.IntComparator) for i := 1; i < container.Size(); i++ { @@ -66,7 +66,7 @@ func TestGetSortedValuesInts(t *testing.T) { } func TestGetSortedValuesStrings(t *testing.T) { - container := Container{} + container := ContainerTest{} container.values = []interface{}{"g", "a", "d", "e", "f", "c", "b"} values := GetSortedValues(container, utils.StringComparator) for i := 1; i < container.Size(); i++ { diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index ca01d415..bdcf1ad7 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -55,19 +55,20 @@ type Iterator struct { } func (list *List) Iterator() Iterator { - return Iterator{list: list, current: 0} + return Iterator{list: list, current: -1} } func (iterator *Iterator) Next() bool { - return false + iterator.current += 1 + return iterator.list.withinRange(iterator.current) } func (iterator *Iterator) Value() interface{} { - return nil + return iterator.list.elements[iterator.current] } func (iterator *Iterator) Index() interface{} { - return nil + return iterator.list.elements[iterator.current] } const ( @@ -108,7 +109,7 @@ func (list *List) Remove(index int) { } list.elements[index] = nil // cleanup reference - copy(list.elements[index:], list.elements[index+1:list.size]) // shift to the left by one (slow operation, need ways to optimize this) + copy(list.elements[index:], list.elements[index + 1:list.size]) // shift to the left by one (slow operation, need ways to optimize this) list.size -= 1 list.shrink() @@ -190,12 +191,12 @@ func (list *List) Insert(index int, values ...interface{}) { list.growBy(l) list.size += l // Shift old to right - for i := list.size - 1; i >= index+l; i-- { - list.elements[i] = list.elements[i-l] + for i := list.size - 1; i >= index + l; i-- { + list.elements[i] = list.elements[i - l] } // Insert new for i, value := range values { - list.elements[index+i] = value + list.elements[index + i] = value } } @@ -275,8 +276,8 @@ func (list *List) resize(cap int) { func (list *List) growBy(n int) { // When capacity is reached, grow by a factor of GROWTH_FACTOR and add number of elements currentCapacity := cap(list.elements) - if list.size+n >= currentCapacity { - newCapacity := int(GROWTH_FACTOR * float32(currentCapacity+n)) + if list.size + n >= currentCapacity { + newCapacity := int(GROWTH_FACTOR * float32(currentCapacity + n)) list.resize(newCapacity) } } @@ -288,7 +289,7 @@ func (list *List) shrink() { } // Shrink when size is at SHRINK_FACTOR * capacity currentCapacity := cap(list.elements) - if list.size <= int(float32(currentCapacity)*SHRINK_FACTOR) { + if list.size <= int(float32(currentCapacity) * SHRINK_FACTOR) { list.resize(list.size) } } From 549ece11005b54a6d4b07e4ecdefdeb944040de8 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 04:53:38 +0200 Subject: [PATCH 027/320] - iterator implementation - tests for arraylist enumerable operations --- containers/iterator.go | 3 + lists/arraylist/arraylist.go | 58 +++++++------- lists/arraylist/arraylist_test.go | 126 ++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 29 deletions(-) diff --git a/containers/iterator.go b/containers/iterator.go index 513a04fd..0dcb829b 100644 --- a/containers/iterator.go +++ b/containers/iterator.go @@ -29,7 +29,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package containers type Iterator interface { + // Moves the iterator to the next element and returns true if there was a next element in the container. Next() bool + // Returns the current element's value. Value() interface{} + // Returns the current element's index(key). Index() interface{} } diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index bdcf1ad7..ff3f51d5 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -49,28 +49,6 @@ type List struct { size int } -type Iterator struct { - list *List - current int -} - -func (list *List) Iterator() Iterator { - return Iterator{list: list, current: -1} -} - -func (iterator *Iterator) Next() bool { - iterator.current += 1 - return iterator.list.withinRange(iterator.current) -} - -func (iterator *Iterator) Value() interface{} { - return iterator.list.elements[iterator.current] -} - -func (iterator *Iterator) Index() interface{} { - return iterator.list.elements[iterator.current] -} - const ( GROWTH_FACTOR = float32(2.0) // growth by 100% SHRINK_FACTOR = float32(0.25) // shrink when size is 25% of capacity (0 means never shrink) @@ -109,7 +87,7 @@ func (list *List) Remove(index int) { } list.elements[index] = nil // cleanup reference - copy(list.elements[index:], list.elements[index + 1:list.size]) // shift to the left by one (slow operation, need ways to optimize this) + copy(list.elements[index:], list.elements[index+1:list.size]) // shift to the left by one (slow operation, need ways to optimize this) list.size -= 1 list.shrink() @@ -191,12 +169,12 @@ func (list *List) Insert(index int, values ...interface{}) { list.growBy(l) list.size += l // Shift old to right - for i := list.size - 1; i >= index + l; i-- { - list.elements[i] = list.elements[i - l] + for i := list.size - 1; i >= index+l; i-- { + list.elements[i] = list.elements[i-l] } // Insert new for i, value := range values { - list.elements[index + i] = value + list.elements[index+i] = value } } @@ -251,6 +229,28 @@ func (list *List) Find(f func(index interface{}, value interface{}) bool) (index return nil, nil } +type Iterator struct { + list *List + current int +} + +func (list *List) Iterator() Iterator { + return Iterator{list: list, current: -1} +} + +func (iterator *Iterator) Next() bool { + iterator.current += 1 + return iterator.list.withinRange(iterator.current) +} + +func (iterator *Iterator) Value() interface{} { + return iterator.list.elements[iterator.current] +} + +func (iterator *Iterator) Index() interface{} { + return iterator.current +} + func (list *List) String() string { str := "ArrayList\n" values := []string{} @@ -276,8 +276,8 @@ func (list *List) resize(cap int) { func (list *List) growBy(n int) { // When capacity is reached, grow by a factor of GROWTH_FACTOR and add number of elements currentCapacity := cap(list.elements) - if list.size + n >= currentCapacity { - newCapacity := int(GROWTH_FACTOR * float32(currentCapacity + n)) + if list.size+n >= currentCapacity { + newCapacity := int(GROWTH_FACTOR * float32(currentCapacity+n)) list.resize(newCapacity) } } @@ -289,7 +289,7 @@ func (list *List) shrink() { } // Shrink when size is at SHRINK_FACTOR * capacity currentCapacity := cap(list.elements) - if list.size <= int(float32(currentCapacity) * SHRINK_FACTOR) { + if list.size <= int(float32(currentCapacity)*SHRINK_FACTOR) { list.resize(list.size) } } diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index ab07f677..ac256878 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -136,6 +136,132 @@ func TestArrayList(t *testing.T) { } +func TestArrayListEnumerableAndIterator(t *testing.T) { + list := New() + list.Add("a", "b", "c") + + // Each + list.Each(func(index interface{}, value interface{}) { + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + }) + + // Map + mappedList := list.Map(func(index interface{}, value interface{}) interface{} { + return "mapped: " + value.(string) + }).(*List) + if actualValue, _ := mappedList.Get(0); actualValue != "mapped: a" { + t.Errorf("Got %v expected %v", actualValue, "mapped: a") + } + if actualValue, _ := mappedList.Get(1); actualValue != "mapped: b" { + t.Errorf("Got %v expected %v", actualValue, "mapped: b") + } + if actualValue, _ := mappedList.Get(2); actualValue != "mapped: c" { + t.Errorf("Got %v expected %v", actualValue, "mapped: c") + } + if mappedList.Size() != 3 { + t.Errorf("Got %v expected %v", mappedList.Size(), 3) + } + + // Select + selectedList := list.Select(func(index interface{}, value interface{}) bool { + return value.(string) >= "a" && value.(string) <= "b" + }).(*List) + if actualValue, _ := selectedList.Get(0); actualValue != "a" { + t.Errorf("Got %v expected %v", actualValue, "value: a") + } + if actualValue, _ := selectedList.Get(1); actualValue != "b" { + t.Errorf("Got %v expected %v", actualValue, "value: b") + } + if selectedList.Size() != 2 { + t.Errorf("Got %v expected %v", selectedList.Size(), 3) + } + + // Any + any := list.Any(func(index interface{}, value interface{}) bool { + return value.(string) == "c" + }) + if any != true { + t.Errorf("Got %v expected %v", any, true) + } + any = list.Any(func(index interface{}, value interface{}) bool { + return value.(string) == "x" + }) + if any != false { + t.Errorf("Got %v expected %v", any, false) + } + + // All + all := list.All(func(index interface{}, value interface{}) bool { + return value.(string) >= "a" && value.(string) <= "c" + }) + if all != true { + t.Errorf("Got %v expected %v", all, true) + } + all = list.All(func(index interface{}, value interface{}) bool { + return value.(string) >= "a" && value.(string) <= "b" + }) + if all != false { + t.Errorf("Got %v expected %v", all, false) + } + + // Find + foundIndex, foundValue := list.Find(func(index interface{}, value interface{}) bool { + return value.(string) == "c" + }) + if foundValue != "c" || foundIndex != 2 { + t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, "c", 2) + } + foundIndex, foundValue = list.Find(func(index interface{}, value interface{}) bool { + return value.(string) == "x" + }) + if foundValue != nil || foundIndex != nil { + t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil) + } + + // Iterator + it := list.Iterator() + for it.Next() { + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + } + list.Clear() + it = list.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty list") + } +} + func BenchmarkArrayList(b *testing.B) { for i := 0; i < b.N; i++ { list := New() From c685593e6e94fb4658cc3b6d3c0287951c7f7a9f Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 05:11:41 +0200 Subject: [PATCH 028/320] - rewrite enumerable operations using iterator (for easier copy/paste into other containers) --- lists/arraylist/arraylist.go | 68 ++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index ff3f51d5..c0e313f6 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -178,33 +178,54 @@ func (list *List) Insert(index int, values ...interface{}) { } } +func (list *List) Iterator() Iterator { + return Iterator{list: list, current: -1} +} + +func (iterator *Iterator) Next() bool { + iterator.current += 1 + return iterator.list.withinRange(iterator.current) +} + +func (iterator *Iterator) Value() interface{} { + return iterator.list.elements[iterator.current] +} + +func (iterator *Iterator) Index() interface{} { + return iterator.current +} + func (list *List) Each(f func(index interface{}, value interface{})) { - for i := 0; i < list.size; i++ { - f(i, list.elements[i]) + iterator := list.Iterator() + for iterator.Next() { + f(iterator.Index(), iterator.Value()) } } func (list *List) Map(f func(index interface{}, value interface{}) interface{}) containers.Container { newList := &List{} - for i := 0; i < list.size; i++ { - newList.Add(f(i, list.elements[i])) + iterator := list.Iterator() + for iterator.Next() { + newList.Add(f(iterator.Index(), iterator.Value())) } return newList } func (list *List) Select(f func(index interface{}, value interface{}) bool) containers.Container { newList := &List{} - for i := 0; i < list.size; i++ { - if f(i, list.elements[i]) { - newList.Add(list.elements[i]) + iterator := list.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + newList.Add(iterator.Value()) } } return newList } func (list *List) Any(f func(index interface{}, value interface{}) bool) bool { - for i := 0; i < list.size; i++ { - if f(i, list.elements[i]) { + iterator := list.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { return true } } @@ -212,8 +233,9 @@ func (list *List) Any(f func(index interface{}, value interface{}) bool) bool { } func (list *List) All(f func(index interface{}, value interface{}) bool) bool { - for i := 0; i < list.size; i++ { - if !f(i, list.elements[i]) { + iterator := list.Iterator() + for iterator.Next() { + if !f(iterator.Index(), iterator.Value()) { return false } } @@ -221,9 +243,10 @@ func (list *List) All(f func(index interface{}, value interface{}) bool) bool { } func (list *List) Find(f func(index interface{}, value interface{}) bool) (index interface{}, value interface{}) { - for i := 0; i < list.size; i++ { - if f(i, list.elements[i]) { - return i, list.elements[i] + iterator := list.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + return iterator.Index(), iterator.Value() } } return nil, nil @@ -234,23 +257,6 @@ type Iterator struct { current int } -func (list *List) Iterator() Iterator { - return Iterator{list: list, current: -1} -} - -func (iterator *Iterator) Next() bool { - iterator.current += 1 - return iterator.list.withinRange(iterator.current) -} - -func (iterator *Iterator) Value() interface{} { - return iterator.list.elements[iterator.current] -} - -func (iterator *Iterator) Index() interface{} { - return iterator.current -} - func (list *List) String() string { str := "ArrayList\n" values := []string{} From 60c2f3af712d112c95ed4dc290003fd739b8434c Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 05:26:48 +0200 Subject: [PATCH 029/320] - add enumerable and iterator to doubly linked list --- lists/arraylist/arraylist.go | 20 +-- lists/arraylist/arraylist_test.go | 1 - lists/doublylinkedlist/doublylinkedlist.go | 92 +++++++++++++ .../doublylinkedlist/doublylinkedlist_test.go | 125 ++++++++++++++++++ 4 files changed, 227 insertions(+), 11 deletions(-) diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index c0e313f6..059ef3e9 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -178,21 +178,26 @@ func (list *List) Insert(index int, values ...interface{}) { } } +type Iterator struct { + list *List + index int +} + func (list *List) Iterator() Iterator { - return Iterator{list: list, current: -1} + return Iterator{list: list, index: -1} } func (iterator *Iterator) Next() bool { - iterator.current += 1 - return iterator.list.withinRange(iterator.current) + iterator.index += 1 + return iterator.list.withinRange(iterator.index) } func (iterator *Iterator) Value() interface{} { - return iterator.list.elements[iterator.current] + return iterator.list.elements[iterator.index] } func (iterator *Iterator) Index() interface{} { - return iterator.current + return iterator.index } func (list *List) Each(f func(index interface{}, value interface{})) { @@ -252,11 +257,6 @@ func (list *List) Find(f func(index interface{}, value interface{}) bool) (index return nil, nil } -type Iterator struct { - list *List - current int -} - func (list *List) String() string { str := "ArrayList\n" values := []string{} diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index ac256878..2ec424f8 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -133,7 +133,6 @@ func TestArrayList(t *testing.T) { if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s%s", list.Values()...), "abcdefghijk"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - } func TestArrayListEnumerableAndIterator(t *testing.T) { diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 281bda1c..69d6368a 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -32,6 +32,7 @@ package doublylinkedlist import ( "fmt" + "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/lists" "github.com/emirpasic/gods/utils" "strings" @@ -39,6 +40,8 @@ import ( func assertInterfaceImplementation() { var _ lists.List = (*List)(nil) + var _ containers.Enumerable = (*List)(nil) + var _ containers.Iterator = (*Iterator)(nil) } type List struct { @@ -297,6 +300,95 @@ func (list *List) Insert(index int, values ...interface{}) { } } +type Iterator struct { + list *List + index int + element *element +} + +func (list *List) Iterator() Iterator { + return Iterator{list: list, index: -1, element: nil} +} + +func (iterator *Iterator) Next() bool { + iterator.index += 1 + if !iterator.list.withinRange(iterator.index) { + iterator.element = nil + return false + } + if iterator.element == nil { + iterator.element = iterator.list.first + } else { + iterator.element = iterator.element.next + } + return true +} + +func (iterator *Iterator) Value() interface{} { + return iterator.element.value +} + +func (iterator *Iterator) Index() interface{} { + return iterator.index +} + +func (list *List) Each(f func(index interface{}, value interface{})) { + iterator := list.Iterator() + for iterator.Next() { + f(iterator.Index(), iterator.Value()) + } +} + +func (list *List) Map(f func(index interface{}, value interface{}) interface{}) containers.Container { + newList := &List{} + iterator := list.Iterator() + for iterator.Next() { + newList.Add(f(iterator.Index(), iterator.Value())) + } + return newList +} + +func (list *List) Select(f func(index interface{}, value interface{}) bool) containers.Container { + newList := &List{} + iterator := list.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + newList.Add(iterator.Value()) + } + } + return newList +} + +func (list *List) Any(f func(index interface{}, value interface{}) bool) bool { + iterator := list.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + return true + } + } + return false +} + +func (list *List) All(f func(index interface{}, value interface{}) bool) bool { + iterator := list.Iterator() + for iterator.Next() { + if !f(iterator.Index(), iterator.Value()) { + return false + } + } + return true +} + +func (list *List) Find(f func(index interface{}, value interface{}) bool) (index interface{}, value interface{}) { + iterator := list.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + return iterator.Index(), iterator.Value() + } + } + return nil, nil +} + func (list *List) String() string { str := "DoublyLinkedList\n" values := []string{} diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 528b00fc..a5c6dcd9 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -135,7 +135,132 @@ func TestDoublyLinkedList(t *testing.T) { if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s%s", list.Values()...), "abcdefghijk"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } +} + +func TestDoublyLinkedListEnumerableAndIterator(t *testing.T) { + list := New() + list.Add("a", "b", "c") + + // Each + list.Each(func(index interface{}, value interface{}) { + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + }) + + // Map + mappedList := list.Map(func(index interface{}, value interface{}) interface{} { + return "mapped: " + value.(string) + }).(*List) + if actualValue, _ := mappedList.Get(0); actualValue != "mapped: a" { + t.Errorf("Got %v expected %v", actualValue, "mapped: a") + } + if actualValue, _ := mappedList.Get(1); actualValue != "mapped: b" { + t.Errorf("Got %v expected %v", actualValue, "mapped: b") + } + if actualValue, _ := mappedList.Get(2); actualValue != "mapped: c" { + t.Errorf("Got %v expected %v", actualValue, "mapped: c") + } + if mappedList.Size() != 3 { + t.Errorf("Got %v expected %v", mappedList.Size(), 3) + } + + // Select + selectedList := list.Select(func(index interface{}, value interface{}) bool { + return value.(string) >= "a" && value.(string) <= "b" + }).(*List) + if actualValue, _ := selectedList.Get(0); actualValue != "a" { + t.Errorf("Got %v expected %v", actualValue, "value: a") + } + if actualValue, _ := selectedList.Get(1); actualValue != "b" { + t.Errorf("Got %v expected %v", actualValue, "value: b") + } + if selectedList.Size() != 2 { + t.Errorf("Got %v expected %v", selectedList.Size(), 3) + } + // Any + any := list.Any(func(index interface{}, value interface{}) bool { + return value.(string) == "c" + }) + if any != true { + t.Errorf("Got %v expected %v", any, true) + } + any = list.Any(func(index interface{}, value interface{}) bool { + return value.(string) == "x" + }) + if any != false { + t.Errorf("Got %v expected %v", any, false) + } + + // All + all := list.All(func(index interface{}, value interface{}) bool { + return value.(string) >= "a" && value.(string) <= "c" + }) + if all != true { + t.Errorf("Got %v expected %v", all, true) + } + all = list.All(func(index interface{}, value interface{}) bool { + return value.(string) >= "a" && value.(string) <= "b" + }) + if all != false { + t.Errorf("Got %v expected %v", all, false) + } + + // Find + foundIndex, foundValue := list.Find(func(index interface{}, value interface{}) bool { + return value.(string) == "c" + }) + if foundValue != "c" || foundIndex != 2 { + t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, "c", 2) + } + foundIndex, foundValue = list.Find(func(index interface{}, value interface{}) bool { + return value.(string) == "x" + }) + if foundValue != nil || foundIndex != nil { + t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil) + } + + // Iterator + it := list.Iterator() + for it.Next() { + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + } + list.Clear() + it = list.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty list") + } } func BenchmarkDoublyLinkedList(b *testing.B) { From 76f36e4980dc89fe8047b774c26be6bc6a9e4f5b Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 05:29:21 +0200 Subject: [PATCH 030/320] - add enumerable and iterator to singly linked list --- lists/singlylinkedlist/singlylinkedlist.go | 92 +++++++++++++ .../singlylinkedlist/singlylinkedlist_test.go | 125 ++++++++++++++++++ 2 files changed, 217 insertions(+) diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 47ab9b20..69177b33 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -32,6 +32,7 @@ package singlylinkedlist import ( "fmt" + "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/lists" "github.com/emirpasic/gods/utils" "strings" @@ -39,6 +40,8 @@ import ( func assertInterfaceImplementation() { var _ lists.List = (*List)(nil) + var _ containers.Enumerable = (*List)(nil) + var _ containers.Iterator = (*Iterator)(nil) } type List struct { @@ -267,6 +270,95 @@ func (list *List) Insert(index int, values ...interface{}) { } } +type Iterator struct { + list *List + index int + element *element +} + +func (list *List) Iterator() Iterator { + return Iterator{list: list, index: -1, element: nil} +} + +func (iterator *Iterator) Next() bool { + iterator.index += 1 + if !iterator.list.withinRange(iterator.index) { + iterator.element = nil + return false + } + if iterator.element == nil { + iterator.element = iterator.list.first + } else { + iterator.element = iterator.element.next + } + return true +} + +func (iterator *Iterator) Value() interface{} { + return iterator.element.value +} + +func (iterator *Iterator) Index() interface{} { + return iterator.index +} + +func (list *List) Each(f func(index interface{}, value interface{})) { + iterator := list.Iterator() + for iterator.Next() { + f(iterator.Index(), iterator.Value()) + } +} + +func (list *List) Map(f func(index interface{}, value interface{}) interface{}) containers.Container { + newList := &List{} + iterator := list.Iterator() + for iterator.Next() { + newList.Add(f(iterator.Index(), iterator.Value())) + } + return newList +} + +func (list *List) Select(f func(index interface{}, value interface{}) bool) containers.Container { + newList := &List{} + iterator := list.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + newList.Add(iterator.Value()) + } + } + return newList +} + +func (list *List) Any(f func(index interface{}, value interface{}) bool) bool { + iterator := list.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + return true + } + } + return false +} + +func (list *List) All(f func(index interface{}, value interface{}) bool) bool { + iterator := list.Iterator() + for iterator.Next() { + if !f(iterator.Index(), iterator.Value()) { + return false + } + } + return true +} + +func (list *List) Find(f func(index interface{}, value interface{}) bool) (index interface{}, value interface{}) { + iterator := list.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + return iterator.Index(), iterator.Value() + } + } + return nil, nil +} + func (list *List) String() string { str := "SinglyLinkedList\n" values := []string{} diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index df084665..48508e7e 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -135,7 +135,132 @@ func TestSinglyLinkedList(t *testing.T) { if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s%s", list.Values()...), "abcdefghijk"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } +} + +func TestSinglyLinkedListEnumerableAndIterator(t *testing.T) { + list := New() + list.Add("a", "b", "c") + + // Each + list.Each(func(index interface{}, value interface{}) { + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + }) + + // Map + mappedList := list.Map(func(index interface{}, value interface{}) interface{} { + return "mapped: " + value.(string) + }).(*List) + if actualValue, _ := mappedList.Get(0); actualValue != "mapped: a" { + t.Errorf("Got %v expected %v", actualValue, "mapped: a") + } + if actualValue, _ := mappedList.Get(1); actualValue != "mapped: b" { + t.Errorf("Got %v expected %v", actualValue, "mapped: b") + } + if actualValue, _ := mappedList.Get(2); actualValue != "mapped: c" { + t.Errorf("Got %v expected %v", actualValue, "mapped: c") + } + if mappedList.Size() != 3 { + t.Errorf("Got %v expected %v", mappedList.Size(), 3) + } + + // Select + selectedList := list.Select(func(index interface{}, value interface{}) bool { + return value.(string) >= "a" && value.(string) <= "b" + }).(*List) + if actualValue, _ := selectedList.Get(0); actualValue != "a" { + t.Errorf("Got %v expected %v", actualValue, "value: a") + } + if actualValue, _ := selectedList.Get(1); actualValue != "b" { + t.Errorf("Got %v expected %v", actualValue, "value: b") + } + if selectedList.Size() != 2 { + t.Errorf("Got %v expected %v", selectedList.Size(), 3) + } + // Any + any := list.Any(func(index interface{}, value interface{}) bool { + return value.(string) == "c" + }) + if any != true { + t.Errorf("Got %v expected %v", any, true) + } + any = list.Any(func(index interface{}, value interface{}) bool { + return value.(string) == "x" + }) + if any != false { + t.Errorf("Got %v expected %v", any, false) + } + + // All + all := list.All(func(index interface{}, value interface{}) bool { + return value.(string) >= "a" && value.(string) <= "c" + }) + if all != true { + t.Errorf("Got %v expected %v", all, true) + } + all = list.All(func(index interface{}, value interface{}) bool { + return value.(string) >= "a" && value.(string) <= "b" + }) + if all != false { + t.Errorf("Got %v expected %v", all, false) + } + + // Find + foundIndex, foundValue := list.Find(func(index interface{}, value interface{}) bool { + return value.(string) == "c" + }) + if foundValue != "c" || foundIndex != 2 { + t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, "c", 2) + } + foundIndex, foundValue = list.Find(func(index interface{}, value interface{}) bool { + return value.(string) == "x" + }) + if foundValue != nil || foundIndex != nil { + t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil) + } + + // Iterator + it := list.Iterator() + for it.Next() { + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + } + list.Clear() + it = list.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty list") + } } func BenchmarkSinglyLinkedList(b *testing.B) { From 8e0280ece64782c8f030fdba2cafb7e223e2d782 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 05:56:09 +0200 Subject: [PATCH 031/320] - add iterator to array stack --- stacks/arraystack/arraystack.go | 30 ++++++++++++++++++++++++ stacks/arraystack/arraystack_test.go | 34 ++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index 407cdf0d..4b670dd7 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -32,6 +32,7 @@ package arraystack import ( "fmt" + "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/lists/arraylist" "github.com/emirpasic/gods/stacks" "strings" @@ -39,6 +40,7 @@ import ( func assertInterfaceImplementation() { var _ stacks.Stack = (*Stack)(nil) + var _ containers.Iterator = (*Iterator)(nil) } type Stack struct { @@ -94,6 +96,29 @@ func (stack *Stack) Values() []interface{} { return elements } +type Iterator struct { + stack *Stack + index int +} + +func (stack *Stack) Iterator() Iterator { + return Iterator{stack: stack, index: -1} +} + +func (iterator *Iterator) Next() bool { + iterator.index += 1 + return iterator.stack.withinRange(iterator.index) +} + +func (iterator *Iterator) Value() interface{} { + value, _ := iterator.stack.list.Get(iterator.stack.list.Size() - iterator.index - 1) // in reverse (LIFO) + return value +} + +func (iterator *Iterator) Index() interface{} { + return iterator.index +} + func (stack *Stack) String() string { str := "ArrayStack\n" values := []string{} @@ -103,3 +128,8 @@ func (stack *Stack) String() string { str += strings.Join(values, ", ") return str } + +// Check that the index is withing bounds of the list +func (stack *Stack) withinRange(index int) bool { + return index >= 0 && index < stack.list.Size() +} diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index 62836db7..65fed89b 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -84,7 +84,41 @@ func TestArrayStack(t *testing.T) { if actualValue := stack.Values(); len(actualValue) != 0 { t.Errorf("Got %v expected %v", actualValue, "[]") } +} +func TestArrayStackIterator(t *testing.T) { + stack := New() + stack.Push("a") + stack.Push("b") + stack.Push("c") + + // Iterator + it := stack.Iterator() + for it.Next() { + 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, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + } + stack.Clear() + it = stack.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty stack") + } } func BenchmarkArrayStack(b *testing.B) { From f35d68c85ddbfd8895d444331ba9e0da269b932a Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 06:04:14 +0200 Subject: [PATCH 032/320] - add iterator to linked list stack --- stacks/linkedliststack/linkedliststack.go | 30 ++++++++++++++++ .../linkedliststack/linkedliststack_test.go | 34 +++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/stacks/linkedliststack/linkedliststack.go b/stacks/linkedliststack/linkedliststack.go index 5cc08e62..14b720f6 100644 --- a/stacks/linkedliststack/linkedliststack.go +++ b/stacks/linkedliststack/linkedliststack.go @@ -33,6 +33,7 @@ package linkedliststack import ( "fmt" + "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/lists/singlylinkedlist" "github.com/emirpasic/gods/stacks" "strings" @@ -40,6 +41,7 @@ import ( func assertInterfaceImplementation() { var _ stacks.Stack = (*Stack)(nil) + var _ containers.Iterator = (*Iterator)(nil) } type Stack struct { @@ -90,6 +92,29 @@ func (stack *Stack) Values() []interface{} { return stack.list.Values() } +type Iterator struct { + stack *Stack + index int +} + +func (stack *Stack) Iterator() Iterator { + return Iterator{stack: stack, index: -1} +} + +func (iterator *Iterator) Next() bool { + iterator.index += 1 + return iterator.stack.withinRange(iterator.index) +} + +func (iterator *Iterator) Value() interface{} { + value, _ := iterator.stack.list.Get(iterator.index) // in reverse (LIFO) + return value +} + +func (iterator *Iterator) Index() interface{} { + return iterator.index +} + func (stack *Stack) String() string { str := "LinkedListStack\n" values := []string{} @@ -99,3 +124,8 @@ func (stack *Stack) String() string { str += strings.Join(values, ", ") return str } + +// Check that the index is withing bounds of the list +func (stack *Stack) withinRange(index int) bool { + return index >= 0 && index < stack.list.Size() +} diff --git a/stacks/linkedliststack/linkedliststack_test.go b/stacks/linkedliststack/linkedliststack_test.go index dea7ba0a..2e082ff9 100644 --- a/stacks/linkedliststack/linkedliststack_test.go +++ b/stacks/linkedliststack/linkedliststack_test.go @@ -84,7 +84,41 @@ func TestLinkedListStack(t *testing.T) { if actualValue := stack.Values(); len(actualValue) != 0 { t.Errorf("Got %v expected %v", actualValue, "[]") } +} +func TestLinkedListStackIterator(t *testing.T) { + stack := New() + stack.Push("a") + stack.Push("b") + stack.Push("c") + + // Iterator + it := stack.Iterator() + for it.Next() { + 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, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + } + stack.Clear() + it = stack.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty stack") + } } func BenchmarkLinkedListStack(b *testing.B) { From 6c3a5ce1cc8fd97122fdf04a1a73109a67ffcfdb Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 06:18:08 +0200 Subject: [PATCH 033/320] - add iterator to binary heap --- trees/binaryheap/binaryheap.go | 30 ++++++++++++++++++++ trees/binaryheap/binaryheap_test.go | 43 +++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index 9320fc43..c5b2e39f 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -33,6 +33,7 @@ package binaryheap import ( "fmt" + "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/lists/arraylist" "github.com/emirpasic/gods/trees" "github.com/emirpasic/gods/utils" @@ -41,6 +42,7 @@ import ( func assertInterfaceImplementation() { var _ trees.Tree = (*Heap)(nil) + var _ containers.Iterator = (*Iterator)(nil) } type Heap struct { @@ -109,6 +111,29 @@ func (heap *Heap) Values() []interface{} { return heap.list.Values() } +type Iterator struct { + heap *Heap + index int +} + +func (heap *Heap) Iterator() Iterator { + return Iterator{heap: heap, index: -1} +} + +func (iterator *Iterator) Next() bool { + iterator.index += 1 + return iterator.heap.withinRange(iterator.index) +} + +func (iterator *Iterator) Value() interface{} { + value, _ := iterator.heap.list.Get(iterator.index) + return value +} + +func (iterator *Iterator) Index() interface{} { + return iterator.index +} + func (heap *Heap) String() string { str := "BinaryHeap\n" values := []string{} @@ -158,3 +183,8 @@ func (heap *Heap) bubbleUp() { index = parentIndex } } + +// Check that the index is withing bounds of the list +func (heap *Heap) withinRange(index int) bool { + return index >= 0 && index < heap.list.Size() +} diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go index 473526fe..66c80e1a 100644 --- a/trees/binaryheap/binaryheap_test.go +++ b/trees/binaryheap/binaryheap_test.go @@ -103,7 +103,50 @@ func TestBinaryHeap(t *testing.T) { } prev = curr } +} + +func TestBinaryHeapIterator(t *testing.T) { + heap := NewWithIntComparator() + + if actualValue := heap.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + + // insertions + heap.Push(3) + // [3] + heap.Push(2) + // [2,3] + heap.Push(1) + // [1,3,2](2 swapped with 1, hence last) + // Iterator + it := heap.Iterator() + for it.Next() { + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + } + heap.Clear() + it = heap.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty stack") + } } func BenchmarkBinaryHeap(b *testing.B) { From 255a3095cb6b96367657b37d985152f0cbb81cc1 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 19:47:24 +0200 Subject: [PATCH 034/320] - add iterator to redblack tree --- trees/redblacktree/redblacktree.go | 43 +++++++++ trees/redblacktree/redblacktree_test.go | 122 ++++++++++++++++++++++++ 2 files changed, 165 insertions(+) diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 3811fb2c..35d1d568 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -33,6 +33,7 @@ package redblacktree import ( "fmt" + "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/stacks/linkedliststack" "github.com/emirpasic/gods/trees" "github.com/emirpasic/gods/utils" @@ -40,6 +41,7 @@ import ( func assertInterfaceImplementation() { var _ trees.Tree = (*Tree)(nil) + var _ containers.Iterator = (*Iterator)(nil) } type color bool @@ -272,6 +274,47 @@ func (tree *Tree) Clear() { tree.size = 0 } +type Iterator struct { + tree *Tree + left *Node +} + +func (tree *Tree) Iterator() Iterator { + return Iterator{tree: tree, left: nil} +} + +func (iterator *Iterator) Next() bool { + if iterator.left == nil { + iterator.left = iterator.tree.Left() + return iterator.left != nil + } + if iterator.left.Right != nil { + iterator.left = iterator.left.Right + for iterator.left.Left != nil { + iterator.left = iterator.left.Left + } + return true + } + if iterator.left.Parent != nil { + key := iterator.left.Key + for iterator.left.Parent != nil { + iterator.left = iterator.left.Parent + if iterator.tree.Comparator(key, iterator.left.Key) <= 0 { + return true + } + } + } + return false +} + +func (iterator *Iterator) Value() interface{} { + return iterator.left.Value +} + +func (iterator *Iterator) Index() interface{} { + return iterator.left.Key +} + func (tree *Tree) String() string { str := "RedBlackTree\n" if !tree.Empty() { diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 20a287c2..90f1fe01 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -216,6 +216,128 @@ func TestRedBlackTree(t *testing.T) { } } +func TestRedBlackTreeIterator(t *testing.T) { + tree := NewWithIntComparator() + + // insertions + tree.Put(5, "e") + tree.Put(6, "f") + tree.Put(7, "g") + tree.Put(3, "c") + tree.Put(4, "d") + tree.Put(1, "x") + tree.Put(2, "b") + tree.Put(1, "a") //overwrite + + // Iterator + it := tree.Iterator() + count := 0 + for it.Next() { + count += 1 + index := it.Index() + switch index { + case count: + if actualValue, expectedValue := index, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := index, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + if actualValue, expectedValue := count, 7; actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } + + // Iterator + tree.Clear() + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it = tree.Iterator() + count = 0 + for it.Next() { + count += 1 + index := it.Index() + switch index { + case count: + if actualValue, expectedValue := index, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := index, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } + + // Iterator + tree.Clear() + tree.Put(1, "a") + it = tree.Iterator() + count = 0 + for it.Next() { + count += 1 + index := it.Index() + switch index { + case count: + if actualValue, expectedValue := index, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := index, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + if actualValue, expectedValue := count, 1; actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } + + // Iterator on empty + tree.Clear() + it = tree.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty stack") + } + + // Iterator (from image) + tree.Clear() + tree.Put(13, 5) + tree.Put(8, 3) + tree.Put(17, 7) + tree.Put(1, 1) + tree.Put(11, 4) + tree.Put(15, 6) + tree.Put(25, 9) + tree.Put(6, 2) + tree.Put(22, 8) + tree.Put(27, 10) + it = tree.Iterator() + count = 0 + for it.Next() { + count += 1 + value := it.Value() + switch value { + case count: + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + if actualValue, expectedValue := count, 10; actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + func BenchmarkRedBlackTree(b *testing.B) { for i := 0; i < b.N; i++ { tree := NewWithIntComparator() From e4c3d8a0d8debd5452dfab4d74d670f52080a5dc Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 19:59:08 +0200 Subject: [PATCH 035/320] - split iterators into two type (iterator with index and iterator with key) --- containers/iterator.go | 23 +++++++++++++++++++--- lists/arraylist/arraylist.go | 4 ++-- lists/doublylinkedlist/doublylinkedlist.go | 4 ++-- lists/singlylinkedlist/singlylinkedlist.go | 4 ++-- stacks/arraystack/arraystack.go | 4 ++-- stacks/linkedliststack/linkedliststack.go | 4 ++-- trees/binaryheap/binaryheap.go | 4 ++-- trees/redblacktree/redblacktree.go | 4 ++-- trees/redblacktree/redblacktree_test.go | 6 +++--- 9 files changed, 37 insertions(+), 20 deletions(-) diff --git a/containers/iterator.go b/containers/iterator.go index 0dcb829b..db0ea7a9 100644 --- a/containers/iterator.go +++ b/containers/iterator.go @@ -28,11 +28,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package containers -type Iterator interface { +// Stateful iterator for ordered containers whose values can be fetched by an index. +type IteratorWithIndex interface { // Moves the iterator to the next element and returns true if there was a next element in the container. + // Modifies the state of the iterator. Next() bool // Returns the current element's value. + // Does not modify the state of the iterator. Value() interface{} - // Returns the current element's index(key). - Index() interface{} + // Returns the current element's index. + // Does not modify the state of the iterator. + Index() int +} + +// Stateful iterator for ordered containers whose elements are key value pairs. +type IteratorWithKey interface { + // Moves the iterator to the next element and returns true if there was a next element in the container. + // Modifies the state of the iterator. + Next() bool + // Returns the current element's value. + // Does not modify the state of the iterator. + Value() interface{} + // Returns the current element's key. + // Does not modify the state of the iterator. + Key() interface{} } diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index 059ef3e9..df40aa8b 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -41,7 +41,7 @@ import ( func assertInterfaceImplementation() { var _ lists.List = (*List)(nil) var _ containers.Enumerable = (*List)(nil) - var _ containers.Iterator = (*Iterator)(nil) + var _ containers.IteratorWithIndex = (*Iterator)(nil) } type List struct { @@ -196,7 +196,7 @@ func (iterator *Iterator) Value() interface{} { return iterator.list.elements[iterator.index] } -func (iterator *Iterator) Index() interface{} { +func (iterator *Iterator) Index() int { return iterator.index } diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 69d6368a..40b6d439 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -41,7 +41,7 @@ import ( func assertInterfaceImplementation() { var _ lists.List = (*List)(nil) var _ containers.Enumerable = (*List)(nil) - var _ containers.Iterator = (*Iterator)(nil) + var _ containers.IteratorWithIndex = (*Iterator)(nil) } type List struct { @@ -328,7 +328,7 @@ func (iterator *Iterator) Value() interface{} { return iterator.element.value } -func (iterator *Iterator) Index() interface{} { +func (iterator *Iterator) Index() int { return iterator.index } diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 69177b33..3faed7d3 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -41,7 +41,7 @@ import ( func assertInterfaceImplementation() { var _ lists.List = (*List)(nil) var _ containers.Enumerable = (*List)(nil) - var _ containers.Iterator = (*Iterator)(nil) + var _ containers.IteratorWithIndex = (*Iterator)(nil) } type List struct { @@ -298,7 +298,7 @@ func (iterator *Iterator) Value() interface{} { return iterator.element.value } -func (iterator *Iterator) Index() interface{} { +func (iterator *Iterator) Index() int { return iterator.index } diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index 4b670dd7..c775e80f 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -40,7 +40,7 @@ import ( func assertInterfaceImplementation() { var _ stacks.Stack = (*Stack)(nil) - var _ containers.Iterator = (*Iterator)(nil) + var _ containers.IteratorWithIndex = (*Iterator)(nil) } type Stack struct { @@ -115,7 +115,7 @@ func (iterator *Iterator) Value() interface{} { return value } -func (iterator *Iterator) Index() interface{} { +func (iterator *Iterator) Index() int { return iterator.index } diff --git a/stacks/linkedliststack/linkedliststack.go b/stacks/linkedliststack/linkedliststack.go index 14b720f6..7bf5d03d 100644 --- a/stacks/linkedliststack/linkedliststack.go +++ b/stacks/linkedliststack/linkedliststack.go @@ -41,7 +41,7 @@ import ( func assertInterfaceImplementation() { var _ stacks.Stack = (*Stack)(nil) - var _ containers.Iterator = (*Iterator)(nil) + var _ containers.IteratorWithIndex = (*Iterator)(nil) } type Stack struct { @@ -111,7 +111,7 @@ func (iterator *Iterator) Value() interface{} { return value } -func (iterator *Iterator) Index() interface{} { +func (iterator *Iterator) Index() int { return iterator.index } diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index c5b2e39f..ab7452ba 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -42,7 +42,7 @@ import ( func assertInterfaceImplementation() { var _ trees.Tree = (*Heap)(nil) - var _ containers.Iterator = (*Iterator)(nil) + var _ containers.IteratorWithIndex = (*Iterator)(nil) } type Heap struct { @@ -130,7 +130,7 @@ func (iterator *Iterator) Value() interface{} { return value } -func (iterator *Iterator) Index() interface{} { +func (iterator *Iterator) Index() int { return iterator.index } diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 35d1d568..da000ad5 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -41,7 +41,7 @@ import ( func assertInterfaceImplementation() { var _ trees.Tree = (*Tree)(nil) - var _ containers.Iterator = (*Iterator)(nil) + var _ containers.IteratorWithKey = (*Iterator)(nil) } type color bool @@ -311,7 +311,7 @@ func (iterator *Iterator) Value() interface{} { return iterator.left.Value } -func (iterator *Iterator) Index() interface{} { +func (iterator *Iterator) Key() interface{} { return iterator.left.Key } diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 90f1fe01..eee89554 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -234,7 +234,7 @@ func TestRedBlackTreeIterator(t *testing.T) { count := 0 for it.Next() { count += 1 - index := it.Index() + index := it.Key() switch index { case count: if actualValue, expectedValue := index, count; actualValue != expectedValue { @@ -259,7 +259,7 @@ func TestRedBlackTreeIterator(t *testing.T) { count = 0 for it.Next() { count += 1 - index := it.Index() + index := it.Key() switch index { case count: if actualValue, expectedValue := index, count; actualValue != expectedValue { @@ -282,7 +282,7 @@ func TestRedBlackTreeIterator(t *testing.T) { count = 0 for it.Next() { count += 1 - index := it.Index() + index := it.Key() switch index { case count: if actualValue, expectedValue := index, count; actualValue != expectedValue { From 0418a59aaf6584daa5fb27b0894789a4a7756f5a Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 20:18:37 +0200 Subject: [PATCH 036/320] - add iterator to tree set --- sets/treeset/treeset.go | 24 ++++++++++++++++++++++++ sets/treeset/treeset_test.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index da6d7d9b..42d0eee8 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -24,6 +24,7 @@ package treeset import ( "fmt" + "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/sets" rbt "github.com/emirpasic/gods/trees/redblacktree" "github.com/emirpasic/gods/utils" @@ -32,6 +33,7 @@ import ( func assertInterfaceImplementation() { var _ sets.Set = (*Set)(nil) + var _ containers.IteratorWithIndex = (*Iterator)(nil) } type Set struct { @@ -101,6 +103,28 @@ func (set *Set) Values() []interface{} { return set.tree.Keys() } +type Iterator struct { + index int + iterator rbt.Iterator +} + +func (set *Set) Iterator() Iterator { + return Iterator{index: -1, iterator: set.tree.Iterator()} +} + +func (iterator *Iterator) Next() bool { + iterator.index += 1 + return iterator.iterator.Next() +} + +func (iterator *Iterator) Value() interface{} { + return iterator.iterator.Key() +} + +func (iterator *Iterator) Index() int { + return iterator.index +} + func (set *Set) String() string { str := "TreeSet\n" items := []string{} diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index b033a7ba..780a9dbe 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -82,7 +82,41 @@ func TestTreeSet(t *testing.T) { if actualValue := set.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } +} +func TestTreeSetIterator(t *testing.T) { + set := NewWithStringComparator() + set.Add("c") + set.Add("a") + set.Add("b") + + // Iterator + it := set.Iterator() + for it.Next() { + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + } + set.Clear() + it = set.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty set") + } } func BenchmarkTreeSet(b *testing.B) { From e9377a48f6d041d2d58e502f3e18d6d0b26c0867 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 20:42:25 +0200 Subject: [PATCH 037/320] - add enumerable to tree set --- sets/treeset/treeset.go | 60 +++++++++++++++++++++- sets/treeset/treeset_test.go | 97 ++++++++++++++++++++++++++++++++++-- 2 files changed, 152 insertions(+), 5 deletions(-) diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 42d0eee8..25acbcf8 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -33,6 +33,7 @@ import ( func assertInterfaceImplementation() { var _ sets.Set = (*Set)(nil) + var _ containers.Enumerable = (*Set)(nil) var _ containers.IteratorWithIndex = (*Iterator)(nil) } @@ -71,7 +72,7 @@ func (set *Set) Remove(items ...interface{}) { } } -// Check wether items (one or more) are present in the set. +// Check weather 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 { @@ -125,6 +126,63 @@ func (iterator *Iterator) Index() int { return iterator.index } +func (set *Set) Each(f func(index interface{}, value interface{})) { + iterator := set.Iterator() + for iterator.Next() { + f(iterator.Index(), iterator.Value()) + } +} + +func (set *Set) Map(f func(index interface{}, value interface{}) interface{}) containers.Container { + newSet := &Set{tree: rbt.NewWith(set.tree.Comparator)} + iterator := set.Iterator() + for iterator.Next() { + newSet.Add(f(iterator.Index(), iterator.Value())) + } + return newSet +} + +func (set *Set) Select(f func(index interface{}, value interface{}) bool) containers.Container { + newSet := &Set{tree: rbt.NewWith(set.tree.Comparator)} + iterator := set.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + newSet.Add(iterator.Value()) + } + } + return newSet +} + +func (set *Set) Any(f func(index interface{}, value interface{}) bool) bool { + iterator := set.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + return true + } + } + return false +} + +func (set *Set) All(f func(index interface{}, value interface{}) bool) bool { + iterator := set.Iterator() + for iterator.Next() { + if !f(iterator.Index(), iterator.Value()) { + return false + } + } + return true +} + +func (set *Set) Find(f func(index interface{}, value interface{}) bool) (index interface{}, value interface{}) { + iterator := set.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + return iterator.Index(), iterator.Value() + } + } + return nil, nil +} + func (set *Set) String() string { str := "TreeSet\n" items := []string{} diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index 780a9dbe..78f1e3a6 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -84,11 +84,100 @@ func TestTreeSet(t *testing.T) { } } -func TestTreeSetIterator(t *testing.T) { +func TestTreeSetEnumerableAndIterator(t *testing.T) { set := NewWithStringComparator() - set.Add("c") - set.Add("a") - set.Add("b") + set.Add("c", "a", "b") + + // Each + set.Each(func(index interface{}, value interface{}) { + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + }) + + // Map + mappedSet := set.Map(func(index interface{}, value interface{}) interface{} { + return "mapped: " + value.(string) + }).(*Set) + if actualValue, expectedValue := mappedSet.Contains("mapped: a", "mapped: b", "mapped: c"), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := mappedSet.Contains("mapped: a", "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) + } + + // Select + selectedSet := set.Select(func(index interface{}, value interface{}) bool { + return value.(string) >= "a" && value.(string) <= "b" + }).(*Set) + if actualValue, expectedValue := selectedSet.Contains("a", "b"), true; actualValue != expectedValue { + fmt.Println("A: ", mappedSet.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) + } + + // Any + any := set.Any(func(index interface{}, value interface{}) bool { + return value.(string) == "c" + }) + if any != true { + t.Errorf("Got %v expected %v", any, true) + } + any = set.Any(func(index interface{}, value interface{}) bool { + return value.(string) == "x" + }) + if any != false { + t.Errorf("Got %v expected %v", any, false) + } + + // All + all := set.All(func(index interface{}, 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 interface{}, value interface{}) bool { + return value.(string) >= "a" && value.(string) <= "b" + }) + if all != false { + t.Errorf("Got %v expected %v", all, false) + } + + // Find + foundIndex, foundValue := set.Find(func(index interface{}, value interface{}) bool { + return value.(string) == "c" + }) + if foundValue != "c" || foundIndex != 2 { + t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, "c", 2) + } + foundIndex, foundValue = set.Find(func(index interface{}, value interface{}) bool { + return value.(string) == "x" + }) + if foundValue != nil || foundIndex != nil { + t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil) + } // Iterator it := set.Iterator() From 7346ca6337046ba688fd640a3ae0abd7d6c2de4f Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 20:56:18 +0200 Subject: [PATCH 038/320] - add iterator to tree map --- maps/treemap/treemap.go | 22 ++++++++++++++++++++++ maps/treemap/treemap_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index d0fc742f..20e4ba2b 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -32,6 +32,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package treemap import ( + "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/maps" rbt "github.com/emirpasic/gods/trees/redblacktree" "github.com/emirpasic/gods/utils" @@ -39,6 +40,7 @@ import ( func assertInterfaceImplementation() { var _ maps.Map = (*Map)(nil) + var _ containers.IteratorWithKey = (*Iterator)(nil) } type Map struct { @@ -122,6 +124,26 @@ func (m *Map) Max() (key interface{}, value interface{}) { return nil, nil } +type Iterator struct { + iterator rbt.Iterator +} + +func (m *Map) Iterator() Iterator { + return Iterator{iterator: m.tree.Iterator()} +} + +func (iterator *Iterator) Next() bool { + return iterator.iterator.Next() +} + +func (iterator *Iterator) Value() interface{} { + return iterator.iterator.Value() +} + +func (iterator *Iterator) Key() interface{} { + return iterator.iterator.Key() +} + func (m *Map) String() string { str := "TreeMap\n" str += m.tree.String() diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index c48c4546..95ee4592 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -179,6 +179,34 @@ func TestTreeMap(t *testing.T) { } } +func TestTreeMapIterator(t *testing.T) { + m := NewWithStringComparator() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + + // Iterator + it := m.Iterator() + count := 0 + for it.Next() { + count += 1 + value := it.Value() + switch value { + case count: + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + } + m.Clear() + it = m.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty map") + } +} + func BenchmarkTreeMap(b *testing.B) { for i := 0; i < b.N; i++ { m := NewWithIntComparator() From 3b6a40775a963e04da754e8b3e30f527be1203f4 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 21:03:51 +0200 Subject: [PATCH 039/320] - split enumerables into enumerables with keys and with indexes (same was done for iterators) --- containers/enumerable.go | 29 ++++++++++++++++++- lists/arraylist/arraylist.go | 16 +++++----- lists/arraylist/arraylist_test.go | 20 ++++++------- lists/doublylinkedlist/doublylinkedlist.go | 16 +++++----- .../doublylinkedlist/doublylinkedlist_test.go | 20 ++++++------- lists/singlylinkedlist/singlylinkedlist.go | 16 +++++----- .../singlylinkedlist/singlylinkedlist_test.go | 20 ++++++------- sets/treeset/treeset.go | 16 +++++----- sets/treeset/treeset_test.go | 20 ++++++------- 9 files changed, 100 insertions(+), 73 deletions(-) diff --git a/containers/enumerable.go b/containers/enumerable.go index bb736abc..ceb51fcc 100644 --- a/containers/enumerable.go +++ b/containers/enumerable.go @@ -29,7 +29,34 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package containers -type Enumerable interface { +// Enumerable function for ordered containers whose values can be fetched by an index. +type EnumerableWithIndex interface { + // Calls the given function once for each element, passing that element's index(key) and value. + Each(func(index int, value interface{})) + + // Invokes the given function once for each element and returns a + // container containing the values returned by the given function. + Map(func(index int, value interface{}) interface{}) Container + + // Returns a new container containing all elements for which the given function returns a true value. + Select(func(index int, value interface{}) bool) Container + + // Passes each element of the collection to the given function and + // returns true if the function ever returns true for any element. + Any(func(index int, value interface{}) bool) bool + + // Passes each element of the collection to the given function and + // returns true if the function returns true for all elements. + All(func(index int, value interface{}) bool) bool + + // Passes each element of the collection to the given function and returns + // the first for which the function is true or nil,nil otherwise if no element + // matches the criteria. + Find(func(index int, value interface{}) bool) (index int, value interface{}) +} + +// Enumerable function for ordered containers whose values whose elements are key value pairs. +type EnumerableWithKey interface { // Calls the given function once for each element, passing that element's index(key) and value. Each(func(index interface{}, value interface{})) diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index df40aa8b..3025a52b 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -40,7 +40,7 @@ import ( func assertInterfaceImplementation() { var _ lists.List = (*List)(nil) - var _ containers.Enumerable = (*List)(nil) + var _ containers.EnumerableWithIndex = (*List)(nil) var _ containers.IteratorWithIndex = (*Iterator)(nil) } @@ -200,14 +200,14 @@ func (iterator *Iterator) Index() int { return iterator.index } -func (list *List) Each(f func(index interface{}, value interface{})) { +func (list *List) Each(f func(index int, value interface{})) { iterator := list.Iterator() for iterator.Next() { f(iterator.Index(), iterator.Value()) } } -func (list *List) Map(f func(index interface{}, value interface{}) interface{}) containers.Container { +func (list *List) Map(f func(index int, value interface{}) interface{}) containers.Container { newList := &List{} iterator := list.Iterator() for iterator.Next() { @@ -216,7 +216,7 @@ func (list *List) Map(f func(index interface{}, value interface{}) interface{}) return newList } -func (list *List) Select(f func(index interface{}, value interface{}) bool) containers.Container { +func (list *List) Select(f func(index int, value interface{}) bool) containers.Container { newList := &List{} iterator := list.Iterator() for iterator.Next() { @@ -227,7 +227,7 @@ func (list *List) Select(f func(index interface{}, value interface{}) bool) cont return newList } -func (list *List) Any(f func(index interface{}, value interface{}) bool) bool { +func (list *List) Any(f func(index int, value interface{}) bool) bool { iterator := list.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { @@ -237,7 +237,7 @@ func (list *List) Any(f func(index interface{}, value interface{}) bool) bool { return false } -func (list *List) All(f func(index interface{}, value interface{}) bool) bool { +func (list *List) All(f func(index int, value interface{}) bool) bool { iterator := list.Iterator() for iterator.Next() { if !f(iterator.Index(), iterator.Value()) { @@ -247,14 +247,14 @@ func (list *List) All(f func(index interface{}, value interface{}) bool) bool { return true } -func (list *List) Find(f func(index interface{}, value interface{}) bool) (index interface{}, value interface{}) { +func (list *List) Find(f func(index int, value interface{}) bool) (index int, value interface{}) { iterator := list.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { return iterator.Index(), iterator.Value() } } - return nil, nil + return -1, nil } func (list *List) String() string { diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 2ec424f8..68c499a4 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -140,7 +140,7 @@ func TestArrayListEnumerableAndIterator(t *testing.T) { list.Add("a", "b", "c") // Each - list.Each(func(index interface{}, value interface{}) { + list.Each(func(index int, value interface{}) { switch index { case 0: if actualValue, expectedValue := value, "a"; actualValue != expectedValue { @@ -160,7 +160,7 @@ func TestArrayListEnumerableAndIterator(t *testing.T) { }) // Map - mappedList := list.Map(func(index interface{}, value interface{}) interface{} { + mappedList := list.Map(func(index int, value interface{}) interface{} { return "mapped: " + value.(string) }).(*List) if actualValue, _ := mappedList.Get(0); actualValue != "mapped: a" { @@ -177,7 +177,7 @@ func TestArrayListEnumerableAndIterator(t *testing.T) { } // Select - selectedList := list.Select(func(index interface{}, value interface{}) bool { + selectedList := list.Select(func(index int, value interface{}) bool { return value.(string) >= "a" && value.(string) <= "b" }).(*List) if actualValue, _ := selectedList.Get(0); actualValue != "a" { @@ -191,13 +191,13 @@ func TestArrayListEnumerableAndIterator(t *testing.T) { } // Any - any := list.Any(func(index interface{}, value interface{}) bool { + any := list.Any(func(index int, value interface{}) bool { return value.(string) == "c" }) if any != true { t.Errorf("Got %v expected %v", any, true) } - any = list.Any(func(index interface{}, value interface{}) bool { + any = list.Any(func(index int, value interface{}) bool { return value.(string) == "x" }) if any != false { @@ -205,13 +205,13 @@ func TestArrayListEnumerableAndIterator(t *testing.T) { } // All - all := list.All(func(index interface{}, value interface{}) bool { + all := list.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 = list.All(func(index interface{}, value interface{}) bool { + all = list.All(func(index int, value interface{}) bool { return value.(string) >= "a" && value.(string) <= "b" }) if all != false { @@ -219,16 +219,16 @@ func TestArrayListEnumerableAndIterator(t *testing.T) { } // Find - foundIndex, foundValue := list.Find(func(index interface{}, value interface{}) bool { + foundIndex, foundValue := list.Find(func(index int, value interface{}) bool { return value.(string) == "c" }) if foundValue != "c" || foundIndex != 2 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, "c", 2) } - foundIndex, foundValue = list.Find(func(index interface{}, value interface{}) bool { + foundIndex, foundValue = list.Find(func(index int, value interface{}) bool { return value.(string) == "x" }) - if foundValue != nil || foundIndex != nil { + if foundValue != nil || foundIndex != -1 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil) } diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 40b6d439..514a9e61 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -40,7 +40,7 @@ import ( func assertInterfaceImplementation() { var _ lists.List = (*List)(nil) - var _ containers.Enumerable = (*List)(nil) + var _ containers.EnumerableWithIndex = (*List)(nil) var _ containers.IteratorWithIndex = (*Iterator)(nil) } @@ -332,14 +332,14 @@ func (iterator *Iterator) Index() int { return iterator.index } -func (list *List) Each(f func(index interface{}, value interface{})) { +func (list *List) Each(f func(index int, value interface{})) { iterator := list.Iterator() for iterator.Next() { f(iterator.Index(), iterator.Value()) } } -func (list *List) Map(f func(index interface{}, value interface{}) interface{}) containers.Container { +func (list *List) Map(f func(index int, value interface{}) interface{}) containers.Container { newList := &List{} iterator := list.Iterator() for iterator.Next() { @@ -348,7 +348,7 @@ func (list *List) Map(f func(index interface{}, value interface{}) interface{}) return newList } -func (list *List) Select(f func(index interface{}, value interface{}) bool) containers.Container { +func (list *List) Select(f func(index int, value interface{}) bool) containers.Container { newList := &List{} iterator := list.Iterator() for iterator.Next() { @@ -359,7 +359,7 @@ func (list *List) Select(f func(index interface{}, value interface{}) bool) cont return newList } -func (list *List) Any(f func(index interface{}, value interface{}) bool) bool { +func (list *List) Any(f func(index int, value interface{}) bool) bool { iterator := list.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { @@ -369,7 +369,7 @@ func (list *List) Any(f func(index interface{}, value interface{}) bool) bool { return false } -func (list *List) All(f func(index interface{}, value interface{}) bool) bool { +func (list *List) All(f func(index int, value interface{}) bool) bool { iterator := list.Iterator() for iterator.Next() { if !f(iterator.Index(), iterator.Value()) { @@ -379,14 +379,14 @@ func (list *List) All(f func(index interface{}, value interface{}) bool) bool { return true } -func (list *List) Find(f func(index interface{}, value interface{}) bool) (index interface{}, value interface{}) { +func (list *List) Find(f func(index int, value interface{}) bool) (index int, value interface{}) { iterator := list.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { return iterator.Index(), iterator.Value() } } - return nil, nil + return -1, nil } func (list *List) String() string { diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index a5c6dcd9..6d580c80 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -142,7 +142,7 @@ func TestDoublyLinkedListEnumerableAndIterator(t *testing.T) { list.Add("a", "b", "c") // Each - list.Each(func(index interface{}, value interface{}) { + list.Each(func(index int, value interface{}) { switch index { case 0: if actualValue, expectedValue := value, "a"; actualValue != expectedValue { @@ -162,7 +162,7 @@ func TestDoublyLinkedListEnumerableAndIterator(t *testing.T) { }) // Map - mappedList := list.Map(func(index interface{}, value interface{}) interface{} { + mappedList := list.Map(func(index int, value interface{}) interface{} { return "mapped: " + value.(string) }).(*List) if actualValue, _ := mappedList.Get(0); actualValue != "mapped: a" { @@ -179,7 +179,7 @@ func TestDoublyLinkedListEnumerableAndIterator(t *testing.T) { } // Select - selectedList := list.Select(func(index interface{}, value interface{}) bool { + selectedList := list.Select(func(index int, value interface{}) bool { return value.(string) >= "a" && value.(string) <= "b" }).(*List) if actualValue, _ := selectedList.Get(0); actualValue != "a" { @@ -193,13 +193,13 @@ func TestDoublyLinkedListEnumerableAndIterator(t *testing.T) { } // Any - any := list.Any(func(index interface{}, value interface{}) bool { + any := list.Any(func(index int, value interface{}) bool { return value.(string) == "c" }) if any != true { t.Errorf("Got %v expected %v", any, true) } - any = list.Any(func(index interface{}, value interface{}) bool { + any = list.Any(func(index int, value interface{}) bool { return value.(string) == "x" }) if any != false { @@ -207,13 +207,13 @@ func TestDoublyLinkedListEnumerableAndIterator(t *testing.T) { } // All - all := list.All(func(index interface{}, value interface{}) bool { + all := list.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 = list.All(func(index interface{}, value interface{}) bool { + all = list.All(func(index int, value interface{}) bool { return value.(string) >= "a" && value.(string) <= "b" }) if all != false { @@ -221,16 +221,16 @@ func TestDoublyLinkedListEnumerableAndIterator(t *testing.T) { } // Find - foundIndex, foundValue := list.Find(func(index interface{}, value interface{}) bool { + foundIndex, foundValue := list.Find(func(index int, value interface{}) bool { return value.(string) == "c" }) if foundValue != "c" || foundIndex != 2 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, "c", 2) } - foundIndex, foundValue = list.Find(func(index interface{}, value interface{}) bool { + foundIndex, foundValue = list.Find(func(index int, value interface{}) bool { return value.(string) == "x" }) - if foundValue != nil || foundIndex != nil { + if foundValue != nil || foundIndex != -1 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil) } diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 3faed7d3..50c9a57f 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -40,7 +40,7 @@ import ( func assertInterfaceImplementation() { var _ lists.List = (*List)(nil) - var _ containers.Enumerable = (*List)(nil) + var _ containers.EnumerableWithIndex = (*List)(nil) var _ containers.IteratorWithIndex = (*Iterator)(nil) } @@ -302,14 +302,14 @@ func (iterator *Iterator) Index() int { return iterator.index } -func (list *List) Each(f func(index interface{}, value interface{})) { +func (list *List) Each(f func(index int, value interface{})) { iterator := list.Iterator() for iterator.Next() { f(iterator.Index(), iterator.Value()) } } -func (list *List) Map(f func(index interface{}, value interface{}) interface{}) containers.Container { +func (list *List) Map(f func(index int, value interface{}) interface{}) containers.Container { newList := &List{} iterator := list.Iterator() for iterator.Next() { @@ -318,7 +318,7 @@ func (list *List) Map(f func(index interface{}, value interface{}) interface{}) return newList } -func (list *List) Select(f func(index interface{}, value interface{}) bool) containers.Container { +func (list *List) Select(f func(index int, value interface{}) bool) containers.Container { newList := &List{} iterator := list.Iterator() for iterator.Next() { @@ -329,7 +329,7 @@ func (list *List) Select(f func(index interface{}, value interface{}) bool) cont return newList } -func (list *List) Any(f func(index interface{}, value interface{}) bool) bool { +func (list *List) Any(f func(index int, value interface{}) bool) bool { iterator := list.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { @@ -339,7 +339,7 @@ func (list *List) Any(f func(index interface{}, value interface{}) bool) bool { return false } -func (list *List) All(f func(index interface{}, value interface{}) bool) bool { +func (list *List) All(f func(index int, value interface{}) bool) bool { iterator := list.Iterator() for iterator.Next() { if !f(iterator.Index(), iterator.Value()) { @@ -349,14 +349,14 @@ func (list *List) All(f func(index interface{}, value interface{}) bool) bool { return true } -func (list *List) Find(f func(index interface{}, value interface{}) bool) (index interface{}, value interface{}) { +func (list *List) Find(f func(index int, value interface{}) bool) (index int, value interface{}) { iterator := list.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { return iterator.Index(), iterator.Value() } } - return nil, nil + return -1, nil } func (list *List) String() string { diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index 48508e7e..c5ce3781 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -142,7 +142,7 @@ func TestSinglyLinkedListEnumerableAndIterator(t *testing.T) { list.Add("a", "b", "c") // Each - list.Each(func(index interface{}, value interface{}) { + list.Each(func(index int, value interface{}) { switch index { case 0: if actualValue, expectedValue := value, "a"; actualValue != expectedValue { @@ -162,7 +162,7 @@ func TestSinglyLinkedListEnumerableAndIterator(t *testing.T) { }) // Map - mappedList := list.Map(func(index interface{}, value interface{}) interface{} { + mappedList := list.Map(func(index int, value interface{}) interface{} { return "mapped: " + value.(string) }).(*List) if actualValue, _ := mappedList.Get(0); actualValue != "mapped: a" { @@ -179,7 +179,7 @@ func TestSinglyLinkedListEnumerableAndIterator(t *testing.T) { } // Select - selectedList := list.Select(func(index interface{}, value interface{}) bool { + selectedList := list.Select(func(index int, value interface{}) bool { return value.(string) >= "a" && value.(string) <= "b" }).(*List) if actualValue, _ := selectedList.Get(0); actualValue != "a" { @@ -193,13 +193,13 @@ func TestSinglyLinkedListEnumerableAndIterator(t *testing.T) { } // Any - any := list.Any(func(index interface{}, value interface{}) bool { + any := list.Any(func(index int, value interface{}) bool { return value.(string) == "c" }) if any != true { t.Errorf("Got %v expected %v", any, true) } - any = list.Any(func(index interface{}, value interface{}) bool { + any = list.Any(func(index int, value interface{}) bool { return value.(string) == "x" }) if any != false { @@ -207,13 +207,13 @@ func TestSinglyLinkedListEnumerableAndIterator(t *testing.T) { } // All - all := list.All(func(index interface{}, value interface{}) bool { + all := list.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 = list.All(func(index interface{}, value interface{}) bool { + all = list.All(func(index int, value interface{}) bool { return value.(string) >= "a" && value.(string) <= "b" }) if all != false { @@ -221,16 +221,16 @@ func TestSinglyLinkedListEnumerableAndIterator(t *testing.T) { } // Find - foundIndex, foundValue := list.Find(func(index interface{}, value interface{}) bool { + foundIndex, foundValue := list.Find(func(index int, value interface{}) bool { return value.(string) == "c" }) if foundValue != "c" || foundIndex != 2 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, "c", 2) } - foundIndex, foundValue = list.Find(func(index interface{}, value interface{}) bool { + foundIndex, foundValue = list.Find(func(index int, value interface{}) bool { return value.(string) == "x" }) - if foundValue != nil || foundIndex != nil { + if foundValue != nil || foundIndex != -1 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil) } diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 25acbcf8..51bd6215 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -33,7 +33,7 @@ import ( func assertInterfaceImplementation() { var _ sets.Set = (*Set)(nil) - var _ containers.Enumerable = (*Set)(nil) + var _ containers.EnumerableWithIndex = (*Set)(nil) var _ containers.IteratorWithIndex = (*Iterator)(nil) } @@ -126,14 +126,14 @@ func (iterator *Iterator) Index() int { return iterator.index } -func (set *Set) Each(f func(index interface{}, value interface{})) { +func (set *Set) Each(f func(index int, value interface{})) { iterator := set.Iterator() for iterator.Next() { f(iterator.Index(), iterator.Value()) } } -func (set *Set) Map(f func(index interface{}, value interface{}) interface{}) containers.Container { +func (set *Set) Map(f func(index int, value interface{}) interface{}) containers.Container { newSet := &Set{tree: rbt.NewWith(set.tree.Comparator)} iterator := set.Iterator() for iterator.Next() { @@ -142,7 +142,7 @@ func (set *Set) Map(f func(index interface{}, value interface{}) interface{}) co return newSet } -func (set *Set) Select(f func(index interface{}, value interface{}) bool) containers.Container { +func (set *Set) Select(f func(index int, value interface{}) bool) containers.Container { newSet := &Set{tree: rbt.NewWith(set.tree.Comparator)} iterator := set.Iterator() for iterator.Next() { @@ -153,7 +153,7 @@ func (set *Set) Select(f func(index interface{}, value interface{}) bool) contai return newSet } -func (set *Set) Any(f func(index interface{}, value interface{}) bool) bool { +func (set *Set) Any(f func(index int, value interface{}) bool) bool { iterator := set.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { @@ -163,7 +163,7 @@ func (set *Set) Any(f func(index interface{}, value interface{}) bool) bool { return false } -func (set *Set) All(f func(index interface{}, value interface{}) bool) bool { +func (set *Set) All(f func(index int, value interface{}) bool) bool { iterator := set.Iterator() for iterator.Next() { if !f(iterator.Index(), iterator.Value()) { @@ -173,14 +173,14 @@ func (set *Set) All(f func(index interface{}, value interface{}) bool) bool { return true } -func (set *Set) Find(f func(index interface{}, value interface{}) bool) (index interface{}, value interface{}) { +func (set *Set) Find(f func(index int, value interface{}) bool) (index int, value interface{}) { iterator := set.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { return iterator.Index(), iterator.Value() } } - return nil, nil + return -1, nil } func (set *Set) String() string { diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index 78f1e3a6..e725d82a 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -89,7 +89,7 @@ func TestTreeSetEnumerableAndIterator(t *testing.T) { set.Add("c", "a", "b") // Each - set.Each(func(index interface{}, value interface{}) { + set.Each(func(index int, value interface{}) { switch index { case 0: if actualValue, expectedValue := value, "a"; actualValue != expectedValue { @@ -109,7 +109,7 @@ func TestTreeSetEnumerableAndIterator(t *testing.T) { }) // Map - mappedSet := set.Map(func(index interface{}, value interface{}) interface{} { + mappedSet := set.Map(func(index int, value interface{}) interface{} { return "mapped: " + value.(string) }).(*Set) if actualValue, expectedValue := mappedSet.Contains("mapped: a", "mapped: b", "mapped: c"), true; actualValue != expectedValue { @@ -123,7 +123,7 @@ func TestTreeSetEnumerableAndIterator(t *testing.T) { } // Select - selectedSet := set.Select(func(index interface{}, value interface{}) bool { + selectedSet := set.Select(func(index int, value interface{}) bool { return value.(string) >= "a" && value.(string) <= "b" }).(*Set) if actualValue, expectedValue := selectedSet.Contains("a", "b"), true; actualValue != expectedValue { @@ -138,13 +138,13 @@ func TestTreeSetEnumerableAndIterator(t *testing.T) { } // Any - any := set.Any(func(index interface{}, value interface{}) bool { + 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 interface{}, value interface{}) bool { + any = set.Any(func(index int, value interface{}) bool { return value.(string) == "x" }) if any != false { @@ -152,13 +152,13 @@ func TestTreeSetEnumerableAndIterator(t *testing.T) { } // All - all := set.All(func(index interface{}, value interface{}) bool { + 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 interface{}, value interface{}) bool { + all = set.All(func(index int, value interface{}) bool { return value.(string) >= "a" && value.(string) <= "b" }) if all != false { @@ -166,16 +166,16 @@ func TestTreeSetEnumerableAndIterator(t *testing.T) { } // Find - foundIndex, foundValue := set.Find(func(index interface{}, value interface{}) bool { + foundIndex, foundValue := set.Find(func(index int, value interface{}) bool { return value.(string) == "c" }) if foundValue != "c" || foundIndex != 2 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, "c", 2) } - foundIndex, foundValue = set.Find(func(index interface{}, value interface{}) bool { + foundIndex, foundValue = set.Find(func(index int, value interface{}) bool { return value.(string) == "x" }) - if foundValue != nil || foundIndex != nil { + if foundValue != nil || foundIndex != -1 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil) } From f0206f2457a21365735c4faff07a81e030a247a0 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 22 Jun 2016 21:30:00 +0200 Subject: [PATCH 040/320] - add enumerable to tree map --- containers/enumerable.go | 18 +++--- maps/treemap/treemap.go | 59 ++++++++++++++++++ maps/treemap/treemap_test.go | 117 +++++++++++++++++++++++++++++++++-- 3 files changed, 179 insertions(+), 15 deletions(-) diff --git a/containers/enumerable.go b/containers/enumerable.go index ceb51fcc..a9c3debf 100644 --- a/containers/enumerable.go +++ b/containers/enumerable.go @@ -31,7 +31,7 @@ package containers // Enumerable function for ordered containers whose values can be fetched by an index. type EnumerableWithIndex interface { - // Calls the given function once for each element, passing that element's index(key) and value. + // Calls the given function once for each element, passing that element's index and value. Each(func(index int, value interface{})) // Invokes the given function once for each element and returns a @@ -50,33 +50,33 @@ type EnumerableWithIndex interface { All(func(index int, value interface{}) bool) bool // Passes each element of the collection to the given function and returns - // the first for which the function is true or nil,nil otherwise if no element + // the first for which the function is true or -1,nil otherwise if no element // matches the criteria. Find(func(index int, value interface{}) bool) (index int, value interface{}) } // Enumerable function for ordered containers whose values whose elements are key value pairs. type EnumerableWithKey interface { - // Calls the given function once for each element, passing that element's index(key) and value. - Each(func(index interface{}, value interface{})) + // Calls the given function once for each element, passing that element's key and value. + Each(func(key interface{}, value interface{})) // Invokes the given function once for each element and returns a // container containing the values returned by the given function. - Map(func(index interface{}, value interface{}) interface{}) Container + Map(func(key1 interface{}, value1 interface{}) (key2 interface{}, value2 interface{})) Container // Returns a new container containing all elements for which the given function returns a true value. - Select(func(index interface{}, value interface{}) bool) Container + Select(func(key interface{}, value interface{}) bool) Container // Passes each element of the collection to the given function and // returns true if the function ever returns true for any element. - Any(func(index interface{}, value interface{}) bool) bool + Any(func(key interface{}, value interface{}) bool) bool // Passes each element of the collection to the given function and // returns true if the function returns true for all elements. - All(func(index interface{}, value interface{}) bool) bool + All(func(key interface{}, value interface{}) bool) bool // Passes each element of the collection to the given function and returns // the first for which the function is true or nil,nil otherwise if no element // matches the criteria. - Find(func(index interface{}, value interface{}) bool) (index interface{}, value interface{}) + Find(func(key interface{}, value interface{}) bool) (key interface{}, value interface{}) } diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index 20e4ba2b..0ae8cc48 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -40,6 +40,7 @@ import ( func assertInterfaceImplementation() { var _ maps.Map = (*Map)(nil) + var _ containers.EnumerableWithKey = (*Map)(nil) var _ containers.IteratorWithKey = (*Iterator)(nil) } @@ -144,6 +145,64 @@ func (iterator *Iterator) Key() interface{} { return iterator.iterator.Key() } +func (m *Map) Each(f func(key interface{}, value interface{})) { + iterator := m.Iterator() + for iterator.Next() { + f(iterator.Key(), iterator.Value()) + } +} + +func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (key2 interface{}, value2 interface{})) containers.Container { + newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)} + iterator := m.Iterator() + for iterator.Next() { + key2, value2 := f(iterator.Key(), iterator.Value()) + newMap.Put(key2, value2) + } + return newMap +} + +func (m *Map) Select(f func(key interface{}, value interface{}) bool) containers.Container { + newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)} + iterator := m.Iterator() + for iterator.Next() { + if f(iterator.Key(), iterator.Value()) { + newMap.Put(iterator.Key(), iterator.Value()) + } + } + return newMap +} + +func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool { + iterator := m.Iterator() + for iterator.Next() { + if f(iterator.Key(), iterator.Value()) { + return true + } + } + return false +} + +func (m *Map) All(f func(key interface{}, value interface{}) bool) bool { + iterator := m.Iterator() + for iterator.Next() { + if !f(iterator.Key(), iterator.Value()) { + return false + } + } + return true +} + +func (m *Map) Find(f func(key interface{}, value interface{}) bool) (key interface{}, value interface{}) { + iterator := m.Iterator() + for iterator.Next() { + if f(iterator.Key(), iterator.Value()) { + return iterator.Key(), iterator.Value() + } + } + return nil, nil +} + func (m *Map) String() string { str := "TreeMap\n" str += m.tree.String() diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 95ee4592..3ad688cd 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -179,21 +179,126 @@ func TestTreeMap(t *testing.T) { } } -func TestTreeMapIterator(t *testing.T) { +func TestTreeMapEnumerableAndIterator(t *testing.T) { m := NewWithStringComparator() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) + // Each + count := 0 + m.Each(func(key interface{}, value interface{}) { + count += 1 + if actualValue, expectedValue := count, value; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + switch value { + case 1: + if actualValue, expectedValue := key, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := key, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 3: + if actualValue, expectedValue := key, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + }) + + // Map + mappedMap := m.Map(func(key1 interface{}, value1 interface{}) (key2 interface{}, value2 interface{}) { + return key1, "mapped: " + key1.(string) + }).(*Map) + if actualValue, _ := mappedMap.Get("a"); actualValue != "mapped: a" { + t.Errorf("Got %v expected %v", actualValue, "mapped: a") + } + if actualValue, _ := mappedMap.Get("b"); actualValue != "mapped: b" { + t.Errorf("Got %v expected %v", actualValue, "mapped: b") + } + if actualValue, _ := mappedMap.Get("c"); actualValue != "mapped: c" { + t.Errorf("Got %v expected %v", actualValue, "mapped: c") + } + if mappedMap.Size() != 3 { + t.Errorf("Got %v expected %v", mappedMap.Size(), 3) + } + + // Select + selectedMap := m.Select(func(key interface{}, value interface{}) bool { + return key.(string) >= "a" && key.(string) <= "b" + }).(*Map) + if actualValue, _ := selectedMap.Get("a"); actualValue != 1 { + t.Errorf("Got %v expected %v", actualValue, "value: a") + } + if actualValue, _ := selectedMap.Get("b"); actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, "value: b") + } + if selectedMap.Size() != 2 { + t.Errorf("Got %v expected %v", selectedMap.Size(), 3) + } + + // Any + any := m.Any(func(key interface{}, value interface{}) bool { + return value.(int) == 3 + }) + if any != true { + t.Errorf("Got %v expected %v", any, true) + } + any = m.Any(func(key interface{}, value interface{}) bool { + return value.(int) == 4 + }) + if any != false { + t.Errorf("Got %v expected %v", any, false) + } + + // All + all := m.All(func(key interface{}, value interface{}) bool { + return key.(string) >= "a" && key.(string) <= "c" + }) + if all != true { + t.Errorf("Got %v expected %v", all, true) + } + all = m.All(func(key interface{}, value interface{}) bool { + return key.(string) >= "a" && key.(string) <= "b" + }) + if all != false { + t.Errorf("Got %v expected %v", all, false) + } + + // Find + foundKey, foundValue := m.Find(func(key interface{}, value interface{}) bool { + return key.(string) == "c" + }) + if foundKey != "c" || foundValue != 3 { + t.Errorf("Got %v -> %v expected %v -> %v", foundKey, foundValue, "c", 3) + } + foundKey, foundValue = m.Find(func(key interface{}, value interface{}) bool { + return key.(string) == "x" + }) + if foundKey != nil || foundValue != nil { + t.Errorf("Got %v at %v expected %v at %v", foundValue, foundKey, nil, nil) + } + // Iterator it := m.Iterator() - count := 0 for it.Next() { - count += 1 + key := it.Key() value := it.Value() - switch value { - case count: - if actualValue, expectedValue := value, count; actualValue != expectedValue { + switch key { + case "a": + if actualValue, expectedValue := value, 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case "b": + if actualValue, expectedValue := value, 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case "c": + if actualValue, expectedValue := value, 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } default: From 8cb4635c2cf45c9fde621ae88f844115b8579cd0 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 24 Jun 2016 00:08:04 +0200 Subject: [PATCH 041/320] - code document all enumarable functions and iterators in containers --- containers/enumerable.go | 28 +++++++++++----------- containers/iterator.go | 2 ++ lists/arraylist/arraylist.go | 21 +++++++++++++++- lists/doublylinkedlist/doublylinkedlist.go | 25 ++++++++++++++++--- lists/singlylinkedlist/singlylinkedlist.go | 25 ++++++++++++++++--- maps/treemap/treemap.go | 23 ++++++++++++++++-- sets/treeset/treeset.go | 21 +++++++++++++++- stacks/arraystack/arraystack.go | 8 +++++++ stacks/linkedliststack/linkedliststack.go | 8 +++++++ trees/binaryheap/binaryheap.go | 8 +++++++ trees/redblacktree/redblacktree.go | 8 +++++++ 11 files changed, 153 insertions(+), 24 deletions(-) diff --git a/containers/enumerable.go b/containers/enumerable.go index a9c3debf..ede0e784 100644 --- a/containers/enumerable.go +++ b/containers/enumerable.go @@ -41,18 +41,18 @@ type EnumerableWithIndex interface { // Returns a new container containing all elements for which the given function returns a true value. Select(func(index int, value interface{}) bool) Container - // Passes each element of the collection to the given function and + // 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 - // Passes each element of the collection to the given function and + // 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 - // Passes each element of the collection to the given function and returns - // the first for which the function is true or -1,nil otherwise if no element - // matches the criteria. - Find(func(index int, value interface{}) bool) (index int, value interface{}) + // 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{}) } // Enumerable function for ordered containers whose values whose elements are key value pairs. @@ -60,23 +60,23 @@ type EnumerableWithKey interface { // Calls the given function once for each element, passing that element's key and value. Each(func(key interface{}, value interface{})) - // Invokes the given function once for each element and returns a - // container containing the values returned by the given function. - Map(func(key1 interface{}, value1 interface{}) (key2 interface{}, value2 interface{})) Container + // Invokes the given function once for each element and returns a container + // containing the values returned by the given function as key/value pairs. + Map(func(key interface{}, value interface{}) (interface{}, interface{})) Container // Returns a new container containing all elements for which the given function returns a true value. Select(func(key interface{}, value interface{}) bool) Container - // Passes each element of the collection to the given function and + // 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 - // Passes each element of the collection to the given function and + // 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 - // Passes each element of the collection to the given function and returns - // the first for which the function is true or nil,nil otherwise if no element + // 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) (key interface{}, value interface{}) + Find(func(key interface{}, value interface{}) bool) (interface{}, interface{}) } diff --git a/containers/iterator.go b/containers/iterator.go index db0ea7a9..45d06188 100644 --- a/containers/iterator.go +++ b/containers/iterator.go @@ -31,6 +31,7 @@ package containers // Stateful iterator for ordered containers whose values can be fetched by an index. type IteratorWithIndex interface { // 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(). // Modifies the state of the iterator. Next() bool // Returns the current element's value. @@ -44,6 +45,7 @@ type IteratorWithIndex interface { // Stateful iterator for ordered containers whose elements are key value pairs. type IteratorWithKey interface { // 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(). // Modifies the state of the iterator. Next() bool // Returns the current element's value. diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index 3025a52b..d5773851 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -183,23 +183,32 @@ type Iterator struct { index int } +// Returns a stateful iterator whose values can be fetched by an index. func (list *List) Iterator() Iterator { return Iterator{list: list, index: -1} } +// 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(). +// Modifies the state of the iterator. func (iterator *Iterator) Next() bool { iterator.index += 1 return iterator.list.withinRange(iterator.index) } +// Returns the current element's value. +// Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { return iterator.list.elements[iterator.index] } +// Returns the current element's index. +// Does not modify the state of the iterator. func (iterator *Iterator) Index() int { return iterator.index } +// Calls the given function once for each element, passing that element's index and value. func (list *List) Each(f func(index int, value interface{})) { iterator := list.Iterator() for iterator.Next() { @@ -207,6 +216,8 @@ func (list *List) Each(f func(index int, value interface{})) { } } +// Invokes the given function once for each element and returns a +// container containing the values returned by the given function. func (list *List) Map(f func(index int, value interface{}) interface{}) containers.Container { newList := &List{} iterator := list.Iterator() @@ -216,6 +227,7 @@ func (list *List) Map(f func(index int, value interface{}) interface{}) containe return newList } +// Returns a new container containing all elements for which the given function returns a true value. func (list *List) Select(f func(index int, value interface{}) bool) containers.Container { newList := &List{} iterator := list.Iterator() @@ -227,6 +239,8 @@ func (list *List) Select(f func(index int, value interface{}) bool) containers.C return newList } +// Passes each element of the collection to the given function and +// returns true if the function ever returns true for any element. func (list *List) Any(f func(index int, value interface{}) bool) bool { iterator := list.Iterator() for iterator.Next() { @@ -237,6 +251,8 @@ func (list *List) Any(f func(index int, value interface{}) bool) bool { return false } +// Passes each element of the collection to the given function and +// returns true if the function returns true for all elements. func (list *List) All(f func(index int, value interface{}) bool) bool { iterator := list.Iterator() for iterator.Next() { @@ -247,7 +263,10 @@ func (list *List) All(f func(index int, value interface{}) bool) bool { return true } -func (list *List) Find(f func(index int, value interface{}) bool) (index int, value interface{}) { +// 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 (list *List) Find(f func(index int, value interface{}) bool) (int, interface{}) { iterator := list.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 514a9e61..2fa22d4f 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -306,32 +306,41 @@ type Iterator struct { element *element } +// Returns a stateful iterator whose values can be fetched by an index. func (list *List) Iterator() Iterator { return Iterator{list: list, index: -1, element: nil} } +// 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(). +// Modifies the state of the iterator. func (iterator *Iterator) Next() bool { iterator.index += 1 if !iterator.list.withinRange(iterator.index) { iterator.element = nil return false } - if iterator.element == nil { - iterator.element = iterator.list.first - } else { + if iterator.element != nil { iterator.element = iterator.element.next + } else { + iterator.element = iterator.list.first } return true } +// Returns the current element's value. +// Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { return iterator.element.value } +// Returns the current element's index. +// Does not modify the state of the iterator. func (iterator *Iterator) Index() int { return iterator.index } +// Calls the given function once for each element, passing that element's index and value. func (list *List) Each(f func(index int, value interface{})) { iterator := list.Iterator() for iterator.Next() { @@ -339,6 +348,8 @@ func (list *List) Each(f func(index int, value interface{})) { } } +// Invokes the given function once for each element and returns a +// container containing the values returned by the given function. func (list *List) Map(f func(index int, value interface{}) interface{}) containers.Container { newList := &List{} iterator := list.Iterator() @@ -348,6 +359,7 @@ func (list *List) Map(f func(index int, value interface{}) interface{}) containe return newList } +// Returns a new container containing all elements for which the given function returns a true value. func (list *List) Select(f func(index int, value interface{}) bool) containers.Container { newList := &List{} iterator := list.Iterator() @@ -359,6 +371,8 @@ func (list *List) Select(f func(index int, value interface{}) bool) containers.C return newList } +// Passes each element of the container to the given function and +// returns true if the function ever returns true for any element. func (list *List) Any(f func(index int, value interface{}) bool) bool { iterator := list.Iterator() for iterator.Next() { @@ -369,6 +383,8 @@ func (list *List) Any(f func(index int, value interface{}) bool) bool { return false } +// Passes each element of the container to the given function and +// returns true if the function returns true for all elements. func (list *List) All(f func(index int, value interface{}) bool) bool { iterator := list.Iterator() for iterator.Next() { @@ -379,6 +395,9 @@ func (list *List) All(f func(index int, value interface{}) bool) bool { return true } +// 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 (list *List) Find(f func(index int, value interface{}) bool) (index int, value interface{}) { iterator := list.Iterator() for iterator.Next() { diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 50c9a57f..52e834e0 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -276,32 +276,41 @@ type Iterator struct { element *element } +// Returns a stateful iterator whose values can be fetched by an index. func (list *List) Iterator() Iterator { return Iterator{list: list, index: -1, element: nil} } +// 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(). +// Modifies the state of the iterator. func (iterator *Iterator) Next() bool { iterator.index += 1 if !iterator.list.withinRange(iterator.index) { iterator.element = nil return false } - if iterator.element == nil { - iterator.element = iterator.list.first - } else { + if iterator.element != nil { iterator.element = iterator.element.next + } else { + iterator.element = iterator.list.first } return true } +// Returns the current element's value. +// Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { return iterator.element.value } +// Returns the current element's index. +// Does not modify the state of the iterator. func (iterator *Iterator) Index() int { return iterator.index } +// Calls the given function once for each element, passing that element's index and value. func (list *List) Each(f func(index int, value interface{})) { iterator := list.Iterator() for iterator.Next() { @@ -309,6 +318,8 @@ func (list *List) Each(f func(index int, value interface{})) { } } +// Invokes the given function once for each element and returns a +// container containing the values returned by the given function. func (list *List) Map(f func(index int, value interface{}) interface{}) containers.Container { newList := &List{} iterator := list.Iterator() @@ -318,6 +329,7 @@ func (list *List) Map(f func(index int, value interface{}) interface{}) containe return newList } +// Returns a new container containing all elements for which the given function returns a true value. func (list *List) Select(f func(index int, value interface{}) bool) containers.Container { newList := &List{} iterator := list.Iterator() @@ -329,6 +341,8 @@ func (list *List) Select(f func(index int, value interface{}) bool) containers.C return newList } +// Passes each element of the container to the given function and +// returns true if the function ever returns true for any element. func (list *List) Any(f func(index int, value interface{}) bool) bool { iterator := list.Iterator() for iterator.Next() { @@ -339,6 +353,8 @@ func (list *List) Any(f func(index int, value interface{}) bool) bool { return false } +// Passes each element of the container to the given function and +// returns true if the function returns true for all elements. func (list *List) All(f func(index int, value interface{}) bool) bool { iterator := list.Iterator() for iterator.Next() { @@ -349,6 +365,9 @@ func (list *List) All(f func(index int, value interface{}) bool) bool { return true } +// 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 (list *List) Find(f func(index int, value interface{}) bool) (index int, value interface{}) { iterator := list.Iterator() for iterator.Next() { diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index 0ae8cc48..c8aee762 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -129,22 +129,31 @@ type Iterator struct { iterator rbt.Iterator } +// Returns a stateful iterator whose elements are key/value pairs. func (m *Map) Iterator() Iterator { return Iterator{iterator: m.tree.Iterator()} } +// 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(). +// Modifies the state of the iterator. func (iterator *Iterator) Next() bool { return iterator.iterator.Next() } +// Returns the current element's value. +// Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { return iterator.iterator.Value() } +// Returns the current element's key. +// Does not modify the state of the iterator. func (iterator *Iterator) Key() interface{} { return iterator.iterator.Key() } +// Calls the given function once for each element, passing that element's key and value. func (m *Map) Each(f func(key interface{}, value interface{})) { iterator := m.Iterator() for iterator.Next() { @@ -152,7 +161,9 @@ func (m *Map) Each(f func(key interface{}, value interface{})) { } } -func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (key2 interface{}, value2 interface{})) containers.Container { +// Invokes the given function once for each element and returns a container +// containing the values returned by the given function as key/value pairs. +func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) containers.Container { newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)} iterator := m.Iterator() for iterator.Next() { @@ -162,6 +173,7 @@ func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (key2 interface{} return newMap } +// Returns a new container containing all elements for which the given function returns a true value. func (m *Map) Select(f func(key interface{}, value interface{}) bool) containers.Container { newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)} iterator := m.Iterator() @@ -173,6 +185,8 @@ func (m *Map) Select(f func(key interface{}, value interface{}) bool) containers return newMap } +// Passes each element of the container to the given function and +// returns true if the function ever returns true for any element. func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool { iterator := m.Iterator() for iterator.Next() { @@ -183,6 +197,8 @@ func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool { return false } +// Passes each element of the container to the given function and +// returns true if the function returns true for all elements. func (m *Map) All(f func(key interface{}, value interface{}) bool) bool { iterator := m.Iterator() for iterator.Next() { @@ -193,7 +209,10 @@ func (m *Map) All(f func(key interface{}, value interface{}) bool) bool { return true } -func (m *Map) Find(f func(key interface{}, value interface{}) bool) (key interface{}, value interface{}) { +// 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. +func (m *Map) Find(f func(key interface{}, value interface{}) bool) (interface{}, interface{}) { iterator := m.Iterator() for iterator.Next() { if f(iterator.Key(), iterator.Value()) { diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 51bd6215..b9ca141f 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -109,23 +109,32 @@ type Iterator struct { iterator rbt.Iterator } +// Returns a stateful iterator whose values can be fetched by an index. func (set *Set) Iterator() Iterator { return Iterator{index: -1, iterator: set.tree.Iterator()} } +// 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(). +// Modifies the state of the iterator. func (iterator *Iterator) Next() bool { iterator.index += 1 return iterator.iterator.Next() } +// Returns the current element's value. +// Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { return iterator.iterator.Key() } +// Returns the current element's index. +// Does not modify the state of the iterator. func (iterator *Iterator) Index() int { return iterator.index } +// 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() { @@ -133,6 +142,8 @@ func (set *Set) Each(f func(index int, value interface{})) { } } +// 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{}) containers.Container { newSet := &Set{tree: rbt.NewWith(set.tree.Comparator)} iterator := set.Iterator() @@ -142,6 +153,7 @@ func (set *Set) Map(f func(index int, value interface{}) interface{}) containers return newSet } +// 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) containers.Container { newSet := &Set{tree: rbt.NewWith(set.tree.Comparator)} iterator := set.Iterator() @@ -153,6 +165,8 @@ func (set *Set) Select(f func(index int, value interface{}) bool) containers.Con return newSet } +// 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() { @@ -163,6 +177,8 @@ func (set *Set) Any(f func(index int, value interface{}) bool) bool { return false } +// 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() { @@ -173,7 +189,10 @@ func (set *Set) All(f func(index int, value interface{}) bool) bool { return true } -func (set *Set) Find(f func(index int, value interface{}) bool) (index int, value interface{}) { +// 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()) { diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index c775e80f..22769570 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -101,20 +101,28 @@ type Iterator struct { index int } +// Returns a stateful iterator whose values can be fetched by an index. func (stack *Stack) Iterator() Iterator { return Iterator{stack: stack, index: -1} } +// 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(). +// Modifies the state of the iterator. func (iterator *Iterator) Next() bool { iterator.index += 1 return iterator.stack.withinRange(iterator.index) } +// Returns the current element's value. +// Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { value, _ := iterator.stack.list.Get(iterator.stack.list.Size() - iterator.index - 1) // in reverse (LIFO) return value } +// Returns the current element's index. +// Does not modify the state of the iterator. func (iterator *Iterator) Index() int { return iterator.index } diff --git a/stacks/linkedliststack/linkedliststack.go b/stacks/linkedliststack/linkedliststack.go index 7bf5d03d..551377e9 100644 --- a/stacks/linkedliststack/linkedliststack.go +++ b/stacks/linkedliststack/linkedliststack.go @@ -97,20 +97,28 @@ type Iterator struct { index int } +// Returns a stateful iterator whose values can be fetched by an index. func (stack *Stack) Iterator() Iterator { return Iterator{stack: stack, index: -1} } +// 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(). +// Modifies the state of the iterator. func (iterator *Iterator) Next() bool { iterator.index += 1 return iterator.stack.withinRange(iterator.index) } +// Returns the current element's value. +// Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { value, _ := iterator.stack.list.Get(iterator.index) // in reverse (LIFO) return value } +// Returns the current element's index. +// Does not modify the state of the iterator. func (iterator *Iterator) Index() int { return iterator.index } diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index ab7452ba..79e7ec58 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -116,20 +116,28 @@ type Iterator struct { index int } +// Returns a stateful iterator whose values can be fetched by an index. func (heap *Heap) Iterator() Iterator { return Iterator{heap: heap, index: -1} } +// 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(). +// Modifies the state of the iterator. func (iterator *Iterator) Next() bool { iterator.index += 1 return iterator.heap.withinRange(iterator.index) } +// Returns the current element's value. +// Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { value, _ := iterator.heap.list.Get(iterator.index) return value } +// Returns the current element's index. +// Does not modify the state of the iterator. func (iterator *Iterator) Index() int { return iterator.index } diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index da000ad5..c6a033e3 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -279,10 +279,14 @@ type Iterator struct { left *Node } +// Returns a stateful iterator whose elements are key/value pairs. func (tree *Tree) Iterator() Iterator { return Iterator{tree: tree, left: nil} } +// 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(). +// Modifies the state of the iterator. func (iterator *Iterator) Next() bool { if iterator.left == nil { iterator.left = iterator.tree.Left() @@ -307,10 +311,14 @@ func (iterator *Iterator) Next() bool { return false } +// Returns the current element's value. +// Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { return iterator.left.Value } +// Returns the current element's key. +// Does not modify the state of the iterator. func (iterator *Iterator) Key() interface{} { return iterator.left.Key } From 49c50d0c4d9c228162f244630264d5384725aa66 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 24 Jun 2016 00:30:35 +0200 Subject: [PATCH 042/320] Update README.md --- README.md | 223 +++++++++++++++++++++++++++++------------------------- 1 file changed, 118 insertions(+), 105 deletions(-) diff --git a/README.md b/README.md index 6d6b9488..361086ad 100644 --- a/README.md +++ b/README.md @@ -7,13 +7,13 @@ Implementation of various data structures in Go. ## Data Structures - [Containers](#containers) - - [Sets](#sets) - - [HashSet](#hashset) - - [TreeSet](#treeset) - [Lists](#lists) - [ArrayList](#arraylist) - [SinglyLinkedList](#singlylinkedlist) - [DoublyLinkedList](#doublylinkedlist) + - [Sets](#sets) + - [HashSet](#hashset) + - [TreeSet](#treeset) - [Stacks](#stacks) - [LinkedListStack](#linkedliststack) - [ArrayStack](#arraystack) @@ -28,7 +28,7 @@ Implementation of various data structures in Go. - [Sort](#sort) -###Containers +## Containers All data structures implement the container interface with the following methods: @@ -41,90 +41,28 @@ type Container interface { } ``` -Container specific operations: - -```go -// Returns sorted container's elements with respect to the passed comparator. -// Does not effect the ordering of elements within the container. -// Uses timsort. -func GetSortedValues(container Container, comparator utils.Comparator) []interface{} { -``` - -####Sets - -A set is a data structure that can store elements and no repeated values. It is a computer implementation of the mathematical concept of a finite set. Unlike most other collection types, rather than retrieving a specific element from a set, one typically tests an element for membership in a set. This structed is often used to ensure that no duplicates are present in a collection. - -All sets implement the set interface with the following methods: - -```go -type Set interface { - Add(elements ...interface{}) - Remove(elements ...interface{}) - Contains(elements ...interface{}) bool - - containers.Container - // Empty() bool - // Size() int - // Clear() - // Values() []interface{} -} -``` - -#####HashSet +Containers are either ordered or unordered: -This structure implements the Set interface and is backed by a hash table (actually a Go's map). It makes no guarantees as to the iteration order of the set, since Go randomizes this iteration order on maps. +- Ordered containers: + - ArrayList + - SinglyLinkedList + - DoublyLinkedList + - TreeSet + - LinkedListStack + - ArrayStack + - TreeMap + - RedBlackTree + - BinaryHeap +- Unordered containers: + - HashSet + - HashMap -This structure offers constant time performance for the basic operations (add, remove, contains and size). +All ordered containers have stateful iterators: -```go -package main +- IteratorWithIndex (iterates over containers whose elements are referenced by an index) +- IteratorWithKey (iterates over containers whose elements are referenced by a key) -import "github.com/emirpasic/gods/sets/hashset" - -func main() { - set := hashset.New() // empty - set.Add(1) // 1 - set.Add(2, 2, 3, 4, 5) // 3, 1, 2, 4, 5 (random order, duplicates ignored) - set.Remove(4) // 5, 3, 2, 1 (random order) - set.Remove(2, 3) // 1, 5 (random order) - set.Contains(1) // true - set.Contains(1, 5) // true - set.Contains(1, 6) // false - _ = set.Values() // []int{5,1} (random order) - set.Clear() // empty - set.Empty() // true - set.Size() // 0 -} -``` - -#####TreeSet - -This structure implements the Set interface and is backed by a red-black tree to keep the elements sorted with respect to the comparator. - -This implementation provides guaranteed log(n) time cost for the basic operations (add, remove and contains). - -```go -package main - -import "github.com/emirpasic/gods/sets/treeset" - -func main() { - set := treeset.NewWithIntComparator() // empty (keys are of type int) - set.Add(1) // 1 - set.Add(2, 2, 3, 4, 5) // 1, 2, 3, 4, 5 (in order, duplicates ignored) - set.Remove(4) // 1, 2, 3, 5 (in order) - set.Remove(2, 3) // 1, 5 (in order) - set.Contains(1) // true - set.Contains(1, 5) // true - set.Contains(1, 6) // false - _ = set.Values() // []int{1,5} (in order) - set.Clear() // empty - set.Empty() // true - set.Size() // 0 -} -``` - -####Lists +### Lists A list is a data structure that can store values and may have repeated values. There is no ordering in a list. The user can access and remove a value by the index position. @@ -148,7 +86,7 @@ type List interface { } ``` -#####ArrayList +#### ArrayList This structure implements the List interface and is backed by a dynamic array that grows and shrinks implicitly (by 100% when capacity is reached). @@ -186,7 +124,7 @@ func main() { } ``` -#####SinglyLinkedList +#### SinglyLinkedList This structure implements the _List_ interface and is a linked data structure where each value points to the next in the list. @@ -223,7 +161,7 @@ func main() { } ``` -#####DoublyLinkedList +#### DoublyLinkedList This structure implements the _List_ interface and is a linked data structure where each value points to the next and previous element in the list. @@ -260,8 +198,81 @@ func main() { } ``` +### Sets + +A set is a data structure that can store elements and no repeated values. It is a computer implementation of the mathematical concept of a finite set. Unlike most other collection types, rather than retrieving a specific element from a set, one typically tests an element for membership in a set. This structed is often used to ensure that no duplicates are present in a collection. + +All sets implement the set interface with the following methods: + +```go +type Set interface { + Add(elements ...interface{}) + Remove(elements ...interface{}) + Contains(elements ...interface{}) bool + + containers.Container + // Empty() bool + // Size() int + // Clear() + // Values() []interface{} +} +``` + +#### HashSet + +This structure implements the Set interface and is backed by a hash table (actually a Go's map). It makes no guarantees as to the iteration order of the set, since Go randomizes this iteration order on maps. + +This structure offers constant time performance for the basic operations (add, remove, contains and size). + +```go +package main + +import "github.com/emirpasic/gods/sets/hashset" + +func main() { + set := hashset.New() // empty + set.Add(1) // 1 + set.Add(2, 2, 3, 4, 5) // 3, 1, 2, 4, 5 (random order, duplicates ignored) + set.Remove(4) // 5, 3, 2, 1 (random order) + set.Remove(2, 3) // 1, 5 (random order) + set.Contains(1) // true + set.Contains(1, 5) // true + set.Contains(1, 6) // false + _ = set.Values() // []int{5,1} (random order) + set.Clear() // empty + set.Empty() // true + set.Size() // 0 +} +``` + +#### TreeSet -####Stacks +This structure implements the Set interface and is backed by a red-black tree to keep the elements sorted with respect to the comparator. + +This implementation provides guaranteed log(n) time cost for the basic operations (add, remove and contains). + +```go +package main + +import "github.com/emirpasic/gods/sets/treeset" + +func main() { + set := treeset.NewWithIntComparator() // empty (keys are of type int) + set.Add(1) // 1 + set.Add(2, 2, 3, 4, 5) // 1, 2, 3, 4, 5 (in order, duplicates ignored) + set.Remove(4) // 1, 2, 3, 5 (in order) + set.Remove(2, 3) // 1, 5 (in order) + set.Contains(1) // true + set.Contains(1, 5) // true + set.Contains(1, 6) // false + _ = set.Values() // []int{1,5} (in order) + set.Clear() // empty + set.Empty() // true + set.Size() // 0 +} +``` + +### Stacks The stack interface represents a last-in-first-out (LIFO) collection of objects. The usual push and pop operations are provided, as well as a method to peek at the top item on the stack, a method to check whether the stack is empty and the size (number of elements). @@ -307,7 +318,7 @@ func main() { } ``` -#####ArrayStack +#### ArrayStack This stack structure is back by ArrayList. @@ -334,7 +345,7 @@ func main() { } ``` -####Maps +### Maps Structure that maps keys to values. A map cannot contain duplicate keys and each key can map to at most one value. @@ -354,7 +365,7 @@ type Map interface { } ``` -#####HashMap +#### HashMap Map structure based on hash tables, more exactly, Go's map. Keys are unordered. @@ -381,7 +392,7 @@ func main() { } ``` -#####TreeMap +#### TreeMap Map structure based on our red-black tree implementation. Keys are ordered with respect to the passed comparator. @@ -414,7 +425,7 @@ func main() { } ``` -####Trees +### Trees A tree is a widely used data data structure that simulates a hierarchical tree structure, with a root value and subtrees of children, represented as a set of linked nodes; thus no cyclic links. @@ -429,7 +440,7 @@ type Tree interface { } ``` -#####RedBlackTree +#### RedBlackTree A red–black tree is a binary search tree with an extra bit of data per node, its color, which can be either red or black. The extra bit of storage ensures an approximately balanced tree by constraining how nodes are colored from any path from the root to the leaf. Thus, it is a data structure which is a type of self-balancing binary search tree. @@ -493,7 +504,7 @@ func main() { Extending the red-black tree's functionality has been demonstrated in the following [example](https://github.com/emirpasic/gods/blob/master/examples/redblacktreeextended.go). -#####BinaryHeap +#### BinaryHeap A binary heap is a heap data structure created using a binary tree. It can be seen as a binary tree with two additional constraints: @@ -544,11 +555,11 @@ func main() { } ``` -### Functions +## Functions Various helper functions used throughout the library. -#### Comparator +### Comparator Some data structures (e.g. TreeMap, TreeSet) require a comparator function to sort their contained elements. This comparator is necessary during the initalization. @@ -569,7 +580,8 @@ Comparator signature: Two common comparators are included in the library: -#####IntComparator +#### IntComparator + ```go func IntComparator(a, b interface{}) int { aInt := a.(int) @@ -585,7 +597,8 @@ func IntComparator(a, b interface{}) int { } ``` -#####StringComparator +#### StringComparator + ```go func StringComparator(a, b interface{}) int { s1 := a.(string) @@ -611,7 +624,7 @@ func StringComparator(a, b interface{}) int { } ``` -#####CustomComparator +#### CustomComparator ```go package main @@ -654,7 +667,7 @@ func main() { } ``` -#### Sort +### Sort Sort uses timsort for best performance on real-world data. Lists have an in-place _Sort()_ method. All containers can return their sorted elements via _GetSortedValues()_ call. @@ -675,11 +688,11 @@ func main() { } ``` -## Motivations +# Motivations Collections and data structures found in other languages: Java Collections, C++ Standard Template Library (STL) containers, Qt Containers, etc. -## Goals +# Goals **Fast algorithms**: @@ -709,7 +722,7 @@ There is often a tug of war between speed and memory when crafting algorithms. W Thread safety is not a concern of this project, this should be handled at a higher level. -## Testing and Benchmarking +# Testing and Benchmarking `go test -v -bench . -benchmem -benchtime 1s ./...` @@ -719,7 +732,7 @@ Biggest contribution towards this library is to use it and give us feedback for For direct contributions, branch of from master and do _pull request_. -## License +# License This library is distributed under the BSD-style license found in the [LICENSE](https://github.com/emirpasic/gods/blob/master/LICENSE) file. From 07e8634b62fe905caa4120b93ab592c53f02272c Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 24 Jun 2016 02:41:16 +0200 Subject: [PATCH 043/320] Update README.md --- README.md | 314 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 202 insertions(+), 112 deletions(-) diff --git a/README.md b/README.md index 361086ad..d83fe885 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -[![Build Status](https://travis-ci.org/emirpasic/gods.svg)](https://travis-ci.org/emirpasic/gods) [![GoDoc](https://godoc.org/github.com/emirpasic/gods?status.svg)](https://godoc.org/github.com/emirpasic/gods) +[![GoDoc](https://godoc.org/github.com/emirpasic/gods?status.svg)](https://godoc.org/github.com/emirpasic/gods) [![Build Status](https://travis-ci.org/emirpasic/gods.svg)](https://travis-ci.org/emirpasic/gods) [![PyPI](https://img.shields.io/pypi/l/Django.svg?maxAge=2592000)](https://github.com/emirpasic/gods/blob/enums/LICENSE) # GoDS (Go Data Structures) -Implementation of various data structures in Go. +Implementation of various data structures and algorithms in Go. ## Data Structures @@ -25,7 +25,14 @@ Implementation of various data structures in Go. - [BinaryHeap](#binaryheap) - [Functions](#functions) - [Comparator](#comparator) + - [Iterator](#iterator) + - [IteratorWithIndex](#iteratorwithindex) + - [IteratorWithKey](#iteratorwithkey) + - [Enumerable](#enumerable) + - [EnumerableWithIndex](#enumerablewithindex) + - [EnumerableWithKey](#enumerablewithkey) - [Sort](#sort) + - [Container](#container) ## Containers @@ -41,32 +48,27 @@ type Container interface { } ``` -Containers are either ordered or unordered: - -- Ordered containers: - - ArrayList - - SinglyLinkedList - - DoublyLinkedList - - TreeSet - - LinkedListStack - - ArrayStack - - TreeMap - - RedBlackTree - - BinaryHeap -- Unordered containers: - - HashSet - - HashMap - -All ordered containers have stateful iterators: - -- IteratorWithIndex (iterates over containers whose elements are referenced by an index) -- IteratorWithKey (iterates over containers whose elements are referenced by a key) +Containers are either ordered or unordered. All ordered containers provide [stateful iterators](iterator) and some of them allow [enumerable functions](#enumerable). + +| Container | Ordered | [Iterator](iterator) | [Enumerable](#enumerable) | Ordered by | +| :--- | :---: | :---: | :---: | :---: | +| [ArrayList](#arraylist) | yes | yes | yes | index | +| [SinglyLinkedList](#singlylinkedlist) | yes | yes | yes | index | +| [DoublyLinkedList](#doublylinkedlist) | yes | yes | yes | index | +| [HashSet](#hashset) | no | no | no | index | +| [TreeSet](#treeset) | yes | yes | yes | index | +| [LinkedListStack](#linkedliststack) | yes | yes | no | index | +| [ArrayStack](#arraystack) | yes | yes | no | index | +| [HashMap](#hashmap) | no | no | no | key | +| [TreeMap](#treemap) | yes | yes | yes | key | +| [RedBlackTree](#redblacktree) | yes | yes | yes | key | +| [BinaryHeap](#binaryheap) | yes | yes | yes | index | ### Lists -A list is a data structure that can store values and may have repeated values. There is no ordering in a list. The user can access and remove a value by the index position. +A list is a data structure that stores values and may have repeated values. -All lists implement the list interface with the following methods: +Implements [Container](#containers) interface. ```go type List interface { @@ -88,10 +90,9 @@ type List interface { #### ArrayList -This structure implements the List interface and is backed by a dynamic array that grows and shrinks implicitly (by 100% when capacity is reached). - -Direct access method _Get(index)_ is guaranteed a constant time performance. Remove is of linear time performance. Checking with _Contains()_ is of quadratic complexity. +A [list](#lists) backed by a dynamic array that grows and shrinks implicitly. +Implements [List](#lists), [IteratorWithIndex](#iteratorwithindex) and [EnumerableWithIndex](#enumerablewithindex) interfaces. ```go package main @@ -126,9 +127,9 @@ func main() { #### SinglyLinkedList -This structure implements the _List_ interface and is a linked data structure where each value points to the next in the list. +A [list](#lists) where each element points to the next element in the list. -Direct access method _Get(index)_ and _Remove()_ are of linear performance. _Append_ and _Prepend_ are of constant time performance. Checking with _Contains()_ is of quadratic complexity. +Implements [List](#lists), [IteratorWithIndex](#iteratorwithindex) and [EnumerableWithIndex](#enumerablewithindex) interfaces. ```go package main @@ -163,9 +164,9 @@ func main() { #### DoublyLinkedList -This structure implements the _List_ interface and is a linked data structure where each value points to the next and previous element in the list. +A [list](#lists) where each element points to the next and previous elements in the list. -Direct access method _Get(index)_ and _Remove()_ are of linear performance. _Append_ and _Prepend_ are of constant time performance. Checking with _Contains()_ is of quadratic complexity. +Implements [List](#lists), [IteratorWithIndex](#iteratorwithindex) and [EnumerableWithIndex](#enumerablewithindex) interfaces. ```go package main @@ -200,9 +201,9 @@ func main() { ### Sets -A set is a data structure that can store elements and no repeated values. It is a computer implementation of the mathematical concept of a finite set. Unlike most other collection types, rather than retrieving a specific element from a set, one typically tests an element for membership in a set. This structed is often used to ensure that no duplicates are present in a collection. +A set is a data structure that can store elements and has no repeated values. It is a computer implementation of the mathematical concept of a finite set. Unlike most other collection types, rather than retrieving a specific element from a set, one typically tests an element for membership in a set. This structed is often used to ensure that no duplicates are present in a container. -All sets implement the set interface with the following methods: +Implements [Container](#containers) interface. ```go type Set interface { @@ -220,9 +221,9 @@ type Set interface { #### HashSet -This structure implements the Set interface and is backed by a hash table (actually a Go's map). It makes no guarantees as to the iteration order of the set, since Go randomizes this iteration order on maps. +A [set](#sets) backed by a hash table (actually a Go's map). It makes no guarantees as to the iteration order of the set. -This structure offers constant time performance for the basic operations (add, remove, contains and size). +Implements [Set](#sets) interface. ```go package main @@ -247,9 +248,9 @@ func main() { #### TreeSet -This structure implements the Set interface and is backed by a red-black tree to keep the elements sorted with respect to the comparator. +A [set](#sets) backed by a [red-black tree](#redblacktree) to keep the elements ordered with respect to the [comparator](#comparator). -This implementation provides guaranteed log(n) time cost for the basic operations (add, remove and contains). +Implements [Set](#sets), [IteratorWithIndex](#iteratorwithindex) and [EnumerableWithIndex](#enumerablewithindex) interfaces. ```go package main @@ -274,9 +275,10 @@ func main() { ### Stacks -The stack interface represents a last-in-first-out (LIFO) collection of objects. The usual push and pop operations are provided, as well as a method to peek at the top item on the stack, a method to check whether the stack is empty and the size (number of elements). +A stack that represents a last-in-first-out (LIFO) data structure. The usual push and pop operations are provided, as well as a method to peek at the top item on the stack. + +Implements [Container](#containers) interface. -All stacks implement the stack interface with the following methods: ```go type Stack interface { Push(value interface{}) @@ -291,11 +293,11 @@ type Stack interface { } ``` -#####LinkedListStack +#### LinkedListStack -This stack structure is based on a linked list, i.e. each previous element has a point to the next. +A [stack](#stacks) based on a [linked list](#singlylinkedlist). -All operations are guaranteed constant time performance, except _Values()_, which is as always of linear time performance. +Implements [Stack](#stacks) and [IteratorWithIndex](#iteratorwithindex) interfaces. ```go package main @@ -320,9 +322,9 @@ func main() { #### ArrayStack -This stack structure is back by ArrayList. +A [stack](#stacks) based on a [array list](#arraylist). -All operations are guaranted constant time performance. +Implements [Stack](#stacks) and [IteratorWithIndex](#iteratorwithindex) interfaces. ```go package main @@ -347,9 +349,10 @@ func main() { ### Maps -Structure that maps keys to values. A map cannot contain duplicate keys and each key can map to at most one value. +A Map is a data structure that maps keys to values. A map cannot contain duplicate keys and each key can map to at most one value. + +Implements [Container](#containers) interface. -All maps implement the map interface with the following methods: ```go type Map interface { Put(key interface{}, value interface{}) @@ -367,9 +370,9 @@ type Map interface { #### HashMap -Map structure based on hash tables, more exactly, Go's map. Keys are unordered. +A [map](#maps) based on hash tables. Keys are unordered. -All operations are guaranted constant time performance, except _Key()_ and _Values()_ retrieval that of linear time performance. +Implements [Map](#maps) interface. ```go package main @@ -379,7 +382,7 @@ import "github.com/emirpasic/gods/maps/hashmap" func main() { m := hashmap.New() // empty m.Put(1, "x") // 1->x - m.Put(2, "b") // 2->b, 1->x (random order) + m.Put(2, "b") // 2->b, 1->x (random order) m.Put(1, "a") // 2->b, 1->a (random order) _, _ = m.Get(2) // b, true _, _ = m.Get(3) // nil, false @@ -394,11 +397,9 @@ func main() { #### TreeMap -Map structure based on our red-black tree implementation. Keys are ordered with respect to the passed comparator. +A [map](#maps) based on [red-black tree](#redblacktree). Keys are ordered ordered with respect to the [comparator](#comparator). -_Put()_, _Get()_ and _Remove()_ are guaranteed log(n) time performance. - -_Key()_ and _Values()_ methods return keys and values respectively in order of the keys. These meethods are quaranteed linear time performance. +Implements [Map](#maps), [IteratorWithKey](#iteratorwithkey) and [EnumerableWithKey](#enumerablewithkey) interfaces. ```go package main @@ -429,7 +430,8 @@ func main() { A tree is a widely used data data structure that simulates a hierarchical tree structure, with a root value and subtrees of children, represented as a set of linked nodes; thus no cyclic links. -All trees implement the tree interface with the following methods: +Implements [Container](#containers) interface. + ```go type Tree interface { containers.Container @@ -442,9 +444,11 @@ type Tree interface { #### RedBlackTree -A red–black tree is a binary search tree with an extra bit of data per node, its color, which can be either red or black. The extra bit of storage ensures an approximately balanced tree by constraining how nodes are colored from any path from the root to the leaf. Thus, it is a data structure which is a type of self-balancing binary search tree. +A red–black [tree](#trees) is a binary search tree with an extra bit of data per node, its color, which can be either red or black. The extra bit of storage ensures an approximately balanced tree by constraining how nodes are colored from any path from the root to the leaf. Thus, it is a data structure which is a type of self-balancing binary search tree. + +The balancing of the tree is not perfect but it is good enough to allow it to guarantee searching in O(log n) time, where n is the total number of elements in the tree. The insertion and deletion operations, along with the tree rearrangement and recoloring, are also performed in O(log n) time. [Wikipedia](http://en.wikipedia.org/wiki/Red%E2%80%93black_tree) -The balancing of the tree is not perfect but it is good enough to allow it to guarantee searching in O(log n) time, where n is the total number of elements in the tree. The insertion and deletion operations, along with the tree rearrangement and recoloring, are also performed in O(log n) time.[Wikipedia](http://en.wikipedia.org/wiki/Red%E2%80%93black_tree) +Implements [Tree](#trees) and [IteratorWithKey](#iteratorwithkey) interfaces.
@@ -457,7 +461,7 @@ import ( ) func main() { - tree := rbt.NewWithIntComparator() // empty(keys are of type int) + tree := rbt.NewWithIntComparator() // empty (keys are of type int) tree.Put(1, "x") // 1->x tree.Put(2, "b") // 1->x, 2->b (in order) @@ -506,7 +510,7 @@ Extending the red-black tree's functionality has been demonstrated in the follo #### BinaryHeap -A binary heap is a heap data structure created using a binary tree. It can be seen as a binary tree with two additional constraints: +A binary heap is a [tree](#trees) created using a binary tree. It can be seen as a binary tree with two additional constraints: - Shape property: @@ -514,6 +518,8 @@ A binary heap is a heap data structure created using a binary tree. It can be se - Heap property: All nodes are either greater than or equal to or less than or equal to each of its children, according to a comparison predicate defined for the heap. [Wikipedia](http://en.wikipedia.org/wiki/Binary_heap) + +Implements [Tree](#trees) and [IteratorWithIndex](#iteratorwithindex) interfaces.
@@ -561,70 +567,36 @@ Various helper functions used throughout the library. ### Comparator -Some data structures (e.g. TreeMap, TreeSet) require a comparator function to sort their contained elements. This comparator is necessary during the initalization. +Some data structures (e.g. TreeMap, TreeSet) require a comparator function to automatically keep their elements sorted upon insertion. This comparator is necessary during the initalization. Comparator is defined as: - -```go Return values: - -1, if a < b - 0, if a == b - 1, if a > b +```go +-1, if a < b + 0, if a == b + 1, if a > b +``` Comparator signature: - type Comparator func(a, b interface{}) int +```go +type Comparator func(a, b interface{}) int ``` Two common comparators are included in the library: -#### IntComparator - ```go -func IntComparator(a, b interface{}) int { - aInt := a.(int) - bInt := b.(int) - switch { - case aInt > bInt: - return 1 - case aInt < bInt: - return -1 - default: - return 0 - } -} +func IntComparator(a, b interface{}) int ``` -#### StringComparator - ```go -func StringComparator(a, b interface{}) int { - s1 := a.(string) - s2 := b.(string) - min := len(s2) - if len(s1) < len(s2) { - min = len(s1) - } - diff := 0 - for i := 0; i < min && diff == 0; i++ { - diff = int(s1[i]) - int(s2[i]) - } - if diff == 0 { - diff = len(s1) - len(s2) - } - if diff < 0 { - return -1 - } - if diff > 0 { - return 1 - } - return 0 -} +func StringComparator(a, b interface{}) int ``` -#### CustomComparator +Writing custom comparators is easy: + ```go package main @@ -638,7 +610,7 @@ type User struct { name string } -// Comparator function (sort by IDs) +// Custom comparator (sort by IDs) func byID(a, b interface{}) int { // Type assertion, program will panic if this is not respected @@ -667,6 +639,104 @@ func main() { } ``` +### Iterator + +All ordered containers have stateful iterators. Typically an iterator is obtained by _Iterator()_ function of an ordered container. Once obtained, iterator's _Next()_ function moves the iterator to the next element and returns true if there was a next element. If there was an element, then element's can be obtained by iterator's _Value()_ function. Depending on the ordering type, it's position can be obtained by iterator's _Index()_ or _Key()_ functions. ' + +#### IteratorWithIndex + +A [iterator](#iterator) whose elements are referenced by an index. Typical usage: + +```go +it := list.Iterator() +for it.Next() { + index, value := it.Index(), it.Value() + ... +} +``` + +#### IteratorWithKey + +A [iterator](#iterator) whose elements are referenced by a key. Typical usage: + +```go +it := map.Iterator() +for it.Next() { + key, value := it.Key(), it.Value() + ... +} +``` + +### Enumerable + +Enumerable functions for ordered containers that implement [EnumerableWithIndex](#enumerablewithindex) or [EnumerableWithKey](#enumerablewithkey) interfaces. + +#### EnumerableWithIndex + +Enumerable function for ordered containers whose values can be fetched by an index. + +Definition: + +```go +type EnumerableWithIndex interface { + // Calls the given function once for each element, passing that element's index and value. + Each(func(index int, value interface{})) + + // Invokes the given function once for each element and returns a + // container containing the values returned by the given function. + Map(func(index int, value interface{}) interface{}) Container + + // Returns a new container containing all elements for which the given function returns a true value. + Select(func(index int, value interface{}) bool) Container + + // 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 + + // 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 + + // 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{}) +} +``` + +#### EnumerableWithKey + +Enumerable functions for ordered containers whose values whose elements are key/value pairs. + +Definition: + +```go +type EnumerableWithKey interface { + // Calls the given function once for each element, passing that element's key and value. + Each(func(key interface{}, value interface{})) + + // Invokes the given function once for each element and returns a container + // containing the values returned by the given function as key/value pairs. + Map(func(key interface{}, value interface{}) (interface{}, interface{})) Container + + // Returns a new container containing all elements for which the given function returns a true value. + Select(func(key interface{}, value interface{}) bool) Container + + // 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 + + // 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 + + // 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{}) +} +``` + ### Sort Sort uses timsort for best performance on real-world data. Lists have an in-place _Sort()_ method. All containers can return their sorted elements via _GetSortedValues()_ call. @@ -688,11 +758,31 @@ func main() { } ``` -# Motivations +### Container + +Container specific operations: + +```go +// Returns sorted container''s elements with respect to the passed comparator. +// Does not effect the ordering of elements within the container. +// Uses timsort. +func GetSortedValues(container Container, comparator utils.Comparator) []interface{} +``` + +Usage: + +```go + list.Add(2, 1, 3) + values := GetSortedValues(container, utils.StringComparator) // [1, 2, 3] +``` + +## Appendix + +### Motivation -Collections and data structures found in other languages: Java Collections, C++ Standard Template Library (STL) containers, Qt Containers, etc. +Collections and data structures found in other languages: Java Collections, C++ Standard Template Library (STL) containers, Qt Containers, Ruby Enumerable etc. -# Goals +### Goals **Fast algorithms**: @@ -722,17 +812,17 @@ There is often a tug of war between speed and memory when crafting algorithms. W Thread safety is not a concern of this project, this should be handled at a higher level. -# Testing and Benchmarking +### Testing and Benchmarking `go test -v -bench . -benchmem -benchtime 1s ./...` -## Contributing +### Contributing Biggest contribution towards this library is to use it and give us feedback for further improvements and additions. -For direct contributions, branch of from master and do _pull request_. +For direct contributions, _pull request_ into master or ask to become a contributor. -# License +### License This library is distributed under the BSD-style license found in the [LICENSE](https://github.com/emirpasic/gods/blob/master/LICENSE) file. From beb6027d2fbe214739ed65c2442630ddc60ffc33 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 24 Jun 2016 04:12:22 +0200 Subject: [PATCH 044/320] - documentation updates --- README.md | 131 +++++++++++++++++++++++++-------------- containers/enumerable.go | 4 +- 2 files changed, 85 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index d83fe885..c51408d8 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,8 @@ Implementation of various data structures and algorithms in Go. - [EnumerableWithKey](#enumerablewithkey) - [Sort](#sort) - [Container](#container) - +- [Appendix](#appendix) + ## Containers @@ -48,9 +49,9 @@ type Container interface { } ``` -Containers are either ordered or unordered. All ordered containers provide [stateful iterators](iterator) and some of them allow [enumerable functions](#enumerable). +Containers are either ordered or unordered. All ordered containers provide [stateful iterators](#iterator) and some of them allow [enumerable functions](#enumerable). -| Container | Ordered | [Iterator](iterator) | [Enumerable](#enumerable) | Ordered by | +| Container | Ordered | [Iterator](#iterator) | [Enumerable](#enumerable) | Ordered by | | :--- | :---: | :---: | :---: | :---: | | [ArrayList](#arraylist) | yes | yes | yes | index | | [SinglyLinkedList](#singlylinkedlist) | yes | yes | yes | index | @@ -518,7 +519,7 @@ A binary heap is a [tree](#trees) created using a binary tree. It can be seen as - Heap property: All nodes are either greater than or equal to or less than or equal to each of its children, according to a comparison predicate defined for the heap. [Wikipedia](http://en.wikipedia.org/wiki/Binary_heap) - + Implements [Tree](#trees) and [IteratorWithIndex](#iteratorwithindex) interfaces.
@@ -641,7 +642,7 @@ func main() { ### Iterator -All ordered containers have stateful iterators. Typically an iterator is obtained by _Iterator()_ function of an ordered container. Once obtained, iterator's _Next()_ function moves the iterator to the next element and returns true if there was a next element. If there was an element, then element's can be obtained by iterator's _Value()_ function. Depending on the ordering type, it's position can be obtained by iterator's _Index()_ or _Key()_ functions. ' +All ordered containers have stateful iterators. Typically an iterator is obtained by _Iterator()_ function of an ordered container. Once obtained, iterator's _Next()_ function moves the iterator to the next element and returns true if there was a next element. If there was an element, then element's can be obtained by iterator's _Value()_ function. Depending on the ordering type, it's position can be obtained by iterator's _Index()_ or _Key()_ functions. #### IteratorWithIndex @@ -673,68 +674,92 @@ Enumerable functions for ordered containers that implement [EnumerableWithIndex] #### EnumerableWithIndex -Enumerable function for ordered containers whose values can be fetched by an index. +[Enumerable](#enumerable) functions for ordered containers whose values can be fetched by an index. -Definition: +**Each**: Calls the given function once for each element, passing that element's index and value. ```go -type EnumerableWithIndex interface { - // 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 interface{})) +``` - // Invokes the given function once for each element and returns a - // container containing the values returned by the given function. - Map(func(index int, value interface{}) interface{}) Container +**Map**: Invokes the given function once for each element and returns a container containing the values returned by the given function. - // Returns a new container containing all elements for which the given function returns a true value. - Select(func(index int, value interface{}) bool) Container +```go +Map(func(index int, value interface{}) interface{}) Container +``` - // 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 +**Select**: Returns a new container containing all elements for which the given function returns a true value. - // 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 +```go +Select(func(index int, value interface{}) bool) Container +``` - // 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{}) -} +**Any**: Passes each element of the container to the given function and returns true if the function ever returns true for any element. + +```go +Any(func(index int, value interface{}) bool) bool +``` + +**All**: Passes each element of the container to the given function and returns true if the function returns true for all elements. + +```go +All(func(index int, value interface{}) 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. + +```go +Find(func(index int, value interface{}) bool) (int, interface{})} +``` + +Typical usage: +```go +TODO ``` #### EnumerableWithKey Enumerable functions for ordered containers whose values whose elements are key/value pairs. -Definition: +**Each**: Calls the given function once for each element, passing that element's key and value. + +```go +Each(func(key interface{}, value interface{})) +``` + +**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. ```go -type EnumerableWithKey interface { - // Calls the given function once for each element, passing that element's key and value. - Each(func(key interface{}, value interface{})) +Map(func(key interface{}, value interface{}) (interface{}, interface{})) Container +``` - // Invokes the given function once for each element and returns a container - // containing the values returned by the given function as key/value pairs. - Map(func(key interface{}, value interface{}) (interface{}, interface{})) Container +**Select**: Returns a new container containing all elements for which the given function returns a true value. - // Returns a new container containing all elements for which the given function returns a true value. - Select(func(key interface{}, value interface{}) bool) Container +```go +Select(func(key interface{}, value interface{}) bool) Container +``` - // 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**: Passes each element of the container to the given function and returns true if the function ever returns true for any element. - // 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 +```go +Any(func(key interface{}, value interface{}) bool) bool +``` - // 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{}) -} +**All**: Passes each element of the container to the given function and returns true if the function returns true for all elements. + +```go +All(func(key interface{}, value interface{}) 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. + +```go +Find(func(key interface{}, value interface{}) bool) (interface{}, interface{}) +``` + +Typical usage: +```go +TODO ``` ### Sort @@ -763,8 +788,8 @@ func main() { Container specific operations: ```go -// Returns sorted container''s elements with respect to the passed comparator. -// Does not effect the ordering of elements within the container. +// Returns sorted container''s elements with respect to the passed comparator. +// Does not effect the ordering of elements within the container. // Uses timsort. func GetSortedValues(container Container, comparator utils.Comparator) []interface{} ``` @@ -772,8 +797,18 @@ func GetSortedValues(container Container, comparator utils.Comparator) []interfa Usage: ```go +package main + +import ( + "github.com/emirpasic/gods/lists/arraylist" + "github.com/emirpasic/gods/utils" +) + +func main() { + list := arraylist.New() list.Add(2, 1, 3) values := GetSortedValues(container, utils.StringComparator) // [1, 2, 3] +} ``` ## Appendix diff --git a/containers/enumerable.go b/containers/enumerable.go index ede0e784..89ca07ef 100644 --- a/containers/enumerable.go +++ b/containers/enumerable.go @@ -29,7 +29,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package containers -// Enumerable function for ordered containers whose values can be fetched by an index. +// Enumerable functions for ordered containers whose values can be fetched by an index. type EnumerableWithIndex interface { // Calls the given function once for each element, passing that element's index and value. Each(func(index int, value interface{})) @@ -55,7 +55,7 @@ type EnumerableWithIndex interface { Find(func(index int, value interface{}) bool) (int, interface{}) } -// Enumerable function for ordered containers whose values whose elements are key value pairs. +// Enumerable functions for ordered containers whose values whose elements are key/value pairs. type EnumerableWithKey interface { // Calls the given function once for each element, passing that element's key and value. Each(func(key interface{}, value interface{})) From 8aba2d70fe286826da392934d834617bcb55d88c Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 24 Jun 2016 06:18:51 +0200 Subject: [PATCH 045/320] - update main documentation - create examples for enumerables operations --- README.md | 175 +++++++++++++++++++++++++++++--- examples/enumerablewithindex.go | 83 +++++++++++++++ examples/enumerablewithkey.go | 91 +++++++++++++++++ 3 files changed, 334 insertions(+), 15 deletions(-) create mode 100644 examples/enumerablewithindex.go create mode 100644 examples/enumerablewithkey.go diff --git a/README.md b/README.md index c51408d8..38990f62 100644 --- a/README.md +++ b/README.md @@ -676,82 +676,163 @@ Enumerable functions for ordered containers that implement [EnumerableWithIndex] [Enumerable](#enumerable) functions for ordered containers whose values can be fetched by an index. -**Each**: Calls the given function once for each element, passing that element's index and value. +**Each** + +Calls the given function once for each element, passing that element's index and value. ```go Each(func(index int, value interface{})) ``` -**Map**: Invokes the given function once for each element and returns a container containing the values returned by the given function. +**Map** + +Invokes the given function once for each element and returns a container containing the values returned by the given function. ```go Map(func(index int, value interface{}) interface{}) Container ``` -**Select**: Returns a new container containing all elements for which the given function returns a true value. +**Select** + +Returns a new container containing all elements for which the given function returns a true value. ```go Select(func(index int, value interface{}) bool) Container ``` -**Any**: Passes each element of the container to the given function and returns true if the function ever returns true for any element. +**Any** + +Passes each element of the container to the given function and returns true if the function ever returns true for any element. ```go Any(func(index int, value interface{}) 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** + +Passes each element of the container to the given function and returns true if the function returns true for all elements. ```go All(func(index int, value interface{}) 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** + +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. ```go Find(func(index int, value interface{}) bool) (int, interface{})} ``` -Typical usage: +**Example: ** + ```go -TODO +package main + +import ( + "fmt" + "github.com/emirpasic/gods/sets/treeset" +) + +func main() { + set := treeset.NewWithIntComparator() + set.Add(2, 3, 4, 2, 5, 6, 7, 8) + fmt.Println(set) // TreeSet [2, 3, 4, 5, 6, 7, 8] + + // Calculates sum. + sum := 0 + set.Each(func(index int, value interface{}) { + sum += value.(int) + }) + fmt.Println(sum) // 35 + + // Selects all even numbers into a new set. + even := set.Select(func(index int, value interface{}) bool { + return value.(int)%2 == 0 + }) + fmt.Println(even) // TreeSet [2, 4, 6, 8] + + // Finds first number divisible by 2 and 3 + foundIndex, foundValue := set.Find(func(index int, value interface{}) bool { + return value.(int)%2 == 0 && value.(int)%3 == 0 + }) + fmt.Println(foundIndex, foundValue) // index: 4, value: 6 + + // Squares each number in a new set. + square := set.Map(func(index int, value interface{}) interface{} { + return value.(int) * value.(int) + }) + fmt.Println(square) // TreeSet [4, 9, 16, 25, 36, 49, 64] + + // Tests if any number is bigger than 5 + bigger := set.Any(func(index int, value interface{}) bool { + return value.(int) > 5 + }) + fmt.Println(bigger) // true + + // Tests if all numbers are positive + positive := set.All(func(index int, value interface{}) bool { + return value.(int) > 0 + }) + fmt.Println(positive) // true + + // Chaining + evenNumbersSquared := set.Select(func(index int, value interface{}) bool { + return value.(int)%2 == 0 + }).Map(func(index int, value interface{}) interface{} { + return value.(int) * value.(int) + }) + fmt.Println(evenNumbersSquared) // TreeSet [4, 16, 36, 64] +} ``` #### EnumerableWithKey Enumerable functions for ordered containers whose values whose elements are key/value pairs. -**Each**: Calls the given function once for each element, passing that element's key and value. +**Each** + +Calls the given function once for each element, passing that element's key and value. ```go Each(func(key interface{}, value interface{})) ``` -**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. +**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. ```go Map(func(key interface{}, value interface{}) (interface{}, interface{})) Container ``` -**Select**: Returns a new container containing all elements for which the given function returns a true value. +**Select** + +Returns a new container containing all elements for which the given function returns a true value. ```go Select(func(key interface{}, value interface{}) bool) Container ``` -**Any**: Passes each element of the container to the given function and returns true if the function ever returns true for any element. +**Any** + +Passes each element of the container to the given function and returns true if the function ever returns true for any element. ```go Any(func(key interface{}, value interface{}) 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** + +Passes each element of the container to the given function and returns true if the function returns true for all elements. ```go All(func(key interface{}, value interface{}) 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** + +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. ```go Find(func(key interface{}, value interface{}) bool) (interface{}, interface{}) @@ -759,7 +840,71 @@ Find(func(key interface{}, value interface{}) bool) (interface{}, interface{}) Typical usage: ```go -TODO +package main + +import ( + "fmt" + "github.com/emirpasic/gods/maps/treemap" + "strconv" +) + +func prettyPrint(m *treemap.Map) { + fmt.Print("{ ") + m.Each(func(key interface{}, value interface{}) { + fmt.Print(key.(string) + ": " + strconv.Itoa(value.(int)) + " ") + }) + fmt.Println("}") +} + +func main() { + m := treemap.NewWithStringComparator() + m.Put("g", 7) + m.Put("f", 6) + m.Put("e", 5) + m.Put("d", 4) + m.Put("c", 3) + m.Put("b", 2) + m.Put("a", 1) + prettyPrint(m) // { a: 1 b: 2 c: 3 d: 4 e: 5 f: 6 g: 7 } + + // Selects all elements with even values into a new map. + even := m.Select(func(key interface{}, value interface{}) bool { + return value.(int)%2 == 0 + }) + prettyPrint(even) // { b: 2 d: 4 f: 6 } + + // Finds first element whose value is divisible by 2 and 3 + foundKey, foundValue := m.Find(func(key interface{}, value interface{}) bool { + return value.(int)%2 == 0 && value.(int)%3 == 0 + }) + fmt.Println(foundKey, foundValue) // key: f, value: 6 + + // Creates a new map containing same elements with their values squared and letters duplicated. + square := m.Map(func(key interface{}, value interface{}) (interface{}, interface{}) { + return key.(string) + key.(string), value.(int) * value.(int) + }) + prettyPrint(square) // { aa: 1 bb: 4 cc: 9 dd: 16 ee: 25 ff: 36 gg: 49 } + + // Tests if any element contains value that is bigger than 5 + bigger := m.Any(func(key interface{}, value interface{}) bool { + return value.(int) > 5 + }) + fmt.Println(bigger) // true + + // Tests if all elements' values are positive + positive := m.All(func(key interface{}, value interface{}) bool { + return value.(int) > 0 + }) + fmt.Println(positive) // true + + // Chaining + evenNumbersSquared := m.Select(func(key interface{}, value interface{}) bool { + return value.(int)%2 == 0 + }).Map(func(key interface{}, value interface{}) (interface{}, interface{}) { + return key, value.(int) * value.(int) + }) + prettyPrint(evenNumbersSquared) // { b: 4 d: 16 f: 36 } +} ``` ### Sort diff --git a/examples/enumerablewithindex.go b/examples/enumerablewithindex.go new file mode 100644 index 00000000..54907ce3 --- /dev/null +++ b/examples/enumerablewithindex.go @@ -0,0 +1,83 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package examples + +import ( + "fmt" + "github.com/emirpasic/gods/sets/treeset" +) + +func EnumerableWithIndexExample() { + set := treeset.NewWithIntComparator() + set.Add(2, 3, 4, 2, 5, 6, 7, 8) + fmt.Println(set) // TreeSet [2, 3, 4, 5, 6, 7, 8] + + // Calculates sum. + sum := 0 + set.Each(func(index int, value interface{}) { + sum += value.(int) + }) + fmt.Println(sum) // 35 + + // Selects all even numbers into a new set. + even := set.Select(func(index int, value interface{}) bool { + return value.(int)%2 == 0 + }) + fmt.Println(even) // TreeSet [2, 4, 6, 8] + + // Finds first number divisible by 2 and 3 + foundIndex, foundValue := set.Find(func(index int, value interface{}) bool { + return value.(int)%2 == 0 && value.(int)%3 == 0 + }) + fmt.Println(foundIndex, foundValue) // index: 4, value: 6 + + // Squares each number in a new set. + square := set.Map(func(index int, value interface{}) interface{} { + return value.(int) * value.(int) + }) + fmt.Println(square) // TreeSet [4, 9, 16, 25, 36, 49, 64] + + // Tests if any number is bigger than 5 + bigger := set.Any(func(index int, value interface{}) bool { + return value.(int) > 5 + }) + fmt.Println(bigger) // true + + // Tests if all numbers are positive + positive := set.All(func(index int, value interface{}) bool { + return value.(int) > 0 + }) + fmt.Println(positive) // true + + // Chaining + evenNumbersSquared := set.Select(func(index int, value interface{}) bool { + return value.(int)%2 == 0 + }).Map(func(index int, value interface{}) interface{} { + return value.(int) * value.(int) + }) + fmt.Println(evenNumbersSquared) // TreeSet [4, 16, 36, 64] +} diff --git a/examples/enumerablewithkey.go b/examples/enumerablewithkey.go new file mode 100644 index 00000000..a5678a3c --- /dev/null +++ b/examples/enumerablewithkey.go @@ -0,0 +1,91 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package examples + +import ( + "fmt" + "github.com/emirpasic/gods/maps/treemap" + "strconv" +) + +func prettyPrint(m *treemap.Map) { + fmt.Print("{ ") + m.Each(func(key interface{}, value interface{}) { + fmt.Print(key.(string) + ": " + strconv.Itoa(value.(int)) + " ") + }) + fmt.Println("}") +} + +func EnumerableWithKeyExample() { + m := treemap.NewWithStringComparator() + m.Put("g", 7) + m.Put("f", 6) + m.Put("e", 5) + m.Put("d", 4) + m.Put("c", 3) + m.Put("b", 2) + m.Put("a", 1) + prettyPrint(m) // { a: 1 b: 2 c: 3 d: 4 e: 5 f: 6 g: 7 } + + // Selects all elements with even values into a new map. + even := m.Select(func(key interface{}, value interface{}) bool { + return value.(int)%2 == 0 + }) + prettyPrint(even) // { b: 2 d: 4 f: 6 } + + // Finds first element whose value is divisible by 2 and 3 + foundKey, foundValue := m.Find(func(key interface{}, value interface{}) bool { + return value.(int)%2 == 0 && value.(int)%3 == 0 + }) + fmt.Println(foundKey, foundValue) // key: f, value: 6 + + // Creates a new map containing same elements with their values squared and letters duplicated. + square := m.Map(func(key interface{}, value interface{}) (interface{}, interface{}) { + return key.(string) + key.(string), value.(int) * value.(int) + }) + prettyPrint(square) // { aa: 1 bb: 4 cc: 9 dd: 16 ee: 25 ff: 36 gg: 49 } + + // Tests if any element contains value that is bigger than 5 + bigger := m.Any(func(key interface{}, value interface{}) bool { + return value.(int) > 5 + }) + fmt.Println(bigger) // true + + // Tests if all elements' values are positive + positive := m.All(func(key interface{}, value interface{}) bool { + return value.(int) > 0 + }) + fmt.Println(positive) // true + + // Chaining + evenNumbersSquared := m.Select(func(key interface{}, value interface{}) bool { + return value.(int)%2 == 0 + }).Map(func(key interface{}, value interface{}) (interface{}, interface{}) { + return key, value.(int) * value.(int) + }) + prettyPrint(evenNumbersSquared) // { b: 4 d: 16 f: 36 } +} From 544abaeab1884c23544c6687aee82be404decfe6 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 24 Jun 2016 06:20:24 +0200 Subject: [PATCH 046/320] - remove map and select functions from enumerable interface, because this requires type assertions in chaining, which is really ugly and unnecessary. the only drawback is that one might forget to implement those functions and interface implementations asserts will not register that. (need help on this) --- containers/enumerable.go | 12 ++++++++---- lists/arraylist/arraylist.go | 4 ++-- lists/arraylist/arraylist_test.go | 4 ++-- lists/doublylinkedlist/doublylinkedlist.go | 4 ++-- lists/doublylinkedlist/doublylinkedlist_test.go | 4 ++-- lists/singlylinkedlist/singlylinkedlist.go | 4 ++-- lists/singlylinkedlist/singlylinkedlist_test.go | 4 ++-- maps/treemap/treemap.go | 4 ++-- maps/treemap/treemap_test.go | 4 ++-- sets/treeset/treeset.go | 4 ++-- sets/treeset/treeset_test.go | 4 ++-- 11 files changed, 28 insertions(+), 24 deletions(-) diff --git a/containers/enumerable.go b/containers/enumerable.go index 89ca07ef..5824b23e 100644 --- a/containers/enumerable.go +++ b/containers/enumerable.go @@ -36,10 +36,12 @@ type EnumerableWithIndex interface { // Invokes the given function once for each element and returns a // container containing the values returned by the given function. - Map(func(index int, value interface{}) interface{}) Container + // TODO need help on how to enforce this in containers (don't want to type assert when chaining) + // Map(func(index int, value interface{}) interface{}) Container // Returns a new container containing all elements for which the given function returns a true value. - Select(func(index int, value interface{}) bool) Container + // TODO need help on how to enforce this in containers (don't want to type assert when chaining) + // Select(func(index int, value interface{}) bool) Container // Passes each element of the container to the given function and // returns true if the function ever returns true for any element. @@ -62,10 +64,12 @@ type EnumerableWithKey interface { // Invokes the given function once for each element and returns a container // containing the values returned by the given function as key/value pairs. - Map(func(key interface{}, value interface{}) (interface{}, interface{})) Container + // TODO need help on how to enforce this in containers (don't want to type assert when chaining) + // Map(func(key interface{}, value interface{}) (interface{}, interface{})) Container // Returns a new container containing all elements for which the given function returns a true value. - Select(func(key interface{}, value interface{}) bool) Container + // TODO need help on how to enforce this in containers (don't want to type assert when chaining) + // Select(func(key interface{}, value interface{}) bool) Container // Passes each element of the container to the given function and // returns true if the function ever returns true for any element. diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index d5773851..cdcd2d93 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -218,7 +218,7 @@ func (list *List) Each(f func(index int, value interface{})) { // Invokes the given function once for each element and returns a // container containing the values returned by the given function. -func (list *List) Map(f func(index int, value interface{}) interface{}) containers.Container { +func (list *List) Map(f func(index int, value interface{}) interface{}) *List { newList := &List{} iterator := list.Iterator() for iterator.Next() { @@ -228,7 +228,7 @@ func (list *List) Map(f func(index int, value interface{}) interface{}) containe } // Returns a new container containing all elements for which the given function returns a true value. -func (list *List) Select(f func(index int, value interface{}) bool) containers.Container { +func (list *List) Select(f func(index int, value interface{}) bool) *List { newList := &List{} iterator := list.Iterator() for iterator.Next() { diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 68c499a4..c3f0c581 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -162,7 +162,7 @@ func TestArrayListEnumerableAndIterator(t *testing.T) { // Map mappedList := list.Map(func(index int, value interface{}) interface{} { return "mapped: " + value.(string) - }).(*List) + }) if actualValue, _ := mappedList.Get(0); actualValue != "mapped: a" { t.Errorf("Got %v expected %v", actualValue, "mapped: a") } @@ -179,7 +179,7 @@ func TestArrayListEnumerableAndIterator(t *testing.T) { // Select selectedList := list.Select(func(index int, value interface{}) bool { return value.(string) >= "a" && value.(string) <= "b" - }).(*List) + }) if actualValue, _ := selectedList.Get(0); actualValue != "a" { t.Errorf("Got %v expected %v", actualValue, "value: a") } diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 2fa22d4f..73f7e59b 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -350,7 +350,7 @@ func (list *List) Each(f func(index int, value interface{})) { // Invokes the given function once for each element and returns a // container containing the values returned by the given function. -func (list *List) Map(f func(index int, value interface{}) interface{}) containers.Container { +func (list *List) Map(f func(index int, value interface{}) interface{}) *List { newList := &List{} iterator := list.Iterator() for iterator.Next() { @@ -360,7 +360,7 @@ func (list *List) Map(f func(index int, value interface{}) interface{}) containe } // Returns a new container containing all elements for which the given function returns a true value. -func (list *List) Select(f func(index int, value interface{}) bool) containers.Container { +func (list *List) Select(f func(index int, value interface{}) bool) *List { newList := &List{} iterator := list.Iterator() for iterator.Next() { diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 6d580c80..5e8331d0 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -164,7 +164,7 @@ func TestDoublyLinkedListEnumerableAndIterator(t *testing.T) { // Map mappedList := list.Map(func(index int, value interface{}) interface{} { return "mapped: " + value.(string) - }).(*List) + }) if actualValue, _ := mappedList.Get(0); actualValue != "mapped: a" { t.Errorf("Got %v expected %v", actualValue, "mapped: a") } @@ -181,7 +181,7 @@ func TestDoublyLinkedListEnumerableAndIterator(t *testing.T) { // Select selectedList := list.Select(func(index int, value interface{}) bool { return value.(string) >= "a" && value.(string) <= "b" - }).(*List) + }) if actualValue, _ := selectedList.Get(0); actualValue != "a" { t.Errorf("Got %v expected %v", actualValue, "value: a") } diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 52e834e0..e71a36f7 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -320,7 +320,7 @@ func (list *List) Each(f func(index int, value interface{})) { // Invokes the given function once for each element and returns a // container containing the values returned by the given function. -func (list *List) Map(f func(index int, value interface{}) interface{}) containers.Container { +func (list *List) Map(f func(index int, value interface{}) interface{}) *List { newList := &List{} iterator := list.Iterator() for iterator.Next() { @@ -330,7 +330,7 @@ func (list *List) Map(f func(index int, value interface{}) interface{}) containe } // Returns a new container containing all elements for which the given function returns a true value. -func (list *List) Select(f func(index int, value interface{}) bool) containers.Container { +func (list *List) Select(f func(index int, value interface{}) bool) *List { newList := &List{} iterator := list.Iterator() for iterator.Next() { diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index c5ce3781..d5879c34 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -164,7 +164,7 @@ func TestSinglyLinkedListEnumerableAndIterator(t *testing.T) { // Map mappedList := list.Map(func(index int, value interface{}) interface{} { return "mapped: " + value.(string) - }).(*List) + }) if actualValue, _ := mappedList.Get(0); actualValue != "mapped: a" { t.Errorf("Got %v expected %v", actualValue, "mapped: a") } @@ -181,7 +181,7 @@ func TestSinglyLinkedListEnumerableAndIterator(t *testing.T) { // Select selectedList := list.Select(func(index int, value interface{}) bool { return value.(string) >= "a" && value.(string) <= "b" - }).(*List) + }) if actualValue, _ := selectedList.Get(0); actualValue != "a" { t.Errorf("Got %v expected %v", actualValue, "value: a") } diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index c8aee762..b18f293a 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -163,7 +163,7 @@ func (m *Map) Each(f func(key interface{}, value interface{})) { // Invokes the given function once for each element and returns a container // containing the values returned by the given function as key/value pairs. -func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) containers.Container { +func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) *Map { newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)} iterator := m.Iterator() for iterator.Next() { @@ -174,7 +174,7 @@ func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, int } // Returns a new container containing all elements for which the given function returns a true value. -func (m *Map) Select(f func(key interface{}, value interface{}) bool) containers.Container { +func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map { newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)} iterator := m.Iterator() for iterator.Next() { diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 3ad688cd..4335b7f3 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -213,7 +213,7 @@ func TestTreeMapEnumerableAndIterator(t *testing.T) { // Map mappedMap := m.Map(func(key1 interface{}, value1 interface{}) (key2 interface{}, value2 interface{}) { return key1, "mapped: " + key1.(string) - }).(*Map) + }) if actualValue, _ := mappedMap.Get("a"); actualValue != "mapped: a" { t.Errorf("Got %v expected %v", actualValue, "mapped: a") } @@ -230,7 +230,7 @@ func TestTreeMapEnumerableAndIterator(t *testing.T) { // Select selectedMap := m.Select(func(key interface{}, value interface{}) bool { return key.(string) >= "a" && key.(string) <= "b" - }).(*Map) + }) if actualValue, _ := selectedMap.Get("a"); actualValue != 1 { t.Errorf("Got %v expected %v", actualValue, "value: a") } diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index b9ca141f..750e264e 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -144,7 +144,7 @@ func (set *Set) Each(f func(index int, value interface{})) { // 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{}) containers.Container { +func (set *Set) Map(f func(index int, value interface{}) interface{}) *Set { newSet := &Set{tree: rbt.NewWith(set.tree.Comparator)} iterator := set.Iterator() for iterator.Next() { @@ -154,7 +154,7 @@ func (set *Set) Map(f func(index int, value interface{}) interface{}) containers } // 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) containers.Container { +func (set *Set) Select(f func(index int, value interface{}) bool) *Set { newSet := &Set{tree: rbt.NewWith(set.tree.Comparator)} iterator := set.Iterator() for iterator.Next() { diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index e725d82a..db307246 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -111,7 +111,7 @@ func TestTreeSetEnumerableAndIterator(t *testing.T) { // Map mappedSet := set.Map(func(index int, value interface{}) interface{} { return "mapped: " + value.(string) - }).(*Set) + }) if actualValue, expectedValue := mappedSet.Contains("mapped: a", "mapped: b", "mapped: c"), true; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } @@ -125,7 +125,7 @@ func TestTreeSetEnumerableAndIterator(t *testing.T) { // Select selectedSet := set.Select(func(index int, value interface{}) bool { return value.(string) >= "a" && value.(string) <= "b" - }).(*Set) + }) if actualValue, expectedValue := selectedSet.Contains("a", "b"), true; actualValue != expectedValue { fmt.Println("A: ", mappedSet.Contains("b")) t.Errorf("Got %v (%v) expected %v (%v)", actualValue, selectedSet.Values(), expectedValue, "[a b]") From f3b33064fa029f27cf574fc0bfdadde775b29e6a Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 24 Jun 2016 07:08:11 +0200 Subject: [PATCH 047/320] - update examples and documentation --- README.md | 81 +++++++++++++++------------------ examples/enumerablewithindex.go | 39 ++++++++-------- examples/enumerablewithkey.go | 31 ++++++------- 3 files changed, 68 insertions(+), 83 deletions(-) diff --git a/README.md b/README.md index 38990f62..bc130be3 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,8 @@ Containers are either ordered or unordered. All ordered containers provide [stat | [ArrayStack](#arraystack) | yes | yes | no | index | | [HashMap](#hashmap) | no | no | no | key | | [TreeMap](#treemap) | yes | yes | yes | key | -| [RedBlackTree](#redblacktree) | yes | yes | yes | key | -| [BinaryHeap](#binaryheap) | yes | yes | yes | index | +| [RedBlackTree](#redblacktree) | yes | yes | no | key | +| [BinaryHeap](#binaryheap) | yes | yes | no | index | ### Lists @@ -724,7 +724,7 @@ Passes each element of the container to the given function and returns the first Find(func(index int, value interface{}) bool) (int, interface{})} ``` -**Example: ** +**Example:** ```go package main @@ -734,55 +734,52 @@ import ( "github.com/emirpasic/gods/sets/treeset" ) +func printSet(txt string, set *treeset.Set) { + fmt.Print(txt, "[ ") + set.Each(func(index int, value interface{}) { + fmt.Print(value, " ") + }) + fmt.Println("]") +} + func main() { set := treeset.NewWithIntComparator() set.Add(2, 3, 4, 2, 5, 6, 7, 8) - fmt.Println(set) // TreeSet [2, 3, 4, 5, 6, 7, 8] - - // Calculates sum. - sum := 0 - set.Each(func(index int, value interface{}) { - sum += value.(int) - }) - fmt.Println(sum) // 35 + printSet("Initial", set) // [ 2 3 4 5 6 7 8 ] - // Selects all even numbers into a new set. even := set.Select(func(index int, value interface{}) bool { return value.(int)%2 == 0 }) - fmt.Println(even) // TreeSet [2, 4, 6, 8] + printSet("Even numbers", even) // [ 2 4 6 8 ] - // Finds first number divisible by 2 and 3 foundIndex, foundValue := set.Find(func(index int, value interface{}) bool { return value.(int)%2 == 0 && value.(int)%3 == 0 }) - fmt.Println(foundIndex, foundValue) // index: 4, value: 6 + if foundIndex != -1 { + fmt.Println("Number divisible by 2 and 3 found is", foundValue, "at index", foundIndex) // value: 6, index: 4 + } - // Squares each number in a new set. square := set.Map(func(index int, value interface{}) interface{} { return value.(int) * value.(int) }) - fmt.Println(square) // TreeSet [4, 9, 16, 25, 36, 49, 64] + printSet("Numbers squared", square) // [ 4 9 16 25 36 49 64 ] - // Tests if any number is bigger than 5 bigger := set.Any(func(index int, value interface{}) bool { return value.(int) > 5 }) - fmt.Println(bigger) // true + fmt.Println("Set contains a number bigger than 5 is ", bigger) // true - // Tests if all numbers are positive positive := set.All(func(index int, value interface{}) bool { return value.(int) > 0 }) - fmt.Println(positive) // true + fmt.Println("All numbers are positive is", positive) // true - // Chaining evenNumbersSquared := set.Select(func(index int, value interface{}) bool { return value.(int)%2 == 0 }).Map(func(index int, value interface{}) interface{} { return value.(int) * value.(int) }) - fmt.Println(evenNumbersSquared) // TreeSet [4, 16, 36, 64] + printSet("Chaining", evenNumbersSquared) // [ 4 16 36 64 ] } ``` @@ -838,20 +835,20 @@ Passes each element of the container to the given function and returns the first Find(func(key interface{}, value interface{}) bool) (interface{}, interface{}) ``` -Typical usage: +**Example:** + ```go package main import ( "fmt" "github.com/emirpasic/gods/maps/treemap" - "strconv" ) -func prettyPrint(m *treemap.Map) { - fmt.Print("{ ") +func printMap(txt string, m *treemap.Map) { + fmt.Print(txt, " { ") m.Each(func(key interface{}, value interface{}) { - fmt.Print(key.(string) + ": " + strconv.Itoa(value.(int)) + " ") + fmt.Print(key, ":", value, " ") }) fmt.Println("}") } @@ -865,45 +862,41 @@ func main() { m.Put("c", 3) m.Put("b", 2) m.Put("a", 1) - prettyPrint(m) // { a: 1 b: 2 c: 3 d: 4 e: 5 f: 6 g: 7 } + printMap("Initial", m) // { a:1 b:2 c:3 d:4 e:5 f:6 g:7 } - // Selects all elements with even values into a new map. even := m.Select(func(key interface{}, value interface{}) bool { - return value.(int)%2 == 0 + return value.(int) % 2 == 0 }) - prettyPrint(even) // { b: 2 d: 4 f: 6 } + printMap("Elements with even values", even) // { b:2 d:4 f:6 } - // Finds first element whose value is divisible by 2 and 3 foundKey, foundValue := m.Find(func(key interface{}, value interface{}) bool { - return value.(int)%2 == 0 && value.(int)%3 == 0 + return value.(int) % 2 == 0 && value.(int) % 3 == 0 }) - fmt.Println(foundKey, foundValue) // key: f, value: 6 + if foundKey != nil { + fmt.Println("Element with value divisible by 2 and 3 found is", foundValue, "with key", foundKey) // value: 6, index: 4 + } - // Creates a new map containing same elements with their values squared and letters duplicated. square := m.Map(func(key interface{}, value interface{}) (interface{}, interface{}) { return key.(string) + key.(string), value.(int) * value.(int) }) - prettyPrint(square) // { aa: 1 bb: 4 cc: 9 dd: 16 ee: 25 ff: 36 gg: 49 } + printMap("Elements' values squared and letters duplicated", square) // { aa:1 bb:4 cc:9 dd:16 ee:25 ff:36 gg:49 } - // Tests if any element contains value that is bigger than 5 bigger := m.Any(func(key interface{}, value interface{}) bool { return value.(int) > 5 }) - fmt.Println(bigger) // true + fmt.Println("Map contains element whose value is bigger than 5 is", bigger) // true - // Tests if all elements' values are positive positive := m.All(func(key interface{}, value interface{}) bool { return value.(int) > 0 }) - fmt.Println(positive) // true + fmt.Println("All map's elements have positive values is", positive) // true - // Chaining evenNumbersSquared := m.Select(func(key interface{}, value interface{}) bool { - return value.(int)%2 == 0 + return value.(int) % 2 == 0 }).Map(func(key interface{}, value interface{}) (interface{}, interface{}) { return key, value.(int) * value.(int) }) - prettyPrint(evenNumbersSquared) // { b: 4 d: 16 f: 36 } + printMap("Chaining", evenNumbersSquared) // { b:4 d:16 f:36 } } ``` diff --git a/examples/enumerablewithindex.go b/examples/enumerablewithindex.go index 54907ce3..99f1954e 100644 --- a/examples/enumerablewithindex.go +++ b/examples/enumerablewithindex.go @@ -31,53 +31,50 @@ import ( "github.com/emirpasic/gods/sets/treeset" ) -func EnumerableWithIndexExample() { - set := treeset.NewWithIntComparator() - set.Add(2, 3, 4, 2, 5, 6, 7, 8) - fmt.Println(set) // TreeSet [2, 3, 4, 5, 6, 7, 8] - - // Calculates sum. - sum := 0 +func printSet(txt string, set *treeset.Set) { + fmt.Print(txt, "[ ") set.Each(func(index int, value interface{}) { - sum += value.(int) + fmt.Print(value, " ") }) - fmt.Println(sum) // 35 + fmt.Println("]") +} + +func EnumerableWithIndexTest() { + set := treeset.NewWithIntComparator() + set.Add(2, 3, 4, 2, 5, 6, 7, 8) + printSet("Initial", set) // [ 2 3 4 5 6 7 8 ] - // Selects all even numbers into a new set. even := set.Select(func(index int, value interface{}) bool { return value.(int)%2 == 0 }) - fmt.Println(even) // TreeSet [2, 4, 6, 8] + printSet("Even numbers", even) // [ 2 4 6 8 ] - // Finds first number divisible by 2 and 3 foundIndex, foundValue := set.Find(func(index int, value interface{}) bool { return value.(int)%2 == 0 && value.(int)%3 == 0 }) - fmt.Println(foundIndex, foundValue) // index: 4, value: 6 + if foundIndex != -1 { + fmt.Println("Number divisible by 2 and 3 found is", foundValue, "at index", foundIndex) // value: 6, index: 4 + } - // Squares each number in a new set. square := set.Map(func(index int, value interface{}) interface{} { return value.(int) * value.(int) }) - fmt.Println(square) // TreeSet [4, 9, 16, 25, 36, 49, 64] + printSet("Numbers squared", square) // [ 4 9 16 25 36 49 64 ] - // Tests if any number is bigger than 5 bigger := set.Any(func(index int, value interface{}) bool { return value.(int) > 5 }) - fmt.Println(bigger) // true + fmt.Println("Set contains a number bigger than 5 is ", bigger) // true - // Tests if all numbers are positive positive := set.All(func(index int, value interface{}) bool { return value.(int) > 0 }) - fmt.Println(positive) // true + fmt.Println("All numbers are positive is", positive) // true - // Chaining evenNumbersSquared := set.Select(func(index int, value interface{}) bool { return value.(int)%2 == 0 }).Map(func(index int, value interface{}) interface{} { return value.(int) * value.(int) }) - fmt.Println(evenNumbersSquared) // TreeSet [4, 16, 36, 64] + printSet("Chaining", evenNumbersSquared) // [ 4 16 36 64 ] } diff --git a/examples/enumerablewithkey.go b/examples/enumerablewithkey.go index a5678a3c..aba2d246 100644 --- a/examples/enumerablewithkey.go +++ b/examples/enumerablewithkey.go @@ -29,18 +29,17 @@ package examples import ( "fmt" "github.com/emirpasic/gods/maps/treemap" - "strconv" ) -func prettyPrint(m *treemap.Map) { - fmt.Print("{ ") +func printMap(txt string, m *treemap.Map) { + fmt.Print(txt, " { ") m.Each(func(key interface{}, value interface{}) { - fmt.Print(key.(string) + ": " + strconv.Itoa(value.(int)) + " ") + fmt.Print(key, ":", value, " ") }) fmt.Println("}") } -func EnumerableWithKeyExample() { +func EunumerableWithKey() { m := treemap.NewWithStringComparator() m.Put("g", 7) m.Put("f", 6) @@ -49,43 +48,39 @@ func EnumerableWithKeyExample() { m.Put("c", 3) m.Put("b", 2) m.Put("a", 1) - prettyPrint(m) // { a: 1 b: 2 c: 3 d: 4 e: 5 f: 6 g: 7 } + printMap("Initial", m) // { a:1 b:2 c:3 d:4 e:5 f:6 g:7 } - // Selects all elements with even values into a new map. even := m.Select(func(key interface{}, value interface{}) bool { return value.(int)%2 == 0 }) - prettyPrint(even) // { b: 2 d: 4 f: 6 } + printMap("Elements with even values", even) // { b:2 d:4 f:6 } - // Finds first element whose value is divisible by 2 and 3 foundKey, foundValue := m.Find(func(key interface{}, value interface{}) bool { return value.(int)%2 == 0 && value.(int)%3 == 0 }) - fmt.Println(foundKey, foundValue) // key: f, value: 6 + if foundKey != nil { + fmt.Println("Element with value divisible by 2 and 3 found is", foundValue, "with key", foundKey) // value: 6, index: 4 + } - // Creates a new map containing same elements with their values squared and letters duplicated. square := m.Map(func(key interface{}, value interface{}) (interface{}, interface{}) { return key.(string) + key.(string), value.(int) * value.(int) }) - prettyPrint(square) // { aa: 1 bb: 4 cc: 9 dd: 16 ee: 25 ff: 36 gg: 49 } + printMap("Elements' values squared and letters duplicated", square) // { aa:1 bb:4 cc:9 dd:16 ee:25 ff:36 gg:49 } - // Tests if any element contains value that is bigger than 5 bigger := m.Any(func(key interface{}, value interface{}) bool { return value.(int) > 5 }) - fmt.Println(bigger) // true + fmt.Println("Map contains element whose value is bigger than 5 is", bigger) // true - // Tests if all elements' values are positive positive := m.All(func(key interface{}, value interface{}) bool { return value.(int) > 0 }) - fmt.Println(positive) // true + fmt.Println("All map's elements have positive values is", positive) // true - // Chaining evenNumbersSquared := m.Select(func(key interface{}, value interface{}) bool { return value.(int)%2 == 0 }).Map(func(key interface{}, value interface{}) (interface{}, interface{}) { return key, value.(int) * value.(int) }) - prettyPrint(evenNumbersSquared) // { b: 4 d: 16 f: 36 } + printMap("Chaining", evenNumbersSquared) // { b:4 d:16 f:36 } } From 0631cc2647e60aa830321120d505affcc1bdc7fb Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 24 Jun 2016 17:56:26 +0200 Subject: [PATCH 048/320] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bc130be3..89785289 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![GoDoc](https://godoc.org/github.com/emirpasic/gods?status.svg)](https://godoc.org/github.com/emirpasic/gods) [![Build Status](https://travis-ci.org/emirpasic/gods.svg)](https://travis-ci.org/emirpasic/gods) [![PyPI](https://img.shields.io/pypi/l/Django.svg?maxAge=2592000)](https://github.com/emirpasic/gods/blob/enums/LICENSE) +[![GoDoc](https://godoc.org/github.com/emirpasic/gods?status.svg)](https://godoc.org/github.com/emirpasic/gods) [![Build Status](https://travis-ci.org/emirpasic/gods.svg)](https://travis-ci.org/emirpasic/gods) [![PyPI](https://img.shields.io/pypi/l/Django.svg?maxAge=2592000)](https://github.com/emirpasic/gods/blob/master/LICENSE) # GoDS (Go Data Structures) From 4d3c47ce2a4792dd499839019e729eaaf490027f Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 24 Jun 2016 18:29:35 +0200 Subject: [PATCH 049/320] - go report badge --- README.md | 2 +- maps/hashmap/hashmap.go | 2 +- sets/hashset/hashset.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 89785289..c9838f7d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![GoDoc](https://godoc.org/github.com/emirpasic/gods?status.svg)](https://godoc.org/github.com/emirpasic/gods) [![Build Status](https://travis-ci.org/emirpasic/gods.svg)](https://travis-ci.org/emirpasic/gods) [![PyPI](https://img.shields.io/pypi/l/Django.svg?maxAge=2592000)](https://github.com/emirpasic/gods/blob/master/LICENSE) +[![GoDoc](https://godoc.org/github.com/emirpasic/gods?status.svg)](https://godoc.org/github.com/emirpasic/gods) [![Build Status](https://travis-ci.org/emirpasic/gods.svg)](https://travis-ci.org/emirpasic/gods) [![Go Report Card](https://goreportcard.com/badge/emirpasic/gods)](https://goreportcard.com/report/emirpasic/gods) [![PyPI](https://img.shields.io/pypi/l/Django.svg?maxAge=2592000)](https://github.com/emirpasic/gods/blob/master/LICENSE) # GoDS (Go Data Structures) diff --git a/maps/hashmap/hashmap.go b/maps/hashmap/hashmap.go index 3033f6bf..ee7141c6 100644 --- a/maps/hashmap/hashmap.go +++ b/maps/hashmap/hashmap.go @@ -80,7 +80,7 @@ func (m *Map) Size() int { func (m *Map) Keys() []interface{} { keys := make([]interface{}, m.Size()) count := 0 - for key, _ := range m.m { + for key := range m.m { keys[count] = key count += 1 } diff --git a/sets/hashset/hashset.go b/sets/hashset/hashset.go index 54d219be..c5f808c7 100644 --- a/sets/hashset/hashset.go +++ b/sets/hashset/hashset.go @@ -96,7 +96,7 @@ func (set *Set) Clear() { func (set *Set) Values() []interface{} { values := make([]interface{}, set.Size()) count := 0 - for item, _ := range set.items { + for item := range set.items { values[count] = item count += 1 } @@ -106,7 +106,7 @@ func (set *Set) Values() []interface{} { func (set *Set) String() string { str := "HashSet\n" items := []string{} - for k, _ := range set.items { + for k := range set.items { items = append(items, fmt.Sprintf("%v", k)) } str += strings.Join(items, ", ") From 616c850bffc342ce486407ab8ce9d8e5849e1ae8 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 24 Jun 2016 19:17:50 +0200 Subject: [PATCH 050/320] - refactor list's tests --- lists/arraylist/arraylist_test.go | 198 +++++++++++------ .../doublylinkedlist/doublylinkedlist_test.go | 199 ++++++++++++------ .../singlylinkedlist/singlylinkedlist_test.go | 199 ++++++++++++------ 3 files changed, 399 insertions(+), 197 deletions(-) diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index c3f0c581..0dea8d8a 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -32,114 +32,149 @@ import ( "testing" ) -func TestArrayList(t *testing.T) { - +func TestListAdd(t *testing.T) { list := New() - - list.Sort(utils.StringComparator) - - list.Add("e", "f", "g", "a", "b", "c", "d") - - list.Sort(utils.StringComparator) - for i := 1; i < list.Size(); i++ { - a, _ := list.Get(i - 1) - b, _ := list.Get(i) - if a.(string) > b.(string) { - t.Errorf("Not sorted! %s > %s", a, b) - } + list.Add("a") + list.Add("b", "c") + if actualValue := list.Empty(); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, false) } + if actualValue := list.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := list.Get(2); actualValue != "c" || !ok { + t.Errorf("Got %v expected %v", actualValue, "c") + } +} - list.Clear() - +func TestListRemove(t *testing.T) { + list := New() + list.Add("a") + list.Add("b", "c") + list.Remove(2) + if actualValue, ok := list.Get(2); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + list.Remove(1) + list.Remove(0) + list.Remove(0) // no effect if actualValue := list.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - if actualValue := list.Size(); actualValue != 0 { t.Errorf("Got %v expected %v", actualValue, 0) } +} +func TestListGet(t *testing.T) { + list := New() list.Add("a") list.Add("b", "c") - - if actualValue := list.Empty(); actualValue != false { - t.Errorf("Got %v expected %v", actualValue, false) + if actualValue, ok := list.Get(0); actualValue != "a" || !ok { + t.Errorf("Got %v expected %v", actualValue, "a") } - - if actualValue := list.Size(); actualValue != 3 { - t.Errorf("Got %v expected %v", actualValue, 3) + if actualValue, ok := list.Get(1); actualValue != "b" || !ok { + t.Errorf("Got %v expected %v", actualValue, "b") } - if actualValue, ok := list.Get(2); actualValue != "c" || !ok { t.Errorf("Got %v expected %v", actualValue, "c") } + if actualValue, ok := list.Get(3); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + list.Remove(0) + if actualValue, ok := list.Get(0); actualValue != "b" || !ok { + t.Errorf("Got %v expected %v", actualValue, "b") + } +} +func TestListSwap(t *testing.T) { + list := New() + list.Add("a") + list.Add("b", "c") list.Swap(0, 1) - if actualValue, ok := list.Get(0); actualValue != "b" || !ok { t.Errorf("Got %v expected %v", actualValue, "c") } +} - list.Remove(2) - - if actualValue, ok := list.Get(2); actualValue != nil || ok { - t.Errorf("Got %v expected %v", actualValue, nil) +func TestListSort(t *testing.T) { + list := New() + list.Sort(utils.StringComparator) + list.Add("e", "f", "g", "a", "b", "c", "d") + list.Sort(utils.StringComparator) + for i := 1; i < list.Size(); i++ { + a, _ := list.Get(i - 1) + b, _ := list.Get(i) + if a.(string) > b.(string) { + t.Errorf("Not sorted! %s > %s", a, b) + } } +} - list.Remove(1) - list.Remove(0) - +func TestListClear(t *testing.T) { + list := New() + list.Add("e", "f", "g", "a", "b", "c", "d") + list.Clear() if actualValue := list.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - if actualValue := list.Size(); actualValue != 0 { t.Errorf("Got %v expected %v", actualValue, 0) } +} - list.Add("a", "b", "c") - +func TestListContains(t *testing.T) { + list := New() + list.Add("a") + list.Add("b", "c") + if actualValue := list.Contains("a"); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } if actualValue := list.Contains("a", "b", "c"); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - if actualValue := list.Contains("a", "b", "c", "d"); actualValue != false { t.Errorf("Got %v expected %v", actualValue, false) } - list.Clear() - if actualValue := list.Contains("a"); actualValue != false { t.Errorf("Got %v expected %v", actualValue, false) } - - if actualValue, ok := list.Get(0); actualValue != nil || ok { + if actualValue := list.Contains("a", "b", "c"); actualValue != false { t.Errorf("Got %v expected %v", actualValue, false) } +} - if actualValue := list.Empty(); actualValue != true { - t.Errorf("Got %v expected %v", actualValue, true) +func TestListValues(t *testing.T) { + list := New() + list.Add("a") + list.Add("b", "c") + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } +} - list.Insert(0, "h") - list.Insert(0, "e") - list.Insert(1, "f") - list.Insert(2, "g") - list.Insert(4, "i") - list.Insert(0, "a", "b") - list.Insert(list.Size(), "j", "k") - list.Insert(2, "c", "d") - - if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s%s", list.Values()...), "abcdefghijk"; actualValue != expectedValue { +func TestListInsert(t *testing.T) { + list := New() + list.Insert(0, "b", "c") + list.Insert(0, "a") + list.Insert(10, "x") // ignore + if actualValue := list.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + list.Insert(3, "d") // append + if actualValue := list.Size(); actualValue != 4 { + t.Errorf("Got %v expected %v", actualValue, 4) + } + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", list.Values()...), "abcd"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } -func TestArrayListEnumerableAndIterator(t *testing.T) { +func TestListEach(t *testing.T) { list := New() list.Add("a", "b", "c") - - // Each list.Each(func(index int, value interface{}) { switch index { case 0: @@ -158,8 +193,11 @@ func TestArrayListEnumerableAndIterator(t *testing.T) { t.Errorf("Too many") } }) +} - // Map +func TestListMap(t *testing.T) { + list := New() + list.Add("a", "b", "c") mappedList := list.Map(func(index int, value interface{}) interface{} { return "mapped: " + value.(string) }) @@ -175,8 +213,11 @@ func TestArrayListEnumerableAndIterator(t *testing.T) { if mappedList.Size() != 3 { t.Errorf("Got %v expected %v", mappedList.Size(), 3) } +} - // Select +func TestListSelect(t *testing.T) { + list := New() + list.Add("a", "b", "c") selectedList := list.Select(func(index int, value interface{}) bool { return value.(string) >= "a" && value.(string) <= "b" }) @@ -189,8 +230,11 @@ func TestArrayListEnumerableAndIterator(t *testing.T) { if selectedList.Size() != 2 { t.Errorf("Got %v expected %v", selectedList.Size(), 3) } +} - // Any +func TestListAny(t *testing.T) { + list := New() + list.Add("a", "b", "c") any := list.Any(func(index int, value interface{}) bool { return value.(string) == "c" }) @@ -203,8 +247,10 @@ func TestArrayListEnumerableAndIterator(t *testing.T) { if any != false { t.Errorf("Got %v expected %v", any, false) } - - // All +} +func TestListAll(t *testing.T) { + list := New() + list.Add("a", "b", "c") all := list.All(func(index int, value interface{}) bool { return value.(string) >= "a" && value.(string) <= "c" }) @@ -217,8 +263,10 @@ func TestArrayListEnumerableAndIterator(t *testing.T) { if all != false { t.Errorf("Got %v expected %v", all, false) } - - // Find +} +func TestListFind(t *testing.T) { + list := New() + list.Add("a", "b", "c") foundIndex, foundValue := list.Find(func(index int, value interface{}) bool { return value.(string) == "c" }) @@ -231,8 +279,29 @@ func TestArrayListEnumerableAndIterator(t *testing.T) { if foundValue != nil || foundIndex != -1 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil) } +} +func TestListChaining(t *testing.T) { + list := New() + list.Add("a", "b", "c") + chainedList := list.Select(func(index int, value interface{}) bool { + return value.(string) > "a" + }).Map(func(index int, value interface{}) interface{} { + return value.(string) + value.(string) + }) + if chainedList.Size() != 2 { + t.Errorf("Got %v expected %v", chainedList.Size(), 2) + } + if actualValue, ok := chainedList.Get(0); actualValue != "bb" || !ok { + t.Errorf("Got %v expected %v", actualValue, "b") + } + if actualValue, ok := chainedList.Get(1); actualValue != "cc" || !ok { + t.Errorf("Got %v expected %v", actualValue, "c") + } +} - // Iterator +func TestListIterator(t *testing.T) { + list := New() + list.Add("a", "b", "c") it := list.Iterator() for it.Next() { index := it.Index() @@ -261,7 +330,7 @@ func TestArrayListEnumerableAndIterator(t *testing.T) { } } -func BenchmarkArrayList(b *testing.B) { +func BenchmarkList(b *testing.B) { for i := 0; i < b.N; i++ { list := New() for n := 0; n < 1000; n++ { @@ -271,5 +340,4 @@ func BenchmarkArrayList(b *testing.B) { list.Remove(0) } } - } diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 5e8331d0..e199102f 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -32,116 +32,149 @@ import ( "testing" ) -func TestDoublyLinkedList(t *testing.T) { - +func TestListAdd(t *testing.T) { list := New() - - list.Sort(utils.StringComparator) - - list.Add("e", "f", "g", "a", "b", "c", "d") - - list.Sort(utils.StringComparator) - for i := 1; i < list.Size(); i++ { - a, _ := list.Get(i - 1) - b, _ := list.Get(i) - if a.(string) > b.(string) { - t.Errorf("Not sorted! %s > %s", a, b) - } + list.Add("a") + list.Add("b", "c") + if actualValue := list.Empty(); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, false) } + if actualValue := list.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := list.Get(2); actualValue != "c" || !ok { + t.Errorf("Got %v expected %v", actualValue, "c") + } +} - list.Clear() - +func TestListRemove(t *testing.T) { + list := New() + list.Add("a") + list.Add("b", "c") + list.Remove(2) + if actualValue, ok := list.Get(2); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + list.Remove(1) + list.Remove(0) + list.Remove(0) // no effect if actualValue := list.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - if actualValue := list.Size(); actualValue != 0 { t.Errorf("Got %v expected %v", actualValue, 0) } +} +func TestListGet(t *testing.T) { + list := New() list.Add("a") list.Add("b", "c") - - if actualValue := list.Empty(); actualValue != false { - t.Errorf("Got %v expected %v", actualValue, false) + if actualValue, ok := list.Get(0); actualValue != "a" || !ok { + t.Errorf("Got %v expected %v", actualValue, "a") } - - if actualValue := list.Size(); actualValue != 3 { - t.Errorf("Got %v expected %v", actualValue, 3) + if actualValue, ok := list.Get(1); actualValue != "b" || !ok { + t.Errorf("Got %v expected %v", actualValue, "b") } - if actualValue, ok := list.Get(2); actualValue != "c" || !ok { t.Errorf("Got %v expected %v", actualValue, "c") } + if actualValue, ok := list.Get(3); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + list.Remove(0) + if actualValue, ok := list.Get(0); actualValue != "b" || !ok { + t.Errorf("Got %v expected %v", actualValue, "b") + } +} - list.Swap(0, 2) - list.Swap(0, 2) +func TestListSwap(t *testing.T) { + list := New() + list.Add("a") + list.Add("b", "c") list.Swap(0, 1) - if actualValue, ok := list.Get(0); actualValue != "b" || !ok { t.Errorf("Got %v expected %v", actualValue, "c") } +} - list.Remove(2) - - if actualValue, ok := list.Get(2); actualValue != nil || ok { - t.Errorf("Got %v expected %v", actualValue, nil) +func TestListSort(t *testing.T) { + list := New() + list.Sort(utils.StringComparator) + list.Add("e", "f", "g", "a", "b", "c", "d") + list.Sort(utils.StringComparator) + for i := 1; i < list.Size(); i++ { + a, _ := list.Get(i - 1) + b, _ := list.Get(i) + if a.(string) > b.(string) { + t.Errorf("Not sorted! %s > %s", a, b) + } } +} - list.Remove(1) - list.Remove(0) - +func TestListClear(t *testing.T) { + list := New() + list.Add("e", "f", "g", "a", "b", "c", "d") + list.Clear() if actualValue := list.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - if actualValue := list.Size(); actualValue != 0 { t.Errorf("Got %v expected %v", actualValue, 0) } +} - list.Add("a", "b", "c") - +func TestListContains(t *testing.T) { + list := New() + list.Add("a") + list.Add("b", "c") + if actualValue := list.Contains("a"); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } if actualValue := list.Contains("a", "b", "c"); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - if actualValue := list.Contains("a", "b", "c", "d"); actualValue != false { t.Errorf("Got %v expected %v", actualValue, false) } - list.Clear() - if actualValue := list.Contains("a"); actualValue != false { t.Errorf("Got %v expected %v", actualValue, false) } - - if actualValue, ok := list.Get(0); actualValue != nil || ok { + if actualValue := list.Contains("a", "b", "c"); actualValue != false { t.Errorf("Got %v expected %v", actualValue, false) } +} - if actualValue := list.Empty(); actualValue != true { - t.Errorf("Got %v expected %v", actualValue, true) +func TestListValues(t *testing.T) { + list := New() + list.Add("a") + list.Add("b", "c") + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } +} - list.Insert(0, "h") - list.Insert(0, "e") - list.Insert(1, "f") - list.Insert(2, "g") - list.Insert(4, "i") - list.Insert(0, "a", "b") - list.Insert(list.Size(), "j", "k") - list.Insert(2, "c", "d") - - if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s%s", list.Values()...), "abcdefghijk"; actualValue != expectedValue { +func TestListInsert(t *testing.T) { + list := New() + list.Insert(0, "b", "c") + list.Insert(0, "a") + list.Insert(10, "x") // ignore + if actualValue := list.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + list.Insert(3, "d") // append + if actualValue := list.Size(); actualValue != 4 { + t.Errorf("Got %v expected %v", actualValue, 4) + } + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", list.Values()...), "abcd"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } -func TestDoublyLinkedListEnumerableAndIterator(t *testing.T) { +func TestListEach(t *testing.T) { list := New() list.Add("a", "b", "c") - - // Each list.Each(func(index int, value interface{}) { switch index { case 0: @@ -160,8 +193,11 @@ func TestDoublyLinkedListEnumerableAndIterator(t *testing.T) { t.Errorf("Too many") } }) +} - // Map +func TestListMap(t *testing.T) { + list := New() + list.Add("a", "b", "c") mappedList := list.Map(func(index int, value interface{}) interface{} { return "mapped: " + value.(string) }) @@ -177,8 +213,11 @@ func TestDoublyLinkedListEnumerableAndIterator(t *testing.T) { if mappedList.Size() != 3 { t.Errorf("Got %v expected %v", mappedList.Size(), 3) } +} - // Select +func TestListSelect(t *testing.T) { + list := New() + list.Add("a", "b", "c") selectedList := list.Select(func(index int, value interface{}) bool { return value.(string) >= "a" && value.(string) <= "b" }) @@ -191,8 +230,11 @@ func TestDoublyLinkedListEnumerableAndIterator(t *testing.T) { if selectedList.Size() != 2 { t.Errorf("Got %v expected %v", selectedList.Size(), 3) } +} - // Any +func TestListAny(t *testing.T) { + list := New() + list.Add("a", "b", "c") any := list.Any(func(index int, value interface{}) bool { return value.(string) == "c" }) @@ -205,8 +247,10 @@ func TestDoublyLinkedListEnumerableAndIterator(t *testing.T) { if any != false { t.Errorf("Got %v expected %v", any, false) } - - // All +} +func TestListAll(t *testing.T) { + list := New() + list.Add("a", "b", "c") all := list.All(func(index int, value interface{}) bool { return value.(string) >= "a" && value.(string) <= "c" }) @@ -219,8 +263,10 @@ func TestDoublyLinkedListEnumerableAndIterator(t *testing.T) { if all != false { t.Errorf("Got %v expected %v", all, false) } - - // Find +} +func TestListFind(t *testing.T) { + list := New() + list.Add("a", "b", "c") foundIndex, foundValue := list.Find(func(index int, value interface{}) bool { return value.(string) == "c" }) @@ -233,8 +279,29 @@ func TestDoublyLinkedListEnumerableAndIterator(t *testing.T) { if foundValue != nil || foundIndex != -1 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil) } +} +func TestListChaining(t *testing.T) { + list := New() + list.Add("a", "b", "c") + chainedList := list.Select(func(index int, value interface{}) bool { + return value.(string) > "a" + }).Map(func(index int, value interface{}) interface{} { + return value.(string) + value.(string) + }) + if chainedList.Size() != 2 { + t.Errorf("Got %v expected %v", chainedList.Size(), 2) + } + if actualValue, ok := chainedList.Get(0); actualValue != "bb" || !ok { + t.Errorf("Got %v expected %v", actualValue, "b") + } + if actualValue, ok := chainedList.Get(1); actualValue != "cc" || !ok { + t.Errorf("Got %v expected %v", actualValue, "c") + } +} - // Iterator +func TestListIterator(t *testing.T) { + list := New() + list.Add("a", "b", "c") it := list.Iterator() for it.Next() { index := it.Index() @@ -263,7 +330,7 @@ func TestDoublyLinkedListEnumerableAndIterator(t *testing.T) { } } -func BenchmarkDoublyLinkedList(b *testing.B) { +func BenchmarkList(b *testing.B) { for i := 0; i < b.N; i++ { list := New() for n := 0; n < 1000; n++ { diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index d5879c34..c5462177 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -32,116 +32,149 @@ import ( "testing" ) -func TestSinglyLinkedList(t *testing.T) { - +func TestListAdd(t *testing.T) { list := New() - - list.Sort(utils.StringComparator) - - list.Add("e", "f", "g", "a", "b", "c", "d") - - list.Sort(utils.StringComparator) - for i := 1; i < list.Size(); i++ { - a, _ := list.Get(i - 1) - b, _ := list.Get(i) - if a.(string) > b.(string) { - t.Errorf("Not sorted! %s > %s", a, b) - } + list.Add("a") + list.Add("b", "c") + if actualValue := list.Empty(); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, false) } + if actualValue := list.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := list.Get(2); actualValue != "c" || !ok { + t.Errorf("Got %v expected %v", actualValue, "c") + } +} - list.Clear() - +func TestListRemove(t *testing.T) { + list := New() + list.Add("a") + list.Add("b", "c") + list.Remove(2) + if actualValue, ok := list.Get(2); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + list.Remove(1) + list.Remove(0) + list.Remove(0) // no effect if actualValue := list.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - if actualValue := list.Size(); actualValue != 0 { t.Errorf("Got %v expected %v", actualValue, 0) } +} +func TestListGet(t *testing.T) { + list := New() list.Add("a") list.Add("b", "c") - - if actualValue := list.Empty(); actualValue != false { - t.Errorf("Got %v expected %v", actualValue, false) + if actualValue, ok := list.Get(0); actualValue != "a" || !ok { + t.Errorf("Got %v expected %v", actualValue, "a") } - - if actualValue := list.Size(); actualValue != 3 { - t.Errorf("Got %v expected %v", actualValue, 3) + if actualValue, ok := list.Get(1); actualValue != "b" || !ok { + t.Errorf("Got %v expected %v", actualValue, "b") } - if actualValue, ok := list.Get(2); actualValue != "c" || !ok { t.Errorf("Got %v expected %v", actualValue, "c") } + if actualValue, ok := list.Get(3); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + list.Remove(0) + if actualValue, ok := list.Get(0); actualValue != "b" || !ok { + t.Errorf("Got %v expected %v", actualValue, "b") + } +} - list.Swap(0, 2) - list.Swap(0, 2) +func TestListSwap(t *testing.T) { + list := New() + list.Add("a") + list.Add("b", "c") list.Swap(0, 1) - if actualValue, ok := list.Get(0); actualValue != "b" || !ok { t.Errorf("Got %v expected %v", actualValue, "c") } +} - list.Remove(2) - - if actualValue, ok := list.Get(2); actualValue != nil || ok { - t.Errorf("Got %v expected %v", actualValue, nil) +func TestListSort(t *testing.T) { + list := New() + list.Sort(utils.StringComparator) + list.Add("e", "f", "g", "a", "b", "c", "d") + list.Sort(utils.StringComparator) + for i := 1; i < list.Size(); i++ { + a, _ := list.Get(i - 1) + b, _ := list.Get(i) + if a.(string) > b.(string) { + t.Errorf("Not sorted! %s > %s", a, b) + } } +} - list.Remove(1) - list.Remove(0) - +func TestListClear(t *testing.T) { + list := New() + list.Add("e", "f", "g", "a", "b", "c", "d") + list.Clear() if actualValue := list.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - if actualValue := list.Size(); actualValue != 0 { t.Errorf("Got %v expected %v", actualValue, 0) } +} - list.Add("a", "b", "c") - +func TestListContains(t *testing.T) { + list := New() + list.Add("a") + list.Add("b", "c") + if actualValue := list.Contains("a"); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } if actualValue := list.Contains("a", "b", "c"); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - if actualValue := list.Contains("a", "b", "c", "d"); actualValue != false { t.Errorf("Got %v expected %v", actualValue, false) } - list.Clear() - if actualValue := list.Contains("a"); actualValue != false { t.Errorf("Got %v expected %v", actualValue, false) } - - if actualValue, ok := list.Get(0); actualValue != nil || ok { + if actualValue := list.Contains("a", "b", "c"); actualValue != false { t.Errorf("Got %v expected %v", actualValue, false) } +} - if actualValue := list.Empty(); actualValue != true { - t.Errorf("Got %v expected %v", actualValue, true) +func TestListValues(t *testing.T) { + list := New() + list.Add("a") + list.Add("b", "c") + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } +} - list.Insert(0, "h") - list.Insert(0, "e") - list.Insert(1, "f") - list.Insert(2, "g") - list.Insert(4, "i") - list.Insert(0, "a", "b") - list.Insert(list.Size(), "j", "k") - list.Insert(2, "c", "d") - - if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s%s", list.Values()...), "abcdefghijk"; actualValue != expectedValue { +func TestListInsert(t *testing.T) { + list := New() + list.Insert(0, "b", "c") + list.Insert(0, "a") + list.Insert(10, "x") // ignore + if actualValue := list.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + list.Insert(3, "d") // append + if actualValue := list.Size(); actualValue != 4 { + t.Errorf("Got %v expected %v", actualValue, 4) + } + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", list.Values()...), "abcd"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } -func TestSinglyLinkedListEnumerableAndIterator(t *testing.T) { +func TestListEach(t *testing.T) { list := New() list.Add("a", "b", "c") - - // Each list.Each(func(index int, value interface{}) { switch index { case 0: @@ -160,8 +193,11 @@ func TestSinglyLinkedListEnumerableAndIterator(t *testing.T) { t.Errorf("Too many") } }) +} - // Map +func TestListMap(t *testing.T) { + list := New() + list.Add("a", "b", "c") mappedList := list.Map(func(index int, value interface{}) interface{} { return "mapped: " + value.(string) }) @@ -177,8 +213,11 @@ func TestSinglyLinkedListEnumerableAndIterator(t *testing.T) { if mappedList.Size() != 3 { t.Errorf("Got %v expected %v", mappedList.Size(), 3) } +} - // Select +func TestListSelect(t *testing.T) { + list := New() + list.Add("a", "b", "c") selectedList := list.Select(func(index int, value interface{}) bool { return value.(string) >= "a" && value.(string) <= "b" }) @@ -191,8 +230,11 @@ func TestSinglyLinkedListEnumerableAndIterator(t *testing.T) { if selectedList.Size() != 2 { t.Errorf("Got %v expected %v", selectedList.Size(), 3) } +} - // Any +func TestListAny(t *testing.T) { + list := New() + list.Add("a", "b", "c") any := list.Any(func(index int, value interface{}) bool { return value.(string) == "c" }) @@ -205,8 +247,10 @@ func TestSinglyLinkedListEnumerableAndIterator(t *testing.T) { if any != false { t.Errorf("Got %v expected %v", any, false) } - - // All +} +func TestListAll(t *testing.T) { + list := New() + list.Add("a", "b", "c") all := list.All(func(index int, value interface{}) bool { return value.(string) >= "a" && value.(string) <= "c" }) @@ -219,8 +263,10 @@ func TestSinglyLinkedListEnumerableAndIterator(t *testing.T) { if all != false { t.Errorf("Got %v expected %v", all, false) } - - // Find +} +func TestListFind(t *testing.T) { + list := New() + list.Add("a", "b", "c") foundIndex, foundValue := list.Find(func(index int, value interface{}) bool { return value.(string) == "c" }) @@ -233,8 +279,29 @@ func TestSinglyLinkedListEnumerableAndIterator(t *testing.T) { if foundValue != nil || foundIndex != -1 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil) } +} +func TestListChaining(t *testing.T) { + list := New() + list.Add("a", "b", "c") + chainedList := list.Select(func(index int, value interface{}) bool { + return value.(string) > "a" + }).Map(func(index int, value interface{}) interface{} { + return value.(string) + value.(string) + }) + if chainedList.Size() != 2 { + t.Errorf("Got %v expected %v", chainedList.Size(), 2) + } + if actualValue, ok := chainedList.Get(0); actualValue != "bb" || !ok { + t.Errorf("Got %v expected %v", actualValue, "b") + } + if actualValue, ok := chainedList.Get(1); actualValue != "cc" || !ok { + t.Errorf("Got %v expected %v", actualValue, "c") + } +} - // Iterator +func TestListIterator(t *testing.T) { + list := New() + list.Add("a", "b", "c") it := list.Iterator() for it.Next() { index := it.Index() @@ -263,7 +330,7 @@ func TestSinglyLinkedListEnumerableAndIterator(t *testing.T) { } } -func BenchmarkSinglyLinkedList(b *testing.B) { +func BenchmarkList(b *testing.B) { for i := 0; i < b.N; i++ { list := New() for n := 0; n < 1000; n++ { From d07be9402c93cc0d20f70cef295713a07c97958b Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 24 Jun 2016 19:38:16 +0200 Subject: [PATCH 051/320] - refactor maps' tests --- maps/hashmap/hashmap_test.go | 49 ++++------- maps/treemap/treemap_test.go | 164 +++++++++++++++++++++-------------- 2 files changed, 114 insertions(+), 99 deletions(-) diff --git a/maps/hashmap/hashmap_test.go b/maps/hashmap/hashmap_test.go index 3c28d1c2..692c616d 100644 --- a/maps/hashmap/hashmap_test.go +++ b/maps/hashmap/hashmap_test.go @@ -31,11 +31,8 @@ import ( "testing" ) -func TestHashMap(t *testing.T) { - +func TestMapPut(t *testing.T) { m := New() - - // insertions m.Put(5, "e") m.Put(6, "f") m.Put(7, "g") @@ -45,17 +42,12 @@ func TestHashMap(t *testing.T) { m.Put(2, "b") m.Put(1, "a") //overwrite - // Test Size() if actualValue := m.Size(); actualValue != 7 { t.Errorf("Got %v expected %v", actualValue, 7) } - - // test Keys() if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - - // test Values() if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "e", "f", "g"}; !sameElements(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } @@ -79,26 +71,34 @@ func TestHashMap(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, test[1]) } } +} + +func TestMapRemove(t *testing.T) { + m := New() + m.Put(5, "e") + m.Put(6, "f") + m.Put(7, "g") + m.Put(3, "c") + m.Put(4, "d") + m.Put(1, "x") + m.Put(2, "b") + m.Put(1, "a") //overwrite - // removals m.Remove(5) m.Remove(6) m.Remove(7) m.Remove(8) m.Remove(5) - // test Keys() if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4}; !sameElements(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - // test Values() if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d"}; !sameElements(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - // Test Size() if actualValue := m.Size(); actualValue != 4 { - t.Errorf("Got %v expected %v", actualValue, 7) + t.Errorf("Got %v expected %v", actualValue, 4) } tests2 := [][]interface{}{ @@ -113,14 +113,12 @@ func TestHashMap(t *testing.T) { } for _, test := range tests2 { - // retrievals actualValue, actualFound := m.Get(test[0]) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } } - // removals m.Remove(1) m.Remove(4) m.Remove(2) @@ -128,35 +126,18 @@ func TestHashMap(t *testing.T) { m.Remove(2) m.Remove(2) - // Test Keys() if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - - // test Values() if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - - // Test Size() if actualValue := m.Size(); actualValue != 0 { t.Errorf("Got %v expected %v", actualValue, 0) } - - // Test Empty() if actualValue := m.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - - m.Put(1, "a") - m.Put(2, "b") - m.Clear() - - // Test Empty() - if actualValue := m.Empty(); actualValue != true { - t.Errorf("Got %v expected %v", actualValue, true) - } - } func sameElements(a []interface{}, b []interface{}) bool { @@ -178,7 +159,7 @@ func sameElements(a []interface{}, b []interface{}) bool { return true } -func BenchmarkHashMap(b *testing.B) { +func BenchmarkMap(b *testing.B) { for i := 0; i < b.N; i++ { m := New() for n := 0; n < 1000; n++ { diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 4335b7f3..9c3775e1 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -31,11 +31,8 @@ import ( "testing" ) -func TestTreeMap(t *testing.T) { - +func TestMapPut(t *testing.T) { m := NewWithIntComparator() - - // insertions m.Put(5, "e") m.Put(6, "f") m.Put(7, "g") @@ -45,31 +42,16 @@ func TestTreeMap(t *testing.T) { m.Put(2, "b") m.Put(1, "a") //overwrite - // Test Size() if actualValue := m.Size(); actualValue != 7 { t.Errorf("Got %v expected %v", actualValue, 7) } - - // test Keys() - if actualValue, expectedValue := fmt.Sprintf("%d%d%d%d%d%d%d", m.Keys()...), "1234567"; actualValue != expectedValue { + if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - - // test Values() - if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s", m.Values()...), "abcdefg"; actualValue != expectedValue { + if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "e", "f", "g"}; !sameElements(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - // test Min() - if key, value := m.Min(); key != 1 || value != "a" { - t.Errorf("Got %v expected %v", key, 1) - } - - // test Max() - if key, value := m.Max(); key != 7 || value != "g" { - t.Errorf("Got %v expected %v", key, 7) - } - // key,expectedValue,expectedFound tests1 := [][]interface{}{ {1, "a", true}, @@ -89,27 +71,34 @@ func TestTreeMap(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, test[1]) } } +} + +func TestMapRemove(t *testing.T) { + m := NewWithIntComparator() + m.Put(5, "e") + m.Put(6, "f") + m.Put(7, "g") + m.Put(3, "c") + m.Put(4, "d") + m.Put(1, "x") + m.Put(2, "b") + m.Put(1, "a") //overwrite - // removals m.Remove(5) m.Remove(6) m.Remove(7) m.Remove(8) m.Remove(5) - // Test Keys() - if actualValue, expectedValue := fmt.Sprintf("%d%d%d%d", m.Keys()...), "1234"; actualValue != expectedValue { + if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4}; !sameElements(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - // test Values() - if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", m.Values()...), "abcd"; actualValue != expectedValue { + if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d"}; !sameElements(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - - // Test Size() if actualValue := m.Size(); actualValue != 4 { - t.Errorf("Got %v expected %v", actualValue, 7) + t.Errorf("Got %v expected %v", actualValue, 4) } tests2 := [][]interface{}{ @@ -124,14 +113,12 @@ func TestTreeMap(t *testing.T) { } for _, test := range tests2 { - // retrievals actualValue, actualFound := m.Get(test[0]) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } } - // removals m.Remove(1) m.Remove(4) m.Remove(2) @@ -139,53 +126,44 @@ func TestTreeMap(t *testing.T) { m.Remove(2) m.Remove(2) - // Test Keys() if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - - // test Values() if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - - // Test Size() if actualValue := m.Size(); actualValue != 0 { t.Errorf("Got %v expected %v", actualValue, 0) } - - // Test Empty() - if actualValue := m.Empty(); actualValue != true { - t.Errorf("Got %v expected %v", actualValue, true) - } - - m.Put(1, "a") - m.Put(2, "b") - m.Clear() - - // Test Empty() if actualValue := m.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } +} - // test Min() - if key, value := m.Min(); key != nil || value != nil { - t.Errorf("Got %v expected %v", key, nil) +func sameElements(a []interface{}, b []interface{}) bool { + if len(a) != len(b) { + return false } - - // test Max() - if key, value := m.Max(); key != nil || value != nil { - t.Errorf("Got %v expected %v", key, nil) + for _, av := range a { + found := false + for _, bv := range b { + if av == bv { + found = true + break + } + } + if !found { + return false + } } + return true } -func TestTreeMapEnumerableAndIterator(t *testing.T) { +func TestMapEach(t *testing.T) { m := NewWithStringComparator() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) - - // Each count := 0 m.Each(func(key interface{}, value interface{}) { count += 1 @@ -209,8 +187,13 @@ func TestTreeMapEnumerableAndIterator(t *testing.T) { t.Errorf("Too many") } }) +} - // Map +func TestMapMap(t *testing.T) { + m := NewWithStringComparator() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) mappedMap := m.Map(func(key1 interface{}, value1 interface{}) (key2 interface{}, value2 interface{}) { return key1, "mapped: " + key1.(string) }) @@ -226,8 +209,13 @@ func TestTreeMapEnumerableAndIterator(t *testing.T) { if mappedMap.Size() != 3 { t.Errorf("Got %v expected %v", mappedMap.Size(), 3) } +} - // Select +func TestMapSelect(t *testing.T) { + m := NewWithStringComparator() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) selectedMap := m.Select(func(key interface{}, value interface{}) bool { return key.(string) >= "a" && key.(string) <= "b" }) @@ -238,10 +226,15 @@ func TestTreeMapEnumerableAndIterator(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, "value: b") } if selectedMap.Size() != 2 { - t.Errorf("Got %v expected %v", selectedMap.Size(), 3) + t.Errorf("Got %v expected %v", selectedMap.Size(), 2) } +} - // Any +func TestMapAny(t *testing.T) { + m := NewWithStringComparator() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) any := m.Any(func(key interface{}, value interface{}) bool { return value.(int) == 3 }) @@ -254,8 +247,13 @@ func TestTreeMapEnumerableAndIterator(t *testing.T) { if any != false { t.Errorf("Got %v expected %v", any, false) } +} - // All +func TestMapAll(t *testing.T) { + m := NewWithStringComparator() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) all := m.All(func(key interface{}, value interface{}) bool { return key.(string) >= "a" && key.(string) <= "c" }) @@ -268,8 +266,13 @@ func TestTreeMapEnumerableAndIterator(t *testing.T) { if all != false { t.Errorf("Got %v expected %v", all, false) } +} - // Find +func TestMapFind(t *testing.T) { + m := NewWithStringComparator() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) foundKey, foundValue := m.Find(func(key interface{}, value interface{}) bool { return key.(string) == "c" }) @@ -282,8 +285,38 @@ func TestTreeMapEnumerableAndIterator(t *testing.T) { if foundKey != nil || foundValue != nil { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundKey, nil, nil) } +} + +func TestMapChaining(t *testing.T) { + m := NewWithStringComparator() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + chainedMap := m.Select(func(key interface{}, value interface{}) bool { + return value.(int) > 1 + }).Map(func(key interface{}, value interface{}) (interface{}, interface{}) { + return key.(string) + key.(string), value.(int) * value.(int) + }) + if actualValue := chainedMap.Size(); actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, found := chainedMap.Get("aa"); actualValue != nil || found { + t.Errorf("Got %v expected %v", actualValue, nil) + } + if actualValue, found := chainedMap.Get("bb"); actualValue != 4 || !found { + t.Errorf("Got %v expected %v", actualValue, 4) + } + if actualValue, found := chainedMap.Get("cc"); actualValue != 9 || !found { + t.Errorf("Got %v expected %v", actualValue, 9) + } +} + +func TestMapIterator(t *testing.T) { + m := NewWithStringComparator() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) - // Iterator it := m.Iterator() for it.Next() { key := it.Key() @@ -305,6 +338,7 @@ func TestTreeMapEnumerableAndIterator(t *testing.T) { t.Errorf("Too many") } } + m.Clear() it = m.Iterator() for it.Next() { @@ -312,7 +346,7 @@ func TestTreeMapEnumerableAndIterator(t *testing.T) { } } -func BenchmarkTreeMap(b *testing.B) { +func BenchmarkMap(b *testing.B) { for i := 0; i < b.N; i++ { m := NewWithIntComparator() for n := 0; n < 1000; n++ { From 9992983a60837234a4e124d49a82e7a3ced42eae Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 24 Jun 2016 19:51:21 +0200 Subject: [PATCH 052/320] - refactor sets' tests --- sets/hashset/hashset_test.go | 51 +++++++++---------- sets/treeset/treeset_test.go | 97 +++++++++++++++++++++--------------- 2 files changed, 80 insertions(+), 68 deletions(-) diff --git a/sets/hashset/hashset_test.go b/sets/hashset/hashset_test.go index 036f80d6..cb6b0079 100644 --- a/sets/hashset/hashset_test.go +++ b/sets/hashset/hashset_test.go @@ -31,66 +31,61 @@ import ( "testing" ) -func TestHashSet(t *testing.T) { - +func TestSetAdd(t *testing.T) { set := New() - - // insertions 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) } +} - // Asking if a set is superset of nothing, thus it's true +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() - set.Remove(1) - - if actualValue, expectedValues := fmt.Sprintf("%d%d", set.Values()...), [2]string{"23", "32"}; actualValue != expectedValues[0] && actualValue != expectedValues[1] { - t.Errorf("Got %v expected %v", actualValue, expectedValues) - } - - if actualValue := set.Contains(1); actualValue != false { - t.Errorf("Got %v expected %v", actualValue, false) + if actualValue := set.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) } - - set.Remove(1, 2, 3) - - if actualValue := set.Contains(3); actualValue != false { - t.Errorf("Got %v expected %v", actualValue, false) + set.Remove(1) + if actualValue := set.Size(); actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, 2) } - - if actualValue := set.Empty(); actualValue != true { - t.Errorf("Got %v expected %v", actualValue, true) + 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 BenchmarkHashSet(b *testing.B) { +func BenchmarkSet(b *testing.B) { for i := 0; i < b.N; i++ { set := New() for n := 0; n < 1000; n++ { diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index db307246..14bb4dea 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -23,72 +23,64 @@ import ( "testing" ) -func TestTreeSet(t *testing.T) { - +func TestSetAdd(t *testing.T) { set := NewWithIntComparator() - - // insertions 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) } + if actualValue, expectedValue := fmt.Sprintf("%d%d%d", set.Values()...), "123"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} - // Asking if a set is superset of nothing, thus it's true +func TestSetContains(t *testing.T) { + set := NewWithIntComparator() + set.Add(3, 1, 2) 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) } +} - // repeat 10 time since map in golang has a random iteration order each time and we want to make sure that the set is ordered - for i := 1; i <= 10; i++ { - if actualValue, expectedValue := fmt.Sprintf("%d%d%d", set.Values()...), "123"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - } - +func TestSetRemove(t *testing.T) { + set := NewWithIntComparator() + set.Add(3, 1, 2) set.Remove() - set.Remove(1) - - if actualValue := set.Contains(1); actualValue != false { - t.Errorf("Got %v expected %v", actualValue, false) + if actualValue := set.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) } - - set.Remove(1, 2, 3) - - if actualValue := set.Contains(3); actualValue != false { - t.Errorf("Got %v expected %v", actualValue, false) + set.Remove(1) + if actualValue := set.Size(); actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, 2) } - - if actualValue := set.Empty(); actualValue != true { - t.Errorf("Got %v expected %v", actualValue, true) + 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 TestTreeSetEnumerableAndIterator(t *testing.T) { +func TestSetEach(t *testing.T) { set := NewWithStringComparator() set.Add("c", "a", "b") - - // Each set.Each(func(index int, value interface{}) { switch index { case 0: @@ -107,8 +99,11 @@ func TestTreeSetEnumerableAndIterator(t *testing.T) { t.Errorf("Too many") } }) +} - // Map +func TestSetMap(t *testing.T) { + set := NewWithStringComparator() + set.Add("c", "a", "b") mappedSet := set.Map(func(index int, value interface{}) interface{} { return "mapped: " + value.(string) }) @@ -121,13 +116,16 @@ func TestTreeSetEnumerableAndIterator(t *testing.T) { if mappedSet.Size() != 3 { t.Errorf("Got %v expected %v", mappedSet.Size(), 3) } +} - // Select +func TestSetSelect(t *testing.T) { + set := NewWithStringComparator() + 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: ", mappedSet.Contains("b")) + 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 { @@ -136,8 +134,11 @@ func TestTreeSetEnumerableAndIterator(t *testing.T) { if selectedSet.Size() != 2 { t.Errorf("Got %v expected %v", selectedSet.Size(), 3) } +} - // Any +func TestSetAny(t *testing.T) { + set := NewWithStringComparator() + set.Add("c", "a", "b") any := set.Any(func(index int, value interface{}) bool { return value.(string) == "c" }) @@ -150,8 +151,11 @@ func TestTreeSetEnumerableAndIterator(t *testing.T) { if any != false { t.Errorf("Got %v expected %v", any, false) } +} - // All +func TestSetAll(t *testing.T) { + set := NewWithStringComparator() + set.Add("c", "a", "b") all := set.All(func(index int, value interface{}) bool { return value.(string) >= "a" && value.(string) <= "c" }) @@ -164,8 +168,11 @@ func TestTreeSetEnumerableAndIterator(t *testing.T) { if all != false { t.Errorf("Got %v expected %v", all, false) } +} - // Find +func TestSetFind(t *testing.T) { + set := NewWithStringComparator() + set.Add("c", "a", "b") foundIndex, foundValue := set.Find(func(index int, value interface{}) bool { return value.(string) == "c" }) @@ -178,8 +185,17 @@ func TestTreeSetEnumerableAndIterator(t *testing.T) { 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 := NewWithStringComparator() + set.Add("c", "a", "b") +} + +func TestSetIterator(t *testing.T) { + set := NewWithStringComparator() + set.Add("c", "a", "b") - // Iterator it := set.Iterator() for it.Next() { index := it.Index() @@ -201,6 +217,7 @@ func TestTreeSetEnumerableAndIterator(t *testing.T) { t.Errorf("Too many") } } + set.Clear() it = set.Iterator() for it.Next() { @@ -208,7 +225,7 @@ func TestTreeSetEnumerableAndIterator(t *testing.T) { } } -func BenchmarkTreeSet(b *testing.B) { +func BenchmarkSet(b *testing.B) { for i := 0; i < b.N; i++ { set := NewWithIntComparator() for n := 0; n < 1000; n++ { From a86a65ffaf91be0512994ea2a41824b3dbba22d2 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 24 Jun 2016 19:51:42 +0200 Subject: [PATCH 053/320] - refactor sets' tests --- sets/hashset/hashset_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/sets/hashset/hashset_test.go b/sets/hashset/hashset_test.go index cb6b0079..2c6025d1 100644 --- a/sets/hashset/hashset_test.go +++ b/sets/hashset/hashset_test.go @@ -27,7 +27,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package hashset import ( - "fmt" "testing" ) From fe7fb7b07be0d40225ce67289b6cafb87e7ea1e5 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 24 Jun 2016 19:57:54 +0200 Subject: [PATCH 054/320] - refactor stacks' tests --- stacks/arraystack/arraystack_test.go | 37 +++++++++++-------- .../linkedliststack/linkedliststack_test.go | 36 ++++++++++-------- 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index 65fed89b..42d7d6a6 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -30,15 +30,11 @@ import ( "testing" ) -func TestArrayStack(t *testing.T) { - +func TestStackPush(t *testing.T) { stack := New() - if actualValue := stack.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - - // insertions stack.Push(1) stack.Push(2) stack.Push(3) @@ -46,47 +42,57 @@ func TestArrayStack(t *testing.T) { if actualValue := stack.Values(); actualValue[0].(int) != 3 || actualValue[1].(int) != 2 || actualValue[2].(int) != 1 { t.Errorf("Got %v expected %v", actualValue, "[3,2,1]") } - if actualValue := stack.Empty(); actualValue != false { t.Errorf("Got %v expected %v", actualValue, false) } - if actualValue := stack.Size(); actualValue != 3 { t.Errorf("Got %v expected %v", actualValue, 3) } + if actualValue, ok := stack.Peek(); actualValue != 3 || !ok { + t.Errorf("Got %v expected %v", actualValue, 3) + } +} +func TestStackPeek(t *testing.T) { + stack := New() + if actualValue, ok := stack.Peek(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + stack.Push(1) + stack.Push(2) + stack.Push(3) if actualValue, ok := stack.Peek(); actualValue != 3 || !ok { t.Errorf("Got %v expected %v", actualValue, 3) } +} +func TestStackPop(t *testing.T) { + stack := New() + stack.Push(1) + stack.Push(2) + stack.Push(3) stack.Pop() - if actualValue, ok := stack.Peek(); actualValue != 2 || !ok { t.Errorf("Got %v expected %v", actualValue, 2) } - if actualValue, ok := stack.Pop(); actualValue != 2 || !ok { t.Errorf("Got %v expected %v", actualValue, 2) } - if actualValue, ok := stack.Pop(); actualValue != 1 || !ok { t.Errorf("Got %v expected %v", actualValue, 1) } - if actualValue, ok := stack.Pop(); actualValue != nil || ok { t.Errorf("Got %v expected %v", actualValue, nil) } - if actualValue := stack.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - if actualValue := stack.Values(); len(actualValue) != 0 { t.Errorf("Got %v expected %v", actualValue, "[]") } } -func TestArrayStackIterator(t *testing.T) { +func TestStackIterator(t *testing.T) { stack := New() stack.Push("a") stack.Push("b") @@ -121,7 +127,7 @@ func TestArrayStackIterator(t *testing.T) { } } -func BenchmarkArrayStack(b *testing.B) { +func BenchmarkStack(b *testing.B) { for i := 0; i < b.N; i++ { stack := New() for n := 0; n < 1000; n++ { @@ -131,5 +137,4 @@ func BenchmarkArrayStack(b *testing.B) { stack.Pop() } } - } diff --git a/stacks/linkedliststack/linkedliststack_test.go b/stacks/linkedliststack/linkedliststack_test.go index 2e082ff9..c9b097af 100644 --- a/stacks/linkedliststack/linkedliststack_test.go +++ b/stacks/linkedliststack/linkedliststack_test.go @@ -30,15 +30,11 @@ import ( "testing" ) -func TestLinkedListStack(t *testing.T) { - +func TestStackPush(t *testing.T) { stack := New() - if actualValue := stack.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - - // insertions stack.Push(1) stack.Push(2) stack.Push(3) @@ -46,47 +42,57 @@ func TestLinkedListStack(t *testing.T) { if actualValue := stack.Values(); actualValue[0].(int) != 3 || actualValue[1].(int) != 2 || actualValue[2].(int) != 1 { t.Errorf("Got %v expected %v", actualValue, "[3,2,1]") } - if actualValue := stack.Empty(); actualValue != false { t.Errorf("Got %v expected %v", actualValue, false) } - if actualValue := stack.Size(); actualValue != 3 { t.Errorf("Got %v expected %v", actualValue, 3) } + if actualValue, ok := stack.Peek(); actualValue != 3 || !ok { + t.Errorf("Got %v expected %v", actualValue, 3) + } +} +func TestStackPeek(t *testing.T) { + stack := New() + if actualValue, ok := stack.Peek(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + stack.Push(1) + stack.Push(2) + stack.Push(3) if actualValue, ok := stack.Peek(); actualValue != 3 || !ok { t.Errorf("Got %v expected %v", actualValue, 3) } +} +func TestStackPop(t *testing.T) { + stack := New() + stack.Push(1) + stack.Push(2) + stack.Push(3) stack.Pop() - if actualValue, ok := stack.Peek(); actualValue != 2 || !ok { t.Errorf("Got %v expected %v", actualValue, 2) } - if actualValue, ok := stack.Pop(); actualValue != 2 || !ok { t.Errorf("Got %v expected %v", actualValue, 2) } - if actualValue, ok := stack.Pop(); actualValue != 1 || !ok { t.Errorf("Got %v expected %v", actualValue, 1) } - if actualValue, ok := stack.Pop(); actualValue != nil || ok { t.Errorf("Got %v expected %v", actualValue, nil) } - if actualValue := stack.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - if actualValue := stack.Values(); len(actualValue) != 0 { t.Errorf("Got %v expected %v", actualValue, "[]") } } -func TestLinkedListStackIterator(t *testing.T) { +func TestStackIterator(t *testing.T) { stack := New() stack.Push("a") stack.Push("b") @@ -121,7 +127,7 @@ func TestLinkedListStackIterator(t *testing.T) { } } -func BenchmarkLinkedListStack(b *testing.B) { +func BenchmarkStack(b *testing.B) { for i := 0; i < b.N; i++ { stack := New() for n := 0; n < 1000; n++ { From ab6656e2862897edbd55dc7efb41986a54e6953f Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 24 Jun 2016 20:23:54 +0200 Subject: [PATCH 055/320] - refactor trees' tests --- trees/binaryheap/binaryheap_test.go | 50 +++---- trees/redblacktree/redblacktree_test.go | 187 +++++++++++------------- 2 files changed, 113 insertions(+), 124 deletions(-) diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go index 66c80e1a..76996341 100644 --- a/trees/binaryheap/binaryheap_test.go +++ b/trees/binaryheap/binaryheap_test.go @@ -31,63 +31,65 @@ import ( "testing" ) -func TestBinaryHeap(t *testing.T) { - +func TestBinaryHeapPush(t *testing.T) { heap := NewWithIntComparator() if actualValue := heap.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - // insertions - heap.Push(3) - // [3] - heap.Push(2) - // [2,3] - heap.Push(1) - // [1,3,2](2 swapped with 1, hence last) + heap.Push(3) // [3] + heap.Push(2) // [2,3] + heap.Push(1) // [1,3,2](2 swapped with 1, hence last) if actualValue := heap.Values(); actualValue[0].(int) != 1 || actualValue[1].(int) != 3 || actualValue[2].(int) != 2 { t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") } - if actualValue := heap.Empty(); actualValue != false { t.Errorf("Got %v expected %v", actualValue, false) } - if actualValue := heap.Size(); actualValue != 3 { t.Errorf("Got %v expected %v", actualValue, 3) } - if actualValue, ok := heap.Peek(); actualValue != 1 || !ok { t.Errorf("Got %v expected %v", actualValue, 1) } +} + +func TestBinaryHeapPop(t *testing.T) { + heap := NewWithIntComparator() + + if actualValue := heap.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } - heap.Pop() + heap.Push(3) // [3] + heap.Push(2) // [2,3] + heap.Push(1) // [1,3,2](2 swapped with 1, hence last) + heap.Pop() // [3,2] if actualValue, ok := heap.Peek(); actualValue != 2 || !ok { t.Errorf("Got %v expected %v", actualValue, 2) } - if actualValue, ok := heap.Pop(); actualValue != 2 || !ok { t.Errorf("Got %v expected %v", actualValue, 2) } - if actualValue, ok := heap.Pop(); actualValue != 3 || !ok { t.Errorf("Got %v expected %v", actualValue, 3) } - if actualValue, ok := heap.Pop(); actualValue != nil || ok { t.Errorf("Got %v expected %v", actualValue, nil) } - if actualValue := heap.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - if actualValue := heap.Values(); len(actualValue) != 0 { t.Errorf("Got %v expected %v", actualValue, "[]") } +} + +func TestBinaryHeapRandom(t *testing.T) { + heap := NewWithIntComparator() rand.Seed(3) for i := 0; i < 10000; i++ { @@ -112,15 +114,10 @@ func TestBinaryHeapIterator(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, true) } - // insertions - heap.Push(3) - // [3] - heap.Push(2) - // [2,3] - heap.Push(1) - // [1,3,2](2 swapped with 1, hence last) + heap.Push(3) // [3] + heap.Push(2) // [2,3] + heap.Push(1) // [1,3,2](2 swapped with 1, hence last) - // Iterator it := heap.Iterator() for it.Next() { index := it.Index() @@ -142,6 +139,7 @@ func TestBinaryHeapIterator(t *testing.T) { t.Errorf("Too many") } } + heap.Clear() it = heap.Iterator() for it.Next() { diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index eee89554..480afa77 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -31,11 +31,8 @@ import ( "testing" ) -func TestRedBlackTree(t *testing.T) { - +func TestRedBlackTreePut(t *testing.T) { tree := NewWithIntComparator() - - // insertions tree.Put(5, "e") tree.Put(6, "f") tree.Put(7, "g") @@ -45,54 +42,16 @@ func TestRedBlackTree(t *testing.T) { tree.Put(2, "b") tree.Put(1, "a") //overwrite - // Test Size() if actualValue := tree.Size(); actualValue != 7 { t.Errorf("Got %v expected %v", actualValue, 7) } - - // test Keys() if actualValue, expectedValue := fmt.Sprintf("%d%d%d%d%d%d%d", tree.Keys()...), "1234567"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - - // test Values() if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s", tree.Values()...), "abcdefg"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - // test Left() - if actualValue, expectedValue := fmt.Sprintf("%d", tree.Left().Key), "1"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := fmt.Sprintf("%s", tree.Left().Value), "a"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - - // test Right() - if actualValue, expectedValue := fmt.Sprintf("%d", tree.Right().Key), "7"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := fmt.Sprintf("%s", tree.Right().Value), "g"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - - // test Floor() - if node, found := tree.Floor(4); node.Key != 4 || !found { - t.Errorf("Got %v expected %v", node.Key, 4) - } - if node, found := tree.Floor(0); node != nil || found { - t.Errorf("Got %v expected %v", node, "") - } - - // test Ceiling() - if node, found := tree.Ceiling(4); node.Key != 4 || !found { - t.Errorf("Got %v expected %v", node.Key, 4) - } - if node, found := tree.Ceiling(8); node != nil || found { - t.Errorf("Got %v expected %v", node, "") - } - - // key,expectedValue,expectedFound tests1 := [][]interface{}{ {1, "a", true}, {2, "b", true}, @@ -111,30 +70,34 @@ func TestRedBlackTree(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, test[1]) } } +} + +func TestRedBlackTreeRemove(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(5, "e") + tree.Put(6, "f") + tree.Put(7, "g") + tree.Put(3, "c") + tree.Put(4, "d") + tree.Put(1, "x") + tree.Put(2, "b") + tree.Put(1, "a") //overwrite - // removals tree.Remove(5) tree.Remove(6) tree.Remove(7) tree.Remove(8) tree.Remove(5) - // Test Keys() if actualValue, expectedValue := fmt.Sprintf("%d%d%d%d", tree.Keys()...), "1234"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - - // test Values() if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", tree.Values()...), "abcd"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - - // test Values() if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", tree.Values()...), "abcd"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - - // Test Size() if actualValue := tree.Size(); actualValue != 4 { t.Errorf("Got %v expected %v", actualValue, 7) } @@ -151,14 +114,12 @@ func TestRedBlackTree(t *testing.T) { } for _, test := range tests2 { - // retrievals actualValue, actualFound := tree.Get(test[0]) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } } - // removals tree.Remove(1) tree.Remove(4) tree.Remove(2) @@ -166,60 +127,87 @@ func TestRedBlackTree(t *testing.T) { tree.Remove(2) tree.Remove(2) - // Test Keys() if actualValue, expectedValue := fmt.Sprintf("%s", tree.Keys()), "[]"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - - // test Values() if actualValue, expectedValue := fmt.Sprintf("%s", tree.Values()), "[]"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - - // Test Size() - if actualValue := tree.Size(); actualValue != 0 { - t.Errorf("Got %v expected %v", actualValue, 0) + if empty, size := tree.Empty(), tree.Size(); empty != true || size != -0 { + t.Errorf("Got %v expected %v", empty, true) } - // Test Empty() - if actualValue := tree.Empty(); actualValue != true { - t.Errorf("Got %v expected %v", actualValue, true) +} + +func TestRedBlackTreeLeftAndRight(t *testing.T) { + tree := NewWithIntComparator() + + if actualValue := tree.Left(); actualValue != nil { + t.Errorf("Got %v expected %v", actualValue, nil) + } + if actualValue := tree.Right(); actualValue != nil { + t.Errorf("Got %v expected %v", actualValue, nil) } tree.Put(1, "a") + tree.Put(5, "e") + tree.Put(6, "f") + tree.Put(7, "g") + tree.Put(3, "c") + tree.Put(4, "d") + tree.Put(1, "x") // overwrite tree.Put(2, "b") - tree.Clear() - // Test Empty() - if actualValue := tree.Empty(); actualValue != true { - t.Errorf("Got %v expected %v", actualValue, true) + if actualValue, expectedValue := fmt.Sprintf("%d", tree.Left().Key), "1"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := fmt.Sprintf("%s", tree.Left().Value), "x"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } - // test Left() - if actualValue, expectedValue := fmt.Sprintf("%s", tree.Left()), ""; actualValue != expectedValue { - t.Errorf("Got %s expected %s", actualValue, expectedValue) + if actualValue, expectedValue := fmt.Sprintf("%d", tree.Right().Key), "7"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := fmt.Sprintf("%s", tree.Right().Value), "g"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } +} + +func TestRedBlackTreeCeilingAndFloor(t *testing.T) { + tree := NewWithIntComparator() - // test Right() - if actualValue, expectedValue := fmt.Sprintf("%s", tree.Right()), ""; actualValue != expectedValue { - t.Errorf("Got %s expected %s", actualValue, expectedValue) + if node, found := tree.Floor(0); node != nil || found { + t.Errorf("Got %v expected %v", node, "") + } + if node, found := tree.Ceiling(0); node != nil || found { + t.Errorf("Got %v expected %v", node, "") } - // test Floor() - if node, found := tree.Floor(1); node != nil || found { + tree.Put(5, "e") + tree.Put(6, "f") + tree.Put(7, "g") + tree.Put(3, "c") + tree.Put(4, "d") + tree.Put(1, "x") + tree.Put(2, "b") + + if node, found := tree.Floor(4); node.Key != 4 || !found { + t.Errorf("Got %v expected %v", node.Key, 4) + } + if node, found := tree.Floor(0); node != nil || found { t.Errorf("Got %v expected %v", node, "") } - // test Ceiling() - if node, found := tree.Ceiling(1); node != nil || found { + if node, found := tree.Ceiling(4); node.Key != 4 || !found { + t.Errorf("Got %v expected %v", node.Key, 4) + } + if node, found := tree.Ceiling(8); node != nil || found { t.Errorf("Got %v expected %v", node, "") } } -func TestRedBlackTreeIterator(t *testing.T) { +func TestRedBlackTreeIterator1(t *testing.T) { tree := NewWithIntComparator() - - // insertions tree.Put(5, "e") tree.Put(6, "f") tree.Put(7, "g") @@ -229,7 +217,6 @@ func TestRedBlackTreeIterator(t *testing.T) { tree.Put(2, "b") tree.Put(1, "a") //overwrite - // Iterator it := tree.Iterator() count := 0 for it.Next() { @@ -249,14 +236,15 @@ func TestRedBlackTreeIterator(t *testing.T) { if actualValue, expectedValue := count, 7; actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } +} - // Iterator - tree.Clear() +func TestRedBlackTreeIterator2(t *testing.T) { + tree := NewWithIntComparator() tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") - it = tree.Iterator() - count = 0 + it := tree.Iterator() + count := 0 for it.Next() { count += 1 index := it.Key() @@ -274,12 +262,20 @@ func TestRedBlackTreeIterator(t *testing.T) { if actualValue, expectedValue := count, 3; actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } +} + +func TestRedBlackTreeIterator3(t *testing.T) { + tree := NewWithIntComparator() + + it := tree.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty stack") + } - // Iterator - tree.Clear() tree.Put(1, "a") + it = tree.Iterator() - count = 0 + count := 0 for it.Next() { count += 1 index := it.Key() @@ -297,16 +293,10 @@ func TestRedBlackTreeIterator(t *testing.T) { if actualValue, expectedValue := count, 1; actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } +} - // Iterator on empty - tree.Clear() - it = tree.Iterator() - for it.Next() { - t.Errorf("Shouldn't iterate on empty stack") - } - - // Iterator (from image) - tree.Clear() +func TestRedBlackTreeIterator4(t *testing.T) { + tree := NewWithIntComparator() tree.Put(13, 5) tree.Put(8, 3) tree.Put(17, 7) @@ -317,8 +307,9 @@ func TestRedBlackTreeIterator(t *testing.T) { tree.Put(6, 2) tree.Put(22, 8) tree.Put(27, 10) - it = tree.Iterator() - count = 0 + + it := tree.Iterator() + count := 0 for it.Next() { count += 1 value := it.Value() From 35457aba813c99e6a5814074ed891289053072d1 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 24 Jun 2016 20:27:34 +0200 Subject: [PATCH 056/320] - fix spelling --- lists/arraylist/arraylist.go | 2 +- lists/doublylinkedlist/doublylinkedlist.go | 2 +- lists/singlylinkedlist/singlylinkedlist.go | 2 +- stacks/arraystack/arraystack.go | 2 +- stacks/linkedliststack/linkedliststack.go | 2 +- trees/binaryheap/binaryheap.go | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index cdcd2d93..34cee03f 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -286,7 +286,7 @@ func (list *List) String() string { return str } -// Check that the index is withing bounds of the list +// Check that the index is within bounds of the list func (list *List) withinRange(index int) bool { return index >= 0 && index < list.size } diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 73f7e59b..1d50f098 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -418,7 +418,7 @@ func (list *List) String() string { return str } -// Check that the index is withing bounds of the list +// Check that the index is within bounds of the list func (list *List) withinRange(index int) bool { return index >= 0 && index < list.size } diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index e71a36f7..7cd5efcb 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -388,7 +388,7 @@ func (list *List) String() string { return str } -// Check that the index is withing bounds of the list +// Check that the index is within bounds of the list func (list *List) withinRange(index int) bool { return index >= 0 && index < list.size } diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index 22769570..466797f5 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -137,7 +137,7 @@ func (stack *Stack) String() string { return str } -// Check that the index is withing bounds of the list +// Check that the index is within bounds of the list func (stack *Stack) withinRange(index int) bool { return index >= 0 && index < stack.list.Size() } diff --git a/stacks/linkedliststack/linkedliststack.go b/stacks/linkedliststack/linkedliststack.go index 551377e9..71df93c0 100644 --- a/stacks/linkedliststack/linkedliststack.go +++ b/stacks/linkedliststack/linkedliststack.go @@ -133,7 +133,7 @@ func (stack *Stack) String() string { return str } -// Check that the index is withing bounds of the list +// Check that the index is within bounds of the list func (stack *Stack) withinRange(index int) bool { return index >= 0 && index < stack.list.Size() } diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index 79e7ec58..3f1c759f 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -192,7 +192,7 @@ func (heap *Heap) bubbleUp() { } } -// Check that the index is withing bounds of the list +// Check that the index is within bounds of the list func (heap *Heap) withinRange(index int) bool { return index >= 0 && index < heap.list.Size() } From ef9baa808a922b844c51aec0434a9d843c7c637d Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 24 Jun 2016 21:52:16 +0200 Subject: [PATCH 057/320] - golint --- containers/containers.go | 5 +- containers/enumerable.go | 28 ++-- containers/iterator.go | 16 +-- examples/arraylist.go | 1 + examples/arraystack.go | 1 + examples/binaryheap.go | 1 + examples/customcomparator.go | 2 + examples/doublylinkedlist.go | 1 + examples/enumerablewithindex.go | 3 +- examples/enumerablewithkey.go | 3 +- examples/hashmap.go | 1 + examples/hashset.go | 1 + examples/linkedliststack.go | 1 + examples/redblacktree.go | 1 + examples/redblacktreeextended.go | 24 ++-- examples/singlylinkedlist.go | 1 + examples/sort.go | 1 + examples/treemap.go | 1 + examples/treeset.go | 1 + lists/arraylist/arraylist.go | 69 +++++----- lists/doublylinkedlist/doublylinkedlist.go | 63 ++++----- lists/lists.go | 1 + lists/singlylinkedlist/singlylinkedlist.go | 53 ++++---- maps/hashmap/hashmap.go | 24 ++-- maps/maps.go | 1 + maps/treemap/treemap.go | 49 +++---- maps/treemap/treemap_test.go | 2 +- sets/hashset/hashset.go | 20 +-- sets/sets.go | 1 + sets/treeset/treeset.go | 45 ++++--- stacks/arraystack/arraystack.go | 29 ++-- stacks/linkedliststack/linkedliststack.go | 29 ++-- stacks/stacks.go | 1 + trees/binaryheap/binaryheap.go | 33 ++--- trees/redblacktree/redblacktree.go | 55 ++++---- trees/redblacktree/redblacktree_test.go | 8 +- trees/trees.go | 1 + utils/comparator.go | 2 + utils/sort.go | 2 +- utils/timsort/timsort.go | 146 ++++++++++----------- 40 files changed, 389 insertions(+), 338 deletions(-) diff --git a/containers/containers.go b/containers/containers.go index 2da6c26a..389d289a 100644 --- a/containers/containers.go +++ b/containers/containers.go @@ -24,12 +24,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// All data structures must implement the container structure - package containers import "github.com/emirpasic/gods/utils" +// Container is base interface that all data structures implement type Container interface { Empty() bool Size() int @@ -37,7 +36,7 @@ type Container interface { Values() []interface{} } -// Returns sorted container's elements with respect to the passed comparator. +// GetSortedValues returns sorted container's elements with respect to the passed comparator. // Does not effect the ordering of elements within the container. // Uses timsort. func GetSortedValues(container Container, comparator utils.Comparator) []interface{} { diff --git a/containers/enumerable.go b/containers/enumerable.go index 5824b23e..0a092070 100644 --- a/containers/enumerable.go +++ b/containers/enumerable.go @@ -29,57 +29,57 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package containers -// Enumerable functions for ordered containers whose values can be fetched by an index. +// EnumerableWithIndex provides functions for ordered containers whose values can be fetched by an index. type EnumerableWithIndex interface { - // Calls the given function once for each element, passing that element's index and value. + // Each calls the given function once for each element, passing that element's index and value. Each(func(index int, value interface{})) - // Invokes the given function once for each element and returns a + // Map invokes the given function once for each element and returns a // container containing the values returned by the given function. // TODO need help on how to enforce this in containers (don't want to type assert when chaining) // Map(func(index int, value interface{}) interface{}) Container - // Returns a new container containing all elements for which the given function returns a true value. + // Select returns a new container containing all elements for which the given function returns a true value. // TODO need help on how to enforce this in containers (don't want to type assert when chaining) // Select(func(index int, value interface{}) bool) Container - // Passes each element of the container to the given function and + // 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 - // Passes each element of the container to the given function and + // 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 - // Passes each element of the container to the given function and returns + // 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{}) } -// Enumerable functions for ordered containers whose values whose elements are key/value pairs. +// EnumerableWithKey provides functions for ordered containers whose values whose elements are key/value pairs. type EnumerableWithKey interface { - // Calls the given function once for each element, passing that element's key and value. + // Each calls the given function once for each element, passing that element's key and value. Each(func(key interface{}, value interface{})) - // Invokes the given function once for each element and returns a container + // 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. // TODO need help on how to enforce this in containers (don't want to type assert when chaining) // Map(func(key interface{}, value interface{}) (interface{}, interface{})) Container - // Returns a new container containing all elements for which the given function returns a true value. + // Select returns a new container containing all elements for which the given function returns a true value. // TODO need help on how to enforce this in containers (don't want to type assert when chaining) // Select(func(key interface{}, value interface{}) bool) Container - // Passes each element of the container to the given function and + // 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 - // Passes each element of the container to the given function and + // 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 - // Passes each element of the container to the given function and returns + // 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{}) diff --git a/containers/iterator.go b/containers/iterator.go index 45d06188..b3d22543 100644 --- a/containers/iterator.go +++ b/containers/iterator.go @@ -28,30 +28,30 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package containers -// Stateful iterator for ordered containers whose values can be fetched by an index. +// IteratorWithIndex is stateful iterator for ordered containers whose values can be fetched by an index. type IteratorWithIndex interface { - // Moves the iterator to the next element and returns true if there was a next element in the container. + // 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(). // Modifies the state of the iterator. Next() bool - // Returns the current element's value. + // Value returns the current element's value. // Does not modify the state of the iterator. Value() interface{} - // Returns the current element's index. + // Index returns the current element's index. // Does not modify the state of the iterator. Index() int } -// Stateful iterator for ordered containers whose elements are key value pairs. +// IteratorWithKey is a stateful iterator for ordered containers whose elements are key value pairs. type IteratorWithKey interface { - // Moves the iterator to the next element and returns true if there was a next element in the container. + // 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(). // Modifies the state of the iterator. Next() bool - // Returns the current element's value. + // Value returns the current element's value. // Does not modify the state of the iterator. Value() interface{} - // Returns the current element's key. + // Key returns the current element's key. // Does not modify the state of the iterator. Key() interface{} } diff --git a/examples/arraylist.go b/examples/arraylist.go index f2134c70..9ef7f025 100644 --- a/examples/arraylist.go +++ b/examples/arraylist.go @@ -31,6 +31,7 @@ import ( "github.com/emirpasic/gods/utils" ) +// ArrayListExample to demonstrate basic usage of ArrayList func ArrayListExample() { list := arraylist.New() list.Add("a") // ["a"] diff --git a/examples/arraystack.go b/examples/arraystack.go index 1dd93cea..66c1144e 100644 --- a/examples/arraystack.go +++ b/examples/arraystack.go @@ -28,6 +28,7 @@ package examples import "github.com/emirpasic/gods/stacks/arraystack" +// ArrayStackExample to demonstrate basic usage of ArrayStack func ArrayStackExample() { stack := arraystack.New() // empty stack.Push(1) // 1 diff --git a/examples/binaryheap.go b/examples/binaryheap.go index 588ce5b8..6b54661c 100644 --- a/examples/binaryheap.go +++ b/examples/binaryheap.go @@ -31,6 +31,7 @@ import ( "github.com/emirpasic/gods/utils" ) +// BinaryHeapExample to demonstrate basic usage of BinaryHeap func BinaryHeapExample() { // Min-heap diff --git a/examples/customcomparator.go b/examples/customcomparator.go index b14e4afa..891d33ac 100644 --- a/examples/customcomparator.go +++ b/examples/customcomparator.go @@ -31,6 +31,7 @@ import ( "github.com/emirpasic/gods/sets/treeset" ) +// User model (id and name) type User struct { id int name string @@ -53,6 +54,7 @@ func byID(a, b interface{}) int { } } +// CustomComparatorExample to demonstrate basic usage of CustomComparator func CustomComparatorExample() { set := treeset.NewWith(byID) diff --git a/examples/doublylinkedlist.go b/examples/doublylinkedlist.go index d475eb73..ce181c47 100644 --- a/examples/doublylinkedlist.go +++ b/examples/doublylinkedlist.go @@ -31,6 +31,7 @@ import ( "github.com/emirpasic/gods/utils" ) +// DoublyLinkedListExample to demonstrate basic usage of DoublyLinkedList func DoublyLinkedListExample() { list := dll.New() list.Add("a") // ["a"] diff --git a/examples/enumerablewithindex.go b/examples/enumerablewithindex.go index 99f1954e..ac9a175b 100644 --- a/examples/enumerablewithindex.go +++ b/examples/enumerablewithindex.go @@ -39,7 +39,8 @@ func printSet(txt string, set *treeset.Set) { fmt.Println("]") } -func EnumerableWithIndexTest() { +// EnumerableWithIndexExample to demonstrate basic usage of EnumerableWithIndex +func EnumerableWithIndexExample() { set := treeset.NewWithIntComparator() set.Add(2, 3, 4, 2, 5, 6, 7, 8) printSet("Initial", set) // [ 2 3 4 5 6 7 8 ] diff --git a/examples/enumerablewithkey.go b/examples/enumerablewithkey.go index aba2d246..191809e6 100644 --- a/examples/enumerablewithkey.go +++ b/examples/enumerablewithkey.go @@ -39,7 +39,8 @@ func printMap(txt string, m *treemap.Map) { fmt.Println("}") } -func EunumerableWithKey() { +// EunumerableWithKeyExample to demonstrate basic usage of EunumerableWithKey +func EunumerableWithKeyExample() { m := treemap.NewWithStringComparator() m.Put("g", 7) m.Put("f", 6) diff --git a/examples/hashmap.go b/examples/hashmap.go index f73882cb..01a94b4c 100644 --- a/examples/hashmap.go +++ b/examples/hashmap.go @@ -28,6 +28,7 @@ package examples import "github.com/emirpasic/gods/maps/hashmap" +// HashMapExample to demonstrate basic usage of HashMap func HashMapExample() { m := hashmap.New() // empty m.Put(1, "x") // 1->x diff --git a/examples/hashset.go b/examples/hashset.go index ed466742..aa30a0d6 100644 --- a/examples/hashset.go +++ b/examples/hashset.go @@ -28,6 +28,7 @@ package examples import "github.com/emirpasic/gods/sets/hashset" +// HashSetExample to demonstrate basic usage of HashSet func HashSetExample() { set := hashset.New() // empty (keys are of type int) set.Add(1) // 1 diff --git a/examples/linkedliststack.go b/examples/linkedliststack.go index b7911f16..34a88695 100644 --- a/examples/linkedliststack.go +++ b/examples/linkedliststack.go @@ -28,6 +28,7 @@ package examples import lls "github.com/emirpasic/gods/stacks/linkedliststack" +// LinkedListStackExample to demonstrate basic usage of LinkedListStack func LinkedListStackExample() { stack := lls.New() // empty stack.Push(1) // 1 diff --git a/examples/redblacktree.go b/examples/redblacktree.go index 8dab4a6d..62a20af1 100644 --- a/examples/redblacktree.go +++ b/examples/redblacktree.go @@ -31,6 +31,7 @@ import ( rbt "github.com/emirpasic/gods/trees/redblacktree" ) +// RedBlackTreeExample to demonstrate basic usage of RedBlackTree func RedBlackTreeExample() { tree := rbt.NewWithIntComparator() // empty(keys are of type int) diff --git a/examples/redblacktreeextended.go b/examples/redblacktreeextended.go index fbb8d6cc..fb23614f 100644 --- a/examples/redblacktreeextended.go +++ b/examples/redblacktreeextended.go @@ -31,46 +31,47 @@ import ( rbt "github.com/emirpasic/gods/trees/redblacktree" ) +// RedBlackTreeExtended to demonstrate how to extend a RedBlackTree to include new functions type RedBlackTreeExtended struct { *rbt.Tree } +// GetMin gets the min value and flag if found func (tree *RedBlackTreeExtended) GetMin() (value interface{}, found bool) { node, found := tree.getMinFromNode(tree.Root) if node != nil { return node.Value, found - } else { - return nil, false } + return nil, false } +// GetMax gets the max value and flag if found func (tree *RedBlackTreeExtended) GetMax() (value interface{}, found bool) { node, found := tree.getMaxFromNode(tree.Root) if node != nil { return node.Value, found - } else { - return nil, false } + return nil, false } +// RemoveMin removes the min value and flag if found func (tree *RedBlackTreeExtended) RemoveMin() (value interface{}, deleted bool) { node, found := tree.getMinFromNode(tree.Root) if found { tree.Remove(node.Key) return node.Value, found - } else { - return nil, false } + return nil, false } +// RemoveMax removes the max value and flag if found func (tree *RedBlackTreeExtended) RemoveMax() (value interface{}, deleted bool) { node, found := tree.getMaxFromNode(tree.Root) if found { tree.Remove(node.Key) return node.Value, found - } else { - return nil, false } + return nil, false } func (tree *RedBlackTreeExtended) getMinFromNode(node *rbt.Node) (foundNode *rbt.Node, found bool) { @@ -79,9 +80,8 @@ func (tree *RedBlackTreeExtended) getMinFromNode(node *rbt.Node) (foundNode *rbt } if node.Left == nil { return node, true - } else { - return tree.getMinFromNode(node.Left) } + return tree.getMinFromNode(node.Left) } func (tree *RedBlackTreeExtended) getMaxFromNode(node *rbt.Node) (foundNode *rbt.Node, found bool) { @@ -90,9 +90,8 @@ func (tree *RedBlackTreeExtended) getMaxFromNode(node *rbt.Node) (foundNode *rbt } if node.Right == nil { return node, true - } else { - return tree.getMaxFromNode(node.Right) } + return tree.getMaxFromNode(node.Right) } func print(tree *RedBlackTreeExtended) { @@ -103,6 +102,7 @@ func print(tree *RedBlackTreeExtended) { fmt.Println(tree) } +// RedBlackTreeExtendedExample main method on how to use the custom red-black tree above func RedBlackTreeExtendedExample() { tree := RedBlackTreeExtended{rbt.NewWithIntComparator()} diff --git a/examples/singlylinkedlist.go b/examples/singlylinkedlist.go index 67252367..4bd0d8fe 100644 --- a/examples/singlylinkedlist.go +++ b/examples/singlylinkedlist.go @@ -31,6 +31,7 @@ import ( "github.com/emirpasic/gods/utils" ) +// SinglyLinkedListExample to demonstrate basic usage of SinglyLinkedList func SinglyLinkedListExample() { list := sll.New() list.Add("a") // ["a"] diff --git a/examples/sort.go b/examples/sort.go index b7133790..5940886b 100644 --- a/examples/sort.go +++ b/examples/sort.go @@ -28,6 +28,7 @@ package examples import "github.com/emirpasic/gods/utils" +// SortExample to demonstrate basic usage of basic sort (timsort) func SortExample() { strings := []interface{}{} // [] strings = append(strings, "d") // ["d"] diff --git a/examples/treemap.go b/examples/treemap.go index 45bea0b5..4177bbf7 100644 --- a/examples/treemap.go +++ b/examples/treemap.go @@ -28,6 +28,7 @@ package examples import "github.com/emirpasic/gods/maps/treemap" +// TreeMapExample to demonstrate basic usage of TreeMap func TreeMapExample() { m := treemap.NewWithIntComparator() // empty (keys are of type int) m.Put(1, "x") // 1->x diff --git a/examples/treeset.go b/examples/treeset.go index 62e717f3..bd0d61cb 100644 --- a/examples/treeset.go +++ b/examples/treeset.go @@ -28,6 +28,7 @@ package examples import "github.com/emirpasic/gods/sets/treeset" +// TreeSetExample to demonstrate basic usage of TreeSet func TreeSetExample() { set := treeset.NewWithIntComparator() // empty set.Add(1) // 1 diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index 34cee03f..5e65f39c 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -44,31 +44,32 @@ func assertInterfaceImplementation() { var _ containers.IteratorWithIndex = (*Iterator)(nil) } +// List holds the elements in a slice type List struct { elements []interface{} size int } const ( - GROWTH_FACTOR = float32(2.0) // growth by 100% - SHRINK_FACTOR = float32(0.25) // shrink when size is 25% of capacity (0 means never shrink) + growthFactor = float32(2.0) // growth by 100% + shrinkFactor = float32(0.25) // shrink when size is 25% of capacity (0 means never shrink) ) -// Instantiates a new empty list +// New instantiates a new empty list func New() *List { return &List{} } -// Appends a value at the end of the list +// Add appends a value at the end of the list func (list *List) Add(values ...interface{}) { list.growBy(len(values)) for _, value := range values { list.elements[list.size] = value - list.size += 1 + list.size++ } } -// Returns the element at index. +// Get returns the element at index. // Second return parameter is true if index is within bounds of the array and array is not empty, otherwise false. func (list *List) Get(index int) (interface{}, bool) { @@ -79,7 +80,7 @@ func (list *List) Get(index int) (interface{}, bool) { return list.elements[index], true } -// Removes one or more elements from the list with the supplied indices. +// Remove removes one or more elements from the list with the supplied indices. func (list *List) Remove(index int) { if !list.withinRange(index) { @@ -88,12 +89,12 @@ func (list *List) Remove(index int) { list.elements[index] = nil // cleanup reference copy(list.elements[index:], list.elements[index+1:list.size]) // shift to the left by one (slow operation, need ways to optimize this) - list.size -= 1 + list.size-- list.shrink() } -// Check if elements (one or more) are present in the set. +// Contains checks if elements (one or more) are present in the set. // All elements have to be present in the set for the method to return true. // Performance time complexity of n^2. // Returns true if no arguments are passed at all, i.e. set is always super-set of empty set. @@ -114,30 +115,30 @@ func (list *List) Contains(values ...interface{}) bool { return true } -// Returns all elements in the list. +// Values returns all elements in the list. func (list *List) Values() []interface{} { newElements := make([]interface{}, list.size, list.size) copy(newElements, list.elements[:list.size]) return newElements } -// Returns true if list does not contain any elements. +// Empty returns true if list does not contain any elements. func (list *List) Empty() bool { return list.size == 0 } -// Returns number of elements within the list. +// Size returns number of elements within the list. func (list *List) Size() int { return list.size } -// Removes all elements from the list. +// Clear removes all elements from the list. func (list *List) Clear() { list.size = 0 list.elements = []interface{}{} } -// Sorts values (in-place) using timsort. +// Sort sorts values (in-place) using timsort. func (list *List) Sort(comparator utils.Comparator) { if len(list.elements) < 2 { return @@ -145,14 +146,14 @@ func (list *List) Sort(comparator utils.Comparator) { utils.Sort(list.elements[:list.size], comparator) } -// Swaps the two values at the specified positions. +// Swap swaps the two values at the specified positions. func (list *List) Swap(i, j int) { if list.withinRange(i) && list.withinRange(j) { list.elements[i], list.elements[j] = list.elements[j], list.elements[i] } } -// Inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right. +// Insert inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right. // Does not do anything if position is negative or bigger than list's size // Note: position equal to list's size is valid, i.e. append. func (list *List) Insert(index int, values ...interface{}) { @@ -178,37 +179,38 @@ func (list *List) Insert(index int, values ...interface{}) { } } +// Iterator holding the iterator's state type Iterator struct { list *List index int } -// Returns a stateful iterator whose values can be fetched by an index. +// Iterator returns a stateful iterator whose values can be fetched by an index. func (list *List) Iterator() Iterator { return Iterator{list: list, index: -1} } -// Moves the iterator to the next element and returns true if there was a next element in the container. +// 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(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index += 1 + iterator.index++ return iterator.list.withinRange(iterator.index) } -// Returns the current element's value. +// Value returns the current element's value. // Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { return iterator.list.elements[iterator.index] } -// Returns the current element's index. +// Index returns the current element's index. // Does not modify the state of the iterator. func (iterator *Iterator) Index() int { return iterator.index } -// Calls the given function once for each element, passing that element's index and value. +// Each calls the given function once for each element, passing that element's index and value. func (list *List) Each(f func(index int, value interface{})) { iterator := list.Iterator() for iterator.Next() { @@ -216,7 +218,7 @@ func (list *List) Each(f func(index int, value interface{})) { } } -// Invokes the given function once for each element and returns a +// Map invokes the given function once for each element and returns a // container containing the values returned by the given function. func (list *List) Map(f func(index int, value interface{}) interface{}) *List { newList := &List{} @@ -227,7 +229,7 @@ func (list *List) Map(f func(index int, value interface{}) interface{}) *List { return newList } -// Returns a new container containing all elements for which the given function returns a true value. +// Select returns a new container containing all elements for which the given function returns a true value. func (list *List) Select(f func(index int, value interface{}) bool) *List { newList := &List{} iterator := list.Iterator() @@ -239,7 +241,7 @@ func (list *List) Select(f func(index int, value interface{}) bool) *List { return newList } -// Passes each element of the collection to the given function and +// Any passes each element of the collection to the given function and // returns true if the function ever returns true for any element. func (list *List) Any(f func(index int, value interface{}) bool) bool { iterator := list.Iterator() @@ -251,7 +253,7 @@ func (list *List) Any(f func(index int, value interface{}) bool) bool { return false } -// Passes each element of the collection to the given function and +// All passes each element of the collection to the given function and // returns true if the function returns true for all elements. func (list *List) All(f func(index int, value interface{}) bool) bool { iterator := list.Iterator() @@ -263,7 +265,7 @@ func (list *List) All(f func(index int, value interface{}) bool) bool { return true } -// Passes each element of the container to the given function and returns +// 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 (list *List) Find(f func(index int, value interface{}) bool) (int, interface{}) { @@ -276,6 +278,7 @@ func (list *List) Find(f func(index int, value interface{}) bool) (int, interfac return -1, nil } +// String returns a string representation of container func (list *List) String() string { str := "ArrayList\n" values := []string{} @@ -299,22 +302,22 @@ func (list *List) resize(cap int) { // Expand the array if necessary, i.e. capacity will be reached if we add n elements func (list *List) growBy(n int) { - // When capacity is reached, grow by a factor of GROWTH_FACTOR and add number of elements + // When capacity is reached, grow by a factor of growthFactor and add number of elements currentCapacity := cap(list.elements) if list.size+n >= currentCapacity { - newCapacity := int(GROWTH_FACTOR * float32(currentCapacity+n)) + newCapacity := int(growthFactor * float32(currentCapacity+n)) list.resize(newCapacity) } } -// Shrink the array if necessary, i.e. when size is SHRINK_FACTOR percent of current capacity +// Shrink the array if necessary, i.e. when size is shrinkFactor percent of current capacity func (list *List) shrink() { - if SHRINK_FACTOR == 0.0 { + if shrinkFactor == 0.0 { return } - // Shrink when size is at SHRINK_FACTOR * capacity + // Shrink when size is at shrinkFactor * capacity currentCapacity := cap(list.elements) - if list.size <= int(float32(currentCapacity)*SHRINK_FACTOR) { + if list.size <= int(float32(currentCapacity)*shrinkFactor) { list.resize(list.size) } } diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 1d50f098..8263cc64 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -44,6 +44,7 @@ func assertInterfaceImplementation() { var _ containers.IteratorWithIndex = (*Iterator)(nil) } +// List holds the elements, where each element points to the next and previous element type List struct { first *element last *element @@ -56,12 +57,12 @@ type element struct { next *element } -// Instantiates a new empty list +// New instantiates a new empty list func New() *List { return &List{} } -// Appends a value (one or more) at the end of the list (same as Append()) +// Add appends a value (one or more) at the end of the list (same as Append()) func (list *List) Add(values ...interface{}) { for _, value := range values { newElement := &element{value: value, prev: list.last} @@ -76,12 +77,12 @@ func (list *List) Add(values ...interface{}) { } } -// Appends a value (one or more) at the end of the list (same as Add()) +// Append appends a value (one or more) at the end of the list (same as Add()) func (list *List) Append(values ...interface{}) { list.Add(values...) } -// Prepends a values (or more) +// Prepend prepends a values (or more) func (list *List) Prepend(values ...interface{}) { // in reverse to keep passed order i.e. ["c","d"] -> Prepend(["a","b"]) -> ["a","b","c",d"] for v := len(values) - 1; v >= 0; v-- { @@ -97,7 +98,7 @@ func (list *List) Prepend(values ...interface{}) { } } -// Returns the element at index. +// Get returns the element at index. // Second return parameter is true if index is within bounds of the array and array is not empty, otherwise false. func (list *List) Get(index int) (interface{}, bool) { @@ -111,16 +112,14 @@ func (list *List) Get(index int) (interface{}, bool) { for e := list.size - 1; e != index; e, element = e-1, element.prev { } return element.value, true - } else { - element := list.first - for e := 0; e != index; e, element = e+1, element.next { - } - return element.value, true } - + element := list.first + for e := 0; e != index; e, element = e+1, element.next { + } + return element.value, true } -// Removes one or more elements from the list with the supplied indices. +// Remove removes one or more elements from the list with the supplied indices. func (list *List) Remove(index int) { if !list.withinRange(index) { @@ -162,7 +161,7 @@ func (list *List) Remove(index int) { list.size-- } -// Check if values (one or more) are present in the set. +// Contains check if values (one or more) are present in the set. // All values have to be present in the set for the method to return true. // Performance time complexity of n^2. // Returns true if no arguments are passed at all, i.e. set is always super-set of empty set. @@ -189,7 +188,7 @@ func (list *List) Contains(values ...interface{}) bool { return true } -// Returns all elements in the list. +// Values returns all elements in the list. func (list *List) Values() []interface{} { values := make([]interface{}, list.size, list.size) for e, element := 0, list.first; element != nil; e, element = e+1, element.next { @@ -198,24 +197,24 @@ func (list *List) Values() []interface{} { return values } -// Returns true if list does not contain any elements. +// Empty returns true if list does not contain any elements. func (list *List) Empty() bool { return list.size == 0 } -// Returns number of elements within the list. +// Size returns number of elements within the list. func (list *List) Size() int { return list.size } -// Removes all elements from the list. +// Clear removes all elements from the list. func (list *List) Clear() { list.size = 0 list.first = nil list.last = nil } -// Sorts values (in-place) using timsort. +// Sort sorts values (in-place) using timsort. func (list *List) Sort(comparator utils.Comparator) { if list.size < 2 { @@ -231,7 +230,7 @@ func (list *List) Sort(comparator utils.Comparator) { } -// Swaps values of two elements at the given indices. +// Swap swaps values of two elements at the given indices. func (list *List) Swap(i, j int) { if list.withinRange(i) && list.withinRange(j) && i != j { var element1, element2 *element @@ -247,7 +246,7 @@ func (list *List) Swap(i, j int) { } } -// Inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right. +// Insert inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right. // Does not do anything if position is negative or bigger than list's size // Note: position equal to list's size is valid, i.e. append. func (list *List) Insert(index int, values ...interface{}) { @@ -300,22 +299,23 @@ func (list *List) Insert(index int, values ...interface{}) { } } +// Iterator holding the iterator's state type Iterator struct { list *List index int element *element } -// Returns a stateful iterator whose values can be fetched by an index. +// Iterator returns a stateful iterator whose values can be fetched by an index. func (list *List) Iterator() Iterator { return Iterator{list: list, index: -1, element: nil} } -// Moves the iterator to the next element and returns true if there was a next element in the container. +// 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(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index += 1 + iterator.index++ if !iterator.list.withinRange(iterator.index) { iterator.element = nil return false @@ -328,19 +328,19 @@ func (iterator *Iterator) Next() bool { return true } -// Returns the current element's value. +// Value returns the current element's value. // Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { return iterator.element.value } -// Returns the current element's index. +// Index returns the current element's index. // Does not modify the state of the iterator. func (iterator *Iterator) Index() int { return iterator.index } -// Calls the given function once for each element, passing that element's index and value. +// Each calls the given function once for each element, passing that element's index and value. func (list *List) Each(f func(index int, value interface{})) { iterator := list.Iterator() for iterator.Next() { @@ -348,7 +348,7 @@ func (list *List) Each(f func(index int, value interface{})) { } } -// Invokes the given function once for each element and returns a +// Map invokes the given function once for each element and returns a // container containing the values returned by the given function. func (list *List) Map(f func(index int, value interface{}) interface{}) *List { newList := &List{} @@ -359,7 +359,7 @@ func (list *List) Map(f func(index int, value interface{}) interface{}) *List { return newList } -// Returns a new container containing all elements for which the given function returns a true value. +// Select returns a new container containing all elements for which the given function returns a true value. func (list *List) Select(f func(index int, value interface{}) bool) *List { newList := &List{} iterator := list.Iterator() @@ -371,7 +371,7 @@ func (list *List) Select(f func(index int, value interface{}) bool) *List { return newList } -// Passes each element of the container to the given function and +// Any passes each element of the container to the given function and // returns true if the function ever returns true for any element. func (list *List) Any(f func(index int, value interface{}) bool) bool { iterator := list.Iterator() @@ -383,7 +383,7 @@ func (list *List) Any(f func(index int, value interface{}) bool) bool { return false } -// Passes each element of the container to the given function and +// All passes each element of the container to the given function and // returns true if the function returns true for all elements. func (list *List) All(f func(index int, value interface{}) bool) bool { iterator := list.Iterator() @@ -395,7 +395,7 @@ func (list *List) All(f func(index int, value interface{}) bool) bool { return true } -// Passes each element of the container to the given function and returns +// 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 (list *List) Find(f func(index int, value interface{}) bool) (index int, value interface{}) { @@ -408,6 +408,7 @@ func (list *List) Find(f func(index int, value interface{}) bool) (index int, va return -1, nil } +// String returns a string representation of container func (list *List) String() string { str := "DoublyLinkedList\n" values := []string{} diff --git a/lists/lists.go b/lists/lists.go index 8bc05757..ad241c26 100644 --- a/lists/lists.go +++ b/lists/lists.go @@ -23,6 +23,7 @@ import ( "github.com/emirpasic/gods/utils" ) +// List interface that all lists implement type List interface { Get(index int) (interface{}, bool) Remove(index int) diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 7cd5efcb..aef92e22 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -44,6 +44,7 @@ func assertInterfaceImplementation() { var _ containers.IteratorWithIndex = (*Iterator)(nil) } +// List holds the elements, where each element points to the next element type List struct { first *element last *element @@ -55,12 +56,12 @@ type element struct { next *element } -// Instantiates a new empty list +// New instantiates a new empty list func New() *List { return &List{} } -// Appends a value (one or more) at the end of the list (same as Append()) +// Add appends a value (one or more) at the end of the list (same as Append()) func (list *List) Add(values ...interface{}) { for _, value := range values { newElement := &element{value: value} @@ -75,12 +76,12 @@ func (list *List) Add(values ...interface{}) { } } -// Appends a value (one or more) at the end of the list (same as Add()) +// Append appends a value (one or more) at the end of the list (same as Add()) func (list *List) Append(values ...interface{}) { list.Add(values...) } -// Prepends a values (or more) +// Prepend prepends a values (or more) func (list *List) Prepend(values ...interface{}) { // in reverse to keep passed order i.e. ["c","d"] -> Prepend(["a","b"]) -> ["a","b","c",d"] for v := len(values) - 1; v >= 0; v-- { @@ -93,7 +94,7 @@ func (list *List) Prepend(values ...interface{}) { } } -// Returns the element at index. +// Get returns the element at index. // Second return parameter is true if index is within bounds of the array and array is not empty, otherwise false. func (list *List) Get(index int) (interface{}, bool) { @@ -108,7 +109,7 @@ func (list *List) Get(index int) (interface{}, bool) { return element.value, true } -// Removes one or more elements from the list with the supplied indices. +// Remove removes one or more elements from the list with the supplied indices. func (list *List) Remove(index int) { if !list.withinRange(index) { @@ -141,7 +142,7 @@ func (list *List) Remove(index int) { list.size-- } -// Check if values (one or more) are present in the set. +// Contains checks if values (one or more) are present in the set. // All values have to be present in the set for the method to return true. // Performance time complexity of n^2. // Returns true if no arguments are passed at all, i.e. set is always super-set of empty set. @@ -168,7 +169,7 @@ func (list *List) Contains(values ...interface{}) bool { return true } -// Returns all elements in the list. +// Values returns all elements in the list. func (list *List) Values() []interface{} { values := make([]interface{}, list.size, list.size) for e, element := 0, list.first; element != nil; e, element = e+1, element.next { @@ -177,24 +178,24 @@ func (list *List) Values() []interface{} { return values } -// Returns true if list does not contain any elements. +// Empty returns true if list does not contain any elements. func (list *List) Empty() bool { return list.size == 0 } -// Returns number of elements within the list. +// Size returns number of elements within the list. func (list *List) Size() int { return list.size } -// Removes all elements from the list. +// Clear removes all elements from the list. func (list *List) Clear() { list.size = 0 list.first = nil list.last = nil } -// Sorts values (in-place) using timsort. +// Sort sort values (in-place) using timsort. func (list *List) Sort(comparator utils.Comparator) { if list.size < 2 { @@ -210,7 +211,7 @@ func (list *List) Sort(comparator utils.Comparator) { } -// Swaps values of two elements at the given indices. +// Swap swaps values of two elements at the given indices. func (list *List) Swap(i, j int) { if list.withinRange(i) && list.withinRange(j) && i != j { var element1, element2 *element @@ -226,7 +227,7 @@ func (list *List) Swap(i, j int) { } } -// Inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right. +// Insert inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right. // Does not do anything if position is negative or bigger than list's size // Note: position equal to list's size is valid, i.e. append. func (list *List) Insert(index int, values ...interface{}) { @@ -270,22 +271,23 @@ func (list *List) Insert(index int, values ...interface{}) { } } +// Iterator holding the iterator's state type Iterator struct { list *List index int element *element } -// Returns a stateful iterator whose values can be fetched by an index. +// Iterator returns a stateful iterator whose values can be fetched by an index. func (list *List) Iterator() Iterator { return Iterator{list: list, index: -1, element: nil} } -// Moves the iterator to the next element and returns true if there was a next element in the container. +// 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(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index += 1 + iterator.index++ if !iterator.list.withinRange(iterator.index) { iterator.element = nil return false @@ -298,19 +300,19 @@ func (iterator *Iterator) Next() bool { return true } -// Returns the current element's value. +// Value returns the current element's value. // Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { return iterator.element.value } -// Returns the current element's index. +// Index returns the current element's index. // Does not modify the state of the iterator. func (iterator *Iterator) Index() int { return iterator.index } -// Calls the given function once for each element, passing that element's index and value. +// Each calls the given function once for each element, passing that element's index and value. func (list *List) Each(f func(index int, value interface{})) { iterator := list.Iterator() for iterator.Next() { @@ -318,7 +320,7 @@ func (list *List) Each(f func(index int, value interface{})) { } } -// Invokes the given function once for each element and returns a +// Map invokes the given function once for each element and returns a // container containing the values returned by the given function. func (list *List) Map(f func(index int, value interface{}) interface{}) *List { newList := &List{} @@ -329,7 +331,7 @@ func (list *List) Map(f func(index int, value interface{}) interface{}) *List { return newList } -// Returns a new container containing all elements for which the given function returns a true value. +// Select returns a new container containing all elements for which the given function returns a true value. func (list *List) Select(f func(index int, value interface{}) bool) *List { newList := &List{} iterator := list.Iterator() @@ -341,7 +343,7 @@ func (list *List) Select(f func(index int, value interface{}) bool) *List { return newList } -// Passes each element of the container to the given function and +// Any passes each element of the container to the given function and // returns true if the function ever returns true for any element. func (list *List) Any(f func(index int, value interface{}) bool) bool { iterator := list.Iterator() @@ -353,7 +355,7 @@ func (list *List) Any(f func(index int, value interface{}) bool) bool { return false } -// Passes each element of the container to the given function and +// All passes each element of the container to the given function and // returns true if the function returns true for all elements. func (list *List) All(f func(index int, value interface{}) bool) bool { iterator := list.Iterator() @@ -365,7 +367,7 @@ func (list *List) All(f func(index int, value interface{}) bool) bool { return true } -// Passes each element of the container to the given function and returns +// 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 (list *List) Find(f func(index int, value interface{}) bool) (index int, value interface{}) { @@ -378,6 +380,7 @@ func (list *List) Find(f func(index int, value interface{}) bool) (index int, va return -1, nil } +// String returns a string representation of container func (list *List) String() string { str := "SinglyLinkedList\n" values := []string{} diff --git a/maps/hashmap/hashmap.go b/maps/hashmap/hashmap.go index ee7141c6..6ce31458 100644 --- a/maps/hashmap/hashmap.go +++ b/maps/hashmap/hashmap.go @@ -40,69 +40,71 @@ func assertInterfaceImplementation() { var _ maps.Map = (*Map)(nil) } +// Map holds the elements in go's native map type Map struct { m map[interface{}]interface{} } -// Instantiates a hash map. +// New instantiates a hash map. func New() *Map { return &Map{m: make(map[interface{}]interface{})} } -// Inserts element into the map. +// Put inserts element into the map. func (m *Map) Put(key interface{}, value interface{}) { m.m[key] = value } -// Searches the elemnt in the map by key and returns its value or nil if key is not found in map. +// Get searches the elemnt in the map by key and returns its value or nil if key is not found in map. // Second return parameter is true if key was found, otherwise false. func (m *Map) Get(key interface{}) (value interface{}, found bool) { value, found = m.m[key] return } -// Remove the element from the map by key. +// Remove removes the element from the map by key. func (m *Map) Remove(key interface{}) { delete(m.m, key) } -// Returns true if map does not contain any elements +// Empty returns true if map does not contain any elements func (m *Map) Empty() bool { return m.Size() == 0 } -// Returns number of elements in the map. +// Size returns number of elements in the map. func (m *Map) Size() int { return len(m.m) } -// Returns all keys (random order). +// Keys returns all keys (random order). func (m *Map) Keys() []interface{} { keys := make([]interface{}, m.Size()) count := 0 for key := range m.m { keys[count] = key - count += 1 + count++ } return keys } -// Returns all values (random order). +// Values returns all values (random order). func (m *Map) Values() []interface{} { values := make([]interface{}, m.Size()) count := 0 for _, value := range m.m { values[count] = value - count += 1 + count++ } return values } -// Removes all elements from the map. +// Clear removes all elements from the map. func (m *Map) Clear() { m.m = make(map[interface{}]interface{}) } +// String returns a string representation of container func (m *Map) String() string { str := "HashMap\n" str += fmt.Sprintf("%v", m.m) diff --git a/maps/maps.go b/maps/maps.go index 22fcf73b..2e82434e 100644 --- a/maps/maps.go +++ b/maps/maps.go @@ -28,6 +28,7 @@ package maps import "github.com/emirpasic/gods/containers" +// Map interface that all maps implement type Map interface { Put(key interface{}, value interface{}) Get(key interface{}) (value interface{}, found bool) diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index b18f293a..4b8558da 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -44,70 +44,71 @@ func assertInterfaceImplementation() { var _ containers.IteratorWithKey = (*Iterator)(nil) } +// Map holds the elements in a red-black tree type Map struct { tree *rbt.Tree } -// Instantiates a tree map with the custom comparator. +// NewWith instantiates a tree map with the custom comparator. func NewWith(comparator utils.Comparator) *Map { return &Map{tree: rbt.NewWith(comparator)} } -// Instantiates a tree map with the IntComparator, i.e. keys are of type int. +// NewWithIntComparator instantiates a tree map with the IntComparator, i.e. keys are of type int. func NewWithIntComparator() *Map { return &Map{tree: rbt.NewWithIntComparator()} } -// Instantiates a tree map with the StringComparator, i.e. keys are of type string. +// NewWithStringComparator instantiates a tree map with the StringComparator, i.e. keys are of type string. func NewWithStringComparator() *Map { return &Map{tree: rbt.NewWithStringComparator()} } -// Inserts key-value pair into the map. +// Put inserts key-value pair into the map. // Key should adhere to the comparator's type assertion, otherwise method panics. func (m *Map) Put(key interface{}, value interface{}) { m.tree.Put(key, value) } -// Searches the element in the map by key and returns its value or nil if key is not found in tree. +// Get searches the element in the map by key and returns its value or nil if key is not found in tree. // Second return parameter is true if key was found, otherwise false. // Key should adhere to the comparator's type assertion, otherwise method panics. func (m *Map) Get(key interface{}) (value interface{}, found bool) { return m.tree.Get(key) } -// Remove the element from the map by key. +// Remove removes the element from the map by key. // Key should adhere to the comparator's type assertion, otherwise method panics. func (m *Map) Remove(key interface{}) { m.tree.Remove(key) } -// Returns true if map does not contain any elements +// Empty returns true if map does not contain any elements func (m *Map) Empty() bool { return m.tree.Empty() } -// Returns number of elements in the map. +// Size returns number of elements in the map. func (m *Map) Size() int { return m.tree.Size() } -// Returns all keys in-order +// Keys returns all keys in-order func (m *Map) Keys() []interface{} { return m.tree.Keys() } -// Returns all values in-order based on the key. +// Values returns all values in-order based on the key. func (m *Map) Values() []interface{} { return m.tree.Values() } -// Removes all elements from the map. +// Clear removes all elements from the map. func (m *Map) Clear() { m.tree.Clear() } -// Returns the minimum key and its value from the tree map. +// Min returns the minimum key and its value from the tree map. // Returns nil, nil if map is empty. func (m *Map) Min() (key interface{}, value interface{}) { if node := m.tree.Left(); node != nil { @@ -116,7 +117,7 @@ func (m *Map) Min() (key interface{}, value interface{}) { return nil, nil } -// Returns the maximum key and its value from the tree map. +// Max returns the maximum key and its value from the tree map. // Returns nil, nil if map is empty. func (m *Map) Max() (key interface{}, value interface{}) { if node := m.tree.Right(); node != nil { @@ -125,35 +126,36 @@ func (m *Map) Max() (key interface{}, value interface{}) { return nil, nil } +// Iterator holding the iterator's state type Iterator struct { iterator rbt.Iterator } -// Returns a stateful iterator whose elements are key/value pairs. +// Iterator returns a stateful iterator whose elements are key/value pairs. func (m *Map) Iterator() Iterator { return Iterator{iterator: m.tree.Iterator()} } -// Moves the iterator to the next element and returns true if there was a next element in the container. +// 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(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { return iterator.iterator.Next() } -// Returns the current element's value. +// Value returns the current element's value. // Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { return iterator.iterator.Value() } -// Returns the current element's key. +// Key returns the current element's key. // Does not modify the state of the iterator. func (iterator *Iterator) Key() interface{} { return iterator.iterator.Key() } -// Calls the given function once for each element, passing that element's key and value. +// Each calls the given function once for each element, passing that element's key and value. func (m *Map) Each(f func(key interface{}, value interface{})) { iterator := m.Iterator() for iterator.Next() { @@ -161,7 +163,7 @@ func (m *Map) Each(f func(key interface{}, value interface{})) { } } -// Invokes the given function once for each element and returns a container +// 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. func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) *Map { newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)} @@ -173,7 +175,7 @@ func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, int return newMap } -// Returns a new container containing all elements for which the given function returns a true value. +// Select returns a new container containing all elements for which the given function returns a true value. func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map { newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)} iterator := m.Iterator() @@ -185,7 +187,7 @@ func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map { return newMap } -// Passes each element of the container to the given function and +// Any passes each element of the container to the given function and // returns true if the function ever returns true for any element. func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool { iterator := m.Iterator() @@ -197,7 +199,7 @@ func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool { return false } -// Passes each element of the container to the given function and +// All passes each element of the container to the given function and // returns true if the function returns true for all elements. func (m *Map) All(f func(key interface{}, value interface{}) bool) bool { iterator := m.Iterator() @@ -209,7 +211,7 @@ func (m *Map) All(f func(key interface{}, value interface{}) bool) bool { return true } -// Passes each element of the container to the given function and returns +// 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. func (m *Map) Find(f func(key interface{}, value interface{}) bool) (interface{}, interface{}) { @@ -222,6 +224,7 @@ func (m *Map) Find(f func(key interface{}, value interface{}) bool) (interface{} return nil, nil } +// String returns a string representation of container func (m *Map) String() string { str := "TreeMap\n" str += m.tree.String() diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 9c3775e1..c0814314 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -166,7 +166,7 @@ func TestMapEach(t *testing.T) { m.Put("b", 2) count := 0 m.Each(func(key interface{}, value interface{}) { - count += 1 + count++ if actualValue, expectedValue := count, value; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } diff --git a/sets/hashset/hashset.go b/sets/hashset/hashset.go index c5f808c7..41b78c7b 100644 --- a/sets/hashset/hashset.go +++ b/sets/hashset/hashset.go @@ -40,32 +40,33 @@ func assertInterfaceImplementation() { var _ sets.Set = (*Set)(nil) } +// Set holds elements in go's native map type Set struct { items map[interface{}]struct{} } var itemExists = struct{}{} -// Instantiates a new empty set +// New instantiates a new empty set func New() *Set { return &Set{items: make(map[interface{}]struct{})} } -// Adds the items (one or more) to the set. +// Add adds the items (one or more) to the set. func (set *Set) Add(items ...interface{}) { for _, item := range items { set.items[item] = itemExists } } -// Removes the items (one or more) from the set. +// Remove removes the items (one or more) from the set. func (set *Set) Remove(items ...interface{}) { for _, item := range items { delete(set.items, item) } } -// Check if items (one or more) are present in the set. +// 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 { @@ -77,32 +78,33 @@ func (set *Set) Contains(items ...interface{}) bool { return true } -// Returns true if set does not contain any elements. +// Empty returns true if set does not contain any elements. func (set *Set) Empty() bool { return set.Size() == 0 } -// Returns number of elements within the set. +// Size returns number of elements within the set. func (set *Set) Size() int { return len(set.items) } -// Clears all values in the set. +// Clear clears all values in the set. func (set *Set) Clear() { set.items = make(map[interface{}]struct{}) } -// Returns all items in the set. +// Values returns all items in the set. func (set *Set) Values() []interface{} { values := make([]interface{}, set.Size()) count := 0 for item := range set.items { values[count] = item - count += 1 + count++ } return values } +// String returns a string representation of container func (set *Set) String() string { str := "HashSet\n" items := []string{} diff --git a/sets/sets.go b/sets/sets.go index 6ced9039..fd4fc084 100644 --- a/sets/sets.go +++ b/sets/sets.go @@ -20,6 +20,7 @@ package sets import "github.com/emirpasic/gods/containers" +// Set interface that all sets implement type Set interface { Add(elements ...interface{}) Remove(elements ...interface{}) diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 750e264e..7b091387 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -37,42 +37,43 @@ func assertInterfaceImplementation() { var _ containers.IteratorWithIndex = (*Iterator)(nil) } +// Set holds elements in a red-black tree type Set struct { tree *rbt.Tree } var itemExists = struct{}{} -// Instantiates a new empty set with the custom comparator. +// NewWith instantiates a new empty set with the custom comparator. func NewWith(comparator utils.Comparator) *Set { return &Set{tree: rbt.NewWith(comparator)} } -// Instantiates a new empty set with the IntComparator, i.e. keys are of type int. +// NewWithIntComparator instantiates a new empty set with the IntComparator, i.e. keys are of type int. func NewWithIntComparator() *Set { return &Set{tree: rbt.NewWithIntComparator()} } -// Instantiates a new empty set with the StringComparator, i.e. keys are of type string. +// NewWithStringComparator instantiates a new empty set with the StringComparator, i.e. keys are of type string. func NewWithStringComparator() *Set { return &Set{tree: rbt.NewWithStringComparator()} } -// Adds the items (one or more) to the set. +// Add adds the items (one or more) to the set. func (set *Set) Add(items ...interface{}) { for _, item := range items { set.tree.Put(item, itemExists) } } -// Removes the items (one or more) from the set. +// Remove removes the items (one or more) from the set. func (set *Set) Remove(items ...interface{}) { for _, item := range items { set.tree.Remove(item) } } -// Check weather items (one or more) are present in the set. +// Contains checks weather 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 { @@ -84,57 +85,58 @@ func (set *Set) Contains(items ...interface{}) bool { return true } -// Returns true if set does not contain any elements. +// Empty returns true if set does not contain any elements. func (set *Set) Empty() bool { return set.tree.Size() == 0 } -// Returns number of elements within the set. +// Size returns number of elements within the set. func (set *Set) Size() int { return set.tree.Size() } -// Clears all values in the set. +// Clear clears all values in the set. func (set *Set) Clear() { set.tree.Clear() } -// Returns all items in the set. +// Values returns all items in the set. func (set *Set) Values() []interface{} { return set.tree.Keys() } +// Iterator returns a stateful iterator whose values can be fetched by an index. type Iterator struct { index int iterator rbt.Iterator } -// Returns a stateful iterator whose values can be fetched by an index. +// Iterator holding the iterator's state func (set *Set) Iterator() Iterator { return Iterator{index: -1, iterator: set.tree.Iterator()} } -// Moves the iterator to the next element and returns true if there was a next element in the container. +// 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(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index += 1 + iterator.index++ return iterator.iterator.Next() } -// Returns the current element's value. +// Value returns the current element's value. // Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { return iterator.iterator.Key() } -// Returns the current element's index. +// Index returns the current element's index. // Does not modify the state of the iterator. func (iterator *Iterator) Index() int { return iterator.index } -// Calls the given function once for each element, passing that element's index and value. +// 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() { @@ -142,7 +144,7 @@ func (set *Set) Each(f func(index int, value interface{})) { } } -// Invokes the given function once for each element and returns a +// 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 := &Set{tree: rbt.NewWith(set.tree.Comparator)} @@ -153,7 +155,7 @@ func (set *Set) Map(f func(index int, value interface{}) interface{}) *Set { return newSet } -// Returns a new container containing all elements for which the given function returns a true value. +// 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 := &Set{tree: rbt.NewWith(set.tree.Comparator)} iterator := set.Iterator() @@ -165,7 +167,7 @@ func (set *Set) Select(f func(index int, value interface{}) bool) *Set { return newSet } -// Passes each element of the container to the given function and +// 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() @@ -177,7 +179,7 @@ func (set *Set) Any(f func(index int, value interface{}) bool) bool { return false } -// Passes each element of the container to the given function and +// 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() @@ -189,7 +191,7 @@ func (set *Set) All(f func(index int, value interface{}) bool) bool { return true } -// Passes each element of the container to the given function and returns +// 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{}) { @@ -202,6 +204,7 @@ func (set *Set) Find(f func(index int, value interface{}) bool) (int, interface{ return -1, nil } +// String returns a string representation of container func (set *Set) String() string { str := "TreeSet\n" items := []string{} diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index 466797f5..1e69adc9 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -43,21 +43,22 @@ func assertInterfaceImplementation() { var _ containers.IteratorWithIndex = (*Iterator)(nil) } +// Stack holds elements in an array-list type Stack struct { list *arraylist.List } -// Instantiates a new empty stack +// New instantiates a new empty stack func New() *Stack { return &Stack{list: arraylist.New()} } -// Pushes a value onto the top of the stack +// Push adds a value onto the top of the stack func (stack *Stack) Push(value interface{}) { stack.list.Add(value) } -// Pops (removes) top element on stack and returns it, or nil if stack is empty. +// Pop removes top element on stack and returns it, or nil if stack is empty. // Second return parameter is true, unless the stack was empty and there was nothing to pop. func (stack *Stack) Pop() (value interface{}, ok bool) { value, ok = stack.list.Get(stack.list.Size() - 1) @@ -65,28 +66,28 @@ func (stack *Stack) Pop() (value interface{}, ok bool) { return } -// Returns top element on the stack without removing it, or nil if stack is empty. +// Peek returns top element on the stack without removing it, or nil if stack is empty. // Second return parameter is true, unless the stack was empty and there was nothing to peek. func (stack *Stack) Peek() (value interface{}, ok bool) { return stack.list.Get(stack.list.Size() - 1) } -// Returns true if stack does not contain any elements. +// Empty returns true if stack does not contain any elements. func (stack *Stack) Empty() bool { return stack.list.Empty() } -// Returns number of elements within the stack. +// Size returns number of elements within the stack. func (stack *Stack) Size() int { return stack.list.Size() } -// Removes all elements from the stack. +// Clear removes all elements from the stack. func (stack *Stack) Clear() { stack.list.Clear() } -// Returns all elements in the stack (LIFO order). +// Values returns all elements in the stack (LIFO order). func (stack *Stack) Values() []interface{} { size := stack.list.Size() elements := make([]interface{}, size, size) @@ -96,37 +97,39 @@ func (stack *Stack) Values() []interface{} { return elements } +// Iterator returns a stateful iterator whose values can be fetched by an index. type Iterator struct { stack *Stack index int } -// Returns a stateful iterator whose values can be fetched by an index. +// Iterator returns a stateful iterator whose values can be fetched by an index. func (stack *Stack) Iterator() Iterator { return Iterator{stack: stack, index: -1} } -// Moves the iterator to the next element and returns true if there was a next element in the container. +// 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(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index += 1 + iterator.index++ return iterator.stack.withinRange(iterator.index) } -// Returns the current element's value. +// Value returns the current element's value. // Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { value, _ := iterator.stack.list.Get(iterator.stack.list.Size() - iterator.index - 1) // in reverse (LIFO) return value } -// Returns the current element's index. +// Index returns the current element's index. // Does not modify the state of the iterator. func (iterator *Iterator) Index() int { return iterator.index } +// String returns a string representation of container func (stack *Stack) String() string { str := "ArrayStack\n" values := []string{} diff --git a/stacks/linkedliststack/linkedliststack.go b/stacks/linkedliststack/linkedliststack.go index 71df93c0..843e159d 100644 --- a/stacks/linkedliststack/linkedliststack.go +++ b/stacks/linkedliststack/linkedliststack.go @@ -44,21 +44,22 @@ func assertInterfaceImplementation() { var _ containers.IteratorWithIndex = (*Iterator)(nil) } +// Stack holds elements in a singly-linked-list type Stack struct { list *singlylinkedlist.List } -// Instantiates a new empty stack +// New nnstantiates a new empty stack func New() *Stack { return &Stack{list: &singlylinkedlist.List{}} } -// Pushes a value onto the top of the stack +// Push adds a value onto the top of the stack func (stack *Stack) Push(value interface{}) { stack.list.Prepend(value) } -// Pops (removes) top element on stack and returns it, or nil if stack is empty. +// Pop removes top element on stack and returns it, or nil if stack is empty. // Second return parameter is true, unless the stack was empty and there was nothing to pop. func (stack *Stack) Pop() (value interface{}, ok bool) { value, ok = stack.list.Get(0) @@ -66,63 +67,65 @@ func (stack *Stack) Pop() (value interface{}, ok bool) { return } -// Returns top element on the stack without removing it, or nil if stack is empty. +// Peek returns top element on the stack without removing it, or nil if stack is empty. // Second return parameter is true, unless the stack was empty and there was nothing to peek. func (stack *Stack) Peek() (value interface{}, ok bool) { return stack.list.Get(0) } -// Returns true if stack does not contain any elements. +// Empty returns true if stack does not contain any elements. func (stack *Stack) Empty() bool { return stack.list.Empty() } -// Returns number of elements within the stack. +// Size returns number of elements within the stack. func (stack *Stack) Size() int { return stack.list.Size() } -// Removes all elements from the stack. +// Clear removes all elements from the stack. func (stack *Stack) Clear() { stack.list.Clear() } -// Returns all elements in the stack (LIFO order). +// Values returns all elements in the stack (LIFO order). func (stack *Stack) Values() []interface{} { return stack.list.Values() } +// Iterator returns a stateful iterator whose values can be fetched by an index. type Iterator struct { stack *Stack index int } -// Returns a stateful iterator whose values can be fetched by an index. +// Iterator returns a stateful iterator whose values can be fetched by an index. func (stack *Stack) Iterator() Iterator { return Iterator{stack: stack, index: -1} } -// Moves the iterator to the next element and returns true if there was a next element in the container. +// 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(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index += 1 + iterator.index++ return iterator.stack.withinRange(iterator.index) } -// Returns the current element's value. +// Value returns the current element's value. // Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { value, _ := iterator.stack.list.Get(iterator.index) // in reverse (LIFO) return value } -// Returns the current element's index. +// Index returns the current element's index. // Does not modify the state of the iterator. func (iterator *Iterator) Index() int { return iterator.index } +// String returns a string representation of container func (stack *Stack) String() string { str := "LinkedListStack\n" values := []string{} diff --git a/stacks/stacks.go b/stacks/stacks.go index 1f504be6..ceaf6f17 100644 --- a/stacks/stacks.go +++ b/stacks/stacks.go @@ -28,6 +28,7 @@ package stacks import "github.com/emirpasic/gods/containers" +// Stack interface that all stacks implement type Stack interface { Push(value interface{}) Pop() (value interface{}, ok bool) diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index 3f1c759f..8a97d5a0 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -45,33 +45,34 @@ func assertInterfaceImplementation() { var _ containers.IteratorWithIndex = (*Iterator)(nil) } +// Heap holds elements in an array-list type Heap struct { list *arraylist.List Comparator utils.Comparator } -// Instantiates a new empty heap tree with the custom comparator. +// NewWith instantiates a new empty heap tree with the custom comparator. func NewWith(comparator utils.Comparator) *Heap { return &Heap{list: arraylist.New(), Comparator: comparator} } -// Instantiates a new empty heap with the IntComparator, i.e. elements are of type int. +// NewWithIntComparator instantiates a new empty heap with the IntComparator, i.e. elements are of type int. func NewWithIntComparator() *Heap { return &Heap{list: arraylist.New(), Comparator: utils.IntComparator} } -// Instantiates a new empty heap with the StringComparator, i.e. elements are of type string. +// NewWithStringComparator instantiates a new empty heap with the StringComparator, i.e. elements are of type string. func NewWithStringComparator() *Heap { return &Heap{list: arraylist.New(), Comparator: utils.StringComparator} } -// Pushes a value onto the heap and bubbles it up accordingly. +// Push adds a value onto the heap and bubbles it up accordingly. func (heap *Heap) Push(value interface{}) { heap.list.Add(value) heap.bubbleUp() } -// Pops (removes) top element on heap and returns it, or nil if heap is empty. +// Pop removes top element on heap and returns it, or nil if heap is empty. // Second return parameter is true, unless the heap was empty and there was nothing to pop. func (heap *Heap) Pop() (value interface{}, ok bool) { value, ok = heap.list.Get(0) @@ -85,63 +86,65 @@ func (heap *Heap) Pop() (value interface{}, ok bool) { return } -// Returns top element on the heap without removing it, or nil if heap is empty. +// Peek returns top element on the heap without removing it, or nil if heap is empty. // Second return parameter is true, unless the heap was empty and there was nothing to peek. func (heap *Heap) Peek() (value interface{}, ok bool) { return heap.list.Get(0) } -// Returns true if heap does not contain any elements. +// Empty returns true if heap does not contain any elements. func (heap *Heap) Empty() bool { return heap.list.Empty() } -// Returns number of elements within the heap. +// Size returns number of elements within the heap. func (heap *Heap) Size() int { return heap.list.Size() } -// Removes all elements from the heap. +// Clear removes all elements from the heap. func (heap *Heap) Clear() { heap.list.Clear() } -// Returns all elements in the heap. +// Values returns all elements in the heap. func (heap *Heap) Values() []interface{} { return heap.list.Values() } +// Iterator returns a stateful iterator whose values can be fetched by an index. type Iterator struct { heap *Heap index int } -// Returns a stateful iterator whose values can be fetched by an index. +// Iterator returns a stateful iterator whose values can be fetched by an index. func (heap *Heap) Iterator() Iterator { return Iterator{heap: heap, index: -1} } -// Moves the iterator to the next element and returns true if there was a next element in the container. +// 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(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index += 1 + iterator.index++ return iterator.heap.withinRange(iterator.index) } -// Returns the current element's value. +// Value returns the current element's value. // Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { value, _ := iterator.heap.list.Get(iterator.index) return value } -// Returns the current element's index. +// Index returns the current element's index. // Does not modify the state of the iterator. func (iterator *Iterator) Index() int { return iterator.index } +// String returns a string representation of container func (heap *Heap) String() string { str := "BinaryHeap\n" values := []string{} diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index c6a033e3..abcdffd3 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -50,12 +50,14 @@ const ( black, red color = true, false ) +// Tree holds elements of the red-black tree type Tree struct { Root *Node size int Comparator utils.Comparator } +// Node is a single element within the tree type Node struct { Key interface{} Value interface{} @@ -65,22 +67,22 @@ type Node struct { Parent *Node } -// Instantiates a red-black tree with the custom comparator. +// NewWith instantiates a red-black tree with the custom comparator. func NewWith(comparator utils.Comparator) *Tree { return &Tree{Comparator: comparator} } -// Instantiates a red-black tree with the IntComparator, i.e. keys are of type int. +// NewWithIntComparator instantiates a red-black tree with the IntComparator, i.e. keys are of type int. func NewWithIntComparator() *Tree { return &Tree{Comparator: utils.IntComparator} } -// Instantiates a red-black tree with the StringComparator, i.e. keys are of type string. +// NewWithStringComparator instantiates a red-black tree with the StringComparator, i.e. keys are of type string. func NewWithStringComparator() *Tree { return &Tree{Comparator: utils.StringComparator} } -// Inserts node into the tree. +// Put inserts node into the tree. // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree) Put(key interface{}, value interface{}) { insertedNode := &Node{Key: key, Value: value, color: red} @@ -114,10 +116,10 @@ func (tree *Tree) Put(key interface{}, value interface{}) { insertedNode.Parent = node } tree.insertCase1(insertedNode) - tree.size += 1 + tree.size++ } -// Searches the node in the tree by key and returns its value or nil if key is not found in tree. +// Get searches the node in the tree by key and returns its value or nil if key is not found in tree. // Second return parameter is true if key was found, otherwise false. // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree) Get(key interface{}) (value interface{}, found bool) { @@ -128,7 +130,7 @@ func (tree *Tree) Get(key interface{}) (value interface{}, found bool) { return nil, false } -// Remove the node from the tree by key. +// Remove remove the node from the tree by key. // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree) Remove(key interface{}) { var child *Node @@ -157,20 +159,20 @@ func (tree *Tree) Remove(key interface{}) { child.color = black } } - tree.size -= 1 + tree.size-- } -// Returns true if tree does not contain any nodes +// Empty returns true if tree does not contain any nodes func (tree *Tree) Empty() bool { return tree.size == 0 } -// Returns number of nodes in the tree. +// Size returns number of nodes in the tree. func (tree *Tree) Size() int { return tree.size } -// Returns all keys in-order +// Keys returns all keys in-order func (tree *Tree) Keys() []interface{} { keys := make([]interface{}, tree.size) for i, node := range tree.inOrder() { @@ -179,7 +181,7 @@ func (tree *Tree) Keys() []interface{} { return keys } -// Returns all values in-order based on the key. +// Values returns all values in-order based on the key. func (tree *Tree) Values() []interface{} { values := make([]interface{}, tree.size) for i, node := range tree.inOrder() { @@ -188,7 +190,7 @@ func (tree *Tree) Values() []interface{} { return values } -// Returns the left-most (min) node or nil if tree is empty. +// Left returns the left-most (min) node or nil if tree is empty. func (tree *Tree) Left() *Node { var parent *Node current := tree.Root @@ -199,7 +201,7 @@ func (tree *Tree) Left() *Node { return parent } -// Returns the right-most (max) node or nil if tree is empty. +// Right returns the right-most (max) node or nil if tree is empty. func (tree *Tree) Right() *Node { var parent *Node current := tree.Root @@ -210,7 +212,7 @@ func (tree *Tree) Right() *Node { return parent } -// Find floor node of the input key, return the floor node or nil if no ceiling is found. +// Floor Finds floor node of the input key, return the floor node or nil if no ceiling is found. // Second return parameter is true if floor was found, otherwise false. // // Floor node is defined as the largest node that is smaller than or equal to the given node. @@ -239,7 +241,7 @@ func (tree *Tree) Floor(key interface{}) (floor *Node, found bool) { return nil, false } -// Find ceiling node of the input key, return the ceiling node or nil if no ceiling is found. +// Ceiling finds ceiling node of the input key, return the ceiling node or nil if no ceiling is found. // Second return parameter is true if ceiling was found, otherwise false. // // Ceiling node is defined as the smallest node that is larger than or equal to the given node. @@ -268,23 +270,24 @@ func (tree *Tree) Ceiling(key interface{}) (ceiling *Node, found bool) { return nil, false } -// Removes all nodes from the tree. +// Clear removes all nodes from the tree. func (tree *Tree) Clear() { tree.Root = nil tree.size = 0 } +// Iterator holding the iterator's state type Iterator struct { tree *Tree left *Node } -// Returns a stateful iterator whose elements are key/value pairs. +// Iterator returns a stateful iterator whose elements are key/value pairs. func (tree *Tree) Iterator() Iterator { return Iterator{tree: tree, left: nil} } -// Moves the iterator to the next element and returns true if there was a next element in the container. +// 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(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { @@ -311,18 +314,19 @@ func (iterator *Iterator) Next() bool { return false } -// Returns the current element's value. +// Value returns the current element's value. // Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { return iterator.left.Value } -// Returns the current element's key. +// Key returns the current element's key. // Does not modify the state of the iterator. func (iterator *Iterator) Key() interface{} { return iterator.left.Key } +// String returns a string representation of container func (tree *Tree) String() string { str := "RedBlackTree\n" if !tree.Empty() { @@ -352,7 +356,7 @@ func (tree *Tree) inOrder() []*Node { currentPop, _ := stack.Pop() current = currentPop.(*Node) nodes[count] = current - count += 1 + count++ current = current.Right } else { done = true @@ -363,6 +367,7 @@ func (tree *Tree) inOrder() []*Node { return nodes } +// String returns a string representation of container func output(node *Node, prefix string, isTail bool, str *string) { if node.Right != nil { newPrefix := prefix @@ -427,9 +432,8 @@ func (node *Node) sibling() *Node { } if node == node.Parent.Left { return node.Parent.Right - } else { - return node.Parent.Left } + return node.Parent.Left } func (tree *Tree) rotateLeft(node *Node) { @@ -532,9 +536,8 @@ func (node *Node) maximumNode() *Node { func (tree *Tree) deleteCase1(node *Node) { if node.Parent == nil { return - } else { - tree.deleteCase2(node) } + tree.deleteCase2(node) } func (tree *Tree) deleteCase2(node *Node) { diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 480afa77..96fa4e1d 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -220,7 +220,7 @@ func TestRedBlackTreeIterator1(t *testing.T) { it := tree.Iterator() count := 0 for it.Next() { - count += 1 + count++ index := it.Key() switch index { case count: @@ -246,7 +246,7 @@ func TestRedBlackTreeIterator2(t *testing.T) { it := tree.Iterator() count := 0 for it.Next() { - count += 1 + count++ index := it.Key() switch index { case count: @@ -277,7 +277,7 @@ func TestRedBlackTreeIterator3(t *testing.T) { it = tree.Iterator() count := 0 for it.Next() { - count += 1 + count++ index := it.Key() switch index { case count: @@ -311,7 +311,7 @@ func TestRedBlackTreeIterator4(t *testing.T) { it := tree.Iterator() count := 0 for it.Next() { - count += 1 + count++ value := it.Value() switch value { case count: diff --git a/trees/trees.go b/trees/trees.go index 0a021dd8..055c3083 100644 --- a/trees/trees.go +++ b/trees/trees.go @@ -28,6 +28,7 @@ package trees import "github.com/emirpasic/gods/containers" +// Tree interface that all trees implement type Tree interface { containers.Container // Empty() bool diff --git a/utils/comparator.go b/utils/comparator.go index 0960dabf..6ce68292 100644 --- a/utils/comparator.go +++ b/utils/comparator.go @@ -35,6 +35,7 @@ package utils // 1, if a > b type Comparator func(a, b interface{}) int +// IntComparator provides a basic comparison on ints func IntComparator(a, b interface{}) int { aInt := a.(int) bInt := b.(int) @@ -48,6 +49,7 @@ func IntComparator(a, b interface{}) int { } } +// StringComparator provides a fast comparison on strings func StringComparator(a, b interface{}) int { s1 := a.(string) s2 := b.(string) diff --git a/utils/sort.go b/utils/sort.go index 176a62fe..04b5721f 100644 --- a/utils/sort.go +++ b/utils/sort.go @@ -30,7 +30,7 @@ package utils import "github.com/emirpasic/gods/utils/timsort" -// Sorts values (in-place) using timsort +// Sort sorts values (in-place) using timsort func Sort(values []interface{}, comparator Comparator) { less := func(a, b interface{}) bool { return comparator(a, b) < 0 } timsort.Sort(values, less) diff --git a/utils/timsort/timsort.go b/utils/timsort/timsort.go index 861c3795..64049016 100644 --- a/utils/timsort/timsort.go +++ b/utils/timsort/timsort.go @@ -64,7 +64,7 @@ const ( * of the minimum stack length required as a function of the length * of the array being sorted and the minimum merge sequence length. */ - _MIN_MERGE = 32 + minMerge = 32 // mk: tried higher MIN_MERGE and got slower sorting (348->375) // c_MIN_MERGE = 64 @@ -72,7 +72,7 @@ const ( * When we get into galloping mode, we stay there until both runs win less * often than c_MIN_GALLOP consecutive times. */ - _MIN_GALLOP = 7 + minGallop = 7 /** * Maximum initial size of tmp array, which is used for merging. The array @@ -81,10 +81,10 @@ const ( * Unlike Tim's original C version, we do not allocate this much storage * when sorting smaller arrays. This change was required for performance. */ - _INITIAL_TMP_STORAGE_LENGTH = 256 + initialTmpStorageLength = 256 ) -// Delegate type that sorting uses as a comparator +// LessThan delegate type for sorting uses as a comparator type LessThan func(a, b interface{}) bool type timSortHandler struct { @@ -132,23 +132,23 @@ type timSortHandler struct { * @param a the array to be sorted * @param c the comparator to determine the order of the sort */ -func newTimSort(a []interface{}, lt LessThan) (self *timSortHandler) { - self = new(timSortHandler) +func newTimSort(a []interface{}, lt LessThan) (tsh *timSortHandler) { + tsh = new(timSortHandler) - self.a = a - self.lt = lt - self.minGallop = _MIN_GALLOP - self.stackSize = 0 + tsh.a = a + tsh.lt = lt + tsh.minGallop = minGallop + tsh.stackSize = 0 // Allocate temp storage (which may be increased later if necessary) len := len(a) - tmpSize := _INITIAL_TMP_STORAGE_LENGTH + tmpSize := initialTmpStorageLength if len < 2*tmpSize { tmpSize = len / 2 } - self.tmp = make([]interface{}, tmpSize) + tsh.tmp = make([]interface{}, tmpSize) /* * Allocate runs-to-be-merged stack (which cannot be expanded). The @@ -171,13 +171,13 @@ func newTimSort(a []interface{}, lt LessThan) (self *timSortHandler) { stackLen = 19 } - self.runBase = make([]int, stackLen) - self.runLen = make([]int, stackLen) + tsh.runBase = make([]int, stackLen) + tsh.runLen = make([]int, stackLen) - return self + return tsh } -// Sorts an array using the provided comparator +// Sort sorts an array using the provided comparator func Sort(a []interface{}, lt LessThan) (err error) { lo := 0 hi := len(a) @@ -188,7 +188,7 @@ func Sort(a []interface{}, lt LessThan) (err error) { } // If array is small, do a "mini-TimSort" with no merges - if nRemaining < _MIN_MERGE { + if nRemaining < minMerge { initRunLen, err := countRunAndMakeAscending(a, lo, hi, lt) if err != nil { return err @@ -243,7 +243,7 @@ func Sort(a []interface{}, lt LessThan) (err error) { // Merge all remaining runs to complete sort if lo != hi { - return errors.New("lo==hi!") + return errors.New("lo==hi") } if err = ts.mergeForceCollapse(); err != nil { @@ -426,7 +426,7 @@ func minRunLength(n int) (int, error) { return 0, errors.New("n >= 0") } r := 0 // Becomes 1 if any 1 bits are shifted off - for n >= _MIN_MERGE { + for n >= minMerge { r |= (n & 1) n >>= 1 } @@ -439,10 +439,10 @@ func minRunLength(n int) (int, error) { * @param runBase index of the first element in the run * @param runLen the number of elements in the run */ -func (self *timSortHandler) pushRun(runBase, runLen int) { - self.runBase[self.stackSize] = runBase - self.runLen[self.stackSize] = runLen - self.stackSize++ +func (tsh *timSortHandler) pushRun(runBase, runLen int) { + tsh.runBase[tsh.stackSize] = runBase + tsh.runLen[tsh.stackSize] = runLen + tsh.stackSize++ } /** @@ -456,18 +456,18 @@ func (self *timSortHandler) pushRun(runBase, runLen int) { * so the invariants are guaranteed to hold for i < stackSize upon * entry to the method. */ -func (self *timSortHandler) mergeCollapse() (err error) { - for self.stackSize > 1 { - n := self.stackSize - 2 - if n > 0 && self.runLen[n-1] <= self.runLen[n]+self.runLen[n+1] { - if self.runLen[n-1] < self.runLen[n+1] { +func (tsh *timSortHandler) mergeCollapse() (err error) { + for tsh.stackSize > 1 { + n := tsh.stackSize - 2 + if n > 0 && tsh.runLen[n-1] <= tsh.runLen[n]+tsh.runLen[n+1] { + if tsh.runLen[n-1] < tsh.runLen[n+1] { n-- } - if err = self.mergeAt(n); err != nil { + if err = tsh.mergeAt(n); err != nil { return } - } else if self.runLen[n] <= self.runLen[n+1] { - if err = self.mergeAt(n); err != nil { + } else if tsh.runLen[n] <= tsh.runLen[n+1] { + if err = tsh.mergeAt(n); err != nil { return } } else { @@ -481,13 +481,13 @@ func (self *timSortHandler) mergeCollapse() (err error) { * Merges all runs on the stack until only one remains. This method is * called once, to complete the sort. */ -func (self *timSortHandler) mergeForceCollapse() (err error) { - for self.stackSize > 1 { - n := self.stackSize - 2 - if n > 0 && self.runLen[n-1] < self.runLen[n+1] { +func (tsh *timSortHandler) mergeForceCollapse() (err error) { + for tsh.stackSize > 1 { + n := tsh.stackSize - 2 + if n > 0 && tsh.runLen[n-1] < tsh.runLen[n+1] { n-- } - if err = self.mergeAt(n); err != nil { + if err = tsh.mergeAt(n); err != nil { return } } @@ -501,8 +501,8 @@ func (self *timSortHandler) mergeForceCollapse() (err error) { * * @param i stack index of the first of the two runs to merge */ -func (self *timSortHandler) mergeAt(i int) (err error) { - if self.stackSize < 2 { +func (tsh *timSortHandler) mergeAt(i int) (err error) { + if tsh.stackSize < 2 { return errors.New("stackSize >= 2") } @@ -510,14 +510,14 @@ func (self *timSortHandler) mergeAt(i int) (err error) { return errors.New(" i >= 0") } - if i != self.stackSize-2 && i != self.stackSize-3 { + if i != tsh.stackSize-2 && i != tsh.stackSize-3 { return errors.New("if i == stackSize - 2 || i == stackSize - 3") } - base1 := self.runBase[i] - len1 := self.runLen[i] - base2 := self.runBase[i+1] - len2 := self.runLen[i+1] + base1 := tsh.runBase[i] + len1 := tsh.runLen[i] + base2 := tsh.runBase[i+1] + len2 := tsh.runLen[i+1] if len1 <= 0 || len2 <= 0 { return errors.New("len1 > 0 && len2 > 0") @@ -532,18 +532,18 @@ func (self *timSortHandler) mergeAt(i int) (err error) { * run now, also slide over the last run (which isn't involved * in this merge). The current run (i+1) goes away in any case. */ - self.runLen[i] = len1 + len2 - if i == self.stackSize-3 { - self.runBase[i+1] = self.runBase[i+2] - self.runLen[i+1] = self.runLen[i+2] + tsh.runLen[i] = len1 + len2 + if i == tsh.stackSize-3 { + tsh.runBase[i+1] = tsh.runBase[i+2] + tsh.runLen[i+1] = tsh.runLen[i+2] } - self.stackSize-- + tsh.stackSize-- /* * Find where the first element of run2 goes in run1. Prior elements * in run1 can be ignored (because they're already in place). */ - k, err := gallopRight(self.a[base2], self.a, base1, len1, 0, self.lt) + k, err := gallopRight(tsh.a[base2], tsh.a, base1, len1, 0, tsh.lt) if err != nil { return err } @@ -560,7 +560,7 @@ func (self *timSortHandler) mergeAt(i int) (err error) { * Find where the last element of run1 goes in run2. Subsequent elements * in run2 can be ignored (because they're already in place). */ - len2, err = gallopLeft(self.a[base1+len1-1], self.a, base2, len2, len2-1, self.lt) + len2, err = gallopLeft(tsh.a[base1+len1-1], tsh.a, base2, len2, len2-1, tsh.lt) if err != nil { return } @@ -573,14 +573,14 @@ func (self *timSortHandler) mergeAt(i int) (err error) { // Merge remaining runs, using tmp array with min(len1, len2) elements if len1 <= len2 { - err = self.mergeLo(base1, len1, base2, len2) + err = tsh.mergeLo(base1, len1, base2, len2) if err != nil { - return errors.New(fmt.Sprintf("mergeLo: %v", err)) + return errors.New(fmt.Errorf("mergeLo: %v", err).Error()) } } else { - err = self.mergeHi(base1, len1, base2, len2) + err = tsh.mergeHi(base1, len1, base2, len2) if err != nil { - return errors.New(fmt.Sprintf("mergeHi: %v", err)) + return errors.New(fmt.Errorf("mergeHi: %v", err).Error()) } } return @@ -771,14 +771,14 @@ func gallopRight(key interface{}, a []interface{}, base, len, hint int, c LessTh * (must be aBase + aLen) * @param len2 length of second run to be merged (must be > 0) */ -func (self *timSortHandler) mergeLo(base1, len1, base2, len2 int) (err error) { +func (tsh *timSortHandler) mergeLo(base1, len1, base2, len2 int) (err error) { if len1 <= 0 || len2 <= 0 || base1+len1 != base2 { return errors.New(" len1 > 0 && len2 > 0 && base1 + len1 == base2") } // Copy first run into temp array - a := self.a // For performance - tmp := self.ensureCapacity(len1) + a := tsh.a // For performance + tmp := tsh.ensureCapacity(len1) copy(tmp, a[base1:base1+len1]) @@ -801,8 +801,8 @@ func (self *timSortHandler) mergeLo(base1, len1, base2, len2 int) (err error) { return } - lt := self.lt // Use local variable for performance - minGallop := self.minGallop // " " " " " + lt := tsh.lt // Use local variable for performance + minGallop := tsh.minGallop // " " " " " outer: for { @@ -895,7 +895,7 @@ outer: break outer } minGallop-- - if count1 < _MIN_GALLOP && count2 < _MIN_GALLOP { + if count1 < minGallop && count2 < minGallop { break } } @@ -908,7 +908,7 @@ outer: if minGallop < 1 { minGallop = 1 } - self.minGallop = minGallop // Write back to field + tsh.minGallop = minGallop // Write back to field if len1 == 1 { @@ -943,14 +943,14 @@ outer: * (must be aBase + aLen) * @param len2 length of second run to be merged (must be > 0) */ -func (self *timSortHandler) mergeHi(base1, len1, base2, len2 int) (err error) { +func (tsh *timSortHandler) mergeHi(base1, len1, base2, len2 int) (err error) { if len1 <= 0 || len2 <= 0 || base1+len1 != base2 { return errors.New("len1 > 0 && len2 > 0 && base1 + len1 == base2;") } // Copy second run into temp array - a := self.a // For performance - tmp := self.ensureCapacity(len2) + a := tsh.a // For performance + tmp := tsh.ensureCapacity(len2) copy(tmp, a[base2:base2+len2]) @@ -976,8 +976,8 @@ func (self *timSortHandler) mergeHi(base1, len1, base2, len2 int) (err error) { return } - lt := self.lt // Use local variable for performance - minGallop := self.minGallop // " " " " " + lt := tsh.lt // Use local variable for performance + minGallop := tsh.minGallop // " " " " " outer: for { @@ -1072,7 +1072,7 @@ outer: } minGallop-- - if count1 < _MIN_GALLOP && count2 < _MIN_GALLOP { + if count1 < minGallop && count2 < minGallop { break } } @@ -1086,7 +1086,7 @@ outer: minGallop = 1 } - self.minGallop = minGallop // Write back to field + tsh.minGallop = minGallop // Write back to field if len2 == 1 { if len1 <= 0 { @@ -1121,8 +1121,8 @@ outer: * @param minCapacity the minimum required capacity of the tmp array * @return tmp, whether or not it grew */ -func (self *timSortHandler) ensureCapacity(minCapacity int) []interface{} { - if len(self.tmp) < minCapacity { +func (tsh *timSortHandler) ensureCapacity(minCapacity int) []interface{} { + if len(tsh.tmp) < minCapacity { // Compute smallest power of 2 > minCapacity newSize := minCapacity newSize |= newSize >> 1 @@ -1135,14 +1135,14 @@ func (self *timSortHandler) ensureCapacity(minCapacity int) []interface{} { if newSize < 0 { // Not bloody likely! newSize = minCapacity } else { - ns := len(self.a) / 2 + ns := len(tsh.a) / 2 if ns < newSize { newSize = ns } } - self.tmp = make([]interface{}, newSize) + tsh.tmp = make([]interface{}, newSize) } - return self.tmp + return tsh.tmp } From faeea55fc955707c1c20ff787a4056ed1fcea8fd Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 24 Jun 2016 21:58:18 +0200 Subject: [PATCH 058/320] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c9838f7d..31248e11 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![GoDoc](https://godoc.org/github.com/emirpasic/gods?status.svg)](https://godoc.org/github.com/emirpasic/gods) [![Build Status](https://travis-ci.org/emirpasic/gods.svg)](https://travis-ci.org/emirpasic/gods) [![Go Report Card](https://goreportcard.com/badge/emirpasic/gods)](https://goreportcard.com/report/emirpasic/gods) [![PyPI](https://img.shields.io/pypi/l/Django.svg?maxAge=2592000)](https://github.com/emirpasic/gods/blob/master/LICENSE) +[![GoDoc](https://godoc.org/github.com/emirpasic/gods?status.svg)](https://godoc.org/github.com/emirpasic/gods) [![Build Status](https://travis-ci.org/emirpasic/gods.svg)](https://travis-ci.org/emirpasic/gods) [![Go Report Card](https://goreportcard.com/badge/github.com/emirpasic/gods)](https://goreportcard.com/report/github.com/emirpasic/gods) [![PyPI](https://img.shields.io/pypi/l/Django.svg?maxAge=2592000)](https://github.com/emirpasic/gods/blob/master/LICENSE) # GoDS (Go Data Structures) From 7b3992bef3cf41d0093c6458d2bc811817594064 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 25 Jun 2016 05:35:13 +0200 Subject: [PATCH 059/320] - replace timsort with go's sort --- README.md | 13 +- utils/sort.go | 23 +- utils/sort_test.go | 24 + utils/timsort/LICENSE | 19 - utils/timsort/timsort.go | 1148 -------------------------------------- 5 files changed, 54 insertions(+), 1173 deletions(-) delete mode 100644 utils/timsort/LICENSE delete mode 100644 utils/timsort/timsort.go diff --git a/README.md b/README.md index 31248e11..e5297f5e 100644 --- a/README.md +++ b/README.md @@ -995,8 +995,17 @@ Biggest contribution towards this library is to use it and give us feedback for For direct contributions, _pull request_ into master or ask to become a contributor. +Coding style: + +```shell +# Install tooling: +go build github.com/golang/lint/golint +go build github.com/fzipp/gocyclo + +# Fix errors and warnings: +go fmt ./... && gofmt -s -w . && go vet ./... && go get ./... && go test ./... && golint ./... && gocyclo -avg -over 15 . +``` + ### License This library is distributed under the BSD-style license found in the [LICENSE](https://github.com/emirpasic/gods/blob/master/LICENSE) file. - -TimSort copied from [https://github.com/psilva261/timsort](https://github.com/psilva261/timsort) with MIT [LICENSE](https://github.com/emirpasic/gods/blob/master/utils/timsort/LICENSE) file. diff --git a/utils/sort.go b/utils/sort.go index 04b5721f..3cf8c1fa 100644 --- a/utils/sort.go +++ b/utils/sort.go @@ -28,10 +28,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package utils -import "github.com/emirpasic/gods/utils/timsort" +import "sort" -// Sort sorts values (in-place) using timsort +// Sort sorts values (in-place) +// Uses Go's sort (hybrid of quicksort for large and then insertion sort for smaller slices) func Sort(values []interface{}, comparator Comparator) { - less := func(a, b interface{}) bool { return comparator(a, b) < 0 } - timsort.Sort(values, less) + sort.Sort(sortable{values, comparator}) +} + +type sortable struct { + values []interface{} + comparator Comparator +} + +func (s sortable) Len() int { + return len(s.values) +} +func (s sortable) Swap(i, j int) { + s.values[i], s.values[j] = s.values[j], s.values[i] +} +func (s sortable) Less(i, j int) bool { + return s.comparator(s.values[i], s.values[j]) < 0 } diff --git a/utils/sort_test.go b/utils/sort_test.go index d1e523bf..f6d546f6 100644 --- a/utils/sort_test.go +++ b/utils/sort_test.go @@ -27,6 +27,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package utils import ( + "math/rand" "testing" ) @@ -98,5 +99,28 @@ func TestSortStructs(t *testing.T) { t.Errorf("Not sorted!") } } +} + +func TestSortRandom(t *testing.T) { + ints := []interface{}{} + for i := 0; i < 10000; i++ { + ints = append(ints, rand.Int()) + } + Sort(ints, IntComparator) + for i := 1; i < len(ints); i++ { + if ints[i-1].(int) > ints[i].(int) { + t.Errorf("Not sorted!") + } + } +} +func BenchmarkGoSortRandom(b *testing.B) { + b.StopTimer() + ints := []interface{}{} + for i := 0; i < 100000; i++ { + ints = append(ints, rand.Int()) + } + b.StartTimer() + Sort(ints, IntComparator) + b.StopTimer() } diff --git a/utils/timsort/LICENSE b/utils/timsort/LICENSE deleted file mode 100644 index 208ba422..00000000 --- a/utils/timsort/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2010-2011 Mike Kroutikov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/utils/timsort/timsort.go b/utils/timsort/timsort.go deleted file mode 100644 index 64049016..00000000 --- a/utils/timsort/timsort.go +++ /dev/null @@ -1,1148 +0,0 @@ -// Obtained from: https://github.com/psilva261/timsort - -/* -Copyright (c) 2010-2011 Mike Kroutikov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE -*/ - -// Fast stable sort, uses external comparator. -// -// A stable, adaptive, iterative mergesort that requires far fewer than -// n lg(n) comparisons when running on partially sorted arrays, while -// offering performance comparable to a traditional mergesort when run -// on random arrays. Like all proper mergesorts, this sort is stable and -// runs O(n log n) time (worst case). In the worst case, this sort requires -// temporary storage space for n/2 object references; in the best case, -// it requires only a small constant amount of space. -// -// This implementation was derived from Java's TimSort object by Josh Bloch, -// which, in turn, was based on the original code by Tim Peters: -// -// http://svn.python.org/projects/python/trunk/Objects/listsort.txt -// -// Mike K. - -package timsort - -import ( - "errors" - "fmt" -) - -const ( - /** - * This is the minimum sized sequence that will be merged. Shorter - * sequences will be lengthened by calling binarySort. If the entire - * array is less than this length, no merges will be performed. - * - * This constant should be a power of two. It was 64 in Tim Peter's C - * implementation, but 32 was empirically determined to work better in - * this implementation. In the unlikely event that you set this constant - * to be a number that's not a power of two, you'll need to change the - * {@link #minRunLength} computation. - * - * If you decrease this constant, you must change the stackLen - * computation in the TimSort constructor, or you risk an - * ArrayOutOfBounds exception. See listsort.txt for a discussion - * of the minimum stack length required as a function of the length - * of the array being sorted and the minimum merge sequence length. - */ - minMerge = 32 - // mk: tried higher MIN_MERGE and got slower sorting (348->375) - // c_MIN_MERGE = 64 - - /** - * When we get into galloping mode, we stay there until both runs win less - * often than c_MIN_GALLOP consecutive times. - */ - minGallop = 7 - - /** - * Maximum initial size of tmp array, which is used for merging. The array - * can grow to accommodate demand. - * - * Unlike Tim's original C version, we do not allocate this much storage - * when sorting smaller arrays. This change was required for performance. - */ - initialTmpStorageLength = 256 -) - -// LessThan delegate type for sorting uses as a comparator -type LessThan func(a, b interface{}) bool - -type timSortHandler struct { - - /** - * The array being sorted. - */ - a []interface{} - - /** - * The comparator for this sort. - */ - lt LessThan - - /** - * This controls when we get *into* galloping mode. It is initialized - * to c_MIN_GALLOP. The mergeLo and mergeHi methods nudge it higher for - * random data, and lower for highly structured data. - */ - minGallop int - - /** - * Temp storage for merges. - */ - tmp []interface{} // Actual runtime type will be Object[], regardless of T - - /** - * A stack of pending runs yet to be merged. Run i starts at - * address base[i] and extends for len[i] elements. It's always - * true (so long as the indices are in bounds) that: - * - * runBase[i] + runLen[i] == runBase[i + 1] - * - * so we could cut the storage for this, but it's a minor amount, - * and keeping all the info explicit simplifies the code. - */ - stackSize int // Number of pending runs on stack - runBase []int - runLen []int -} - -/** - * Creates a TimSort instance to maintain the state of an ongoing sort. - * - * @param a the array to be sorted - * @param c the comparator to determine the order of the sort - */ -func newTimSort(a []interface{}, lt LessThan) (tsh *timSortHandler) { - tsh = new(timSortHandler) - - tsh.a = a - tsh.lt = lt - tsh.minGallop = minGallop - tsh.stackSize = 0 - - // Allocate temp storage (which may be increased later if necessary) - len := len(a) - - tmpSize := initialTmpStorageLength - if len < 2*tmpSize { - tmpSize = len / 2 - } - - tsh.tmp = make([]interface{}, tmpSize) - - /* - * Allocate runs-to-be-merged stack (which cannot be expanded). The - * stack length requirements are described in listsort.txt. The C - * version always uses the same stack length (85), but this was - * measured to be too expensive when sorting "mid-sized" arrays (e.g., - * 100 elements) in Java. Therefore, we use smaller (but sufficiently - * large) stack lengths for smaller arrays. The "magic numbers" in the - * computation below must be changed if c_MIN_MERGE is decreased. See - * the c_MIN_MERGE declaration above for more information. - */ - // mk: confirmed that for small sorts this optimization gives measurable (albeit small) - // performance enhancement - stackLen := 40 - if len < 120 { - stackLen = 5 - } else if len < 1542 { - stackLen = 10 - } else if len < 119151 { - stackLen = 19 - } - - tsh.runBase = make([]int, stackLen) - tsh.runLen = make([]int, stackLen) - - return tsh -} - -// Sort sorts an array using the provided comparator -func Sort(a []interface{}, lt LessThan) (err error) { - lo := 0 - hi := len(a) - nRemaining := hi - - if nRemaining < 2 { - return // Arrays of size 0 and 1 are always sorted - } - - // If array is small, do a "mini-TimSort" with no merges - if nRemaining < minMerge { - initRunLen, err := countRunAndMakeAscending(a, lo, hi, lt) - if err != nil { - return err - } - - return binarySort(a, lo, hi, lo+initRunLen, lt) - } - - /** - * March over the array once, left to right, finding natural runs, - * extending short natural runs to minRun elements, and merging runs - * to maintain stack invariant. - */ - - ts := newTimSort(a, lt) - minRun, err := minRunLength(nRemaining) - if err != nil { - return - } - for { - // Identify next run - runLen, err := countRunAndMakeAscending(a, lo, hi, lt) - if err != nil { - return err - } - - // If run is short, extend to min(minRun, nRemaining) - if runLen < minRun { - force := minRun - if nRemaining <= minRun { - force = nRemaining - } - if err = binarySort(a, lo, lo+force, lo+runLen, lt); err != nil { - return err - } - runLen = force - } - - // Push run onto pending-run stack, and maybe merge - ts.pushRun(lo, runLen) - if err = ts.mergeCollapse(); err != nil { - return err - } - - // Advance to find next run - lo += runLen - nRemaining -= runLen - if nRemaining == 0 { - break - } - } - - // Merge all remaining runs to complete sort - if lo != hi { - return errors.New("lo==hi") - } - - if err = ts.mergeForceCollapse(); err != nil { - return - } - if ts.stackSize != 1 { - return errors.New("ts.stackSize != 1") - } - return -} - -/** - * Sorts the specified portion of the specified array using a binary - * insertion sort. This is the best method for sorting small numbers - * of elements. It requires O(n log n) compares, but O(n^2) data - * movement (worst case). - * - * If the initial part of the specified range is already sorted, - * this method can take advantage of it: the method assumes that the - * elements from index {@code lo}, inclusive, to {@code start}, - * exclusive are already sorted. - * - * @param a the array in which a range is to be sorted - * @param lo the index of the first element in the range to be sorted - * @param hi the index after the last element in the range to be sorted - * @param start the index of the first element in the range that is - * not already known to be sorted (@code lo <= start <= hi} - * @param c comparator to used for the sort - */ -func binarySort(a []interface{}, lo, hi, start int, lt LessThan) (err error) { - if lo > start || start > hi { - return errors.New("lo <= start && start <= hi") - } - - if start == lo { - start++ - } - - for ; start < hi; start++ { - pivot := a[start] - - // Set left (and right) to the index where a[start] (pivot) belongs - left := lo - right := start - - if left > right { - return errors.New("left <= right") - } - - /* - * Invariants: - * pivot >= all in [lo, left). - * pivot < all in [right, start). - */ - for left < right { - mid := (left + right) / 2 - if lt(pivot, a[mid]) { - right = mid - } else { - left = mid + 1 - } - } - - if left != right { - return errors.New("left == right") - } - - /* - * The invariants still hold: pivot >= all in [lo, left) and - * pivot < all in [left, start), so pivot belongs at left. Note - * that if there are elements equal to pivot, left points to the - * first slot after them -- that's why this sort is stable. - * Slide elements over to make room to make room for pivot. - */ - n := start - left // The number of elements to move - // just an optimization for copy in default case - if n <= 2 { - if n == 2 { - a[left+2] = a[left+1] - } - if n > 0 { - a[left+1] = a[left] - } - } else { - copy(a[left+1:], a[left:left+n]) - } - a[left] = pivot - } - return -} - -/** - * Returns the length of the run beginning at the specified position in - * the specified array and reverses the run if it is descending (ensuring - * that the run will always be ascending when the method returns). - * - * A run is the longest ascending sequence with: - * - * a[lo] <= a[lo + 1] <= a[lo + 2] <= ... - * - * or the longest descending sequence with: - * - * a[lo] > a[lo + 1] > a[lo + 2] > ... - * - * For its intended use in a stable mergesort, the strictness of the - * definition of "descending" is needed so that the call can safely - * reverse a descending sequence without violating stability. - * - * @param a the array in which a run is to be counted and possibly reversed - * @param lo index of the first element in the run - * @param hi index after the last element that may be contained in the run. - It is required that @code{lo < hi}. - * @param c the comparator to used for the sort - * @return the length of the run beginning at the specified position in - * the specified array -*/ -func countRunAndMakeAscending(a []interface{}, lo, hi int, lt LessThan) (int, error) { - - if lo >= hi { - return 0, errors.New("lo < hi") - } - - runHi := lo + 1 - if runHi == hi { - return 1, nil - } - - // Find end of run, and reverse range if descending - if lt(a[runHi], a[lo]) { // Descending - runHi++ - - for runHi < hi && lt(a[runHi], a[runHi-1]) { - runHi++ - } - reverseRange(a, lo, runHi) - } else { // Ascending - for runHi < hi && !lt(a[runHi], a[runHi-1]) { - runHi++ - } - } - - return runHi - lo, nil -} - -/** - * Reverse the specified range of the specified array. - * - * @param a the array in which a range is to be reversed - * @param lo the index of the first element in the range to be reversed - * @param hi the index after the last element in the range to be reversed - */ -func reverseRange(a []interface{}, lo, hi int) { - hi-- - for lo < hi { - a[lo], a[hi] = a[hi], a[lo] - lo++ - hi-- - } -} - -/** - * Returns the minimum acceptable run length for an array of the specified - * length. Natural runs shorter than this will be extended with - * {@link #binarySort}. - * - * Roughly speaking, the computation is: - * - * If n < c_MIN_MERGE, return n (it's too small to bother with fancy stuff). - * Else if n is an exact power of 2, return c_MIN_MERGE/2. - * Else return an int k, c_MIN_MERGE/2 <= k <= c_MIN_MERGE, such that n/k - * is close to, but strictly less than, an exact power of 2. - * - * For the rationale, see listsort.txt. - * - * @param n the length of the array to be sorted - * @return the length of the minimum run to be merged - */ -func minRunLength(n int) (int, error) { - if n < 0 { - return 0, errors.New("n >= 0") - } - r := 0 // Becomes 1 if any 1 bits are shifted off - for n >= minMerge { - r |= (n & 1) - n >>= 1 - } - return n + r, nil -} - -/** - * Pushes the specified run onto the pending-run stack. - * - * @param runBase index of the first element in the run - * @param runLen the number of elements in the run - */ -func (tsh *timSortHandler) pushRun(runBase, runLen int) { - tsh.runBase[tsh.stackSize] = runBase - tsh.runLen[tsh.stackSize] = runLen - tsh.stackSize++ -} - -/** - * Examines the stack of runs waiting to be merged and merges adjacent runs - * until the stack invariants are reestablished: - * - * 1. runLen[i - 3] > runLen[i - 2] + runLen[i - 1] - * 2. runLen[i - 2] > runLen[i - 1] - * - * This method is called each time a new run is pushed onto the stack, - * so the invariants are guaranteed to hold for i < stackSize upon - * entry to the method. - */ -func (tsh *timSortHandler) mergeCollapse() (err error) { - for tsh.stackSize > 1 { - n := tsh.stackSize - 2 - if n > 0 && tsh.runLen[n-1] <= tsh.runLen[n]+tsh.runLen[n+1] { - if tsh.runLen[n-1] < tsh.runLen[n+1] { - n-- - } - if err = tsh.mergeAt(n); err != nil { - return - } - } else if tsh.runLen[n] <= tsh.runLen[n+1] { - if err = tsh.mergeAt(n); err != nil { - return - } - } else { - break // Invariant is established - } - } - return -} - -/** - * Merges all runs on the stack until only one remains. This method is - * called once, to complete the sort. - */ -func (tsh *timSortHandler) mergeForceCollapse() (err error) { - for tsh.stackSize > 1 { - n := tsh.stackSize - 2 - if n > 0 && tsh.runLen[n-1] < tsh.runLen[n+1] { - n-- - } - if err = tsh.mergeAt(n); err != nil { - return - } - } - return -} - -/** - * Merges the two runs at stack indices i and i+1. Run i must be - * the penultimate or antepenultimate run on the stack. In other words, - * i must be equal to stackSize-2 or stackSize-3. - * - * @param i stack index of the first of the two runs to merge - */ -func (tsh *timSortHandler) mergeAt(i int) (err error) { - if tsh.stackSize < 2 { - return errors.New("stackSize >= 2") - } - - if i < 0 { - return errors.New(" i >= 0") - } - - if i != tsh.stackSize-2 && i != tsh.stackSize-3 { - return errors.New("if i == stackSize - 2 || i == stackSize - 3") - } - - base1 := tsh.runBase[i] - len1 := tsh.runLen[i] - base2 := tsh.runBase[i+1] - len2 := tsh.runLen[i+1] - - if len1 <= 0 || len2 <= 0 { - return errors.New("len1 > 0 && len2 > 0") - } - - if base1+len1 != base2 { - return errors.New("base1 + len1 == base2") - } - - /* - * Record the length of the combined runs; if i is the 3rd-last - * run now, also slide over the last run (which isn't involved - * in this merge). The current run (i+1) goes away in any case. - */ - tsh.runLen[i] = len1 + len2 - if i == tsh.stackSize-3 { - tsh.runBase[i+1] = tsh.runBase[i+2] - tsh.runLen[i+1] = tsh.runLen[i+2] - } - tsh.stackSize-- - - /* - * Find where the first element of run2 goes in run1. Prior elements - * in run1 can be ignored (because they're already in place). - */ - k, err := gallopRight(tsh.a[base2], tsh.a, base1, len1, 0, tsh.lt) - if err != nil { - return err - } - if k < 0 { - return errors.New(" k >= 0;") - } - base1 += k - len1 -= k - if len1 == 0 { - return - } - - /* - * Find where the last element of run1 goes in run2. Subsequent elements - * in run2 can be ignored (because they're already in place). - */ - len2, err = gallopLeft(tsh.a[base1+len1-1], tsh.a, base2, len2, len2-1, tsh.lt) - if err != nil { - return - } - if len2 < 0 { - return errors.New(" len2 >= 0;") - } - if len2 == 0 { - return - } - - // Merge remaining runs, using tmp array with min(len1, len2) elements - if len1 <= len2 { - err = tsh.mergeLo(base1, len1, base2, len2) - if err != nil { - return errors.New(fmt.Errorf("mergeLo: %v", err).Error()) - } - } else { - err = tsh.mergeHi(base1, len1, base2, len2) - if err != nil { - return errors.New(fmt.Errorf("mergeHi: %v", err).Error()) - } - } - return -} - -/** - * Locates the position at which to insert the specified key into the - * specified sorted range; if the range contains an element equal to key, - * returns the index of the leftmost equal element. - * - * @param key the key whose insertion point to search for - * @param a the array in which to search - * @param base the index of the first element in the range - * @param len the length of the range; must be > 0 - * @param hint the index at which to begin the search, 0 <= hint < n. - * The closer hint is to the result, the faster this method will run. - * @param c the comparator used to order the range, and to search - * @return the int k, 0 <= k <= n such that a[b + k - 1] < key <= a[b + k], - * pretending that a[b - 1] is minus infinity and a[b + n] is infinity. - * In other words, key belongs at index b + k; or in other words, - * the first k elements of a should precede key, and the last n - k - * should follow it. - */ -func gallopLeft(key interface{}, a []interface{}, base, len, hint int, c LessThan) (int, error) { - if len <= 0 || hint < 0 || hint >= len { - return 0, errors.New(" len > 0 && hint >= 0 && hint < len;") - } - lastOfs := 0 - ofs := 1 - - if c(a[base+hint], key) { - // Gallop right until a[base+hint+lastOfs] < key <= a[base+hint+ofs] - maxOfs := len - hint - for ofs < maxOfs && c(a[base+hint+ofs], key) { - lastOfs = ofs - ofs = (ofs << 1) + 1 - if ofs <= 0 { // int overflow - ofs = maxOfs - } - } - if ofs > maxOfs { - ofs = maxOfs - } - - // Make offsets relative to base - lastOfs += hint - ofs += hint - } else { // key <= a[base + hint] - // Gallop left until a[base+hint-ofs] < key <= a[base+hint-lastOfs] - maxOfs := hint + 1 - for ofs < maxOfs && !c(a[base+hint-ofs], key) { - lastOfs = ofs - ofs = (ofs << 1) + 1 - if ofs <= 0 { // int overflow - ofs = maxOfs - } - } - if ofs > maxOfs { - ofs = maxOfs - } - - // Make offsets relative to base - tmp := lastOfs - lastOfs = hint - ofs - ofs = hint - tmp - } - - if -1 > lastOfs || lastOfs >= ofs || ofs > len { - return 0, errors.New(" -1 <= lastOfs && lastOfs < ofs && ofs <= len;") - } - - /* - * Now a[base+lastOfs] < key <= a[base+ofs], so key belongs somewhere - * to the right of lastOfs but no farther right than ofs. Do a binary - * search, with invariant a[base + lastOfs - 1] < key <= a[base + ofs]. - */ - lastOfs++ - for lastOfs < ofs { - m := lastOfs + (ofs-lastOfs)/2 - - if c(a[base+m], key) { - lastOfs = m + 1 // a[base + m] < key - } else { - ofs = m // key <= a[base + m] - } - } - - if lastOfs != ofs { - return 0, errors.New(" lastOfs == ofs") // so a[base + ofs - 1] < key <= a[base + ofs] - } - return ofs, nil -} - -/** - * Like gallopLeft, except that if the range contains an element equal to - * key, gallopRight returns the index after the rightmost equal element. - * - * @param key the key whose insertion point to search for - * @param a the array in which to search - * @param base the index of the first element in the range - * @param len the length of the range; must be > 0 - * @param hint the index at which to begin the search, 0 <= hint < n. - * The closer hint is to the result, the faster this method will run. - * @param c the comparator used to order the range, and to search - * @return the int k, 0 <= k <= n such that a[b + k - 1] <= key < a[b + k] - */ -func gallopRight(key interface{}, a []interface{}, base, len, hint int, c LessThan) (int, error) { - if len <= 0 || hint < 0 || hint >= len { - return 0, errors.New(" len > 0 && hint >= 0 && hint < len;") - } - - ofs := 1 - lastOfs := 0 - if c(key, a[base+hint]) { - // Gallop left until a[b+hint - ofs] <= key < a[b+hint - lastOfs] - maxOfs := hint + 1 - for ofs < maxOfs && c(key, a[base+hint-ofs]) { - lastOfs = ofs - ofs = (ofs << 1) + 1 - if ofs <= 0 { // int overflow - ofs = maxOfs - } - } - if ofs > maxOfs { - ofs = maxOfs - } - - // Make offsets relative to b - tmp := lastOfs - lastOfs = hint - ofs - ofs = hint - tmp - } else { // a[b + hint] <= key - // Gallop right until a[b+hint + lastOfs] <= key < a[b+hint + ofs] - maxOfs := len - hint - for ofs < maxOfs && !c(key, a[base+hint+ofs]) { - lastOfs = ofs - ofs = (ofs << 1) + 1 - if ofs <= 0 { // int overflow - ofs = maxOfs - } - } - if ofs > maxOfs { - ofs = maxOfs - } - - // Make offsets relative to b - lastOfs += hint - ofs += hint - } - if -1 > lastOfs || lastOfs >= ofs || ofs > len { - return 0, errors.New("-1 <= lastOfs && lastOfs < ofs && ofs <= len") - } - - /* - * Now a[b + lastOfs] <= key < a[b + ofs], so key belongs somewhere to - * the right of lastOfs but no farther right than ofs. Do a binary - * search, with invariant a[b + lastOfs - 1] <= key < a[b + ofs]. - */ - lastOfs++ - for lastOfs < ofs { - m := lastOfs + (ofs-lastOfs)/2 - - if c(key, a[base+m]) { - ofs = m // key < a[b + m] - } else { - lastOfs = m + 1 // a[b + m] <= key - } - } - if lastOfs != ofs { - return 0, errors.New(" lastOfs == ofs") // so a[b + ofs - 1] <= key < a[b + ofs] - } - return ofs, nil -} - -/** - * Merges two adjacent runs in place, in a stable fashion. The first - * element of the first run must be greater than the first element of the - * second run (a[base1] > a[base2]), and the last element of the first run - * (a[base1 + len1-1]) must be greater than all elements of the second run. - * - * For performance, this method should be called only when len1 <= len2; - * its twin, mergeHi should be called if len1 >= len2. (Either method - * may be called if len1 == len2.) - * - * @param base1 index of first element in first run to be merged - * @param len1 length of first run to be merged (must be > 0) - * @param base2 index of first element in second run to be merged - * (must be aBase + aLen) - * @param len2 length of second run to be merged (must be > 0) - */ -func (tsh *timSortHandler) mergeLo(base1, len1, base2, len2 int) (err error) { - if len1 <= 0 || len2 <= 0 || base1+len1 != base2 { - return errors.New(" len1 > 0 && len2 > 0 && base1 + len1 == base2") - } - - // Copy first run into temp array - a := tsh.a // For performance - tmp := tsh.ensureCapacity(len1) - - copy(tmp, a[base1:base1+len1]) - - cursor1 := 0 // Indexes into tmp array - cursor2 := base2 // Indexes int a - dest := base1 // Indexes int a - - // Move first element of second run and deal with degenerate cases - a[dest] = a[cursor2] - dest++ - cursor2++ - len2-- - if len2 == 0 { - copy(a[dest:dest+len1], tmp) - return - } - if len1 == 1 { - copy(a[dest:dest+len2], a[cursor2:cursor2+len2]) - a[dest+len2] = tmp[cursor1] // Last elt of run 1 to end of merge - return - } - - lt := tsh.lt // Use local variable for performance - minGallop := tsh.minGallop // " " " " " - -outer: - for { - count1 := 0 // Number of times in a row that first run won - count2 := 0 // Number of times in a row that second run won - - /* - * Do the straightforward thing until (if ever) one run starts - * winning consistently. - */ - for { - if len1 <= 1 || len2 <= 0 { - return errors.New(" len1 > 1 && len2 > 0") - } - - if lt(a[cursor2], tmp[cursor1]) { - a[dest] = a[cursor2] - dest++ - cursor2++ - count2++ - count1 = 0 - len2-- - if len2 == 0 { - break outer - } - } else { - a[dest] = tmp[cursor1] - dest++ - cursor1++ - count1++ - count2 = 0 - len1-- - if len1 == 1 { - break outer - } - } - if (count1 | count2) >= minGallop { - break - } - } - - /* - * One run is winning so consistently that galloping may be a - * huge win. So try that, and continue galloping until (if ever) - * neither run appears to be winning consistently anymore. - */ - for { - if len1 <= 1 || len2 <= 0 { - return errors.New("len1 > 1 && len2 > 0") - } - count1, err = gallopRight(a[cursor2], tmp, cursor1, len1, 0, lt) - if err != nil { - return - } - if count1 != 0 { - copy(a[dest:dest+count1], tmp[cursor1:cursor1+count1]) - dest += count1 - cursor1 += count1 - len1 -= count1 - if len1 <= 1 { // len1 == 1 || len1 == 0 - break outer - } - } - a[dest] = a[cursor2] - dest++ - cursor2++ - len2-- - if len2 == 0 { - break outer - } - - count2, err = gallopLeft(tmp[cursor1], a, cursor2, len2, 0, lt) - if err != nil { - return - } - if count2 != 0 { - copy(a[dest:dest+count2], a[cursor2:cursor2+count2]) - dest += count2 - cursor2 += count2 - len2 -= count2 - if len2 == 0 { - break outer - } - } - a[dest] = tmp[cursor1] - dest++ - cursor1++ - len1-- - if len1 == 1 { - break outer - } - minGallop-- - if count1 < minGallop && count2 < minGallop { - break - } - } - if minGallop < 0 { - minGallop = 0 - } - minGallop += 2 // Penalize for leaving gallop mode - } // End of "outer" loop - - if minGallop < 1 { - minGallop = 1 - } - tsh.minGallop = minGallop // Write back to field - - if len1 == 1 { - - if len2 <= 0 { - return errors.New(" len2 > 0;") - } - copy(a[dest:dest+len2], a[cursor2:cursor2+len2]) - a[dest+len2] = tmp[cursor1] // Last elt of run 1 to end of merge - } else if len1 == 0 { - return errors.New("Comparison method violates its general contract!") - } else { - if len2 != 0 { - return errors.New("len2 == 0;") - } - if len1 <= 1 { - return errors.New(" len1 > 1;") - } - - copy(a[dest:dest+len1], tmp[cursor1:cursor1+len1]) - } - return -} - -/** - * Like mergeLo, except that this method should be called only if - * len1 >= len2; mergeLo should be called if len1 <= len2. (Either method - * may be called if len1 == len2.) - * - * @param base1 index of first element in first run to be merged - * @param len1 length of first run to be merged (must be > 0) - * @param base2 index of first element in second run to be merged - * (must be aBase + aLen) - * @param len2 length of second run to be merged (must be > 0) - */ -func (tsh *timSortHandler) mergeHi(base1, len1, base2, len2 int) (err error) { - if len1 <= 0 || len2 <= 0 || base1+len1 != base2 { - return errors.New("len1 > 0 && len2 > 0 && base1 + len1 == base2;") - } - - // Copy second run into temp array - a := tsh.a // For performance - tmp := tsh.ensureCapacity(len2) - - copy(tmp, a[base2:base2+len2]) - - cursor1 := base1 + len1 - 1 // Indexes into a - cursor2 := len2 - 1 // Indexes into tmp array - dest := base2 + len2 - 1 // Indexes into a - - // Move last element of first run and deal with degenerate cases - a[dest] = a[cursor1] - dest-- - cursor1-- - len1-- - if len1 == 0 { - dest -= len2 - 1 - copy(a[dest:dest+len2], tmp) - return - } - if len2 == 1 { - dest -= len1 - 1 - cursor1 -= len1 - 1 - copy(a[dest:dest+len1], a[cursor1:cursor1+len1]) - a[dest-1] = tmp[cursor2] - return - } - - lt := tsh.lt // Use local variable for performance - minGallop := tsh.minGallop // " " " " " - -outer: - for { - count1 := 0 // Number of times in a row that first run won - count2 := 0 // Number of times in a row that second run won - - /* - * Do the straightforward thing until (if ever) one run - * appears to win consistently. - */ - for { - if len1 <= 0 || len2 <= 1 { - return errors.New(" len1 > 0 && len2 > 1;") - } - if lt(tmp[cursor2], a[cursor1]) { - a[dest] = a[cursor1] - dest-- - cursor1-- - count1++ - count2 = 0 - len1-- - if len1 == 0 { - break outer - } - } else { - a[dest] = tmp[cursor2] - dest-- - cursor2-- - count2++ - count1 = 0 - len2-- - if len2 == 1 { - break outer - } - } - if (count1 | count2) >= minGallop { - break - } - } - - /* - * One run is winning so consistently that galloping may be a - * huge win. So try that, and continue galloping until (if ever) - * neither run appears to be winning consistently anymore. - */ - for { - if len1 <= 0 || len2 <= 1 { - return errors.New(" len1 > 0 && len2 > 1;") - } - if gr, err := gallopRight(tmp[cursor2], a, base1, len1, len1-1, lt); err == nil { - count1 = len1 - gr - } else { - return err - } - if count1 != 0 { - dest -= count1 - cursor1 -= count1 - len1 -= count1 - copy(a[dest+1:dest+1+count1], a[cursor1+1:cursor1+1+count1]) - if len1 == 0 { - break outer - } - } - a[dest] = tmp[cursor2] - dest-- - cursor2-- - len2-- - if len2 == 1 { - break outer - } - - if gl, err := gallopLeft(a[cursor1], tmp, 0, len2, len2-1, lt); err == nil { - count2 = len2 - gl - } else { - return err - } - if count2 != 0 { - dest -= count2 - cursor2 -= count2 - len2 -= count2 - copy(a[dest+1:dest+1+count2], tmp[cursor2+1:cursor2+1+count2]) - if len2 <= 1 { // len2 == 1 || len2 == 0 - break outer - } - } - a[dest] = a[cursor1] - dest-- - cursor1-- - len1-- - if len1 == 0 { - break outer - } - minGallop-- - - if count1 < minGallop && count2 < minGallop { - break - } - } - if minGallop < 0 { - minGallop = 0 - } - minGallop += 2 // Penalize for leaving gallop mode - } // End of "outer" loop - - if minGallop < 1 { - minGallop = 1 - } - - tsh.minGallop = minGallop // Write back to field - - if len2 == 1 { - if len1 <= 0 { - return errors.New(" len1 > 0;") - } - dest -= len1 - cursor1 -= len1 - - copy(a[dest+1:dest+1+len1], a[cursor1+1:cursor1+1+len1]) - a[dest] = tmp[cursor2] // Move first elt of run2 to front of merge - } else if len2 == 0 { - return errors.New("Comparison method violates its general contract!") - } else { - if len1 != 0 { - return errors.New("len1 == 0;") - } - - if len2 <= 0 { - return errors.New(" len2 > 0;") - } - - copy(a[dest-(len2-1):dest+1], tmp) - } - return -} - -/** - * Ensures that the external array tmp has at least the specified - * number of elements, increasing its size if necessary. The size - * increases exponentially to ensure amortized linear time complexity. - * - * @param minCapacity the minimum required capacity of the tmp array - * @return tmp, whether or not it grew - */ -func (tsh *timSortHandler) ensureCapacity(minCapacity int) []interface{} { - if len(tsh.tmp) < minCapacity { - // Compute smallest power of 2 > minCapacity - newSize := minCapacity - newSize |= newSize >> 1 - newSize |= newSize >> 2 - newSize |= newSize >> 4 - newSize |= newSize >> 8 - newSize |= newSize >> 16 - newSize++ - - if newSize < 0 { // Not bloody likely! - newSize = minCapacity - } else { - ns := len(tsh.a) / 2 - if ns < newSize { - newSize = ns - } - } - - tsh.tmp = make([]interface{}, newSize) - } - - return tsh.tmp -} From 2ccfba5f938d22c6c06e2e0b815fe8ea522acfe5 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 25 Jun 2016 05:51:41 +0200 Subject: [PATCH 060/320] - replace timsort with go's sort --- README.md | 7 ++++--- containers/containers.go | 1 - examples/sort.go | 2 +- lists/arraylist/arraylist.go | 2 +- lists/doublylinkedlist/doublylinkedlist.go | 2 +- lists/singlylinkedlist/singlylinkedlist.go | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e5297f5e..f5a4c811 100644 --- a/README.md +++ b/README.md @@ -902,9 +902,11 @@ func main() { ### Sort -Sort uses timsort for best performance on real-world data. Lists have an in-place _Sort()_ method. All containers can return their sorted elements via _GetSortedValues()_ call. +Sort is a general purpose sort function. -Internally they use the _utils.Sort()_ method: +Lists have an in-place _Sort()_ function and all containers can return their sorted elements via _containers.GetSortedValues()_ function. + +Internally these all use the _utils.Sort()_ method: ```go package main @@ -928,7 +930,6 @@ Container specific operations: ```go // Returns sorted container''s elements with respect to the passed comparator. // Does not effect the ordering of elements within the container. -// Uses timsort. func GetSortedValues(container Container, comparator utils.Comparator) []interface{} ``` diff --git a/containers/containers.go b/containers/containers.go index 389d289a..0a26c44e 100644 --- a/containers/containers.go +++ b/containers/containers.go @@ -38,7 +38,6 @@ type Container interface { // GetSortedValues returns sorted container's elements with respect to the passed comparator. // Does not effect the ordering of elements within the container. -// Uses timsort. func GetSortedValues(container Container, comparator utils.Comparator) []interface{} { values := container.Values() if len(values) < 2 { diff --git a/examples/sort.go b/examples/sort.go index 5940886b..e2fd7136 100644 --- a/examples/sort.go +++ b/examples/sort.go @@ -28,7 +28,7 @@ package examples import "github.com/emirpasic/gods/utils" -// SortExample to demonstrate basic usage of basic sort (timsort) +// SortExample to demonstrate basic usage of basic sort func SortExample() { strings := []interface{}{} // [] strings = append(strings, "d") // ["d"] diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index 5e65f39c..f471908d 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -138,7 +138,7 @@ func (list *List) Clear() { list.elements = []interface{}{} } -// Sort sorts values (in-place) using timsort. +// Sort sorts values (in-place) using. func (list *List) Sort(comparator utils.Comparator) { if len(list.elements) < 2 { return diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 8263cc64..58a0e4bf 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -214,7 +214,7 @@ func (list *List) Clear() { list.last = nil } -// Sort sorts values (in-place) using timsort. +// Sort sorts values (in-place) using. func (list *List) Sort(comparator utils.Comparator) { if list.size < 2 { diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index aef92e22..baf028c4 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -195,7 +195,7 @@ func (list *List) Clear() { list.last = nil } -// Sort sort values (in-place) using timsort. +// Sort sort values (in-place) using. func (list *List) Sort(comparator utils.Comparator) { if list.size < 2 { From 59bebe43ce49653e95d8a40af2a58754ef33c92c Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 25 Jun 2016 17:02:21 +0200 Subject: [PATCH 061/320] - update all documentation to be in godoc style --- README.md | 8 ++++---- containers/containers.go | 9 ++++++++- containers/enumerable.go | 3 --- containers/iterator.go | 2 -- lists/arraylist/arraylist.go | 7 ++++--- lists/doublylinkedlist/doublylinkedlist.go | 7 ++++--- lists/lists.go | 5 +++++ lists/singlylinkedlist/singlylinkedlist.go | 7 ++++--- maps/hashmap/hashmap.go | 8 +++++--- maps/maps.go | 11 +++++++++++ maps/treemap/treemap.go | 8 +++++--- sets/hashset/hashset.go | 5 +++-- sets/sets.go | 5 +++++ sets/treeset/treeset.go | 7 ++++--- stacks/arraystack/arraystack.go | 7 ++++--- stacks/linkedliststack/linkedliststack.go | 8 ++++---- stacks/stacks.go | 5 +++++ trees/binaryheap/binaryheap.go | 6 ++++-- trees/redblacktree/redblacktree.go | 6 ++++-- trees/trees.go | 5 +++++ utils/comparator.go | 8 ++++---- utils/sort.go | 7 +++---- 22 files changed, 95 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index f5a4c811..4c6006b3 100644 --- a/README.md +++ b/README.md @@ -572,12 +572,12 @@ Some data structures (e.g. TreeMap, TreeSet) require a comparator function to au Comparator is defined as: -Return values: +Return values (int): ```go --1, if a < b - 0, if a == b - 1, if a > b +negative , if a < b +zero , if a == b +positive , if a > b ``` Comparator signature: diff --git a/containers/containers.go b/containers/containers.go index 0a26c44e..91ca0463 100644 --- a/containers/containers.go +++ b/containers/containers.go @@ -24,11 +24,18 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +// Package containers provides core interfaces and functions data structures. +// +// Container is the base interface for all data structures to implement. +// +// Iterators provide stateful iterators. +// +// Enumerable provides Ruby inspired (each, select, map, find, any?, etc.) container functions. package containers import "github.com/emirpasic/gods/utils" -// Container is base interface that all data structures implement +// Container is base interface that all data structures implement. type Container interface { Empty() bool Size() int diff --git a/containers/enumerable.go b/containers/enumerable.go index 0a092070..027de5a8 100644 --- a/containers/enumerable.go +++ b/containers/enumerable.go @@ -24,9 +24,6 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Enumerable functions for ordered containers. -// Ruby's enumerable inspired package. - package containers // EnumerableWithIndex provides functions for ordered containers whose values can be fetched by an index. diff --git a/containers/iterator.go b/containers/iterator.go index b3d22543..fd2d4d47 100644 --- a/containers/iterator.go +++ b/containers/iterator.go @@ -24,8 +24,6 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Stateful iterator pattern for ordered containers. - package containers // IteratorWithIndex is stateful iterator for ordered containers whose values can be fetched by an index. diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index f471908d..ad0fc092 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -24,10 +24,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of list using a slice. +// Package arraylist implements the array list. +// // Structure is not thread safe. -// References: http://en.wikipedia.org/wiki/List_%28abstract_data_type%29 - +// +// Reference: https://en.wikipedia.org/wiki/List_%28abstract_data_type%29 package arraylist import ( diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 58a0e4bf..3f976479 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -24,10 +24,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of doubly linked list. +// Package doublylinkedlist implements the doubly-linked list. +// // Structure is not thread safe. -// References: http://en.wikipedia.org/wiki/Doubly_linked_list - +// +// Reference: https://en.wikipedia.org/wiki/List_%28abstract_data_type%29 package doublylinkedlist import ( diff --git a/lists/lists.go b/lists/lists.go index ad241c26..539d14eb 100644 --- a/lists/lists.go +++ b/lists/lists.go @@ -16,6 +16,11 @@ License along with this library. See the file LICENSE included with this distribution for more information. */ +// Package lists provides abstract List interface for that all concrete lists should implement. +// +// In computer science, a list or sequence is an abstract data type that represents an ordered sequence of values, where the same value may occur more than once. An instance of a list is a computer representation of the mathematical concept of a finite sequence; the (potentially) infinite analog of a list is a stream. Lists are a basic example of containers, as they contain other values. If the same value occurs multiple times, each occurrence is considered a distinct item. +// +// Reference: https://en.wikipedia.org/wiki/List_%28abstract_data_type%29 package lists import ( diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index baf028c4..953ab8b9 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -24,10 +24,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of doubly linked list. +// Package singlylinkedlist implements the singly-linked list. +// // Structure is not thread safe. -// References: http://en.wikipedia.org/wiki/Linked_list#Singly_linked_list - +// +// Reference: https://en.wikipedia.org/wiki/List_%28abstract_data_type%29 package singlylinkedlist import ( diff --git a/maps/hashmap/hashmap.go b/maps/hashmap/hashmap.go index 6ce31458..6cb8565c 100644 --- a/maps/hashmap/hashmap.go +++ b/maps/hashmap/hashmap.go @@ -24,11 +24,13 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of unorder map backed by a hash table. +// Package hashmap implements a map backed by a hash table. +// // Elements are unordered in the map. +// // Structure is not thread safe. -// References: http://en.wikipedia.org/wiki/Associative_array - +// +// Reference: http://en.wikipedia.org/wiki/Associative_array package hashmap import ( diff --git a/maps/maps.go b/maps/maps.go index 2e82434e..809f138b 100644 --- a/maps/maps.go +++ b/maps/maps.go @@ -24,6 +24,17 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +// Package maps provides abstract Map interface for that all concrete maps should implement. +// +// In computer science, an associative array, map, symbol table, or dictionary is an abstract data type composed of a collection of (key, value) pairs, such that each possible key appears just once in the collection. +// +// Operations associated with this data type allow: +// - the addition of a pair to the collection +// - the removal of a pair from the collection +// - the modification of an existing pair +// - the lookup of a value associated with a particular key +// +// Reference: https://en.wikipedia.org/wiki/Associative_array package maps import "github.com/emirpasic/gods/containers" diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index 4b8558da..efa46e43 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -24,11 +24,13 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of order map backed by red-black tree. +// Package treemap implements a map backed by red-black tree. +// // Elements are ordered by key in the map. +// // Structure is not thread safe. -// References: http://en.wikipedia.org/wiki/Associative_array - +// +// Reference: http://en.wikipedia.org/wiki/Associative_array package treemap import ( diff --git a/sets/hashset/hashset.go b/sets/hashset/hashset.go index 41b78c7b..e3f44c71 100644 --- a/sets/hashset/hashset.go +++ b/sets/hashset/hashset.go @@ -24,10 +24,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of set backed by a hash table. +// Package hashset implements a set backed by a hash table. +// // Structure is not thread safe. +// // References: http://en.wikipedia.org/wiki/Set_%28abstract_data_type%29 - package hashset import ( diff --git a/sets/sets.go b/sets/sets.go index fd4fc084..af4aa22c 100644 --- a/sets/sets.go +++ b/sets/sets.go @@ -16,6 +16,11 @@ License along with this library. See the file LICENSE included with this distribution for more information. */ +// Package sets provides abstract Set interface for that all concrete sets should implement. +// +// In computer science, a set is an abstract data type that can store certain values and no repeated values. It is a computer implementation of the mathematical concept of a finite set. Unlike most other collection types, rather than retrieving a specific element from a set, one typically tests a value for membership in a set. +// +// Reference: https://en.wikipedia.org/wiki/Set_%28abstract_data_type%29 package sets import "github.com/emirpasic/gods/containers" diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 7b091387..a1b8ee93 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -16,10 +16,11 @@ License along with this library. See the file LICENSE included with this distribution for more information. */ -// Implementation of an ordered set backed by a red-black tree. +// Package treeset implements a tree backed by a red-black tree. +// // Structure is not thread safe. -// References: http://en.wikipedia.org/wiki/Set_%28abstract_data_type%29 - +// +// Reference: http://en.wikipedia.org/wiki/Set_%28abstract_data_type%29 package treeset import ( diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index 1e69adc9..caacf4d2 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -24,10 +24,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of stack backed by ArrayList. +// Package arraystack implements a stack backed by array list. +// // Structure is not thread safe. -// References: http://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29 - +// +// Reference: https://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29#Array package arraystack import ( diff --git a/stacks/linkedliststack/linkedliststack.go b/stacks/linkedliststack/linkedliststack.go index 843e159d..858033ed 100644 --- a/stacks/linkedliststack/linkedliststack.go +++ b/stacks/linkedliststack/linkedliststack.go @@ -24,11 +24,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of stack backed by our singly linked list. -// Used by red-black tree during in-order traversal. +// Package linkedliststack implements a stack backed by a singly-linked list. +// // Structure is not thread safe. -// References: http://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29 - +// +// Reference:https://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29#Linked_list package linkedliststack import ( diff --git a/stacks/stacks.go b/stacks/stacks.go index ceaf6f17..749bd3f2 100644 --- a/stacks/stacks.go +++ b/stacks/stacks.go @@ -24,6 +24,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +// Package stacks provides abstract Stack interface for that all concrete stacks should implement. +// +// In computer science, a stack is an abstract data type that serves as a collection of elements, with two principal operations: push, which adds an element to the collection, and pop, which removes the most recently added element that was not yet removed. The order in which elements come off a stack gives rise to its alternative name, LIFO (for last in, first out). Additionally, a peek operation may give access to the top without modifying the stack. +// +// Reference: https://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29 package stacks import "github.com/emirpasic/gods/containers" diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index 8a97d5a0..2bad245d 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -24,11 +24,13 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of binary heap backed by ArrayList. +// Package binaryheap implements a binary heap backed by array list. +// // Comparator defines this heap as either min or max heap. +// // Structure is not thread safe. +// // References: http://en.wikipedia.org/wiki/Binary_heap - package binaryheap import ( diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index abcdffd3..adcd4ec2 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -24,11 +24,13 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of Red-black tree. +// Package redblacktree implements a red-black tree. +// // Used by TreeSet and TreeMap. +// // Structure is not thread safe. +// // References: http://en.wikipedia.org/wiki/Red%E2%80%93black_tree - package redblacktree import ( diff --git a/trees/trees.go b/trees/trees.go index 055c3083..069a8806 100644 --- a/trees/trees.go +++ b/trees/trees.go @@ -24,6 +24,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +// Package trees provides abstract Tree interface for that all concrete trees should implement. +// +// In computer science, a tree is a widely used abstract data type (ADT) or data structure implementing this ADT that simulates a hierarchical tree structure, with a root value and subtrees of children with a parent node, represented as a set of linked nodes. +// +// Reference: https://en.wikipedia.org/wiki/Tree_%28data_structure%29 package trees import "github.com/emirpasic/gods/containers" diff --git a/utils/comparator.go b/utils/comparator.go index 6ce68292..7dfd6988 100644 --- a/utils/comparator.go +++ b/utils/comparator.go @@ -29,10 +29,10 @@ package utils // Comparator will make type assertion (see IntComparator for example), // which will panic if a or b are not of the asserted type. // -// Should return: -// -1, if a < b -// 0, if a == b -// 1, if a > b +// Should return a number: +// negative , if a < b +// zero , if a == b +// positive , if a > b type Comparator func(a, b interface{}) int // IntComparator provides a basic comparison on ints diff --git a/utils/sort.go b/utils/sort.go index 3cf8c1fa..154ce3d5 100644 --- a/utils/sort.go +++ b/utils/sort.go @@ -24,14 +24,13 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Util methods for sorting a slice of values with respect to the comparator - package utils import "sort" -// Sort sorts values (in-place) -// Uses Go's sort (hybrid of quicksort for large and then insertion sort for smaller slices) +// Sort sorts values (in-place) with respect to the given comparator. +// +// Uses Go's sort (hybrid of quicksort for large and then insertion sort for smaller slices). func Sort(values []interface{}, comparator Comparator) { sort.Sort(sortable{values, comparator}) } From d7a31571cc977b8cd232dc8c66533b554990b67c Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 25 Jun 2016 18:17:48 +0200 Subject: [PATCH 062/320] - add reversible iterators to lists (array list and doubly-linked list) - documentation and tests updates --- README.md | 37 ++++++++++-- containers/containers.go | 2 +- containers/iterator.go | 30 ++++++++++ lists/arraylist/arraylist.go | 16 +++++- lists/arraylist/arraylist_test.go | 57 +++++++++++++++++-- lists/doublylinkedlist/doublylinkedlist.go | 27 ++++++++- .../doublylinkedlist/doublylinkedlist_test.go | 57 +++++++++++++++++-- lists/lists.go | 2 +- lists/singlylinkedlist/singlylinkedlist.go | 10 ++-- .../singlylinkedlist/singlylinkedlist_test.go | 18 ++++-- maps/maps.go | 2 +- sets/sets.go | 2 +- stacks/stacks.go | 2 +- trees/trees.go | 2 +- utils/utils.go | 32 +++++++++++ 15 files changed, 264 insertions(+), 32 deletions(-) create mode 100644 utils/utils.go diff --git a/README.md b/README.md index 4c6006b3..2cf8d6e3 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ Implementation of various data structures and algorithms in Go. - [Iterator](#iterator) - [IteratorWithIndex](#iteratorwithindex) - [IteratorWithKey](#iteratorwithkey) + - [ReverseIteratorWithIndex](#reverseiteratorwithindex) + - [ReverseIteratorWithKey](#reverseiteratorwithkey) - [Enumerable](#enumerable) - [EnumerableWithIndex](#enumerablewithindex) - [EnumerableWithKey](#enumerablewithkey) @@ -53,9 +55,9 @@ Containers are either ordered or unordered. All ordered containers provide [stat | Container | Ordered | [Iterator](#iterator) | [Enumerable](#enumerable) | Ordered by | | :--- | :---: | :---: | :---: | :---: | -| [ArrayList](#arraylist) | yes | yes | yes | index | -| [SinglyLinkedList](#singlylinkedlist) | yes | yes | yes | index | -| [DoublyLinkedList](#doublylinkedlist) | yes | yes | yes | index | +| [ArrayList](#arraylist) | yes | yes* | yes | index | +| [SinglyLinkedList](#singlylinkedlist) | yes | yes* | yes | index | +| [DoublyLinkedList](#doublylinkedlist) | yes | yes* | yes | index | | [HashSet](#hashset) | no | no | no | index | | [TreeSet](#treeset) | yes | yes | yes | index | | [LinkedListStack](#linkedliststack) | yes | yes | no | index | @@ -64,6 +66,7 @@ Containers are either ordered or unordered. All ordered containers provide [stat | [TreeMap](#treemap) | yes | yes | yes | key | | [RedBlackTree](#redblacktree) | yes | yes | no | key | | [BinaryHeap](#binaryheap) | yes | yes | no | index | +| | | *reversible | | | ### Lists @@ -642,7 +645,7 @@ func main() { ### Iterator -All ordered containers have stateful iterators. Typically an iterator is obtained by _Iterator()_ function of an ordered container. Once obtained, iterator's _Next()_ function moves the iterator to the next element and returns true if there was a next element. If there was an element, then element's can be obtained by iterator's _Value()_ function. Depending on the ordering type, it's position can be obtained by iterator's _Index()_ or _Key()_ functions. +All ordered containers have stateful iterators. Typically an iterator is obtained by _Iterator()_ function of an ordered container. Once obtained, iterator's _Next()_ function moves the iterator to the next element and returns true if there was a next element. If there was an element, then element's can be obtained by iterator's _Value()_ function. Depending on the ordering type, it's position can be obtained by iterator's _Index()_ or _Key()_ functions. Some containers even provide reversible iterators, essentially the same, but provide another extra _Prev()_ function that moves the iterator to the previous element and returns true if there was a previous element. #### IteratorWithIndex @@ -668,6 +671,32 @@ for it.Next() { } ``` +#### ReverseIteratorWithIndex + +A [iterator](#iterator) whose elements are referenced by an index. Typical usage: + +```go +it := list.Iterator() +for it.Next() { /* Move to end */ } +for it.Prev() { + index, value := it.Index(), it.Value() + ... +} +``` + +#### ReverseIteratorWithKey + +A [iterator](#iterator) whose elements are referenced by a key. Typical usage: + +```go +it := map.Iterator() +for it.Next() { /* Move to end */ } +for it.Prev() { + key, value := it.Key(), it.Value() + ... +} +``` + ### Enumerable Enumerable functions for ordered containers that implement [EnumerableWithIndex](#enumerablewithindex) or [EnumerableWithKey](#enumerablewithkey) interfaces. diff --git a/containers/containers.go b/containers/containers.go index 91ca0463..6e73dea6 100644 --- a/containers/containers.go +++ b/containers/containers.go @@ -24,7 +24,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Package containers provides core interfaces and functions data structures. +// Package containers provides core interfaces and functions for data structures. // // Container is the base interface for all data structures to implement. // diff --git a/containers/iterator.go b/containers/iterator.go index fd2d4d47..c1a7c545 100644 --- a/containers/iterator.go +++ b/containers/iterator.go @@ -53,3 +53,33 @@ type IteratorWithKey interface { // Does not modify the state of the iterator. Key() interface{} } + +// 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. +type ReverseIteratorWithIndex 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. + Prev() bool + + IteratorWithIndex + // Next() bool + // Value() interface{} + // Index() int +} + +// 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. +type ReverseIteratorWithKey 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 Key() and Value(). + // Modifies the state of the iterator. + Prev() bool + + IteratorWithKey + // Next() bool + // Value() interface{} + // Key() interface{} +} diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index ad0fc092..c08d928b 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -42,7 +42,7 @@ import ( func assertInterfaceImplementation() { var _ lists.List = (*List)(nil) var _ containers.EnumerableWithIndex = (*List)(nil) - var _ containers.IteratorWithIndex = (*Iterator)(nil) + var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) } // List holds the elements in a slice @@ -195,7 +195,19 @@ func (list *List) Iterator() Iterator { // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index++ + if iterator.index < iterator.list.size { + iterator.index++ + } + return iterator.list.withinRange(iterator.index) +} + +// 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 { + if iterator.index >= 0 { + iterator.index-- + } return iterator.list.withinRange(iterator.index) } diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 0dea8d8a..9de67da9 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -299,11 +299,21 @@ func TestListChaining(t *testing.T) { } } -func TestListIterator(t *testing.T) { +func TestListIteratorNextOnEmpty(t *testing.T) { + list := New() + it := list.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty list") + } +} + +func TestListIteratorNext(t *testing.T) { list := New() list.Add("a", "b", "c") it := list.Iterator() + count := 0 for it.Next() { + count++ index := it.Index() value := it.Value() switch index { @@ -323,13 +333,52 @@ func TestListIterator(t *testing.T) { t.Errorf("Too many") } } - list.Clear() - it = list.Iterator() - for it.Next() { + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + +func TestListIteratorPrevOnEmpty(t *testing.T) { + list := New() + it := list.Iterator() + for it.Prev() { t.Errorf("Shouldn't iterate on empty list") } } +func TestListIteratorPrev(t *testing.T) { + list := New() + list.Add("a", "b", "c") + it := list.Iterator() + for it.Next() { + } + count := 0 + for it.Prev() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + } + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + func BenchmarkList(b *testing.B) { for i := 0; i < b.N; i++ { list := New() diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 3f976479..cb7bdfc5 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -42,7 +42,7 @@ import ( func assertInterfaceImplementation() { var _ lists.List = (*List)(nil) var _ containers.EnumerableWithIndex = (*List)(nil) - var _ containers.IteratorWithIndex = (*Iterator)(nil) + var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) } // List holds the elements, where each element points to the next and previous element @@ -316,12 +316,14 @@ func (list *List) Iterator() Iterator { // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index++ + if iterator.index < iterator.list.size { + iterator.index++ + } if !iterator.list.withinRange(iterator.index) { iterator.element = nil return false } - if iterator.element != nil { + if iterator.index != 0 { iterator.element = iterator.element.next } else { iterator.element = iterator.list.first @@ -329,6 +331,25 @@ func (iterator *Iterator) Next() bool { return true } +// 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 { + if iterator.index >= 0 { + iterator.index-- + } + if !iterator.list.withinRange(iterator.index) { + iterator.element = nil + return false + } + if iterator.index == iterator.list.size-1 { + iterator.element = iterator.list.last + } else { + iterator.element = iterator.element.prev + } + return iterator.list.withinRange(iterator.index) +} + // Value returns the current element's value. // Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index e199102f..1ff73b67 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -299,11 +299,21 @@ func TestListChaining(t *testing.T) { } } -func TestListIterator(t *testing.T) { +func TestListIteratorNextOnEmpty(t *testing.T) { + list := New() + it := list.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty list") + } +} + +func TestListIteratorNext(t *testing.T) { list := New() list.Add("a", "b", "c") it := list.Iterator() + count := 0 for it.Next() { + count++ index := it.Index() value := it.Value() switch index { @@ -323,13 +333,52 @@ func TestListIterator(t *testing.T) { t.Errorf("Too many") } } - list.Clear() - it = list.Iterator() - for it.Next() { + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + +func TestListIteratorPrevOnEmpty(t *testing.T) { + list := New() + it := list.Iterator() + for it.Prev() { t.Errorf("Shouldn't iterate on empty list") } } +func TestListIteratorPrev(t *testing.T) { + list := New() + list.Add("a", "b", "c") + it := list.Iterator() + for it.Next() { + } + count := 0 + for it.Prev() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + } + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + func BenchmarkList(b *testing.B) { for i := 0; i < b.N; i++ { list := New() diff --git a/lists/lists.go b/lists/lists.go index 539d14eb..b3d9b9af 100644 --- a/lists/lists.go +++ b/lists/lists.go @@ -16,7 +16,7 @@ License along with this library. See the file LICENSE included with this distribution for more information. */ -// Package lists provides abstract List interface for that all concrete lists should implement. +// Package lists provides an abstract List interface. // // In computer science, a list or sequence is an abstract data type that represents an ordered sequence of values, where the same value may occur more than once. An instance of a list is a computer representation of the mathematical concept of a finite sequence; the (potentially) infinite analog of a list is a stream. Lists are a basic example of containers, as they contain other values. If the same value occurs multiple times, each occurrence is considered a distinct item. // diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 953ab8b9..f65f7282 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -288,15 +288,17 @@ func (list *List) Iterator() Iterator { // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index++ + if iterator.index < iterator.list.size { + iterator.index++ + } if !iterator.list.withinRange(iterator.index) { iterator.element = nil return false } - if iterator.element != nil { - iterator.element = iterator.element.next - } else { + if iterator.index == 0 { iterator.element = iterator.list.first + } else { + iterator.element = iterator.element.next } return true } diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index c5462177..53c2ad8f 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -299,11 +299,21 @@ func TestListChaining(t *testing.T) { } } -func TestListIterator(t *testing.T) { +func TestListIteratorNextOnEmpty(t *testing.T) { + list := New() + it := list.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty list") + } +} + +func TestListIteratorNext(t *testing.T) { list := New() list.Add("a", "b", "c") it := list.Iterator() + count := 0 for it.Next() { + count++ index := it.Index() value := it.Value() switch index { @@ -323,10 +333,8 @@ func TestListIterator(t *testing.T) { t.Errorf("Too many") } } - list.Clear() - it = list.Iterator() - for it.Next() { - t.Errorf("Shouldn't iterate on empty list") + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } diff --git a/maps/maps.go b/maps/maps.go index 809f138b..93f8bc0f 100644 --- a/maps/maps.go +++ b/maps/maps.go @@ -24,7 +24,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Package maps provides abstract Map interface for that all concrete maps should implement. +// Package maps provides an abstract Map interface. // // In computer science, an associative array, map, symbol table, or dictionary is an abstract data type composed of a collection of (key, value) pairs, such that each possible key appears just once in the collection. // diff --git a/sets/sets.go b/sets/sets.go index af4aa22c..b0ae9884 100644 --- a/sets/sets.go +++ b/sets/sets.go @@ -16,7 +16,7 @@ License along with this library. See the file LICENSE included with this distribution for more information. */ -// Package sets provides abstract Set interface for that all concrete sets should implement. +// Package sets provides an abstract Set interface. // // In computer science, a set is an abstract data type that can store certain values and no repeated values. It is a computer implementation of the mathematical concept of a finite set. Unlike most other collection types, rather than retrieving a specific element from a set, one typically tests a value for membership in a set. // diff --git a/stacks/stacks.go b/stacks/stacks.go index 749bd3f2..a580d36e 100644 --- a/stacks/stacks.go +++ b/stacks/stacks.go @@ -24,7 +24,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Package stacks provides abstract Stack interface for that all concrete stacks should implement. +// Package stacks provides an abstract Stack interface. // // In computer science, a stack is an abstract data type that serves as a collection of elements, with two principal operations: push, which adds an element to the collection, and pop, which removes the most recently added element that was not yet removed. The order in which elements come off a stack gives rise to its alternative name, LIFO (for last in, first out). Additionally, a peek operation may give access to the top without modifying the stack. // diff --git a/trees/trees.go b/trees/trees.go index 069a8806..2b235c16 100644 --- a/trees/trees.go +++ b/trees/trees.go @@ -24,7 +24,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Package trees provides abstract Tree interface for that all concrete trees should implement. +// Package trees provides an abstract Tree interface. // // In computer science, a tree is a widely used abstract data type (ADT) or data structure implementing this ADT that simulates a hierarchical tree structure, with a root value and subtrees of children with a parent node, represented as a set of linked nodes. // diff --git a/utils/utils.go b/utils/utils.go new file mode 100644 index 00000000..077c1f0a --- /dev/null +++ b/utils/utils.go @@ -0,0 +1,32 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// Package utils provides common utility functions. +// +// Provided functionalities: +// - sorting +// - comparators +package utils From b304f5eb5843c37332c3c0f824b5ac5d0eb94e2b Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 25 Jun 2016 19:11:20 +0200 Subject: [PATCH 063/320] - add reversible iterators to array stack --- README.md | 12 +++--- maps/treemap/treemap_test.go | 8 ++++ sets/treeset/treeset_test.go | 8 ++++ stacks/arraystack/arraystack.go | 16 +++++++- stacks/arraystack/arraystack_test.go | 41 ++++++++++++++++++- .../linkedliststack/linkedliststack_test.go | 9 ++++ 6 files changed, 85 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 2cf8d6e3..ad968b90 100644 --- a/README.md +++ b/README.md @@ -56,16 +56,16 @@ Containers are either ordered or unordered. All ordered containers provide [stat | Container | Ordered | [Iterator](#iterator) | [Enumerable](#enumerable) | Ordered by | | :--- | :---: | :---: | :---: | :---: | | [ArrayList](#arraylist) | yes | yes* | yes | index | -| [SinglyLinkedList](#singlylinkedlist) | yes | yes* | yes | index | +| [SinglyLinkedList](#singlylinkedlist) | yes | yes | yes | index | | [DoublyLinkedList](#doublylinkedlist) | yes | yes* | yes | index | | [HashSet](#hashset) | no | no | no | index | -| [TreeSet](#treeset) | yes | yes | yes | index | +| [TreeSet](#treeset) | yes | yes* | yes | index | | [LinkedListStack](#linkedliststack) | yes | yes | no | index | -| [ArrayStack](#arraystack) | yes | yes | no | index | +| [ArrayStack](#arraystack) | yes | yes* | no | index | | [HashMap](#hashmap) | no | no | no | key | -| [TreeMap](#treemap) | yes | yes | yes | key | -| [RedBlackTree](#redblacktree) | yes | yes | no | key | -| [BinaryHeap](#binaryheap) | yes | yes | no | index | +| [TreeMap](#treemap) | yes | yes* | yes | key | +| [RedBlackTree](#redblacktree) | yes | yes* | no | key | +| [BinaryHeap](#binaryheap) | yes | yes* | no | index | | | | *reversible | | | ### Lists diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index c0814314..66f411c4 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -318,7 +318,9 @@ func TestMapIterator(t *testing.T) { m.Put("b", 2) it := m.Iterator() + count := 0 for it.Next() { + count++ key := it.Key() value := it.Value() switch key { @@ -337,6 +339,12 @@ func TestMapIterator(t *testing.T) { default: t.Errorf("Too many") } + if actualValue, expectedValue := value, count; 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) } m.Clear() diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index 14bb4dea..31428ac8 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -197,7 +197,9 @@ func TestSetIterator(t *testing.T) { set.Add("c", "a", "b") it := set.Iterator() + count := 0 for it.Next() { + count++ index := it.Index() value := it.Value() switch index { @@ -216,6 +218,12 @@ func TestSetIterator(t *testing.T) { 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) } set.Clear() diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index caacf4d2..ece76a9b 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -41,7 +41,7 @@ import ( func assertInterfaceImplementation() { var _ stacks.Stack = (*Stack)(nil) - var _ containers.IteratorWithIndex = (*Iterator)(nil) + var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) } // Stack holds elements in an array-list @@ -113,7 +113,19 @@ func (stack *Stack) Iterator() Iterator { // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index++ + if iterator.index < iterator.stack.Size() { + iterator.index++ + } + return iterator.stack.withinRange(iterator.index) +} + +// 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 { + if iterator.index >= 0 { + iterator.index-- + } return iterator.stack.withinRange(iterator.index) } diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index 42d7d6a6..98af62c3 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -98,9 +98,11 @@ func TestStackIterator(t *testing.T) { stack.Push("b") stack.Push("c") - // Iterator + // Iterator (next) it := stack.Iterator() + count := 0 for it.Next() { + count++ index := it.Index() value := it.Value() switch index { @@ -119,7 +121,44 @@ func TestStackIterator(t *testing.T) { 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) } + + // Iterator (prev) + count = 0 + for it.Prev() { + 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, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := index, 3-count; 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) + } + stack.Clear() it = stack.Iterator() for it.Next() { diff --git a/stacks/linkedliststack/linkedliststack_test.go b/stacks/linkedliststack/linkedliststack_test.go index c9b097af..4fb00024 100644 --- a/stacks/linkedliststack/linkedliststack_test.go +++ b/stacks/linkedliststack/linkedliststack_test.go @@ -100,7 +100,9 @@ func TestStackIterator(t *testing.T) { // Iterator it := stack.Iterator() + count := 0 for it.Next() { + count++ index := it.Index() value := it.Value() switch index { @@ -119,7 +121,14 @@ func TestStackIterator(t *testing.T) { 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) } + stack.Clear() it = stack.Iterator() for it.Next() { From ae143689c625cac225765fa5dcf6c086a133e01f Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 25 Jun 2016 19:26:08 +0200 Subject: [PATCH 064/320] - add reversible iterators to binary heap --- stacks/arraystack/arraystack_test.go | 30 ++++++++---- stacks/linkedliststack/linkedliststack.go | 4 +- trees/binaryheap/binaryheap.go | 16 ++++++- trees/binaryheap/binaryheap_test.go | 58 ++++++++++++++++++++--- 4 files changed, 88 insertions(+), 20 deletions(-) diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index 98af62c3..fad4ac08 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -92,13 +92,20 @@ func TestStackPop(t *testing.T) { } } -func TestStackIterator(t *testing.T) { +func TestStackIteratorOnEmpty(t *testing.T) { + stack := New() + it := stack.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty stack") + } +} + +func TestStackIteratorNext(t *testing.T) { stack := New() stack.Push("a") stack.Push("b") stack.Push("c") - // Iterator (next) it := stack.Iterator() count := 0 for it.Next() { @@ -128,9 +135,18 @@ func TestStackIterator(t *testing.T) { if actualValue, expectedValue := count, 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } +} - // Iterator (prev) - count = 0 +func TestStackIteratorPrev(t *testing.T) { + stack := New() + stack.Push("a") + stack.Push("b") + stack.Push("c") + + it := stack.Iterator() + for it.Next() { + } + count := 0 for it.Prev() { count++ index := it.Index() @@ -158,12 +174,6 @@ func TestStackIterator(t *testing.T) { if actualValue, expectedValue := count, 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - - stack.Clear() - it = stack.Iterator() - for it.Next() { - t.Errorf("Shouldn't iterate on empty stack") - } } func BenchmarkStack(b *testing.B) { diff --git a/stacks/linkedliststack/linkedliststack.go b/stacks/linkedliststack/linkedliststack.go index 858033ed..75f19480 100644 --- a/stacks/linkedliststack/linkedliststack.go +++ b/stacks/linkedliststack/linkedliststack.go @@ -108,7 +108,9 @@ func (stack *Stack) Iterator() Iterator { // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index++ + if iterator.index < iterator.stack.Size() { + iterator.index++ + } return iterator.stack.withinRange(iterator.index) } diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index 2bad245d..0e5942f4 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -44,7 +44,7 @@ import ( func assertInterfaceImplementation() { var _ trees.Tree = (*Heap)(nil) - var _ containers.IteratorWithIndex = (*Iterator)(nil) + var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) } // Heap holds elements in an array-list @@ -129,7 +129,19 @@ func (heap *Heap) Iterator() Iterator { // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index++ + if iterator.index < iterator.heap.Size() { + iterator.index++ + } + return iterator.heap.withinRange(iterator.index) +} + +// 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 { + if iterator.index >= 0 { + iterator.index-- + } return iterator.heap.withinRange(iterator.index) } diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go index 76996341..d72375a3 100644 --- a/trees/binaryheap/binaryheap_test.go +++ b/trees/binaryheap/binaryheap_test.go @@ -107,19 +107,24 @@ func TestBinaryHeapRandom(t *testing.T) { } } -func TestBinaryHeapIterator(t *testing.T) { +func TestBinaryHeapIteratorOnEmpty(t *testing.T) { heap := NewWithIntComparator() - - if actualValue := heap.Empty(); actualValue != true { - t.Errorf("Got %v expected %v", actualValue, true) + it := heap.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty heap") } +} +func TestBinaryHeapIteratorNext(t *testing.T) { + heap := NewWithIntComparator() heap.Push(3) // [3] heap.Push(2) // [2,3] heap.Push(1) // [1,3,2](2 swapped with 1, hence last) it := heap.Iterator() + count := 0 for it.Next() { + count++ index := it.Index() value := it.Value() switch index { @@ -138,12 +143,51 @@ func TestBinaryHeapIterator(t *testing.T) { 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) + } +} - heap.Clear() - it = heap.Iterator() +func TestBinaryHeapIteratorPrev(t *testing.T) { + heap := NewWithIntComparator() + heap.Push(3) // [3] + heap.Push(2) // [2,3] + heap.Push(1) // [1,3,2](2 swapped with 1, hence last) + + it := heap.Iterator() for it.Next() { - t.Errorf("Shouldn't iterate on empty stack") + } + count := 0 + for it.Prev() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := index, 3-count; 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) } } From 178bc76d62c2a44f18925823bbdafd804a292150 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 25 Jun 2016 20:45:43 +0200 Subject: [PATCH 065/320] - add reversible iterators to red-black tree --- trees/redblacktree/redblacktree.go | 64 +++++--- trees/redblacktree/redblacktree_test.go | 193 +++++++++++++++++++++--- 2 files changed, 215 insertions(+), 42 deletions(-) diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index adcd4ec2..cf68bab3 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -43,7 +43,7 @@ import ( func assertInterfaceImplementation() { var _ trees.Tree = (*Tree)(nil) - var _ containers.IteratorWithKey = (*Iterator)(nil) + var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) } type color bool @@ -281,37 +281,65 @@ func (tree *Tree) Clear() { // Iterator holding the iterator's state type Iterator struct { tree *Tree - left *Node + node *Node } // Iterator returns a stateful iterator whose elements are key/value pairs. func (tree *Tree) Iterator() Iterator { - return Iterator{tree: tree, left: nil} + return Iterator{tree: tree, node: nil} } // 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(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - if iterator.left == nil { - iterator.left = iterator.tree.Left() - return iterator.left != nil - } - if iterator.left.Right != nil { - iterator.left = iterator.left.Right - for iterator.left.Left != nil { - iterator.left = iterator.left.Left + if iterator.node == nil { + iterator.node = iterator.tree.Left() + return iterator.node != nil + } + if iterator.node.Right != nil { + iterator.node = iterator.node.Right + for iterator.node.Left != nil { + iterator.node = iterator.node.Left } return true } - if iterator.left.Parent != nil { - key := iterator.left.Key - for iterator.left.Parent != nil { - iterator.left = iterator.left.Parent - if iterator.tree.Comparator(key, iterator.left.Key) <= 0 { + if iterator.node.Parent != nil { + node := iterator.node + for iterator.node.Parent != nil { + iterator.node = iterator.node.Parent + if iterator.tree.Comparator(node.Key, iterator.node.Key) <= 0 { return true } } + iterator.node = node // fix: if parent didn't satisfy the comparator criteria + } + return false +} + +// 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 Key() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Prev() bool { + if iterator.node == nil { + return false + } + if iterator.node.Left != nil { + iterator.node = iterator.node.Left + for iterator.node.Right != nil { + iterator.node = iterator.node.Right + } + return true + } + if iterator.node.Parent != nil { + node := iterator.node + for iterator.node.Parent != nil { + iterator.node = iterator.node.Parent + if iterator.tree.Comparator(node.Key, iterator.node.Key) >= 0 { + return true + } + } + iterator.node = node // fix: if parent didn't satisfy the comparator criteria } return false } @@ -319,13 +347,13 @@ func (iterator *Iterator) Next() bool { // Value returns the current element's value. // Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { - return iterator.left.Value + return iterator.node.Value } // Key returns the current element's key. // Does not modify the state of the iterator. func (iterator *Iterator) Key() interface{} { - return iterator.left.Key + return iterator.node.Key } // String returns a string representation of container diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 96fa4e1d..377ee9e2 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -206,7 +206,23 @@ func TestRedBlackTreeCeilingAndFloor(t *testing.T) { } } -func TestRedBlackTreeIterator1(t *testing.T) { +func TestRedBlackTreeIteratorNextOnEmpty(t *testing.T) { + tree := NewWithIntComparator() + it := tree.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty tree") + } +} + +func TestRedBlackTreeIteratorPrevOnEmpty(t *testing.T) { + tree := NewWithIntComparator() + it := tree.Iterator() + for it.Prev() { + t.Errorf("Shouldn't iterate on empty tree") + } +} + +func TestRedBlackTreeIterator1Next(t *testing.T) { tree := NewWithIntComparator() tree.Put(5, "e") tree.Put(6, "f") @@ -216,29 +232,76 @@ func TestRedBlackTreeIterator1(t *testing.T) { tree.Put(1, "x") tree.Put(2, "b") tree.Put(1, "a") //overwrite - + // │ ┌── 7 + // └── 6 + // │ ┌── 5 + // └── 4 + // │ ┌── 3 + // └── 2 + // └── 1 it := tree.Iterator() count := 0 for it.Next() { count++ - index := it.Key() - switch index { + key := it.Key() + switch key { case count: - if actualValue, expectedValue := index, count; actualValue != expectedValue { + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + +func TestRedBlackTreeIterator1Prev(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(5, "e") + tree.Put(6, "f") + tree.Put(7, "g") + tree.Put(3, "c") + tree.Put(4, "d") + tree.Put(1, "x") + tree.Put(2, "b") + tree.Put(1, "a") //overwrite + // │ ┌── 7 + // └── 6 + // │ ┌── 5 + // └── 4 + // │ ┌── 3 + // └── 2 + // └── 1 + it := tree.Iterator() + for it.Next() { + } + countDown := tree.size + for it.Prev() { + countDown-- + key := it.Key() + switch key { + case countDown: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } default: - if actualValue, expectedValue := index, count; actualValue != expectedValue { + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } } - if actualValue, expectedValue := count, 7; actualValue != expectedValue { + // one less that in Next(), thus "1" + if actualValue, expectedValue := countDown, 1; actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } } -func TestRedBlackTreeIterator2(t *testing.T) { +func TestRedBlackTreeIterator2Next(t *testing.T) { tree := NewWithIntComparator() tree.Put(3, "c") tree.Put(1, "a") @@ -247,50 +310,99 @@ func TestRedBlackTreeIterator2(t *testing.T) { count := 0 for it.Next() { count++ - index := it.Key() - switch index { + key := it.Key() + switch key { case count: - if actualValue, expectedValue := index, count; actualValue != expectedValue { + if actualValue, expectedValue := key, count; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } default: - if actualValue, expectedValue := index, count; actualValue != expectedValue { + if actualValue, expectedValue := key, count; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } } - if actualValue, expectedValue := count, 3; actualValue != expectedValue { + if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } } -func TestRedBlackTreeIterator3(t *testing.T) { +func TestRedBlackTreeIterator2Prev(t *testing.T) { tree := NewWithIntComparator() - + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") it := tree.Iterator() for it.Next() { - t.Errorf("Shouldn't iterate on empty stack") } + countDown := tree.size + for it.Prev() { + countDown-- + key := it.Key() + switch key { + case countDown: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + // one less that in Next(), thus "1" + if actualValue, expectedValue := countDown, 1; actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} +func TestRedBlackTreeIterator3Next(t *testing.T) { + tree := NewWithIntComparator() tree.Put(1, "a") - - it = tree.Iterator() + it := tree.Iterator() count := 0 for it.Next() { count++ - index := it.Key() - switch index { + key := it.Key() + switch key { case count: - if actualValue, expectedValue := index, count; actualValue != expectedValue { + if actualValue, expectedValue := key, count; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } default: - if actualValue, expectedValue := index, count; actualValue != expectedValue { + if actualValue, expectedValue := key, count; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } } - if actualValue, expectedValue := count, 1; actualValue != expectedValue { + if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + +func TestRedBlackTreeIterator3Prev(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(1, "a") + it := tree.Iterator() + for it.Next() { + } + countDown := tree.size + for it.Prev() { + countDown-- + key := it.Key() + switch key { + case countDown: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + // one less that in Next(), thus "1" + if actualValue, expectedValue := countDown, 1; actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } } @@ -308,7 +420,20 @@ func TestRedBlackTreeIterator4(t *testing.T) { tree.Put(22, 8) tree.Put(27, 10) + // │ ┌── 27 + // │ ┌── 25 + // │ │ └── 22 + // │ ┌── 17 + // │ │ └── 15 + // └── 13 + // │ ┌── 11 + // └── 8 + // │ ┌── 6 + // └── 1 + it := tree.Iterator() + + // Iterator (next) count := 0 for it.Next() { count++ @@ -324,7 +449,27 @@ func TestRedBlackTreeIterator4(t *testing.T) { } } } - if actualValue, expectedValue := count, 10; actualValue != expectedValue { + if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } + + // Iterator (prev) + for it.Prev() { + count-- + value := it.Value() + switch value { + case count: + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + // one less that in Next(), thus "1" + if actualValue, expectedValue := count, 1; actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } } From eb4bb224e398363dd251b8b884f5bdbfc467a55c Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 25 Jun 2016 21:01:33 +0200 Subject: [PATCH 066/320] - add reversible iterators to tree set and tree map --- maps/treemap/treemap.go | 9 +++- maps/treemap/treemap_test.go | 60 +++++++++++++++++++++++-- sets/treeset/treeset.go | 19 ++++++-- sets/treeset/treeset_test.go | 55 ++++++++++++++++++++--- trees/redblacktree/redblacktree_test.go | 34 +++++++++++--- 5 files changed, 158 insertions(+), 19 deletions(-) diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index efa46e43..f1640bfd 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -43,7 +43,7 @@ import ( func assertInterfaceImplementation() { var _ maps.Map = (*Map)(nil) var _ containers.EnumerableWithKey = (*Map)(nil) - var _ containers.IteratorWithKey = (*Iterator)(nil) + var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) } // Map holds the elements in a red-black tree @@ -145,6 +145,13 @@ 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 Key() 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{} { diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 66f411c4..ac4d778b 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -311,7 +311,25 @@ func TestMapChaining(t *testing.T) { } } -func TestMapIterator(t *testing.T) { +func TestMapIteratorNextOnEmpty(t *testing.T) { + m := NewWithStringComparator() + it := m.Iterator() + it = m.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty map") + } +} + +func TestMapIteratorPrevOnEmpty(t *testing.T) { + m := NewWithStringComparator() + it := m.Iterator() + it = m.Iterator() + for it.Prev() { + t.Errorf("Shouldn't iterate on empty map") + } +} + +func TestMapIteratorNext(t *testing.T) { m := NewWithStringComparator() m.Put("c", 3) m.Put("a", 1) @@ -346,11 +364,45 @@ func TestMapIterator(t *testing.T) { if actualValue, expectedValue := count, 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } +} - m.Clear() - it = m.Iterator() +func TestMapIteratorPrev(t *testing.T) { + m := NewWithStringComparator() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + + it := m.Iterator() for it.Next() { - t.Errorf("Shouldn't iterate on empty map") + } + countDown := m.Size() + for it.Prev() { + countDown-- + key := it.Key() + value := it.Value() + switch key { + case "a": + if actualValue, expectedValue := value, 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case "b": + if actualValue, expectedValue := value, 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case "c": + if actualValue, expectedValue := value, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := value, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + // one less that in Next(), thus "1" + if actualValue, expectedValue := countDown, 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index a1b8ee93..3a0de080 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -35,7 +35,7 @@ import ( func assertInterfaceImplementation() { var _ sets.Set = (*Set)(nil) var _ containers.EnumerableWithIndex = (*Set)(nil) - var _ containers.IteratorWithIndex = (*Iterator)(nil) + var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) } // Set holds elements in a red-black tree @@ -110,21 +110,34 @@ func (set *Set) Values() []interface{} { type Iterator struct { index int iterator rbt.Iterator + tree *rbt.Tree } // Iterator holding the iterator's state func (set *Set) Iterator() Iterator { - return Iterator{index: -1, iterator: set.tree.Iterator()} + return Iterator{index: -1, iterator: set.tree.Iterator(), tree: set.tree} } // 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(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index++ + if iterator.index < iterator.tree.Size() { + iterator.index++ + } 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 { + if iterator.index >= 0 { + iterator.index-- + } + return iterator.iterator.Prev() +} + // Value returns the current element's value. // Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index 31428ac8..ccdb16c4 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -192,10 +192,25 @@ func TestSetChaining(t *testing.T) { set.Add("c", "a", "b") } -func TestSetIterator(t *testing.T) { +func TestSetIteratorNextOnEmpty(t *testing.T) { set := NewWithStringComparator() - set.Add("c", "a", "b") + it := set.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty set") + } +} +func TestSetIteratorPrevOnEmpty(t *testing.T) { + set := NewWithStringComparator() + it := set.Iterator() + for it.Prev() { + t.Errorf("Shouldn't iterate on empty set") + } +} + +func TestSetIteratorNext(t *testing.T) { + set := NewWithStringComparator() + set.Add("c", "a", "b") it := set.Iterator() count := 0 for it.Next() { @@ -225,11 +240,41 @@ func TestSetIterator(t *testing.T) { if actualValue, expectedValue := count, 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } +} - set.Clear() - it = set.Iterator() +func TestSetIteratorPrev(t *testing.T) { + set := NewWithStringComparator() + set.Add("c", "a", "b") + it := set.Iterator() + for it.Prev() { + } + count := 0 for it.Next() { - t.Errorf("Shouldn't iterate on empty set") + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; 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) } } diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 377ee9e2..3f5987a3 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -407,7 +407,7 @@ func TestRedBlackTreeIterator3Prev(t *testing.T) { } } -func TestRedBlackTreeIterator4(t *testing.T) { +func TestRedBlackTreeIterator4Next(t *testing.T) { tree := NewWithIntComparator() tree.Put(13, 5) tree.Put(8, 3) @@ -419,7 +419,6 @@ func TestRedBlackTreeIterator4(t *testing.T) { tree.Put(6, 2) tree.Put(22, 8) tree.Put(27, 10) - // │ ┌── 27 // │ ┌── 25 // │ │ └── 22 @@ -430,10 +429,7 @@ func TestRedBlackTreeIterator4(t *testing.T) { // └── 8 // │ ┌── 6 // └── 1 - it := tree.Iterator() - - // Iterator (next) count := 0 for it.Next() { count++ @@ -452,8 +448,34 @@ func TestRedBlackTreeIterator4(t *testing.T) { if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } +} - // Iterator (prev) +func TestRedBlackTreeIterator4(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(13, 5) + tree.Put(8, 3) + tree.Put(17, 7) + tree.Put(1, 1) + tree.Put(11, 4) + tree.Put(15, 6) + tree.Put(25, 9) + tree.Put(6, 2) + tree.Put(22, 8) + tree.Put(27, 10) + // │ ┌── 27 + // │ ┌── 25 + // │ │ └── 22 + // │ ┌── 17 + // │ │ └── 15 + // └── 13 + // │ ┌── 11 + // └── 8 + // │ ┌── 6 + // └── 1 + it := tree.Iterator() + count := tree.Size() + for it.Next() { + } for it.Prev() { count-- value := it.Value() From b86d413e66d49930536535e5d3e43ea45c84e0ee Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 26 Jun 2016 20:50:49 +0200 Subject: [PATCH 067/320] - iterator reset on all structures --- containers/iterator.go | 8 ++++++++ lists/arraylist/arraylist.go | 7 +++++++ lists/doublylinkedlist/doublylinkedlist.go | 8 ++++++++ lists/singlylinkedlist/singlylinkedlist.go | 8 ++++++++ maps/treemap/treemap.go | 7 +++++++ sets/treeset/treeset.go | 7 +++++++ stacks/arraystack/arraystack.go | 7 +++++++ stacks/linkedliststack/linkedliststack.go | 7 +++++++ trees/binaryheap/binaryheap.go | 7 +++++++ trees/redblacktree/redblacktree.go | 7 +++++++ 10 files changed, 73 insertions(+) diff --git a/containers/iterator.go b/containers/iterator.go index c1a7c545..8c08ba1f 100644 --- a/containers/iterator.go +++ b/containers/iterator.go @@ -30,6 +30,7 @@ package containers type IteratorWithIndex 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. // Modifies the state of the iterator. Next() bool // Value returns the current element's value. @@ -38,12 +39,16 @@ type IteratorWithIndex interface { // Index returns the current element's index. // Does not modify the state of the iterator. Index() int + // Reset sets the iterator to the initial state. + // Call Next() to fetch the first element if any. + Reset() } // IteratorWithKey is a stateful iterator for ordered containers whose elements are key value pairs. type IteratorWithKey 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. // Modifies the state of the iterator. Next() bool // Value returns the current element's value. @@ -52,6 +57,9 @@ type IteratorWithKey interface { // Key returns the current element's key. // Does not modify the state of the iterator. Key() interface{} + // Reset sets the iterator to the initial state. + // Call Next() to fetch the first element if any. + Reset() } // ReverseIteratorWithIndex is stateful iterator for ordered containers whose values can be fetched by an index. diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index c08d928b..909311ba 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -193,6 +193,7 @@ func (list *List) Iterator() 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 { if iterator.index < iterator.list.size { @@ -223,6 +224,12 @@ func (iterator *Iterator) Index() int { return iterator.index } +// Reset sets the iterator to the initial state. +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Reset() { + iterator.index = -1 +} + // Each calls the given function once for each element, passing that element's index and value. func (list *List) Each(f func(index int, value interface{})) { iterator := list.Iterator() diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index cb7bdfc5..c5be4cfc 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -314,6 +314,7 @@ func (list *List) Iterator() 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 { if iterator.index < iterator.list.size { @@ -362,6 +363,13 @@ func (iterator *Iterator) Index() int { return iterator.index } +// Reset sets the iterator to the initial state. +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Reset() { + iterator.index = -1 + iterator.element = nil +} + // Each calls the given function once for each element, passing that element's index and value. func (list *List) Each(f func(index int, value interface{})) { iterator := list.Iterator() diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index f65f7282..4a0eb1ea 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -286,6 +286,7 @@ func (list *List) Iterator() 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 { if iterator.index < iterator.list.size { @@ -315,6 +316,13 @@ func (iterator *Iterator) Index() int { return iterator.index } +// Reset sets the iterator to the initial state. +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Reset() { + iterator.index = -1 + iterator.element = nil +} + // Each calls the given function once for each element, passing that element's index and value. func (list *List) Each(f func(index int, value interface{})) { iterator := list.Iterator() diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index f1640bfd..1b0f313d 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -140,6 +140,7 @@ func (m *Map) Iterator() 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 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. // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { return iterator.iterator.Next() @@ -164,6 +165,12 @@ func (iterator *Iterator) Key() interface{} { return iterator.iterator.Key() } +// Reset sets the iterator to the initial state. +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Reset() { + iterator.iterator.Reset() +} + // Each calls the given function once for each element, passing that element's key and value. func (m *Map) Each(f func(key interface{}, value interface{})) { iterator := m.Iterator() diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 3a0de080..9a590ff5 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -120,6 +120,7 @@ func (set *Set) Iterator() 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 { if iterator.index < iterator.tree.Size() { @@ -150,6 +151,12 @@ func (iterator *Iterator) Index() int { return iterator.index } +// Reset sets the iterator to the initial state. +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Reset() { + iterator.iterator.Reset() +} + // 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() diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index ece76a9b..07fa5611 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -111,6 +111,7 @@ func (stack *Stack) Iterator() 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 { if iterator.index < iterator.stack.Size() { @@ -142,6 +143,12 @@ func (iterator *Iterator) Index() int { return iterator.index } +// Reset sets the iterator to the initial state. +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Reset() { + iterator.index = -1 +} + // String returns a string representation of container func (stack *Stack) String() string { str := "ArrayStack\n" diff --git a/stacks/linkedliststack/linkedliststack.go b/stacks/linkedliststack/linkedliststack.go index 75f19480..f8cd31d9 100644 --- a/stacks/linkedliststack/linkedliststack.go +++ b/stacks/linkedliststack/linkedliststack.go @@ -106,6 +106,7 @@ func (stack *Stack) Iterator() 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 { if iterator.index < iterator.stack.Size() { @@ -127,6 +128,12 @@ func (iterator *Iterator) Index() int { return iterator.index } +// Reset sets the iterator to the initial state. +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Reset() { + iterator.index = -1 +} + // String returns a string representation of container func (stack *Stack) String() string { str := "LinkedListStack\n" diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index 0e5942f4..a98f65e6 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -127,6 +127,7 @@ func (heap *Heap) Iterator() 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 { if iterator.index < iterator.heap.Size() { @@ -158,6 +159,12 @@ func (iterator *Iterator) Index() int { return iterator.index } +// Reset sets the iterator to the initial state. +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Reset() { + iterator.index = -1 +} + // String returns a string representation of container func (heap *Heap) String() string { str := "BinaryHeap\n" diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index cf68bab3..01d22b4a 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -291,6 +291,7 @@ func (tree *Tree) Iterator() 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 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. // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { if iterator.node == nil { @@ -356,6 +357,12 @@ func (iterator *Iterator) Key() interface{} { return iterator.node.Key } +// Reset sets the iterator to the initial state. +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Reset() { + iterator.node = nil +} + // String returns a string representation of container func (tree *Tree) String() string { str := "RedBlackTree\n" From 3a938233a09e968142ce754ff357f99ce4d8f086 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 26 Jun 2016 21:44:23 +0200 Subject: [PATCH 068/320] - test iterator reset on all structures --- lists/arraylist/arraylist_test.go | 14 ++++++++++++++ lists/doublylinkedlist/doublylinkedlist_test.go | 14 ++++++++++++++ lists/singlylinkedlist/singlylinkedlist_test.go | 14 ++++++++++++++ maps/treemap/treemap_test.go | 16 ++++++++++++++++ sets/treeset/treeset.go | 1 + sets/treeset/treeset_test.go | 14 ++++++++++++++ stacks/arraystack/arraystack_test.go | 16 ++++++++++++++++ stacks/linkedliststack/linkedliststack_test.go | 16 ++++++++++++++++ trees/binaryheap/binaryheap_test.go | 16 ++++++++++++++++ trees/redblacktree/redblacktree_test.go | 16 ++++++++++++++++ 10 files changed, 137 insertions(+) diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 9de67da9..b4e131bd 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -379,6 +379,20 @@ func TestListIteratorPrev(t *testing.T) { } } +func TestListIteratorReset(t *testing.T) { + list := New() + it := list.Iterator() + it.Reset() + list.Add("a", "b", "c") + for it.Next() { + } + it.Reset() + 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 BenchmarkList(b *testing.B) { for i := 0; i < b.N; i++ { list := New() diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 1ff73b67..e24f3763 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -379,6 +379,20 @@ func TestListIteratorPrev(t *testing.T) { } } +func TestListIteratorReset(t *testing.T) { + list := New() + it := list.Iterator() + it.Reset() + list.Add("a", "b", "c") + for it.Next() { + } + it.Reset() + 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 BenchmarkList(b *testing.B) { for i := 0; i < b.N; i++ { list := New() diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index 53c2ad8f..6c0241d2 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -338,6 +338,20 @@ func TestListIteratorNext(t *testing.T) { } } +func TestListIteratorReset(t *testing.T) { + list := New() + it := list.Iterator() + it.Reset() + list.Add("a", "b", "c") + for it.Next() { + } + it.Reset() + 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 BenchmarkList(b *testing.B) { for i := 0; i < b.N; i++ { list := New() diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index ac4d778b..228472ca 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -406,6 +406,22 @@ func TestMapIteratorPrev(t *testing.T) { } } +func TestListIteratorReset(t *testing.T) { + m := NewWithIntComparator() + it := m.Iterator() + it.Reset() + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + for it.Next() { + } + it.Reset() + it.Next() + if key, value := it.Key(), it.Value(); key != 1 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") + } +} + func BenchmarkMap(b *testing.B) { for i := 0; i < b.N; i++ { m := NewWithIntComparator() diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 9a590ff5..43a17174 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -154,6 +154,7 @@ func (iterator *Iterator) Index() int { // Reset sets the iterator to the initial state. // Call Next() to fetch the first element if any. func (iterator *Iterator) Reset() { + iterator.index = -1 iterator.iterator.Reset() } diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index ccdb16c4..990cf3c3 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -278,6 +278,20 @@ func TestSetIteratorPrev(t *testing.T) { } } +func TestListIteratorReset(t *testing.T) { + m := NewWithStringComparator() + it := m.Iterator() + it.Reset() + m.Add("a", "b", "c") + for it.Next() { + } + it.Reset() + 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 BenchmarkSet(b *testing.B) { for i := 0; i < b.N; i++ { set := NewWithIntComparator() diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index fad4ac08..89faa43f 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -176,6 +176,22 @@ func TestStackIteratorPrev(t *testing.T) { } } +func TestListIteratorReset(t *testing.T) { + stack := New() + it := stack.Iterator() + it.Reset() + stack.Push("a") + stack.Push("b") + stack.Push("c") + for it.Next() { + } + it.Reset() + it.Next() + if index, value := it.Index(), it.Value(); index != 0 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "c") + } +} + func BenchmarkStack(b *testing.B) { for i := 0; i < b.N; i++ { stack := New() diff --git a/stacks/linkedliststack/linkedliststack_test.go b/stacks/linkedliststack/linkedliststack_test.go index 4fb00024..f9f1df0b 100644 --- a/stacks/linkedliststack/linkedliststack_test.go +++ b/stacks/linkedliststack/linkedliststack_test.go @@ -136,6 +136,22 @@ func TestStackIterator(t *testing.T) { } } +func TestListIteratorReset(t *testing.T) { + stack := New() + it := stack.Iterator() + it.Reset() + stack.Push("a") + stack.Push("b") + stack.Push("c") + for it.Next() { + } + it.Reset() + it.Next() + if index, value := it.Index(), it.Value(); index != 0 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "c") + } +} + func BenchmarkStack(b *testing.B) { for i := 0; i < b.N; i++ { stack := New() diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go index d72375a3..aed82c05 100644 --- a/trees/binaryheap/binaryheap_test.go +++ b/trees/binaryheap/binaryheap_test.go @@ -191,6 +191,22 @@ func TestBinaryHeapIteratorPrev(t *testing.T) { } } +func TestListIteratorReset(t *testing.T) { + tree := NewWithIntComparator() + it := tree.Iterator() + it.Reset() + tree.Push(2) + tree.Push(3) + tree.Push(1) + for it.Next() { + } + it.Reset() + it.Next() + if index, value := it.Index(), it.Value(); index != 0 || value != 1 { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, 1) + } +} + func BenchmarkBinaryHeap(b *testing.B) { for i := 0; i < b.N; i++ { heap := NewWithIntComparator() diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 3f5987a3..37958594 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -496,6 +496,22 @@ func TestRedBlackTreeIterator4(t *testing.T) { } } +func TestListIteratorReset(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it := tree.Iterator() + it.Reset() + for it.Next() { + } + it.Reset() + it.Next() + if key, value := it.Key(), it.Value(); key != 1 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") + } +} + func BenchmarkRedBlackTree(b *testing.B) { for i := 0; i < b.N; i++ { tree := NewWithIntComparator() From f8b0747409454b9fb4a24c087758f94da04fb775 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 26 Jun 2016 22:27:08 +0200 Subject: [PATCH 069/320] - iterator last on all structures with reversible iterators --- containers/iterator.go | 20 ++++++++++++++++++-- lists/arraylist/arraylist.go | 8 ++++++++ lists/doublylinkedlist/doublylinkedlist.go | 9 +++++++++ maps/treemap/treemap.go | 7 +++++++ sets/treeset/treeset.go | 8 ++++++++ stacks/arraystack/arraystack.go | 8 ++++++++ trees/binaryheap/binaryheap.go | 8 ++++++++ trees/redblacktree/redblacktree.go | 8 ++++++++ 8 files changed, 74 insertions(+), 2 deletions(-) diff --git a/containers/iterator.go b/containers/iterator.go index 8c08ba1f..9251550f 100644 --- a/containers/iterator.go +++ b/containers/iterator.go @@ -64,12 +64,20 @@ type IteratorWithKey interface { // 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. +// Essentially it is the same as IteratorWithIndex, but provides additional: +// +// Prev() function to enable traversal in reverse +// +// Last() function to move the iterator to the last element. type ReverseIteratorWithIndex 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. Prev() bool + // 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. + Last() bool IteratorWithIndex // Next() bool @@ -79,12 +87,20 @@ type ReverseIteratorWithIndex interface { // 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. +// Essentially it is the same as IteratorWithKey, but provides additional: +// +// Prev() function to enable traversal in reverse +// +// Last() function to move the iterator to the last element. type ReverseIteratorWithKey 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 Key() and Value(). // Modifies the state of the iterator. Prev() bool + // 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 Key() and Value(). + // Modifies the state of the iterator. + Last() bool IteratorWithKey // Next() bool diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index 909311ba..17d84d78 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -230,6 +230,14 @@ func (iterator *Iterator) Reset() { iterator.index = -1 } +// 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 { + iterator.index = iterator.list.size + return iterator.Prev() +} + // Each calls the given function once for each element, passing that element's index and value. func (list *List) Each(f func(index int, value interface{})) { iterator := list.Iterator() diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index c5be4cfc..7ef40475 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -370,6 +370,15 @@ func (iterator *Iterator) Reset() { iterator.element = nil } +// 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 { + iterator.index = iterator.list.size + iterator.element = iterator.list.last + return iterator.Prev() +} + // Each calls the given function once for each element, passing that element's index and value. func (list *List) Each(f func(index int, value interface{})) { iterator := list.Iterator() diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index 1b0f313d..424cae63 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -171,6 +171,13 @@ func (iterator *Iterator) Reset() { iterator.iterator.Reset() } +// 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 Key() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Last() bool { + return iterator.iterator.Last() +} + // Each calls the given function once for each element, passing that element's key and value. func (m *Map) Each(f func(key interface{}, value interface{})) { iterator := m.Iterator() diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 43a17174..46feceba 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -158,6 +158,14 @@ func (iterator *Iterator) Reset() { iterator.iterator.Reset() } +// 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 { + iterator.index = iterator.tree.Size() + return iterator.iterator.Last() +} + // 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() diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index 07fa5611..ea65bdd9 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -149,6 +149,14 @@ func (iterator *Iterator) Reset() { iterator.index = -1 } +// 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 { + iterator.index = iterator.stack.Size() + return iterator.Prev() +} + // String returns a string representation of container func (stack *Stack) String() string { str := "ArrayStack\n" diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index a98f65e6..e7819da4 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -165,6 +165,14 @@ func (iterator *Iterator) Reset() { iterator.index = -1 } +// 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 { + iterator.index = iterator.heap.Size() + return iterator.Prev() +} + // String returns a string representation of container func (heap *Heap) String() string { str := "BinaryHeap\n" diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 01d22b4a..b1ab99b9 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -363,6 +363,14 @@ func (iterator *Iterator) Reset() { iterator.node = nil } +// 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 Key() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Last() bool { + iterator.node = iterator.tree.Right() + return iterator.node != nil +} + // String returns a string representation of container func (tree *Tree) String() string { str := "RedBlackTree\n" From 3d1014bf630eb3263a45b388aa1f5be34e29d501 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 26 Jun 2016 22:40:49 +0200 Subject: [PATCH 070/320] - test iterator last on all structures with reversible iterators --- lists/arraylist/arraylist_test.go | 15 +++++++++++++++ .../doublylinkedlist/doublylinkedlist_test.go | 15 +++++++++++++++ maps/treemap/treemap_test.go | 16 +++++++++++++++- sets/treeset/treeset_test.go | 14 +++++++++++++- stacks/arraystack/arraystack_test.go | 19 ++++++++++++++++++- .../linkedliststack/linkedliststack_test.go | 2 +- trees/binaryheap/binaryheap_test.go | 19 ++++++++++++++++++- trees/redblacktree/redblacktree_test.go | 16 +++++++++++++++- 8 files changed, 110 insertions(+), 6 deletions(-) diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index b4e131bd..66b7499d 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -393,6 +393,21 @@ func TestListIteratorReset(t *testing.T) { } } +func TestListIteratorLast(t *testing.T) { + list := New() + it := list.Iterator() + if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + list.Add("a", "b", "c") + 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, 2, "c") + } +} + func BenchmarkList(b *testing.B) { for i := 0; i < b.N; i++ { list := New() diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index e24f3763..4a6b66a6 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -393,6 +393,21 @@ func TestListIteratorReset(t *testing.T) { } } +func TestListIteratorLast(t *testing.T) { + list := New() + it := list.Iterator() + if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + list.Add("a", "b", "c") + 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, 2, "c") + } +} + func BenchmarkList(b *testing.B) { for i := 0; i < b.N; i++ { list := New() diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 228472ca..76f13bf8 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -406,7 +406,7 @@ func TestMapIteratorPrev(t *testing.T) { } } -func TestListIteratorReset(t *testing.T) { +func TestMapIteratorReset(t *testing.T) { m := NewWithIntComparator() it := m.Iterator() it.Reset() @@ -422,6 +422,20 @@ func TestListIteratorReset(t *testing.T) { } } +func TestMapIteratorLast(t *testing.T) { + m := NewWithIntComparator() + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + it := m.Iterator() + if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if key, value := it.Key(), it.Value(); key != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") + } +} + func BenchmarkMap(b *testing.B) { for i := 0; i < b.N; i++ { m := NewWithIntComparator() diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index 990cf3c3..b645eb04 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -278,7 +278,7 @@ func TestSetIteratorPrev(t *testing.T) { } } -func TestListIteratorReset(t *testing.T) { +func TestSetIteratorReset(t *testing.T) { m := NewWithStringComparator() it := m.Iterator() it.Reset() @@ -292,6 +292,18 @@ func TestListIteratorReset(t *testing.T) { } } +func TestSetIteratorLast(t *testing.T) { + set := NewWithStringComparator() + 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 != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 3, "c") + } +} + func BenchmarkSet(b *testing.B) { for i := 0; i < b.N; i++ { set := NewWithIntComparator() diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index 89faa43f..0fd2118b 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -176,7 +176,7 @@ func TestStackIteratorPrev(t *testing.T) { } } -func TestListIteratorReset(t *testing.T) { +func TestStackIteratorReset(t *testing.T) { stack := New() it := stack.Iterator() it.Reset() @@ -192,6 +192,23 @@ func TestListIteratorReset(t *testing.T) { } } +func TestStackIteratorLast(t *testing.T) { + stack := New() + it := stack.Iterator() + if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + stack.Push("a") + stack.Push("b") + stack.Push("c") + 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 != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "a") + } +} + func BenchmarkStack(b *testing.B) { for i := 0; i < b.N; i++ { stack := New() diff --git a/stacks/linkedliststack/linkedliststack_test.go b/stacks/linkedliststack/linkedliststack_test.go index f9f1df0b..4283da05 100644 --- a/stacks/linkedliststack/linkedliststack_test.go +++ b/stacks/linkedliststack/linkedliststack_test.go @@ -136,7 +136,7 @@ func TestStackIterator(t *testing.T) { } } -func TestListIteratorReset(t *testing.T) { +func TestStackIteratorReset(t *testing.T) { stack := New() it := stack.Iterator() it.Reset() diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go index aed82c05..3f925f7c 100644 --- a/trees/binaryheap/binaryheap_test.go +++ b/trees/binaryheap/binaryheap_test.go @@ -191,7 +191,7 @@ func TestBinaryHeapIteratorPrev(t *testing.T) { } } -func TestListIteratorReset(t *testing.T) { +func TestBinaryHeapIteratorReset(t *testing.T) { tree := NewWithIntComparator() it := tree.Iterator() it.Reset() @@ -207,6 +207,23 @@ func TestListIteratorReset(t *testing.T) { } } +func TestBinaryHeapIteratorLast(t *testing.T) { + tree := NewWithIntComparator() + it := tree.Iterator() + if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + tree.Push(2) + tree.Push(3) + tree.Push(1) // [1,3,2](2 swapped with 1, hence last) + 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 != 2 { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, 2) + } +} + func BenchmarkBinaryHeap(b *testing.B) { for i := 0; i < b.N; i++ { heap := NewWithIntComparator() diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 37958594..9c321f15 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -496,7 +496,7 @@ func TestRedBlackTreeIterator4(t *testing.T) { } } -func TestListIteratorReset(t *testing.T) { +func TestRedBlackTreeIteratorReset(t *testing.T) { tree := NewWithIntComparator() tree.Put(3, "c") tree.Put(1, "a") @@ -512,6 +512,20 @@ func TestListIteratorReset(t *testing.T) { } } +func TestRedBlackTreeIteratorLast(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it := tree.Iterator() + if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if key, value := it.Key(), it.Value(); key != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") + } +} + func BenchmarkRedBlackTree(b *testing.B) { for i := 0; i < b.N; i++ { tree := NewWithIntComparator() From bdfeab4912b5ea8f1a853c290a7494ce89ae5547 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 26 Jun 2016 22:50:14 +0200 Subject: [PATCH 071/320] - iterator first on all structures with reversible iterators --- containers/iterator.go | 12 ++++++++++-- lists/arraylist/arraylist.go | 8 ++++++++ lists/doublylinkedlist/doublylinkedlist.go | 8 ++++++++ lists/singlylinkedlist/singlylinkedlist.go | 8 ++++++++ maps/treemap/treemap.go | 12 ++++++++++-- sets/treeset/treeset.go | 8 ++++++++ stacks/arraystack/arraystack.go | 8 ++++++++ stacks/linkedliststack/linkedliststack.go | 8 ++++++++ trees/binaryheap/binaryheap.go | 8 ++++++++ trees/redblacktree/redblacktree.go | 12 ++++++++++-- 10 files changed, 86 insertions(+), 6 deletions(-) diff --git a/containers/iterator.go b/containers/iterator.go index 9251550f..144151e5 100644 --- a/containers/iterator.go +++ b/containers/iterator.go @@ -42,6 +42,10 @@ type IteratorWithIndex interface { // Reset sets the iterator to the initial state. // Call Next() to fetch the first element if any. Reset() + // 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. + First() bool } // IteratorWithKey is a stateful iterator for ordered containers whose elements are key value pairs. @@ -60,6 +64,10 @@ type IteratorWithKey interface { // Reset sets the iterator to the initial state. // Call Next() to fetch the first element if any. Reset() + // 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 key and value can be retrieved by Key() and Value(). + // Modifies the state of the iterator. + First() bool } // ReverseIteratorWithIndex is stateful iterator for ordered containers whose values can be fetched by an index. @@ -94,11 +102,11 @@ type ReverseIteratorWithIndex interface { // Last() function to move the iterator to the last element. type ReverseIteratorWithKey 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 Key() and Value(). + // If Prev() returns true, then previous element's key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. Prev() bool // 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 Key() and Value(). + // If Last() returns true, then last element's key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. Last() bool diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index 17d84d78..dccfc884 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -230,6 +230,14 @@ func (iterator *Iterator) Reset() { iterator.index = -1 } +// 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 { + iterator.Reset() + return iterator.Next() +} + // 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. diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 7ef40475..7cb6778c 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -370,6 +370,14 @@ func (iterator *Iterator) Reset() { iterator.element = nil } +// 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 { + iterator.Reset() + return iterator.Next() +} + // 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. diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 4a0eb1ea..cbcf95af 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -323,6 +323,14 @@ func (iterator *Iterator) Reset() { iterator.element = nil } +// 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 { + iterator.Reset() + return iterator.Next() +} + // Each calls the given function once for each element, passing that element's index and value. func (list *List) Each(f func(index int, value interface{})) { iterator := list.Iterator() diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index 424cae63..a24e9023 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -147,7 +147,7 @@ func (iterator *Iterator) Next() bool { } // 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 Key() and Value(). +// If Prev() returns true, then previous element's key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Prev() bool { return iterator.iterator.Prev() @@ -171,8 +171,16 @@ func (iterator *Iterator) Reset() { iterator.iterator.Reset() } +// 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 key and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator +func (iterator *Iterator) First() bool { + iterator.Reset() + return iterator.Next() +} + // 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 Key() and Value(). +// If Last() returns true, then last element's key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Last() bool { return iterator.iterator.Last() diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 46feceba..d33cb812 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -158,6 +158,14 @@ func (iterator *Iterator) Reset() { iterator.iterator.Reset() } +// 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 { + iterator.Reset() + return iterator.Next() +} + // 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. diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index ea65bdd9..3539538f 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -149,6 +149,14 @@ func (iterator *Iterator) Reset() { iterator.index = -1 } +// 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 { + iterator.Reset() + return iterator.Next() +} + // 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. diff --git a/stacks/linkedliststack/linkedliststack.go b/stacks/linkedliststack/linkedliststack.go index f8cd31d9..8ca75796 100644 --- a/stacks/linkedliststack/linkedliststack.go +++ b/stacks/linkedliststack/linkedliststack.go @@ -134,6 +134,14 @@ func (iterator *Iterator) Reset() { iterator.index = -1 } +// 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 { + iterator.Reset() + return iterator.Next() +} + // String returns a string representation of container func (stack *Stack) String() string { str := "LinkedListStack\n" diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index e7819da4..5188033d 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -165,6 +165,14 @@ func (iterator *Iterator) Reset() { iterator.index = -1 } +// 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 { + iterator.Reset() + return iterator.Next() +} + // 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. diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index b1ab99b9..69c8baf9 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -319,7 +319,7 @@ func (iterator *Iterator) Next() bool { } // 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 Key() and Value(). +// If Prev() returns true, then previous element's key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Prev() bool { if iterator.node == nil { @@ -363,8 +363,16 @@ func (iterator *Iterator) Reset() { iterator.node = nil } +// 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 key and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator +func (iterator *Iterator) First() bool { + iterator.Reset() + return iterator.Next() +} + // 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 Key() and Value(). +// If Last() returns true, then last element's key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Last() bool { iterator.node = iterator.tree.Right() From cbc23a5b79203f9a468f09a79a03b0088fc1060e Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 26 Jun 2016 23:58:23 +0200 Subject: [PATCH 072/320] - test iterator first on all iterable data structures --- lists/arraylist/arraylist_test.go | 15 +++++++++++ .../doublylinkedlist/doublylinkedlist_test.go | 15 +++++++++++ .../singlylinkedlist/singlylinkedlist_test.go | 15 +++++++++++ maps/treemap/treemap_test.go | 14 ++++++++++ sets/treeset/treeset_test.go | 12 +++++++++ stacks/arraystack/arraystack_test.go | 17 ++++++++++++ .../linkedliststack/linkedliststack_test.go | 17 ++++++++++++ trees/binaryheap/binaryheap_test.go | 27 +++++++++++++++---- trees/redblacktree/redblacktree_test.go | 14 ++++++++++ 9 files changed, 141 insertions(+), 5 deletions(-) diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 66b7499d..fa2ba57b 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -393,6 +393,21 @@ func TestListIteratorReset(t *testing.T) { } } +func TestListIteratorFirst(t *testing.T) { + list := New() + it := list.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + list.Add("a", "b", "c") + 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 TestListIteratorLast(t *testing.T) { list := New() it := list.Iterator() diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 4a6b66a6..fd8495db 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -393,6 +393,21 @@ func TestListIteratorReset(t *testing.T) { } } +func TestListIteratorFirst(t *testing.T) { + list := New() + it := list.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + list.Add("a", "b", "c") + 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 TestListIteratorLast(t *testing.T) { list := New() it := list.Iterator() diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index 6c0241d2..c313347d 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -352,6 +352,21 @@ func TestListIteratorReset(t *testing.T) { } } +func TestListIteratorFirst(t *testing.T) { + list := New() + it := list.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + list.Add("a", "b", "c") + 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 BenchmarkList(b *testing.B) { for i := 0; i < b.N; i++ { list := New() diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 76f13bf8..2a4f82d3 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -422,6 +422,20 @@ func TestMapIteratorReset(t *testing.T) { } } +func TestMapIteratorFirst(t *testing.T) { + m := NewWithIntComparator() + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + it := m.Iterator() + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if key, value := it.Key(), it.Value(); key != 1 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") + } +} + func TestMapIteratorLast(t *testing.T) { m := NewWithIntComparator() m.Put(3, "c") diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index b645eb04..c419a6b5 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -292,6 +292,18 @@ func TestSetIteratorReset(t *testing.T) { } } +func TestSetIteratorFirst(t *testing.T) { + set := NewWithStringComparator() + 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 := NewWithStringComparator() set.Add("a", "b", "c") diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index 0fd2118b..b744bc1d 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -192,6 +192,23 @@ func TestStackIteratorReset(t *testing.T) { } } +func TestStackIteratorFirst(t *testing.T) { + stack := New() + it := stack.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + stack.Push("a") + stack.Push("b") + stack.Push("c") + 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 != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "c") + } +} + func TestStackIteratorLast(t *testing.T) { stack := New() it := stack.Iterator() diff --git a/stacks/linkedliststack/linkedliststack_test.go b/stacks/linkedliststack/linkedliststack_test.go index 4283da05..ce97b8ae 100644 --- a/stacks/linkedliststack/linkedliststack_test.go +++ b/stacks/linkedliststack/linkedliststack_test.go @@ -152,6 +152,23 @@ func TestStackIteratorReset(t *testing.T) { } } +func TestStackIteratorFirst(t *testing.T) { + stack := New() + it := stack.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + stack.Push("a") + stack.Push("b") + stack.Push("c") + 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 != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "c") + } +} + func BenchmarkStack(b *testing.B) { for i := 0; i < b.N; i++ { stack := New() diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go index 3f925f7c..17311a39 100644 --- a/trees/binaryheap/binaryheap_test.go +++ b/trees/binaryheap/binaryheap_test.go @@ -192,12 +192,12 @@ func TestBinaryHeapIteratorPrev(t *testing.T) { } func TestBinaryHeapIteratorReset(t *testing.T) { - tree := NewWithIntComparator() - it := tree.Iterator() + heap := NewWithIntComparator() + it := heap.Iterator() it.Reset() - tree.Push(2) - tree.Push(3) - tree.Push(1) + heap.Push(2) + heap.Push(3) + heap.Push(1) for it.Next() { } it.Reset() @@ -207,6 +207,23 @@ func TestBinaryHeapIteratorReset(t *testing.T) { } } +func TestStackIteratorFirst(t *testing.T) { + heap := NewWithIntComparator() + it := heap.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + heap.Push(3) // [3] + heap.Push(2) // [2,3] + heap.Push(1) // [1,3,2](2 swapped with 1, hence last) + 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 != 1 { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, 1) + } +} + func TestBinaryHeapIteratorLast(t *testing.T) { tree := NewWithIntComparator() it := tree.Iterator() diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 9c321f15..495b68ec 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -512,6 +512,20 @@ func TestRedBlackTreeIteratorReset(t *testing.T) { } } +func TestRedBlackTreeIteratorFirst(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it := tree.Iterator() + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if key, value := it.Key(), it.Value(); key != 1 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") + } +} + func TestRedBlackTreeIteratorLast(t *testing.T) { tree := NewWithIntComparator() tree.Put(3, "c") From 57162feff5d4a7f343b131008eaab85e8732b74b Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 27 Jun 2016 00:08:01 +0200 Subject: [PATCH 073/320] - rename Reset() to Begin() in iterators (this will allow End() which will make reverse loops more readable) --- containers/iterator.go | 18 ++++++++++++++---- lists/arraylist/arraylist.go | 6 +++--- lists/arraylist/arraylist_test.go | 6 +++--- lists/doublylinkedlist/doublylinkedlist.go | 6 +++--- .../doublylinkedlist/doublylinkedlist_test.go | 6 +++--- lists/singlylinkedlist/singlylinkedlist.go | 6 +++--- .../singlylinkedlist/singlylinkedlist_test.go | 6 +++--- maps/treemap/treemap.go | 8 ++++---- maps/treemap/treemap_test.go | 6 +++--- sets/treeset/treeset.go | 8 ++++---- sets/treeset/treeset_test.go | 6 +++--- stacks/arraystack/arraystack.go | 6 +++--- stacks/arraystack/arraystack_test.go | 6 +++--- stacks/linkedliststack/linkedliststack.go | 6 +++--- stacks/linkedliststack/linkedliststack_test.go | 6 +++--- trees/binaryheap/binaryheap.go | 6 +++--- trees/binaryheap/binaryheap_test.go | 6 +++--- trees/redblacktree/redblacktree.go | 6 +++--- trees/redblacktree/redblacktree_test.go | 6 +++--- 19 files changed, 70 insertions(+), 60 deletions(-) diff --git a/containers/iterator.go b/containers/iterator.go index 144151e5..1bd7b0ed 100644 --- a/containers/iterator.go +++ b/containers/iterator.go @@ -33,15 +33,19 @@ type IteratorWithIndex interface { // 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. Next() bool + // Value returns the current element's value. // Does not modify the state of the iterator. Value() interface{} + // Index returns the current element's index. // Does not modify the state of the iterator. Index() int - // Reset sets the iterator to the initial state. + + // Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. - Reset() + Begin() + // 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. @@ -55,15 +59,19 @@ type IteratorWithKey interface { // 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. Next() bool + // Value returns the current element's value. // Does not modify the state of the iterator. Value() interface{} + // Key returns the current element's key. // Does not modify the state of the iterator. Key() interface{} - // Reset sets the iterator to the initial state. + + // Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. - Reset() + Begin() + // 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. @@ -82,6 +90,7 @@ type ReverseIteratorWithIndex interface { // If Prev() returns true, then previous element's index and value can be retrieved by Index() and Value(). // Modifies the state of the iterator. Prev() bool + // 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. @@ -105,6 +114,7 @@ type ReverseIteratorWithKey interface { // If Prev() returns true, then previous element's key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. Prev() bool + // 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index dccfc884..57eca3c9 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -224,9 +224,9 @@ func (iterator *Iterator) Index() int { return iterator.index } -// Reset sets the iterator to the initial state. +// Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. -func (iterator *Iterator) Reset() { +func (iterator *Iterator) Begin() { iterator.index = -1 } @@ -234,7 +234,7 @@ func (iterator *Iterator) Reset() { // 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 { - iterator.Reset() + iterator.Begin() return iterator.Next() } diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index fa2ba57b..f87cfe92 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -379,14 +379,14 @@ func TestListIteratorPrev(t *testing.T) { } } -func TestListIteratorReset(t *testing.T) { +func TestListIteratorBegin(t *testing.T) { list := New() it := list.Iterator() - it.Reset() + it.Begin() list.Add("a", "b", "c") for it.Next() { } - it.Reset() + 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") diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 7cb6778c..2f5bb2e9 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -363,9 +363,9 @@ func (iterator *Iterator) Index() int { return iterator.index } -// Reset sets the iterator to the initial state. +// Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. -func (iterator *Iterator) Reset() { +func (iterator *Iterator) Begin() { iterator.index = -1 iterator.element = nil } @@ -374,7 +374,7 @@ func (iterator *Iterator) Reset() { // 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 { - iterator.Reset() + iterator.Begin() return iterator.Next() } diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index fd8495db..621c7508 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -379,14 +379,14 @@ func TestListIteratorPrev(t *testing.T) { } } -func TestListIteratorReset(t *testing.T) { +func TestListIteratorBegin(t *testing.T) { list := New() it := list.Iterator() - it.Reset() + it.Begin() list.Add("a", "b", "c") for it.Next() { } - it.Reset() + 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") diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index cbcf95af..41db2553 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -316,9 +316,9 @@ func (iterator *Iterator) Index() int { return iterator.index } -// Reset sets the iterator to the initial state. +// Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. -func (iterator *Iterator) Reset() { +func (iterator *Iterator) Begin() { iterator.index = -1 iterator.element = nil } @@ -327,7 +327,7 @@ func (iterator *Iterator) Reset() { // 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 { - iterator.Reset() + iterator.Begin() return iterator.Next() } diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index c313347d..03f9b2d1 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -338,14 +338,14 @@ func TestListIteratorNext(t *testing.T) { } } -func TestListIteratorReset(t *testing.T) { +func TestListIteratorBegin(t *testing.T) { list := New() it := list.Iterator() - it.Reset() + it.Begin() list.Add("a", "b", "c") for it.Next() { } - it.Reset() + 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") diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index a24e9023..1b531eed 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -165,17 +165,17 @@ func (iterator *Iterator) Key() interface{} { return iterator.iterator.Key() } -// Reset sets the iterator to the initial state. +// Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. -func (iterator *Iterator) Reset() { - iterator.iterator.Reset() +func (iterator *Iterator) Begin() { + iterator.iterator.Begin() } // 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator func (iterator *Iterator) First() bool { - iterator.Reset() + iterator.Begin() return iterator.Next() } diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 2a4f82d3..8b0857a8 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -406,16 +406,16 @@ func TestMapIteratorPrev(t *testing.T) { } } -func TestMapIteratorReset(t *testing.T) { +func TestMapIteratorBegin(t *testing.T) { m := NewWithIntComparator() it := m.Iterator() - it.Reset() + it.Begin() m.Put(3, "c") m.Put(1, "a") m.Put(2, "b") for it.Next() { } - it.Reset() + it.Begin() it.Next() if key, value := it.Key(), it.Value(); key != 1 || value != "a" { t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index d33cb812..8acd8041 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -151,18 +151,18 @@ func (iterator *Iterator) Index() int { return iterator.index } -// Reset sets the iterator to the initial state. +// Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. -func (iterator *Iterator) Reset() { +func (iterator *Iterator) Begin() { iterator.index = -1 - iterator.iterator.Reset() + iterator.iterator.Begin() } // 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 { - iterator.Reset() + iterator.Begin() return iterator.Next() } diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index c419a6b5..a2a78fe8 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -278,14 +278,14 @@ func TestSetIteratorPrev(t *testing.T) { } } -func TestSetIteratorReset(t *testing.T) { +func TestSetIteratorBegin(t *testing.T) { m := NewWithStringComparator() it := m.Iterator() - it.Reset() + it.Begin() m.Add("a", "b", "c") for it.Next() { } - it.Reset() + 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") diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index 3539538f..81f68370 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -143,9 +143,9 @@ func (iterator *Iterator) Index() int { return iterator.index } -// Reset sets the iterator to the initial state. +// Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. -func (iterator *Iterator) Reset() { +func (iterator *Iterator) Begin() { iterator.index = -1 } @@ -153,7 +153,7 @@ func (iterator *Iterator) Reset() { // 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 { - iterator.Reset() + iterator.Begin() return iterator.Next() } diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index b744bc1d..bb68e97e 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -176,16 +176,16 @@ func TestStackIteratorPrev(t *testing.T) { } } -func TestStackIteratorReset(t *testing.T) { +func TestStackIteratorBegin(t *testing.T) { stack := New() it := stack.Iterator() - it.Reset() + it.Begin() stack.Push("a") stack.Push("b") stack.Push("c") for it.Next() { } - it.Reset() + it.Begin() it.Next() if index, value := it.Index(), it.Value(); index != 0 || value != "c" { t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "c") diff --git a/stacks/linkedliststack/linkedliststack.go b/stacks/linkedliststack/linkedliststack.go index 8ca75796..0778f6d8 100644 --- a/stacks/linkedliststack/linkedliststack.go +++ b/stacks/linkedliststack/linkedliststack.go @@ -128,9 +128,9 @@ func (iterator *Iterator) Index() int { return iterator.index } -// Reset sets the iterator to the initial state. +// Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. -func (iterator *Iterator) Reset() { +func (iterator *Iterator) Begin() { iterator.index = -1 } @@ -138,7 +138,7 @@ func (iterator *Iterator) Reset() { // 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 { - iterator.Reset() + iterator.Begin() return iterator.Next() } diff --git a/stacks/linkedliststack/linkedliststack_test.go b/stacks/linkedliststack/linkedliststack_test.go index ce97b8ae..ec218cb6 100644 --- a/stacks/linkedliststack/linkedliststack_test.go +++ b/stacks/linkedliststack/linkedliststack_test.go @@ -136,16 +136,16 @@ func TestStackIterator(t *testing.T) { } } -func TestStackIteratorReset(t *testing.T) { +func TestStackIteratorBegin(t *testing.T) { stack := New() it := stack.Iterator() - it.Reset() + it.Begin() stack.Push("a") stack.Push("b") stack.Push("c") for it.Next() { } - it.Reset() + it.Begin() it.Next() if index, value := it.Index(), it.Value(); index != 0 || value != "c" { t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "c") diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index 5188033d..fc62d795 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -159,9 +159,9 @@ func (iterator *Iterator) Index() int { return iterator.index } -// Reset sets the iterator to the initial state. +// Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. -func (iterator *Iterator) Reset() { +func (iterator *Iterator) Begin() { iterator.index = -1 } @@ -169,7 +169,7 @@ func (iterator *Iterator) Reset() { // 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 { - iterator.Reset() + iterator.Begin() return iterator.Next() } diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go index 17311a39..83658ffa 100644 --- a/trees/binaryheap/binaryheap_test.go +++ b/trees/binaryheap/binaryheap_test.go @@ -191,16 +191,16 @@ func TestBinaryHeapIteratorPrev(t *testing.T) { } } -func TestBinaryHeapIteratorReset(t *testing.T) { +func TestBinaryHeapIteratorBegin(t *testing.T) { heap := NewWithIntComparator() it := heap.Iterator() - it.Reset() + it.Begin() heap.Push(2) heap.Push(3) heap.Push(1) for it.Next() { } - it.Reset() + it.Begin() it.Next() if index, value := it.Index(), it.Value(); index != 0 || value != 1 { t.Errorf("Got %v,%v expected %v,%v", index, value, 0, 1) diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 69c8baf9..134c74e3 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -357,9 +357,9 @@ func (iterator *Iterator) Key() interface{} { return iterator.node.Key } -// Reset sets the iterator to the initial state. +// Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. -func (iterator *Iterator) Reset() { +func (iterator *Iterator) Begin() { iterator.node = nil } @@ -367,7 +367,7 @@ func (iterator *Iterator) Reset() { // If First() returns true, then first element's key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator func (iterator *Iterator) First() bool { - iterator.Reset() + iterator.Begin() return iterator.Next() } diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 495b68ec..ab2946a8 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -496,16 +496,16 @@ func TestRedBlackTreeIterator4(t *testing.T) { } } -func TestRedBlackTreeIteratorReset(t *testing.T) { +func TestRedBlackTreeIteratorBegin(t *testing.T) { tree := NewWithIntComparator() tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") it := tree.Iterator() - it.Reset() + it.Begin() for it.Next() { } - it.Reset() + it.Begin() it.Next() if key, value := it.Key(), it.Value(); key != 1 || value != "a" { t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") From f052c960692e1691068c742cb2651155cfecb883 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 27 Jun 2016 00:41:32 +0200 Subject: [PATCH 074/320] - iterator end on reverse-iterable data structures --- containers/iterator.go | 16 ++++--- examples/main/iteratorwithindex.go | 55 ++++++++++++++++++++++ lists/arraylist/arraylist.go | 8 +++- lists/doublylinkedlist/doublylinkedlist.go | 10 +++- maps/treemap/treemap.go | 9 +++- sets/treeset/treeset.go | 9 +++- stacks/arraystack/arraystack.go | 8 +++- trees/binaryheap/binaryheap.go | 8 +++- trees/redblacktree/redblacktree.go | 11 ++++- 9 files changed, 118 insertions(+), 16 deletions(-) create mode 100644 examples/main/iteratorwithindex.go diff --git a/containers/iterator.go b/containers/iterator.go index 1bd7b0ed..56929825 100644 --- a/containers/iterator.go +++ b/containers/iterator.go @@ -85,21 +85,24 @@ type IteratorWithKey interface { // 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 { // 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. Prev() bool + // End moves the iterator past the last element (one-past-the-end). + // Call Prev() to fetch the last element if any. + End() + // 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. Last() bool IteratorWithIndex - // Next() bool - // Value() interface{} - // Index() int } // ReverseIteratorWithKey is a stateful iterator for ordered containers whose elements are key value pairs. @@ -115,13 +118,14 @@ type ReverseIteratorWithKey interface { // Modifies the state of the iterator. Prev() bool + // End moves the iterator past the last element (one-past-the-end). + // Call Prev() to fetch the last element if any. + End() + // 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. Last() bool IteratorWithKey - // Next() bool - // Value() interface{} - // Key() interface{} } diff --git a/examples/main/iteratorwithindex.go b/examples/main/iteratorwithindex.go new file mode 100644 index 00000000..6b715d44 --- /dev/null +++ b/examples/main/iteratorwithindex.go @@ -0,0 +1,55 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package main + +import ( + "fmt" + "github.com/emirpasic/gods/sets/treeset" +) + +// IteratorWithIndexExample to demonstrate basic usage of IteratorWithIndex +//func IteratorWithIndexExample() { +func main() { + set := treeset.NewWithIntComparator() + set.Add(1, 2, 3) + + // Forward iteration + it := set.Iterator() + for it.Next() { + index, value := it.Index(), it.Value() + fmt.Println("Index: ", index, "Value: ", value) + } + + // Backward iteration (reverse) + for it.Last(); ; { + index, value := it.Index(), it.Value() + fmt.Println("Index: ", index, "Value: ", value) + if !it.Prev() { + break + } + } +} diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index 57eca3c9..4e44d4a7 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -230,6 +230,12 @@ func (iterator *Iterator) Begin() { iterator.index = -1 } +// 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.index = iterator.list.size +} + // 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. @@ -242,7 +248,7 @@ func (iterator *Iterator) First() bool { // 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 { - iterator.index = iterator.list.size + iterator.End() return iterator.Prev() } diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 2f5bb2e9..184db766 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -370,6 +370,13 @@ func (iterator *Iterator) Begin() { iterator.element = nil } +// 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.index = iterator.list.size + iterator.element = iterator.list.last +} + // 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. @@ -382,8 +389,7 @@ func (iterator *Iterator) First() bool { // 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 { - iterator.index = iterator.list.size - iterator.element = iterator.list.last + iterator.End() return iterator.Prev() } diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index 1b531eed..995d25b0 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -171,12 +171,17 @@ 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator func (iterator *Iterator) First() bool { - iterator.Begin() - return iterator.Next() + return iterator.iterator.First() } // Last moves the iterator to the last element and returns true if there was a last element in the container. diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 8acd8041..6651baea 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -158,6 +158,13 @@ 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.index = iterator.tree.Size() + 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. @@ -170,7 +177,7 @@ func (iterator *Iterator) First() bool { // 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 { - iterator.index = iterator.tree.Size() + iterator.End() return iterator.iterator.Last() } diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index 81f68370..ee7cc827 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -149,6 +149,12 @@ func (iterator *Iterator) Begin() { iterator.index = -1 } +// 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.index = iterator.stack.Size() +} + // 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. @@ -161,7 +167,7 @@ func (iterator *Iterator) First() bool { // 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 { - iterator.index = iterator.stack.Size() + iterator.End() return iterator.Prev() } diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index fc62d795..4845c310 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -165,6 +165,12 @@ func (iterator *Iterator) Begin() { iterator.index = -1 } +// 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.index = iterator.heap.Size() +} + // 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. @@ -177,7 +183,7 @@ func (iterator *Iterator) First() bool { // 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 { - iterator.index = iterator.heap.Size() + iterator.End() return iterator.Prev() } diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 134c74e3..323cfac3 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -363,6 +363,13 @@ func (iterator *Iterator) Begin() { iterator.node = nil } +// 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() { + right := iterator.tree.Right() // ugly hack (TODO: use flags) + iterator.node = &Node{Parent: right, Key: right.Key} +} + // 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator @@ -375,8 +382,8 @@ func (iterator *Iterator) First() bool { // If Last() returns true, then last element's key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Last() bool { - iterator.node = iterator.tree.Right() - return iterator.node != nil + iterator.End() + return iterator.Prev() } // String returns a string representation of container From 02f40db0cf90447cb1af3f00c10e2f2eedeb2eac Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 27 Jun 2016 02:42:05 +0200 Subject: [PATCH 075/320] - test iterator end on reverse-iterable data structures - fix red-black tree --- lists/arraylist/arraylist_test.go | 25 +++++++ .../doublylinkedlist/doublylinkedlist_test.go | 25 +++++++ maps/treemap/treemap_test.go | 18 ++++- sets/treeset/treeset_test.go | 25 +++++++ stacks/arraystack/arraystack_test.go | 27 ++++++++ trees/binaryheap/binaryheap_test.go | 27 ++++++++ trees/redblacktree/redblacktree.go | 69 ++++++++++++++----- trees/redblacktree/redblacktree_test.go | 65 +++++++++++++---- 8 files changed, 249 insertions(+), 32 deletions(-) diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index f87cfe92..daf8a16c 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -393,6 +393,31 @@ func TestListIteratorBegin(t *testing.T) { } } +func TestListIteratorEnd(t *testing.T) { + list := New() + it := list.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) + } + + list.Add("a", "b", "c") + it.End() + if index := it.Index(); index != list.Size() { + t.Errorf("Got %v expected %v", index, list.Size()) + } + + it.Prev() + if index, value := it.Index(), it.Value(); index != list.Size()-1 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, list.Size()-1, "c") + } +} + func TestListIteratorFirst(t *testing.T) { list := New() it := list.Iterator() diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 621c7508..8cd9e96c 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -393,6 +393,31 @@ func TestListIteratorBegin(t *testing.T) { } } +func TestListIteratorEnd(t *testing.T) { + list := New() + it := list.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) + } + + list.Add("a", "b", "c") + it.End() + if index := it.Index(); index != list.Size() { + t.Errorf("Got %v expected %v", index, list.Size()) + } + + it.Prev() + if index, value := it.Index(), it.Value(); index != list.Size()-1 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, list.Size()-1, "c") + } +} + func TestListIteratorFirst(t *testing.T) { list := New() it := list.Iterator() diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 8b0857a8..b896f363 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -377,7 +377,6 @@ func TestMapIteratorPrev(t *testing.T) { } countDown := m.Size() for it.Prev() { - countDown-- key := it.Key() value := it.Value() switch key { @@ -399,9 +398,9 @@ func TestMapIteratorPrev(t *testing.T) { if actualValue, expectedValue := value, countDown; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } + countDown-- } - // one less that in Next(), thus "1" - if actualValue, expectedValue := countDown, 1; actualValue != expectedValue { + if actualValue, expectedValue := countDown, 0; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } @@ -422,6 +421,19 @@ func TestMapIteratorBegin(t *testing.T) { } } +func TestMapTreeIteratorEnd(t *testing.T) { + m := NewWithIntComparator() + it := m.Iterator() + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + it.End() + it.Prev() + if key, value := it.Key(), it.Value(); key != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") + } +} + func TestMapIteratorFirst(t *testing.T) { m := NewWithIntComparator() m.Put(3, "c") diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index a2a78fe8..c0d21afc 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -292,6 +292,31 @@ func TestSetIteratorBegin(t *testing.T) { } } +func TestSetIteratorEnd(t *testing.T) { + set := NewWithStringComparator() + 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 := NewWithStringComparator() set.Add("a", "b", "c") diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index bb68e97e..ed27db05 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -192,6 +192,33 @@ func TestStackIteratorBegin(t *testing.T) { } } +func TestStackIteratorEnd(t *testing.T) { + stack := New() + it := stack.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) + } + + stack.Push("a") + stack.Push("b") + stack.Push("c") + it.End() + if index := it.Index(); index != stack.Size() { + t.Errorf("Got %v expected %v", index, stack.Size()) + } + + it.Prev() + if index, value := it.Index(), it.Value(); index != stack.Size()-1 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, stack.Size()-1, "a") + } +} + func TestStackIteratorFirst(t *testing.T) { stack := New() it := stack.Iterator() diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go index 83658ffa..916f9e5d 100644 --- a/trees/binaryheap/binaryheap_test.go +++ b/trees/binaryheap/binaryheap_test.go @@ -207,6 +207,33 @@ func TestBinaryHeapIteratorBegin(t *testing.T) { } } +func TestListIteratorEnd(t *testing.T) { + heap := NewWithIntComparator() + it := heap.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) + } + + heap.Push(3) // [3] + heap.Push(2) // [2,3] + heap.Push(1) // [1,3,2](2 swapped with 1, hence last) + it.End() + if index := it.Index(); index != heap.Size() { + t.Errorf("Got %v expected %v", index, heap.Size()) + } + + it.Prev() + if index, value := it.Index(), it.Value(); index != heap.Size()-1 || value != 2 { + t.Errorf("Got %v,%v expected %v,%v", index, value, heap.Size()-1, 2) + } +} + func TestStackIteratorFirst(t *testing.T) { heap := NewWithIntComparator() it := heap.Iterator() diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 323cfac3..7d6f0833 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -280,13 +280,20 @@ func (tree *Tree) Clear() { // Iterator holding the iterator's state type Iterator struct { - tree *Tree - node *Node + tree *Tree + node *Node + position position } +type position byte + +const ( + begin, between, end position = 0, 1, 2 +) + // Iterator returns a stateful iterator whose elements are key/value pairs. func (tree *Tree) Iterator() Iterator { - return Iterator{tree: tree, node: nil} + return Iterator{tree: tree, node: nil, position: begin} } // Next moves the iterator to the next element and returns true if there was a next element in the container. @@ -294,55 +301,84 @@ func (tree *Tree) Iterator() Iterator { // 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 { - if iterator.node == nil { - iterator.node = iterator.tree.Left() - return iterator.node != nil + if iterator.position == end { + goto end + } + if iterator.position == begin { + left := iterator.tree.Left() + if left == nil { + goto end + } + iterator.node = left + goto between } if iterator.node.Right != nil { iterator.node = iterator.node.Right for iterator.node.Left != nil { iterator.node = iterator.node.Left } - return true + goto between } if iterator.node.Parent != nil { node := iterator.node for iterator.node.Parent != nil { iterator.node = iterator.node.Parent if iterator.tree.Comparator(node.Key, iterator.node.Key) <= 0 { - return true + goto between } } - iterator.node = node // fix: if parent didn't satisfy the comparator criteria } + +end: + iterator.node = nil + iterator.position = end return false + +between: + iterator.position = between + return true } // 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. func (iterator *Iterator) Prev() bool { - if iterator.node == nil { - return false + if iterator.position == begin { + goto begin + } + if iterator.position == end { + right := iterator.tree.Right() + if right == nil { + goto begin + } + iterator.node = right + goto between } if iterator.node.Left != nil { iterator.node = iterator.node.Left for iterator.node.Right != nil { iterator.node = iterator.node.Right } - return true + goto between } if iterator.node.Parent != nil { node := iterator.node for iterator.node.Parent != nil { iterator.node = iterator.node.Parent if iterator.tree.Comparator(node.Key, iterator.node.Key) >= 0 { - return true + goto between } } - iterator.node = node // fix: if parent didn't satisfy the comparator criteria } + +begin: + iterator.node = nil + iterator.position = begin return false + +between: + iterator.position = between + return true } // Value returns the current element's value. @@ -361,13 +397,14 @@ func (iterator *Iterator) Key() interface{} { // Call Next() to fetch the first element if any. func (iterator *Iterator) Begin() { iterator.node = nil + iterator.position = 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() { - right := iterator.tree.Right() // ugly hack (TODO: use flags) - iterator.node = &Node{Parent: right, Key: right.Key} + iterator.node = nil + iterator.position = end } // First moves the iterator to the first element and returns true if there was a first element in the container. diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index ab2946a8..3cc5487f 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -282,7 +282,6 @@ func TestRedBlackTreeIterator1Prev(t *testing.T) { } countDown := tree.size for it.Prev() { - countDown-- key := it.Key() switch key { case countDown: @@ -294,9 +293,9 @@ func TestRedBlackTreeIterator1Prev(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } + countDown-- } - // one less that in Next(), thus "1" - if actualValue, expectedValue := countDown, 1; actualValue != expectedValue { + if actualValue, expectedValue := countDown, 0; actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } } @@ -337,7 +336,6 @@ func TestRedBlackTreeIterator2Prev(t *testing.T) { } countDown := tree.size for it.Prev() { - countDown-- key := it.Key() switch key { case countDown: @@ -349,9 +347,9 @@ func TestRedBlackTreeIterator2Prev(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } + countDown-- } - // one less that in Next(), thus "1" - if actualValue, expectedValue := countDown, 1; actualValue != expectedValue { + if actualValue, expectedValue := countDown, 0; actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } } @@ -388,7 +386,6 @@ func TestRedBlackTreeIterator3Prev(t *testing.T) { } countDown := tree.size for it.Prev() { - countDown-- key := it.Key() switch key { case countDown: @@ -400,9 +397,9 @@ func TestRedBlackTreeIterator3Prev(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } + countDown-- } - // one less that in Next(), thus "1" - if actualValue, expectedValue := countDown, 1; actualValue != expectedValue { + if actualValue, expectedValue := countDown, 0; actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } } @@ -450,7 +447,7 @@ func TestRedBlackTreeIterator4Next(t *testing.T) { } } -func TestRedBlackTreeIterator4(t *testing.T) { +func TestRedBlackTreeIterator4Prev(t *testing.T) { tree := NewWithIntComparator() tree.Put(13, 5) tree.Put(8, 3) @@ -477,7 +474,6 @@ func TestRedBlackTreeIterator4(t *testing.T) { for it.Next() { } for it.Prev() { - count-- value := it.Value() switch value { case count: @@ -489,9 +485,9 @@ func TestRedBlackTreeIterator4(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } + count-- } - // one less that in Next(), thus "1" - if actualValue, expectedValue := count, 1; actualValue != expectedValue { + if actualValue, expectedValue := count, 0; actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } } @@ -502,16 +498,59 @@ func TestRedBlackTreeIteratorBegin(t *testing.T) { tree.Put(1, "a") tree.Put(2, "b") it := tree.Iterator() + + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + it.Begin() + + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + for it.Next() { } + it.Begin() + + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + it.Next() if key, value := it.Key(), it.Value(); key != 1 || value != "a" { t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") } } +func TestRedBlackTreeIteratorEnd(t *testing.T) { + tree := NewWithIntComparator() + it := tree.Iterator() + + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + it.End() + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it.End() + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + it.Prev() + if key, value := it.Key(), it.Value(); key != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") + } +} + func TestRedBlackTreeIteratorFirst(t *testing.T) { tree := NewWithIntComparator() tree.Put(3, "c") From e49a74aa9112c24526489ac3b075c4950c2204e3 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 27 Jun 2016 03:09:20 +0200 Subject: [PATCH 076/320] - test iterator end on reverse-iterable data structures - fix red-black tree iteration with explicit begin and end states - examples for iterators (with index and key) (with forward and reverse iteration) --- README.md | 66 +++++++++++++++++---- examples/{main => }/iteratorwithindex.go | 46 ++++++++++----- examples/iteratorwithkey.go | 75 ++++++++++++++++++++++++ 3 files changed, 163 insertions(+), 24 deletions(-) rename examples/{main => }/iteratorwithindex.go (61%) create mode 100644 examples/iteratorwithkey.go diff --git a/README.md b/README.md index ad968b90..a491abb3 100644 --- a/README.md +++ b/README.md @@ -649,8 +649,9 @@ All ordered containers have stateful iterators. Typically an iterator is obtaine #### IteratorWithIndex -A [iterator](#iterator) whose elements are referenced by an index. Typical usage: +An [iterator](#iterator) whose elements are referenced by an index. +Typical usage: ```go it := list.Iterator() for it.Next() { @@ -659,44 +660,89 @@ for it.Next() { } ``` +Other usages: +```go +if it.First() { + firstIndex, firstValue := it.Index(), it.Value() + ... +} +``` + +```go +for it.Begin(); it.Next(); { + ... +} +``` + #### IteratorWithKey -A [iterator](#iterator) whose elements are referenced by a key. Typical usage: +An [iterator](#iterator) whose elements are referenced by a key. +Typical usage: ```go -it := map.Iterator() +it := tree.Iterator() for it.Next() { key, value := it.Key(), it.Value() ... } ``` +Other usages: +```go +if it.First() { + firstKey, firstValue := it.Key(), it.Value() + ... +} +``` + +```go +for it.Begin(); it.Next(); { + ... +} +``` + #### ReverseIteratorWithIndex -A [iterator](#iterator) whose elements are referenced by an index. Typical usage: +An [iterator](#iterator) whose elements are referenced by an index. Provides all functions as [IteratorWithIndex](#iteratorwithindex), but can also be used for reverse iteration. +Typical usage of iteration in reverse: ```go it := list.Iterator() -for it.Next() { /* Move to end */ } -for it.Prev() { +for it.End(); it.Prev(); { index, value := it.Index(), it.Value() ... } ``` +Other usages: +```go +if it.Last() { + lastIndex, lastValue := it.Index(), it.Value() + ... +} +``` + #### ReverseIteratorWithKey -A [iterator](#iterator) whose elements are referenced by a key. Typical usage: +An [iterator](#iterator) whose elements are referenced by a key. Provides all functions as [IteratorWithKey](#iteratorwithkey), but can also be used for reverse iteration. +Typical usage of iteration in reverse: ```go -it := map.Iterator() -for it.Next() { /* Move to end */ } -for it.Prev() { +it := tree.Iterator() +for it.End(); it.Prev(); { key, value := it.Key(), it.Value() ... } ``` +Other usages: +```go +if it.Last() { + lastKey, lastValue := it.Key(), it.Value() + ... +} +``` + ### Enumerable Enumerable functions for ordered containers that implement [EnumerableWithIndex](#enumerablewithindex) or [EnumerableWithKey](#enumerablewithkey) interfaces. diff --git a/examples/main/iteratorwithindex.go b/examples/iteratorwithindex.go similarity index 61% rename from examples/main/iteratorwithindex.go rename to examples/iteratorwithindex.go index 6b715d44..8edfe30f 100644 --- a/examples/main/iteratorwithindex.go +++ b/examples/iteratorwithindex.go @@ -24,7 +24,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package main +package examples import ( "fmt" @@ -32,24 +32,42 @@ import ( ) // IteratorWithIndexExample to demonstrate basic usage of IteratorWithIndex -//func IteratorWithIndexExample() { -func main() { - set := treeset.NewWithIntComparator() - set.Add(1, 2, 3) - - // Forward iteration +func IteratorWithIndexExample() { + set := treeset.NewWithStringComparator() + set.Add("a", "b", "c") it := set.Iterator() + + fmt.Print("\nForward iteration\n") for it.Next() { index, value := it.Index(), it.Value() - fmt.Println("Index: ", index, "Value: ", value) + fmt.Print("[", index, ":", value, "]") // [0:a][1:b][2:c] + } + + fmt.Print("\nForward iteration (again)\n") + for it.Begin(); it.Next(); { + index, value := it.Index(), it.Value() + fmt.Print("[", index, ":", value, "]") // [0:a][1:b][2:c] + } + + fmt.Print("\nBackward iteration\n") + for it.Prev() { + index, value := it.Index(), it.Value() + fmt.Print("[", index, ":", value, "]") // [2:c][1:b][0:a] } - // Backward iteration (reverse) - for it.Last(); ; { + fmt.Print("\nBackward iteration (again)\n") + for it.End(); it.Prev(); { index, value := it.Index(), it.Value() - fmt.Println("Index: ", index, "Value: ", value) - if !it.Prev() { - break - } + fmt.Print("[", index, ":", value, "]") // [2:c][1:b][0:a] + } + + if it.First() { + fmt.Print("\nFirst index: ", it.Index()) // First index: 0 + fmt.Print("\nFirst value: ", it.Value()) // First value: a + } + + if it.Last() { + fmt.Print("\nLast index: ", it.Index()) // Last index: 3 + fmt.Print("\nLast value: ", it.Value()) // Last value: c } } diff --git a/examples/iteratorwithkey.go b/examples/iteratorwithkey.go new file mode 100644 index 00000000..51716a2d --- /dev/null +++ b/examples/iteratorwithkey.go @@ -0,0 +1,75 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package examples + +import ( + "fmt" + "github.com/emirpasic/gods/maps/treemap" +) + +// IteratorWithKeyExample to demonstrate basic usage of IteratorWithKey +func IteratorWithKeyExample() { + m := treemap.NewWithIntComparator() + m.Put(1, "a") + m.Put(2, "b") + m.Put(3, "a") + it := m.Iterator() + + fmt.Print("\nForward iteration\n") + for it.Next() { + key, value := it.Key(), it.Value() + fmt.Print("[", key, ":", value, "]") // [0:a][1:b][2:c] + } + + fmt.Print("\nForward iteration (again)\n") + for it.Begin(); it.Next(); { + key, value := it.Key(), it.Value() + fmt.Print("[", key, ":", value, "]") // [0:a][1:b][2:c] + } + + fmt.Print("\nBackward iteration\n") + for it.Prev() { + key, value := it.Key(), it.Value() + fmt.Print("[", key, ":", value, "]") // [2:c][1:b][0:a] + } + + fmt.Print("\nBackward iteration (again)\n") + for it.End(); it.Prev(); { + key, value := it.Key(), it.Value() + fmt.Print("[", key, ":", value, "]") // [2:c][1:b][0:a] + } + + if it.First() { + fmt.Print("\nFirst key: ", it.Key()) // First key: 0 + fmt.Print("\nFirst value: ", it.Value()) // First value: a + } + + if it.Last() { + fmt.Print("\nLast key: ", it.Key()) // Last key: 3 + fmt.Print("\nLast value: ", it.Value()) // Last value: c + } +} From 20229603abc2e39d931517fca787c1173958edd4 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 27 Jun 2016 04:02:52 +0200 Subject: [PATCH 077/320] - refactor all iterators and enumerables into separate files --- lists/arraylist/arraylist.go | 145 +---------------- lists/arraylist/enumerable.go | 101 ++++++++++++ lists/arraylist/iterator.go | 105 ++++++++++++ lists/doublylinkedlist/doublylinkedlist.go | 166 +------------------ lists/doublylinkedlist/enumerable.go | 101 ++++++++++++ lists/doublylinkedlist/iterator.go | 126 +++++++++++++++ lists/singlylinkedlist/enumerable.go | 101 ++++++++++++ lists/singlylinkedlist/iterator.go | 92 +++++++++++ lists/singlylinkedlist/singlylinkedlist.go | 132 +-------------- maps/hashmap/hashmap.go | 2 +- maps/treemap/enumerable.go | 105 ++++++++++++ maps/treemap/iterator.go | 99 ++++++++++++ maps/treemap/treemap.go | 137 +--------------- sets/hashset/hashset.go | 2 +- sets/treeset/enumerable.go | 96 +++++++++++ sets/treeset/iterator.go | 103 ++++++++++++ sets/treeset/treeset.go | 148 +---------------- stacks/arraystack/arraystack.go | 77 +-------- stacks/arraystack/iterator.go | 106 ++++++++++++ stacks/linkedliststack/iterator.go | 82 ++++++++++ stacks/linkedliststack/linkedliststack.go | 53 +----- trees/binaryheap/binaryheap.go | 77 +-------- trees/binaryheap/iterator.go | 106 ++++++++++++ trees/redblacktree/iterator.go | 178 +++++++++++++++++++++ trees/redblacktree/redblacktree.go | 149 +---------------- 25 files changed, 1512 insertions(+), 1077 deletions(-) create mode 100644 lists/arraylist/enumerable.go create mode 100644 lists/arraylist/iterator.go create mode 100644 lists/doublylinkedlist/enumerable.go create mode 100644 lists/doublylinkedlist/iterator.go create mode 100644 lists/singlylinkedlist/enumerable.go create mode 100644 lists/singlylinkedlist/iterator.go create mode 100644 maps/treemap/enumerable.go create mode 100644 maps/treemap/iterator.go create mode 100644 sets/treeset/enumerable.go create mode 100644 sets/treeset/iterator.go create mode 100644 stacks/arraystack/iterator.go create mode 100644 stacks/linkedliststack/iterator.go create mode 100644 trees/binaryheap/iterator.go create mode 100644 trees/redblacktree/iterator.go diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index 4e44d4a7..1ce3b87d 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -33,16 +33,13 @@ package arraylist import ( "fmt" - "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/lists" "github.com/emirpasic/gods/utils" "strings" ) -func assertInterfaceImplementation() { +func assertListImplementation() { var _ lists.List = (*List)(nil) - var _ containers.EnumerableWithIndex = (*List)(nil) - var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) } // List holds the elements in a slice @@ -180,146 +177,6 @@ func (list *List) Insert(index int, values ...interface{}) { } } -// Iterator holding the iterator's state -type Iterator struct { - list *List - index int -} - -// Iterator returns a stateful iterator whose values can be fetched by an index. -func (list *List) Iterator() Iterator { - return Iterator{list: list, index: -1} -} - -// 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 { - if iterator.index < iterator.list.size { - iterator.index++ - } - return iterator.list.withinRange(iterator.index) -} - -// 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 { - if iterator.index >= 0 { - iterator.index-- - } - return iterator.list.withinRange(iterator.index) -} - -// Value returns the current element's value. -// Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { - return iterator.list.elements[iterator.index] -} - -// Index returns the current element's index. -// Does not modify the state of the iterator. -func (iterator *Iterator) Index() int { - return 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.index = -1 -} - -// 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.index = iterator.list.size -} - -// 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 { - iterator.Begin() - return iterator.Next() -} - -// 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 { - iterator.End() - return iterator.Prev() -} - -// Each calls the given function once for each element, passing that element's index and value. -func (list *List) Each(f func(index int, value interface{})) { - iterator := list.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 (list *List) Map(f func(index int, value interface{}) interface{}) *List { - newList := &List{} - iterator := list.Iterator() - for iterator.Next() { - newList.Add(f(iterator.Index(), iterator.Value())) - } - return newList -} - -// Select returns a new container containing all elements for which the given function returns a true value. -func (list *List) Select(f func(index int, value interface{}) bool) *List { - newList := &List{} - iterator := list.Iterator() - for iterator.Next() { - if f(iterator.Index(), iterator.Value()) { - newList.Add(iterator.Value()) - } - } - return newList -} - -// Any passes each element of the collection to the given function and -// returns true if the function ever returns true for any element. -func (list *List) Any(f func(index int, value interface{}) bool) bool { - iterator := list.Iterator() - for iterator.Next() { - if f(iterator.Index(), iterator.Value()) { - return true - } - } - return false -} - -// All passes each element of the collection to the given function and -// returns true if the function returns true for all elements. -func (list *List) All(f func(index int, value interface{}) bool) bool { - iterator := list.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 (list *List) Find(f func(index int, value interface{}) bool) (int, interface{}) { - iterator := list.Iterator() - for iterator.Next() { - if f(iterator.Index(), iterator.Value()) { - return iterator.Index(), iterator.Value() - } - } - return -1, nil -} - // String returns a string representation of container func (list *List) String() string { str := "ArrayList\n" diff --git a/lists/arraylist/enumerable.go b/lists/arraylist/enumerable.go new file mode 100644 index 00000000..11f265aa --- /dev/null +++ b/lists/arraylist/enumerable.go @@ -0,0 +1,101 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package arraylist + +import "github.com/emirpasic/gods/containers" + +func assertEnumerableImplementation() { + var _ containers.EnumerableWithIndex = (*List)(nil) +} + +// Each calls the given function once for each element, passing that element's index and value. +func (list *List) Each(f func(index int, value interface{})) { + iterator := list.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 (list *List) Map(f func(index int, value interface{}) interface{}) *List { + newList := &List{} + iterator := list.Iterator() + for iterator.Next() { + newList.Add(f(iterator.Index(), iterator.Value())) + } + return newList +} + +// Select returns a new container containing all elements for which the given function returns a true value. +func (list *List) Select(f func(index int, value interface{}) bool) *List { + newList := &List{} + iterator := list.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + newList.Add(iterator.Value()) + } + } + return newList +} + +// Any passes each element of the collection to the given function and +// returns true if the function ever returns true for any element. +func (list *List) Any(f func(index int, value interface{}) bool) bool { + iterator := list.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + return true + } + } + return false +} + +// All passes each element of the collection to the given function and +// returns true if the function returns true for all elements. +func (list *List) All(f func(index int, value interface{}) bool) bool { + iterator := list.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 (list *List) Find(f func(index int, value interface{}) bool) (int, interface{}) { + iterator := list.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + return iterator.Index(), iterator.Value() + } + } + return -1, nil +} diff --git a/lists/arraylist/iterator.go b/lists/arraylist/iterator.go new file mode 100644 index 00000000..aaa58744 --- /dev/null +++ b/lists/arraylist/iterator.go @@ -0,0 +1,105 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package arraylist + +import "github.com/emirpasic/gods/containers" + +func assertIteratorImplementation() { + var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) +} + +// Iterator holding the iterator's state +type Iterator struct { + list *List + index int +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +func (list *List) Iterator() Iterator { + return Iterator{list: list, index: -1} +} + +// 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 { + if iterator.index < iterator.list.size { + iterator.index++ + } + return iterator.list.withinRange(iterator.index) +} + +// 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 { + if iterator.index >= 0 { + iterator.index-- + } + return iterator.list.withinRange(iterator.index) +} + +// Value returns the current element's value. +// Does not modify the state of the iterator. +func (iterator *Iterator) Value() interface{} { + return iterator.list.elements[iterator.index] +} + +// Index returns the current element's index. +// Does not modify the state of the iterator. +func (iterator *Iterator) Index() int { + return 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.index = -1 +} + +// 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.index = iterator.list.size +} + +// 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 { + iterator.Begin() + return iterator.Next() +} + +// 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 { + iterator.End() + return iterator.Prev() +} diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 184db766..6768b19e 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -33,16 +33,13 @@ package doublylinkedlist import ( "fmt" - "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/lists" "github.com/emirpasic/gods/utils" "strings" ) -func assertInterfaceImplementation() { +func assertListImplementation() { var _ lists.List = (*List)(nil) - var _ containers.EnumerableWithIndex = (*List)(nil) - var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) } // List holds the elements, where each element points to the next and previous element @@ -300,167 +297,6 @@ func (list *List) Insert(index int, values ...interface{}) { } } -// Iterator holding the iterator's state -type Iterator struct { - list *List - index int - element *element -} - -// Iterator returns a stateful iterator whose values can be fetched by an index. -func (list *List) Iterator() Iterator { - return Iterator{list: list, index: -1, element: nil} -} - -// 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 { - if iterator.index < iterator.list.size { - iterator.index++ - } - if !iterator.list.withinRange(iterator.index) { - iterator.element = nil - return false - } - if iterator.index != 0 { - iterator.element = iterator.element.next - } else { - iterator.element = iterator.list.first - } - return true -} - -// 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 { - if iterator.index >= 0 { - iterator.index-- - } - if !iterator.list.withinRange(iterator.index) { - iterator.element = nil - return false - } - if iterator.index == iterator.list.size-1 { - iterator.element = iterator.list.last - } else { - iterator.element = iterator.element.prev - } - return iterator.list.withinRange(iterator.index) -} - -// Value returns the current element's value. -// Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { - return iterator.element.value -} - -// Index returns the current element's index. -// Does not modify the state of the iterator. -func (iterator *Iterator) Index() int { - return 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.index = -1 - iterator.element = nil -} - -// 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.index = iterator.list.size - iterator.element = iterator.list.last -} - -// 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 { - iterator.Begin() - return iterator.Next() -} - -// 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 { - iterator.End() - return iterator.Prev() -} - -// Each calls the given function once for each element, passing that element's index and value. -func (list *List) Each(f func(index int, value interface{})) { - iterator := list.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 (list *List) Map(f func(index int, value interface{}) interface{}) *List { - newList := &List{} - iterator := list.Iterator() - for iterator.Next() { - newList.Add(f(iterator.Index(), iterator.Value())) - } - return newList -} - -// Select returns a new container containing all elements for which the given function returns a true value. -func (list *List) Select(f func(index int, value interface{}) bool) *List { - newList := &List{} - iterator := list.Iterator() - for iterator.Next() { - if f(iterator.Index(), iterator.Value()) { - newList.Add(iterator.Value()) - } - } - return newList -} - -// Any passes each element of the container to the given function and -// returns true if the function ever returns true for any element. -func (list *List) Any(f func(index int, value interface{}) bool) bool { - iterator := list.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 (list *List) All(f func(index int, value interface{}) bool) bool { - iterator := list.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 (list *List) Find(f func(index int, value interface{}) bool) (index int, value interface{}) { - iterator := list.Iterator() - for iterator.Next() { - if f(iterator.Index(), iterator.Value()) { - return iterator.Index(), iterator.Value() - } - } - return -1, nil -} - // String returns a string representation of container func (list *List) String() string { str := "DoublyLinkedList\n" diff --git a/lists/doublylinkedlist/enumerable.go b/lists/doublylinkedlist/enumerable.go new file mode 100644 index 00000000..7f439364 --- /dev/null +++ b/lists/doublylinkedlist/enumerable.go @@ -0,0 +1,101 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package doublylinkedlist + +import "github.com/emirpasic/gods/containers" + +func assertEnumerableImplementation() { + var _ containers.EnumerableWithIndex = (*List)(nil) +} + +// Each calls the given function once for each element, passing that element's index and value. +func (list *List) Each(f func(index int, value interface{})) { + iterator := list.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 (list *List) Map(f func(index int, value interface{}) interface{}) *List { + newList := &List{} + iterator := list.Iterator() + for iterator.Next() { + newList.Add(f(iterator.Index(), iterator.Value())) + } + return newList +} + +// Select returns a new container containing all elements for which the given function returns a true value. +func (list *List) Select(f func(index int, value interface{}) bool) *List { + newList := &List{} + iterator := list.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + newList.Add(iterator.Value()) + } + } + return newList +} + +// Any passes each element of the container to the given function and +// returns true if the function ever returns true for any element. +func (list *List) Any(f func(index int, value interface{}) bool) bool { + iterator := list.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 (list *List) All(f func(index int, value interface{}) bool) bool { + iterator := list.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 (list *List) Find(f func(index int, value interface{}) bool) (index int, value interface{}) { + iterator := list.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + return iterator.Index(), iterator.Value() + } + } + return -1, nil +} diff --git a/lists/doublylinkedlist/iterator.go b/lists/doublylinkedlist/iterator.go new file mode 100644 index 00000000..54e114a8 --- /dev/null +++ b/lists/doublylinkedlist/iterator.go @@ -0,0 +1,126 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package doublylinkedlist + +import "github.com/emirpasic/gods/containers" + +func assertIteratorImplementation() { + var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) +} + +// Iterator holding the iterator's state +type Iterator struct { + list *List + index int + element *element +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +func (list *List) Iterator() Iterator { + return Iterator{list: list, index: -1, element: nil} +} + +// 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 { + if iterator.index < iterator.list.size { + iterator.index++ + } + if !iterator.list.withinRange(iterator.index) { + iterator.element = nil + return false + } + if iterator.index != 0 { + iterator.element = iterator.element.next + } else { + iterator.element = iterator.list.first + } + return true +} + +// 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 { + if iterator.index >= 0 { + iterator.index-- + } + if !iterator.list.withinRange(iterator.index) { + iterator.element = nil + return false + } + if iterator.index == iterator.list.size-1 { + iterator.element = iterator.list.last + } else { + iterator.element = iterator.element.prev + } + return iterator.list.withinRange(iterator.index) +} + +// Value returns the current element's value. +// Does not modify the state of the iterator. +func (iterator *Iterator) Value() interface{} { + return iterator.element.value +} + +// Index returns the current element's index. +// Does not modify the state of the iterator. +func (iterator *Iterator) Index() int { + return 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.index = -1 + iterator.element = nil +} + +// 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.index = iterator.list.size + iterator.element = iterator.list.last +} + +// 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 { + iterator.Begin() + return iterator.Next() +} + +// 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 { + iterator.End() + return iterator.Prev() +} diff --git a/lists/singlylinkedlist/enumerable.go b/lists/singlylinkedlist/enumerable.go new file mode 100644 index 00000000..8a291a7b --- /dev/null +++ b/lists/singlylinkedlist/enumerable.go @@ -0,0 +1,101 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package singlylinkedlist + +import "github.com/emirpasic/gods/containers" + +func assertEnumerableImplementation() { + var _ containers.EnumerableWithIndex = (*List)(nil) +} + +// Each calls the given function once for each element, passing that element's index and value. +func (list *List) Each(f func(index int, value interface{})) { + iterator := list.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 (list *List) Map(f func(index int, value interface{}) interface{}) *List { + newList := &List{} + iterator := list.Iterator() + for iterator.Next() { + newList.Add(f(iterator.Index(), iterator.Value())) + } + return newList +} + +// Select returns a new container containing all elements for which the given function returns a true value. +func (list *List) Select(f func(index int, value interface{}) bool) *List { + newList := &List{} + iterator := list.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + newList.Add(iterator.Value()) + } + } + return newList +} + +// Any passes each element of the container to the given function and +// returns true if the function ever returns true for any element. +func (list *List) Any(f func(index int, value interface{}) bool) bool { + iterator := list.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 (list *List) All(f func(index int, value interface{}) bool) bool { + iterator := list.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 (list *List) Find(f func(index int, value interface{}) bool) (index int, value interface{}) { + iterator := list.Iterator() + for iterator.Next() { + if f(iterator.Index(), iterator.Value()) { + return iterator.Index(), iterator.Value() + } + } + return -1, nil +} diff --git a/lists/singlylinkedlist/iterator.go b/lists/singlylinkedlist/iterator.go new file mode 100644 index 00000000..3fb64dbd --- /dev/null +++ b/lists/singlylinkedlist/iterator.go @@ -0,0 +1,92 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package singlylinkedlist + +import "github.com/emirpasic/gods/containers" + +func assertIteratorImplementation() { + var _ containers.IteratorWithIndex = (*Iterator)(nil) +} + +// Iterator holding the iterator's state +type Iterator struct { + list *List + index int + element *element +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +func (list *List) Iterator() Iterator { + return Iterator{list: list, index: -1, element: nil} +} + +// 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 { + if iterator.index < iterator.list.size { + iterator.index++ + } + if !iterator.list.withinRange(iterator.index) { + iterator.element = nil + return false + } + if iterator.index == 0 { + iterator.element = iterator.list.first + } else { + iterator.element = iterator.element.next + } + return true +} + +// Value returns the current element's value. +// Does not modify the state of the iterator. +func (iterator *Iterator) Value() interface{} { + return iterator.element.value +} + +// Index returns the current element's index. +// Does not modify the state of the iterator. +func (iterator *Iterator) Index() int { + return 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.index = -1 + iterator.element = nil +} + +// 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 { + iterator.Begin() + return iterator.Next() +} diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 41db2553..25671cc0 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -33,16 +33,13 @@ package singlylinkedlist import ( "fmt" - "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/lists" "github.com/emirpasic/gods/utils" "strings" ) -func assertInterfaceImplementation() { +func assertListImplementation() { var _ lists.List = (*List)(nil) - var _ containers.EnumerableWithIndex = (*List)(nil) - var _ containers.IteratorWithIndex = (*Iterator)(nil) } // List holds the elements, where each element points to the next element @@ -272,133 +269,6 @@ func (list *List) Insert(index int, values ...interface{}) { } } -// Iterator holding the iterator's state -type Iterator struct { - list *List - index int - element *element -} - -// Iterator returns a stateful iterator whose values can be fetched by an index. -func (list *List) Iterator() Iterator { - return Iterator{list: list, index: -1, element: nil} -} - -// 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 { - if iterator.index < iterator.list.size { - iterator.index++ - } - if !iterator.list.withinRange(iterator.index) { - iterator.element = nil - return false - } - if iterator.index == 0 { - iterator.element = iterator.list.first - } else { - iterator.element = iterator.element.next - } - return true -} - -// Value returns the current element's value. -// Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { - return iterator.element.value -} - -// Index returns the current element's index. -// Does not modify the state of the iterator. -func (iterator *Iterator) Index() int { - return 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.index = -1 - iterator.element = nil -} - -// 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 { - iterator.Begin() - return iterator.Next() -} - -// Each calls the given function once for each element, passing that element's index and value. -func (list *List) Each(f func(index int, value interface{})) { - iterator := list.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 (list *List) Map(f func(index int, value interface{}) interface{}) *List { - newList := &List{} - iterator := list.Iterator() - for iterator.Next() { - newList.Add(f(iterator.Index(), iterator.Value())) - } - return newList -} - -// Select returns a new container containing all elements for which the given function returns a true value. -func (list *List) Select(f func(index int, value interface{}) bool) *List { - newList := &List{} - iterator := list.Iterator() - for iterator.Next() { - if f(iterator.Index(), iterator.Value()) { - newList.Add(iterator.Value()) - } - } - return newList -} - -// Any passes each element of the container to the given function and -// returns true if the function ever returns true for any element. -func (list *List) Any(f func(index int, value interface{}) bool) bool { - iterator := list.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 (list *List) All(f func(index int, value interface{}) bool) bool { - iterator := list.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 (list *List) Find(f func(index int, value interface{}) bool) (index int, value interface{}) { - iterator := list.Iterator() - for iterator.Next() { - if f(iterator.Index(), iterator.Value()) { - return iterator.Index(), iterator.Value() - } - } - return -1, nil -} - // String returns a string representation of container func (list *List) String() string { str := "SinglyLinkedList\n" diff --git a/maps/hashmap/hashmap.go b/maps/hashmap/hashmap.go index 6cb8565c..1eab5284 100644 --- a/maps/hashmap/hashmap.go +++ b/maps/hashmap/hashmap.go @@ -38,7 +38,7 @@ import ( "github.com/emirpasic/gods/maps" ) -func assertInterfaceImplementation() { +func assertMapImplementation() { var _ maps.Map = (*Map)(nil) } diff --git a/maps/treemap/enumerable.go b/maps/treemap/enumerable.go new file mode 100644 index 00000000..2957419a --- /dev/null +++ b/maps/treemap/enumerable.go @@ -0,0 +1,105 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package treemap + +import ( + "github.com/emirpasic/gods/containers" + rbt "github.com/emirpasic/gods/trees/redblacktree" +) + +func assertEnumerableImplementation() { + var _ containers.EnumerableWithKey = (*Map)(nil) +} + +// Each calls the given function once for each element, passing that element's key and value. +func (m *Map) Each(f func(key interface{}, value interface{})) { + iterator := m.Iterator() + for iterator.Next() { + f(iterator.Key(), iterator.Value()) + } +} + +// 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. +func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) *Map { + newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)} + iterator := m.Iterator() + for iterator.Next() { + key2, value2 := f(iterator.Key(), iterator.Value()) + newMap.Put(key2, value2) + } + return newMap +} + +// Select returns a new container containing all elements for which the given function returns a true value. +func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map { + newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)} + iterator := m.Iterator() + for iterator.Next() { + if f(iterator.Key(), iterator.Value()) { + newMap.Put(iterator.Key(), iterator.Value()) + } + } + return newMap +} + +// Any passes each element of the container to the given function and +// returns true if the function ever returns true for any element. +func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool { + iterator := m.Iterator() + for iterator.Next() { + if f(iterator.Key(), 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 (m *Map) All(f func(key interface{}, value interface{}) bool) bool { + iterator := m.Iterator() + for iterator.Next() { + if !f(iterator.Key(), iterator.Value()) { + return false + } + } + return true +} + +// 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. +func (m *Map) Find(f func(key interface{}, value interface{}) bool) (interface{}, interface{}) { + iterator := m.Iterator() + for iterator.Next() { + if f(iterator.Key(), iterator.Value()) { + return iterator.Key(), iterator.Value() + } + } + return nil, nil +} diff --git a/maps/treemap/iterator.go b/maps/treemap/iterator.go new file mode 100644 index 00000000..5b00a89c --- /dev/null +++ b/maps/treemap/iterator.go @@ -0,0 +1,99 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package treemap + +import ( + "github.com/emirpasic/gods/containers" + rbt "github.com/emirpasic/gods/trees/redblacktree" +) + +func assertIteratorImplementation() { + var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) +} + +// Iterator holding the iterator's state +type Iterator struct { + iterator rbt.Iterator +} + +// Iterator returns a stateful iterator whose elements are key/value pairs. +func (m *Map) Iterator() Iterator { + return Iterator{iterator: m.tree.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 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. +// 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 key and value can be retrieved by Key() 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() +} + +// Key returns the current element's key. +// Does not modify the state of the iterator. +func (iterator *Iterator) Key() interface{} { + return iterator.iterator.Key() +} + +// 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 key and value can be retrieved by Key() 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 key and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Last() bool { + return iterator.iterator.Last() +} diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index 995d25b0..3c9bb456 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -34,16 +34,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package treemap import ( - "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/maps" rbt "github.com/emirpasic/gods/trees/redblacktree" "github.com/emirpasic/gods/utils" ) -func assertInterfaceImplementation() { +func assertMapImplementation() { var _ maps.Map = (*Map)(nil) - var _ containers.EnumerableWithKey = (*Map)(nil) - var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) } // Map holds the elements in a red-black tree @@ -128,138 +125,6 @@ func (m *Map) Max() (key interface{}, value interface{}) { return nil, nil } -// Iterator holding the iterator's state -type Iterator struct { - iterator rbt.Iterator -} - -// Iterator returns a stateful iterator whose elements are key/value pairs. -func (m *Map) Iterator() Iterator { - return Iterator{iterator: m.tree.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 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. -// 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 key and value can be retrieved by Key() 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() -} - -// Key returns the current element's key. -// Does not modify the state of the iterator. -func (iterator *Iterator) Key() interface{} { - return iterator.iterator.Key() -} - -// 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 key and value can be retrieved by Key() 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 key and value can be retrieved by Key() and Value(). -// Modifies the state of the iterator. -func (iterator *Iterator) Last() bool { - return iterator.iterator.Last() -} - -// Each calls the given function once for each element, passing that element's key and value. -func (m *Map) Each(f func(key interface{}, value interface{})) { - iterator := m.Iterator() - for iterator.Next() { - f(iterator.Key(), iterator.Value()) - } -} - -// 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. -func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) *Map { - newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)} - iterator := m.Iterator() - for iterator.Next() { - key2, value2 := f(iterator.Key(), iterator.Value()) - newMap.Put(key2, value2) - } - return newMap -} - -// Select returns a new container containing all elements for which the given function returns a true value. -func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map { - newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)} - iterator := m.Iterator() - for iterator.Next() { - if f(iterator.Key(), iterator.Value()) { - newMap.Put(iterator.Key(), iterator.Value()) - } - } - return newMap -} - -// Any passes each element of the container to the given function and -// returns true if the function ever returns true for any element. -func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool { - iterator := m.Iterator() - for iterator.Next() { - if f(iterator.Key(), 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 (m *Map) All(f func(key interface{}, value interface{}) bool) bool { - iterator := m.Iterator() - for iterator.Next() { - if !f(iterator.Key(), iterator.Value()) { - return false - } - } - return true -} - -// 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. -func (m *Map) Find(f func(key interface{}, value interface{}) bool) (interface{}, interface{}) { - iterator := m.Iterator() - for iterator.Next() { - if f(iterator.Key(), iterator.Value()) { - return iterator.Key(), iterator.Value() - } - } - return nil, nil -} - // String returns a string representation of container func (m *Map) String() string { str := "TreeMap\n" diff --git a/sets/hashset/hashset.go b/sets/hashset/hashset.go index e3f44c71..41a1f47f 100644 --- a/sets/hashset/hashset.go +++ b/sets/hashset/hashset.go @@ -37,7 +37,7 @@ import ( "strings" ) -func assertInterfaceImplementation() { +func assertSetImplementation() { var _ sets.Set = (*Set)(nil) } diff --git a/sets/treeset/enumerable.go b/sets/treeset/enumerable.go new file mode 100644 index 00000000..a9c3b9e5 --- /dev/null +++ b/sets/treeset/enumerable.go @@ -0,0 +1,96 @@ +/* +Copyright (c) Emir Pasic, All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3.0 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. See the file LICENSE included +with this distribution for more information. +*/ + +package treeset + +import ( + "github.com/emirpasic/gods/containers" + rbt "github.com/emirpasic/gods/trees/redblacktree" +) + +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 := &Set{tree: rbt.NewWith(set.tree.Comparator)} + 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 := &Set{tree: rbt.NewWith(set.tree.Comparator)} + 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 +} diff --git a/sets/treeset/iterator.go b/sets/treeset/iterator.go new file mode 100644 index 00000000..5f19a212 --- /dev/null +++ b/sets/treeset/iterator.go @@ -0,0 +1,103 @@ +/* +Copyright (c) Emir Pasic, All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3.0 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. See the file LICENSE included +with this distribution for more information. +*/ + +package treeset + +import ( + "github.com/emirpasic/gods/containers" + rbt "github.com/emirpasic/gods/trees/redblacktree" +) + +func assertIteratorImplementation() { + var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +type Iterator struct { + index int + iterator rbt.Iterator + tree *rbt.Tree +} + +// Iterator holding the iterator's state +func (set *Set) Iterator() Iterator { + return Iterator{index: -1, iterator: set.tree.Iterator(), tree: set.tree} +} + +// 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 { + if iterator.index < iterator.tree.Size() { + iterator.index++ + } + 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 { + if iterator.index >= 0 { + iterator.index-- + } + 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.Key() +} + +// Index returns the current element's index. +// Does not modify the state of the iterator. +func (iterator *Iterator) Index() int { + return 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.index = -1 + 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.index = iterator.tree.Size() + 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 { + iterator.Begin() + return iterator.Next() +} + +// 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 { + iterator.End() + return iterator.iterator.Last() +} diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 6651baea..855c769c 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -25,17 +25,14 @@ package treeset import ( "fmt" - "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/sets" rbt "github.com/emirpasic/gods/trees/redblacktree" "github.com/emirpasic/gods/utils" "strings" ) -func assertInterfaceImplementation() { +func assertSetImplementation() { var _ sets.Set = (*Set)(nil) - var _ containers.EnumerableWithIndex = (*Set)(nil) - var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) } // Set holds elements in a red-black tree @@ -106,149 +103,6 @@ func (set *Set) Values() []interface{} { return set.tree.Keys() } -// Iterator returns a stateful iterator whose values can be fetched by an index. -type Iterator struct { - index int - iterator rbt.Iterator - tree *rbt.Tree -} - -// Iterator holding the iterator's state -func (set *Set) Iterator() Iterator { - return Iterator{index: -1, iterator: set.tree.Iterator(), tree: set.tree} -} - -// 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 { - if iterator.index < iterator.tree.Size() { - iterator.index++ - } - 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 { - if iterator.index >= 0 { - iterator.index-- - } - 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.Key() -} - -// Index returns the current element's index. -// Does not modify the state of the iterator. -func (iterator *Iterator) Index() int { - return 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.index = -1 - 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.index = iterator.tree.Size() - 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 { - iterator.Begin() - return iterator.Next() -} - -// 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 { - iterator.End() - return iterator.iterator.Last() -} - -// 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 := &Set{tree: rbt.NewWith(set.tree.Comparator)} - 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 := &Set{tree: rbt.NewWith(set.tree.Comparator)} - 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 -} - // String returns a string representation of container func (set *Set) String() string { str := "TreeSet\n" diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index ee7cc827..068c7206 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -33,15 +33,13 @@ package arraystack import ( "fmt" - "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/lists/arraylist" "github.com/emirpasic/gods/stacks" "strings" ) -func assertInterfaceImplementation() { +func assertStackImplementation() { var _ stacks.Stack = (*Stack)(nil) - var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) } // Stack holds elements in an array-list @@ -98,79 +96,6 @@ func (stack *Stack) Values() []interface{} { return elements } -// Iterator returns a stateful iterator whose values can be fetched by an index. -type Iterator struct { - stack *Stack - index int -} - -// Iterator returns a stateful iterator whose values can be fetched by an index. -func (stack *Stack) Iterator() Iterator { - return Iterator{stack: stack, index: -1} -} - -// 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 { - if iterator.index < iterator.stack.Size() { - iterator.index++ - } - return iterator.stack.withinRange(iterator.index) -} - -// 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 { - if iterator.index >= 0 { - iterator.index-- - } - return iterator.stack.withinRange(iterator.index) -} - -// Value returns the current element's value. -// Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { - value, _ := iterator.stack.list.Get(iterator.stack.list.Size() - iterator.index - 1) // in reverse (LIFO) - return value -} - -// Index returns the current element's index. -// Does not modify the state of the iterator. -func (iterator *Iterator) Index() int { - return 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.index = -1 -} - -// 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.index = iterator.stack.Size() -} - -// 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 { - iterator.Begin() - return iterator.Next() -} - -// 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 { - iterator.End() - return iterator.Prev() -} - // String returns a string representation of container func (stack *Stack) String() string { str := "ArrayStack\n" diff --git a/stacks/arraystack/iterator.go b/stacks/arraystack/iterator.go new file mode 100644 index 00000000..a083965d --- /dev/null +++ b/stacks/arraystack/iterator.go @@ -0,0 +1,106 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package arraystack + +import "github.com/emirpasic/gods/containers" + +func assertIteratorImplementation() { + var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +type Iterator struct { + stack *Stack + index int +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +func (stack *Stack) Iterator() Iterator { + return Iterator{stack: stack, index: -1} +} + +// 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 { + if iterator.index < iterator.stack.Size() { + iterator.index++ + } + return iterator.stack.withinRange(iterator.index) +} + +// 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 { + if iterator.index >= 0 { + iterator.index-- + } + return iterator.stack.withinRange(iterator.index) +} + +// Value returns the current element's value. +// Does not modify the state of the iterator. +func (iterator *Iterator) Value() interface{} { + value, _ := iterator.stack.list.Get(iterator.stack.list.Size() - iterator.index - 1) // in reverse (LIFO) + return value +} + +// Index returns the current element's index. +// Does not modify the state of the iterator. +func (iterator *Iterator) Index() int { + return 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.index = -1 +} + +// 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.index = iterator.stack.Size() +} + +// 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 { + iterator.Begin() + return iterator.Next() +} + +// 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 { + iterator.End() + return iterator.Prev() +} diff --git a/stacks/linkedliststack/iterator.go b/stacks/linkedliststack/iterator.go new file mode 100644 index 00000000..36e997af --- /dev/null +++ b/stacks/linkedliststack/iterator.go @@ -0,0 +1,82 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package linkedliststack + +import "github.com/emirpasic/gods/containers" + +func assertIteratorImplementation() { + var _ containers.IteratorWithIndex = (*Iterator)(nil) +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +type Iterator struct { + stack *Stack + index int +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +func (stack *Stack) Iterator() Iterator { + return Iterator{stack: stack, index: -1} +} + +// 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 { + if iterator.index < iterator.stack.Size() { + iterator.index++ + } + return iterator.stack.withinRange(iterator.index) +} + +// Value returns the current element's value. +// Does not modify the state of the iterator. +func (iterator *Iterator) Value() interface{} { + value, _ := iterator.stack.list.Get(iterator.index) // in reverse (LIFO) + return value +} + +// Index returns the current element's index. +// Does not modify the state of the iterator. +func (iterator *Iterator) Index() int { + return 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.index = -1 +} + +// 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 { + iterator.Begin() + return iterator.Next() +} diff --git a/stacks/linkedliststack/linkedliststack.go b/stacks/linkedliststack/linkedliststack.go index 0778f6d8..4bf27015 100644 --- a/stacks/linkedliststack/linkedliststack.go +++ b/stacks/linkedliststack/linkedliststack.go @@ -33,15 +33,13 @@ package linkedliststack import ( "fmt" - "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/lists/singlylinkedlist" "github.com/emirpasic/gods/stacks" "strings" ) -func assertInterfaceImplementation() { +func assertStackImplementation() { var _ stacks.Stack = (*Stack)(nil) - var _ containers.IteratorWithIndex = (*Iterator)(nil) } // Stack holds elements in a singly-linked-list @@ -93,55 +91,6 @@ func (stack *Stack) Values() []interface{} { return stack.list.Values() } -// Iterator returns a stateful iterator whose values can be fetched by an index. -type Iterator struct { - stack *Stack - index int -} - -// Iterator returns a stateful iterator whose values can be fetched by an index. -func (stack *Stack) Iterator() Iterator { - return Iterator{stack: stack, index: -1} -} - -// 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 { - if iterator.index < iterator.stack.Size() { - iterator.index++ - } - return iterator.stack.withinRange(iterator.index) -} - -// Value returns the current element's value. -// Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { - value, _ := iterator.stack.list.Get(iterator.index) // in reverse (LIFO) - return value -} - -// Index returns the current element's index. -// Does not modify the state of the iterator. -func (iterator *Iterator) Index() int { - return 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.index = -1 -} - -// 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 { - iterator.Begin() - return iterator.Next() -} - // String returns a string representation of container func (stack *Stack) String() string { str := "LinkedListStack\n" diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index 4845c310..d4a54de2 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -35,16 +35,14 @@ package binaryheap import ( "fmt" - "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/lists/arraylist" "github.com/emirpasic/gods/trees" "github.com/emirpasic/gods/utils" "strings" ) -func assertInterfaceImplementation() { +func assertTreeImplementation() { var _ trees.Tree = (*Heap)(nil) - var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) } // Heap holds elements in an array-list @@ -114,79 +112,6 @@ func (heap *Heap) Values() []interface{} { return heap.list.Values() } -// Iterator returns a stateful iterator whose values can be fetched by an index. -type Iterator struct { - heap *Heap - index int -} - -// Iterator returns a stateful iterator whose values can be fetched by an index. -func (heap *Heap) Iterator() Iterator { - return Iterator{heap: heap, index: -1} -} - -// 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 { - if iterator.index < iterator.heap.Size() { - iterator.index++ - } - return iterator.heap.withinRange(iterator.index) -} - -// 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 { - if iterator.index >= 0 { - iterator.index-- - } - return iterator.heap.withinRange(iterator.index) -} - -// Value returns the current element's value. -// Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { - value, _ := iterator.heap.list.Get(iterator.index) - return value -} - -// Index returns the current element's index. -// Does not modify the state of the iterator. -func (iterator *Iterator) Index() int { - return 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.index = -1 -} - -// 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.index = iterator.heap.Size() -} - -// 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 { - iterator.Begin() - return iterator.Next() -} - -// 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 { - iterator.End() - return iterator.Prev() -} - // String returns a string representation of container func (heap *Heap) String() string { str := "BinaryHeap\n" diff --git a/trees/binaryheap/iterator.go b/trees/binaryheap/iterator.go new file mode 100644 index 00000000..53ac2f57 --- /dev/null +++ b/trees/binaryheap/iterator.go @@ -0,0 +1,106 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package binaryheap + +import "github.com/emirpasic/gods/containers" + +func assertIteratorImplementation() { + var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +type Iterator struct { + heap *Heap + index int +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +func (heap *Heap) Iterator() Iterator { + return Iterator{heap: heap, index: -1} +} + +// 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 { + if iterator.index < iterator.heap.Size() { + iterator.index++ + } + return iterator.heap.withinRange(iterator.index) +} + +// 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 { + if iterator.index >= 0 { + iterator.index-- + } + return iterator.heap.withinRange(iterator.index) +} + +// Value returns the current element's value. +// Does not modify the state of the iterator. +func (iterator *Iterator) Value() interface{} { + value, _ := iterator.heap.list.Get(iterator.index) + return value +} + +// Index returns the current element's index. +// Does not modify the state of the iterator. +func (iterator *Iterator) Index() int { + return 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.index = -1 +} + +// 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.index = iterator.heap.Size() +} + +// 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 { + iterator.Begin() + return iterator.Next() +} + +// 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 { + iterator.End() + return iterator.Prev() +} diff --git a/trees/redblacktree/iterator.go b/trees/redblacktree/iterator.go new file mode 100644 index 00000000..e7e14ef1 --- /dev/null +++ b/trees/redblacktree/iterator.go @@ -0,0 +1,178 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package redblacktree + +import "github.com/emirpasic/gods/containers" + +func assertIteratorImplementation() { + var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) +} + +// Iterator holding the iterator's state +type Iterator struct { + tree *Tree + node *Node + position position +} + +type position byte + +const ( + begin, between, end position = 0, 1, 2 +) + +// Iterator returns a stateful iterator whose elements are key/value pairs. +func (tree *Tree) Iterator() Iterator { + return Iterator{tree: tree, node: nil, position: begin} +} + +// 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. +// Modifies the state of the iterator. +func (iterator *Iterator) Next() bool { + if iterator.position == end { + goto end + } + if iterator.position == begin { + left := iterator.tree.Left() + if left == nil { + goto end + } + iterator.node = left + goto between + } + if iterator.node.Right != nil { + iterator.node = iterator.node.Right + for iterator.node.Left != nil { + iterator.node = iterator.node.Left + } + goto between + } + if iterator.node.Parent != nil { + node := iterator.node + for iterator.node.Parent != nil { + iterator.node = iterator.node.Parent + if iterator.tree.Comparator(node.Key, iterator.node.Key) <= 0 { + goto between + } + } + } + +end: + iterator.node = nil + iterator.position = end + return false + +between: + iterator.position = between + return true +} + +// 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. +func (iterator *Iterator) Prev() bool { + if iterator.position == begin { + goto begin + } + if iterator.position == end { + right := iterator.tree.Right() + if right == nil { + goto begin + } + iterator.node = right + goto between + } + if iterator.node.Left != nil { + iterator.node = iterator.node.Left + for iterator.node.Right != nil { + iterator.node = iterator.node.Right + } + goto between + } + if iterator.node.Parent != nil { + node := iterator.node + for iterator.node.Parent != nil { + iterator.node = iterator.node.Parent + if iterator.tree.Comparator(node.Key, iterator.node.Key) >= 0 { + goto between + } + } + } + +begin: + iterator.node = nil + iterator.position = begin + return false + +between: + iterator.position = between + return true +} + +// Value returns the current element's value. +// Does not modify the state of the iterator. +func (iterator *Iterator) Value() interface{} { + return iterator.node.Value +} + +// Key returns the current element's key. +// Does not modify the state of the iterator. +func (iterator *Iterator) Key() interface{} { + return iterator.node.Key +} + +// 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.node = nil + iterator.position = 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.node = nil + iterator.position = 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 key and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator +func (iterator *Iterator) First() bool { + iterator.Begin() + return iterator.Next() +} + +// 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 key and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Last() bool { + iterator.End() + return iterator.Prev() +} diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 7d6f0833..8c1adc66 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -35,15 +35,13 @@ package redblacktree import ( "fmt" - "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/stacks/linkedliststack" "github.com/emirpasic/gods/trees" "github.com/emirpasic/gods/utils" ) -func assertInterfaceImplementation() { +func assertTreeImplementation() { var _ trees.Tree = (*Tree)(nil) - var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) } type color bool @@ -278,151 +276,6 @@ func (tree *Tree) Clear() { tree.size = 0 } -// Iterator holding the iterator's state -type Iterator struct { - tree *Tree - node *Node - position position -} - -type position byte - -const ( - begin, between, end position = 0, 1, 2 -) - -// Iterator returns a stateful iterator whose elements are key/value pairs. -func (tree *Tree) Iterator() Iterator { - return Iterator{tree: tree, node: nil, position: begin} -} - -// 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. -// Modifies the state of the iterator. -func (iterator *Iterator) Next() bool { - if iterator.position == end { - goto end - } - if iterator.position == begin { - left := iterator.tree.Left() - if left == nil { - goto end - } - iterator.node = left - goto between - } - if iterator.node.Right != nil { - iterator.node = iterator.node.Right - for iterator.node.Left != nil { - iterator.node = iterator.node.Left - } - goto between - } - if iterator.node.Parent != nil { - node := iterator.node - for iterator.node.Parent != nil { - iterator.node = iterator.node.Parent - if iterator.tree.Comparator(node.Key, iterator.node.Key) <= 0 { - goto between - } - } - } - -end: - iterator.node = nil - iterator.position = end - return false - -between: - iterator.position = between - return true -} - -// 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. -func (iterator *Iterator) Prev() bool { - if iterator.position == begin { - goto begin - } - if iterator.position == end { - right := iterator.tree.Right() - if right == nil { - goto begin - } - iterator.node = right - goto between - } - if iterator.node.Left != nil { - iterator.node = iterator.node.Left - for iterator.node.Right != nil { - iterator.node = iterator.node.Right - } - goto between - } - if iterator.node.Parent != nil { - node := iterator.node - for iterator.node.Parent != nil { - iterator.node = iterator.node.Parent - if iterator.tree.Comparator(node.Key, iterator.node.Key) >= 0 { - goto between - } - } - } - -begin: - iterator.node = nil - iterator.position = begin - return false - -between: - iterator.position = between - return true -} - -// Value returns the current element's value. -// Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { - return iterator.node.Value -} - -// Key returns the current element's key. -// Does not modify the state of the iterator. -func (iterator *Iterator) Key() interface{} { - return iterator.node.Key -} - -// 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.node = nil - iterator.position = 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.node = nil - iterator.position = 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 key and value can be retrieved by Key() and Value(). -// Modifies the state of the iterator -func (iterator *Iterator) First() bool { - iterator.Begin() - return iterator.Next() -} - -// 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 key and value can be retrieved by Key() and Value(). -// Modifies the state of the iterator. -func (iterator *Iterator) Last() bool { - iterator.End() - return iterator.Prev() -} - // String returns a string representation of container func (tree *Tree) String() string { str := "RedBlackTree\n" From 213367f1ca932600ce530ae11c8a8cc444e3a6da Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 27 Jun 2016 04:21:09 +0200 Subject: [PATCH 078/320] - replace long bsd text with short in all .go files --- containers/containers.go | 28 ++----------------- containers/containers_test.go | 28 ++----------------- containers/enumerable.go | 28 ++----------------- containers/iterator.go | 28 ++----------------- examples/arraylist.go | 28 ++----------------- examples/arraystack.go | 28 ++----------------- examples/binaryheap.go | 28 ++----------------- examples/customcomparator.go | 28 ++----------------- examples/doublylinkedlist.go | 28 ++----------------- examples/enumerablewithindex.go | 28 ++----------------- examples/enumerablewithkey.go | 28 ++----------------- examples/hashmap.go | 28 ++----------------- examples/hashset.go | 28 ++----------------- examples/iteratorwithindex.go | 28 ++----------------- examples/iteratorwithkey.go | 28 ++----------------- examples/linkedliststack.go | 28 ++----------------- examples/redblacktree.go | 28 ++----------------- examples/redblacktreeextended.go | 28 ++----------------- examples/singlylinkedlist.go | 28 ++----------------- examples/sort.go | 28 ++----------------- examples/treemap.go | 28 ++----------------- examples/treeset.go | 28 ++----------------- lists/arraylist/arraylist.go | 28 ++----------------- lists/arraylist/arraylist_test.go | 28 ++----------------- lists/arraylist/enumerable.go | 28 ++----------------- lists/arraylist/iterator.go | 28 ++----------------- lists/doublylinkedlist/doublylinkedlist.go | 28 ++----------------- .../doublylinkedlist/doublylinkedlist_test.go | 28 ++----------------- lists/doublylinkedlist/enumerable.go | 28 ++----------------- lists/doublylinkedlist/iterator.go | 28 ++----------------- lists/lists.go | 20 ++----------- lists/singlylinkedlist/enumerable.go | 28 ++----------------- lists/singlylinkedlist/iterator.go | 28 ++----------------- lists/singlylinkedlist/singlylinkedlist.go | 28 ++----------------- .../singlylinkedlist/singlylinkedlist_test.go | 28 ++----------------- maps/hashmap/hashmap.go | 28 ++----------------- maps/hashmap/hashmap_test.go | 28 ++----------------- maps/maps.go | 28 ++----------------- maps/treemap/enumerable.go | 28 ++----------------- maps/treemap/iterator.go | 28 ++----------------- maps/treemap/treemap.go | 28 ++----------------- maps/treemap/treemap_test.go | 28 ++----------------- sets/hashset/hashset.go | 28 ++----------------- sets/hashset/hashset_test.go | 28 ++----------------- sets/sets.go | 20 ++----------- sets/treeset/enumerable.go | 20 ++----------- sets/treeset/iterator.go | 20 ++----------- sets/treeset/treeset.go | 20 ++----------- sets/treeset/treeset_test.go | 20 ++----------- stacks/arraystack/arraystack.go | 28 ++----------------- stacks/arraystack/arraystack_test.go | 28 ++----------------- stacks/arraystack/iterator.go | 28 ++----------------- stacks/linkedliststack/iterator.go | 28 ++----------------- stacks/linkedliststack/linkedliststack.go | 28 ++----------------- .../linkedliststack/linkedliststack_test.go | 28 ++----------------- stacks/stacks.go | 28 ++----------------- trees/binaryheap/binaryheap.go | 28 ++----------------- trees/binaryheap/binaryheap_test.go | 28 ++----------------- trees/binaryheap/iterator.go | 28 ++----------------- trees/redblacktree/iterator.go | 28 ++----------------- trees/redblacktree/redblacktree.go | 28 ++----------------- trees/redblacktree/redblacktree_test.go | 28 ++----------------- trees/trees.go | 28 ++----------------- utils/comparator.go | 28 ++----------------- utils/comparator_test.go | 28 ++----------------- utils/sort.go | 28 ++----------------- utils/sort_test.go | 28 ++----------------- utils/utils.go | 28 ++----------------- 68 files changed, 204 insertions(+), 1652 deletions(-) diff --git a/containers/containers.go b/containers/containers.go index 6e73dea6..91a57c7d 100644 --- a/containers/containers.go +++ b/containers/containers.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 containers provides core interfaces and functions for data structures. // diff --git a/containers/containers_test.go b/containers/containers_test.go index a2da7193..94cf4f80 100644 --- a/containers/containers_test.go +++ b/containers/containers_test.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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. // All data structures must implement the container structure diff --git a/containers/enumerable.go b/containers/enumerable.go index 027de5a8..b0b56e4d 100644 --- a/containers/enumerable.go +++ b/containers/enumerable.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 containers diff --git a/containers/iterator.go b/containers/iterator.go index 56929825..f1a52a36 100644 --- a/containers/iterator.go +++ b/containers/iterator.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 containers diff --git a/examples/arraylist.go b/examples/arraylist.go index 9ef7f025..8e983fa8 100644 --- a/examples/arraylist.go +++ b/examples/arraylist.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 examples diff --git a/examples/arraystack.go b/examples/arraystack.go index 66c1144e..84c2d89c 100644 --- a/examples/arraystack.go +++ b/examples/arraystack.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 examples diff --git a/examples/binaryheap.go b/examples/binaryheap.go index 6b54661c..c56dc279 100644 --- a/examples/binaryheap.go +++ b/examples/binaryheap.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 examples diff --git a/examples/customcomparator.go b/examples/customcomparator.go index 891d33ac..4c9f8de7 100644 --- a/examples/customcomparator.go +++ b/examples/customcomparator.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 examples diff --git a/examples/doublylinkedlist.go b/examples/doublylinkedlist.go index ce181c47..95a64a21 100644 --- a/examples/doublylinkedlist.go +++ b/examples/doublylinkedlist.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 examples diff --git a/examples/enumerablewithindex.go b/examples/enumerablewithindex.go index ac9a175b..a33399ad 100644 --- a/examples/enumerablewithindex.go +++ b/examples/enumerablewithindex.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 examples diff --git a/examples/enumerablewithkey.go b/examples/enumerablewithkey.go index 191809e6..c9123abc 100644 --- a/examples/enumerablewithkey.go +++ b/examples/enumerablewithkey.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 examples diff --git a/examples/hashmap.go b/examples/hashmap.go index 01a94b4c..f49c0425 100644 --- a/examples/hashmap.go +++ b/examples/hashmap.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 examples diff --git a/examples/hashset.go b/examples/hashset.go index aa30a0d6..5fe2bd0e 100644 --- a/examples/hashset.go +++ b/examples/hashset.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 examples diff --git a/examples/iteratorwithindex.go b/examples/iteratorwithindex.go index 8edfe30f..86d6bd16 100644 --- a/examples/iteratorwithindex.go +++ b/examples/iteratorwithindex.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 examples diff --git a/examples/iteratorwithkey.go b/examples/iteratorwithkey.go index 51716a2d..94e5618e 100644 --- a/examples/iteratorwithkey.go +++ b/examples/iteratorwithkey.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 examples diff --git a/examples/linkedliststack.go b/examples/linkedliststack.go index 34a88695..46ddf408 100644 --- a/examples/linkedliststack.go +++ b/examples/linkedliststack.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 examples diff --git a/examples/redblacktree.go b/examples/redblacktree.go index 62a20af1..ad36e6c6 100644 --- a/examples/redblacktree.go +++ b/examples/redblacktree.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 examples diff --git a/examples/redblacktreeextended.go b/examples/redblacktreeextended.go index fb23614f..9823a6b9 100644 --- a/examples/redblacktreeextended.go +++ b/examples/redblacktreeextended.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 examples diff --git a/examples/singlylinkedlist.go b/examples/singlylinkedlist.go index 4bd0d8fe..5d3036ad 100644 --- a/examples/singlylinkedlist.go +++ b/examples/singlylinkedlist.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 examples diff --git a/examples/sort.go b/examples/sort.go index e2fd7136..854b95b8 100644 --- a/examples/sort.go +++ b/examples/sort.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 examples diff --git a/examples/treemap.go b/examples/treemap.go index 4177bbf7..0f4e8d65 100644 --- a/examples/treemap.go +++ b/examples/treemap.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 examples diff --git a/examples/treeset.go b/examples/treeset.go index bd0d61cb..23caa161 100644 --- a/examples/treeset.go +++ b/examples/treeset.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 examples diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index 1ce3b87d..f9e35439 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 arraylist implements the array list. // diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index daf8a16c..8f70385e 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 arraylist diff --git a/lists/arraylist/enumerable.go b/lists/arraylist/enumerable.go index 11f265aa..b3a87388 100644 --- a/lists/arraylist/enumerable.go +++ b/lists/arraylist/enumerable.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 arraylist diff --git a/lists/arraylist/iterator.go b/lists/arraylist/iterator.go index aaa58744..38a93f3a 100644 --- a/lists/arraylist/iterator.go +++ b/lists/arraylist/iterator.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 arraylist diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 6768b19e..c82575b2 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 doublylinkedlist implements the doubly-linked list. // diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 8cd9e96c..159761dc 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 doublylinkedlist diff --git a/lists/doublylinkedlist/enumerable.go b/lists/doublylinkedlist/enumerable.go index 7f439364..e6cf60fb 100644 --- a/lists/doublylinkedlist/enumerable.go +++ b/lists/doublylinkedlist/enumerable.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 doublylinkedlist diff --git a/lists/doublylinkedlist/iterator.go b/lists/doublylinkedlist/iterator.go index 54e114a8..040921d0 100644 --- a/lists/doublylinkedlist/iterator.go +++ b/lists/doublylinkedlist/iterator.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 doublylinkedlist diff --git a/lists/lists.go b/lists/lists.go index b3d9b9af..3b1d3239 100644 --- a/lists/lists.go +++ b/lists/lists.go @@ -1,20 +1,6 @@ -/* -Copyright (c) Emir Pasic, All rights reserved. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 3.0 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library. See the file LICENSE included -with this distribution for more information. -*/ +// 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 lists provides an abstract List interface. // diff --git a/lists/singlylinkedlist/enumerable.go b/lists/singlylinkedlist/enumerable.go index 8a291a7b..61ac289a 100644 --- a/lists/singlylinkedlist/enumerable.go +++ b/lists/singlylinkedlist/enumerable.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 singlylinkedlist diff --git a/lists/singlylinkedlist/iterator.go b/lists/singlylinkedlist/iterator.go index 3fb64dbd..48605c26 100644 --- a/lists/singlylinkedlist/iterator.go +++ b/lists/singlylinkedlist/iterator.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 singlylinkedlist diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 25671cc0..139925bd 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 singlylinkedlist implements the singly-linked list. // diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index 03f9b2d1..c81ba85d 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 singlylinkedlist diff --git a/maps/hashmap/hashmap.go b/maps/hashmap/hashmap.go index 1eab5284..77192332 100644 --- a/maps/hashmap/hashmap.go +++ b/maps/hashmap/hashmap.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 hashmap implements a map backed by a hash table. // diff --git a/maps/hashmap/hashmap_test.go b/maps/hashmap/hashmap_test.go index 692c616d..c4adf47f 100644 --- a/maps/hashmap/hashmap_test.go +++ b/maps/hashmap/hashmap_test.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 hashmap diff --git a/maps/maps.go b/maps/maps.go index 93f8bc0f..6ee3b23a 100644 --- a/maps/maps.go +++ b/maps/maps.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 maps provides an abstract Map interface. // diff --git a/maps/treemap/enumerable.go b/maps/treemap/enumerable.go index 2957419a..8cea6d00 100644 --- a/maps/treemap/enumerable.go +++ b/maps/treemap/enumerable.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 treemap diff --git a/maps/treemap/iterator.go b/maps/treemap/iterator.go index 5b00a89c..02b5c753 100644 --- a/maps/treemap/iterator.go +++ b/maps/treemap/iterator.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 treemap diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index 3c9bb456..e2b4233d 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 treemap implements a map backed by red-black tree. // diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index b896f363..72406673 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 treemap diff --git a/sets/hashset/hashset.go b/sets/hashset/hashset.go index 41a1f47f..9669d384 100644 --- a/sets/hashset/hashset.go +++ b/sets/hashset/hashset.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 hashset implements a set backed by a hash table. // diff --git a/sets/hashset/hashset_test.go b/sets/hashset/hashset_test.go index 2c6025d1..b84924b6 100644 --- a/sets/hashset/hashset_test.go +++ b/sets/hashset/hashset_test.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 hashset diff --git a/sets/sets.go b/sets/sets.go index b0ae9884..25732971 100644 --- a/sets/sets.go +++ b/sets/sets.go @@ -1,20 +1,6 @@ -/* -Copyright (c) Emir Pasic, All rights reserved. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 3.0 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library. See the file LICENSE included -with this distribution for more information. -*/ +// 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 sets provides an abstract Set interface. // diff --git a/sets/treeset/enumerable.go b/sets/treeset/enumerable.go index a9c3b9e5..59a0913a 100644 --- a/sets/treeset/enumerable.go +++ b/sets/treeset/enumerable.go @@ -1,20 +1,6 @@ -/* -Copyright (c) Emir Pasic, All rights reserved. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 3.0 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library. See the file LICENSE included -with this distribution for more information. -*/ +// 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 treeset diff --git a/sets/treeset/iterator.go b/sets/treeset/iterator.go index 5f19a212..2cb465f8 100644 --- a/sets/treeset/iterator.go +++ b/sets/treeset/iterator.go @@ -1,20 +1,6 @@ -/* -Copyright (c) Emir Pasic, All rights reserved. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 3.0 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library. See the file LICENSE included -with this distribution for more information. -*/ +// 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 treeset diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 855c769c..9ead6341 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -1,20 +1,6 @@ -/* -Copyright (c) Emir Pasic, All rights reserved. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 3.0 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library. See the file LICENSE included -with this distribution for more information. -*/ +// 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 treeset implements a tree backed by a red-black tree. // diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index c0d21afc..7a5c7e8d 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -1,20 +1,6 @@ -/* -Copyright (c) Emir Pasic, All rights reserved. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 3.0 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library. See the file LICENSE included -with this distribution for more information. -*/ +// 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 treeset diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index 068c7206..9a971e98 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 arraystack implements a stack backed by array list. // diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index ed27db05..5b2579fa 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 arraystack diff --git a/stacks/arraystack/iterator.go b/stacks/arraystack/iterator.go index a083965d..48f9bf88 100644 --- a/stacks/arraystack/iterator.go +++ b/stacks/arraystack/iterator.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 arraystack diff --git a/stacks/linkedliststack/iterator.go b/stacks/linkedliststack/iterator.go index 36e997af..4c7eafaf 100644 --- a/stacks/linkedliststack/iterator.go +++ b/stacks/linkedliststack/iterator.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 linkedliststack diff --git a/stacks/linkedliststack/linkedliststack.go b/stacks/linkedliststack/linkedliststack.go index 4bf27015..da5bf2f7 100644 --- a/stacks/linkedliststack/linkedliststack.go +++ b/stacks/linkedliststack/linkedliststack.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 linkedliststack implements a stack backed by a singly-linked list. // diff --git a/stacks/linkedliststack/linkedliststack_test.go b/stacks/linkedliststack/linkedliststack_test.go index ec218cb6..ae5031a4 100644 --- a/stacks/linkedliststack/linkedliststack_test.go +++ b/stacks/linkedliststack/linkedliststack_test.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 linkedliststack diff --git a/stacks/stacks.go b/stacks/stacks.go index a580d36e..b959e19f 100644 --- a/stacks/stacks.go +++ b/stacks/stacks.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 stacks provides an abstract Stack interface. // diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index d4a54de2..0ba92844 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 binaryheap implements a binary heap backed by array list. // diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go index 916f9e5d..987d806e 100644 --- a/trees/binaryheap/binaryheap_test.go +++ b/trees/binaryheap/binaryheap_test.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 binaryheap diff --git a/trees/binaryheap/iterator.go b/trees/binaryheap/iterator.go index 53ac2f57..beeb8d70 100644 --- a/trees/binaryheap/iterator.go +++ b/trees/binaryheap/iterator.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 binaryheap diff --git a/trees/redblacktree/iterator.go b/trees/redblacktree/iterator.go index e7e14ef1..90b84afe 100644 --- a/trees/redblacktree/iterator.go +++ b/trees/redblacktree/iterator.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 redblacktree diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 8c1adc66..f79d02b6 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 redblacktree implements a red-black tree. // diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 3cc5487f..cdacdeee 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 redblacktree diff --git a/trees/trees.go b/trees/trees.go index 2b235c16..a5a7427d 100644 --- a/trees/trees.go +++ b/trees/trees.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 trees provides an abstract Tree interface. // diff --git a/utils/comparator.go b/utils/comparator.go index 7dfd6988..9efab79c 100644 --- a/utils/comparator.go +++ b/utils/comparator.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 utils diff --git a/utils/comparator_test.go b/utils/comparator_test.go index 9efda990..12849f84 100644 --- a/utils/comparator_test.go +++ b/utils/comparator_test.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 utils diff --git a/utils/sort.go b/utils/sort.go index 154ce3d5..79ced1f5 100644 --- a/utils/sort.go +++ b/utils/sort.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 utils diff --git a/utils/sort_test.go b/utils/sort_test.go index f6d546f6..7831fc9b 100644 --- a/utils/sort_test.go +++ b/utils/sort_test.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 utils diff --git a/utils/utils.go b/utils/utils.go index 077c1f0a..120f1a71 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -1,28 +1,6 @@ -/* -Copyright (c) 2015, Emir Pasic -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// 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 utils provides common utility functions. // From a7ad28443d8f8ecc0e4e6b85689d75f631184afb Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 1 Jul 2016 06:48:01 +0200 Subject: [PATCH 079/320] - bidimap implemention as dual hashmap bidirectional map - tests --- maps/hashbidimap/hashbidimap.go | 102 +++++++++++++++ maps/hashbidimap/hashbidimap_test.go | 182 +++++++++++++++++++++++++++ maps/hashmap/hashmap.go | 2 +- maps/maps.go | 7 ++ 4 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 maps/hashbidimap/hashbidimap.go create mode 100644 maps/hashbidimap/hashbidimap_test.go diff --git a/maps/hashbidimap/hashbidimap.go b/maps/hashbidimap/hashbidimap.go new file mode 100644 index 00000000..11027fd5 --- /dev/null +++ b/maps/hashbidimap/hashbidimap.go @@ -0,0 +1,102 @@ +// 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 hashbidimap implements a bidirectional map backed by two hashmaps. +// +// A bidirectional map, or hash bag, is an associative data structure in which the (key,value) pairs form a one-to-one correspondence. +// Thus the binary relation is functional in each direction: value can also act as a key to key. +// A pair (a,b) thus provides a unique coupling between 'a' and 'b' so that 'b' can be found when 'a' is used as a key and 'a' can be found when 'b' is used as a key. +// +// Elements are unordered in the map. +// +// Structure is not thread safe. +// +// Reference: https://en.wikipedia.org/wiki/Bidirectional_map +package hashbidimap + +import ( + "fmt" + "github.com/emirpasic/gods/maps" + "github.com/emirpasic/gods/maps/hashmap" +) + +func assertMapImplementation() { + var _ maps.BidiMap = (*Map)(nil) +} + +// Map holds the elements in two hashmaps. +type Map struct { + forwardMap hashmap.Map + inverseMap hashmap.Map +} + +// New instantiates a bidirectional map. +func New() *Map { + return &Map{*hashmap.New(), *hashmap.New()} +} + +// Put inserts element into the map. +func (m *Map) Put(key interface{}, value interface{}) { + if valueByKey, ok := m.forwardMap.Get(key); ok { + m.inverseMap.Remove(valueByKey) + } + if keyByValue, ok := m.inverseMap.Get(value); ok { + m.forwardMap.Remove(keyByValue) + } + m.forwardMap.Put(key, value) + m.inverseMap.Put(value, key) +} + +// Get searches the element in the map by key and returns its value or nil if key is not found in map. +// Second return parameter is true if key was found, otherwise false. +func (m *Map) Get(key interface{}) (value interface{}, found bool) { + return m.forwardMap.Get(key) +} + +// GetKey searches the element in the map by value and returns its key or nil if value is not found in map. +// Second return parameter is true if value was found, otherwise false. +func (m *Map) GetKey(value interface{}) (key interface{}, found bool) { + return m.inverseMap.Get(value) +} + +// Remove removes the element from the map by key. +func (m *Map) Remove(key interface{}) { + if value, found := m.forwardMap.Get(key); found { + m.forwardMap.Remove(key) + m.inverseMap.Remove(value) + } +} + +// Empty returns true if map does not contain any elements +func (m *Map) Empty() bool { + return m.Size() == 0 +} + +// Size returns number of elements in the map. +func (m *Map) Size() int { + return m.forwardMap.Size() +} + +// Keys returns all keys (random order). +func (m *Map) Keys() []interface{} { + return m.forwardMap.Keys() +} + +// Values returns all values (random order). +func (m *Map) Values() []interface{} { + return m.inverseMap.Keys() +} + +// Clear removes all elements from the map. +func (m *Map) Clear() { + m.forwardMap.Clear() + m.inverseMap.Clear() +} + +// String returns a string representation of container +func (m *Map) String() string { + str := "HashMap\n" + str += fmt.Sprintf("%v", m.forwardMap) + return str +} diff --git a/maps/hashbidimap/hashbidimap_test.go b/maps/hashbidimap/hashbidimap_test.go new file mode 100644 index 00000000..ca46a069 --- /dev/null +++ b/maps/hashbidimap/hashbidimap_test.go @@ -0,0 +1,182 @@ +// 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 hashbidimap + +import ( + "fmt" + "testing" +) + +func TestMapPut(t *testing.T) { + m := New() + m.Put(5, "e") + m.Put(6, "f") + m.Put(7, "g") + m.Put(3, "c") + m.Put(4, "d") + m.Put(1, "x") + m.Put(2, "b") + m.Put(1, "a") //overwrite + + if actualValue := m.Size(); actualValue != 7 { + t.Errorf("Got %v expected %v", actualValue, 7) + } + if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "e", "f", "g"}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + // key,expectedValue,expectedFound + tests1 := [][]interface{}{ + {1, "a", true}, + {2, "b", true}, + {3, "c", true}, + {4, "d", true}, + {5, "e", true}, + {6, "f", true}, + {7, "g", true}, + {8, nil, false}, + } + + for _, test := range tests1 { + // retrievals + actualValue, actualFound := m.Get(test[0]) + if actualValue != test[1] || actualFound != test[2] { + t.Errorf("Got %v expected %v", actualValue, test[1]) + } + } +} + +func TestMapRemove(t *testing.T) { + m := New() + m.Put(5, "e") + m.Put(6, "f") + m.Put(7, "g") + m.Put(3, "c") + m.Put(4, "d") + m.Put(1, "x") + m.Put(2, "b") + m.Put(1, "a") //overwrite + + m.Remove(5) + m.Remove(6) + m.Remove(7) + m.Remove(8) + m.Remove(5) + + if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d"}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := m.Size(); actualValue != 4 { + t.Errorf("Got %v expected %v", actualValue, 4) + } + + tests2 := [][]interface{}{ + {1, "a", true}, + {2, "b", true}, + {3, "c", true}, + {4, "d", true}, + {5, nil, false}, + {6, nil, false}, + {7, nil, false}, + {8, nil, false}, + } + + for _, test := range tests2 { + actualValue, actualFound := m.Get(test[0]) + if actualValue != test[1] || actualFound != test[2] { + t.Errorf("Got %v expected %v", actualValue, test[1]) + } + } + + m.Remove(1) + m.Remove(4) + m.Remove(2) + m.Remove(3) + m.Remove(2) + m.Remove(2) + + if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := m.Size(); actualValue != 0 { + t.Errorf("Got %v expected %v", actualValue, 0) + } + if actualValue := m.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } +} + +func TestMapGetKey(t *testing.T) { + m := New() + m.Put(5, "e") + m.Put(6, "f") + m.Put(7, "g") + m.Put(3, "c") + m.Put(4, "d") + m.Put(1, "x") + m.Put(2, "b") + m.Put(1, "a") //overwrite + + // key,expectedValue,expectedFound + tests1 := [][]interface{}{ + {1, "a", true}, + {2, "b", true}, + {3, "c", true}, + {4, "d", true}, + {5, "e", true}, + {6, "f", true}, + {7, "g", true}, + {nil, "x", false}, + } + + for _, test := range tests1 { + // retrievals + actualValue, actualFound := m.GetKey(test[1]) + if actualValue != test[0] || actualFound != test[2] { + t.Errorf("Got %v expected %v", actualValue, test[0]) + } + } +} + +func sameElements(a []interface{}, b []interface{}) bool { + if len(a) != len(b) { + return false + } + for _, av := range a { + found := false + for _, bv := range b { + if av == bv { + found = true + break + } + } + if !found { + return false + } + } + return true +} + +func BenchmarkMap(b *testing.B) { + for i := 0; i < b.N; i++ { + m := New() + for n := 0; n < 1000; n++ { + m.Put(n, n) + } + for n := 0; n < 1000; n++ { + m.Remove(n) + } + } +} diff --git a/maps/hashmap/hashmap.go b/maps/hashmap/hashmap.go index 77192332..3f42ffc1 100644 --- a/maps/hashmap/hashmap.go +++ b/maps/hashmap/hashmap.go @@ -35,7 +35,7 @@ func (m *Map) Put(key interface{}, value interface{}) { m.m[key] = value } -// Get searches the elemnt in the map by key and returns its value or nil if key is not found in map. +// Get searches the element in the map by key and returns its value or nil if key is not found in map. // Second return parameter is true if key was found, otherwise false. func (m *Map) Get(key interface{}) (value interface{}, found bool) { value, found = m.m[key] diff --git a/maps/maps.go b/maps/maps.go index 6ee3b23a..6a0deb95 100644 --- a/maps/maps.go +++ b/maps/maps.go @@ -30,3 +30,10 @@ type Map interface { // Clear() // Values() []interface{} } + +// BidiMap interface that all bidirectional maps implement +type BidiMap interface { + GetKey(value interface{}) (key interface{}, found bool) + + Map +} From 52d942a0538c185239fa3737047f297d983ac3e0 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 1 Jul 2016 07:39:46 +0200 Subject: [PATCH 080/320] - hashbidimap documentation and example --- README.md | 49 +++++++++++++++++++++++++++++++++++++++-- examples/hashbidimap.go | 25 +++++++++++++++++++++ maps/maps.go | 2 +- 3 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 examples/hashbidimap.go diff --git a/README.md b/README.md index a491abb3..e73ffb1b 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ Implementation of various data structures and algorithms in Go. - [Maps](#maps) - [HashMap](#hashmap) - [TreeMap](#treemap) + - [HashBidiMap](#hashbidimap) - [Trees](#trees) - [RedBlackTree](#redblacktree) - [BinaryHeap](#binaryheap) @@ -53,7 +54,7 @@ type Container interface { Containers are either ordered or unordered. All ordered containers provide [stateful iterators](#iterator) and some of them allow [enumerable functions](#enumerable). -| Container | Ordered | [Iterator](#iterator) | [Enumerable](#enumerable) | Ordered by | +| Container | Ordered | [Iterator](#iterator) | [Enumerable](#enumerable) | Referenced by | | :--- | :---: | :---: | :---: | :---: | | [ArrayList](#arraylist) | yes | yes* | yes | index | | [SinglyLinkedList](#singlylinkedlist) | yes | yes | yes | index | @@ -64,9 +65,10 @@ Containers are either ordered or unordered. All ordered containers provide [stat | [ArrayStack](#arraystack) | yes | yes* | no | index | | [HashMap](#hashmap) | no | no | no | key | | [TreeMap](#treemap) | yes | yes* | yes | key | +| [HashBidiMap](#hashbidimap) | no | no | no | key* | | [RedBlackTree](#redblacktree) | yes | yes* | no | key | | [BinaryHeap](#binaryheap) | yes | yes* | no | index | -| | | *reversible | | | +| | | *reversible | | *bidirectional | ### Lists @@ -372,6 +374,16 @@ type Map interface { } ``` +A BidiMap is an extension to the Map. A bidirectional map (BidiMap), also called a hash bag, is an associative data structure in which the key-value pairs form a one-to-one relation. This relation works in both directions by allow the value to also act as a key to key, e.g. a pair (a,b) thus provides a coupling between 'a' and 'b' so that 'b' can be found when 'a' is used as a key and 'a' can be found when 'b' is used as a key. + +```go +type BidiMap interface { + GetKey(value interface{}) (key interface{}, found bool) + + Map +} +``` + #### HashMap A [map](#maps) based on hash tables. Keys are unordered. @@ -430,6 +442,35 @@ func main() { } ``` +#### HashBidiMap + +A [map](#maps) based on two hashmaps. Keys are unordered. + +Implements [BidiMap](#maps) interface. + +```go +package main + +import "github.com/emirpasic/gods/maps/hashbidimap" + +func main() { + m := hashbidimap.New() // empty + m.Put(1, "x") // 1->x + m.Put(3, "b") // 1->x, 3->b (random order) + m.Put(1, "a") // 1->a, 3->b (random order) + m.Put(2, "b") // 1->a, 2->b (random order) + _, _ = m.GetKey("a") // 1, true + _, _ = m.Get(2) // b, true + _, _ = m.Get(3) // nil, false + _ = m.Values() // []interface {}{"a", "b"} (random order) + _ = m.Keys() // []interface {}{1, 2} (random order) + m.Remove(1) // 2->b + m.Clear() // empty + m.Empty() // true + m.Size() // 0 +} +``` + ### Trees A tree is a widely used data data structure that simulates a hierarchical tree structure, with a root value and subtrees of children, represented as a set of linked nodes; thus no cyclic links. @@ -1057,6 +1098,10 @@ Collections and data structures found in other languages: Java Collections, C++ - Used in production. +**No dependencies**: + + - No external imports. + There is often a tug of war between speed and memory when crafting algorithms. We choose to optimize for speed in most cases within reasonable limits on memory consumption. Thread safety is not a concern of this project, this should be handled at a higher level. diff --git a/examples/hashbidimap.go b/examples/hashbidimap.go new file mode 100644 index 00000000..861fff90 --- /dev/null +++ b/examples/hashbidimap.go @@ -0,0 +1,25 @@ +// 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 examples + +import "github.com/emirpasic/gods/maps/hashbidimap" + +// HashBidiMapExample to demonstrate basic usage of HashMap +func HashBidiMapExample() { + m := hashbidimap.New() // empty + m.Put(1, "x") // 1->x + m.Put(3, "b") // 1->x, 3->b (random order) + m.Put(1, "a") // 1->a, 3->b (random order) + m.Put(2, "b") // 1->a, 2->b (random order) + _, _ = m.GetKey("a") // 1, true + _, _ = m.Get(2) // b, true + _, _ = m.Get(3) // nil, false + _ = m.Values() // []interface {}{"a", "b"} (random order) + _ = m.Keys() // []interface {}{1, 2} (random order) + m.Remove(1) // 2->b + m.Clear() // empty + m.Empty() // true + m.Size() // 0 +} diff --git a/maps/maps.go b/maps/maps.go index 6a0deb95..93c64c92 100644 --- a/maps/maps.go +++ b/maps/maps.go @@ -31,7 +31,7 @@ type Map interface { // Values() []interface{} } -// BidiMap interface that all bidirectional maps implement +// BidiMap interface that all bidirectional maps implement (extends the Map interface) type BidiMap interface { GetKey(value interface{}) (key interface{}, found bool) From 20e2a00f13df512798c5942b8e1b42946d8f8d93 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 2 Jul 2016 12:16:38 +0200 Subject: [PATCH 081/320] - start on treebidimap --- README.md | 7 +- maps/treebidimap/hashbidimap.go | 104 +++++++++++++++ maps/treebidimap/hashbidimap_test.go | 182 +++++++++++++++++++++++++++ 3 files changed, 290 insertions(+), 3 deletions(-) create mode 100644 maps/treebidimap/hashbidimap.go create mode 100644 maps/treebidimap/hashbidimap_test.go diff --git a/README.md b/README.md index e73ffb1b..b4983a99 100644 --- a/README.md +++ b/README.md @@ -1119,9 +1119,10 @@ For direct contributions, _pull request_ into master or ask to become a contribu Coding style: ```shell -# Install tooling: -go build github.com/golang/lint/golint -go build github.com/fzipp/gocyclo +# Install tooling and set path: +go get github.com/golang/lint/golint +go get github.com/fzipp/gocyclo +export PATH=$PATH:$GOPATH/bin # Fix errors and warnings: go fmt ./... && gofmt -s -w . && go vet ./... && go get ./... && go test ./... && golint ./... && gocyclo -avg -over 15 . diff --git a/maps/treebidimap/hashbidimap.go b/maps/treebidimap/hashbidimap.go new file mode 100644 index 00000000..a48de18a --- /dev/null +++ b/maps/treebidimap/hashbidimap.go @@ -0,0 +1,104 @@ +// 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 treebidimap implements a bidirectional map backed by a red-black tree. +// This structure guarantees that the map will be in both ascending key and value order. +// The goal with this structure is to avoid duplication of elements, which can be significant if contained elements are large. +// +// A bidirectional map, or hash bag, is an associative data structure in which the (key,value) pairs form a one-to-one correspondence. +// Thus the binary relation is functional in each direction: value can also act as a key to key. +// A pair (a,b) thus provides a unique coupling between 'a' and 'b' so that 'b' can be found when 'a' is used as a key and 'a' can be found when 'b' is used as a key. +// +// Elements are unordered in the map. +// +// Structure is not thread safe. +// +// Reference: https://en.wikipedia.org/wiki/Bidirectional_map +package treebidimap + +import ( + "fmt" + "github.com/emirpasic/gods/maps" + "github.com/emirpasic/gods/maps/hashmap" +) + +func assertMapImplementation() { + var _ maps.BidiMap = (*Map)(nil) +} + +// Map holds the elements in two hashmaps. +type Map struct { + forwardMap hashmap.Map + inverseMap hashmap.Map +} + +// New instantiates a bidirectional map. +func New() *Map { + return &Map{*hashmap.New(), *hashmap.New()} +} + +// Put inserts element into the map. +func (m *Map) Put(key interface{}, value interface{}) { + if valueByKey, ok := m.forwardMap.Get(key); ok { + m.inverseMap.Remove(valueByKey) + } + if keyByValue, ok := m.inverseMap.Get(value); ok { + m.forwardMap.Remove(keyByValue) + } + m.forwardMap.Put(key, value) + m.inverseMap.Put(value, key) +} + +// Get searches the element in the map by key and returns its value or nil if key is not found in map. +// Second return parameter is true if key was found, otherwise false. +func (m *Map) Get(key interface{}) (value interface{}, found bool) { + return m.forwardMap.Get(key) +} + +// GetKey searches the element in the map by value and returns its key or nil if value is not found in map. +// Second return parameter is true if value was found, otherwise false. +func (m *Map) GetKey(value interface{}) (key interface{}, found bool) { + return m.inverseMap.Get(value) +} + +// Remove removes the element from the map by key. +func (m *Map) Remove(key interface{}) { + if value, found := m.forwardMap.Get(key); found { + m.forwardMap.Remove(key) + m.inverseMap.Remove(value) + } +} + +// Empty returns true if map does not contain any elements +func (m *Map) Empty() bool { + return m.Size() == 0 +} + +// Size returns number of elements in the map. +func (m *Map) Size() int { + return m.forwardMap.Size() +} + +// Keys returns all keys (random order). +func (m *Map) Keys() []interface{} { + return m.forwardMap.Keys() +} + +// Values returns all values (random order). +func (m *Map) Values() []interface{} { + return m.inverseMap.Keys() +} + +// Clear removes all elements from the map. +func (m *Map) Clear() { + m.forwardMap.Clear() + m.inverseMap.Clear() +} + +// String returns a string representation of container +func (m *Map) String() string { + str := "HashMap\n" + str += fmt.Sprintf("%v", m.forwardMap) + return str +} diff --git a/maps/treebidimap/hashbidimap_test.go b/maps/treebidimap/hashbidimap_test.go new file mode 100644 index 00000000..0731c43c --- /dev/null +++ b/maps/treebidimap/hashbidimap_test.go @@ -0,0 +1,182 @@ +// 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 treebidimap + +import ( + "fmt" + "testing" +) + +func TestMapPut(t *testing.T) { + m := New() + m.Put(5, "e") + m.Put(6, "f") + m.Put(7, "g") + m.Put(3, "c") + m.Put(4, "d") + m.Put(1, "x") + m.Put(2, "b") + m.Put(1, "a") //overwrite + + if actualValue := m.Size(); actualValue != 7 { + t.Errorf("Got %v expected %v", actualValue, 7) + } + if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "e", "f", "g"}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + // key,expectedValue,expectedFound + tests1 := [][]interface{}{ + {1, "a", true}, + {2, "b", true}, + {3, "c", true}, + {4, "d", true}, + {5, "e", true}, + {6, "f", true}, + {7, "g", true}, + {8, nil, false}, + } + + for _, test := range tests1 { + // retrievals + actualValue, actualFound := m.Get(test[0]) + if actualValue != test[1] || actualFound != test[2] { + t.Errorf("Got %v expected %v", actualValue, test[1]) + } + } +} + +func TestMapRemove(t *testing.T) { + m := New() + m.Put(5, "e") + m.Put(6, "f") + m.Put(7, "g") + m.Put(3, "c") + m.Put(4, "d") + m.Put(1, "x") + m.Put(2, "b") + m.Put(1, "a") //overwrite + + m.Remove(5) + m.Remove(6) + m.Remove(7) + m.Remove(8) + m.Remove(5) + + if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d"}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := m.Size(); actualValue != 4 { + t.Errorf("Got %v expected %v", actualValue, 4) + } + + tests2 := [][]interface{}{ + {1, "a", true}, + {2, "b", true}, + {3, "c", true}, + {4, "d", true}, + {5, nil, false}, + {6, nil, false}, + {7, nil, false}, + {8, nil, false}, + } + + for _, test := range tests2 { + actualValue, actualFound := m.Get(test[0]) + if actualValue != test[1] || actualFound != test[2] { + t.Errorf("Got %v expected %v", actualValue, test[1]) + } + } + + m.Remove(1) + m.Remove(4) + m.Remove(2) + m.Remove(3) + m.Remove(2) + m.Remove(2) + + if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := m.Size(); actualValue != 0 { + t.Errorf("Got %v expected %v", actualValue, 0) + } + if actualValue := m.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } +} + +func TestMapGetKey(t *testing.T) { + m := New() + m.Put(5, "e") + m.Put(6, "f") + m.Put(7, "g") + m.Put(3, "c") + m.Put(4, "d") + m.Put(1, "x") + m.Put(2, "b") + m.Put(1, "a") //overwrite + + // key,expectedValue,expectedFound + tests1 := [][]interface{}{ + {1, "a", true}, + {2, "b", true}, + {3, "c", true}, + {4, "d", true}, + {5, "e", true}, + {6, "f", true}, + {7, "g", true}, + {nil, "x", false}, + } + + for _, test := range tests1 { + // retrievals + actualValue, actualFound := m.GetKey(test[1]) + if actualValue != test[0] || actualFound != test[2] { + t.Errorf("Got %v expected %v", actualValue, test[0]) + } + } +} + +func sameElements(a []interface{}, b []interface{}) bool { + if len(a) != len(b) { + return false + } + for _, av := range a { + found := false + for _, bv := range b { + if av == bv { + found = true + break + } + } + if !found { + return false + } + } + return true +} + +func BenchmarkMap(b *testing.B) { + for i := 0; i < b.N; i++ { + m := New() + for n := 0; n < 1000; n++ { + m.Put(n, n) + } + for n := 0; n < 1000; n++ { + m.Remove(n) + } + } +} From 0d9a0e612443bc32f9c23e78ea6bd1c706eb4683 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 3 Jul 2016 03:18:28 +0200 Subject: [PATCH 082/320] - TreeBidiMap core implemented (with tests) --- maps/hashbidimap/hashbidimap.go | 2 +- .../{hashbidimap.go => treebidimap.go} | 74 +++++++++++++------ ...ashbidimap_test.go => treebidimap_test.go} | 9 ++- 3 files changed, 56 insertions(+), 29 deletions(-) rename maps/treebidimap/{hashbidimap.go => treebidimap.go} (56%) rename maps/treebidimap/{hashbidimap_test.go => treebidimap_test.go} (94%) diff --git a/maps/hashbidimap/hashbidimap.go b/maps/hashbidimap/hashbidimap.go index 11027fd5..32985ab2 100644 --- a/maps/hashbidimap/hashbidimap.go +++ b/maps/hashbidimap/hashbidimap.go @@ -96,7 +96,7 @@ func (m *Map) Clear() { // String returns a string representation of container func (m *Map) String() string { - str := "HashMap\n" + str := "HashBidiMap\n" str += fmt.Sprintf("%v", m.forwardMap) return str } diff --git a/maps/treebidimap/hashbidimap.go b/maps/treebidimap/treebidimap.go similarity index 56% rename from maps/treebidimap/hashbidimap.go rename to maps/treebidimap/treebidimap.go index a48de18a..28555427 100644 --- a/maps/treebidimap/hashbidimap.go +++ b/maps/treebidimap/treebidimap.go @@ -2,16 +2,16 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package treebidimap implements a bidirectional map backed by a red-black tree. +// Package treebidimap implements a bidirectional map backed by two red-black tree. +// // This structure guarantees that the map will be in both ascending key and value order. -// The goal with this structure is to avoid duplication of elements, which can be significant if contained elements are large. +// +// Other than key and value ordering, the goal with this structure is to avoid duplication of elements, which can be significant if contained elements are large. // // A bidirectional map, or hash bag, is an associative data structure in which the (key,value) pairs form a one-to-one correspondence. // Thus the binary relation is functional in each direction: value can also act as a key to key. // A pair (a,b) thus provides a unique coupling between 'a' and 'b' so that 'b' can be found when 'a' is used as a key and 'a' can be found when 'b' is used as a key. // -// Elements are unordered in the map. -// // Structure is not thread safe. // // Reference: https://en.wikipedia.org/wiki/Bidirectional_map @@ -20,53 +20,79 @@ package treebidimap import ( "fmt" "github.com/emirpasic/gods/maps" - "github.com/emirpasic/gods/maps/hashmap" + "github.com/emirpasic/gods/trees/redblacktree" + "github.com/emirpasic/gods/utils" ) func assertMapImplementation() { var _ maps.BidiMap = (*Map)(nil) } -// Map holds the elements in two hashmaps. +// Map holds the elements in two red-black trees. type Map struct { - forwardMap hashmap.Map - inverseMap hashmap.Map + forwardMap redblacktree.Tree + inverseMap redblacktree.Tree +} + +type data struct { + key interface{} + value interface{} +} + +// NewWith instantiates a bidirectional map. +func NewWith(keyComparator utils.Comparator, valueComparator utils.Comparator) *Map { + return &Map{ + forwardMap: *redblacktree.NewWith(keyComparator), + inverseMap: *redblacktree.NewWith(valueComparator), + } +} + +// NewWithIntComparators instantiates a bidirectional map with the IntComparator for key and value, i.e. keys and values are of type int. +func NewWithIntComparators() *Map { + return NewWith(utils.IntComparator, utils.IntComparator) } -// New instantiates a bidirectional map. -func New() *Map { - return &Map{*hashmap.New(), *hashmap.New()} +// NewWithStringComparators instantiates a bidirectional map with the StringComparator for key and value, i.e. keys and values are of type string. +func NewWithStringComparators() *Map { + return NewWith(utils.StringComparator, utils.StringComparator) } // Put inserts element into the map. func (m *Map) Put(key interface{}, value interface{}) { - if valueByKey, ok := m.forwardMap.Get(key); ok { - m.inverseMap.Remove(valueByKey) + if d, ok := m.forwardMap.Get(key); ok { + m.inverseMap.Remove(d.(*data).value) } - if keyByValue, ok := m.inverseMap.Get(value); ok { - m.forwardMap.Remove(keyByValue) + if d, ok := m.inverseMap.Get(value); ok { + m.forwardMap.Remove(d.(*data).key) } - m.forwardMap.Put(key, value) - m.inverseMap.Put(value, key) + d := &data{key: key, value: value} + m.forwardMap.Put(key, d) + m.inverseMap.Put(value, d) } // Get searches the element in the map by key and returns its value or nil if key is not found in map. // Second return parameter is true if key was found, otherwise false. func (m *Map) Get(key interface{}) (value interface{}, found bool) { - return m.forwardMap.Get(key) + if d, ok := m.forwardMap.Get(key); ok { + return d.(*data).value, true + } + return nil, false } // GetKey searches the element in the map by value and returns its key or nil if value is not found in map. // Second return parameter is true if value was found, otherwise false. func (m *Map) GetKey(value interface{}) (key interface{}, found bool) { - return m.inverseMap.Get(value) + if d, ok := m.inverseMap.Get(value); ok { + return d.(*data).key, true + } + return nil, false } // Remove removes the element from the map by key. func (m *Map) Remove(key interface{}) { - if value, found := m.forwardMap.Get(key); found { + if d, found := m.forwardMap.Get(key); found { m.forwardMap.Remove(key) - m.inverseMap.Remove(value) + m.inverseMap.Remove(d.(*data).value) } } @@ -80,12 +106,12 @@ func (m *Map) Size() int { return m.forwardMap.Size() } -// Keys returns all keys (random order). +// Keys returns all keys (ordered). func (m *Map) Keys() []interface{} { return m.forwardMap.Keys() } -// Values returns all values (random order). +// Values returns all values (ordered). func (m *Map) Values() []interface{} { return m.inverseMap.Keys() } @@ -98,7 +124,7 @@ func (m *Map) Clear() { // String returns a string representation of container func (m *Map) String() string { - str := "HashMap\n" + str := "TreeBidiMap\n" str += fmt.Sprintf("%v", m.forwardMap) return str } diff --git a/maps/treebidimap/hashbidimap_test.go b/maps/treebidimap/treebidimap_test.go similarity index 94% rename from maps/treebidimap/hashbidimap_test.go rename to maps/treebidimap/treebidimap_test.go index 0731c43c..fb95840f 100644 --- a/maps/treebidimap/hashbidimap_test.go +++ b/maps/treebidimap/treebidimap_test.go @@ -6,11 +6,12 @@ package treebidimap import ( "fmt" + "github.com/emirpasic/gods/utils" "testing" ) func TestMapPut(t *testing.T) { - m := New() + m := NewWith(utils.IntComparator, utils.StringComparator) m.Put(5, "e") m.Put(6, "f") m.Put(7, "g") @@ -52,7 +53,7 @@ func TestMapPut(t *testing.T) { } func TestMapRemove(t *testing.T) { - m := New() + m := NewWith(utils.IntComparator, utils.StringComparator) m.Put(5, "e") m.Put(6, "f") m.Put(7, "g") @@ -119,7 +120,7 @@ func TestMapRemove(t *testing.T) { } func TestMapGetKey(t *testing.T) { - m := New() + m := NewWith(utils.IntComparator, utils.StringComparator) m.Put(5, "e") m.Put(6, "f") m.Put(7, "g") @@ -171,7 +172,7 @@ func sameElements(a []interface{}, b []interface{}) bool { func BenchmarkMap(b *testing.B) { for i := 0; i < b.N; i++ { - m := New() + m := NewWithIntComparators() for n := 0; n < 1000; n++ { m.Put(n, n) } From cec0ec524f962bffc9e0d269519531095a110913 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 3 Jul 2016 03:26:14 +0200 Subject: [PATCH 083/320] - TreeBidiMap iterator implemented (with tests) --- maps/treebidimap/iterator.go | 77 ++++++++++++++ maps/treebidimap/treebidimap_test.go | 151 +++++++++++++++++++++++++++ 2 files changed, 228 insertions(+) create mode 100644 maps/treebidimap/iterator.go diff --git a/maps/treebidimap/iterator.go b/maps/treebidimap/iterator.go new file mode 100644 index 00000000..af9e27ae --- /dev/null +++ b/maps/treebidimap/iterator.go @@ -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 treebidimap + +import ( + "github.com/emirpasic/gods/containers" + rbt "github.com/emirpasic/gods/trees/redblacktree" +) + +func assertIteratorImplementation() { + var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) +} + +// Iterator holding the iterator's state +type Iterator struct { + iterator rbt.Iterator +} + +// Iterator returns a stateful iterator whose elements are key/value pairs. +func (m *Map) Iterator() Iterator { + return Iterator{iterator: m.forwardMap.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 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. +// 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 key and value can be retrieved by Key() 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().(*data).value +} + +// Key returns the current element's key. +// Does not modify the state of the iterator. +func (iterator *Iterator) Key() interface{} { + return iterator.iterator.Key() +} + +// 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 key and value can be retrieved by Key() 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 key and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Last() bool { + return iterator.iterator.Last() +} diff --git a/maps/treebidimap/treebidimap_test.go b/maps/treebidimap/treebidimap_test.go index fb95840f..40b34975 100644 --- a/maps/treebidimap/treebidimap_test.go +++ b/maps/treebidimap/treebidimap_test.go @@ -170,6 +170,157 @@ func sameElements(a []interface{}, b []interface{}) bool { return true } +func TestMapIteratorNextOnEmpty(t *testing.T) { + m := NewWithStringComparators() + it := m.Iterator() + it = m.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty map") + } +} + +func TestMapIteratorPrevOnEmpty(t *testing.T) { + m := NewWithStringComparators() + it := m.Iterator() + it = m.Iterator() + for it.Prev() { + t.Errorf("Shouldn't iterate on empty map") + } +} + +func TestMapIteratorNext(t *testing.T) { + m := NewWith(utils.StringComparator, utils.IntComparator) + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + + it := m.Iterator() + count := 0 + for it.Next() { + count++ + key := it.Key() + value := it.Value() + switch key { + case "a": + if actualValue, expectedValue := value, 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case "b": + if actualValue, expectedValue := value, 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case "c": + if actualValue, expectedValue := value, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := value, count; 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 TestMapIteratorPrev(t *testing.T) { + m := NewWith(utils.StringComparator, utils.IntComparator) + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + + it := m.Iterator() + for it.Next() { + } + countDown := m.Size() + for it.Prev() { + key := it.Key() + value := it.Value() + switch key { + case "a": + if actualValue, expectedValue := value, 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case "b": + if actualValue, expectedValue := value, 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case "c": + if actualValue, expectedValue := value, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := value, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + countDown-- + } + if actualValue, expectedValue := countDown, 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + +func TestMapIteratorBegin(t *testing.T) { + m := NewWith(utils.IntComparator, utils.StringComparator) + it := m.Iterator() + it.Begin() + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + for it.Next() { + } + it.Begin() + it.Next() + if key, value := it.Key(), it.Value(); key != 1 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") + } +} + +func TestMapTreeIteratorEnd(t *testing.T) { + m := NewWith(utils.IntComparator, utils.StringComparator) + it := m.Iterator() + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + it.End() + it.Prev() + if key, value := it.Key(), it.Value(); key != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") + } +} + +func TestMapIteratorFirst(t *testing.T) { + m := NewWith(utils.IntComparator, utils.StringComparator) + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + it := m.Iterator() + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if key, value := it.Key(), it.Value(); key != 1 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") + } +} + +func TestMapIteratorLast(t *testing.T) { + m := NewWith(utils.IntComparator, utils.StringComparator) + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + it := m.Iterator() + if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if key, value := it.Key(), it.Value(); key != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") + } +} + func BenchmarkMap(b *testing.B) { for i := 0; i < b.N; i++ { m := NewWithIntComparators() From b41257272c91ce84368d29e347621c8804030684 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 3 Jul 2016 03:47:35 +0200 Subject: [PATCH 084/320] - TreeBidiMap enumerable implemented (with tests) --- maps/treebidimap/enumerable.go | 80 ++++++++++++++ maps/treebidimap/treebidimap.go | 12 ++- maps/treebidimap/treebidimap_test.go | 152 +++++++++++++++++++++++++++ maps/treemap/treemap_test.go | 8 +- 4 files changed, 244 insertions(+), 8 deletions(-) create mode 100644 maps/treebidimap/enumerable.go diff --git a/maps/treebidimap/enumerable.go b/maps/treebidimap/enumerable.go new file mode 100644 index 00000000..d5d829ab --- /dev/null +++ b/maps/treebidimap/enumerable.go @@ -0,0 +1,80 @@ +// 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 treebidimap + +import "github.com/emirpasic/gods/containers" + +func assertEnumerableImplementation() { + var _ containers.EnumerableWithKey = (*Map)(nil) +} + +// Each calls the given function once for each element, passing that element's key and value. +func (m *Map) Each(f func(key interface{}, value interface{})) { + iterator := m.Iterator() + for iterator.Next() { + f(iterator.Key(), iterator.Value()) + } +} + +// 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. +func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) *Map { + newMap := NewWith(m.keyComparator, m.valueComparator) + iterator := m.Iterator() + for iterator.Next() { + key2, value2 := f(iterator.Key(), iterator.Value()) + newMap.Put(key2, value2) + } + return newMap +} + +// Select returns a new container containing all elements for which the given function returns a true value. +func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map { + newMap := NewWith(m.keyComparator, m.valueComparator) + iterator := m.Iterator() + for iterator.Next() { + if f(iterator.Key(), iterator.Value()) { + newMap.Put(iterator.Key(), iterator.Value()) + } + } + return newMap +} + +// Any passes each element of the container to the given function and +// returns true if the function ever returns true for any element. +func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool { + iterator := m.Iterator() + for iterator.Next() { + if f(iterator.Key(), 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 (m *Map) All(f func(key interface{}, value interface{}) bool) bool { + iterator := m.Iterator() + for iterator.Next() { + if !f(iterator.Key(), iterator.Value()) { + return false + } + } + return true +} + +// 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. +func (m *Map) Find(f func(key interface{}, value interface{}) bool) (interface{}, interface{}) { + iterator := m.Iterator() + for iterator.Next() { + if f(iterator.Key(), iterator.Value()) { + return iterator.Key(), iterator.Value() + } + } + return nil, nil +} diff --git a/maps/treebidimap/treebidimap.go b/maps/treebidimap/treebidimap.go index 28555427..342e2cf5 100644 --- a/maps/treebidimap/treebidimap.go +++ b/maps/treebidimap/treebidimap.go @@ -30,8 +30,10 @@ func assertMapImplementation() { // Map holds the elements in two red-black trees. type Map struct { - forwardMap redblacktree.Tree - inverseMap redblacktree.Tree + forwardMap redblacktree.Tree + inverseMap redblacktree.Tree + keyComparator utils.Comparator + valueComparator utils.Comparator } type data struct { @@ -42,8 +44,10 @@ type data struct { // NewWith instantiates a bidirectional map. func NewWith(keyComparator utils.Comparator, valueComparator utils.Comparator) *Map { return &Map{ - forwardMap: *redblacktree.NewWith(keyComparator), - inverseMap: *redblacktree.NewWith(valueComparator), + forwardMap: *redblacktree.NewWith(keyComparator), + inverseMap: *redblacktree.NewWith(valueComparator), + keyComparator: keyComparator, + valueComparator: valueComparator, } } diff --git a/maps/treebidimap/treebidimap_test.go b/maps/treebidimap/treebidimap_test.go index 40b34975..5c41961e 100644 --- a/maps/treebidimap/treebidimap_test.go +++ b/maps/treebidimap/treebidimap_test.go @@ -170,6 +170,158 @@ func sameElements(a []interface{}, b []interface{}) bool { return true } +func TestMapEach(t *testing.T) { + m := NewWith(utils.StringComparator, utils.IntComparator) + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + count := 0 + m.Each(func(key interface{}, value interface{}) { + count++ + if actualValue, expectedValue := count, value; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + switch value { + case 1: + if actualValue, expectedValue := key, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := key, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 3: + if actualValue, expectedValue := key, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + }) +} + +func TestMapMap(t *testing.T) { + m := NewWith(utils.StringComparator, utils.IntComparator) + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + mappedMap := m.Map(func(key1 interface{}, value1 interface{}) (key2 interface{}, value2 interface{}) { + return key1, value1.(int) * value1.(int) + }) + if actualValue, _ := mappedMap.Get("a"); actualValue != 1 { + t.Errorf("Got %v expected %v", actualValue, "mapped: a") + } + if actualValue, _ := mappedMap.Get("b"); actualValue != 4 { + t.Errorf("Got %v expected %v", actualValue, "mapped: b") + } + if actualValue, _ := mappedMap.Get("c"); actualValue != 9 { + t.Errorf("Got %v expected %v", actualValue, "mapped: c") + } + if mappedMap.Size() != 3 { + t.Errorf("Got %v expected %v", mappedMap.Size(), 3) + } +} + +func TestMapSelect(t *testing.T) { + m := NewWith(utils.StringComparator, utils.IntComparator) + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + selectedMap := m.Select(func(key interface{}, value interface{}) bool { + return key.(string) >= "a" && key.(string) <= "b" + }) + if actualValue, _ := selectedMap.Get("a"); actualValue != 1 { + t.Errorf("Got %v expected %v", actualValue, "value: a") + } + if actualValue, _ := selectedMap.Get("b"); actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, "value: b") + } + if selectedMap.Size() != 2 { + t.Errorf("Got %v expected %v", selectedMap.Size(), 2) + } +} + +func TestMapAny(t *testing.T) { + m := NewWith(utils.StringComparator, utils.IntComparator) + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + any := m.Any(func(key interface{}, value interface{}) bool { + return value.(int) == 3 + }) + if any != true { + t.Errorf("Got %v expected %v", any, true) + } + any = m.Any(func(key interface{}, value interface{}) bool { + return value.(int) == 4 + }) + if any != false { + t.Errorf("Got %v expected %v", any, false) + } +} + +func TestMapAll(t *testing.T) { + m := NewWith(utils.StringComparator, utils.IntComparator) + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + all := m.All(func(key interface{}, value interface{}) bool { + return key.(string) >= "a" && key.(string) <= "c" + }) + if all != true { + t.Errorf("Got %v expected %v", all, true) + } + all = m.All(func(key interface{}, value interface{}) bool { + return key.(string) >= "a" && key.(string) <= "b" + }) + if all != false { + t.Errorf("Got %v expected %v", all, false) + } +} + +func TestMapFind(t *testing.T) { + m := NewWith(utils.StringComparator, utils.IntComparator) + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + foundKey, foundValue := m.Find(func(key interface{}, value interface{}) bool { + return key.(string) == "c" + }) + if foundKey != "c" || foundValue != 3 { + t.Errorf("Got %v -> %v expected %v -> %v", foundKey, foundValue, "c", 3) + } + foundKey, foundValue = m.Find(func(key interface{}, value interface{}) bool { + return key.(string) == "x" + }) + if foundKey != nil || foundValue != nil { + t.Errorf("Got %v at %v expected %v at %v", foundValue, foundKey, nil, nil) + } +} + +func TestMapChaining(t *testing.T) { + m := NewWith(utils.StringComparator, utils.IntComparator) + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + chainedMap := m.Select(func(key interface{}, value interface{}) bool { + return value.(int) > 1 + }).Map(func(key interface{}, value interface{}) (interface{}, interface{}) { + return key.(string) + key.(string), value.(int) * value.(int) + }) + if actualValue := chainedMap.Size(); actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, found := chainedMap.Get("aa"); actualValue != nil || found { + t.Errorf("Got %v expected %v", actualValue, nil) + } + if actualValue, found := chainedMap.Get("bb"); actualValue != 4 || !found { + t.Errorf("Got %v expected %v", actualValue, 4) + } + if actualValue, found := chainedMap.Get("cc"); actualValue != 9 || !found { + t.Errorf("Got %v expected %v", actualValue, 9) + } +} + func TestMapIteratorNextOnEmpty(t *testing.T) { m := NewWithStringComparators() it := m.Iterator() diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 72406673..920b051a 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -173,15 +173,15 @@ func TestMapMap(t *testing.T) { m.Put("a", 1) m.Put("b", 2) mappedMap := m.Map(func(key1 interface{}, value1 interface{}) (key2 interface{}, value2 interface{}) { - return key1, "mapped: " + key1.(string) + return key1, value1.(int) * value1.(int) }) - if actualValue, _ := mappedMap.Get("a"); actualValue != "mapped: a" { + if actualValue, _ := mappedMap.Get("a"); actualValue != 1 { t.Errorf("Got %v expected %v", actualValue, "mapped: a") } - if actualValue, _ := mappedMap.Get("b"); actualValue != "mapped: b" { + if actualValue, _ := mappedMap.Get("b"); actualValue != 4 { t.Errorf("Got %v expected %v", actualValue, "mapped: b") } - if actualValue, _ := mappedMap.Get("c"); actualValue != "mapped: c" { + if actualValue, _ := mappedMap.Get("c"); actualValue != 9 { t.Errorf("Got %v expected %v", actualValue, "mapped: c") } if mappedMap.Size() != 3 { From d8c5aa20eb31226a2c6bb948d4ac546882460557 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 3 Jul 2016 04:25:03 +0200 Subject: [PATCH 085/320] - TreeBidiMap example implemented - TreeMap string output fixed to be consistent with other maps --- examples/treebidimap.go | 28 ++++++++++++++++++++++++++++ maps/treebidimap/treebidimap.go | 10 +++++++--- maps/treemap/treemap.go | 12 +++++++++--- 3 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 examples/treebidimap.go diff --git a/examples/treebidimap.go b/examples/treebidimap.go new file mode 100644 index 00000000..fc87c807 --- /dev/null +++ b/examples/treebidimap.go @@ -0,0 +1,28 @@ +// 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 examples + +import ( + "github.com/emirpasic/gods/maps/treebidimap" + "github.com/emirpasic/gods/utils" +) + +// TreeBidiMapExample to demonstrate basic usage of TreeBidiMap +func TreeBidiMapExample() { + m := treebidimap.NewWith(utils.IntComparator, utils.StringComparator) // empty + m.Put(1, "x") // 1->x + m.Put(3, "b") // 1->x, 3->b (ordered) + m.Put(1, "a") // 1->a, 3->b (ordered) + m.Put(2, "b") // 1->a, 2->b (ordered) + _, _ = m.GetKey("a") // 1, true + _, _ = m.Get(2) // b, true + _, _ = m.Get(3) // nil, false + _ = m.Values() // []interface {}{"a", "b"} (ordered) + _ = m.Keys() // []interface {}{1, 2} (ordered) + m.Remove(1) // 2->b + m.Clear() // empty + m.Empty() // true + m.Size() // 0 +} diff --git a/maps/treebidimap/treebidimap.go b/maps/treebidimap/treebidimap.go index 342e2cf5..87eff9f7 100644 --- a/maps/treebidimap/treebidimap.go +++ b/maps/treebidimap/treebidimap.go @@ -22,6 +22,7 @@ import ( "github.com/emirpasic/gods/maps" "github.com/emirpasic/gods/trees/redblacktree" "github.com/emirpasic/gods/utils" + "strings" ) func assertMapImplementation() { @@ -128,7 +129,10 @@ func (m *Map) Clear() { // String returns a string representation of container func (m *Map) String() string { - str := "TreeBidiMap\n" - str += fmt.Sprintf("%v", m.forwardMap) - return str + str := "TreeBidiMap\nmap[" + it := m.Iterator() + for it.Next() { + str += fmt.Sprintf("%v:%v ", it.Key(), it.Value()) + } + return strings.TrimRight(str, " ") + "]" } diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index e2b4233d..a1e58ad4 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -12,9 +12,11 @@ package treemap import ( + "fmt" "github.com/emirpasic/gods/maps" rbt "github.com/emirpasic/gods/trees/redblacktree" "github.com/emirpasic/gods/utils" + "strings" ) func assertMapImplementation() { @@ -105,7 +107,11 @@ func (m *Map) Max() (key interface{}, value interface{}) { // String returns a string representation of container func (m *Map) String() string { - str := "TreeMap\n" - str += m.tree.String() - return str + str := "TreeMap\nmap[" + it := m.Iterator() + for it.Next() { + str += fmt.Sprintf("%v:%v ", it.Key(), it.Value()) + } + return strings.TrimRight(str, " ") + "]" + } From 7c82c74b0096e51c494b1a9674b4b0b89586f461 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 3 Jul 2016 04:36:21 +0200 Subject: [PATCH 086/320] - TreeBidiMap documentation --- README.md | 34 ++++++++++++++++++++++++++++++++++ examples/treebidimap.go | 28 ++++++++++++++-------------- 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index b4983a99..5095c624 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Implementation of various data structures and algorithms in Go. - [HashMap](#hashmap) - [TreeMap](#treemap) - [HashBidiMap](#hashbidimap) + - [TreeBidiMap](#treebidimap) - [Trees](#trees) - [RedBlackTree](#redblacktree) - [BinaryHeap](#binaryheap) @@ -66,6 +67,7 @@ Containers are either ordered or unordered. All ordered containers provide [stat | [HashMap](#hashmap) | no | no | no | key | | [TreeMap](#treemap) | yes | yes* | yes | key | | [HashBidiMap](#hashbidimap) | no | no | no | key* | +| [TreeBidiMap](#treebidimap) | yes | yes* | yes | key* | | [RedBlackTree](#redblacktree) | yes | yes* | no | key | | [BinaryHeap](#binaryheap) | yes | yes* | no | index | | | | *reversible | | *bidirectional | @@ -471,6 +473,38 @@ func main() { } ``` +#### TreeBidiMap + +A [map](#maps) based on red-black tree. This map guarantees that the map will be in both ascending key and value order. Other than key and value ordering, the goal with this structure is to avoid duplication of elements (unlike in [HashBidiMap](#hashbidimap)), which can be significant if contained elements are large. + +Implements [BidiMap](#maps), [IteratorWithKey](#iteratorwithkey) and [EnumerableWithKey](#enumerablewithkey) interfaces. + +```go +package main + +import ( + "github.com/emirpasic/gods/maps/treebidimap" + "github.com/emirpasic/gods/utils" +) + +func main() { + m := treebidimap.NewWith(utils.IntComparator, utils.StringComparator) + m.Put(1, "x") // 1->x + m.Put(3, "b") // 1->x, 3->b (ordered) + m.Put(1, "a") // 1->a, 3->b (ordered) + m.Put(2, "b") // 1->a, 2->b (ordered) + _, _ = m.GetKey("a") // 1, true + _, _ = m.Get(2) // b, true + _, _ = m.Get(3) // nil, false + _ = m.Values() // []interface {}{"a", "b"} (ordered) + _ = m.Keys() // []interface {}{1, 2} (ordered) + m.Remove(1) // 2->b + m.Clear() // empty + m.Empty() // true + m.Size() // 0 +} +``` + ### Trees A tree is a widely used data data structure that simulates a hierarchical tree structure, with a root value and subtrees of children, represented as a set of linked nodes; thus no cyclic links. diff --git a/examples/treebidimap.go b/examples/treebidimap.go index fc87c807..f4138cb2 100644 --- a/examples/treebidimap.go +++ b/examples/treebidimap.go @@ -11,18 +11,18 @@ import ( // TreeBidiMapExample to demonstrate basic usage of TreeBidiMap func TreeBidiMapExample() { - m := treebidimap.NewWith(utils.IntComparator, utils.StringComparator) // empty - m.Put(1, "x") // 1->x - m.Put(3, "b") // 1->x, 3->b (ordered) - m.Put(1, "a") // 1->a, 3->b (ordered) - m.Put(2, "b") // 1->a, 2->b (ordered) - _, _ = m.GetKey("a") // 1, true - _, _ = m.Get(2) // b, true - _, _ = m.Get(3) // nil, false - _ = m.Values() // []interface {}{"a", "b"} (ordered) - _ = m.Keys() // []interface {}{1, 2} (ordered) - m.Remove(1) // 2->b - m.Clear() // empty - m.Empty() // true - m.Size() // 0 + m := treebidimap.NewWith(utils.IntComparator, utils.StringComparator) + m.Put(1, "x") // 1->x + m.Put(3, "b") // 1->x, 3->b (ordered) + m.Put(1, "a") // 1->a, 3->b (ordered) + m.Put(2, "b") // 1->a, 2->b (ordered) + _, _ = m.GetKey("a") // 1, true + _, _ = m.Get(2) // b, true + _, _ = m.Get(3) // nil, false + _ = m.Values() // []interface {}{"a", "b"} (ordered) + _ = m.Keys() // []interface {}{1, 2} (ordered) + m.Remove(1) // 2->b + m.Clear() // empty + m.Empty() // true + m.Size() // 0 } From 9563b150100081bad15dcfd3e8997bf1973f60c6 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 9 Jul 2016 03:57:18 +0200 Subject: [PATCH 087/320] - btree insertion with tests --- trees/btree/btree_test.go | 225 ++++++++++++++++++++++++++++++++++++++ trees/btree/main/main.go | 14 +++ 2 files changed, 239 insertions(+) create mode 100644 trees/btree/btree_test.go create mode 100644 trees/btree/main/main.go diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go new file mode 100644 index 00000000..c8a7b78b --- /dev/null +++ b/trees/btree/btree_test.go @@ -0,0 +1,225 @@ +// 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 btree + +import ( + _ "fmt" + "testing" +) + +func TestBTree_search(t *testing.T) { + { + tree := NewWithIntComparator(3) + tree.root = &Node{entries: []*Entry{}, children: make([]*Node, 0)} + tests := [][]interface{}{ + {0, 0, false}, + } + for _, test := range tests { + index, found := tree.search(tree.root, &Entry{test[0], nil}) + if actualValue, expectedValue := index, test[1]; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := found, test[2]; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + { + tree := NewWithIntComparator(3) + tree.root = &Node{entries: []*Entry{&Entry{2, 0}, &Entry{4, 1}, &Entry{6, 2}}, children: []*Node{}} + tests := [][]interface{}{ + {0, 0, false}, + {1, 0, false}, + {2, 0, true}, + {3, 1, false}, + {4, 1, true}, + {5, 2, false}, + {6, 2, true}, + {7, 3, false}, + } + for _, test := range tests { + index, found := tree.search(tree.root, &Entry{test[0], nil}) + if actualValue, expectedValue := index, test[1]; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := found, test[2]; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } +} + +func TestBTree_insert1(t *testing.T) { + // https://upload.wikimedia.org/wikipedia/commons/3/33/B_tree_insertion_example.png + tree := NewWithIntComparator(3) + assertValidTree(t, tree, 0) + + tree.Put(1, 0) + assertValidTree(t, tree, 1) + assertValidTreeNode(t, tree.root, 1, 0, []int{1}) + + tree.Put(2, 1) + assertValidTree(t, tree, 2) + assertValidTreeNode(t, tree.root, 2, 0, []int{1, 2}) + + tree.Put(3, 2) + assertValidTree(t, tree, 3) + assertValidTreeNode(t, tree.root, 1, 2, []int{2}) + assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{1}) + assertValidTreeNode(t, tree.root.children[1], 1, 0, []int{3}) + + tree.Put(4, 2) + assertValidTree(t, tree, 4) + assertValidTreeNode(t, tree.root, 1, 2, []int{2}) + assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{1}) + assertValidTreeNode(t, tree.root.children[1], 2, 0, []int{3, 4}) + + tree.Put(5, 2) + assertValidTree(t, tree, 5) + assertValidTreeNode(t, tree.root, 2, 3, []int{2, 4}) + assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{1}) + assertValidTreeNode(t, tree.root.children[1], 1, 0, []int{3}) + assertValidTreeNode(t, tree.root.children[2], 1, 0, []int{5}) + + tree.Put(6, 2) + assertValidTree(t, tree, 6) + assertValidTreeNode(t, tree.root, 2, 3, []int{2, 4}) + assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{1}) + assertValidTreeNode(t, tree.root.children[1], 1, 0, []int{3}) + assertValidTreeNode(t, tree.root.children[2], 2, 0, []int{5, 6}) + + tree.Put(7, 2) + assertValidTree(t, tree, 7) + assertValidTreeNode(t, tree.root, 1, 2, []int{4}) + assertValidTreeNode(t, tree.root.children[0], 1, 2, []int{2}) + assertValidTreeNode(t, tree.root.children[1], 1, 2, []int{6}) + assertValidTreeNode(t, tree.root.children[0].children[0], 1, 0, []int{1}) + assertValidTreeNode(t, tree.root.children[0].children[1], 1, 0, []int{3}) + assertValidTreeNode(t, tree.root.children[1].children[0], 1, 0, []int{5}) + assertValidTreeNode(t, tree.root.children[1].children[1], 1, 0, []int{7}) +} + +func TestBTree_insert2(t *testing.T) { + tree := NewWithIntComparator(4) + assertValidTree(t, tree, 0) + + tree.Put(0, 0) + assertValidTree(t, tree, 1) + assertValidTreeNode(t, tree.root, 1, 0, []int{0}) + + tree.Put(2, 2) + assertValidTree(t, tree, 2) + assertValidTreeNode(t, tree.root, 2, 0, []int{0, 2}) + + tree.Put(1, 1) + assertValidTree(t, tree, 3) + assertValidTreeNode(t, tree.root, 3, 0, []int{0, 1, 2}) + + tree.Put(1, 1) + assertValidTree(t, tree, 3) + assertValidTreeNode(t, tree.root, 3, 0, []int{0, 1, 2}) + + tree.Put(3, 3) + assertValidTree(t, tree, 4) + assertValidTreeNode(t, tree.root, 1, 2, []int{1}) + assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{0}) + assertValidTreeNode(t, tree.root.children[1], 2, 0, []int{2, 3}) + + tree.Put(4, 4) + assertValidTree(t, tree, 5) + assertValidTreeNode(t, tree.root, 1, 2, []int{1}) + assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{0}) + assertValidTreeNode(t, tree.root.children[1], 3, 0, []int{2, 3, 4}) + + tree.Put(5, 5) + assertValidTree(t, tree, 6) + assertValidTreeNode(t, tree.root, 2, 3, []int{1, 3}) + assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{0}) + assertValidTreeNode(t, tree.root.children[1], 1, 0, []int{2}) + assertValidTreeNode(t, tree.root.children[2], 2, 0, []int{4, 5}) +} + +func TestBTree_insert3(t *testing.T) { + // http://www.geeksforgeeks.org/b-tree-set-1-insert-2/ + tree := NewWithIntComparator(6) + assertValidTree(t, tree, 0) + + tree.Put(10, 0) + assertValidTree(t, tree, 1) + assertValidTreeNode(t, tree.root, 1, 0, []int{10}) + + tree.Put(20, 1) + assertValidTree(t, tree, 2) + assertValidTreeNode(t, tree.root, 2, 0, []int{10, 20}) + + tree.Put(30, 2) + assertValidTree(t, tree, 3) + assertValidTreeNode(t, tree.root, 3, 0, []int{10, 20, 30}) + + tree.Put(40, 3) + assertValidTree(t, tree, 4) + assertValidTreeNode(t, tree.root, 4, 0, []int{10, 20, 30, 40}) + + tree.Put(50, 4) + assertValidTree(t, tree, 5) + assertValidTreeNode(t, tree.root, 5, 0, []int{10, 20, 30, 40, 50}) + + tree.Put(60, 5) + assertValidTree(t, tree, 6) + assertValidTreeNode(t, tree.root, 1, 2, []int{30}) + assertValidTreeNode(t, tree.root.children[0], 2, 0, []int{10, 20}) + assertValidTreeNode(t, tree.root.children[1], 3, 0, []int{40, 50, 60}) + + tree.Put(70, 6) + assertValidTree(t, tree, 7) + assertValidTreeNode(t, tree.root, 1, 2, []int{30}) + assertValidTreeNode(t, tree.root.children[0], 2, 0, []int{10, 20}) + assertValidTreeNode(t, tree.root.children[1], 4, 0, []int{40, 50, 60, 70}) + + tree.Put(80, 7) + assertValidTree(t, tree, 8) + assertValidTreeNode(t, tree.root, 1, 2, []int{30}) + assertValidTreeNode(t, tree.root.children[0], 2, 0, []int{10, 20}) + assertValidTreeNode(t, tree.root.children[1], 5, 0, []int{40, 50, 60, 70, 80}) + + tree.Put(90, 8) + assertValidTree(t, tree, 9) + assertValidTreeNode(t, tree.root, 2, 3, []int{30, 60}) + assertValidTreeNode(t, tree.root.children[0], 2, 0, []int{10, 20}) + assertValidTreeNode(t, tree.root.children[1], 2, 0, []int{40, 50}) + assertValidTreeNode(t, tree.root.children[2], 3, 0, []int{70, 80, 90}) +} + +func assertValidTree(t *testing.T, tree *Tree, expectedSize int) { + if actualValue, expectedValue := tree.size, expectedSize; actualValue != expectedValue { + t.Errorf("Got %v expected %v for tree size", actualValue, expectedValue) + } +} + +func assertValidTreeNode(t *testing.T, node *Node, expectedEntries int, expectedChildren int, keys []int) { + if actualValue, expectedValue := len(node.entries), expectedEntries; actualValue != expectedValue { + t.Errorf("Got %v expected %v for entries size", actualValue, expectedValue) + } + if actualValue, expectedValue := len(node.children), expectedChildren; actualValue != expectedValue { + t.Errorf("Got %v expected %v for children size", actualValue, expectedValue) + } + for i, key := range keys { + if actualValue, expectedValue := node.entries[i].key, key; actualValue != expectedValue { + t.Errorf("Got %v expected %v for key", actualValue, expectedValue) + } + } +} + +func BenchmarkBTree(b *testing.B) { + for i := 0; i < b.N; i++ { + tree := NewWithIntComparator(32) + for n := 0; n < 1000; n++ { + tree.Put(n, n) + } + for n := 0; n < 1000; n++ { + tree.Remove(n) + } + } +} diff --git a/trees/btree/main/main.go b/trees/btree/main/main.go new file mode 100644 index 00000000..145f36d5 --- /dev/null +++ b/trees/btree/main/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "github.com/emirpasic/gods/trees/btree" + "fmt" +) + +func main() { + tree := btree.NewWithIntComparator(3) + tree.Put(1, 0) + tree.Put(2, 1) + tree.Put(3, 2) + fmt.Println() +} From 28b826151aebcb3584c7efe1aaab5b4b0de67151 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 9 Jul 2016 03:57:27 +0200 Subject: [PATCH 088/320] - btree insertion with tests --- trees/btree/btree.go | 266 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 trees/btree/btree.go diff --git a/trees/btree/btree.go b/trees/btree/btree.go new file mode 100644 index 00000000..806e590c --- /dev/null +++ b/trees/btree/btree.go @@ -0,0 +1,266 @@ +// 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 btree implements a B tree. +// +// Structure is not thread safe. +// +// References: https://en.wikipedia.org/wiki/B-tree +package btree + +import ( + "fmt" + "github.com/emirpasic/gods/trees" + "github.com/emirpasic/gods/utils" +) + +func assertTreeImplementation() { + var _ trees.Tree = (*Tree)(nil) +} + +// Tree holds elements of the B-tree +type Tree struct { + root *Node // Root node + comparator utils.Comparator // Key comparator + size int // Total number of keys in the tree + m int // Knuth order (maximum number of children) +} + +// Node is a single element within the tree +type Node struct { + parent *Node + entries []*Entry // Contained keys in node + children []*Node // Children nodes +} + +type Entry struct { + key interface{} + value interface{} +} + +// NewWith instantiates a B-tree with the Knuth order (maximum number of children) and a custom key comparator. +func NewWith(order int, comparator utils.Comparator) *Tree { + if order < 2 { + panic("Invalid order, should be at least 2") + } + return &Tree{m: order, comparator: comparator} +} + +// NewWithIntComparator instantiates a B-tree with the Knuth order (maximum number of children) and the IntComparator, i.e. keys are of type int. +func NewWithIntComparator(order int) *Tree { + return NewWith(order, utils.IntComparator) +} + +// NewWithStringComparator instantiates a B-tree with the Knuth order (maximum number of children) and the StringComparator, i.e. keys are of type string. +func NewWithStringComparator(order int) *Tree { + return NewWith(order, utils.StringComparator) +} + +// Put inserts key-value pair node into the tree. +// If key already exists, then its value is updated with the new value. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (tree *Tree) Put(key interface{}, value interface{}) { + entry := &Entry{key: key, value: value} + + if tree.root == nil { + tree.root = &Node{entries: []*Entry{entry}, children: []*Node{}} + tree.size++ + return + } + + if tree.insert(tree.root, entry) { + tree.size++ + } +} + +// Get searches the node in the tree by key and returns its value or nil if key is not found in tree. +// Second return parameter is true if key was found, otherwise false. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (tree *Tree) Get(key interface{}) (value interface{}, found bool) { + return nil, false +} + +// Remove remove the node from the tree by key. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (tree *Tree) Remove(key interface{}) { + // TODO +} + +// Empty returns true if tree does not contain any nodes +func (tree *Tree) Empty() bool { + return tree.size == 0 +} + +// Size returns number of nodes in the tree. +func (tree *Tree) Size() int { + return tree.size +} + +// Keys returns all keys in-order +func (tree *Tree) Keys() []interface{} { + return nil // TODO +} + +// Values returns all values in-order based on the key. +func (tree *Tree) Values() []interface{} { + return nil // TODO +} + +// Clear removes all nodes from the tree. +func (tree *Tree) Clear() { + tree.root = nil + tree.size = 0 +} + +// String returns a string representation of container +func (tree *Tree) String() string { + str := "BTree\n" + if !tree.Empty() { + str += tree.root.String() + } + return str +} + +func (node *Node) String() string { + return fmt.Sprintf("%v", node.entries) +} + +func (entry *Entry) String() string { + return fmt.Sprintf("%v", entry.key) +} + +func (tree *Tree) isLeaf(node *Node) bool { + return len(node.children) == 0 +} + +func (tree *Tree) isFull(node *Node) bool { + return len(node.entries) == tree.maxEntries() +} + +func (tree *Tree) shouldSplit(node *Node) bool { + return len(node.entries) > tree.maxEntries() +} + +func (tree *Tree) maxChildren() int { + return tree.m +} + +func (tree *Tree) maxEntries() int { + return tree.m - 1 +} + +func (tree *Tree) middle() int { + return (tree.m - 1) / 2 // "-1" to favor right nodes to have more keys when splitting +} + +func (tree *Tree) search(node *Node, entry *Entry) (index int, found bool) { + low, high := 0, len(node.entries) - 1 + var mid int + for low <= high { + mid = (high + low) / 2 + compare := tree.comparator(entry.key, node.entries[mid].key) + switch { + case compare > 0: + low = mid + 1 + case compare < 0: + high = mid - 1 + case compare == 0: + return mid, true + } + } + return low, false +} + +func (tree *Tree) insert(node *Node, entry *Entry) (inserted bool) { + if tree.isLeaf(node) { + return tree.insertIntoLeaf(node, entry) + } + return tree.insertIntoInternal(node, entry) +} + +func (tree *Tree) insertIntoLeaf(node *Node, entry *Entry) (inserted bool) { + insertPosition, found := tree.search(node, entry) + if found { + node.entries[insertPosition] = nil // GC + node.entries[insertPosition] = entry + return false + } + node.entries = append(node.entries, nil) + copy(node.entries[insertPosition + 1:], node.entries[insertPosition:]) + node.entries[insertPosition] = entry + tree.split(node) + return true +} + +func (tree *Tree) insertIntoInternal(node *Node, entry *Entry) (inserted bool) { + insertPosition, found := tree.search(node, entry) + if found { + node.entries[insertPosition] = nil // GC + node.entries[insertPosition] = entry + return false + } + return tree.insert(node.children[insertPosition], entry) +} + +func (tree *Tree) split(node *Node) { + if !tree.shouldSplit(node) { + return + } + + if node == tree.root { + tree.splitRoot() + return + } + + tree.splitNonRoot(node) +} + +func (tree *Tree) splitNonRoot(node *Node) { + middle := tree.middle() + parent := node.parent + + left := &Node{entries: node.entries[:middle], parent: parent} + right := &Node{entries: node.entries[middle + 1:], parent: parent} + + if !tree.isLeaf(node) { + left.children = node.children[:middle + 1] + right.children = node.children[middle + 1:] + } + + insertPosition, _ := tree.search(parent, node.entries[middle]) + parent.entries = append(parent.entries, nil) + copy(parent.entries[insertPosition + 1:], parent.entries[insertPosition:]) + parent.entries[insertPosition] = node.entries[middle] + + parent.children[insertPosition] = left + + parent.children = append(parent.children, nil) + copy(parent.children[insertPosition + 2:], parent.children[insertPosition + 1:]) + parent.children[insertPosition + 1] = right + + node = nil // GC + + tree.split(parent) +} + +func (tree *Tree) splitRoot() { + middle := tree.middle() + + left := &Node{entries: tree.root.entries[:middle]} + right := &Node{entries: tree.root.entries[middle + 1:]} + + if !tree.isLeaf(tree.root) { + left.children = tree.root.children[:middle + 1] + right.children = tree.root.children[middle + 1:] + } + + newRoot := &Node{ + entries: []*Entry{tree.root.entries[middle]}, + children: []*Node{left, right}, + } + + left.parent = newRoot + right.parent = newRoot + tree.root = newRoot +} From 19bf8e5c1533ad30a1fd674992d40d52ac88e956 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 9 Jul 2016 04:10:02 +0200 Subject: [PATCH 089/320] - remove inOrder function in red-black tree and use iterator --- trees/redblacktree/redblacktree.go | 39 +++++------------------------- 1 file changed, 6 insertions(+), 33 deletions(-) diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index f79d02b6..10c0b0e2 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -13,7 +13,6 @@ package redblacktree import ( "fmt" - "github.com/emirpasic/gods/stacks/linkedliststack" "github.com/emirpasic/gods/trees" "github.com/emirpasic/gods/utils" ) @@ -153,8 +152,9 @@ func (tree *Tree) Size() int { // Keys returns all keys in-order func (tree *Tree) Keys() []interface{} { keys := make([]interface{}, tree.size) - for i, node := range tree.inOrder() { - keys[i] = node.Key + it := tree.Iterator() + for i := 0; it.Next(); i++ { + keys[i] = it.Key() } return keys } @@ -162,8 +162,9 @@ func (tree *Tree) Keys() []interface{} { // Values returns all values in-order based on the key. func (tree *Tree) Values() []interface{} { values := make([]interface{}, tree.size) - for i, node := range tree.inOrder() { - values[i] = node.Value + it := tree.Iterator() + for i := 0; it.Next(); i++ { + values[i] = it.Value() } return values } @@ -267,34 +268,6 @@ func (node *Node) String() string { return fmt.Sprintf("%v", node.Key) } -// Returns all nodes in order -func (tree *Tree) inOrder() []*Node { - nodes := make([]*Node, tree.size) - if tree.size > 0 { - current := tree.Root - stack := linkedliststack.New() - done := false - count := 0 - for !done { - if current != nil { - stack.Push(current) - current = current.Left - } else { - if !stack.Empty() { - currentPop, _ := stack.Pop() - current = currentPop.(*Node) - nodes[count] = current - count++ - current = current.Right - } else { - done = true - } - } - } - } - return nodes -} - // String returns a string representation of container func output(node *Node, prefix string, isTail bool, str *string) { if node.Right != nil { From ab73314ad47c851ec0929b66a1e5410b9cb4064f Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 9 Jul 2016 04:13:51 +0200 Subject: [PATCH 090/320] - btree expose its root, nodes and entries (for extension purposes) --- trees/btree/btree.go | 107 ++++++++++++++++---------------- trees/btree/btree_test.go | 124 +++++++++++++++++++------------------- trees/btree/main/main.go | 14 ----- 3 files changed, 116 insertions(+), 129 deletions(-) delete mode 100644 trees/btree/main/main.go diff --git a/trees/btree/btree.go b/trees/btree/btree.go index 806e590c..d3658255 100644 --- a/trees/btree/btree.go +++ b/trees/btree/btree.go @@ -21,22 +21,23 @@ func assertTreeImplementation() { // Tree holds elements of the B-tree type Tree struct { - root *Node // Root node - comparator utils.Comparator // Key comparator + Root *Node // Root node + Comparator utils.Comparator // Key comparator size int // Total number of keys in the tree m int // Knuth order (maximum number of children) } // Node is a single element within the tree type Node struct { - parent *Node - entries []*Entry // Contained keys in node - children []*Node // Children nodes + Parent *Node + Entries []*Entry // Contained keys in node + Children []*Node // Children nodes } +// Entry represents the key-value pair contained within nodes type Entry struct { - key interface{} - value interface{} + Key interface{} + Value interface{} } // NewWith instantiates a B-tree with the Knuth order (maximum number of children) and a custom key comparator. @@ -44,7 +45,7 @@ func NewWith(order int, comparator utils.Comparator) *Tree { if order < 2 { panic("Invalid order, should be at least 2") } - return &Tree{m: order, comparator: comparator} + return &Tree{m: order, Comparator: comparator} } // NewWithIntComparator instantiates a B-tree with the Knuth order (maximum number of children) and the IntComparator, i.e. keys are of type int. @@ -61,15 +62,15 @@ func NewWithStringComparator(order int) *Tree { // If key already exists, then its value is updated with the new value. // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree) Put(key interface{}, value interface{}) { - entry := &Entry{key: key, value: value} + entry := &Entry{Key: key, Value: value} - if tree.root == nil { - tree.root = &Node{entries: []*Entry{entry}, children: []*Node{}} + if tree.Root == nil { + tree.Root = &Node{Entries: []*Entry{entry}, Children: []*Node{}} tree.size++ return } - if tree.insert(tree.root, entry) { + if tree.insert(tree.Root, entry) { tree.size++ } } @@ -109,7 +110,7 @@ func (tree *Tree) Values() []interface{} { // Clear removes all nodes from the tree. func (tree *Tree) Clear() { - tree.root = nil + tree.Root = nil tree.size = 0 } @@ -117,29 +118,29 @@ func (tree *Tree) Clear() { func (tree *Tree) String() string { str := "BTree\n" if !tree.Empty() { - str += tree.root.String() + str += tree.Root.String() } return str } func (node *Node) String() string { - return fmt.Sprintf("%v", node.entries) + return fmt.Sprintf("%v", node.Entries) } func (entry *Entry) String() string { - return fmt.Sprintf("%v", entry.key) + return fmt.Sprintf("%v", entry.Key) } func (tree *Tree) isLeaf(node *Node) bool { - return len(node.children) == 0 + return len(node.Children) == 0 } func (tree *Tree) isFull(node *Node) bool { - return len(node.entries) == tree.maxEntries() + return len(node.Entries) == tree.maxEntries() } func (tree *Tree) shouldSplit(node *Node) bool { - return len(node.entries) > tree.maxEntries() + return len(node.Entries) > tree.maxEntries() } func (tree *Tree) maxChildren() int { @@ -155,11 +156,11 @@ func (tree *Tree) middle() int { } func (tree *Tree) search(node *Node, entry *Entry) (index int, found bool) { - low, high := 0, len(node.entries) - 1 + low, high := 0, len(node.Entries)-1 var mid int for low <= high { mid = (high + low) / 2 - compare := tree.comparator(entry.key, node.entries[mid].key) + compare := tree.Comparator(entry.Key, node.Entries[mid].Key) switch { case compare > 0: low = mid + 1 @@ -182,13 +183,13 @@ func (tree *Tree) insert(node *Node, entry *Entry) (inserted bool) { func (tree *Tree) insertIntoLeaf(node *Node, entry *Entry) (inserted bool) { insertPosition, found := tree.search(node, entry) if found { - node.entries[insertPosition] = nil // GC - node.entries[insertPosition] = entry + node.Entries[insertPosition] = nil // GC + node.Entries[insertPosition] = entry return false } - node.entries = append(node.entries, nil) - copy(node.entries[insertPosition + 1:], node.entries[insertPosition:]) - node.entries[insertPosition] = entry + node.Entries = append(node.Entries, nil) + copy(node.Entries[insertPosition+1:], node.Entries[insertPosition:]) + node.Entries[insertPosition] = entry tree.split(node) return true } @@ -196,11 +197,11 @@ func (tree *Tree) insertIntoLeaf(node *Node, entry *Entry) (inserted bool) { func (tree *Tree) insertIntoInternal(node *Node, entry *Entry) (inserted bool) { insertPosition, found := tree.search(node, entry) if found { - node.entries[insertPosition] = nil // GC - node.entries[insertPosition] = entry + node.Entries[insertPosition] = nil // GC + node.Entries[insertPosition] = entry return false } - return tree.insert(node.children[insertPosition], entry) + return tree.insert(node.Children[insertPosition], entry) } func (tree *Tree) split(node *Node) { @@ -208,7 +209,7 @@ func (tree *Tree) split(node *Node) { return } - if node == tree.root { + if node == tree.Root { tree.splitRoot() return } @@ -218,26 +219,26 @@ func (tree *Tree) split(node *Node) { func (tree *Tree) splitNonRoot(node *Node) { middle := tree.middle() - parent := node.parent + parent := node.Parent - left := &Node{entries: node.entries[:middle], parent: parent} - right := &Node{entries: node.entries[middle + 1:], parent: parent} + left := &Node{Entries: node.Entries[:middle], Parent: parent} + right := &Node{Entries: node.Entries[middle+1:], Parent: parent} if !tree.isLeaf(node) { - left.children = node.children[:middle + 1] - right.children = node.children[middle + 1:] + left.Children = node.Children[:middle+1] + right.Children = node.Children[middle+1:] } - insertPosition, _ := tree.search(parent, node.entries[middle]) - parent.entries = append(parent.entries, nil) - copy(parent.entries[insertPosition + 1:], parent.entries[insertPosition:]) - parent.entries[insertPosition] = node.entries[middle] + insertPosition, _ := tree.search(parent, node.Entries[middle]) + parent.Entries = append(parent.Entries, nil) + copy(parent.Entries[insertPosition+1:], parent.Entries[insertPosition:]) + parent.Entries[insertPosition] = node.Entries[middle] - parent.children[insertPosition] = left + parent.Children[insertPosition] = left - parent.children = append(parent.children, nil) - copy(parent.children[insertPosition + 2:], parent.children[insertPosition + 1:]) - parent.children[insertPosition + 1] = right + parent.Children = append(parent.Children, nil) + copy(parent.Children[insertPosition+2:], parent.Children[insertPosition+1:]) + parent.Children[insertPosition+1] = right node = nil // GC @@ -247,20 +248,20 @@ func (tree *Tree) splitNonRoot(node *Node) { func (tree *Tree) splitRoot() { middle := tree.middle() - left := &Node{entries: tree.root.entries[:middle]} - right := &Node{entries: tree.root.entries[middle + 1:]} + left := &Node{Entries: tree.Root.Entries[:middle]} + right := &Node{Entries: tree.Root.Entries[middle+1:]} - if !tree.isLeaf(tree.root) { - left.children = tree.root.children[:middle + 1] - right.children = tree.root.children[middle + 1:] + if !tree.isLeaf(tree.Root) { + left.Children = tree.Root.Children[:middle+1] + right.Children = tree.Root.Children[middle+1:] } newRoot := &Node{ - entries: []*Entry{tree.root.entries[middle]}, - children: []*Node{left, right}, + Entries: []*Entry{tree.Root.Entries[middle]}, + Children: []*Node{left, right}, } - left.parent = newRoot - right.parent = newRoot - tree.root = newRoot + left.Parent = newRoot + right.Parent = newRoot + tree.Root = newRoot } diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index c8a7b78b..3a873441 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -12,12 +12,12 @@ import ( func TestBTree_search(t *testing.T) { { tree := NewWithIntComparator(3) - tree.root = &Node{entries: []*Entry{}, children: make([]*Node, 0)} + tree.Root = &Node{Entries: []*Entry{}, Children: make([]*Node, 0)} tests := [][]interface{}{ {0, 0, false}, } for _, test := range tests { - index, found := tree.search(tree.root, &Entry{test[0], nil}) + index, found := tree.search(tree.Root, &Entry{test[0], nil}) if actualValue, expectedValue := index, test[1]; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } @@ -28,7 +28,7 @@ func TestBTree_search(t *testing.T) { } { tree := NewWithIntComparator(3) - tree.root = &Node{entries: []*Entry{&Entry{2, 0}, &Entry{4, 1}, &Entry{6, 2}}, children: []*Node{}} + tree.Root = &Node{Entries: []*Entry{{2, 0}, {4, 1}, {6, 2}}, Children: []*Node{}} tests := [][]interface{}{ {0, 0, false}, {1, 0, false}, @@ -40,7 +40,7 @@ func TestBTree_search(t *testing.T) { {7, 3, false}, } for _, test := range tests { - index, found := tree.search(tree.root, &Entry{test[0], nil}) + index, found := tree.search(tree.Root, &Entry{test[0], nil}) if actualValue, expectedValue := index, test[1]; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } @@ -58,47 +58,47 @@ func TestBTree_insert1(t *testing.T) { tree.Put(1, 0) assertValidTree(t, tree, 1) - assertValidTreeNode(t, tree.root, 1, 0, []int{1}) + assertValidTreeNode(t, tree.Root, 1, 0, []int{1}) tree.Put(2, 1) assertValidTree(t, tree, 2) - assertValidTreeNode(t, tree.root, 2, 0, []int{1, 2}) + assertValidTreeNode(t, tree.Root, 2, 0, []int{1, 2}) tree.Put(3, 2) assertValidTree(t, tree, 3) - assertValidTreeNode(t, tree.root, 1, 2, []int{2}) - assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{1}) - assertValidTreeNode(t, tree.root.children[1], 1, 0, []int{3}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{2}) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{3}) tree.Put(4, 2) assertValidTree(t, tree, 4) - assertValidTreeNode(t, tree.root, 1, 2, []int{2}) - assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{1}) - assertValidTreeNode(t, tree.root.children[1], 2, 0, []int{3, 4}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{2}) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}) + assertValidTreeNode(t, tree.Root.Children[1], 2, 0, []int{3, 4}) tree.Put(5, 2) assertValidTree(t, tree, 5) - assertValidTreeNode(t, tree.root, 2, 3, []int{2, 4}) - assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{1}) - assertValidTreeNode(t, tree.root.children[1], 1, 0, []int{3}) - assertValidTreeNode(t, tree.root.children[2], 1, 0, []int{5}) + assertValidTreeNode(t, tree.Root, 2, 3, []int{2, 4}) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{3}) + assertValidTreeNode(t, tree.Root.Children[2], 1, 0, []int{5}) tree.Put(6, 2) assertValidTree(t, tree, 6) - assertValidTreeNode(t, tree.root, 2, 3, []int{2, 4}) - assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{1}) - assertValidTreeNode(t, tree.root.children[1], 1, 0, []int{3}) - assertValidTreeNode(t, tree.root.children[2], 2, 0, []int{5, 6}) + assertValidTreeNode(t, tree.Root, 2, 3, []int{2, 4}) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{3}) + assertValidTreeNode(t, tree.Root.Children[2], 2, 0, []int{5, 6}) tree.Put(7, 2) assertValidTree(t, tree, 7) - assertValidTreeNode(t, tree.root, 1, 2, []int{4}) - assertValidTreeNode(t, tree.root.children[0], 1, 2, []int{2}) - assertValidTreeNode(t, tree.root.children[1], 1, 2, []int{6}) - assertValidTreeNode(t, tree.root.children[0].children[0], 1, 0, []int{1}) - assertValidTreeNode(t, tree.root.children[0].children[1], 1, 0, []int{3}) - assertValidTreeNode(t, tree.root.children[1].children[0], 1, 0, []int{5}) - assertValidTreeNode(t, tree.root.children[1].children[1], 1, 0, []int{7}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{4}) + assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{2}) + assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{6}) + assertValidTreeNode(t, tree.Root.Children[0].Children[0], 1, 0, []int{1}) + assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{3}) + assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{5}) + assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{7}) } func TestBTree_insert2(t *testing.T) { @@ -107,38 +107,38 @@ func TestBTree_insert2(t *testing.T) { tree.Put(0, 0) assertValidTree(t, tree, 1) - assertValidTreeNode(t, tree.root, 1, 0, []int{0}) + assertValidTreeNode(t, tree.Root, 1, 0, []int{0}) tree.Put(2, 2) assertValidTree(t, tree, 2) - assertValidTreeNode(t, tree.root, 2, 0, []int{0, 2}) + assertValidTreeNode(t, tree.Root, 2, 0, []int{0, 2}) tree.Put(1, 1) assertValidTree(t, tree, 3) - assertValidTreeNode(t, tree.root, 3, 0, []int{0, 1, 2}) + assertValidTreeNode(t, tree.Root, 3, 0, []int{0, 1, 2}) tree.Put(1, 1) assertValidTree(t, tree, 3) - assertValidTreeNode(t, tree.root, 3, 0, []int{0, 1, 2}) + assertValidTreeNode(t, tree.Root, 3, 0, []int{0, 1, 2}) tree.Put(3, 3) assertValidTree(t, tree, 4) - assertValidTreeNode(t, tree.root, 1, 2, []int{1}) - assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{0}) - assertValidTreeNode(t, tree.root.children[1], 2, 0, []int{2, 3}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{1}) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{0}) + assertValidTreeNode(t, tree.Root.Children[1], 2, 0, []int{2, 3}) tree.Put(4, 4) assertValidTree(t, tree, 5) - assertValidTreeNode(t, tree.root, 1, 2, []int{1}) - assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{0}) - assertValidTreeNode(t, tree.root.children[1], 3, 0, []int{2, 3, 4}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{1}) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{0}) + assertValidTreeNode(t, tree.Root.Children[1], 3, 0, []int{2, 3, 4}) tree.Put(5, 5) assertValidTree(t, tree, 6) - assertValidTreeNode(t, tree.root, 2, 3, []int{1, 3}) - assertValidTreeNode(t, tree.root.children[0], 1, 0, []int{0}) - assertValidTreeNode(t, tree.root.children[1], 1, 0, []int{2}) - assertValidTreeNode(t, tree.root.children[2], 2, 0, []int{4, 5}) + assertValidTreeNode(t, tree.Root, 2, 3, []int{1, 3}) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{0}) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{2}) + assertValidTreeNode(t, tree.Root.Children[2], 2, 0, []int{4, 5}) } func TestBTree_insert3(t *testing.T) { @@ -148,48 +148,48 @@ func TestBTree_insert3(t *testing.T) { tree.Put(10, 0) assertValidTree(t, tree, 1) - assertValidTreeNode(t, tree.root, 1, 0, []int{10}) + assertValidTreeNode(t, tree.Root, 1, 0, []int{10}) tree.Put(20, 1) assertValidTree(t, tree, 2) - assertValidTreeNode(t, tree.root, 2, 0, []int{10, 20}) + assertValidTreeNode(t, tree.Root, 2, 0, []int{10, 20}) tree.Put(30, 2) assertValidTree(t, tree, 3) - assertValidTreeNode(t, tree.root, 3, 0, []int{10, 20, 30}) + assertValidTreeNode(t, tree.Root, 3, 0, []int{10, 20, 30}) tree.Put(40, 3) assertValidTree(t, tree, 4) - assertValidTreeNode(t, tree.root, 4, 0, []int{10, 20, 30, 40}) + assertValidTreeNode(t, tree.Root, 4, 0, []int{10, 20, 30, 40}) tree.Put(50, 4) assertValidTree(t, tree, 5) - assertValidTreeNode(t, tree.root, 5, 0, []int{10, 20, 30, 40, 50}) + assertValidTreeNode(t, tree.Root, 5, 0, []int{10, 20, 30, 40, 50}) tree.Put(60, 5) assertValidTree(t, tree, 6) - assertValidTreeNode(t, tree.root, 1, 2, []int{30}) - assertValidTreeNode(t, tree.root.children[0], 2, 0, []int{10, 20}) - assertValidTreeNode(t, tree.root.children[1], 3, 0, []int{40, 50, 60}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{30}) + assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}) + assertValidTreeNode(t, tree.Root.Children[1], 3, 0, []int{40, 50, 60}) tree.Put(70, 6) assertValidTree(t, tree, 7) - assertValidTreeNode(t, tree.root, 1, 2, []int{30}) - assertValidTreeNode(t, tree.root.children[0], 2, 0, []int{10, 20}) - assertValidTreeNode(t, tree.root.children[1], 4, 0, []int{40, 50, 60, 70}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{30}) + assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}) + assertValidTreeNode(t, tree.Root.Children[1], 4, 0, []int{40, 50, 60, 70}) tree.Put(80, 7) assertValidTree(t, tree, 8) - assertValidTreeNode(t, tree.root, 1, 2, []int{30}) - assertValidTreeNode(t, tree.root.children[0], 2, 0, []int{10, 20}) - assertValidTreeNode(t, tree.root.children[1], 5, 0, []int{40, 50, 60, 70, 80}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{30}) + assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}) + assertValidTreeNode(t, tree.Root.Children[1], 5, 0, []int{40, 50, 60, 70, 80}) tree.Put(90, 8) assertValidTree(t, tree, 9) - assertValidTreeNode(t, tree.root, 2, 3, []int{30, 60}) - assertValidTreeNode(t, tree.root.children[0], 2, 0, []int{10, 20}) - assertValidTreeNode(t, tree.root.children[1], 2, 0, []int{40, 50}) - assertValidTreeNode(t, tree.root.children[2], 3, 0, []int{70, 80, 90}) + assertValidTreeNode(t, tree.Root, 2, 3, []int{30, 60}) + assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}) + assertValidTreeNode(t, tree.Root.Children[1], 2, 0, []int{40, 50}) + assertValidTreeNode(t, tree.Root.Children[2], 3, 0, []int{70, 80, 90}) } func assertValidTree(t *testing.T, tree *Tree, expectedSize int) { @@ -199,14 +199,14 @@ func assertValidTree(t *testing.T, tree *Tree, expectedSize int) { } func assertValidTreeNode(t *testing.T, node *Node, expectedEntries int, expectedChildren int, keys []int) { - if actualValue, expectedValue := len(node.entries), expectedEntries; actualValue != expectedValue { + if actualValue, expectedValue := len(node.Entries), expectedEntries; actualValue != expectedValue { t.Errorf("Got %v expected %v for entries size", actualValue, expectedValue) } - if actualValue, expectedValue := len(node.children), expectedChildren; actualValue != expectedValue { + if actualValue, expectedValue := len(node.Children), expectedChildren; actualValue != expectedValue { t.Errorf("Got %v expected %v for children size", actualValue, expectedValue) } for i, key := range keys { - if actualValue, expectedValue := node.entries[i].key, key; actualValue != expectedValue { + if actualValue, expectedValue := node.Entries[i].Key, key; actualValue != expectedValue { t.Errorf("Got %v expected %v for key", actualValue, expectedValue) } } diff --git a/trees/btree/main/main.go b/trees/btree/main/main.go deleted file mode 100644 index 145f36d5..00000000 --- a/trees/btree/main/main.go +++ /dev/null @@ -1,14 +0,0 @@ -package main - -import ( - "github.com/emirpasic/gods/trees/btree" - "fmt" -) - -func main() { - tree := btree.NewWithIntComparator(3) - tree.Put(1, 0) - tree.Put(2, 1) - tree.Put(3, 2) - fmt.Println() -} From eecaef5625b71899309ef7f9c93798faa5c71925 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 10 Jul 2016 05:16:02 +0200 Subject: [PATCH 091/320] - btree Height() and String() implementations --- trees/btree/btree.go | 48 ++++++++++++++++++++++-------- trees/btree/btree_test.go | 42 ++++++++++++++++++++++++++ trees/redblacktree/redblacktree.go | 1 - 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/trees/btree/btree.go b/trees/btree/btree.go index d3658255..578e8077 100644 --- a/trees/btree/btree.go +++ b/trees/btree/btree.go @@ -10,9 +10,11 @@ package btree import ( + "bytes" "fmt" "github.com/emirpasic/gods/trees" "github.com/emirpasic/gods/utils" + "strings" ) func assertTreeImplementation() { @@ -114,23 +116,49 @@ func (tree *Tree) Clear() { tree.size = 0 } -// String returns a string representation of container +// Height returns the height of the tree. +func (tree *Tree) Height() int { + return tree.Root.height() +} + +// String returns a string representation of container (for debugging purposes) func (tree *Tree) String() string { - str := "BTree\n" + var buffer bytes.Buffer + buffer.WriteString("BTree\n") if !tree.Empty() { - str += tree.Root.String() + tree.output(&buffer, tree.Root, 0, true) } - return str -} - -func (node *Node) String() string { - return fmt.Sprintf("%v", node.Entries) + return buffer.String() } func (entry *Entry) String() string { return fmt.Sprintf("%v", entry.Key) } +func (tree *Tree) output(buffer *bytes.Buffer, node *Node, level int, isTail bool) { + for e := 0; e < len(node.Entries)+1; e++ { + if e < len(node.Children) { + buffer.WriteString(strings.Repeat(" ", level)) + tree.output(buffer, node.Children[e], level+1, true) + } + if e < len(node.Entries) { + buffer.WriteString(strings.Repeat(" ", level)) + buffer.WriteString(fmt.Sprintf("%v", node.Entries[e].Key) + "\n") + } + } +} + +func (node *Node) height() int { + height := 0 + for ; node != nil; node = node.Children[0] { + height++ + if len(node.Children) == 0 { + break + } + } + return height +} + func (tree *Tree) isLeaf(node *Node) bool { return len(node.Children) == 0 } @@ -183,7 +211,6 @@ func (tree *Tree) insert(node *Node, entry *Entry) (inserted bool) { func (tree *Tree) insertIntoLeaf(node *Node, entry *Entry) (inserted bool) { insertPosition, found := tree.search(node, entry) if found { - node.Entries[insertPosition] = nil // GC node.Entries[insertPosition] = entry return false } @@ -197,7 +224,6 @@ func (tree *Tree) insertIntoLeaf(node *Node, entry *Entry) (inserted bool) { func (tree *Tree) insertIntoInternal(node *Node, entry *Entry) (inserted bool) { insertPosition, found := tree.search(node, entry) if found { - node.Entries[insertPosition] = nil // GC node.Entries[insertPosition] = entry return false } @@ -240,8 +266,6 @@ func (tree *Tree) splitNonRoot(node *Node) { copy(parent.Children[insertPosition+2:], parent.Children[insertPosition+1:]) parent.Children[insertPosition+1] = right - node = nil // GC - tree.split(parent) } diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index 3a873441..619c80fb 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -192,6 +192,48 @@ func TestBTree_insert3(t *testing.T) { assertValidTreeNode(t, tree.Root.Children[2], 3, 0, []int{70, 80, 90}) } +func TestBTree_height(t *testing.T) { + tree := NewWithIntComparator(3) + if actualValue, expectedValue := tree.Height(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + tree.Put(1, 0) + if actualValue, expectedValue := tree.Height(), 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + tree.Put(2, 1) + if actualValue, expectedValue := tree.Height(), 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + tree.Put(3, 2) + if actualValue, expectedValue := tree.Height(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + tree.Put(4, 2) + if actualValue, expectedValue := tree.Height(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + tree.Put(5, 2) + if actualValue, expectedValue := tree.Height(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + tree.Put(6, 2) + if actualValue, expectedValue := tree.Height(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + tree.Put(7, 2) + if actualValue, expectedValue := tree.Height(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + func assertValidTree(t *testing.T, tree *Tree, expectedSize int) { if actualValue, expectedValue := tree.size, expectedSize; actualValue != expectedValue { t.Errorf("Got %v expected %v for tree size", actualValue, expectedValue) diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 10c0b0e2..a8a496ec 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -268,7 +268,6 @@ func (node *Node) String() string { return fmt.Sprintf("%v", node.Key) } -// String returns a string representation of container func output(node *Node, prefix string, isTail bool, str *string) { if node.Right != nil { newPrefix := prefix From 2df9ce1ab54c0517f269d2ed1d443fef4b7c2ab0 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 10 Jul 2016 22:03:59 +0200 Subject: [PATCH 092/320] - btree put fixes --- trees/btree/btree.go | 53 +++++-- trees/btree/btree_test.go | 326 ++++++++++++++++++++++++++------------ 2 files changed, 266 insertions(+), 113 deletions(-) diff --git a/trees/btree/btree.go b/trees/btree/btree.go index 578e8077..18bcb53e 100644 --- a/trees/btree/btree.go +++ b/trees/btree/btree.go @@ -26,7 +26,7 @@ type Tree struct { Root *Node // Root node Comparator utils.Comparator // Key comparator size int // Total number of keys in the tree - m int // Knuth order (maximum number of children) + m int // order (maximum number of children) } // Node is a single element within the tree @@ -42,7 +42,7 @@ type Entry struct { Value interface{} } -// NewWith instantiates a B-tree with the Knuth order (maximum number of children) and a custom key comparator. +// NewWith instantiates a B-tree with the order (maximum number of children) and a custom key comparator. func NewWith(order int, comparator utils.Comparator) *Tree { if order < 2 { panic("Invalid order, should be at least 2") @@ -50,12 +50,12 @@ func NewWith(order int, comparator utils.Comparator) *Tree { return &Tree{m: order, Comparator: comparator} } -// NewWithIntComparator instantiates a B-tree with the Knuth order (maximum number of children) and the IntComparator, i.e. keys are of type int. +// NewWithIntComparator instantiates a B-tree with the order (maximum number of children) and the IntComparator, i.e. keys are of type int. func NewWithIntComparator(order int) *Tree { return NewWith(order, utils.IntComparator) } -// NewWithStringComparator instantiates a B-tree with the Knuth order (maximum number of children) and the StringComparator, i.e. keys are of type string. +// NewWithStringComparator instantiates a B-tree with the order (maximum number of children) and the StringComparator, i.e. keys are of type string. func NewWithStringComparator(order int) *Tree { return NewWith(order, utils.StringComparator) } @@ -81,7 +81,20 @@ func (tree *Tree) Put(key interface{}, value interface{}) { // Second return parameter is true if key was found, otherwise false. // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree) Get(key interface{}) (value interface{}, found bool) { - return nil, false + if tree.Empty() { + return nil, false + } + node := tree.Root + for { + index, found := tree.search(node, key) + if found { + return node.Entries[index].Value, true + } + if tree.isLeaf(node) { + return nil, false + } + node = node.Children[index] + } } // Remove remove the node from the tree by key. @@ -138,7 +151,6 @@ func (entry *Entry) String() string { func (tree *Tree) output(buffer *bytes.Buffer, node *Node, level int, isTail bool) { for e := 0; e < len(node.Entries)+1; e++ { if e < len(node.Children) { - buffer.WriteString(strings.Repeat(" ", level)) tree.output(buffer, node.Children[e], level+1, true) } if e < len(node.Entries) { @@ -183,12 +195,12 @@ func (tree *Tree) middle() int { return (tree.m - 1) / 2 // "-1" to favor right nodes to have more keys when splitting } -func (tree *Tree) search(node *Node, entry *Entry) (index int, found bool) { +func (tree *Tree) search(node *Node, key interface{}) (index int, found bool) { low, high := 0, len(node.Entries)-1 var mid int for low <= high { mid = (high + low) / 2 - compare := tree.Comparator(entry.Key, node.Entries[mid].Key) + compare := tree.Comparator(key, node.Entries[mid].Key) switch { case compare > 0: low = mid + 1 @@ -209,11 +221,12 @@ func (tree *Tree) insert(node *Node, entry *Entry) (inserted bool) { } func (tree *Tree) insertIntoLeaf(node *Node, entry *Entry) (inserted bool) { - insertPosition, found := tree.search(node, entry) + insertPosition, found := tree.search(node, entry.Key) if found { node.Entries[insertPosition] = entry return false } + // Insert entry's key in the middle of the node node.Entries = append(node.Entries, nil) copy(node.Entries[insertPosition+1:], node.Entries[insertPosition:]) node.Entries[insertPosition] = entry @@ -222,7 +235,7 @@ func (tree *Tree) insertIntoLeaf(node *Node, entry *Entry) (inserted bool) { } func (tree *Tree) insertIntoInternal(node *Node, entry *Entry) (inserted bool) { - insertPosition, found := tree.search(node, entry) + insertPosition, found := tree.search(node, entry.Key) if found { node.Entries[insertPosition] = entry return false @@ -246,22 +259,30 @@ func (tree *Tree) split(node *Node) { func (tree *Tree) splitNonRoot(node *Node) { middle := tree.middle() parent := node.Parent + if node.Parent == nil { + panic("test") //TODO + } - left := &Node{Entries: node.Entries[:middle], Parent: parent} - right := &Node{Entries: node.Entries[middle+1:], Parent: parent} + left := &Node{Entries: append([]*Entry(nil), node.Entries[:middle]...), Parent: parent} + right := &Node{Entries: append([]*Entry(nil), node.Entries[middle+1:]...), Parent: parent} + // Move children from the node to be split into left and right nodes if !tree.isLeaf(node) { left.Children = node.Children[:middle+1] right.Children = node.Children[middle+1:] } - insertPosition, _ := tree.search(parent, node.Entries[middle]) + insertPosition, _ := tree.search(parent, node.Entries[middle].Key) + + // Insert middle key into parent parent.Entries = append(parent.Entries, nil) copy(parent.Entries[insertPosition+1:], parent.Entries[insertPosition:]) parent.Entries[insertPosition] = node.Entries[middle] + // Set child left of inserted key in parent to the created left node parent.Children[insertPosition] = left + // Set child right of inserted key in parent to the created right node parent.Children = append(parent.Children, nil) copy(parent.Children[insertPosition+2:], parent.Children[insertPosition+1:]) parent.Children[insertPosition+1] = right @@ -272,14 +293,16 @@ func (tree *Tree) splitNonRoot(node *Node) { func (tree *Tree) splitRoot() { middle := tree.middle() - left := &Node{Entries: tree.Root.Entries[:middle]} - right := &Node{Entries: tree.Root.Entries[middle+1:]} + left := &Node{Entries: append([]*Entry(nil), tree.Root.Entries[:middle]...)} + right := &Node{Entries: append([]*Entry(nil), tree.Root.Entries[middle+1:]...)} + // Move children from the node to be split into left and right nodes if !tree.isLeaf(tree.Root) { left.Children = tree.Root.Children[:middle+1] right.Children = tree.Root.Children[middle+1:] } + // Root is a node with one entry and two children (left and right) newRoot := &Node{ Entries: []*Entry{tree.Root.Entries[middle]}, Children: []*Node{left, right}, diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index 619c80fb..0912bbf5 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -5,194 +5,279 @@ package btree import ( - _ "fmt" + "fmt" "testing" ) -func TestBTree_search(t *testing.T) { - { - tree := NewWithIntComparator(3) - tree.Root = &Node{Entries: []*Entry{}, Children: make([]*Node, 0)} - tests := [][]interface{}{ - {0, 0, false}, - } - for _, test := range tests { - index, found := tree.search(tree.Root, &Entry{test[0], nil}) - if actualValue, expectedValue := index, test[1]; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := found, test[2]; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - } +func TestBTreeGet1(t *testing.T) { + tree := NewWithIntComparator(3) + tree.Put(1, "a") + tree.Put(2, "b") + tree.Put(3, "c") + tree.Put(4, "d") + tree.Put(5, "e") + tree.Put(6, "f") + tree.Put(7, "g") + + tests := [][]interface{}{ + {0, nil, false}, + {1, "a", true}, + {2, "b", true}, + {3, "c", true}, + {4, "d", true}, + {5, "e", true}, + {6, "f", true}, + {7, "g", true}, + {8, nil, false}, } - { - tree := NewWithIntComparator(3) - tree.Root = &Node{Entries: []*Entry{{2, 0}, {4, 1}, {6, 2}}, Children: []*Node{}} - tests := [][]interface{}{ - {0, 0, false}, - {1, 0, false}, - {2, 0, true}, - {3, 1, false}, - {4, 1, true}, - {5, 2, false}, - {6, 2, true}, - {7, 3, false}, - } - for _, test := range tests { - index, found := tree.search(tree.Root, &Entry{test[0], nil}) - if actualValue, expectedValue := index, test[1]; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := found, test[2]; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + + for _, test := range tests { + if value, found := tree.Get(test[0]); value != test[1] || found != test[2] { + t.Errorf("Got %v,%v expected %v,%v", value, found, test[1], test[2]) } } } -func TestBTree_insert1(t *testing.T) { +func TestBTreeGet2(t *testing.T) { + //tree := NewWithIntComparator(3) + //tree.Put(7, "g") + //tree.Put(9, "i") + //tree.Put(10, "j") + //tree.Put(6, "f") + //tree.Put(3, "c") + //tree.Put(4, "d") + //tree.Put(5, "e") + //tree.Put(8, "h") + //tree.Put(2, "b") + ////tree.Put(1, "a") + //fmt.Println(tree) + // + //tests := [][]interface{}{ + // {0, nil, false}, + // {1, "a", true}, + // {2, "b", true}, + // {3, "c", true}, + // {4, "d", true}, + // {5, "e", true}, + // {6, "f", true}, + // {7, "g", true}, + // {8, "h", true}, + // {9, "i", true}, + // {10, "j", true}, + // {11, nil, false}, + //} + // + //for _, test := range tests { + // if value, found := tree.Get(test[0]); value != test[1] || found != test[2] { + // t.Errorf("Got %v,%v expected %v,%v", value, found, test[1], test[2]) + // } + //} +} + +func TestBTreePut1(t *testing.T) { // https://upload.wikimedia.org/wikipedia/commons/3/33/B_tree_insertion_example.png tree := NewWithIntComparator(3) assertValidTree(t, tree, 0) tree.Put(1, 0) assertValidTree(t, tree, 1) - assertValidTreeNode(t, tree.Root, 1, 0, []int{1}) + assertValidTreeNode(t, tree.Root, 1, 0, []int{1}, false) tree.Put(2, 1) assertValidTree(t, tree, 2) - assertValidTreeNode(t, tree.Root, 2, 0, []int{1, 2}) + assertValidTreeNode(t, tree.Root, 2, 0, []int{1, 2}, false) tree.Put(3, 2) assertValidTree(t, tree, 3) - assertValidTreeNode(t, tree.Root, 1, 2, []int{2}) - assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}) - assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{3}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{2}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{3}, true) tree.Put(4, 2) assertValidTree(t, tree, 4) - assertValidTreeNode(t, tree.Root, 1, 2, []int{2}) - assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}) - assertValidTreeNode(t, tree.Root.Children[1], 2, 0, []int{3, 4}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{2}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}, true) + assertValidTreeNode(t, tree.Root.Children[1], 2, 0, []int{3, 4}, true) tree.Put(5, 2) assertValidTree(t, tree, 5) - assertValidTreeNode(t, tree.Root, 2, 3, []int{2, 4}) - assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}) - assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{3}) - assertValidTreeNode(t, tree.Root.Children[2], 1, 0, []int{5}) + assertValidTreeNode(t, tree.Root, 2, 3, []int{2, 4}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{3}, true) + assertValidTreeNode(t, tree.Root.Children[2], 1, 0, []int{5}, true) tree.Put(6, 2) assertValidTree(t, tree, 6) - assertValidTreeNode(t, tree.Root, 2, 3, []int{2, 4}) - assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}) - assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{3}) - assertValidTreeNode(t, tree.Root.Children[2], 2, 0, []int{5, 6}) + assertValidTreeNode(t, tree.Root, 2, 3, []int{2, 4}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{3}, true) + assertValidTreeNode(t, tree.Root.Children[2], 2, 0, []int{5, 6}, true) tree.Put(7, 2) assertValidTree(t, tree, 7) - assertValidTreeNode(t, tree.Root, 1, 2, []int{4}) - assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{2}) - assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{6}) - assertValidTreeNode(t, tree.Root.Children[0].Children[0], 1, 0, []int{1}) - assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{3}) - assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{5}) - assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{7}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{4}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{2}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{6}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[0], 1, 0, []int{1}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{3}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{5}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{7}, true) } -func TestBTree_insert2(t *testing.T) { +func TestBTreePut2(t *testing.T) { tree := NewWithIntComparator(4) assertValidTree(t, tree, 0) tree.Put(0, 0) assertValidTree(t, tree, 1) - assertValidTreeNode(t, tree.Root, 1, 0, []int{0}) + assertValidTreeNode(t, tree.Root, 1, 0, []int{0}, false) tree.Put(2, 2) assertValidTree(t, tree, 2) - assertValidTreeNode(t, tree.Root, 2, 0, []int{0, 2}) + assertValidTreeNode(t, tree.Root, 2, 0, []int{0, 2}, false) tree.Put(1, 1) assertValidTree(t, tree, 3) - assertValidTreeNode(t, tree.Root, 3, 0, []int{0, 1, 2}) + assertValidTreeNode(t, tree.Root, 3, 0, []int{0, 1, 2}, false) tree.Put(1, 1) assertValidTree(t, tree, 3) - assertValidTreeNode(t, tree.Root, 3, 0, []int{0, 1, 2}) + assertValidTreeNode(t, tree.Root, 3, 0, []int{0, 1, 2}, false) tree.Put(3, 3) assertValidTree(t, tree, 4) - assertValidTreeNode(t, tree.Root, 1, 2, []int{1}) - assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{0}) - assertValidTreeNode(t, tree.Root.Children[1], 2, 0, []int{2, 3}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{1}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{0}, true) + assertValidTreeNode(t, tree.Root.Children[1], 2, 0, []int{2, 3}, true) tree.Put(4, 4) assertValidTree(t, tree, 5) - assertValidTreeNode(t, tree.Root, 1, 2, []int{1}) - assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{0}) - assertValidTreeNode(t, tree.Root.Children[1], 3, 0, []int{2, 3, 4}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{1}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{0}, true) + assertValidTreeNode(t, tree.Root.Children[1], 3, 0, []int{2, 3, 4}, true) tree.Put(5, 5) assertValidTree(t, tree, 6) - assertValidTreeNode(t, tree.Root, 2, 3, []int{1, 3}) - assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{0}) - assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{2}) - assertValidTreeNode(t, tree.Root.Children[2], 2, 0, []int{4, 5}) + assertValidTreeNode(t, tree.Root, 2, 3, []int{1, 3}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{0}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{2}, true) + assertValidTreeNode(t, tree.Root.Children[2], 2, 0, []int{4, 5}, true) } -func TestBTree_insert3(t *testing.T) { +func TestBTreePut3(t *testing.T) { // http://www.geeksforgeeks.org/b-tree-set-1-insert-2/ tree := NewWithIntComparator(6) assertValidTree(t, tree, 0) tree.Put(10, 0) assertValidTree(t, tree, 1) - assertValidTreeNode(t, tree.Root, 1, 0, []int{10}) + assertValidTreeNode(t, tree.Root, 1, 0, []int{10}, false) tree.Put(20, 1) assertValidTree(t, tree, 2) - assertValidTreeNode(t, tree.Root, 2, 0, []int{10, 20}) + assertValidTreeNode(t, tree.Root, 2, 0, []int{10, 20}, false) tree.Put(30, 2) assertValidTree(t, tree, 3) - assertValidTreeNode(t, tree.Root, 3, 0, []int{10, 20, 30}) + assertValidTreeNode(t, tree.Root, 3, 0, []int{10, 20, 30}, false) tree.Put(40, 3) assertValidTree(t, tree, 4) - assertValidTreeNode(t, tree.Root, 4, 0, []int{10, 20, 30, 40}) + assertValidTreeNode(t, tree.Root, 4, 0, []int{10, 20, 30, 40}, false) tree.Put(50, 4) assertValidTree(t, tree, 5) - assertValidTreeNode(t, tree.Root, 5, 0, []int{10, 20, 30, 40, 50}) + assertValidTreeNode(t, tree.Root, 5, 0, []int{10, 20, 30, 40, 50}, false) tree.Put(60, 5) assertValidTree(t, tree, 6) - assertValidTreeNode(t, tree.Root, 1, 2, []int{30}) - assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}) - assertValidTreeNode(t, tree.Root.Children[1], 3, 0, []int{40, 50, 60}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{30}, false) + assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}, true) + assertValidTreeNode(t, tree.Root.Children[1], 3, 0, []int{40, 50, 60}, true) tree.Put(70, 6) assertValidTree(t, tree, 7) - assertValidTreeNode(t, tree.Root, 1, 2, []int{30}) - assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}) - assertValidTreeNode(t, tree.Root.Children[1], 4, 0, []int{40, 50, 60, 70}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{30}, false) + assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}, true) + assertValidTreeNode(t, tree.Root.Children[1], 4, 0, []int{40, 50, 60, 70}, true) tree.Put(80, 7) assertValidTree(t, tree, 8) - assertValidTreeNode(t, tree.Root, 1, 2, []int{30}) - assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}) - assertValidTreeNode(t, tree.Root.Children[1], 5, 0, []int{40, 50, 60, 70, 80}) + assertValidTreeNode(t, tree.Root, 1, 2, []int{30}, false) + assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}, true) + assertValidTreeNode(t, tree.Root.Children[1], 5, 0, []int{40, 50, 60, 70, 80}, true) tree.Put(90, 8) assertValidTree(t, tree, 9) - assertValidTreeNode(t, tree.Root, 2, 3, []int{30, 60}) - assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}) - assertValidTreeNode(t, tree.Root.Children[1], 2, 0, []int{40, 50}) - assertValidTreeNode(t, tree.Root.Children[2], 3, 0, []int{70, 80, 90}) + assertValidTreeNode(t, tree.Root, 2, 3, []int{30, 60}, false) + assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}, true) + assertValidTreeNode(t, tree.Root.Children[1], 2, 0, []int{40, 50}, true) + assertValidTreeNode(t, tree.Root.Children[2], 3, 0, []int{70, 80, 90}, true) +} + +func TestBTreePut4(t *testing.T) { + tree := NewWithIntComparator(3) + assertValidTree(t, tree, 0) + + tree.Put(6, nil) + assertValidTree(t, tree, 1) + assertValidTreeNode(t, tree.Root, 1, 0, []int{6}, false) + + tree.Put(5, nil) + assertValidTree(t, tree, 2) + assertValidTreeNode(t, tree.Root, 2, 0, []int{5, 6}, false) + + tree.Put(4, nil) + assertValidTree(t, tree, 3) + assertValidTreeNode(t, tree.Root, 1, 2, []int{5}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{4}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{6}, true) + + tree.Put(3, nil) + assertValidTreeNode(t, tree.Root, 1, 2, []int{5}, false) + assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{3, 4}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{6}, true) + + tree.Put(2, nil) + assertValidTreeNode(t, tree.Root, 2, 3, []int{3, 5}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{2}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{4}, true) + assertValidTreeNode(t, tree.Root.Children[2], 1, 0, []int{6}, true) + + tree.Put(1, nil) + assertValidTreeNode(t, tree.Root, 2, 3, []int{3, 5}, false) + assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{1, 2}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{4}, true) + assertValidTreeNode(t, tree.Root.Children[2], 1, 0, []int{6}, true) + + tree.Put(0, nil) + assertValidTreeNode(t, tree.Root, 1, 2, []int{3}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{1}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{5}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[0], 1, 0, []int{0}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{2}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{4}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{6}, true) + + tree.Put(-1, nil) + assertValidTreeNode(t, tree.Root, 1, 2, []int{3}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{1}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{5}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[0], 2, 0, []int{-1, 0}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{2}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{4}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{6}, true) + + fmt.Println(tree) + //tree.Put(-2, nil) + //tree.Put(-3, nil) + //tree.Put(-4, nil) + //tree.Put(-5, nil) + //tree.Put(-6, nil) + //fmt.Println(tree) } -func TestBTree_height(t *testing.T) { +func TestBTreeHeight(t *testing.T) { tree := NewWithIntComparator(3) if actualValue, expectedValue := tree.Height(), 0; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -234,13 +319,58 @@ func TestBTree_height(t *testing.T) { } } +func TestBTree_search(t *testing.T) { + { + tree := NewWithIntComparator(3) + tree.Root = &Node{Entries: []*Entry{}, Children: make([]*Node, 0)} + tests := [][]interface{}{ + {0, 0, false}, + } + for _, test := range tests { + index, found := tree.search(tree.Root, test[0]) + if actualValue, expectedValue := index, test[1]; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := found, test[2]; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + { + tree := NewWithIntComparator(3) + tree.Root = &Node{Entries: []*Entry{{2, 0}, {4, 1}, {6, 2}}, Children: []*Node{}} + tests := [][]interface{}{ + {0, 0, false}, + {1, 0, false}, + {2, 0, true}, + {3, 1, false}, + {4, 1, true}, + {5, 2, false}, + {6, 2, true}, + {7, 3, false}, + } + for _, test := range tests { + index, found := tree.search(tree.Root, test[0]) + if actualValue, expectedValue := index, test[1]; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := found, test[2]; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } +} + func assertValidTree(t *testing.T, tree *Tree, expectedSize int) { if actualValue, expectedValue := tree.size, expectedSize; actualValue != expectedValue { t.Errorf("Got %v expected %v for tree size", actualValue, expectedValue) } } -func assertValidTreeNode(t *testing.T, node *Node, expectedEntries int, expectedChildren int, keys []int) { +func assertValidTreeNode(t *testing.T, node *Node, expectedEntries int, expectedChildren int, keys []int, hasParent bool) { + if actualValue, expectedValue := node.Parent != nil, hasParent; actualValue != expectedValue { + t.Errorf("Got %v expected %v for hasParent", actualValue, expectedValue) + } if actualValue, expectedValue := len(node.Entries), expectedEntries; actualValue != expectedValue { t.Errorf("Got %v expected %v for entries size", actualValue, expectedValue) } From 966309396146cac614349ad51dcc1d7f20516bc2 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 11 Jul 2016 00:18:00 +0200 Subject: [PATCH 093/320] - btree put fixes --- trees/btree/btree.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/trees/btree/btree.go b/trees/btree/btree.go index 18bcb53e..212e4702 100644 --- a/trees/btree/btree.go +++ b/trees/btree/btree.go @@ -259,9 +259,6 @@ func (tree *Tree) split(node *Node) { func (tree *Tree) splitNonRoot(node *Node) { middle := tree.middle() parent := node.Parent - if node.Parent == nil { - panic("test") //TODO - } left := &Node{Entries: append([]*Entry(nil), node.Entries[:middle]...), Parent: parent} right := &Node{Entries: append([]*Entry(nil), node.Entries[middle+1:]...), Parent: parent} @@ -270,6 +267,8 @@ func (tree *Tree) splitNonRoot(node *Node) { if !tree.isLeaf(node) { left.Children = node.Children[:middle+1] right.Children = node.Children[middle+1:] + setParent(left.Children, left) + setParent(right.Children, right) } insertPosition, _ := tree.search(parent, node.Entries[middle].Key) @@ -300,6 +299,8 @@ func (tree *Tree) splitRoot() { if !tree.isLeaf(tree.Root) { left.Children = tree.Root.Children[:middle+1] right.Children = tree.Root.Children[middle+1:] + setParent(left.Children, left) + setParent(right.Children, right) } // Root is a node with one entry and two children (left and right) @@ -312,3 +313,9 @@ func (tree *Tree) splitRoot() { right.Parent = newRoot tree.Root = newRoot } + +func setParent(nodes []*Node, parent *Node) { + for _, node := range nodes { + node.Parent = parent + } +} From 4e3ff2046982c8529bb8dbe927f4e467914867d3 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 11 Jul 2016 01:00:52 +0200 Subject: [PATCH 094/320] - btree get and put tests --- trees/btree/btree.go | 11 ++-- trees/btree/btree_test.go | 113 ++++++++++++++++++++++++-------------- 2 files changed, 78 insertions(+), 46 deletions(-) diff --git a/trees/btree/btree.go b/trees/btree/btree.go index 212e4702..87cdcb7d 100644 --- a/trees/btree/btree.go +++ b/trees/btree/btree.go @@ -154,7 +154,7 @@ func (tree *Tree) output(buffer *bytes.Buffer, node *Node, level int, isTail boo tree.output(buffer, node.Children[e], level+1, true) } if e < len(node.Entries) { - buffer.WriteString(strings.Repeat(" ", level)) + buffer.WriteString(strings.Repeat(" ", level)) buffer.WriteString(fmt.Sprintf("%v", node.Entries[e].Key) + "\n") } } @@ -195,6 +195,7 @@ func (tree *Tree) middle() int { return (tree.m - 1) / 2 // "-1" to favor right nodes to have more keys when splitting } +// search searches only within the single node among its entries func (tree *Tree) search(node *Node, key interface{}) (index int, found bool) { low, high := 0, len(node.Entries)-1 var mid int @@ -265,8 +266,8 @@ func (tree *Tree) splitNonRoot(node *Node) { // Move children from the node to be split into left and right nodes if !tree.isLeaf(node) { - left.Children = node.Children[:middle+1] - right.Children = node.Children[middle+1:] + left.Children = append([]*Node(nil), node.Children[:middle+1]...) + right.Children = append([]*Node(nil), node.Children[middle+1:]...) setParent(left.Children, left) setParent(right.Children, right) } @@ -297,8 +298,8 @@ func (tree *Tree) splitRoot() { // Move children from the node to be split into left and right nodes if !tree.isLeaf(tree.Root) { - left.Children = tree.Root.Children[:middle+1] - right.Children = tree.Root.Children[middle+1:] + left.Children = append([]*Node(nil), tree.Root.Children[:middle+1]...) + right.Children = append([]*Node(nil), tree.Root.Children[middle+1:]...) setParent(left.Children, left) setParent(right.Children, right) } diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index 0912bbf5..f41c4255 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -5,7 +5,7 @@ package btree import ( - "fmt" + _ "fmt" "testing" ) @@ -39,39 +39,38 @@ func TestBTreeGet1(t *testing.T) { } func TestBTreeGet2(t *testing.T) { - //tree := NewWithIntComparator(3) - //tree.Put(7, "g") - //tree.Put(9, "i") - //tree.Put(10, "j") - //tree.Put(6, "f") - //tree.Put(3, "c") - //tree.Put(4, "d") - //tree.Put(5, "e") - //tree.Put(8, "h") - //tree.Put(2, "b") - ////tree.Put(1, "a") - //fmt.Println(tree) - // - //tests := [][]interface{}{ - // {0, nil, false}, - // {1, "a", true}, - // {2, "b", true}, - // {3, "c", true}, - // {4, "d", true}, - // {5, "e", true}, - // {6, "f", true}, - // {7, "g", true}, - // {8, "h", true}, - // {9, "i", true}, - // {10, "j", true}, - // {11, nil, false}, - //} - // - //for _, test := range tests { - // if value, found := tree.Get(test[0]); value != test[1] || found != test[2] { - // t.Errorf("Got %v,%v expected %v,%v", value, found, test[1], test[2]) - // } - //} + tree := NewWithIntComparator(3) + tree.Put(7, "g") + tree.Put(9, "i") + tree.Put(10, "j") + tree.Put(6, "f") + tree.Put(3, "c") + tree.Put(4, "d") + tree.Put(5, "e") + tree.Put(8, "h") + tree.Put(2, "b") + tree.Put(1, "a") + + tests := [][]interface{}{ + {0, nil, false}, + {1, "a", true}, + {2, "b", true}, + {3, "c", true}, + {4, "d", true}, + {5, "e", true}, + {6, "f", true}, + {7, "g", true}, + {8, "h", true}, + {9, "i", true}, + {10, "j", true}, + {11, nil, false}, + } + + for _, test := range tests { + if value, found := tree.Get(test[0]); value != test[1] || found != test[2] { + t.Errorf("Got %v,%v expected %v,%v", value, found, test[1], test[2]) + } + } } func TestBTreePut1(t *testing.T) { @@ -234,23 +233,27 @@ func TestBTreePut4(t *testing.T) { assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{6}, true) tree.Put(3, nil) + assertValidTree(t, tree, 4) assertValidTreeNode(t, tree.Root, 1, 2, []int{5}, false) assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{3, 4}, true) assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{6}, true) tree.Put(2, nil) + assertValidTree(t, tree, 5) assertValidTreeNode(t, tree.Root, 2, 3, []int{3, 5}, false) assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{2}, true) assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{4}, true) assertValidTreeNode(t, tree.Root.Children[2], 1, 0, []int{6}, true) tree.Put(1, nil) + assertValidTree(t, tree, 6) assertValidTreeNode(t, tree.Root, 2, 3, []int{3, 5}, false) assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{1, 2}, true) assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{4}, true) assertValidTreeNode(t, tree.Root.Children[2], 1, 0, []int{6}, true) tree.Put(0, nil) + assertValidTree(t, tree, 7) assertValidTreeNode(t, tree.Root, 1, 2, []int{3}, false) assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{1}, true) assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{5}, true) @@ -260,6 +263,7 @@ func TestBTreePut4(t *testing.T) { assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{6}, true) tree.Put(-1, nil) + assertValidTree(t, tree, 8) assertValidTreeNode(t, tree.Root, 1, 2, []int{3}, false) assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{1}, true) assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{5}, true) @@ -268,13 +272,40 @@ func TestBTreePut4(t *testing.T) { assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{4}, true) assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{6}, true) - fmt.Println(tree) - //tree.Put(-2, nil) - //tree.Put(-3, nil) - //tree.Put(-4, nil) - //tree.Put(-5, nil) - //tree.Put(-6, nil) - //fmt.Println(tree) + tree.Put(-2, nil) + assertValidTree(t, tree, 9) + assertValidTreeNode(t, tree.Root, 1, 2, []int{3}, false) + assertValidTreeNode(t, tree.Root.Children[0], 2, 3, []int{-1, 1}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{5}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[0], 1, 0, []int{-2}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{0}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[2], 1, 0, []int{2}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{4}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{6}, true) + + tree.Put(-3, nil) + assertValidTree(t, tree, 10) + assertValidTreeNode(t, tree.Root, 1, 2, []int{3}, false) + assertValidTreeNode(t, tree.Root.Children[0], 2, 3, []int{-1, 1}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{5}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[0], 2, 0, []int{-3, -2}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{0}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[2], 1, 0, []int{2}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{4}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{6}, true) + + tree.Put(-4, nil) + assertValidTree(t, tree, 11) + assertValidTreeNode(t, tree.Root, 2, 3, []int{-1, 3}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{-3}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{1}, true) + assertValidTreeNode(t, tree.Root.Children[2], 1, 2, []int{5}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[0], 1, 0, []int{-4}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{-2}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{0}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{2}, true) + assertValidTreeNode(t, tree.Root.Children[2].Children[0], 1, 0, []int{4}, true) + assertValidTreeNode(t, tree.Root.Children[2].Children[1], 1, 0, []int{6}, true) } func TestBTreeHeight(t *testing.T) { From 76711f5b7173d6b127af64a0bdacf93c17a02c26 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 11 Jul 2016 02:28:14 +0200 Subject: [PATCH 095/320] - btree don't allow order less than 3 - btree Left(), Right(), LeftKey(), RightKey(), LeftValue(), RightValue() implementation with tests --- trees/btree/btree.go | 64 +++++++++++++++++++++++++++++++++++++-- trees/btree/btree_test.go | 34 +++++++++++++++++++++ 2 files changed, 96 insertions(+), 2 deletions(-) diff --git a/trees/btree/btree.go b/trees/btree/btree.go index 87cdcb7d..97387231 100644 --- a/trees/btree/btree.go +++ b/trees/btree/btree.go @@ -44,8 +44,8 @@ type Entry struct { // NewWith instantiates a B-tree with the order (maximum number of children) and a custom key comparator. func NewWith(order int, comparator utils.Comparator) *Tree { - if order < 2 { - panic("Invalid order, should be at least 2") + if order < 3 { + panic("Invalid order, should be at least 3") } return &Tree{m: order, Comparator: comparator} } @@ -134,6 +134,66 @@ func (tree *Tree) Height() int { return tree.Root.height() } +// Left returns the left-most (min) node or nil if tree is empty. +func (tree *Tree) Left() *Node { + if tree.Empty() { + return nil + } + node := tree.Root + for { + if tree.isLeaf(node) { + return node + } + node = node.Children[0] + } +} + +// LeftKey returns the left-most (min) key or nil if tree is empty. +func (tree *Tree) LeftKey() interface{} { + if left := tree.Left(); left != nil { + return left.Entries[0].Key + } + return nil +} + +// LeftValue returns the left-most value or nil if tree is empty. +func (tree *Tree) LeftValue() interface{} { + if left := tree.Left(); left != nil { + return left.Entries[0].Value + } + return nil +} + +// Right returns the right-most (max) node or nil if tree is empty. +func (tree *Tree) Right() *Node { + if tree.Empty() { + return nil + } + node := tree.Root + for { + if tree.isLeaf(node) { + return node + } + node = node.Children[len(node.Children)-1] + } +} + +// RightKey returns the right-most (max) key or nil if tree is empty. +func (tree *Tree) RightKey() interface{} { + if right := tree.Right(); right != nil { + return right.Entries[len(right.Entries)-1].Key + } + return nil +} + +// RightValue returns the right-most value or nil if tree is empty. +func (tree *Tree) RightValue() interface{} { + if right := tree.Right(); right != nil { + return right.Entries[len(right.Entries)-1].Value + } + return nil +} + // String returns a string representation of container (for debugging purposes) func (tree *Tree) String() string { var buffer bytes.Buffer diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index f41c4255..dde69ef3 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -350,6 +350,40 @@ func TestBTreeHeight(t *testing.T) { } } +func TestBTreeLeftAndRight(t *testing.T) { + tree := NewWithIntComparator(3) + + if actualValue := tree.Left(); actualValue != nil { + t.Errorf("Got %v expected %v", actualValue, nil) + } + if actualValue := tree.Right(); actualValue != nil { + t.Errorf("Got %v expected %v", actualValue, nil) + } + + tree.Put(1, "a") + tree.Put(5, "e") + tree.Put(6, "f") + tree.Put(7, "g") + tree.Put(3, "c") + tree.Put(4, "d") + tree.Put(1, "x") // overwrite + tree.Put(2, "b") + + if actualValue, expectedValue := tree.LeftKey(), 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := tree.LeftValue(), "x"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + if actualValue, expectedValue := tree.RightKey(), 7; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := tree.RightValue(), "g"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + func TestBTree_search(t *testing.T) { { tree := NewWithIntComparator(3) From 53898058bb558e43cc0fffb9043604460f2d0dfe Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 12 Jul 2016 02:53:48 +0200 Subject: [PATCH 096/320] - btree iterator implemented with tests --- trees/btree/btree_test.go | 339 ++++++++++++++++++++++++++++++++++++++ trees/btree/iterator.go | 193 ++++++++++++++++++++++ 2 files changed, 532 insertions(+) create mode 100644 trees/btree/iterator.go diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index dde69ef3..71e86d2b 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -384,6 +384,345 @@ func TestBTreeLeftAndRight(t *testing.T) { } } +func TestBTreeIteratorNextOnEmpty(t *testing.T) { + tree := NewWithIntComparator(3) + it := tree.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty tree") + } +} + +func TestBTreeIteratorPrevOnEmpty(t *testing.T) { + tree := NewWithIntComparator(3) + it := tree.Iterator() + for it.Prev() { + t.Errorf("Shouldn't iterate on empty tree") + } +} + +func TestBTreeIterator1Next(t *testing.T) { + tree := NewWithIntComparator(3) + tree.Put(5, "e") + tree.Put(6, "f") + tree.Put(7, "g") + tree.Put(3, "c") + tree.Put(4, "d") + tree.Put(1, "x") + tree.Put(2, "b") + tree.Put(1, "a") //overwrite + it := tree.Iterator() + count := 0 + for it.Next() { + count++ + key := it.Key() + switch key { + case count: + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + +func TestBTreeIterator1Prev(t *testing.T) { + tree := NewWithIntComparator(3) + tree.Put(5, "e") + tree.Put(6, "f") + tree.Put(7, "g") + tree.Put(3, "c") + tree.Put(4, "d") + tree.Put(1, "x") + tree.Put(2, "b") + tree.Put(1, "a") //overwrite + it := tree.Iterator() + for it.Next() { + } + countDown := tree.size + for it.Prev() { + key := it.Key() + switch key { + case countDown: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + countDown-- + } + if actualValue, expectedValue := countDown, 0; actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + +func TestBTreeIterator2Next(t *testing.T) { + tree := NewWithIntComparator(3) + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it := tree.Iterator() + count := 0 + for it.Next() { + count++ + key := it.Key() + switch key { + case count: + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + +func TestBTreeIterator2Prev(t *testing.T) { + tree := NewWithIntComparator(3) + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it := tree.Iterator() + for it.Next() { + } + countDown := tree.size + for it.Prev() { + key := it.Key() + switch key { + case countDown: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + countDown-- + } + if actualValue, expectedValue := countDown, 0; actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + +func TestBTreeIterator3Next(t *testing.T) { + tree := NewWithIntComparator(3) + tree.Put(1, "a") + it := tree.Iterator() + count := 0 + for it.Next() { + count++ + key := it.Key() + switch key { + case count: + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + +func TestBTreeIterator3Prev(t *testing.T) { + tree := NewWithIntComparator(3) + tree.Put(1, "a") + it := tree.Iterator() + for it.Next() { + } + countDown := tree.size + for it.Prev() { + key := it.Key() + switch key { + case countDown: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + countDown-- + } + if actualValue, expectedValue := countDown, 0; actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + +func TestBTreeIterator4Next(t *testing.T) { + tree := NewWithIntComparator(3) + tree.Put(13, 5) + tree.Put(8, 3) + tree.Put(17, 7) + tree.Put(1, 1) + tree.Put(11, 4) + tree.Put(15, 6) + tree.Put(25, 9) + tree.Put(6, 2) + tree.Put(22, 8) + tree.Put(27, 10) + it := tree.Iterator() + count := 0 + for it.Next() { + count++ + value := it.Value() + switch value { + case count: + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + +func TestBTreeIterator4Prev(t *testing.T) { + tree := NewWithIntComparator(3) + tree.Put(13, 5) + tree.Put(8, 3) + tree.Put(17, 7) + tree.Put(1, 1) + tree.Put(11, 4) + tree.Put(15, 6) + tree.Put(25, 9) + tree.Put(6, 2) + tree.Put(22, 8) + tree.Put(27, 10) + it := tree.Iterator() + count := tree.Size() + for it.Next() { + } + for it.Prev() { + value := it.Value() + switch value { + case count: + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + count-- + } + if actualValue, expectedValue := count, 0; actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + +func TestBTreeIteratorBegin(t *testing.T) { + tree := NewWithIntComparator(3) + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it := tree.Iterator() + + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + it.Begin() + + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + for it.Next() { + } + + it.Begin() + + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + it.Next() + if key, value := it.Key(), it.Value(); key != 1 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") + } +} + +func TestBTreeIteratorEnd(t *testing.T) { + tree := NewWithIntComparator(3) + it := tree.Iterator() + + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + it.End() + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it.End() + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + it.Prev() + if key, value := it.Key(), it.Value(); key != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") + } +} + +func TestBTreeIteratorFirst(t *testing.T) { + tree := NewWithIntComparator(3) + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it := tree.Iterator() + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if key, value := it.Key(), it.Value(); key != 1 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") + } +} + +func TestBTreeIteratorLast(t *testing.T) { + tree := NewWithIntComparator(3) + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it := tree.Iterator() + if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if key, value := it.Key(), it.Value(); key != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") + } +} + func TestBTree_search(t *testing.T) { { tree := NewWithIntComparator(3) diff --git a/trees/btree/iterator.go b/trees/btree/iterator.go new file mode 100644 index 00000000..840db687 --- /dev/null +++ b/trees/btree/iterator.go @@ -0,0 +1,193 @@ +// 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 btree + +import "github.com/emirpasic/gods/containers" + +func assertIteratorImplementation() { + var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) +} + +// Iterator holding the iterator's state +type Iterator struct { + tree *Tree + node *Node + entry *Entry + position position +} + +type position byte + +const ( + begin, between, end position = 0, 1, 2 +) + +// Iterator returns a stateful iterator whose elements are key/value pairs. +func (tree *Tree) Iterator() Iterator { + return Iterator{tree: tree, node: nil, position: begin} +} + +// 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. +// Modifies the state of the iterator. +func (iterator *Iterator) Next() bool { + // If already at end, go to end + if iterator.position == end { + goto end + } + // If at beginning, get the left-most entry in the tree + if iterator.position == begin { + left := iterator.tree.Left() + if left == nil { + goto end + } + iterator.node = left + iterator.entry = left.Entries[0] + goto between + } + { + // Find current entry position in current node + e, _ := iterator.tree.search(iterator.node, iterator.entry.Key) + // Try to go down to the child right of the current entry + if e+1 < len(iterator.node.Children) { + iterator.node = iterator.node.Children[e+1] + // Try to go down to the child left of the current node + for len(iterator.node.Children) > 0 { + iterator.node = iterator.node.Children[0] + } + // Return the left-most entry + iterator.entry = iterator.node.Entries[0] + goto between + } + // Above assures that we have reached a leaf node, so return the next entry in current node (if any) + if e+1 < len(iterator.node.Entries) { + iterator.entry = iterator.node.Entries[e+1] + goto between + } + } + // Reached leaf node and there are no entries to the right of the current entry, so go up to the parent + for iterator.node.Parent != nil { + iterator.node = iterator.node.Parent + // Find next entry position in current node (note: search returns the first equal or bigger than entry) + e, _ := iterator.tree.search(iterator.node, iterator.entry.Key) + // Check that there is a next entry position in current node + if e < len(iterator.node.Entries) { + iterator.entry = iterator.node.Entries[e] + goto between + } + } + +end: + iterator.End() + return false + +between: + iterator.position = between + return true +} + +// 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. +func (iterator *Iterator) Prev() bool { + // If already at beginning, go to begin + if iterator.position == begin { + goto begin + } + // If at end, get the right-most entry in the tree + if iterator.position == end { + right := iterator.tree.Right() + if right == nil { + goto begin + } + iterator.node = right + iterator.entry = right.Entries[len(right.Entries)-1] + goto between + } + { + // Find current entry position in current node + e, _ := iterator.tree.search(iterator.node, iterator.entry.Key) + // Try to go down to the child left of the current entry + if e < len(iterator.node.Children) { + iterator.node = iterator.node.Children[e] + // Try to go down to the child right of the current node + for len(iterator.node.Children) > 0 { + iterator.node = iterator.node.Children[len(iterator.node.Children)-1] + } + // Return the right-most entry + iterator.entry = iterator.node.Entries[len(iterator.node.Entries)-1] + goto between + } + // Above assures that we have reached a leaf node, so return the previous entry in current node (if any) + if e-1 >= 0 { + iterator.entry = iterator.node.Entries[e-1] + goto between + } + } + // Reached leaf node and there are no entries to the left of the current entry, so go up to the parent + for iterator.node.Parent != nil { + iterator.node = iterator.node.Parent + // Find previous entry position in current node (note: search returns the first equal or bigger than entry) + e, _ := iterator.tree.search(iterator.node, iterator.entry.Key) + // Check that there is a previous entry position in current node + if e-1 >= 0 { + iterator.entry = iterator.node.Entries[e-1] + goto between + } + } + +begin: + iterator.Begin() + return false + +between: + iterator.position = between + return true +} + +// Value returns the current element's value. +// Does not modify the state of the iterator. +func (iterator *Iterator) Value() interface{} { + return iterator.entry.Value +} + +// Key returns the current element's key. +// Does not modify the state of the iterator. +func (iterator *Iterator) Key() interface{} { + return iterator.entry.Key +} + +// 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.node = nil + iterator.position = begin + iterator.entry = nil +} + +// 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.node = nil + iterator.position = end + iterator.entry = nil +} + +// 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 key and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator +func (iterator *Iterator) First() bool { + iterator.Begin() + return iterator.Next() +} + +// 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 key and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Last() bool { + iterator.End() + return iterator.Prev() +} From eb4171fdb0a2d02a6980d1d52e35f3501aaa2c09 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 12 Jul 2016 03:05:00 +0200 Subject: [PATCH 097/320] - btree Keys() and Values() implemented with tests (using iterator) --- trees/btree/btree.go | 14 ++++++++++++-- trees/btree/btree_test.go | 23 ++++++++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/trees/btree/btree.go b/trees/btree/btree.go index 97387231..ab03ee7d 100644 --- a/trees/btree/btree.go +++ b/trees/btree/btree.go @@ -115,12 +115,22 @@ func (tree *Tree) Size() int { // Keys returns all keys in-order func (tree *Tree) Keys() []interface{} { - return nil // TODO + keys := make([]interface{}, tree.size) + it := tree.Iterator() + for i := 0; it.Next(); i++ { + keys[i] = it.Key() + } + return keys } // Values returns all values in-order based on the key. func (tree *Tree) Values() []interface{} { - return nil // TODO + values := make([]interface{}, tree.size) + it := tree.Iterator() + for i := 0; it.Next(); i++ { + values[i] = it.Value() + } + return values } // Clear removes all nodes from the tree. diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index 71e86d2b..f3bf2045 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -5,7 +5,7 @@ package btree import ( - _ "fmt" + "fmt" "testing" ) @@ -384,6 +384,27 @@ func TestBTreeLeftAndRight(t *testing.T) { } } +func TestBTreeIteratorValuesAndKeys(t *testing.T) { + tree := NewWithIntComparator(4) + tree.Put(4, "d") + tree.Put(5, "e") + tree.Put(6, "f") + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(7, "g") + tree.Put(2, "b") + tree.Put(1, "x") // override + if actualValue, expectedValue := fmt.Sprintf("%d%d%d%d%d%d%d", tree.Keys()...), "1234567"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s", tree.Values()...), "xbcdefg"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := tree.Size(); actualValue != 7 { + t.Errorf("Got %v expected %v", actualValue, 7) + } +} + func TestBTreeIteratorNextOnEmpty(t *testing.T) { tree := NewWithIntComparator(3) it := tree.Iterator() From 288c1a4ca39323178df7ee66463f36c76b4de4df Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Thu, 14 Jul 2016 05:55:24 +0200 Subject: [PATCH 098/320] - btree deletion with tests --- trees/btree/btree.go | 247 ++++++++++++++++++++++++++++++++------ trees/btree/btree_test.go | 176 +++++++++++++++++++++++++++ 2 files changed, 387 insertions(+), 36 deletions(-) diff --git a/trees/btree/btree.go b/trees/btree/btree.go index ab03ee7d..bf26fe19 100644 --- a/trees/btree/btree.go +++ b/trees/btree/btree.go @@ -4,6 +4,13 @@ // Package btree implements a B tree. // +// According to Knuth's definition, a B-tree of order m is a tree which satisfies the following properties: +// - Every node has at most m children. +// - Every non-leaf node (except root) has at least ⌈m/2⌉ children. +// - The root has at least two children if it is not a leaf node. +// - A non-leaf node with k children contains k−1 keys. +// - All leaves appear in the same level +// // Structure is not thread safe. // // References: https://en.wikipedia.org/wiki/B-tree @@ -81,26 +88,22 @@ func (tree *Tree) Put(key interface{}, value interface{}) { // Second return parameter is true if key was found, otherwise false. // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree) Get(key interface{}) (value interface{}, found bool) { - if tree.Empty() { - return nil, false - } - node := tree.Root - for { - index, found := tree.search(node, key) - if found { - return node.Entries[index].Value, true - } - if tree.isLeaf(node) { - return nil, false - } - node = node.Children[index] + node, index, found := tree.searchRecursively(tree.Root, key) + if found { + return node.Entries[index].Value, true } + return nil, false } // Remove remove the node from the tree by key. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *Tree) Remove(key interface{}) { - // TODO +func (tree *Tree) Remove(key interface{}) bool { + node, index, found := tree.searchRecursively(tree.Root, key) + if found { + tree.delete(node, index) + tree.size-- + } + return found } // Empty returns true if tree does not contain any nodes @@ -146,16 +149,7 @@ func (tree *Tree) Height() int { // Left returns the left-most (min) node or nil if tree is empty. func (tree *Tree) Left() *Node { - if tree.Empty() { - return nil - } - node := tree.Root - for { - if tree.isLeaf(node) { - return node - } - node = node.Children[0] - } + return tree.left(tree.Root) } // LeftKey returns the left-most (min) key or nil if tree is empty. @@ -176,16 +170,7 @@ func (tree *Tree) LeftValue() interface{} { // Right returns the right-most (max) node or nil if tree is empty. func (tree *Tree) Right() *Node { - if tree.Empty() { - return nil - } - node := tree.Root - for { - if tree.isLeaf(node) { - return node - } - node = node.Children[len(node.Children)-1] - } + return tree.right(tree.Root) } // RightKey returns the right-most (max) key or nil if tree is empty. @@ -257,8 +242,16 @@ func (tree *Tree) maxChildren() int { return tree.m } +func (tree *Tree) minChildren() int { + return (tree.m + 1) / 2 // ceil(m/2) +} + func (tree *Tree) maxEntries() int { - return tree.m - 1 + return tree.maxChildren() - 1 +} + +func (tree *Tree) minEntries() int { + return tree.minChildren() - 1 } func (tree *Tree) middle() int { @@ -284,6 +277,24 @@ func (tree *Tree) search(node *Node, key interface{}) (index int, found bool) { return low, false } +// searchRecursively searches recursively down the tree starting at the startNode +func (tree *Tree) searchRecursively(startNode *Node, key interface{}) (node *Node, index int, found bool) { + if tree.Empty() { + return nil, -1, false + } + node = startNode + for { + index, found = tree.search(node, key) + if found { + return node, index, true + } + if tree.isLeaf(node) { + return nil, -1, false + } + node = node.Children[index] + } +} + func (tree *Tree) insert(node *Node, entry *Entry) (inserted bool) { if tree.isLeaf(node) { return tree.insertIntoLeaf(node, entry) @@ -345,6 +356,7 @@ func (tree *Tree) splitNonRoot(node *Node) { insertPosition, _ := tree.search(parent, node.Entries[middle].Key) // Insert middle key into parent + // TODO check for memory leaks: node should be nilled and all its entries parent.Entries = append(parent.Entries, nil) copy(parent.Entries[insertPosition+1:], parent.Entries[insertPosition:]) parent.Entries[insertPosition] = node.Entries[middle] @@ -390,3 +402,166 @@ func setParent(nodes []*Node, parent *Node) { node.Parent = parent } } + +func (tree *Tree) left(node *Node) *Node { + if tree.Empty() { + return nil + } + current := node + for { + if tree.isLeaf(current) { + return current + } + current = current.Children[0] + } +} + +func (tree *Tree) right(node *Node) *Node { + if tree.Empty() { + return nil + } + current := node + for { + if tree.isLeaf(current) { + return current + } + current = current.Children[len(current.Children)-1] + } +} + +// leftSibling returns the node's left sibling and child index (in parent) if it exists, otherwise (nil,-1) +// key is any of keys in node (could even be deleted). +func (tree *Tree) leftSibling(node *Node, key interface{}) (*Node, int) { + if node.Parent != nil { + index, _ := tree.search(node.Parent, key) + index-- + if index >= 0 && index < len(node.Parent.Children) { + return node.Parent.Children[index], index + } + } + return nil, -1 +} + +// rightSibling returns the node's right sibling and child index (in parent) if it exists, otherwise (nil,-1) +// key is any of keys in node (could even be deleted). +func (tree *Tree) rightSibling(node *Node, key interface{}) (*Node, int) { + if node.Parent != nil { + index, _ := tree.search(node.Parent, key) + index++ + if index < len(node.Parent.Children) { + return node.Parent.Children[index], index + } + } + return nil, -1 +} + +// delete deletes an entry in node at entries' index +// ref.: https://en.wikipedia.org/wiki/B-tree#Deletion +func (tree *Tree) delete(node *Node, index int) { + // deleting from a leaf node + if tree.isLeaf(node) { + deletedKey := node.Entries[index].Key + tree.deleteEntry(node, index) + tree.rebalance(node, deletedKey) + return + } + + // deleting from an internal node + leftLargestNode := tree.right(node.Children[index]) // largest node in the left sub-tree (exists) + leftLargestEntryIndex := len(leftLargestNode.Entries) - 1 + node.Entries[index] = leftLargestNode.Entries[leftLargestEntryIndex] + deletedKey := leftLargestNode.Entries[leftLargestEntryIndex].Key + tree.deleteEntry(leftLargestNode, leftLargestEntryIndex) + tree.rebalance(leftLargestNode, deletedKey) +} + +// rebalance rebalances the tree after deletion if necessary and returns true, otherwise false. +// Note that we first delete the entry and then call rebalance, thus the passed deleted key as reference. +func (tree *Tree) rebalance(node *Node, deletedKey interface{}) { + // check if rebalancing is needed + if len(node.Entries) >= tree.minEntries() { + return + } + + // try to borrow from left sibling + leftSibling, leftSiblingIndex := tree.leftSibling(node, deletedKey) + if leftSibling != nil && len(leftSibling.Entries) > tree.minEntries() { + // rotate right + node.Entries = append([]*Entry{node.Parent.Entries[leftSiblingIndex]}, node.Entries...) // prepend parent's separator entry to node's entries + node.Parent.Entries[leftSiblingIndex] = leftSibling.Entries[len(leftSibling.Entries)-1] + tree.deleteEntry(leftSibling, len(leftSibling.Entries)-1) + return + } + + // try to borrow from right sibling + rightSibling, rightSiblingIndex := tree.rightSibling(node, deletedKey) + if rightSibling != nil && len(rightSibling.Entries) > tree.minEntries() { + // rotate left + node.Entries = append(node.Entries, node.Parent.Entries[rightSiblingIndex-1]) // append parent's separator entry to node's entries + node.Parent.Entries[rightSiblingIndex-1] = rightSibling.Entries[0] + tree.deleteEntry(rightSibling, 0) + return + } + + // merge with siblings + if rightSibling != nil { + // merge with right sibling + node.Entries = append(node.Entries, node.Parent.Entries[rightSiblingIndex-1]) + node.Entries = append(node.Entries, rightSibling.Entries...) + deletedKey = node.Parent.Entries[rightSiblingIndex-1].Key + tree.deleteEntry(node.Parent, rightSiblingIndex-1) + tree.appendChildren(node.Parent.Children[rightSiblingIndex], node) + tree.deleteChild(node.Parent, rightSiblingIndex) + } else if leftSibling != nil { + // merge with left sibling + entries := append([]*Entry(nil), leftSibling.Entries...) + entries = append(entries, node.Parent.Entries[leftSiblingIndex]) + node.Entries = append(entries, node.Entries...) + deletedKey = node.Parent.Entries[leftSiblingIndex].Key + tree.deleteEntry(node.Parent, leftSiblingIndex) + tree.prependChildren(node.Parent.Children[leftSiblingIndex], node) + tree.deleteChild(node.Parent, leftSiblingIndex) + } else { + // node is empty root + tree.Root = node + node.Parent = nil + return + } + + // make the merged node the root if its parent was the root and the root is empty + if node.Parent == tree.Root && len(tree.Root.Entries) == 0 { + tree.Root = node + node.Parent = nil + return + } + + // parent might underflow, so try to rebalance if necessary + tree.rebalance(node.Parent, deletedKey) +} + +func (tree *Tree) prependChildren(fromNode *Node, toNode *Node) { + children := append([]*Node(nil), fromNode.Children...) + toNode.Children = append(children, toNode.Children...) +} + +func (tree *Tree) appendChildren(fromNode *Node, toNode *Node) { + toNode.Children = append(toNode.Children, fromNode.Children...) +} + +func (tree *Tree) deleteEntry(node *Node, index int) { + node.Entries[index] = nil + copy(node.Entries[index:], node.Entries[index+1:]) + node.Entries[len(node.Entries)-1] = nil + node.Entries = node.Entries[:len(node.Entries)-1] +} + +func (tree *Tree) deleteChild(node *Node, index int) { + if index >= len(node.Children) { + return + } + node.Children[index].Entries = nil // GC + node.Children[index] = nil // GC + copy(node.Children[index:], node.Children[index+1:]) + node.Children[len(node.Children)-1] = nil + node.Children = node.Children[:len(node.Children)-1] +} diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index f3bf2045..af3007ca 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -308,6 +308,182 @@ func TestBTreePut4(t *testing.T) { assertValidTreeNode(t, tree.Root.Children[2].Children[1], 1, 0, []int{6}, true) } +func TestBTreeRemove1(t *testing.T) { + // empty + tree := NewWithIntComparator(3) + tree.Remove(1) + assertValidTree(t, tree, 0) +} + +func TestBTreeRemove2(t *testing.T) { + // leaf node (no underflow) + tree := NewWithIntComparator(3) + tree.Put(1, nil) + tree.Put(2, nil) + + tree.Remove(1) + assertValidTree(t, tree, 1) + assertValidTreeNode(t, tree.Root, 1, 0, []int{2}, false) + + tree.Remove(2) + assertValidTree(t, tree, 0) + assertValidTreeNode(t, tree.Root, 0, 0, []int{}, false) +} + +func TestBTreeRemove3(t *testing.T) { + // merge with right (underflow) + { + tree := NewWithIntComparator(3) + tree.Put(1, nil) + tree.Put(2, nil) + tree.Put(3, nil) + + tree.Remove(1) + assertValidTree(t, tree, 2) + assertValidTreeNode(t, tree.Root, 2, 0, []int{2, 3}, false) + } + // merge with left (underflow) + { + tree := NewWithIntComparator(3) + tree.Put(1, nil) + tree.Put(2, nil) + tree.Put(3, nil) + + tree.Remove(3) + assertValidTree(t, tree, 2) + assertValidTreeNode(t, tree.Root, 2, 0, []int{1, 2}, false) + } +} + +func TestBTreeRemove4(t *testing.T) { + // rotate left (underflow) + tree := NewWithIntComparator(3) + tree.Put(1, nil) + tree.Put(2, nil) + tree.Put(3, nil) + tree.Put(4, nil) + + assertValidTree(t, tree, 4) + assertValidTreeNode(t, tree.Root, 1, 2, []int{2}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}, true) + assertValidTreeNode(t, tree.Root.Children[1], 2, 0, []int{3, 4}, true) + + tree.Remove(1) + assertValidTree(t, tree, 3) + assertValidTreeNode(t, tree.Root, 1, 2, []int{3}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{2}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{4}, true) +} + +func TestBTreeRemove5(t *testing.T) { + // rotate right (underflow) + tree := NewWithIntComparator(3) + tree.Put(1, nil) + tree.Put(2, nil) + tree.Put(3, nil) + tree.Put(0, nil) + + assertValidTree(t, tree, 4) + assertValidTreeNode(t, tree.Root, 1, 2, []int{2}, false) + assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{0, 1}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{3}, true) + + tree.Remove(3) + assertValidTree(t, tree, 3) + assertValidTreeNode(t, tree.Root, 1, 2, []int{1}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{0}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{2}, true) +} + +func TestBTreeRemove6(t *testing.T) { + // root height reduction after a series of underflows on right side + // use simulator: https://www.cs.usfca.edu/~galles/visualization/BTree.html + tree := NewWithIntComparator(3) + tree.Put(1, nil) + tree.Put(2, nil) + tree.Put(3, nil) + tree.Put(4, nil) + tree.Put(5, nil) + tree.Put(6, nil) + tree.Put(7, nil) + + assertValidTree(t, tree, 7) + assertValidTreeNode(t, tree.Root, 1, 2, []int{4}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{2}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{6}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[0], 1, 0, []int{1}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{3}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{5}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{7}, true) + + tree.Remove(7) + assertValidTree(t, tree, 6) + assertValidTreeNode(t, tree.Root, 2, 3, []int{2, 4}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{3}, true) + assertValidTreeNode(t, tree.Root.Children[2], 2, 0, []int{5, 6}, true) +} + +func TestBTreeRemove7(t *testing.T) { + // root height reduction after a series of underflows on left side + // use simulator: https://www.cs.usfca.edu/~galles/visualization/BTree.html + tree := NewWithIntComparator(3) + tree.Put(1, nil) + tree.Put(2, nil) + tree.Put(3, nil) + tree.Put(4, nil) + tree.Put(5, nil) + tree.Put(6, nil) + tree.Put(7, nil) + + assertValidTree(t, tree, 7) + assertValidTreeNode(t, tree.Root, 1, 2, []int{4}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{2}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{6}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[0], 1, 0, []int{1}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{3}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{5}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{7}, true) + + tree.Remove(1) // series of underflows + assertValidTree(t, tree, 6) + assertValidTreeNode(t, tree.Root, 2, 3, []int{4, 6}, false) + assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{2, 3}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{5}, true) + assertValidTreeNode(t, tree.Root.Children[2], 1, 0, []int{7}, true) + + // clear all remaining + tree.Remove(2) + assertValidTree(t, tree, 5) + assertValidTreeNode(t, tree.Root, 2, 3, []int{4, 6}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{3}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{5}, true) + assertValidTreeNode(t, tree.Root.Children[2], 1, 0, []int{7}, true) + + tree.Remove(3) + assertValidTree(t, tree, 4) + assertValidTreeNode(t, tree.Root, 1, 2, []int{6}, false) + assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{4, 5}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{7}, true) + + tree.Remove(4) + assertValidTree(t, tree, 3) + assertValidTreeNode(t, tree.Root, 1, 2, []int{6}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{5}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{7}, true) + + tree.Remove(5) + assertValidTree(t, tree, 2) + assertValidTreeNode(t, tree.Root, 2, 0, []int{6, 7}, false) + + tree.Remove(6) + assertValidTree(t, tree, 1) + assertValidTreeNode(t, tree.Root, 1, 0, []int{7}, false) + + tree.Remove(7) + assertValidTree(t, tree, 0) +} + func TestBTreeHeight(t *testing.T) { tree := NewWithIntComparator(3) if actualValue, expectedValue := tree.Height(), 0; actualValue != expectedValue { From b38c99bf338842e4f420a403a9b224e253ec451c Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Thu, 14 Jul 2016 08:28:11 +0200 Subject: [PATCH 099/320] - btree deletion fixes with more tests (done) --- trees/btree/btree.go | 32 ++++++++------ trees/btree/btree_test.go | 91 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 110 insertions(+), 13 deletions(-) diff --git a/trees/btree/btree.go b/trees/btree/btree.go index bf26fe19..d796a12a 100644 --- a/trees/btree/btree.go +++ b/trees/btree/btree.go @@ -97,13 +97,12 @@ func (tree *Tree) Get(key interface{}) (value interface{}, found bool) { // Remove remove the node from the tree by key. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *Tree) Remove(key interface{}) bool { +func (tree *Tree) Remove(key interface{}) { node, index, found := tree.searchRecursively(tree.Root, key) if found { tree.delete(node, index) tree.size-- } - return found } // Empty returns true if tree does not contain any nodes @@ -463,11 +462,14 @@ func (tree *Tree) delete(node *Node, index int) { deletedKey := node.Entries[index].Key tree.deleteEntry(node, index) tree.rebalance(node, deletedKey) + if len(tree.Root.Entries) == 0 { + tree.Root = nil + } return } // deleting from an internal node - leftLargestNode := tree.right(node.Children[index]) // largest node in the left sub-tree (exists) + leftLargestNode := tree.right(node.Children[index]) // largest node in the left sub-tree (assumed to exist) leftLargestEntryIndex := len(leftLargestNode.Entries) - 1 node.Entries[index] = leftLargestNode.Entries[leftLargestEntryIndex] deletedKey := leftLargestNode.Entries[leftLargestEntryIndex].Key @@ -479,7 +481,7 @@ func (tree *Tree) delete(node *Node, index int) { // Note that we first delete the entry and then call rebalance, thus the passed deleted key as reference. func (tree *Tree) rebalance(node *Node, deletedKey interface{}) { // check if rebalancing is needed - if len(node.Entries) >= tree.minEntries() { + if node == nil || len(node.Entries) >= tree.minEntries() { return } @@ -490,6 +492,12 @@ func (tree *Tree) rebalance(node *Node, deletedKey interface{}) { node.Entries = append([]*Entry{node.Parent.Entries[leftSiblingIndex]}, node.Entries...) // prepend parent's separator entry to node's entries node.Parent.Entries[leftSiblingIndex] = leftSibling.Entries[len(leftSibling.Entries)-1] tree.deleteEntry(leftSibling, len(leftSibling.Entries)-1) + if !tree.isLeaf(leftSibling) { + leftSiblingRightMostChild := leftSibling.Children[len(leftSibling.Children)-1] + leftSiblingRightMostChild.Parent = node + node.Children = append([]*Node{leftSiblingRightMostChild}, node.Children...) + tree.deleteChild(leftSibling, len(leftSibling.Children)-1) + } return } @@ -500,6 +508,12 @@ func (tree *Tree) rebalance(node *Node, deletedKey interface{}) { node.Entries = append(node.Entries, node.Parent.Entries[rightSiblingIndex-1]) // append parent's separator entry to node's entries node.Parent.Entries[rightSiblingIndex-1] = rightSibling.Entries[0] tree.deleteEntry(rightSibling, 0) + if !tree.isLeaf(rightSibling) { + rightSiblingLeftMostChild := rightSibling.Children[0] + rightSiblingLeftMostChild.Parent = node + node.Children = append(node.Children, rightSiblingLeftMostChild) + tree.deleteChild(rightSibling, 0) + } return } @@ -521,11 +535,6 @@ func (tree *Tree) rebalance(node *Node, deletedKey interface{}) { tree.deleteEntry(node.Parent, leftSiblingIndex) tree.prependChildren(node.Parent.Children[leftSiblingIndex], node) tree.deleteChild(node.Parent, leftSiblingIndex) - } else { - // node is empty root - tree.Root = node - node.Parent = nil - return } // make the merged node the root if its parent was the root and the root is empty @@ -542,14 +551,15 @@ func (tree *Tree) rebalance(node *Node, deletedKey interface{}) { func (tree *Tree) prependChildren(fromNode *Node, toNode *Node) { children := append([]*Node(nil), fromNode.Children...) toNode.Children = append(children, toNode.Children...) + setParent(fromNode.Children, toNode) } func (tree *Tree) appendChildren(fromNode *Node, toNode *Node) { toNode.Children = append(toNode.Children, fromNode.Children...) + setParent(fromNode.Children, toNode) } func (tree *Tree) deleteEntry(node *Node, index int) { - node.Entries[index] = nil copy(node.Entries[index:], node.Entries[index+1:]) node.Entries[len(node.Entries)-1] = nil node.Entries = node.Entries[:len(node.Entries)-1] @@ -559,8 +569,6 @@ func (tree *Tree) deleteChild(node *Node, index int) { if index >= len(node.Children) { return } - node.Children[index].Entries = nil // GC - node.Children[index] = nil // GC copy(node.Children[index:], node.Children[index+1:]) node.Children[len(node.Children)-1] = nil node.Children = node.Children[:len(node.Children)-1] diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index af3007ca..14571eea 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -327,7 +327,6 @@ func TestBTreeRemove2(t *testing.T) { tree.Remove(2) assertValidTree(t, tree, 0) - assertValidTreeNode(t, tree.Root, 0, 0, []int{}, false) } func TestBTreeRemove3(t *testing.T) { @@ -484,6 +483,85 @@ func TestBTreeRemove7(t *testing.T) { assertValidTree(t, tree, 0) } +func TestBTreeRemove8(t *testing.T) { + // use simulator: https://www.cs.usfca.edu/~galles/visualization/BTree.html + tree := NewWithIntComparator(3) + tree.Put(1, nil) + tree.Put(2, nil) + tree.Put(3, nil) + tree.Put(4, nil) + tree.Put(5, nil) + tree.Put(6, nil) + tree.Put(7, nil) + tree.Put(8, nil) + tree.Put(9, nil) + + assertValidTree(t, tree, 9) + assertValidTreeNode(t, tree.Root, 1, 2, []int{4}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{2}, true) + assertValidTreeNode(t, tree.Root.Children[1], 2, 3, []int{6, 8}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[0], 1, 0, []int{1}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{3}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{5}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{7}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[2], 1, 0, []int{9}, true) + + tree.Remove(1) + assertValidTree(t, tree, 8) + assertValidTreeNode(t, tree.Root, 1, 2, []int{6}, false) + assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{4}, true) + assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{8}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[0], 2, 0, []int{2, 3}, true) + assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{5}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{7}, true) + assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{9}, true) +} + +func TestBTreeRemove9(t *testing.T) { + const max = 1000 + orders := []int{3, 4, 5, 6, 7, 8, 9, 10, 20, 100, 500, 1000, 5000, 10000} + for _, order := range orders { + + tree := NewWithIntComparator(order) + + { + for i := 1; i <= max; i++ { + tree.Put(i, i) + } + assertValidTree(t, tree, max) + + for i := 1; i <= max; i++ { + if _, found := tree.Get(i); !found { + t.Errorf("Not found %v", i) + } + } + + for i := 1; i <= max; i++ { + tree.Remove(i) + } + assertValidTree(t, tree, 0) + } + + { + for i := max; i > 0; i-- { + tree.Put(i, i) + } + assertValidTree(t, tree, max) + + for i := max; i > 0; i-- { + if _, found := tree.Get(i); !found { + t.Errorf("Not found %v", i) + } + } + + for i := max; i > 0; i-- { + tree.Remove(i) + } + assertValidTree(t, tree, 0) + } + } +} + func TestBTreeHeight(t *testing.T) { tree := NewWithIntComparator(3) if actualValue, expectedValue := tree.Height(), 0; actualValue != expectedValue { @@ -524,6 +602,17 @@ func TestBTreeHeight(t *testing.T) { if actualValue, expectedValue := tree.Height(), 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } + + tree.Remove(1) + tree.Remove(2) + tree.Remove(3) + tree.Remove(4) + tree.Remove(5) + tree.Remove(6) + tree.Remove(7) + if actualValue, expectedValue := tree.Height(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } } func TestBTreeLeftAndRight(t *testing.T) { From efcbbe62748bdffae6f7e29fddd0324d108022db Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 16 Jul 2016 04:40:16 +0200 Subject: [PATCH 100/320] - detailed extensive tests with breakdown on number of elements --- README.md | 2 +- lists/arraylist/arraylist_test.go | 153 +++++++++++++++++- .../doublylinkedlist/doublylinkedlist_test.go | 153 +++++++++++++++++- .../singlylinkedlist/singlylinkedlist_test.go | 153 +++++++++++++++++- maps/hashbidimap/hashbidimap_test.go | 149 ++++++++++++++++- maps/hashmap/hashmap_test.go | 151 ++++++++++++++++- maps/treebidimap/treebidimap_test.go | 149 ++++++++++++++++- maps/treemap/treemap_test.go | 151 ++++++++++++++++- sets/hashset/hashset_test.go | 151 ++++++++++++++++- sets/treeset/treeset_test.go | 151 ++++++++++++++++- stacks/arraystack/arraystack_test.go | 99 +++++++++++- .../linkedliststack/linkedliststack_test.go | 99 +++++++++++- trees/binaryheap/binaryheap_test.go | 98 ++++++++++- trees/btree/btree.go | 1 - trees/btree/btree_test.go | 151 ++++++++++++++++- trees/redblacktree/redblacktree_test.go | 151 ++++++++++++++++- 16 files changed, 1889 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index 5095c624..e1006895 100644 --- a/README.md +++ b/README.md @@ -1142,7 +1142,7 @@ Thread safety is not a concern of this project, this should be handled at a high ### Testing and Benchmarking -`go test -v -bench . -benchmem -benchtime 1s ./...` +`go test -run=NO_TEST -bench . -benchmem -benchtime 5s ./...` ### Contributing diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 8f70385e..67317e06 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -426,14 +426,155 @@ func TestListIteratorLast(t *testing.T) { } } -func BenchmarkList(b *testing.B) { +func benchmarkGet(b *testing.B, list *List, size int) { for i := 0; i < b.N; i++ { - list := New() - for n := 0; n < 1000; n++ { - list.Add(i) + for n := 0; n < size; n++ { + list.Get(n) } - for !list.Empty() { - list.Remove(0) + } +} + +func benchmarkAdd(b *testing.B, list *List, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + list.Add(n) + } + } +} + +func benchmarkRemove(b *testing.B, list *List, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + list.Remove(n) } } } + +func BenchmarkArrayListGet100(b *testing.B) { + b.StopTimer() + size := 100 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkGet(b, list, size) +} + +func BenchmarkArrayListGet1000(b *testing.B) { + b.StopTimer() + size := 1000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkGet(b, list, size) +} + +func BenchmarkArrayListGet10000(b *testing.B) { + b.StopTimer() + size := 10000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkGet(b, list, size) +} + +func BenchmarkArrayListGet100000(b *testing.B) { + b.StopTimer() + size := 100000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkGet(b, list, size) +} + +func BenchmarkArrayListAdd100(b *testing.B) { + b.StopTimer() + size := 100 + list := New() + b.StartTimer() + benchmarkAdd(b, list, size) +} + +func BenchmarkArrayListAdd1000(b *testing.B) { + b.StopTimer() + size := 1000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkAdd(b, list, size) +} + +func BenchmarkArrayListAdd10000(b *testing.B) { + b.StopTimer() + size := 10000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkAdd(b, list, size) +} + +func BenchmarkArrayListAdd100000(b *testing.B) { + b.StopTimer() + size := 100000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkAdd(b, list, size) +} + +func BenchmarkArrayListRemove100(b *testing.B) { + b.StopTimer() + size := 100 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkRemove(b, list, size) +} + +func BenchmarkArrayListRemove1000(b *testing.B) { + b.StopTimer() + size := 1000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkRemove(b, list, size) +} + +func BenchmarkArrayListRemove10000(b *testing.B) { + b.StopTimer() + size := 10000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkRemove(b, list, size) +} + +func BenchmarkArrayListRemove100000(b *testing.B) { + b.StopTimer() + size := 100000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkRemove(b, list, size) +} diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 159761dc..fa663445 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -426,14 +426,155 @@ func TestListIteratorLast(t *testing.T) { } } -func BenchmarkList(b *testing.B) { +func benchmarkGet(b *testing.B, list *List, size int) { for i := 0; i < b.N; i++ { - list := New() - for n := 0; n < 1000; n++ { - list.Add(i) + for n := 0; n < size; n++ { + list.Get(n) } - for !list.Empty() { - list.Remove(0) + } +} + +func benchmarkAdd(b *testing.B, list *List, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + list.Add(n) + } + } +} + +func benchmarkRemove(b *testing.B, list *List, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + list.Remove(n) } } } + +func BenchmarkDoublyLinkedListGet100(b *testing.B) { + b.StopTimer() + size := 100 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkGet(b, list, size) +} + +func BenchmarkDoublyLinkedListGet1000(b *testing.B) { + b.StopTimer() + size := 1000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkGet(b, list, size) +} + +func BenchmarkDoublyLinkedListGet10000(b *testing.B) { + b.StopTimer() + size := 10000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkGet(b, list, size) +} + +func BenchmarkDoublyLinkedListGet100000(b *testing.B) { + b.StopTimer() + size := 100000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkGet(b, list, size) +} + +func BenchmarkDoublyLinkedListAdd100(b *testing.B) { + b.StopTimer() + size := 100 + list := New() + b.StartTimer() + benchmarkAdd(b, list, size) +} + +func BenchmarkDoublyLinkedListAdd1000(b *testing.B) { + b.StopTimer() + size := 1000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkAdd(b, list, size) +} + +func BenchmarkDoublyLinkedListAdd10000(b *testing.B) { + b.StopTimer() + size := 10000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkAdd(b, list, size) +} + +func BenchmarkDoublyLinkedListAdd100000(b *testing.B) { + b.StopTimer() + size := 100000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkAdd(b, list, size) +} + +func BenchmarkDoublyLinkedListRemove100(b *testing.B) { + b.StopTimer() + size := 100 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkRemove(b, list, size) +} + +func BenchmarkDoublyLinkedListRemove1000(b *testing.B) { + b.StopTimer() + size := 1000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkRemove(b, list, size) +} + +func BenchmarkDoublyLinkedListRemove10000(b *testing.B) { + b.StopTimer() + size := 10000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkRemove(b, list, size) +} + +func BenchmarkDoublyLinkedListRemove100000(b *testing.B) { + b.StopTimer() + size := 100000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkRemove(b, list, size) +} diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index c81ba85d..0a45929f 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -345,14 +345,155 @@ func TestListIteratorFirst(t *testing.T) { } } -func BenchmarkList(b *testing.B) { +func benchmarkGet(b *testing.B, list *List, size int) { for i := 0; i < b.N; i++ { - list := New() - for n := 0; n < 1000; n++ { - list.Add(i) + for n := 0; n < size; n++ { + list.Get(n) } - for !list.Empty() { - list.Remove(0) + } +} + +func benchmarkAdd(b *testing.B, list *List, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + list.Add(n) + } + } +} + +func benchmarkRemove(b *testing.B, list *List, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + list.Remove(n) } } } + +func BenchmarkSinglyLinkedListGet100(b *testing.B) { + b.StopTimer() + size := 100 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkGet(b, list, size) +} + +func BenchmarkSinglyLinkedListGet1000(b *testing.B) { + b.StopTimer() + size := 1000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkGet(b, list, size) +} + +func BenchmarkSinglyLinkedListGet10000(b *testing.B) { + b.StopTimer() + size := 10000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkGet(b, list, size) +} + +func BenchmarkSinglyLinkedListGet100000(b *testing.B) { + b.StopTimer() + size := 100000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkGet(b, list, size) +} + +func BenchmarkSinglyLinkedListAdd100(b *testing.B) { + b.StopTimer() + size := 100 + list := New() + b.StartTimer() + benchmarkAdd(b, list, size) +} + +func BenchmarkSinglyLinkedListAdd1000(b *testing.B) { + b.StopTimer() + size := 1000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkAdd(b, list, size) +} + +func BenchmarkSinglyLinkedListAdd10000(b *testing.B) { + b.StopTimer() + size := 10000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkAdd(b, list, size) +} + +func BenchmarkSinglyLinkedListAdd100000(b *testing.B) { + b.StopTimer() + size := 100000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkAdd(b, list, size) +} + +func BenchmarkSinglyLinkedListRemove100(b *testing.B) { + b.StopTimer() + size := 100 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkRemove(b, list, size) +} + +func BenchmarkSinglyLinkedListRemove1000(b *testing.B) { + b.StopTimer() + size := 1000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkRemove(b, list, size) +} + +func BenchmarkSinglyLinkedListRemove10000(b *testing.B) { + b.StopTimer() + size := 10000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkRemove(b, list, size) +} + +func BenchmarkSinglyLinkedListRemove100000(b *testing.B) { + b.StopTimer() + size := 100000 + list := New() + for n := 0; n < size; n++ { + list.Add(n) + } + b.StartTimer() + benchmarkRemove(b, list, size) +} diff --git a/maps/hashbidimap/hashbidimap_test.go b/maps/hashbidimap/hashbidimap_test.go index ca46a069..5527a033 100644 --- a/maps/hashbidimap/hashbidimap_test.go +++ b/maps/hashbidimap/hashbidimap_test.go @@ -169,14 +169,155 @@ func sameElements(a []interface{}, b []interface{}) bool { return true } -func BenchmarkMap(b *testing.B) { +func benchmarkGet(b *testing.B, m *Map, size int) { for i := 0; i < b.N; i++ { - m := New() - for n := 0; n < 1000; n++ { + for n := 0; n < size; n++ { + m.Get(n) + } + } +} + +func benchmarkPut(b *testing.B, m *Map, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { m.Put(n, n) } - for n := 0; n < 1000; n++ { + } +} + +func benchmarkRemove(b *testing.B, m *Map, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { m.Remove(n) } } } + +func BenchmarkHashBidiMapGet100(b *testing.B) { + b.StopTimer() + size := 100 + m := New() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkHashBidiMapGet1000(b *testing.B) { + b.StopTimer() + size := 1000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkHashBidiMapGet10000(b *testing.B) { + b.StopTimer() + size := 10000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkHashBidiMapGet100000(b *testing.B) { + b.StopTimer() + size := 100000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkHashBidiMapPut100(b *testing.B) { + b.StopTimer() + size := 100 + m := New() + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkHashBidiMapPut1000(b *testing.B) { + b.StopTimer() + size := 1000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkHashBidiMapPut10000(b *testing.B) { + b.StopTimer() + size := 10000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkHashBidiMapPut100000(b *testing.B) { + b.StopTimer() + size := 100000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkHashBidiMapRemove100(b *testing.B) { + b.StopTimer() + size := 100 + m := New() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} + +func BenchmarkHashBidiMapRemove1000(b *testing.B) { + b.StopTimer() + size := 1000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} + +func BenchmarkHashBidiMapRemove10000(b *testing.B) { + b.StopTimer() + size := 10000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} + +func BenchmarkHashBidiMapRemove100000(b *testing.B) { + b.StopTimer() + size := 100000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} diff --git a/maps/hashmap/hashmap_test.go b/maps/hashmap/hashmap_test.go index c4adf47f..119e9edc 100644 --- a/maps/hashmap/hashmap_test.go +++ b/maps/hashmap/hashmap_test.go @@ -137,14 +137,155 @@ func sameElements(a []interface{}, b []interface{}) bool { return true } -func BenchmarkMap(b *testing.B) { +func benchmarkGet(b *testing.B, m *Map, size int) { for i := 0; i < b.N; i++ { - m := New() - for n := 0; n < 1000; n++ { - m.Put(n, n) + for n := 0; n < size; n++ { + m.Get(n) } - for n := 0; n < 1000; n++ { + } +} + +func benchmarkPut(b *testing.B, m *Map, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + } +} + +func benchmarkRemove(b *testing.B, m *Map, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { m.Remove(n) } } } + +func BenchmarkHashMapGet100(b *testing.B) { + b.StopTimer() + size := 100 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkHashMapGet1000(b *testing.B) { + b.StopTimer() + size := 1000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkHashMapGet10000(b *testing.B) { + b.StopTimer() + size := 10000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkHashMapGet100000(b *testing.B) { + b.StopTimer() + size := 100000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkHashMapPut100(b *testing.B) { + b.StopTimer() + size := 100 + m := New() + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkHashMapPut1000(b *testing.B) { + b.StopTimer() + size := 1000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkHashMapPut10000(b *testing.B) { + b.StopTimer() + size := 10000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkHashMapPut100000(b *testing.B) { + b.StopTimer() + size := 100000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkHashMapRemove100(b *testing.B) { + b.StopTimer() + size := 100 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} + +func BenchmarkHashMapRemove1000(b *testing.B) { + b.StopTimer() + size := 1000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} + +func BenchmarkHashMapRemove10000(b *testing.B) { + b.StopTimer() + size := 10000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} + +func BenchmarkHashMapRemove100000(b *testing.B) { + b.StopTimer() + size := 100000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} diff --git a/maps/treebidimap/treebidimap_test.go b/maps/treebidimap/treebidimap_test.go index 5c41961e..c504e97f 100644 --- a/maps/treebidimap/treebidimap_test.go +++ b/maps/treebidimap/treebidimap_test.go @@ -473,14 +473,155 @@ func TestMapIteratorLast(t *testing.T) { } } -func BenchmarkMap(b *testing.B) { +func benchmarkGet(b *testing.B, m *Map, size int) { for i := 0; i < b.N; i++ { - m := NewWithIntComparators() - for n := 0; n < 1000; n++ { + for n := 0; n < size; n++ { + m.Get(n) + } + } +} + +func benchmarkPut(b *testing.B, m *Map, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { m.Put(n, n) } - for n := 0; n < 1000; n++ { + } +} + +func benchmarkRemove(b *testing.B, m *Map, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { m.Remove(n) } } } + +func BenchmarkTreeBidiMapGet100(b *testing.B) { + b.StopTimer() + size := 100 + m := NewWithIntComparators() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkTreeBidiMapGet1000(b *testing.B) { + b.StopTimer() + size := 1000 + m := NewWithIntComparators() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkTreeBidiMapGet10000(b *testing.B) { + b.StopTimer() + size := 10000 + m := NewWithIntComparators() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkTreeBidiMapGet100000(b *testing.B) { + b.StopTimer() + size := 100000 + m := NewWithIntComparators() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkTreeBidiMapPut100(b *testing.B) { + b.StopTimer() + size := 100 + m := NewWithIntComparators() + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkTreeBidiMapPut1000(b *testing.B) { + b.StopTimer() + size := 1000 + m := NewWithIntComparators() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkTreeBidiMapPut10000(b *testing.B) { + b.StopTimer() + size := 10000 + m := NewWithIntComparators() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkTreeBidiMapPut100000(b *testing.B) { + b.StopTimer() + size := 100000 + m := NewWithIntComparators() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkTreeBidiMapRemove100(b *testing.B) { + b.StopTimer() + size := 100 + m := NewWithIntComparators() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} + +func BenchmarkTreeBidiMapRemove1000(b *testing.B) { + b.StopTimer() + size := 1000 + m := NewWithIntComparators() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} + +func BenchmarkTreeBidiMapRemove10000(b *testing.B) { + b.StopTimer() + size := 10000 + m := NewWithIntComparators() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} + +func BenchmarkTreeBidiMapRemove100000(b *testing.B) { + b.StopTimer() + size := 100000 + m := NewWithIntComparators() + for n := 0; n < size; n++ { + m.Put(n, n) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 920b051a..0039601a 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -440,14 +440,155 @@ func TestMapIteratorLast(t *testing.T) { } } -func BenchmarkMap(b *testing.B) { +func benchmarkGet(b *testing.B, m *Map, size int) { for i := 0; i < b.N; i++ { - m := NewWithIntComparator() - for n := 0; n < 1000; n++ { - m.Put(n, n) + for n := 0; n < size; n++ { + m.Get(n) } - for n := 0; n < 1000; n++ { + } +} + +func benchmarkPut(b *testing.B, m *Map, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + } +} + +func benchmarkRemove(b *testing.B, m *Map, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { m.Remove(n) } } } + +func BenchmarkTreeMapGet100(b *testing.B) { + b.StopTimer() + size := 100 + m := NewWithIntComparator() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkTreeMapGet1000(b *testing.B) { + b.StopTimer() + size := 1000 + m := NewWithIntComparator() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkTreeMapGet10000(b *testing.B) { + b.StopTimer() + size := 10000 + m := NewWithIntComparator() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkTreeMapGet100000(b *testing.B) { + b.StopTimer() + size := 100000 + m := NewWithIntComparator() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkTreeMapPut100(b *testing.B) { + b.StopTimer() + size := 100 + m := NewWithIntComparator() + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkTreeMapPut1000(b *testing.B) { + b.StopTimer() + size := 1000 + m := NewWithIntComparator() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkTreeMapPut10000(b *testing.B) { + b.StopTimer() + size := 10000 + m := NewWithIntComparator() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkTreeMapPut100000(b *testing.B) { + b.StopTimer() + size := 100000 + m := NewWithIntComparator() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkTreeMapRemove100(b *testing.B) { + b.StopTimer() + size := 100 + m := NewWithIntComparator() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} + +func BenchmarkTreeMapRemove1000(b *testing.B) { + b.StopTimer() + size := 1000 + m := NewWithIntComparator() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} + +func BenchmarkTreeMapRemove10000(b *testing.B) { + b.StopTimer() + size := 10000 + m := NewWithIntComparator() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} + +func BenchmarkTreeMapRemove100000(b *testing.B) { + b.StopTimer() + size := 100000 + m := NewWithIntComparator() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} diff --git a/sets/hashset/hashset_test.go b/sets/hashset/hashset_test.go index b84924b6..b868631d 100644 --- a/sets/hashset/hashset_test.go +++ b/sets/hashset/hashset_test.go @@ -62,14 +62,155 @@ func TestSetRemove(t *testing.T) { } } -func BenchmarkSet(b *testing.B) { +func benchmarkContains(b *testing.B, set *Set, size int) { for i := 0; i < b.N; i++ { - set := New() - for n := 0; n < 1000; n++ { - set.Add(i) + for n := 0; n < size; n++ { + set.Contains(n) } - for n := 0; n < 1000; 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) +} diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index 7a5c7e8d..881adc21 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -327,14 +327,155 @@ func TestSetIteratorLast(t *testing.T) { } } -func BenchmarkSet(b *testing.B) { +func benchmarkContains(b *testing.B, set *Set, size int) { for i := 0; i < b.N; i++ { - set := NewWithIntComparator() - for n := 0; n < 1000; n++ { - set.Add(i) + for n := 0; n < size; n++ { + set.Contains(n) } - for n := 0; n < 1000; 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 BenchmarkTreeSetContains100(b *testing.B) { + b.StopTimer() + size := 100 + set := NewWithIntComparator() + for n := 0; n < size; n++ { + set.Add(n) + } + b.StartTimer() + benchmarkContains(b, set, size) +} + +func BenchmarkTreeSetContains1000(b *testing.B) { + b.StopTimer() + size := 1000 + set := NewWithIntComparator() + for n := 0; n < size; n++ { + set.Add(n) + } + b.StartTimer() + benchmarkContains(b, set, size) +} + +func BenchmarkTreeSetContains10000(b *testing.B) { + b.StopTimer() + size := 10000 + set := NewWithIntComparator() + for n := 0; n < size; n++ { + set.Add(n) + } + b.StartTimer() + benchmarkContains(b, set, size) +} + +func BenchmarkTreeSetContains100000(b *testing.B) { + b.StopTimer() + size := 100000 + set := NewWithIntComparator() + for n := 0; n < size; n++ { + set.Add(n) + } + b.StartTimer() + benchmarkContains(b, set, size) +} + +func BenchmarkTreeSetAdd100(b *testing.B) { + b.StopTimer() + size := 100 + set := NewWithIntComparator() + b.StartTimer() + benchmarkAdd(b, set, size) +} + +func BenchmarkTreeSetAdd1000(b *testing.B) { + b.StopTimer() + size := 1000 + set := NewWithIntComparator() + for n := 0; n < size; n++ { + set.Add(n) + } + b.StartTimer() + benchmarkAdd(b, set, size) +} + +func BenchmarkTreeSetAdd10000(b *testing.B) { + b.StopTimer() + size := 10000 + set := NewWithIntComparator() + for n := 0; n < size; n++ { + set.Add(n) + } + b.StartTimer() + benchmarkAdd(b, set, size) +} + +func BenchmarkTreeSetAdd100000(b *testing.B) { + b.StopTimer() + size := 100000 + set := NewWithIntComparator() + for n := 0; n < size; n++ { + set.Add(n) + } + b.StartTimer() + benchmarkAdd(b, set, size) +} + +func BenchmarkTreeSetRemove100(b *testing.B) { + b.StopTimer() + size := 100 + set := NewWithIntComparator() + for n := 0; n < size; n++ { + set.Add(n) + } + b.StartTimer() + benchmarkRemove(b, set, size) +} + +func BenchmarkTreeSetRemove1000(b *testing.B) { + b.StopTimer() + size := 1000 + set := NewWithIntComparator() + for n := 0; n < size; n++ { + set.Add(n) + } + b.StartTimer() + benchmarkRemove(b, set, size) +} + +func BenchmarkTreeSetRemove10000(b *testing.B) { + b.StopTimer() + size := 10000 + set := NewWithIntComparator() + for n := 0; n < size; n++ { + set.Add(n) + } + b.StartTimer() + benchmarkRemove(b, set, size) +} + +func BenchmarkTreeSetRemove100000(b *testing.B) { + b.StopTimer() + size := 100000 + set := NewWithIntComparator() + for n := 0; n < size; n++ { + set.Add(n) + } + b.StartTimer() + benchmarkRemove(b, set, size) +} diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index 5b2579fa..48f6be4e 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -231,14 +231,103 @@ func TestStackIteratorLast(t *testing.T) { } } -func BenchmarkStack(b *testing.B) { +func benchmarkPush(b *testing.B, stack *Stack, size int) { for i := 0; i < b.N; i++ { - stack := New() - for n := 0; n < 1000; n++ { - stack.Push(i) + for n := 0; n < size; n++ { + stack.Push(n) } - for !stack.Empty() { + } +} + +func benchmarkPop(b *testing.B, stack *Stack, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { stack.Pop() } } } + +func BenchmarkArrayStackPop100(b *testing.B) { + b.StopTimer() + size := 100 + stack := New() + for n := 0; n < size; n++ { + stack.Push(n) + } + b.StartTimer() + benchmarkPop(b, stack, size) +} + +func BenchmarkArrayStackPop1000(b *testing.B) { + b.StopTimer() + size := 1000 + stack := New() + for n := 0; n < size; n++ { + stack.Push(n) + } + b.StartTimer() + benchmarkPop(b, stack, size) +} + +func BenchmarkArrayStackPop10000(b *testing.B) { + b.StopTimer() + size := 10000 + stack := New() + for n := 0; n < size; n++ { + stack.Push(n) + } + b.StartTimer() + benchmarkPop(b, stack, size) +} + +func BenchmarkArrayStackPop100000(b *testing.B) { + b.StopTimer() + size := 100000 + stack := New() + for n := 0; n < size; n++ { + stack.Push(n) + } + b.StartTimer() + benchmarkPop(b, stack, size) +} + +func BenchmarkArrayStackPush100(b *testing.B) { + b.StopTimer() + size := 100 + stack := New() + b.StartTimer() + benchmarkPush(b, stack, size) +} + +func BenchmarkArrayStackPush1000(b *testing.B) { + b.StopTimer() + size := 1000 + stack := New() + for n := 0; n < size; n++ { + stack.Push(n) + } + b.StartTimer() + benchmarkPush(b, stack, size) +} + +func BenchmarkArrayStackPush10000(b *testing.B) { + b.StopTimer() + size := 10000 + stack := New() + for n := 0; n < size; n++ { + stack.Push(n) + } + b.StartTimer() + benchmarkPush(b, stack, size) +} + +func BenchmarkArrayStackPush100000(b *testing.B) { + b.StopTimer() + size := 100000 + stack := New() + for n := 0; n < size; n++ { + stack.Push(n) + } + b.StartTimer() + benchmarkPush(b, stack, size) +} diff --git a/stacks/linkedliststack/linkedliststack_test.go b/stacks/linkedliststack/linkedliststack_test.go index ae5031a4..8fb0f437 100644 --- a/stacks/linkedliststack/linkedliststack_test.go +++ b/stacks/linkedliststack/linkedliststack_test.go @@ -147,14 +147,103 @@ func TestStackIteratorFirst(t *testing.T) { } } -func BenchmarkStack(b *testing.B) { +func benchmarkPush(b *testing.B, stack *Stack, size int) { for i := 0; i < b.N; i++ { - stack := New() - for n := 0; n < 1000; n++ { - stack.Push(i) + for n := 0; n < size; n++ { + stack.Push(n) } - for !stack.Empty() { + } +} + +func benchmarkPop(b *testing.B, stack *Stack, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { stack.Pop() } } } + +func BenchmarkLinkedListStackPop100(b *testing.B) { + b.StopTimer() + size := 100 + stack := New() + for n := 0; n < size; n++ { + stack.Push(n) + } + b.StartTimer() + benchmarkPop(b, stack, size) +} + +func BenchmarkLinkedListStackPop1000(b *testing.B) { + b.StopTimer() + size := 1000 + stack := New() + for n := 0; n < size; n++ { + stack.Push(n) + } + b.StartTimer() + benchmarkPop(b, stack, size) +} + +func BenchmarkLinkedListStackPop10000(b *testing.B) { + b.StopTimer() + size := 10000 + stack := New() + for n := 0; n < size; n++ { + stack.Push(n) + } + b.StartTimer() + benchmarkPop(b, stack, size) +} + +func BenchmarkLinkedListStackPop100000(b *testing.B) { + b.StopTimer() + size := 100000 + stack := New() + for n := 0; n < size; n++ { + stack.Push(n) + } + b.StartTimer() + benchmarkPop(b, stack, size) +} + +func BenchmarkLinkedListStackPush100(b *testing.B) { + b.StopTimer() + size := 100 + stack := New() + b.StartTimer() + benchmarkPush(b, stack, size) +} + +func BenchmarkLinkedListStackPush1000(b *testing.B) { + b.StopTimer() + size := 1000 + stack := New() + for n := 0; n < size; n++ { + stack.Push(n) + } + b.StartTimer() + benchmarkPush(b, stack, size) +} + +func BenchmarkLinkedListStackPush10000(b *testing.B) { + b.StopTimer() + size := 10000 + stack := New() + for n := 0; n < size; n++ { + stack.Push(n) + } + b.StartTimer() + benchmarkPush(b, stack, size) +} + +func BenchmarkLinkedListStackPush100000(b *testing.B) { + b.StopTimer() + size := 100000 + stack := New() + for n := 0; n < size; n++ { + stack.Push(n) + } + b.StartTimer() + benchmarkPush(b, stack, size) +} diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go index 987d806e..36ce9f95 100644 --- a/trees/binaryheap/binaryheap_test.go +++ b/trees/binaryheap/binaryheap_test.go @@ -246,15 +246,103 @@ func TestBinaryHeapIteratorLast(t *testing.T) { } } -func BenchmarkBinaryHeap(b *testing.B) { +func benchmarkPush(b *testing.B, heap *Heap, size int) { for i := 0; i < b.N; i++ { - heap := NewWithIntComparator() - for n := 0; n < 1000; n++ { - heap.Push(i) + for n := 0; n < size; n++ { + heap.Push(n) } - for !heap.Empty() { + } +} + +func benchmarkPop(b *testing.B, heap *Heap, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { heap.Pop() } } +} + +func BenchmarkBinaryHeapPop100(b *testing.B) { + b.StopTimer() + size := 100 + heap := NewWithIntComparator() + for n := 0; n < size; n++ { + heap.Push(n) + } + b.StartTimer() + benchmarkPop(b, heap, size) +} + +func BenchmarkBinaryHeapPop1000(b *testing.B) { + b.StopTimer() + size := 1000 + heap := NewWithIntComparator() + for n := 0; n < size; n++ { + heap.Push(n) + } + b.StartTimer() + benchmarkPop(b, heap, size) +} + +func BenchmarkBinaryHeapPop10000(b *testing.B) { + b.StopTimer() + size := 10000 + heap := NewWithIntComparator() + for n := 0; n < size; n++ { + heap.Push(n) + } + b.StartTimer() + benchmarkPop(b, heap, size) +} + +func BenchmarkBinaryHeapPop100000(b *testing.B) { + b.StopTimer() + size := 100000 + heap := NewWithIntComparator() + for n := 0; n < size; n++ { + heap.Push(n) + } + b.StartTimer() + benchmarkPop(b, heap, size) +} +func BenchmarkBinaryHeapPush100(b *testing.B) { + b.StopTimer() + size := 100 + heap := NewWithIntComparator() + b.StartTimer() + benchmarkPush(b, heap, size) +} + +func BenchmarkBinaryHeapPush1000(b *testing.B) { + b.StopTimer() + size := 1000 + heap := NewWithIntComparator() + for n := 0; n < size; n++ { + heap.Push(n) + } + b.StartTimer() + benchmarkPush(b, heap, size) +} + +func BenchmarkBinaryHeapPush10000(b *testing.B) { + b.StopTimer() + size := 10000 + heap := NewWithIntComparator() + for n := 0; n < size; n++ { + heap.Push(n) + } + b.StartTimer() + benchmarkPush(b, heap, size) +} + +func BenchmarkBinaryHeapPush100000(b *testing.B) { + b.StopTimer() + size := 100000 + heap := NewWithIntComparator() + for n := 0; n < size; n++ { + heap.Push(n) + } + b.StartTimer() + benchmarkPush(b, heap, size) } diff --git a/trees/btree/btree.go b/trees/btree/btree.go index d796a12a..549684f7 100644 --- a/trees/btree/btree.go +++ b/trees/btree/btree.go @@ -355,7 +355,6 @@ func (tree *Tree) splitNonRoot(node *Node) { insertPosition, _ := tree.search(parent, node.Entries[middle].Key) // Insert middle key into parent - // TODO check for memory leaks: node should be nilled and all its entries parent.Entries = append(parent.Entries, nil) copy(parent.Entries[insertPosition+1:], parent.Entries[insertPosition:]) parent.Entries[insertPosition] = node.Entries[middle] diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index 14571eea..4705bc10 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -1074,14 +1074,155 @@ func assertValidTreeNode(t *testing.T, node *Node, expectedEntries int, expected } } -func BenchmarkBTree(b *testing.B) { +func benchmarkGet(b *testing.B, tree *Tree, size int) { for i := 0; i < b.N; i++ { - tree := NewWithIntComparator(32) - for n := 0; n < 1000; n++ { - tree.Put(n, n) + for n := 0; n < size; n++ { + tree.Get(n) } - for n := 0; n < 1000; n++ { + } +} + +func benchmarkPut(b *testing.B, tree *Tree, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + } +} + +func benchmarkRemove(b *testing.B, tree *Tree, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { tree.Remove(n) } } } + +func BenchmarkBTreeGet100(b *testing.B) { + b.StopTimer() + size := 100 + tree := NewWithIntComparator(128) + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, tree, size) +} + +func BenchmarkBTreeGet1000(b *testing.B) { + b.StopTimer() + size := 1000 + tree := NewWithIntComparator(128) + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, tree, size) +} + +func BenchmarkBTreeGet10000(b *testing.B) { + b.StopTimer() + size := 10000 + tree := NewWithIntComparator(128) + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, tree, size) +} + +func BenchmarkBTreeGet100000(b *testing.B) { + b.StopTimer() + size := 100000 + tree := NewWithIntComparator(128) + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, tree, size) +} + +func BenchmarkBTreePut100(b *testing.B) { + b.StopTimer() + size := 100 + tree := NewWithIntComparator(128) + b.StartTimer() + benchmarkPut(b, tree, size) +} + +func BenchmarkBTreePut1000(b *testing.B) { + b.StopTimer() + size := 1000 + tree := NewWithIntComparator(128) + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, tree, size) +} + +func BenchmarkBTreePut10000(b *testing.B) { + b.StopTimer() + size := 10000 + tree := NewWithIntComparator(128) + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, tree, size) +} + +func BenchmarkBTreePut100000(b *testing.B) { + b.StopTimer() + size := 100000 + tree := NewWithIntComparator(128) + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, tree, size) +} + +func BenchmarkBTreeRemove100(b *testing.B) { + b.StopTimer() + size := 100 + tree := NewWithIntComparator(128) + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, tree, size) +} + +func BenchmarkBTreeRemove1000(b *testing.B) { + b.StopTimer() + size := 1000 + tree := NewWithIntComparator(128) + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, tree, size) +} + +func BenchmarkBTreeRemove10000(b *testing.B) { + b.StopTimer() + size := 10000 + tree := NewWithIntComparator(128) + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, tree, size) +} + +func BenchmarkBTreeRemove100000(b *testing.B) { + b.StopTimer() + size := 100000 + tree := NewWithIntComparator(128) + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, tree, size) +} diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index cdacdeee..714defcf 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -557,14 +557,155 @@ func TestRedBlackTreeIteratorLast(t *testing.T) { } } -func BenchmarkRedBlackTree(b *testing.B) { +func benchmarkGet(b *testing.B, tree *Tree, size int) { for i := 0; i < b.N; i++ { - tree := NewWithIntComparator() - for n := 0; n < 1000; n++ { - tree.Put(n, n) + for n := 0; n < size; n++ { + tree.Get(n) } - for n := 0; n < 1000; n++ { + } +} + +func benchmarkPut(b *testing.B, tree *Tree, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + } +} + +func benchmarkRemove(b *testing.B, tree *Tree, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { tree.Remove(n) } } } + +func BenchmarkRedBlackTreeGet100(b *testing.B) { + b.StopTimer() + size := 100 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, tree, size) +} + +func BenchmarkRedBlackTreeGet1000(b *testing.B) { + b.StopTimer() + size := 1000 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, tree, size) +} + +func BenchmarkRedBlackTreeGet10000(b *testing.B) { + b.StopTimer() + size := 10000 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, tree, size) +} + +func BenchmarkRedBlackTreeGet100000(b *testing.B) { + b.StopTimer() + size := 100000 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, tree, size) +} + +func BenchmarkRedBlackTreePut100(b *testing.B) { + b.StopTimer() + size := 100 + tree := NewWithIntComparator() + b.StartTimer() + benchmarkPut(b, tree, size) +} + +func BenchmarkRedBlackTreePut1000(b *testing.B) { + b.StopTimer() + size := 1000 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, tree, size) +} + +func BenchmarkRedBlackTreePut10000(b *testing.B) { + b.StopTimer() + size := 10000 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, tree, size) +} + +func BenchmarkRedBlackTreePut100000(b *testing.B) { + b.StopTimer() + size := 100000 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, tree, size) +} + +func BenchmarkRedBlackTreeRemove100(b *testing.B) { + b.StopTimer() + size := 100 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, tree, size) +} + +func BenchmarkRedBlackTreeRemove1000(b *testing.B) { + b.StopTimer() + size := 1000 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, tree, size) +} + +func BenchmarkRedBlackTreeRemove10000(b *testing.B) { + b.StopTimer() + size := 10000 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, tree, size) +} + +func BenchmarkRedBlackTreeRemove100000(b *testing.B) { + b.StopTimer() + size := 100000 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, tree, size) +} From ce647c94dddc66f232766911d2de8f8c2cd7b7a0 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 16 Jul 2016 06:57:46 +0200 Subject: [PATCH 101/320] - btree example and documentation --- README.md | 97 ++++++++++++++++++++++++++++++++++++++++++----- examples/btree.go | 59 ++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+), 9 deletions(-) create mode 100644 examples/btree.go diff --git a/README.md b/README.md index e1006895..74dcedaf 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Implementation of various data structures and algorithms in Go. - [TreeBidiMap](#treebidimap) - [Trees](#trees) - [RedBlackTree](#redblacktree) + - [BTree](#btree) - [BinaryHeap](#binaryheap) - [Functions](#functions) - [Comparator](#comparator) @@ -69,6 +70,7 @@ Containers are either ordered or unordered. All ordered containers provide [stat | [HashBidiMap](#hashbidimap) | no | no | no | key* | | [TreeBidiMap](#treebidimap) | yes | yes* | yes | key* | | [RedBlackTree](#redblacktree) | yes | yes* | no | key | +| [BTree](#btree) | yes | yes* | no | key | | [BinaryHeap](#binaryheap) | yes | yes* | no | index | | | | *reversible | | *bidirectional | @@ -525,11 +527,11 @@ type Tree interface { A red–black [tree](#trees) is a binary search tree with an extra bit of data per node, its color, which can be either red or black. The extra bit of storage ensures an approximately balanced tree by constraining how nodes are colored from any path from the root to the leaf. Thus, it is a data structure which is a type of self-balancing binary search tree. -The balancing of the tree is not perfect but it is good enough to allow it to guarantee searching in O(log n) time, where n is the total number of elements in the tree. The insertion and deletion operations, along with the tree rearrangement and recoloring, are also performed in O(log n) time. [Wikipedia](http://en.wikipedia.org/wiki/Red%E2%80%93black_tree) +The balancing of the tree is not perfect but it is good enough to allow it to guarantee searching in O(log n) time, where n is the total number of elements in the tree. The insertion and deletion operations, along with the tree rearrangement and recoloring, are also performed in O(log n) time. [Wikipedia](http://en.wikipedia.org/wiki/Red%E2%80%93black_tree) -Implements [Tree](#trees) and [IteratorWithKey](#iteratorwithkey) interfaces. +Implements [Tree](#trees) and [ReverseIteratorWithKey](#reverseiteratorwithkey) interfaces. -
+

```go package main @@ -550,7 +552,7 @@ func main() { tree.Put(5, "e") // 1->a, 2->b, 3->c, 4->d, 5->e (in order) tree.Put(6, "f") // 1->a, 2->b, 3->c, 4->d, 5->e, 6->f (in order) - fmt.Println(m) + fmt.Println(tree) // // RedBlackTree // │ ┌── 6 @@ -564,7 +566,7 @@ func main() { _ = tree.Keys() // []interface {}{1, 2, 3, 4, 5, 6} (in order) tree.Remove(2) // 1->a, 3->c, 4->d, 5->e, 6->f (in order) - fmt.Println(m) + fmt.Println(tree) // // RedBlackTree // │ ┌── 6 @@ -587,6 +589,81 @@ func main() { Extending the red-black tree's functionality has been demonstrated in the following [example](https://github.com/emirpasic/gods/blob/master/examples/redblacktreeextended.go). +#### BTree + +B-tree is a self-balancing tree data structure that keeps data sorted and allows searches, sequential access, insertions, and deletions in logarithmic time. The B-tree is a generalization of a binary search tree in that a node can have more than two children. + +According to Knuth's definition, a B-tree of order m is a tree which satisfies the following properties: + +- Every node has at most m children. +- Every non-leaf node (except root) has at least ⌈m/2⌉ children. +- The root has at least two children if it is not a leaf node. +- A non-leaf node with k children contains k−1 keys. +- All leaves appear in the same level + +Each internal node’s keys act as separation values which divide its subtrees. For example, if an internal node has 3 child nodes (or subtrees) then it must have 2 keys: a1 and a2. All values in the leftmost subtree will be less than a1, all values in the middle subtree will be between a1 and a2, and all values in the rightmost subtree will be greater than a2.[Wikipedia](http://en.wikipedia.org/wiki/Red%E2%80%93black_tree) + +Implements [Tree](#trees) and [ReverseIteratorWithKey](#reverseiteratorwithkey) interfaces. + +

+ +```go +package main + +import ( + "fmt" + "github.com/emirpasic/gods/trees/btree" +) + +func main() { + tree := btree.NewWithIntComparator(3) // empty (keys are of type int) + + tree.Put(1, "x") // 1->x + tree.Put(2, "b") // 1->x, 2->b (in order) + tree.Put(1, "a") // 1->a, 2->b (in order, replacement) + tree.Put(3, "c") // 1->a, 2->b, 3->c (in order) + tree.Put(4, "d") // 1->a, 2->b, 3->c, 4->d (in order) + tree.Put(5, "e") // 1->a, 2->b, 3->c, 4->d, 5->e (in order) + tree.Put(6, "f") // 1->a, 2->b, 3->c, 4->d, 5->e, 6->f (in order) + tree.Put(7, "g") // 1->a, 2->b, 3->c, 4->d, 5->e, 6->f, 7->g (in order) + + fmt.Println(tree) + // BTree + // 1 + // 2 + // 3 + // 4 + // 5 + // 6 + // 7 + + _ = tree.Values() // []interface {}{"a", "b", "c", "d", "e", "f", "g"} (in order) + _ = tree.Keys() // []interface {}{1, 2, 3, 4, 5, 6, 7} (in order) + + tree.Remove(2) // 1->a, 3->c, 4->d, 5->e, 6->f (in order) + fmt.Println(tree) + // BTree + // 1 + // 3 + // 4 + // 5 + // 6 + + tree.Clear() // empty + tree.Empty() // true + tree.Size() // 0 + + // Other: + tree.Height() // gets the height of the tree + tree.Left() // gets the left-most (min) node + tree.LeftKey() // get the left-most (min) node's key + tree.LeftValue() // get the left-most (min) node's value + tree.Right() // get the right-most (max) node + tree.RightKey() // get the right-most (max) node's key + tree.RightValue() // get the right-most (max) node's value +} +``` + #### BinaryHeap A binary heap is a [tree](#trees) created using a binary tree. It can be seen as a binary tree with two additional constraints: @@ -596,11 +673,11 @@ A binary heap is a [tree](#trees) created using a binary tree. It can be seen as A binary heap is a complete binary tree; that is, all levels of the tree, except possibly the last one (deepest) are fully filled, and, if the last level of the tree is not complete, the nodes of that level are filled from left to right. - Heap property: - All nodes are either greater than or equal to or less than or equal to each of its children, according to a comparison predicate defined for the heap. [Wikipedia](http://en.wikipedia.org/wiki/Binary_heap) + All nodes are either greater than or equal to or less than or equal to each of its children, according to a comparison predicate defined for the heap. [Wikipedia](http://en.wikipedia.org/wiki/Binary_heap) -Implements [Tree](#trees) and [IteratorWithIndex](#iteratorwithindex) interfaces. +Implements [Tree](#trees) and [ReverseIteratorWithIndex](#reverseiteratorwithindex) interfaces. -
+

```go package main @@ -1142,7 +1219,9 @@ Thread safety is not a concern of this project, this should be handled at a high ### Testing and Benchmarking -`go test -run=NO_TEST -bench . -benchmem -benchtime 5s ./...` +This takes a while, so test within sub-packages: + +`go test -run=NO_TEST -bench . -benchmem -benchtime 1s ./...` ### Contributing diff --git a/examples/btree.go b/examples/btree.go new file mode 100644 index 00000000..b9076965 --- /dev/null +++ b/examples/btree.go @@ -0,0 +1,59 @@ +// 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 examples + +import ( + "fmt" + "github.com/emirpasic/gods/trees/btree" +) + +// BTreeExample to demonstrate basic usage of BTree +func BTreeExample() { + tree := btree.NewWithIntComparator(3) // empty (keys are of type int) + + tree.Put(1, "x") // 1->x + tree.Put(2, "b") // 1->x, 2->b (in order) + tree.Put(1, "a") // 1->a, 2->b (in order, replacement) + tree.Put(3, "c") // 1->a, 2->b, 3->c (in order) + tree.Put(4, "d") // 1->a, 2->b, 3->c, 4->d (in order) + tree.Put(5, "e") // 1->a, 2->b, 3->c, 4->d, 5->e (in order) + tree.Put(6, "f") // 1->a, 2->b, 3->c, 4->d, 5->e, 6->f (in order) + tree.Put(7, "g") // 1->a, 2->b, 3->c, 4->d, 5->e, 6->f, 7->g (in order) + + fmt.Println(tree) + // BTree + // 1 + // 2 + // 3 + // 4 + // 5 + // 6 + // 7 + + _ = tree.Values() // []interface {}{"a", "b", "c", "d", "e", "f", "g"} (in order) + _ = tree.Keys() // []interface {}{1, 2, 3, 4, 5, 6, 7} (in order) + + tree.Remove(2) // 1->a, 3->c, 4->d, 5->e, 6->f (in order) + fmt.Println(tree) + // BTree + // 1 + // 3 + // 4 + // 5 + // 6 + + tree.Clear() // empty + tree.Empty() // true + tree.Size() // 0 + + // Other: + tree.Height() // gets the height of the tree + tree.Left() // gets the left-most (min) node + tree.LeftKey() // get the left-most (min) node's key + tree.LeftValue() // get the left-most (min) node's value + tree.Right() // get the right-most (max) node + tree.RightKey() // get the right-most (max) node's key + tree.RightValue() // get the right-most (max) node's value +} From 3066d0de5ebb4ac0539e5a171b8694e4cc08a59b Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 16 Jul 2016 07:24:44 +0200 Subject: [PATCH 102/320] - benchmarks in documentation --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 74dcedaf..7c409096 100644 --- a/README.md +++ b/README.md @@ -1223,6 +1223,8 @@ This takes a while, so test within sub-packages: `go test -run=NO_TEST -bench . -benchmem -benchtime 1s ./...` +![enter image description here](https://cloud.githubusercontent.com/assets/3115942/16892949/e4a70b60-4b25-11e6-8914-b294f3a5a1aa.png) + ### Contributing Biggest contribution towards this library is to use it and give us feedback for further improvements and additions. From 63d434cce6beb006e349f6ffcb0612f0c442ed6e Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 16 Jul 2016 07:26:40 +0200 Subject: [PATCH 103/320] - benchmarks in documentation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7c409096..1f552b21 100644 --- a/README.md +++ b/README.md @@ -1223,7 +1223,7 @@ This takes a while, so test within sub-packages: `go test -run=NO_TEST -bench . -benchmem -benchtime 1s ./...` -![enter image description here](https://cloud.githubusercontent.com/assets/3115942/16892949/e4a70b60-4b25-11e6-8914-b294f3a5a1aa.png) +

![enter image description here](https://cloud.githubusercontent.com/assets/3115942/16892949/e4a70b60-4b25-11e6-8914-b294f3a5a1aa.png)

### Contributing From 7728a69eae695339a55653b0c6b1f057236f92ca Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 16 Jul 2016 07:29:43 +0200 Subject: [PATCH 104/320] - benchmarks in documentation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1f552b21..c00e0d56 100644 --- a/README.md +++ b/README.md @@ -1223,7 +1223,7 @@ This takes a while, so test within sub-packages: `go test -run=NO_TEST -bench . -benchmem -benchtime 1s ./...` -

![enter image description here](https://cloud.githubusercontent.com/assets/3115942/16892949/e4a70b60-4b25-11e6-8914-b294f3a5a1aa.png)

+

### Contributing From 8e34c656ab75d8ba92da6e87c86d80de94f055d1 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 16 Jul 2016 07:32:26 +0200 Subject: [PATCH 105/320] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c00e0d56..0ebd8ebf 100644 --- a/README.md +++ b/README.md @@ -1223,7 +1223,7 @@ This takes a while, so test within sub-packages: `go test -run=NO_TEST -bench . -benchmem -benchtime 1s ./...` -

+

### Contributing From 84564da2b4aabad6c322177a2c4fcd7538e93823 Mon Sep 17 00:00:00 2001 From: glenherb Date: Sat, 6 Aug 2016 16:41:29 -0500 Subject: [PATCH 106/320] Make IntComparator a bit more direct --- utils/comparator.go | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/utils/comparator.go b/utils/comparator.go index 9efab79c..5da01646 100644 --- a/utils/comparator.go +++ b/utils/comparator.go @@ -15,16 +15,7 @@ type Comparator func(a, b interface{}) int // IntComparator provides a basic comparison on ints func IntComparator(a, b interface{}) int { - aInt := a.(int) - bInt := b.(int) - switch { - case aInt > bInt: - return 1 - case aInt < bInt: - return -1 - default: - return 0 - } + return a.(int) - b.(int) } // StringComparator provides a fast comparison on strings From 0790df9fd00ba7ab2f7b6dcc3b9d422a02383986 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 7 Aug 2016 01:54:22 +0200 Subject: [PATCH 107/320] - errcheck --- README.md | 3 ++- trees/btree/btree.go | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0ebd8ebf..8e4a1b2a 100644 --- a/README.md +++ b/README.md @@ -1237,10 +1237,11 @@ Coding style: # Install tooling and set path: go get github.com/golang/lint/golint go get github.com/fzipp/gocyclo +go get github.com/kisielk/errcheck export PATH=$PATH:$GOPATH/bin # Fix errors and warnings: -go fmt ./... && gofmt -s -w . && go vet ./... && go get ./... && go test ./... && golint ./... && gocyclo -avg -over 15 . +go fmt ./... && gofmt -s -w . && go vet ./... && go get ./... && go test ./... && golint ./... && gocyclo -avg -over 15 . && errcheck ./... ``` ### License diff --git a/trees/btree/btree.go b/trees/btree/btree.go index 549684f7..5f866997 100644 --- a/trees/btree/btree.go +++ b/trees/btree/btree.go @@ -191,7 +191,8 @@ func (tree *Tree) RightValue() interface{} { // String returns a string representation of container (for debugging purposes) func (tree *Tree) String() string { var buffer bytes.Buffer - buffer.WriteString("BTree\n") + if _, err := buffer.WriteString("BTree\n"); err != nil { + } if !tree.Empty() { tree.output(&buffer, tree.Root, 0, true) } @@ -208,8 +209,10 @@ func (tree *Tree) output(buffer *bytes.Buffer, node *Node, level int, isTail boo tree.output(buffer, node.Children[e], level+1, true) } if e < len(node.Entries) { - buffer.WriteString(strings.Repeat(" ", level)) - buffer.WriteString(fmt.Sprintf("%v", node.Entries[e].Key) + "\n") + if _, err := buffer.WriteString(strings.Repeat(" ", level)); err != nil { + } + if _, err := buffer.WriteString(fmt.Sprintf("%v", node.Entries[e].Key) + "\n"); err != nil { + } } } } From f310ac001e4d5af4eecb5a13bafe7114a382be7f Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 7 Aug 2016 01:57:52 +0200 Subject: [PATCH 108/320] - fix comparator test --- utils/comparator_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/comparator_test.go b/utils/comparator_test.go index 12849f84..fcdef29c 100644 --- a/utils/comparator_test.go +++ b/utils/comparator_test.go @@ -15,7 +15,7 @@ func TestIntComparator(t *testing.T) { {1, 1, 0}, {1, 2, -1}, {2, 1, 1}, - {11, 22, -1}, + {11, 22, -11}, {0, 0, 0}, {1, 0, 1}, {0, 1, -1}, From 62b6e90ed7e32e181a49fae6834041f02af2f840 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 7 Aug 2016 02:03:02 +0200 Subject: [PATCH 109/320] - documentation update on removing elements while iterating #28 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8e4a1b2a..0534ddfc 100644 --- a/README.md +++ b/README.md @@ -799,6 +799,8 @@ func main() { All ordered containers have stateful iterators. Typically an iterator is obtained by _Iterator()_ function of an ordered container. Once obtained, iterator's _Next()_ function moves the iterator to the next element and returns true if there was a next element. If there was an element, then element's can be obtained by iterator's _Value()_ function. Depending on the ordering type, it's position can be obtained by iterator's _Index()_ or _Key()_ functions. Some containers even provide reversible iterators, essentially the same, but provide another extra _Prev()_ function that moves the iterator to the previous element and returns true if there was a previous element. +Note: it is unsafe to remove elements from container while iterating. + #### IteratorWithIndex An [iterator](#iterator) whose elements are referenced by an index. From 196706bb29654f92e625d1b26315de0755dffa33 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 7 Sep 2016 03:19:20 +0200 Subject: [PATCH 110/320] - set key to key if direct match when inserting into red-black tree. fixes the issue when the key is a struct type, which is how treeset uses the red-black tree #31 --- trees/redblacktree/redblacktree.go | 1 + 1 file changed, 1 insertion(+) diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index a8a496ec..f9c9bc91 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -72,6 +72,7 @@ func (tree *Tree) Put(key interface{}, value interface{}) { compare := tree.Comparator(key, node.Key) switch { case compare == 0: + node.Key = key node.Value = value return case compare < 0: From 4ea857183a71ac609dba19c2de618768ca748a22 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 7 Sep 2016 03:51:19 +0200 Subject: [PATCH 111/320] - optimization to bulk insert into heap as per @cristaloleg suggestion #32 --- README.md | 4 +--- trees/binaryheap/binaryheap.go | 28 ++++++++++++++++++++++------ trees/binaryheap/binaryheap_test.go | 13 +++++++++++++ 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 0534ddfc..e1bdca6f 100644 --- a/README.md +++ b/README.md @@ -710,9 +710,7 @@ func main() { return -utils.IntComparator(a, b) } heap = binaryheap.NewWith(inverseIntComparator) // empty (min-heap) - heap.Push(2) // 2 - heap.Push(3) // 3, 2 - heap.Push(1) // 3, 2, 1 + heap.Push(2, 3, 1) // 3, 2, 1 (bulk optimized) heap.Values() // 3, 2, 1 } ``` diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index 0ba92844..70b28cf5 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -45,9 +45,20 @@ func NewWithStringComparator() *Heap { } // Push adds a value onto the heap and bubbles it up accordingly. -func (heap *Heap) Push(value interface{}) { - heap.list.Add(value) - heap.bubbleUp() +func (heap *Heap) Push(values ...interface{}) { + if len(values) == 1 { + heap.list.Add(values[0]) + heap.bubbleUp() + } else { + // Reference: https://en.wikipedia.org/wiki/Binary_heap#Building_a_heap + for _, value := range values { + heap.list.Add(value) + } + size := heap.list.Size()/2 + 1 + for i := size; i >= 0; i-- { + heap.bubbleDownIndex(i) + } + } } // Pop removes top element on heap and returns it, or nil if heap is empty. @@ -101,10 +112,15 @@ func (heap *Heap) String() string { return str } -// Performs the "bubble down" operation. This is to place the element that is at the -// root of the heap in its correct place so that the heap maintains the min/max-heap order property. +// Performs the "bubble down" operation. This is to place the element that is at the root +// of the heap in its correct place so that the heap maintains the min/max-heap order property. func (heap *Heap) bubbleDown() { - index := 0 + heap.bubbleDownIndex(0) +} + +// Performs the "bubble down" operation. This is to place the element that is at the index +// of the heap in its correct place so that the heap maintains the min/max-heap order property. +func (heap *Heap) bubbleDownIndex(index int) { size := heap.list.Size() for leftIndex := index<<1 + 1; leftIndex < size; leftIndex = index<<1 + 1 { rightIndex := index<<1 + 2 diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go index 36ce9f95..a20d6471 100644 --- a/trees/binaryheap/binaryheap_test.go +++ b/trees/binaryheap/binaryheap_test.go @@ -34,6 +34,19 @@ func TestBinaryHeapPush(t *testing.T) { } } +func TestBinaryHeapPushBulk(t *testing.T) { + heap := NewWithIntComparator() + + heap.Push(15, 20, 3, 1, 2) + + if actualValue := heap.Values(); actualValue[0].(int) != 1 || actualValue[1].(int) != 2 || actualValue[2].(int) != 3 { + t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + } + if actualValue, ok := heap.Pop(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + func TestBinaryHeapPop(t *testing.T) { heap := NewWithIntComparator() From 320ab1bc739807472101aeb4a2b096b0411b4ec5 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 7 Sep 2016 05:07:13 +0200 Subject: [PATCH 112/320] Revert "Make IntComparator a bit more direct" --- utils/comparator.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/utils/comparator.go b/utils/comparator.go index 5da01646..9efab79c 100644 --- a/utils/comparator.go +++ b/utils/comparator.go @@ -15,7 +15,16 @@ type Comparator func(a, b interface{}) int // IntComparator provides a basic comparison on ints func IntComparator(a, b interface{}) int { - return a.(int) - b.(int) + aInt := a.(int) + bInt := b.(int) + switch { + case aInt > bInt: + return 1 + case aInt < bInt: + return -1 + default: + return 0 + } } // StringComparator provides a fast comparison on strings From 0a96a47f6ba41b5509e30aafa8877ede555a0b5c Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 7 Sep 2016 05:19:07 +0200 Subject: [PATCH 113/320] - fix test for int comparator --- utils/comparator_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/comparator_test.go b/utils/comparator_test.go index fcdef29c..12849f84 100644 --- a/utils/comparator_test.go +++ b/utils/comparator_test.go @@ -15,7 +15,7 @@ func TestIntComparator(t *testing.T) { {1, 1, 0}, {1, 2, -1}, {2, 1, 1}, - {11, 22, -11}, + {11, 22, -1}, {0, 0, 0}, {1, 0, 1}, {0, 1, -1}, From 8f1121f54daa196950ef5299bdf631e0472307ff Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 7 Sep 2016 05:25:42 +0200 Subject: [PATCH 114/320] test different go versions with travis --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index ff2c2cd1..b7fa8691 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,10 @@ language: go go: + - 1.1 + - 1.2 + - 1.3 - 1.4 + - 1.5 + - 1.6 + - 1.7 - tip From b5ede7d429dc73ecfd0dae6580458d7a71fb93ee Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 17 Sep 2016 22:11:18 +0200 Subject: [PATCH 115/320] - all comparators for builtin types --- README.md | 32 ++++++- utils/comparator.go | 210 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 224 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index e1bdca6f..a833b131 100644 --- a/README.md +++ b/README.md @@ -739,14 +739,38 @@ Comparator signature: type Comparator func(a, b interface{}) int ``` -Two common comparators are included in the library: +All common comparators for builtin types are included in the library: ```go +func StringComparator(a, b interface{}) int + func IntComparator(a, b interface{}) int -``` -```go -func StringComparator(a, b interface{}) int +func Int8Comparator(a, b interface{}) int + +func Int16Comparator(a, b interface{}) int + +func Int32Comparator(a, b interface{}) int + +func Int64Comparator(a, b interface{}) int + +func UIntComparator(a, b interface{}) int + +func UInt8Comparator(a, b interface{}) int + +func UInt16Comparator(a, b interface{}) int + +func UInt32Comparator(a, b interface{}) int + +func UInt64Comparator(a, b interface{}) int + +func Float32Comparator(a, b interface{}) int + +func Float64Comparator(a, b interface{}) int + +func ByteComparator(a, b interface{}) int + +func RuneComparator(a, b interface{}) int ``` Writing custom comparators is easy: diff --git a/utils/comparator.go b/utils/comparator.go index 9efab79c..98d6e3d8 100644 --- a/utils/comparator.go +++ b/utils/comparator.go @@ -13,20 +13,6 @@ package utils // positive , if a > b type Comparator func(a, b interface{}) int -// IntComparator provides a basic comparison on ints -func IntComparator(a, b interface{}) int { - aInt := a.(int) - bInt := b.(int) - switch { - case aInt > bInt: - return 1 - case aInt < bInt: - return -1 - default: - return 0 - } -} - // StringComparator provides a fast comparison on strings func StringComparator(a, b interface{}) int { s1 := a.(string) @@ -50,3 +36,199 @@ func StringComparator(a, b interface{}) int { } return 0 } + +// IntComparator provides a basic comparison on int +func IntComparator(a, b interface{}) int { + aAsserted := a.(int) + bAsserted := b.(int) + switch { + case aAsserted > bAsserted: + return 1 + case aAsserted < bAsserted: + return -1 + default: + return 0 + } +} + +// Int8Comparator provides a basic comparison on int8 +func Int8Comparator(a, b interface{}) int { + aAsserted := a.(int8) + bAsserted := b.(int8) + switch { + case aAsserted > bAsserted: + return 1 + case aAsserted < bAsserted: + return -1 + default: + return 0 + } +} + +// Int16Comparator provides a basic comparison on int16 +func Int16Comparator(a, b interface{}) int { + aAsserted := a.(int16) + bAsserted := b.(int16) + switch { + case aAsserted > bAsserted: + return 1 + case aAsserted < bAsserted: + return -1 + default: + return 0 + } +} + +// Int32Comparator provides a basic comparison on int32 +func Int32Comparator(a, b interface{}) int { + aAsserted := a.(int32) + bAsserted := b.(int32) + switch { + case aAsserted > bAsserted: + return 1 + case aAsserted < bAsserted: + return -1 + default: + return 0 + } +} + +// Int64Comparator provides a basic comparison on int64 +func Int64Comparator(a, b interface{}) int { + aAsserted := a.(int64) + bAsserted := b.(int64) + switch { + case aAsserted > bAsserted: + return 1 + case aAsserted < bAsserted: + return -1 + default: + return 0 + } +} + +// UIntComparator provides a basic comparison on uint +func UIntComparator(a, b interface{}) int { + aAsserted := a.(uint) + bAsserted := b.(uint) + switch { + case aAsserted > bAsserted: + return 1 + case aAsserted < bAsserted: + return -1 + default: + return 0 + } +} + +// UInt8Comparator provides a basic comparison on uint8 +func UInt8Comparator(a, b interface{}) int { + aAsserted := a.(uint8) + bAsserted := b.(uint8) + switch { + case aAsserted > bAsserted: + return 1 + case aAsserted < bAsserted: + return -1 + default: + return 0 + } +} + +// UInt16Comparator provides a basic comparison on uint16 +func UInt16Comparator(a, b interface{}) int { + aAsserted := a.(uint16) + bAsserted := b.(uint16) + switch { + case aAsserted > bAsserted: + return 1 + case aAsserted < bAsserted: + return -1 + default: + return 0 + } +} + +// UInt32Comparator provides a basic comparison on uint32 +func UInt32Comparator(a, b interface{}) int { + aAsserted := a.(uint32) + bAsserted := b.(uint32) + switch { + case aAsserted > bAsserted: + return 1 + case aAsserted < bAsserted: + return -1 + default: + return 0 + } +} + +// UInt64Comparator provides a basic comparison on uint64 +func UInt64Comparator(a, b interface{}) int { + aAsserted := a.(uint64) + bAsserted := b.(uint64) + switch { + case aAsserted > bAsserted: + return 1 + case aAsserted < bAsserted: + return -1 + default: + return 0 + } +} + +// Float32Comparator provides a basic comparison on float32 +func Float32Comparator(a, b interface{}) int { + aAsserted := a.(float32) + bAsserted := b.(float32) + switch { + case aAsserted > bAsserted: + return 1 + case aAsserted < bAsserted: + return -1 + default: + return 0 + } +} + +// Float64Comparator provides a basic comparison on float64 +func Float64Comparator(a, b interface{}) int { + aAsserted := a.(float64) + bAsserted := b.(float64) + switch { + case aAsserted > bAsserted: + return 1 + case aAsserted < bAsserted: + return -1 + default: + return 0 + } +} + +// ByteComparator provides a basic comparison on byte +func ByteComparator(a, b interface{}) int { + aAsserted := a.(byte) + bAsserted := b.(byte) + switch { + case aAsserted > bAsserted: + return 1 + case aAsserted < bAsserted: + return -1 + default: + return 0 + } +} + +// RuneComparator provides a basic comparison on rune +func RuneComparator(a, b interface{}) int { + aAsserted := a.(rune) + bAsserted := b.(rune) + switch { + case aAsserted > bAsserted: + return 1 + case aAsserted < bAsserted: + return -1 + default: + return 0 + } +} From d036ecbbb9eae9a0546efefe73dda9180375bfb3 Mon Sep 17 00:00:00 2001 From: RichardHightower Date: Tue, 20 Dec 2016 10:32:18 -0800 Subject: [PATCH 116/320] added time comparison --- utils/comparator.go | 17 +++++++++++++++++ utils/comparator_test.go | 22 ++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/utils/comparator.go b/utils/comparator.go index 98d6e3d8..ef5246a8 100644 --- a/utils/comparator.go +++ b/utils/comparator.go @@ -4,6 +4,8 @@ package utils +import "time" + // Comparator will make type assertion (see IntComparator for example), // which will panic if a or b are not of the asserted type. // @@ -51,6 +53,21 @@ func IntComparator(a, b interface{}) int { } } +// IntComparator provides a basic comparison on int +func TimeComparator(a, b interface{}) int { + aAsserted := a.(time.Time) + bAsserted := b.(time.Time) + + switch { + case aAsserted.After(bAsserted) : + return 1 + case aAsserted.Before(bAsserted): + return -1 + default: + return 0 + } +} + // Int8Comparator provides a basic comparison on int8 func Int8Comparator(a, b interface{}) int { aAsserted := a.(int8) diff --git a/utils/comparator_test.go b/utils/comparator_test.go index 12849f84..00d028f2 100644 --- a/utils/comparator_test.go +++ b/utils/comparator_test.go @@ -6,6 +6,7 @@ package utils import ( "testing" + "time" ) func TestIntComparator(t *testing.T) { @@ -30,6 +31,27 @@ func TestIntComparator(t *testing.T) { } } + +func TestTimeComparator(t *testing.T) { + + now := time.Now() + + // i1,i2,expected + tests := [][]interface{}{ + {now, now, 0}, + {now.Add(24 * 7 * 2 * time.Hour), now, 1}, + {now, now.Add(24 * 7 * 2 * time.Hour), -1}, + } + + for _, test := range tests { + actual := TimeComparator(test[0], test[1]) + expected := test[2] + if actual != expected { + t.Errorf("Got %v expected %v", actual, expected) + } + } +} + func TestStringComparator(t *testing.T) { // s1,s2,expected From 1d7bfb173f7ef278b5c541d3bad82973610650cb Mon Sep 17 00:00:00 2001 From: RichardHightower Date: Tue, 20 Dec 2016 10:35:13 -0800 Subject: [PATCH 117/320] Comparator for time. --- utils/comparator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/comparator.go b/utils/comparator.go index ef5246a8..b5f0f79b 100644 --- a/utils/comparator.go +++ b/utils/comparator.go @@ -53,7 +53,7 @@ func IntComparator(a, b interface{}) int { } } -// IntComparator provides a basic comparison on int +// TimeComparator provides a basic comparison on time.Time func TimeComparator(a, b interface{}) int { aAsserted := a.(time.Time) bAsserted := b.(time.Time) From 5e31aedca2d717c2ca7f5b6de9fe0b78e09359a1 Mon Sep 17 00:00:00 2001 From: ferhat elmas Date: Thu, 12 Jan 2017 17:25:02 +0100 Subject: [PATCH 118/320] readme: simple typo fix --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a833b131..9bb50e6f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # GoDS (Go Data Structures) -Implementation of various data structures and algorithms in Go. +Implementation of various data structures and algorithms in Go. ## Data Structures @@ -211,7 +211,7 @@ func main() { ### Sets -A set is a data structure that can store elements and has no repeated values. It is a computer implementation of the mathematical concept of a finite set. Unlike most other collection types, rather than retrieving a specific element from a set, one typically tests an element for membership in a set. This structed is often used to ensure that no duplicates are present in a container. +A set is a data structure that can store elements and has no repeated values. It is a computer implementation of the mathematical concept of a finite set. Unlike most other collection types, rather than retrieving a specific element from a set, one typically tests an element for membership in a set. This structure is often used to ensure that no duplicates are present in a container. Implements [Container](#containers) interface. From e3980e5b80c39c604c21ed7cbe56a737fd2d258e Mon Sep 17 00:00:00 2001 From: Benjamin Scher Purcell Date: Sat, 25 Feb 2017 14:29:26 -0600 Subject: [PATCH 119/320] add avl implementation --- trees/avl/LICENSE | 13 + trees/avl/avl.go | 425 +++++++++++++++++++++++++ trees/avl/avl_test.go | 711 ++++++++++++++++++++++++++++++++++++++++++ trees/avl/iterator.go | 111 +++++++ 4 files changed, 1260 insertions(+) create mode 100644 trees/avl/LICENSE create mode 100644 trees/avl/avl.go create mode 100644 trees/avl/avl_test.go create mode 100644 trees/avl/iterator.go diff --git a/trees/avl/LICENSE b/trees/avl/LICENSE new file mode 100644 index 00000000..985d32d1 --- /dev/null +++ b/trees/avl/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2017 Benjamin Scher Purcell + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/trees/avl/avl.go b/trees/avl/avl.go new file mode 100644 index 00000000..09b51814 --- /dev/null +++ b/trees/avl/avl.go @@ -0,0 +1,425 @@ +// Copyright (c) 2017, Benjamin Scher Purcell. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package avl implements an AVL balanced binary tree. +// +// Structure is not thread safe. +// +package avl + +import ( + "io/ioutil" + "log" + + "github.com/emirpasic/gods/trees" + "github.com/emirpasic/gods/utils" +) + +func assertTreeImplementation() { + var _ trees.Tree = new(Tree) +} + +var dbgLog = log.New(ioutil.Discard, "avl: ", log.LstdFlags) + +// Tree holds elements of the AVL tree. +type Tree struct { + Root *Node + size int + Comparator utils.Comparator +} + +// A Node holds an Ordered element of the AVL tree in +// the Val field. +type Node struct { + Key interface{} + Value interface{} + c [2]*Node + p *Node + b int8 +} + +// NewWith instantiates a red-black tree with the custom comparator. +func NewWith(comparator utils.Comparator) *Tree { + return &Tree{Comparator: comparator} +} + +// NewWithIntComparator instantiates a red-black tree with the IntComparator, i.e. keys are of type int. +func NewWithIntComparator() *Tree { + return &Tree{Comparator: utils.IntComparator} +} + +// NewWithStringComparator instantiates a red-black tree with the StringComparator, i.e. keys are of type string. +func NewWithStringComparator() *Tree { + return &Tree{Comparator: utils.StringComparator} +} + +// Size returns the number of elements stored in the tree. +func (t *Tree) Size() int { + return t.size +} + +// Empty returns true if tree does not contain any nodes. +func (t *Tree) Empty() bool { + return t.size == 0 +} + +// Clear removes all nodes from the tree. +func (t *Tree) Clear() { + t.Root = nil + t.size = 0 +} + +// Get looks up val and returns the matching element if +// it is found. +// +// Val's Less implementation must be able to handle +// comparisons to elements stored in this tree. +func (t *Tree) Get(key interface{}) (value interface{}, found bool) { + n := t.Root + for n != nil { + cmp := t.Comparator(key, n.Key) + switch { + case cmp < 0: + n = n.c[0] + case cmp == 0: + return n.Value, true + case cmp > 0: + n = n.c[1] + } + } + return nil, false +} + +// Floor Finds floor node of the input key, return the floor node or nil if no ceiling is found. +// Second return parameter is true if floor was found, otherwise false. +// +// Floor node is defined as the largest node that is smaller than or equal to the given node. +// A floor node may not be found, either because the tree is empty, or because +// all nodes in the tree is larger than the given node. +// +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (t *Tree) Floor(key interface{}) (floor *Node, found bool) { + found = false + n := t.Root + for n != nil { + c := t.Comparator(key, n.Key) + switch { + case c == 0: + return n, true + case c < 0: + n = n.c[0] + case c > 0: + floor, found = n, true + n = n.c[1] + } + } + if found { + return + } + return nil, false +} + +// Ceiling finds ceiling node of the input key, return the ceiling node or nil if no ceiling is found. +// Second return parameter is true if ceiling was found, otherwise false. +// +// Ceiling node is defined as the smallest node that is larger than or equal to the given node. +// A ceiling node may not be found, either because the tree is empty, or because +// all nodes in the tree is smaller than the given node. +// +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (t *Tree) Ceiling(key interface{}) (floor *Node, found bool) { + found = false + n := t.Root + for n != nil { + c := t.Comparator(key, n.Key) + switch { + case c == 0: + return n, true + case c < 0: + floor, found = n, true + n = n.c[0] + case c > 0: + n = n.c[1] + } + } + if found { + return + } + return nil, false +} + +// Put inserts node into the tree. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (t *Tree) Put(key interface{}, value interface{}) { + var put func(*Node, **Node) bool + put = func(p *Node, qp **Node) bool { + q := *qp + if q == nil { + t.size++ + *qp = &Node{Key: key, Value: value, p: p} + return true + } + + c := t.Comparator(key, q.Key) + if c == 0 { + q.Key = key + q.Value = value + return false + } + + if c < 0 { + c = -1 + } else { + c = 1 + } + a := (c + 1) / 2 + var fix bool + fix = put(q, &q.c[a]) + if fix { + return putFix(int8(c), qp) + } + return false + } + + put(nil, &t.Root) +} + +// Remove remove the node from the tree by key. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (t *Tree) Remove(key interface{}) { + var remove func(**Node) bool + remove = func(qp **Node) bool { + q := *qp + if q == nil { + return false + } + + c := t.Comparator(key, q.Key) + if c == 0 { + t.size-- + if q.c[1] == nil { + if q.c[0] != nil { + q.c[0].p = q.p + } + *qp = q.c[0] + return true + } + fix := removemin(&q.c[1], &q.Key, &q.Value) + if fix { + return removeFix(-1, qp) + } + return false + } + + if c < 0 { + c = -1 + } else { + c = 1 + } + a := (c + 1) / 2 + fix := remove(&q.c[a]) + if fix { + return removeFix(int8(-c), qp) + } + return false + } + + remove(&t.Root) +} + +func removemin(qp **Node, minKey *interface{}, minVal *interface{}) bool { + q := *qp + if q.c[0] == nil { + *minKey = q.Key + *minVal = q.Value + if q.c[1] != nil { + q.c[1].p = q.p + } + *qp = q.c[1] + return true + } + fix := removemin(&q.c[0], minKey, minVal) + if fix { + return removeFix(1, qp) + } + return false +} + +func putFix(c int8, t **Node) bool { + s := *t + if s.b == 0 { + s.b = c + return true + } + + if s.b == -c { + s.b = 0 + return false + } + + if s.c[(c+1)/2].b == c { + s = singlerot(c, s) + } else { + s = doublerot(c, s) + } + *t = s + return false +} + +func removeFix(c int8, t **Node) bool { + s := *t + if s.b == 0 { + s.b = c + return false + } + + if s.b == -c { + s.b = 0 + return true + } + + a := (c + 1) / 2 + if s.c[a].b == 0 { + s = rotate(c, s) + s.b = -c + *t = s + return false + } + + if s.c[a].b == c { + s = singlerot(c, s) + } else { + s = doublerot(c, s) + } + *t = s + return true +} + +func singlerot(c int8, s *Node) *Node { + dbgLog.Printf("singlerot: enter %p:%v %d\n", s, s, c) + s.b = 0 + s = rotate(c, s) + s.b = 0 + dbgLog.Printf("singlerot: exit %p:%v\n", s, s) + return s +} + +func doublerot(c int8, s *Node) *Node { + dbgLog.Printf("doublerot: enter %p:%v %d\n", s, s, c) + a := (c + 1) / 2 + r := s.c[a] + s.c[a] = rotate(-c, s.c[a]) + p := rotate(c, s) + if r.p != p || s.p != p { + panic("doublerot: bad parents") + } + + switch { + default: + s.b = 0 + r.b = 0 + case p.b == c: + s.b = -c + r.b = 0 + case p.b == -c: + s.b = 0 + r.b = c + } + + p.b = 0 + dbgLog.Printf("doublerot: exit %p:%v\n", s, s) + return p +} + +func rotate(c int8, s *Node) *Node { + dbgLog.Printf("rotate: enter %p:%v %d\n", s, s, c) + a := (c + 1) / 2 + r := s.c[a] + s.c[a] = r.c[a^1] + if s.c[a] != nil { + s.c[a].p = s + } + r.c[a^1] = s + r.p = s.p + s.p = r + dbgLog.Printf("rotate: exit %p:%v\n", r, r) + return r +} + +// Keys returns all keys in-order +func (t *Tree) Keys() []interface{} { + keys := make([]interface{}, t.size) + it := t.Iterator() + for i := 0; it.Next(); i++ { + keys[i] = it.Key() + } + return keys +} + +// Values returns all values in-order based on the key. +func (t *Tree) Values() []interface{} { + values := make([]interface{}, t.size) + it := t.Iterator() + for i := 0; it.Next(); i++ { + values[i] = it.Value() + } + return values +} + +// Left returns the minimum element of the AVL tree +// or nil if the tree is empty. +func (t *Tree) Left() *Node { + return t.bottom(0) +} + +// Right returns the maximum element of the AVL tree +// or nil if the tree is empty. +func (t *Tree) Right() *Node { + return t.bottom(1) +} + +func (t *Tree) bottom(d int) *Node { + n := t.Root + if n == nil { + return nil + } + + for c := n.c[d]; c != nil; c = n.c[d] { + n = c + } + return n +} + +// Prev returns the previous element in an inorder +// walk of the AVL tree. +func (n *Node) Prev() *Node { + return n.walk1(0) +} + +// Next returns the next element in an inorder +// walk of the AVL tree. +func (n *Node) Next() *Node { + return n.walk1(1) +} + +func (n *Node) walk1(a int) *Node { + if n == nil { + return nil + } + + if n.c[a] != nil { + n = n.c[a] + for n.c[a^1] != nil { + n = n.c[a^1] + } + return n + } + + p := n.p + for p != nil && p.c[a] == n { + n = p + p = p.p + } + return p +} diff --git a/trees/avl/avl_test.go b/trees/avl/avl_test.go new file mode 100644 index 00000000..94db9e4e --- /dev/null +++ b/trees/avl/avl_test.go @@ -0,0 +1,711 @@ +// Copyright (c) 2017, Benjamin Scher Purcell. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package avl + +import ( + "fmt" + "testing" +) + +func TestAVLPut(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(5, "e") + tree.Put(6, "f") + tree.Put(7, "g") + tree.Put(3, "c") + tree.Put(4, "d") + tree.Put(1, "x") + tree.Put(2, "b") + tree.Put(1, "a") //overwrite + + if actualValue := tree.Size(); actualValue != 7 { + t.Errorf("Got %v expected %v", actualValue, 7) + } + if actualValue, expectedValue := fmt.Sprintf("%d%d%d%d%d%d%d", tree.Keys()...), "1234567"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s", tree.Values()...), "abcdefg"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + tests1 := [][]interface{}{ + {1, "a", true}, + {2, "b", true}, + {3, "c", true}, + {4, "d", true}, + {5, "e", true}, + {6, "f", true}, + {7, "g", true}, + {8, nil, false}, + } + + for _, test := range tests1 { + // retrievals + actualValue, actualFound := tree.Get(test[0]) + if actualValue != test[1] || actualFound != test[2] { + t.Errorf("Got %v expected %v", actualValue, test[1]) + } + } +} + +func TestAVLRemove(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(5, "e") + tree.Put(6, "f") + tree.Put(7, "g") + tree.Put(3, "c") + tree.Put(4, "d") + tree.Put(1, "x") + tree.Put(2, "b") + tree.Put(1, "a") //overwrite + + tree.Remove(5) + tree.Remove(6) + tree.Remove(7) + tree.Remove(8) + tree.Remove(5) + + if actualValue, expectedValue := fmt.Sprintf("%d%d%d%d", tree.Keys()...), "1234"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", tree.Values()...), "abcd"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", tree.Values()...), "abcd"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := tree.Size(); actualValue != 4 { + t.Errorf("Got %v expected %v", actualValue, 7) + } + + tests2 := [][]interface{}{ + {1, "a", true}, + {2, "b", true}, + {3, "c", true}, + {4, "d", true}, + {5, nil, false}, + {6, nil, false}, + {7, nil, false}, + {8, nil, false}, + } + + for _, test := range tests2 { + actualValue, actualFound := tree.Get(test[0]) + if actualValue != test[1] || actualFound != test[2] { + t.Errorf("Got %v expected %v", actualValue, test[1]) + } + } + + tree.Remove(1) + tree.Remove(4) + tree.Remove(2) + tree.Remove(3) + tree.Remove(2) + tree.Remove(2) + + if actualValue, expectedValue := fmt.Sprintf("%s", tree.Keys()), "[]"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := fmt.Sprintf("%s", tree.Values()), "[]"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if empty, size := tree.Empty(), tree.Size(); empty != true || size != -0 { + t.Errorf("Got %v expected %v", empty, true) + } + +} + +func TestAVLLeftAndRight(t *testing.T) { + tree := NewWithIntComparator() + + if actualValue := tree.Left(); actualValue != nil { + t.Errorf("Got %v expected %v", actualValue, nil) + } + if actualValue := tree.Right(); actualValue != nil { + t.Errorf("Got %v expected %v", actualValue, nil) + } + + tree.Put(1, "a") + tree.Put(5, "e") + tree.Put(6, "f") + tree.Put(7, "g") + tree.Put(3, "c") + tree.Put(4, "d") + tree.Put(1, "x") // overwrite + tree.Put(2, "b") + + if actualValue, expectedValue := fmt.Sprintf("%d", tree.Left().Key), "1"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := fmt.Sprintf("%s", tree.Left().Value), "x"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + if actualValue, expectedValue := fmt.Sprintf("%d", tree.Right().Key), "7"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := fmt.Sprintf("%s", tree.Right().Value), "g"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + +func TestAVLCeilingAndFloor(t *testing.T) { + tree := NewWithIntComparator() + + if node, found := tree.Floor(0); node != nil || found { + t.Errorf("Got %v expected %v", node, "") + } + if node, found := tree.Ceiling(0); node != nil || found { + t.Errorf("Got %v expected %v", node, "") + } + + tree.Put(5, "e") + tree.Put(6, "f") + tree.Put(7, "g") + tree.Put(3, "c") + tree.Put(4, "d") + tree.Put(1, "x") + tree.Put(2, "b") + + if node, found := tree.Floor(4); node.Key != 4 || !found { + t.Errorf("Got %v expected %v", node.Key, 4) + } + if node, found := tree.Floor(0); node != nil || found { + t.Errorf("Got %v expected %v", node, "") + } + + if node, found := tree.Ceiling(4); node.Key != 4 || !found { + t.Errorf("Got %v expected %v", node.Key, 4) + } + if node, found := tree.Ceiling(8); node != nil || found { + t.Errorf("Got %v expected %v", node, "") + } +} + +func TestAVLIteratorNextOnEmpty(t *testing.T) { + tree := NewWithIntComparator() + it := tree.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty tree") + } +} + +func TestAVLIteratorPrevOnEmpty(t *testing.T) { + tree := NewWithIntComparator() + it := tree.Iterator() + for it.Prev() { + t.Errorf("Shouldn't iterate on empty tree") + } +} + +func TestAVLIterator1Next(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(5, "e") + tree.Put(6, "f") + tree.Put(7, "g") + tree.Put(3, "c") + tree.Put(4, "d") + tree.Put(1, "x") + tree.Put(2, "b") + tree.Put(1, "a") //overwrite + // │ ┌── 7 + // └── 6 + // │ ┌── 5 + // └── 4 + // │ ┌── 3 + // └── 2 + // └── 1 + it := tree.Iterator() + count := 0 + for it.Next() { + count++ + key := it.Key() + switch key { + case count: + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + +func TestAVLIterator1Prev(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(5, "e") + tree.Put(6, "f") + tree.Put(7, "g") + tree.Put(3, "c") + tree.Put(4, "d") + tree.Put(1, "x") + tree.Put(2, "b") + tree.Put(1, "a") //overwrite + // │ ┌── 7 + // └── 6 + // │ ┌── 5 + // └── 4 + // │ ┌── 3 + // └── 2 + // └── 1 + it := tree.Iterator() + for it.Next() { + } + countDown := tree.size + for it.Prev() { + key := it.Key() + switch key { + case countDown: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + countDown-- + } + if actualValue, expectedValue := countDown, 0; actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + +func TestAVLIterator2Next(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it := tree.Iterator() + count := 0 + for it.Next() { + count++ + key := it.Key() + switch key { + case count: + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + +func TestAVLIterator2Prev(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it := tree.Iterator() + for it.Next() { + } + countDown := tree.size + for it.Prev() { + key := it.Key() + switch key { + case countDown: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + countDown-- + } + if actualValue, expectedValue := countDown, 0; actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + +func TestAVLIterator3Next(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(1, "a") + it := tree.Iterator() + count := 0 + for it.Next() { + count++ + key := it.Key() + switch key { + case count: + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + +func TestAVLIterator3Prev(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(1, "a") + it := tree.Iterator() + for it.Next() { + } + countDown := tree.size + for it.Prev() { + key := it.Key() + switch key { + case countDown: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + countDown-- + } + if actualValue, expectedValue := countDown, 0; actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + +func TestAVLIterator4Next(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(13, 5) + tree.Put(8, 3) + tree.Put(17, 7) + tree.Put(1, 1) + tree.Put(11, 4) + tree.Put(15, 6) + tree.Put(25, 9) + tree.Put(6, 2) + tree.Put(22, 8) + tree.Put(27, 10) + // │ ┌── 27 + // │ ┌── 25 + // │ │ └── 22 + // │ ┌── 17 + // │ │ └── 15 + // └── 13 + // │ ┌── 11 + // └── 8 + // │ ┌── 6 + // └── 1 + it := tree.Iterator() + count := 0 + for it.Next() { + count++ + value := it.Value() + switch value { + case count: + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + +func TestAVLIterator4Prev(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(13, 5) + tree.Put(8, 3) + tree.Put(17, 7) + tree.Put(1, 1) + tree.Put(11, 4) + tree.Put(15, 6) + tree.Put(25, 9) + tree.Put(6, 2) + tree.Put(22, 8) + tree.Put(27, 10) + // │ ┌── 27 + // │ ┌── 25 + // │ │ └── 22 + // │ ┌── 17 + // │ │ └── 15 + // └── 13 + // │ ┌── 11 + // └── 8 + // │ ┌── 6 + // └── 1 + it := tree.Iterator() + count := tree.Size() + for it.Next() { + } + for it.Prev() { + value := it.Value() + switch value { + case count: + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + count-- + } + if actualValue, expectedValue := count, 0; actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + +func TestAVLIteratorBegin(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it := tree.Iterator() + + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + it.Begin() + + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + for it.Next() { + } + + it.Begin() + + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + it.Next() + if key, value := it.Key(), it.Value(); key != 1 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") + } +} + +func TestAVLIteratorEnd(t *testing.T) { + tree := NewWithIntComparator() + it := tree.Iterator() + + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + it.End() + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it.End() + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + + it.Prev() + if key, value := it.Key(), it.Value(); key != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") + } +} + +func TestAVLIteratorFirst(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it := tree.Iterator() + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if key, value := it.Key(), it.Value(); key != 1 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") + } +} + +func TestAVLIteratorLast(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it := tree.Iterator() + if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if key, value := it.Key(), it.Value(); key != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") + } +} + +func benchmarkGet(b *testing.B, tree *Tree, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Get(n) + } + } +} + +func benchmarkPut(b *testing.B, tree *Tree, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + } +} + +func benchmarkRemove(b *testing.B, tree *Tree, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Remove(n) + } + } +} + +func BenchmarkAVLGet100(b *testing.B) { + b.StopTimer() + size := 100 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, tree, size) +} + +func BenchmarkAVLGet1000(b *testing.B) { + b.StopTimer() + size := 1000 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, tree, size) +} + +func BenchmarkAVLGet10000(b *testing.B) { + b.StopTimer() + size := 10000 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, tree, size) +} + +func BenchmarkAVLGet100000(b *testing.B) { + b.StopTimer() + size := 100000 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, tree, size) +} + +func BenchmarkAVLPut100(b *testing.B) { + b.StopTimer() + size := 100 + tree := NewWithIntComparator() + b.StartTimer() + benchmarkPut(b, tree, size) +} + +func BenchmarkAVLPut1000(b *testing.B) { + b.StopTimer() + size := 1000 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, tree, size) +} + +func BenchmarkAVLPut10000(b *testing.B) { + b.StopTimer() + size := 10000 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, tree, size) +} + +func BenchmarkAVLPut100000(b *testing.B) { + b.StopTimer() + size := 100000 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, tree, size) +} + +func BenchmarkAVLRemove100(b *testing.B) { + b.StopTimer() + size := 100 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, tree, size) +} + +func BenchmarkAVLRemove1000(b *testing.B) { + b.StopTimer() + size := 1000 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, tree, size) +} + +func BenchmarkAVLRemove10000(b *testing.B) { + b.StopTimer() + size := 10000 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, tree, size) +} + +func BenchmarkAVLRemove100000(b *testing.B) { + b.StopTimer() + size := 100000 + tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, tree, size) +} diff --git a/trees/avl/iterator.go b/trees/avl/iterator.go new file mode 100644 index 00000000..b2df5c66 --- /dev/null +++ b/trees/avl/iterator.go @@ -0,0 +1,111 @@ +// Copyright (c) 2017, Benjamin Scher Purcell. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package avl + +import "github.com/emirpasic/gods/containers" + +func assertIteratorImplementation() { + var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) +} + +// Iterator holding the iterator's state +type Iterator struct { + tree *Tree + node *Node + position position +} + +type position byte + +const ( + begin, between, end position = 0, 1, 2 +) + +// Iterator returns a stateful iterator whose elements are key/value pairs. +func (tree *Tree) Iterator() Iterator { + return Iterator{tree: tree, node: nil, position: begin} +} + +// 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. +// Modifies the state of the iterator. +func (iter *Iterator) Next() bool { + switch iter.position { + case begin: + iter.position = between + iter.node = iter.tree.Left() + case between: + iter.node = iter.node.Next() + } + + if iter.node == nil { + iter.position = end + return false + } + return true +} + +// Prev moves the iterator to the next element and returns true if there was a previous element in the container. +// If Prev() returns true, then next element's key and value can be retrieved by Key() and Value(). +// If Prev() 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 (iter *Iterator) Prev() bool { + switch iter.position { + case end: + iter.position = between + iter.node = iter.tree.Right() + case between: + iter.node = iter.node.Prev() + } + + if iter.node == nil { + iter.position = begin + return false + } + return true +} + +// Value returns the current element's value. +// Does not modify the state of the iterator. +func (iter *Iterator) Value() interface{} { + return iter.node.Value +} + +// Key returns the current element's key. +// Does not modify the state of the iterator. +func (iter *Iterator) Key() interface{} { + return iter.node.Key +} + +// Begin resets the iterator to its initial state (one-before-first) +// Call Next() to fetch the first element if any. +func (iter *Iterator) Begin() { + iter.node = nil + iter.position = begin +} + +// End moves the iterator past the last element (one-past-the-end). +// Call Prev() to fetch the last element if any. +func (iter *Iterator) End() { + iter.node = nil + iter.position = 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 key and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator +func (iter *Iterator) First() bool { + iter.Begin() + return iter.Next() +} + +// 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 key and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator. +func (iter *Iterator) Last() bool { + iter.End() + return iter.Prev() +} From 64f44f66bce7327cad54e4700926a77b4855199e Mon Sep 17 00:00:00 2001 From: Benjamin Scher Purcell Date: Sun, 26 Feb 2017 13:12:51 -0600 Subject: [PATCH 120/320] more tests, revise existing tests --- trees/{avl => avltree}/LICENSE | 0 trees/{avl/avl.go => avltree/avltree.go} | 70 ++++-- .../avl_test.go => avltree/avltree_test.go} | 184 +++++++++++++--- trees/{avl => avltree}/iterator.go | 2 +- trees/redblacktree/redblacktree_test.go | 200 ++++++++++++++---- 5 files changed, 367 insertions(+), 89 deletions(-) rename trees/{avl => avltree}/LICENSE (100%) rename trees/{avl/avl.go => avltree/avltree.go} (84%) rename trees/{avl/avl_test.go => avltree/avltree_test.go} (82%) rename trees/{avl => avltree}/iterator.go (99%) diff --git a/trees/avl/LICENSE b/trees/avltree/LICENSE similarity index 100% rename from trees/avl/LICENSE rename to trees/avltree/LICENSE diff --git a/trees/avl/avl.go b/trees/avltree/avltree.go similarity index 84% rename from trees/avl/avl.go rename to trees/avltree/avltree.go index 09b51814..226efccd 100644 --- a/trees/avl/avl.go +++ b/trees/avltree/avltree.go @@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package avl implements an AVL balanced binary tree. +// Package avltree implements an AVL balanced binary tree. // // Structure is not thread safe. -// -package avl +package avltree import ( + "fmt" "io/ioutil" "log" @@ -20,7 +20,7 @@ func assertTreeImplementation() { var _ trees.Tree = new(Tree) } -var dbgLog = log.New(ioutil.Discard, "avl: ", log.LstdFlags) +var dbgLog = log.New(ioutil.Discard, "avltree: ", log.LstdFlags) // Tree holds elements of the AVL tree. type Tree struct { @@ -29,8 +29,7 @@ type Tree struct { Comparator utils.Comparator } -// A Node holds an Ordered element of the AVL tree in -// the Val field. +// Node is a single element within the tree type Node struct { Key interface{} Value interface{} @@ -70,20 +69,18 @@ func (t *Tree) Clear() { t.size = 0 } -// Get looks up val and returns the matching element if -// it is found. -// -// Val's Less implementation must be able to handle -// comparisons to elements stored in this tree. +// Get searches the node in the tree by key and returns its value or nil if key is not found in tree. +// Second return parameter is true if key was found, otherwise false. +// Key should adhere to the comparator's type assertion, otherwise method panics. func (t *Tree) Get(key interface{}) (value interface{}, found bool) { n := t.Root for n != nil { cmp := t.Comparator(key, n.Key) switch { - case cmp < 0: - n = n.c[0] case cmp == 0: return n.Value, true + case cmp < 0: + n = n.c[0] case cmp > 0: n = n.c[1] } @@ -205,7 +202,7 @@ func (t *Tree) Remove(key interface{}) { *qp = q.c[0] return true } - fix := removemin(&q.c[1], &q.Key, &q.Value) + fix := removeMin(&q.c[1], &q.Key, &q.Value) if fix { return removeFix(-1, qp) } @@ -228,7 +225,7 @@ func (t *Tree) Remove(key interface{}) { remove(&t.Root) } -func removemin(qp **Node, minKey *interface{}, minVal *interface{}) bool { +func removeMin(qp **Node, minKey *interface{}, minVal *interface{}) bool { q := *qp if q.c[0] == nil { *minKey = q.Key @@ -239,7 +236,7 @@ func removemin(qp **Node, minKey *interface{}, minVal *interface{}) bool { *qp = q.c[1] return true } - fix := removemin(&q.c[0], minKey, minVal) + fix := removeMin(&q.c[0], minKey, minVal) if fix { return removeFix(1, qp) } @@ -423,3 +420,44 @@ func (n *Node) walk1(a int) *Node { } return p } + +// String returns a string representation of container +func (t *Tree) String() string { + str := "AVLTree\n" + if !t.Empty() { + output(t.Root, "", true, &str) + } + return str +} + +func (n *Node) String() string { + return fmt.Sprintf("%v", n.Key) +} + +func output(node *Node, prefix string, isTail bool, str *string) { + if node.c[0] != nil { + newPrefix := prefix + if isTail { + newPrefix += "│ " + } else { + newPrefix += " " + } + output(node.c[0], newPrefix, false, str) + } + *str += prefix + if isTail { + *str += "└── " + } else { + *str += "┌── " + } + *str += node.String() + "\n" + if node.c[1] != nil { + newPrefix := prefix + if isTail { + newPrefix += " " + } else { + newPrefix += "│ " + } + output(node.c[1], newPrefix, true, str) + } +} diff --git a/trees/avl/avl_test.go b/trees/avltree/avltree_test.go similarity index 82% rename from trees/avl/avl_test.go rename to trees/avltree/avltree_test.go index 94db9e4e..f79b7393 100644 --- a/trees/avl/avl_test.go +++ b/trees/avltree/avltree_test.go @@ -2,13 +2,24 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package avl +package avltree import ( "fmt" + "math/rand" + "os" "testing" + "time" ) +var rng *rand.Rand + +func TestMain(m *testing.M) { + seed := time.Now().UTC().UnixNano() + rng = rand.New(rand.NewSource(seed)) + os.Exit(m.Run()) +} + func TestAVLPut(t *testing.T) { tree := NewWithIntComparator() tree.Put(5, "e") @@ -557,7 +568,15 @@ func TestAVLIteratorLast(t *testing.T) { } } -func benchmarkGet(b *testing.B, tree *Tree, size int) { +func newRandomIntTree(size, randMax int) *Tree { + tree := NewWithIntComparator() + for i := 0; i < size; i++ { + tree.Put(rng.Intn(randMax), nil) + } + return tree +} + +func (tree *Tree) benchmarkGet(b *testing.B, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { tree.Get(n) @@ -565,19 +584,53 @@ func benchmarkGet(b *testing.B, tree *Tree, size int) { } } -func benchmarkPut(b *testing.B, tree *Tree, size int) { +func (tree *Tree) benchmarkGetRandom(b *testing.B, size, randMax int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Get(rng.Intn(randMax)) + } + } +} + +func (tree *Tree) benchmarkPut(b *testing.B, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Put(n, nil) + } + tree.Empty() + } +} + +func (tree *Tree) benchmarkPutRandom(b *testing.B, size, randMax int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(rng.Intn(randMax), nil) } + tree.Empty() } } -func benchmarkRemove(b *testing.B, tree *Tree, size int) { +func (tree *Tree) benchmarkPutAndRemove(b *testing.B, size int) { for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Put(n, nil) + } for n := 0; n < size; n++ { tree.Remove(n) } + tree.Empty() + } +} + +func (tree *Tree) benchmarkPutAndRemoveRandom(b *testing.B, size int, randMax int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Put(rng.Intn(randMax), nil) + } + for n := 0; n < size; n++ { + tree.Remove(rng.Intn(randMax)) + } + tree.Empty() } } @@ -586,10 +639,10 @@ func BenchmarkAVLGet100(b *testing.B) { size := 100 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkGet(b, tree, size) + tree.benchmarkGet(b, size) } func BenchmarkAVLGet1000(b *testing.B) { @@ -597,10 +650,10 @@ func BenchmarkAVLGet1000(b *testing.B) { size := 1000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkGet(b, tree, size) + tree.benchmarkGet(b, size) } func BenchmarkAVLGet10000(b *testing.B) { @@ -608,10 +661,10 @@ func BenchmarkAVLGet10000(b *testing.B) { size := 10000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkGet(b, tree, size) + tree.benchmarkGet(b, size) } func BenchmarkAVLGet100000(b *testing.B) { @@ -619,18 +672,53 @@ func BenchmarkAVLGet100000(b *testing.B) { size := 100000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkGet(b, tree, size) + tree.benchmarkGet(b, size) +} + +func BenchmarkAVLGetRandom100(b *testing.B) { + b.StopTimer() + size := 100 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkGetRandom(b, size, size*5) +} + +func BenchmarkAVLGetRandom1000(b *testing.B) { + b.StopTimer() + size := 1000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkGetRandom(b, size, size*5) +} + +func BenchmarkAVLGetRandom10000(b *testing.B) { + b.StopTimer() + size := 10000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkGetRandom(b, size, size*5) +} + +func BenchmarkAVLGetRandom100000(b *testing.B) { + b.StopTimer() + size := 100000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkGetRandom(b, size, size*5) } func BenchmarkAVLPut100(b *testing.B) { b.StopTimer() size := 100 tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, nil) + } b.StartTimer() - benchmarkPut(b, tree, size) + tree.benchmarkPut(b, size) } func BenchmarkAVLPut1000(b *testing.B) { @@ -638,10 +726,10 @@ func BenchmarkAVLPut1000(b *testing.B) { size := 1000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkPut(b, tree, size) + tree.benchmarkPut(b, size) } func BenchmarkAVLPut10000(b *testing.B) { @@ -649,10 +737,10 @@ func BenchmarkAVLPut10000(b *testing.B) { size := 10000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkPut(b, tree, size) + tree.benchmarkPut(b, size) } func BenchmarkAVLPut100000(b *testing.B) { @@ -660,52 +748,84 @@ func BenchmarkAVLPut100000(b *testing.B) { size := 100000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkPut(b, tree, size) + tree.benchmarkPut(b, size) +} + +func BenchmarkAVLPutRandom100(b *testing.B) { + b.StopTimer() + size := 100 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkPutRandom(b, size, size*5) +} + +func BenchmarkAVLPutRandom1000(b *testing.B) { + b.StopTimer() + size := 1000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkPutRandom(b, size, size*5) +} + +func BenchmarkAVLPutRandom10000(b *testing.B) { + b.StopTimer() + size := 10000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkPutRandom(b, size, size*5) +} + +func BenchmarkAVLPutRandom100000(b *testing.B) { + b.StopTimer() + size := 100000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkPutRandom(b, size, size*5) } -func BenchmarkAVLRemove100(b *testing.B) { +func BenchmarkAVLPutAndRemove100(b *testing.B) { b.StopTimer() size := 100 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkRemove(b, tree, size) + tree.benchmarkPutAndRemove(b, size) } -func BenchmarkAVLRemove1000(b *testing.B) { +func BenchmarkAVLPutAndRemove1000(b *testing.B) { b.StopTimer() size := 1000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkRemove(b, tree, size) + tree.benchmarkPutAndRemove(b, size) } -func BenchmarkAVLRemove10000(b *testing.B) { +func BenchmarkAVLPutAndRemove10000(b *testing.B) { b.StopTimer() size := 10000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkRemove(b, tree, size) + tree.benchmarkPutAndRemove(b, size) } -func BenchmarkAVLRemove100000(b *testing.B) { +func BenchmarkAVLPutAndRemove100000(b *testing.B) { b.StopTimer() size := 100000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkRemove(b, tree, size) + tree.benchmarkPutAndRemove(b, size) } diff --git a/trees/avl/iterator.go b/trees/avltree/iterator.go similarity index 99% rename from trees/avl/iterator.go rename to trees/avltree/iterator.go index b2df5c66..a3d930c0 100644 --- a/trees/avl/iterator.go +++ b/trees/avltree/iterator.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package avl +package avltree import "github.com/emirpasic/gods/containers" diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 714defcf..bca5e7e4 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -6,9 +6,20 @@ package redblacktree import ( "fmt" + "math/rand" + "os" "testing" + "time" ) +var rng *rand.Rand + +func TestMain(m *testing.M) { + seed := time.Now().UTC().UnixNano() + rng = rand.New(rand.NewSource(seed)) + os.Exit(m.Run()) +} + func TestRedBlackTreePut(t *testing.T) { tree := NewWithIntComparator() tree.Put(5, "e") @@ -19,7 +30,7 @@ func TestRedBlackTreePut(t *testing.T) { tree.Put(1, "x") tree.Put(2, "b") tree.Put(1, "a") //overwrite - + t.Log(tree) if actualValue := tree.Size(); actualValue != 7 { t.Errorf("Got %v expected %v", actualValue, 7) } @@ -557,7 +568,15 @@ func TestRedBlackTreeIteratorLast(t *testing.T) { } } -func benchmarkGet(b *testing.B, tree *Tree, size int) { +func newRandomIntTree(size, randMax int) *Tree { + tree := NewWithIntComparator() + for i := 0; i < size; i++ { + tree.Put(rng.Intn(randMax), nil) + } + return tree +} + +func (tree *Tree) benchmarkGet(b *testing.B, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { tree.Get(n) @@ -565,147 +584,248 @@ func benchmarkGet(b *testing.B, tree *Tree, size int) { } } -func benchmarkPut(b *testing.B, tree *Tree, size int) { +func (tree *Tree) benchmarkGetRandom(b *testing.B, size, randMax int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Get(rng.Intn(randMax)) + } + } +} + +func (tree *Tree) benchmarkPut(b *testing.B, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Put(n, nil) + } + tree.Empty() + } +} + +func (tree *Tree) benchmarkPutRandom(b *testing.B, size, randMax int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(rng.Intn(randMax), nil) } + tree.Empty() } } -func benchmarkRemove(b *testing.B, tree *Tree, size int) { +func (tree *Tree) benchmarkPutAndRemove(b *testing.B, size int) { for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Put(n, nil) + } for n := 0; n < size; n++ { tree.Remove(n) } + tree.Empty() + } +} + +func (tree *Tree) benchmarkPutAndRemoveRandom(b *testing.B, size int, randMax int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Put(rng.Intn(randMax), nil) + } + for n := 0; n < size; n++ { + tree.Remove(rng.Intn(randMax)) + } + tree.Empty() } } -func BenchmarkRedBlackTreeGet100(b *testing.B) { +func BenchmarkAVLGet100(b *testing.B) { b.StopTimer() size := 100 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkGet(b, tree, size) + tree.benchmarkGet(b, size) } -func BenchmarkRedBlackTreeGet1000(b *testing.B) { +func BenchmarkAVLGet1000(b *testing.B) { b.StopTimer() size := 1000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkGet(b, tree, size) + tree.benchmarkGet(b, size) } -func BenchmarkRedBlackTreeGet10000(b *testing.B) { +func BenchmarkAVLGet10000(b *testing.B) { b.StopTimer() size := 10000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkGet(b, tree, size) + tree.benchmarkGet(b, size) } -func BenchmarkRedBlackTreeGet100000(b *testing.B) { +func BenchmarkAVLGet100000(b *testing.B) { b.StopTimer() size := 100000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkGet(b, tree, size) + tree.benchmarkGet(b, size) +} + +func BenchmarkAVLGetRandom100(b *testing.B) { + b.StopTimer() + size := 100 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkGetRandom(b, size, size*5) +} + +func BenchmarkAVLGetRandom1000(b *testing.B) { + b.StopTimer() + size := 1000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkGetRandom(b, size, size*5) +} + +func BenchmarkAVLGetRandom10000(b *testing.B) { + b.StopTimer() + size := 10000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkGetRandom(b, size, size*5) } -func BenchmarkRedBlackTreePut100(b *testing.B) { +func BenchmarkAVLGetRandom100000(b *testing.B) { + b.StopTimer() + size := 100000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkGetRandom(b, size, size*5) +} + +func BenchmarkAVLPut100(b *testing.B) { b.StopTimer() size := 100 tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, nil) + } b.StartTimer() - benchmarkPut(b, tree, size) + tree.benchmarkPut(b, size) } -func BenchmarkRedBlackTreePut1000(b *testing.B) { +func BenchmarkAVLPut1000(b *testing.B) { b.StopTimer() size := 1000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkPut(b, tree, size) + tree.benchmarkPut(b, size) } -func BenchmarkRedBlackTreePut10000(b *testing.B) { +func BenchmarkAVLPut10000(b *testing.B) { b.StopTimer() size := 10000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkPut(b, tree, size) + tree.benchmarkPut(b, size) } -func BenchmarkRedBlackTreePut100000(b *testing.B) { +func BenchmarkAVLPut100000(b *testing.B) { b.StopTimer() size := 100000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkPut(b, tree, size) + tree.benchmarkPut(b, size) +} + +func BenchmarkAVLPutRandom100(b *testing.B) { + b.StopTimer() + size := 100 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkPutRandom(b, size, size*5) +} + +func BenchmarkAVLPutRandom1000(b *testing.B) { + b.StopTimer() + size := 1000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkPutRandom(b, size, size*5) +} + +func BenchmarkAVLPutRandom10000(b *testing.B) { + b.StopTimer() + size := 10000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkPutRandom(b, size, size*5) +} + +func BenchmarkAVLPutRandom100000(b *testing.B) { + b.StopTimer() + size := 100000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkPutRandom(b, size, size*5) } -func BenchmarkRedBlackTreeRemove100(b *testing.B) { +func BenchmarkAVLPutAndRemove100(b *testing.B) { b.StopTimer() size := 100 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkRemove(b, tree, size) + tree.benchmarkPutAndRemove(b, size) } -func BenchmarkRedBlackTreeRemove1000(b *testing.B) { +func BenchmarkAVLPutAndRemove1000(b *testing.B) { b.StopTimer() size := 1000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkRemove(b, tree, size) + tree.benchmarkPutAndRemove(b, size) } -func BenchmarkRedBlackTreeRemove10000(b *testing.B) { +func BenchmarkAVLPutAndRemove10000(b *testing.B) { b.StopTimer() size := 10000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkRemove(b, tree, size) + tree.benchmarkPutAndRemove(b, size) } -func BenchmarkRedBlackTreeRemove100000(b *testing.B) { +func BenchmarkAVLPutAndRemove100000(b *testing.B) { b.StopTimer() size := 100000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkRemove(b, tree, size) + tree.benchmarkPutAndRemove(b, size) } From d43b189795939df57917809744f67eb607c51e71 Mon Sep 17 00:00:00 2001 From: Benjamin Scher Purcell Date: Sun, 26 Feb 2017 13:37:01 -0600 Subject: [PATCH 121/320] add random put and remove --- trees/avltree/avltree_test.go | 64 +++++++++++---- trees/redblacktree/redblacktree_test.go | 104 ++++++++++++++++-------- 2 files changed, 116 insertions(+), 52 deletions(-) diff --git a/trees/avltree/avltree_test.go b/trees/avltree/avltree_test.go index f79b7393..a1a3e4b7 100644 --- a/trees/avltree/avltree_test.go +++ b/trees/avltree/avltree_test.go @@ -681,33 +681,33 @@ func BenchmarkAVLGet100000(b *testing.B) { func BenchmarkAVLGetRandom100(b *testing.B) { b.StopTimer() size := 100 - tree := newRandomIntTree(size, size*5) + tree := newRandomIntTree(size, size*3) b.StartTimer() - tree.benchmarkGetRandom(b, size, size*5) + tree.benchmarkGetRandom(b, size, size*3) } func BenchmarkAVLGetRandom1000(b *testing.B) { b.StopTimer() size := 1000 - tree := newRandomIntTree(size, size*5) + tree := newRandomIntTree(size, size*3) b.StartTimer() - tree.benchmarkGetRandom(b, size, size*5) + tree.benchmarkGetRandom(b, size, size*3) } func BenchmarkAVLGetRandom10000(b *testing.B) { b.StopTimer() size := 10000 - tree := newRandomIntTree(size, size*5) + tree := newRandomIntTree(size, size*3) b.StartTimer() - tree.benchmarkGetRandom(b, size, size*5) + tree.benchmarkGetRandom(b, size, size*3) } func BenchmarkAVLGetRandom100000(b *testing.B) { b.StopTimer() size := 100000 - tree := newRandomIntTree(size, size*5) + tree := newRandomIntTree(size, size*3) b.StartTimer() - tree.benchmarkGetRandom(b, size, size*5) + tree.benchmarkGetRandom(b, size, size*3) } func BenchmarkAVLPut100(b *testing.B) { @@ -757,33 +757,33 @@ func BenchmarkAVLPut100000(b *testing.B) { func BenchmarkAVLPutRandom100(b *testing.B) { b.StopTimer() size := 100 - tree := newRandomIntTree(size, size*5) + tree := newRandomIntTree(size, size*3) b.StartTimer() - tree.benchmarkPutRandom(b, size, size*5) + tree.benchmarkPutRandom(b, size, size*3) } func BenchmarkAVLPutRandom1000(b *testing.B) { b.StopTimer() size := 1000 - tree := newRandomIntTree(size, size*5) + tree := newRandomIntTree(size, size*3) b.StartTimer() - tree.benchmarkPutRandom(b, size, size*5) + tree.benchmarkPutRandom(b, size, size*3) } func BenchmarkAVLPutRandom10000(b *testing.B) { b.StopTimer() size := 10000 - tree := newRandomIntTree(size, size*5) + tree := newRandomIntTree(size, size*3) b.StartTimer() - tree.benchmarkPutRandom(b, size, size*5) + tree.benchmarkPutRandom(b, size, size*3) } func BenchmarkAVLPutRandom100000(b *testing.B) { b.StopTimer() size := 100000 - tree := newRandomIntTree(size, size*5) + tree := newRandomIntTree(size, size*3) b.StartTimer() - tree.benchmarkPutRandom(b, size, size*5) + tree.benchmarkPutRandom(b, size, size*3) } func BenchmarkAVLPutAndRemove100(b *testing.B) { @@ -829,3 +829,35 @@ func BenchmarkAVLPutAndRemove100000(b *testing.B) { b.StartTimer() tree.benchmarkPutAndRemove(b, size) } + +func BenchmarkAVLPutAndRemoveRandom100(b *testing.B) { + b.StopTimer() + size := 100 + tree := newRandomIntTree(size, size*3) + b.StartTimer() + tree.benchmarkPutAndRemoveRandom(b, size, size*3) +} + +func BenchmarkAVLPutAndRemoveRandom1000(b *testing.B) { + b.StopTimer() + size := 1000 + tree := newRandomIntTree(size, size*3) + b.StartTimer() + tree.benchmarkPutAndRemoveRandom(b, size, size*3) +} + +func BenchmarkAVLPutAndRemoveRandom10000(b *testing.B) { + b.StopTimer() + size := 10000 + tree := newRandomIntTree(size, size*3) + b.StartTimer() + tree.benchmarkPutAndRemoveRandom(b, size, size*3) +} + +func BenchmarkAVLPutAndRemoveRandom100000(b *testing.B) { + b.StopTimer() + size := 100000 + tree := newRandomIntTree(size, size*3) + b.StartTimer() + tree.benchmarkPutAndRemoveRandom(b, size, size*3) +} diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index bca5e7e4..799b56dd 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -634,7 +634,7 @@ func (tree *Tree) benchmarkPutAndRemoveRandom(b *testing.B, size int, randMax in } } -func BenchmarkAVLGet100(b *testing.B) { +func BenchmarkRBTGet100(b *testing.B) { b.StopTimer() size := 100 tree := NewWithIntComparator() @@ -645,7 +645,7 @@ func BenchmarkAVLGet100(b *testing.B) { tree.benchmarkGet(b, size) } -func BenchmarkAVLGet1000(b *testing.B) { +func BenchmarkRBTGet1000(b *testing.B) { b.StopTimer() size := 1000 tree := NewWithIntComparator() @@ -656,7 +656,7 @@ func BenchmarkAVLGet1000(b *testing.B) { tree.benchmarkGet(b, size) } -func BenchmarkAVLGet10000(b *testing.B) { +func BenchmarkRBTGet10000(b *testing.B) { b.StopTimer() size := 10000 tree := NewWithIntComparator() @@ -667,7 +667,7 @@ func BenchmarkAVLGet10000(b *testing.B) { tree.benchmarkGet(b, size) } -func BenchmarkAVLGet100000(b *testing.B) { +func BenchmarkRBTGet100000(b *testing.B) { b.StopTimer() size := 100000 tree := NewWithIntComparator() @@ -678,39 +678,39 @@ func BenchmarkAVLGet100000(b *testing.B) { tree.benchmarkGet(b, size) } -func BenchmarkAVLGetRandom100(b *testing.B) { +func BenchmarkRBTGetRandom100(b *testing.B) { b.StopTimer() size := 100 - tree := newRandomIntTree(size, size*5) + tree := newRandomIntTree(size, size*3) b.StartTimer() - tree.benchmarkGetRandom(b, size, size*5) + tree.benchmarkGetRandom(b, size, size*3) } -func BenchmarkAVLGetRandom1000(b *testing.B) { +func BenchmarkRBTGetRandom1000(b *testing.B) { b.StopTimer() size := 1000 - tree := newRandomIntTree(size, size*5) + tree := newRandomIntTree(size, size*3) b.StartTimer() - tree.benchmarkGetRandom(b, size, size*5) + tree.benchmarkGetRandom(b, size, size*3) } -func BenchmarkAVLGetRandom10000(b *testing.B) { +func BenchmarkRBTGetRandom10000(b *testing.B) { b.StopTimer() size := 10000 - tree := newRandomIntTree(size, size*5) + tree := newRandomIntTree(size, size*3) b.StartTimer() - tree.benchmarkGetRandom(b, size, size*5) + tree.benchmarkGetRandom(b, size, size*3) } -func BenchmarkAVLGetRandom100000(b *testing.B) { +func BenchmarkRBTGetRandom100000(b *testing.B) { b.StopTimer() size := 100000 - tree := newRandomIntTree(size, size*5) + tree := newRandomIntTree(size, size*3) b.StartTimer() - tree.benchmarkGetRandom(b, size, size*5) + tree.benchmarkGetRandom(b, size, size*3) } -func BenchmarkAVLPut100(b *testing.B) { +func BenchmarkRBTPut100(b *testing.B) { b.StopTimer() size := 100 tree := NewWithIntComparator() @@ -721,7 +721,7 @@ func BenchmarkAVLPut100(b *testing.B) { tree.benchmarkPut(b, size) } -func BenchmarkAVLPut1000(b *testing.B) { +func BenchmarkRBTPut1000(b *testing.B) { b.StopTimer() size := 1000 tree := NewWithIntComparator() @@ -732,7 +732,7 @@ func BenchmarkAVLPut1000(b *testing.B) { tree.benchmarkPut(b, size) } -func BenchmarkAVLPut10000(b *testing.B) { +func BenchmarkRBTPut10000(b *testing.B) { b.StopTimer() size := 10000 tree := NewWithIntComparator() @@ -743,7 +743,7 @@ func BenchmarkAVLPut10000(b *testing.B) { tree.benchmarkPut(b, size) } -func BenchmarkAVLPut100000(b *testing.B) { +func BenchmarkRBTPut100000(b *testing.B) { b.StopTimer() size := 100000 tree := NewWithIntComparator() @@ -754,39 +754,39 @@ func BenchmarkAVLPut100000(b *testing.B) { tree.benchmarkPut(b, size) } -func BenchmarkAVLPutRandom100(b *testing.B) { +func BenchmarkRBTPutRandom100(b *testing.B) { b.StopTimer() size := 100 - tree := newRandomIntTree(size, size*5) + tree := newRandomIntTree(size, size*3) b.StartTimer() - tree.benchmarkPutRandom(b, size, size*5) + tree.benchmarkPutRandom(b, size, size*3) } -func BenchmarkAVLPutRandom1000(b *testing.B) { +func BenchmarkRBTPutRandom1000(b *testing.B) { b.StopTimer() size := 1000 - tree := newRandomIntTree(size, size*5) + tree := newRandomIntTree(size, size*3) b.StartTimer() - tree.benchmarkPutRandom(b, size, size*5) + tree.benchmarkPutRandom(b, size, size*3) } -func BenchmarkAVLPutRandom10000(b *testing.B) { +func BenchmarkRBTPutRandom10000(b *testing.B) { b.StopTimer() size := 10000 - tree := newRandomIntTree(size, size*5) + tree := newRandomIntTree(size, size*3) b.StartTimer() - tree.benchmarkPutRandom(b, size, size*5) + tree.benchmarkPutRandom(b, size, size*3) } -func BenchmarkAVLPutRandom100000(b *testing.B) { +func BenchmarkRBTPutRandom100000(b *testing.B) { b.StopTimer() size := 100000 - tree := newRandomIntTree(size, size*5) + tree := newRandomIntTree(size, size*3) b.StartTimer() - tree.benchmarkPutRandom(b, size, size*5) + tree.benchmarkPutRandom(b, size, size*3) } -func BenchmarkAVLPutAndRemove100(b *testing.B) { +func BenchmarkRBTPutAndRemove100(b *testing.B) { b.StopTimer() size := 100 tree := NewWithIntComparator() @@ -797,7 +797,7 @@ func BenchmarkAVLPutAndRemove100(b *testing.B) { tree.benchmarkPutAndRemove(b, size) } -func BenchmarkAVLPutAndRemove1000(b *testing.B) { +func BenchmarkRBTPutAndRemove1000(b *testing.B) { b.StopTimer() size := 1000 tree := NewWithIntComparator() @@ -808,7 +808,7 @@ func BenchmarkAVLPutAndRemove1000(b *testing.B) { tree.benchmarkPutAndRemove(b, size) } -func BenchmarkAVLPutAndRemove10000(b *testing.B) { +func BenchmarkRBTPutAndRemove10000(b *testing.B) { b.StopTimer() size := 10000 tree := NewWithIntComparator() @@ -819,7 +819,7 @@ func BenchmarkAVLPutAndRemove10000(b *testing.B) { tree.benchmarkPutAndRemove(b, size) } -func BenchmarkAVLPutAndRemove100000(b *testing.B) { +func BenchmarkRBTPutAndRemove100000(b *testing.B) { b.StopTimer() size := 100000 tree := NewWithIntComparator() @@ -829,3 +829,35 @@ func BenchmarkAVLPutAndRemove100000(b *testing.B) { b.StartTimer() tree.benchmarkPutAndRemove(b, size) } + +func BenchmarkRBTPutAndRemoveRandom100(b *testing.B) { + b.StopTimer() + size := 100 + tree := newRandomIntTree(size, size*3) + b.StartTimer() + tree.benchmarkPutAndRemoveRandom(b, size, size*3) +} + +func BenchmarkRBTPutAndRemoveRandom1000(b *testing.B) { + b.StopTimer() + size := 1000 + tree := newRandomIntTree(size, size*3) + b.StartTimer() + tree.benchmarkPutAndRemoveRandom(b, size, size*3) +} + +func BenchmarkRBTPutAndRemoveRandom10000(b *testing.B) { + b.StopTimer() + size := 10000 + tree := newRandomIntTree(size, size*3) + b.StartTimer() + tree.benchmarkPutAndRemoveRandom(b, size, size*3) +} + +func BenchmarkRBTPutAndRemoveRandom100000(b *testing.B) { + b.StopTimer() + size := 100000 + tree := newRandomIntTree(size, size*3) + b.StartTimer() + tree.benchmarkPutAndRemoveRandom(b, size, size*3) +} From 2339521ad938d398304762c158e7290a1ebbd2f8 Mon Sep 17 00:00:00 2001 From: Benjamin Scher Purcell Date: Sun, 26 Feb 2017 18:49:18 -0600 Subject: [PATCH 122/320] put tests back --- trees/avltree/avltree_test.go | 266 +++++------------------- trees/redblacktree/redblacktree_test.go | 232 ++++----------------- 2 files changed, 97 insertions(+), 401 deletions(-) diff --git a/trees/avltree/avltree_test.go b/trees/avltree/avltree_test.go index a1a3e4b7..7af00914 100644 --- a/trees/avltree/avltree_test.go +++ b/trees/avltree/avltree_test.go @@ -6,21 +6,10 @@ package avltree import ( "fmt" - "math/rand" - "os" "testing" - "time" ) -var rng *rand.Rand - -func TestMain(m *testing.M) { - seed := time.Now().UTC().UnixNano() - rng = rand.New(rand.NewSource(seed)) - os.Exit(m.Run()) -} - -func TestAVLPut(t *testing.T) { +func TestAVLTreePut(t *testing.T) { tree := NewWithIntComparator() tree.Put(5, "e") tree.Put(6, "f") @@ -61,7 +50,7 @@ func TestAVLPut(t *testing.T) { } } -func TestAVLRemove(t *testing.T) { +func TestAVLTreeRemove(t *testing.T) { tree := NewWithIntComparator() tree.Put(5, "e") tree.Put(6, "f") @@ -128,7 +117,7 @@ func TestAVLRemove(t *testing.T) { } -func TestAVLLeftAndRight(t *testing.T) { +func TestAVLTreeLeftAndRight(t *testing.T) { tree := NewWithIntComparator() if actualValue := tree.Left(); actualValue != nil { @@ -162,7 +151,7 @@ func TestAVLLeftAndRight(t *testing.T) { } } -func TestAVLCeilingAndFloor(t *testing.T) { +func TestAVLTreeCeilingAndFloor(t *testing.T) { tree := NewWithIntComparator() if node, found := tree.Floor(0); node != nil || found { @@ -195,7 +184,7 @@ func TestAVLCeilingAndFloor(t *testing.T) { } } -func TestAVLIteratorNextOnEmpty(t *testing.T) { +func TestAVLTreeIteratorNextOnEmpty(t *testing.T) { tree := NewWithIntComparator() it := tree.Iterator() for it.Next() { @@ -203,7 +192,7 @@ func TestAVLIteratorNextOnEmpty(t *testing.T) { } } -func TestAVLIteratorPrevOnEmpty(t *testing.T) { +func TestAVLTreeIteratorPrevOnEmpty(t *testing.T) { tree := NewWithIntComparator() it := tree.Iterator() for it.Prev() { @@ -211,7 +200,7 @@ func TestAVLIteratorPrevOnEmpty(t *testing.T) { } } -func TestAVLIterator1Next(t *testing.T) { +func TestAVLTreeIterator1Next(t *testing.T) { tree := NewWithIntComparator() tree.Put(5, "e") tree.Put(6, "f") @@ -249,7 +238,7 @@ func TestAVLIterator1Next(t *testing.T) { } } -func TestAVLIterator1Prev(t *testing.T) { +func TestAVLTreeIterator1Prev(t *testing.T) { tree := NewWithIntComparator() tree.Put(5, "e") tree.Put(6, "f") @@ -289,7 +278,7 @@ func TestAVLIterator1Prev(t *testing.T) { } } -func TestAVLIterator2Next(t *testing.T) { +func TestAVLTreeIterator2Next(t *testing.T) { tree := NewWithIntComparator() tree.Put(3, "c") tree.Put(1, "a") @@ -315,7 +304,7 @@ func TestAVLIterator2Next(t *testing.T) { } } -func TestAVLIterator2Prev(t *testing.T) { +func TestAVLTreeIterator2Prev(t *testing.T) { tree := NewWithIntComparator() tree.Put(3, "c") tree.Put(1, "a") @@ -343,7 +332,7 @@ func TestAVLIterator2Prev(t *testing.T) { } } -func TestAVLIterator3Next(t *testing.T) { +func TestAVLTreeIterator3Next(t *testing.T) { tree := NewWithIntComparator() tree.Put(1, "a") it := tree.Iterator() @@ -367,7 +356,7 @@ func TestAVLIterator3Next(t *testing.T) { } } -func TestAVLIterator3Prev(t *testing.T) { +func TestAVLTreeIterator3Prev(t *testing.T) { tree := NewWithIntComparator() tree.Put(1, "a") it := tree.Iterator() @@ -393,7 +382,7 @@ func TestAVLIterator3Prev(t *testing.T) { } } -func TestAVLIterator4Next(t *testing.T) { +func TestAVLTreeIterator4Next(t *testing.T) { tree := NewWithIntComparator() tree.Put(13, 5) tree.Put(8, 3) @@ -436,7 +425,7 @@ func TestAVLIterator4Next(t *testing.T) { } } -func TestAVLIterator4Prev(t *testing.T) { +func TestAVLTreeIterator4Prev(t *testing.T) { tree := NewWithIntComparator() tree.Put(13, 5) tree.Put(8, 3) @@ -481,7 +470,7 @@ func TestAVLIterator4Prev(t *testing.T) { } } -func TestAVLIteratorBegin(t *testing.T) { +func TestAVLTreeIteratorBegin(t *testing.T) { tree := NewWithIntComparator() tree.Put(3, "c") tree.Put(1, "a") @@ -513,7 +502,7 @@ func TestAVLIteratorBegin(t *testing.T) { } } -func TestAVLIteratorEnd(t *testing.T) { +func TestAVLTreeIteratorEnd(t *testing.T) { tree := NewWithIntComparator() it := tree.Iterator() @@ -540,7 +529,7 @@ func TestAVLIteratorEnd(t *testing.T) { } } -func TestAVLIteratorFirst(t *testing.T) { +func TestAVLTreeIteratorFirst(t *testing.T) { tree := NewWithIntComparator() tree.Put(3, "c") tree.Put(1, "a") @@ -554,7 +543,7 @@ func TestAVLIteratorFirst(t *testing.T) { } } -func TestAVLIteratorLast(t *testing.T) { +func TestAVLTreeIteratorLast(t *testing.T) { tree := NewWithIntComparator() tree.Put(3, "c") tree.Put(1, "a") @@ -568,15 +557,7 @@ func TestAVLIteratorLast(t *testing.T) { } } -func newRandomIntTree(size, randMax int) *Tree { - tree := NewWithIntComparator() - for i := 0; i < size; i++ { - tree.Put(rng.Intn(randMax), nil) - } - return tree -} - -func (tree *Tree) benchmarkGet(b *testing.B, size int) { +func benchmarkGet(b *testing.B, tree *Tree, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { tree.Get(n) @@ -584,280 +565,147 @@ func (tree *Tree) benchmarkGet(b *testing.B, size int) { } } -func (tree *Tree) benchmarkGetRandom(b *testing.B, size, randMax int) { +func benchmarkPut(b *testing.B, tree *Tree, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { - tree.Get(rng.Intn(randMax)) + tree.Put(n, struct{}{}) } } } -func (tree *Tree) benchmarkPut(b *testing.B, size int) { +func benchmarkRemove(b *testing.B, tree *Tree, size int) { for i := 0; i < b.N; i++ { - for n := 0; n < size; n++ { - tree.Put(n, nil) - } - tree.Empty() - } -} - -func (tree *Tree) benchmarkPutRandom(b *testing.B, size, randMax int) { - for i := 0; i < b.N; i++ { - for n := 0; n < size; n++ { - tree.Put(rng.Intn(randMax), nil) - } - tree.Empty() - } -} - -func (tree *Tree) benchmarkPutAndRemove(b *testing.B, size int) { - for i := 0; i < b.N; i++ { - for n := 0; n < size; n++ { - tree.Put(n, nil) - } for n := 0; n < size; n++ { tree.Remove(n) } - tree.Empty() - } -} - -func (tree *Tree) benchmarkPutAndRemoveRandom(b *testing.B, size int, randMax int) { - for i := 0; i < b.N; i++ { - for n := 0; n < size; n++ { - tree.Put(rng.Intn(randMax), nil) - } - for n := 0; n < size; n++ { - tree.Remove(rng.Intn(randMax)) - } - tree.Empty() } } -func BenchmarkAVLGet100(b *testing.B) { +func BenchmarkAVLTreeGet100(b *testing.B) { b.StopTimer() size := 100 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkGet(b, size) + benchmarkGet(b, tree, size) } -func BenchmarkAVLGet1000(b *testing.B) { +func BenchmarkAVLTreeGet1000(b *testing.B) { b.StopTimer() size := 1000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkGet(b, size) + benchmarkGet(b, tree, size) } -func BenchmarkAVLGet10000(b *testing.B) { +func BenchmarkAVLTreeGet10000(b *testing.B) { b.StopTimer() size := 10000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkGet(b, size) + benchmarkGet(b, tree, size) } -func BenchmarkAVLGet100000(b *testing.B) { +func BenchmarkAVLTreeGet100000(b *testing.B) { b.StopTimer() size := 100000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkGet(b, size) + benchmarkGet(b, tree, size) } -func BenchmarkAVLGetRandom100(b *testing.B) { - b.StopTimer() - size := 100 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkGetRandom(b, size, size*3) -} - -func BenchmarkAVLGetRandom1000(b *testing.B) { - b.StopTimer() - size := 1000 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkGetRandom(b, size, size*3) -} - -func BenchmarkAVLGetRandom10000(b *testing.B) { - b.StopTimer() - size := 10000 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkGetRandom(b, size, size*3) -} - -func BenchmarkAVLGetRandom100000(b *testing.B) { - b.StopTimer() - size := 100000 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkGetRandom(b, size, size*3) -} - -func BenchmarkAVLPut100(b *testing.B) { +func BenchmarkAVLTreePut100(b *testing.B) { b.StopTimer() size := 100 tree := NewWithIntComparator() - for n := 0; n < size; n++ { - tree.Put(n, nil) - } b.StartTimer() - tree.benchmarkPut(b, size) + benchmarkPut(b, tree, size) } -func BenchmarkAVLPut1000(b *testing.B) { +func BenchmarkAVLTreePut1000(b *testing.B) { b.StopTimer() size := 1000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkPut(b, size) + benchmarkPut(b, tree, size) } -func BenchmarkAVLPut10000(b *testing.B) { +func BenchmarkAVLTreePut10000(b *testing.B) { b.StopTimer() size := 10000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkPut(b, size) + benchmarkPut(b, tree, size) } -func BenchmarkAVLPut100000(b *testing.B) { +func BenchmarkAVLTreePut100000(b *testing.B) { b.StopTimer() size := 100000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkPut(b, size) + benchmarkPut(b, tree, size) } -func BenchmarkAVLPutRandom100(b *testing.B) { - b.StopTimer() - size := 100 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkPutRandom(b, size, size*3) -} - -func BenchmarkAVLPutRandom1000(b *testing.B) { - b.StopTimer() - size := 1000 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkPutRandom(b, size, size*3) -} - -func BenchmarkAVLPutRandom10000(b *testing.B) { - b.StopTimer() - size := 10000 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkPutRandom(b, size, size*3) -} - -func BenchmarkAVLPutRandom100000(b *testing.B) { - b.StopTimer() - size := 100000 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkPutRandom(b, size, size*3) -} - -func BenchmarkAVLPutAndRemove100(b *testing.B) { +func BenchmarkAVLTreeRemove100(b *testing.B) { b.StopTimer() size := 100 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkPutAndRemove(b, size) + benchmarkRemove(b, tree, size) } -func BenchmarkAVLPutAndRemove1000(b *testing.B) { +func BenchmarkAVLTreeRemove1000(b *testing.B) { b.StopTimer() size := 1000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkPutAndRemove(b, size) + benchmarkRemove(b, tree, size) } -func BenchmarkAVLPutAndRemove10000(b *testing.B) { +func BenchmarkAVLTreeRemove10000(b *testing.B) { b.StopTimer() size := 10000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkPutAndRemove(b, size) + benchmarkRemove(b, tree, size) } -func BenchmarkAVLPutAndRemove100000(b *testing.B) { +func BenchmarkAVLTreeRemove100000(b *testing.B) { b.StopTimer() size := 100000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkPutAndRemove(b, size) -} - -func BenchmarkAVLPutAndRemoveRandom100(b *testing.B) { - b.StopTimer() - size := 100 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkPutAndRemoveRandom(b, size, size*3) -} - -func BenchmarkAVLPutAndRemoveRandom1000(b *testing.B) { - b.StopTimer() - size := 1000 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkPutAndRemoveRandom(b, size, size*3) -} - -func BenchmarkAVLPutAndRemoveRandom10000(b *testing.B) { - b.StopTimer() - size := 10000 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkPutAndRemoveRandom(b, size, size*3) -} - -func BenchmarkAVLPutAndRemoveRandom100000(b *testing.B) { - b.StopTimer() - size := 100000 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkPutAndRemoveRandom(b, size, size*3) + benchmarkRemove(b, tree, size) } diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 799b56dd..714defcf 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -6,20 +6,9 @@ package redblacktree import ( "fmt" - "math/rand" - "os" "testing" - "time" ) -var rng *rand.Rand - -func TestMain(m *testing.M) { - seed := time.Now().UTC().UnixNano() - rng = rand.New(rand.NewSource(seed)) - os.Exit(m.Run()) -} - func TestRedBlackTreePut(t *testing.T) { tree := NewWithIntComparator() tree.Put(5, "e") @@ -30,7 +19,7 @@ func TestRedBlackTreePut(t *testing.T) { tree.Put(1, "x") tree.Put(2, "b") tree.Put(1, "a") //overwrite - t.Log(tree) + if actualValue := tree.Size(); actualValue != 7 { t.Errorf("Got %v expected %v", actualValue, 7) } @@ -568,15 +557,7 @@ func TestRedBlackTreeIteratorLast(t *testing.T) { } } -func newRandomIntTree(size, randMax int) *Tree { - tree := NewWithIntComparator() - for i := 0; i < size; i++ { - tree.Put(rng.Intn(randMax), nil) - } - return tree -} - -func (tree *Tree) benchmarkGet(b *testing.B, size int) { +func benchmarkGet(b *testing.B, tree *Tree, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { tree.Get(n) @@ -584,280 +565,147 @@ func (tree *Tree) benchmarkGet(b *testing.B, size int) { } } -func (tree *Tree) benchmarkGetRandom(b *testing.B, size, randMax int) { +func benchmarkPut(b *testing.B, tree *Tree, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { - tree.Get(rng.Intn(randMax)) + tree.Put(n, struct{}{}) } } } -func (tree *Tree) benchmarkPut(b *testing.B, size int) { +func benchmarkRemove(b *testing.B, tree *Tree, size int) { for i := 0; i < b.N; i++ { - for n := 0; n < size; n++ { - tree.Put(n, nil) - } - tree.Empty() - } -} - -func (tree *Tree) benchmarkPutRandom(b *testing.B, size, randMax int) { - for i := 0; i < b.N; i++ { - for n := 0; n < size; n++ { - tree.Put(rng.Intn(randMax), nil) - } - tree.Empty() - } -} - -func (tree *Tree) benchmarkPutAndRemove(b *testing.B, size int) { - for i := 0; i < b.N; i++ { - for n := 0; n < size; n++ { - tree.Put(n, nil) - } for n := 0; n < size; n++ { tree.Remove(n) } - tree.Empty() - } -} - -func (tree *Tree) benchmarkPutAndRemoveRandom(b *testing.B, size int, randMax int) { - for i := 0; i < b.N; i++ { - for n := 0; n < size; n++ { - tree.Put(rng.Intn(randMax), nil) - } - for n := 0; n < size; n++ { - tree.Remove(rng.Intn(randMax)) - } - tree.Empty() } } -func BenchmarkRBTGet100(b *testing.B) { +func BenchmarkRedBlackTreeGet100(b *testing.B) { b.StopTimer() size := 100 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkGet(b, size) + benchmarkGet(b, tree, size) } -func BenchmarkRBTGet1000(b *testing.B) { +func BenchmarkRedBlackTreeGet1000(b *testing.B) { b.StopTimer() size := 1000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkGet(b, size) + benchmarkGet(b, tree, size) } -func BenchmarkRBTGet10000(b *testing.B) { +func BenchmarkRedBlackTreeGet10000(b *testing.B) { b.StopTimer() size := 10000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkGet(b, size) + benchmarkGet(b, tree, size) } -func BenchmarkRBTGet100000(b *testing.B) { +func BenchmarkRedBlackTreeGet100000(b *testing.B) { b.StopTimer() size := 100000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkGet(b, size) -} - -func BenchmarkRBTGetRandom100(b *testing.B) { - b.StopTimer() - size := 100 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkGetRandom(b, size, size*3) -} - -func BenchmarkRBTGetRandom1000(b *testing.B) { - b.StopTimer() - size := 1000 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkGetRandom(b, size, size*3) -} - -func BenchmarkRBTGetRandom10000(b *testing.B) { - b.StopTimer() - size := 10000 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkGetRandom(b, size, size*3) -} - -func BenchmarkRBTGetRandom100000(b *testing.B) { - b.StopTimer() - size := 100000 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkGetRandom(b, size, size*3) + benchmarkGet(b, tree, size) } -func BenchmarkRBTPut100(b *testing.B) { +func BenchmarkRedBlackTreePut100(b *testing.B) { b.StopTimer() size := 100 tree := NewWithIntComparator() - for n := 0; n < size; n++ { - tree.Put(n, nil) - } b.StartTimer() - tree.benchmarkPut(b, size) + benchmarkPut(b, tree, size) } -func BenchmarkRBTPut1000(b *testing.B) { +func BenchmarkRedBlackTreePut1000(b *testing.B) { b.StopTimer() size := 1000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkPut(b, size) + benchmarkPut(b, tree, size) } -func BenchmarkRBTPut10000(b *testing.B) { +func BenchmarkRedBlackTreePut10000(b *testing.B) { b.StopTimer() size := 10000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkPut(b, size) + benchmarkPut(b, tree, size) } -func BenchmarkRBTPut100000(b *testing.B) { +func BenchmarkRedBlackTreePut100000(b *testing.B) { b.StopTimer() size := 100000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkPut(b, size) -} - -func BenchmarkRBTPutRandom100(b *testing.B) { - b.StopTimer() - size := 100 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkPutRandom(b, size, size*3) -} - -func BenchmarkRBTPutRandom1000(b *testing.B) { - b.StopTimer() - size := 1000 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkPutRandom(b, size, size*3) -} - -func BenchmarkRBTPutRandom10000(b *testing.B) { - b.StopTimer() - size := 10000 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkPutRandom(b, size, size*3) -} - -func BenchmarkRBTPutRandom100000(b *testing.B) { - b.StopTimer() - size := 100000 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkPutRandom(b, size, size*3) + benchmarkPut(b, tree, size) } -func BenchmarkRBTPutAndRemove100(b *testing.B) { +func BenchmarkRedBlackTreeRemove100(b *testing.B) { b.StopTimer() size := 100 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkPutAndRemove(b, size) + benchmarkRemove(b, tree, size) } -func BenchmarkRBTPutAndRemove1000(b *testing.B) { +func BenchmarkRedBlackTreeRemove1000(b *testing.B) { b.StopTimer() size := 1000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkPutAndRemove(b, size) + benchmarkRemove(b, tree, size) } -func BenchmarkRBTPutAndRemove10000(b *testing.B) { +func BenchmarkRedBlackTreeRemove10000(b *testing.B) { b.StopTimer() size := 10000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkPutAndRemove(b, size) + benchmarkRemove(b, tree, size) } -func BenchmarkRBTPutAndRemove100000(b *testing.B) { +func BenchmarkRedBlackTreeRemove100000(b *testing.B) { b.StopTimer() size := 100000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, nil) + tree.Put(n, struct{}{}) } b.StartTimer() - tree.benchmarkPutAndRemove(b, size) -} - -func BenchmarkRBTPutAndRemoveRandom100(b *testing.B) { - b.StopTimer() - size := 100 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkPutAndRemoveRandom(b, size, size*3) -} - -func BenchmarkRBTPutAndRemoveRandom1000(b *testing.B) { - b.StopTimer() - size := 1000 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkPutAndRemoveRandom(b, size, size*3) -} - -func BenchmarkRBTPutAndRemoveRandom10000(b *testing.B) { - b.StopTimer() - size := 10000 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkPutAndRemoveRandom(b, size, size*3) -} - -func BenchmarkRBTPutAndRemoveRandom100000(b *testing.B) { - b.StopTimer() - size := 100000 - tree := newRandomIntTree(size, size*3) - b.StartTimer() - tree.benchmarkPutAndRemoveRandom(b, size, size*3) + benchmarkRemove(b, tree, size) } From d84c1f0a425b940ac65527f071551dca1abe14db Mon Sep 17 00:00:00 2001 From: Benjamin Scher Purcell Date: Sun, 26 Feb 2017 18:52:00 -0600 Subject: [PATCH 123/320] fix documentation --- trees/avltree/avltree.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index 226efccd..efcedf97 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -38,17 +38,17 @@ type Node struct { b int8 } -// NewWith instantiates a red-black tree with the custom comparator. +// NewWith instantiates an AVL tree with the custom comparator. func NewWith(comparator utils.Comparator) *Tree { return &Tree{Comparator: comparator} } -// NewWithIntComparator instantiates a red-black tree with the IntComparator, i.e. keys are of type int. +// NewWithIntComparator instantiates an AVL tree with the IntComparator, i.e. keys are of type int. func NewWithIntComparator() *Tree { return &Tree{Comparator: utils.IntComparator} } -// NewWithStringComparator instantiates a red-black tree with the StringComparator, i.e. keys are of type string. +// NewWithStringComparator instantiates an AVL tree with the StringComparator, i.e. keys are of type string. func NewWithStringComparator() *Tree { return &Tree{Comparator: utils.StringComparator} } From 67a0d2f54762a16963e4b10dba78b7ad3a77faae Mon Sep 17 00:00:00 2001 From: Benjamin Scher Purcell Date: Sun, 26 Feb 2017 19:46:04 -0600 Subject: [PATCH 124/320] Make treeset take an interface, make the trees satisfy that interface --- sets/treeset/enumerable.go | 6 +++--- sets/treeset/iterator.go | 6 +++--- sets/treeset/treeset.go | 13 ++++++++++--- sets/treeset/treeset_test.go | 20 ++++++++++++++++++++ trees/avltree/avltree.go | 30 ++++++++++++++++++++---------- trees/avltree/iterator.go | 4 ++-- trees/redblacktree/iterator.go | 8 ++++---- trees/redblacktree/redblacktree.go | 29 ++++++++++++++++++++--------- trees/trees.go | 13 ++++++++++++- 9 files changed, 94 insertions(+), 35 deletions(-) diff --git a/sets/treeset/enumerable.go b/sets/treeset/enumerable.go index 59a0913a..db3ce9e2 100644 --- a/sets/treeset/enumerable.go +++ b/sets/treeset/enumerable.go @@ -6,7 +6,7 @@ package treeset import ( "github.com/emirpasic/gods/containers" - rbt "github.com/emirpasic/gods/trees/redblacktree" + rbt "github.com/spewspews/gods/trees/redblacktree" ) func assertEnumerableImplementation() { @@ -24,7 +24,7 @@ func (set *Set) Each(f func(index int, value interface{})) { // 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 := &Set{tree: rbt.NewWith(set.tree.Comparator)} + newSet := &Set{tree: set.tree.New()} iterator := set.Iterator() for iterator.Next() { newSet.Add(f(iterator.Index(), iterator.Value())) @@ -34,7 +34,7 @@ func (set *Set) Map(f func(index int, value interface{}) interface{}) *Set { // 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 := &Set{tree: rbt.NewWith(set.tree.Comparator)} + newSet := &Set{tree: rbt.NewWith(set.tree.Comparator())} iterator := set.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { diff --git a/sets/treeset/iterator.go b/sets/treeset/iterator.go index 2cb465f8..9f76f66c 100644 --- a/sets/treeset/iterator.go +++ b/sets/treeset/iterator.go @@ -6,7 +6,7 @@ package treeset import ( "github.com/emirpasic/gods/containers" - rbt "github.com/emirpasic/gods/trees/redblacktree" + "github.com/spewspews/gods/trees" ) func assertIteratorImplementation() { @@ -16,8 +16,8 @@ func assertIteratorImplementation() { // Iterator returns a stateful iterator whose values can be fetched by an index. type Iterator struct { index int - iterator rbt.Iterator - tree *rbt.Tree + iterator containers.ReverseIteratorWithKey + tree trees.Tree } // Iterator holding the iterator's state diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 9ead6341..baa168a9 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -11,10 +11,12 @@ package treeset import ( "fmt" + "strings" + "github.com/emirpasic/gods/sets" - rbt "github.com/emirpasic/gods/trees/redblacktree" "github.com/emirpasic/gods/utils" - "strings" + "github.com/spewspews/gods/trees" + rbt "github.com/spewspews/gods/trees/redblacktree" ) func assertSetImplementation() { @@ -23,7 +25,7 @@ func assertSetImplementation() { // Set holds elements in a red-black tree type Set struct { - tree *rbt.Tree + tree trees.Tree } var itemExists = struct{}{} @@ -43,6 +45,11 @@ func NewWithStringComparator() *Set { return &Set{tree: rbt.NewWithStringComparator()} } +// NewWithTree instantiates a new empty set with given tree +func NewWithTree(tree trees.Tree) (set *Set) { + return &Set{tree: tree} +} + // Add adds the items (one or more) to the set. func (set *Set) Add(items ...interface{}) { for _, item := range items { diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index 881adc21..e5d5c1eb 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -7,6 +7,8 @@ package treeset import ( "fmt" "testing" + + "github.com/spewspews/gods/trees/avltree" ) func TestSetAdd(t *testing.T) { @@ -27,6 +29,24 @@ func TestSetAdd(t *testing.T) { } } +func TestSetAVLAdd(t *testing.T) { + set := NewWithTree(avltree.NewWithIntComparator()) + 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) + } + if actualValue, expectedValue := fmt.Sprintf("%d%d%d", set.Values()...), "123"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + func TestSetContains(t *testing.T) { set := NewWithIntComparator() set.Add(3, 1, 2) diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index efcedf97..f446e191 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -12,8 +12,8 @@ import ( "io/ioutil" "log" - "github.com/emirpasic/gods/trees" "github.com/emirpasic/gods/utils" + "github.com/spewspews/gods/trees" ) func assertTreeImplementation() { @@ -26,7 +26,7 @@ var dbgLog = log.New(ioutil.Discard, "avltree: ", log.LstdFlags) type Tree struct { Root *Node size int - Comparator utils.Comparator + comparator utils.Comparator } // Node is a single element within the tree @@ -40,17 +40,27 @@ type Node struct { // NewWith instantiates an AVL tree with the custom comparator. func NewWith(comparator utils.Comparator) *Tree { - return &Tree{Comparator: comparator} + return &Tree{comparator: comparator} } // NewWithIntComparator instantiates an AVL tree with the IntComparator, i.e. keys are of type int. func NewWithIntComparator() *Tree { - return &Tree{Comparator: utils.IntComparator} + return &Tree{comparator: utils.IntComparator} } // NewWithStringComparator instantiates an AVL tree with the StringComparator, i.e. keys are of type string. func NewWithStringComparator() *Tree { - return &Tree{Comparator: utils.StringComparator} + return &Tree{comparator: utils.StringComparator} +} + +// Comparator returns the comparator function for the tree. +func (t *Tree) Comparator() utils.Comparator { + return t.comparator +} + +// New returns a new empty tree with the same comparator. +func (t *Tree) New() trees.Tree { + return &Tree{comparator: t.comparator} } // Size returns the number of elements stored in the tree. @@ -75,7 +85,7 @@ func (t *Tree) Clear() { func (t *Tree) Get(key interface{}) (value interface{}, found bool) { n := t.Root for n != nil { - cmp := t.Comparator(key, n.Key) + cmp := t.comparator(key, n.Key) switch { case cmp == 0: return n.Value, true @@ -100,7 +110,7 @@ func (t *Tree) Floor(key interface{}) (floor *Node, found bool) { found = false n := t.Root for n != nil { - c := t.Comparator(key, n.Key) + c := t.comparator(key, n.Key) switch { case c == 0: return n, true @@ -129,7 +139,7 @@ func (t *Tree) Ceiling(key interface{}) (floor *Node, found bool) { found = false n := t.Root for n != nil { - c := t.Comparator(key, n.Key) + c := t.comparator(key, n.Key) switch { case c == 0: return n, true @@ -158,7 +168,7 @@ func (t *Tree) Put(key interface{}, value interface{}) { return true } - c := t.Comparator(key, q.Key) + c := t.comparator(key, q.Key) if c == 0 { q.Key = key q.Value = value @@ -192,7 +202,7 @@ func (t *Tree) Remove(key interface{}) { return false } - c := t.Comparator(key, q.Key) + c := t.comparator(key, q.Key) if c == 0 { t.size-- if q.c[1] == nil { diff --git a/trees/avltree/iterator.go b/trees/avltree/iterator.go index a3d930c0..b61bc829 100644 --- a/trees/avltree/iterator.go +++ b/trees/avltree/iterator.go @@ -24,8 +24,8 @@ const ( ) // Iterator returns a stateful iterator whose elements are key/value pairs. -func (tree *Tree) Iterator() Iterator { - return Iterator{tree: tree, node: nil, position: begin} +func (tree *Tree) Iterator() containers.ReverseIteratorWithKey { + return &Iterator{tree: tree, node: nil, position: begin} } // Next moves the iterator to the next element and returns true if there was a next element in the container. diff --git a/trees/redblacktree/iterator.go b/trees/redblacktree/iterator.go index 90b84afe..56bf5a5f 100644 --- a/trees/redblacktree/iterator.go +++ b/trees/redblacktree/iterator.go @@ -24,8 +24,8 @@ const ( ) // Iterator returns a stateful iterator whose elements are key/value pairs. -func (tree *Tree) Iterator() Iterator { - return Iterator{tree: tree, node: nil, position: begin} +func (tree *Tree) Iterator() containers.ReverseIteratorWithKey { + return &Iterator{tree: tree, node: nil, position: begin} } // Next moves the iterator to the next element and returns true if there was a next element in the container. @@ -55,7 +55,7 @@ func (iterator *Iterator) Next() bool { node := iterator.node for iterator.node.Parent != nil { iterator.node = iterator.node.Parent - if iterator.tree.Comparator(node.Key, iterator.node.Key) <= 0 { + if iterator.tree.comparator(node.Key, iterator.node.Key) <= 0 { goto between } } @@ -97,7 +97,7 @@ func (iterator *Iterator) Prev() bool { node := iterator.node for iterator.node.Parent != nil { iterator.node = iterator.node.Parent - if iterator.tree.Comparator(node.Key, iterator.node.Key) >= 0 { + if iterator.tree.comparator(node.Key, iterator.node.Key) >= 0 { goto between } } diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index f9c9bc91..3c39694c 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -13,8 +13,9 @@ package redblacktree import ( "fmt" - "github.com/emirpasic/gods/trees" + "github.com/emirpasic/gods/utils" + "github.com/spewspews/gods/trees" ) func assertTreeImplementation() { @@ -31,7 +32,7 @@ const ( type Tree struct { Root *Node size int - Comparator utils.Comparator + comparator utils.Comparator } // Node is a single element within the tree @@ -46,17 +47,27 @@ type Node struct { // NewWith instantiates a red-black tree with the custom comparator. func NewWith(comparator utils.Comparator) *Tree { - return &Tree{Comparator: comparator} + return &Tree{comparator: comparator} } // NewWithIntComparator instantiates a red-black tree with the IntComparator, i.e. keys are of type int. func NewWithIntComparator() *Tree { - return &Tree{Comparator: utils.IntComparator} + return &Tree{comparator: utils.IntComparator} } // NewWithStringComparator instantiates a red-black tree with the StringComparator, i.e. keys are of type string. func NewWithStringComparator() *Tree { - return &Tree{Comparator: utils.StringComparator} + return &Tree{comparator: utils.StringComparator} +} + +// Comparator returns the comparator function for the tree. +func (t *Tree) Comparator() utils.Comparator { + return t.comparator +} + +// New returns a new empty tree with the same comparator. +func (t *Tree) New() trees.Tree { + return &Tree{comparator: t.comparator} } // Put inserts node into the tree. @@ -69,7 +80,7 @@ func (tree *Tree) Put(key interface{}, value interface{}) { node := tree.Root loop := true for loop { - compare := tree.Comparator(key, node.Key) + compare := tree.comparator(key, node.Key) switch { case compare == 0: node.Key = key @@ -204,7 +215,7 @@ func (tree *Tree) Floor(key interface{}) (floor *Node, found bool) { found = false node := tree.Root for node != nil { - compare := tree.Comparator(key, node.Key) + compare := tree.comparator(key, node.Key) switch { case compare == 0: return node, true @@ -233,7 +244,7 @@ func (tree *Tree) Ceiling(key interface{}) (ceiling *Node, found bool) { found = false node := tree.Root for node != nil { - compare := tree.Comparator(key, node.Key) + compare := tree.comparator(key, node.Key) switch { case compare == 0: return node, true @@ -300,7 +311,7 @@ func output(node *Node, prefix string, isTail bool, str *string) { func (tree *Tree) lookup(key interface{}) *Node { node := tree.Root for node != nil { - compare := tree.Comparator(key, node.Key) + compare := tree.comparator(key, node.Key) switch { case compare == 0: return node diff --git a/trees/trees.go b/trees/trees.go index a5a7427d..52b2b942 100644 --- a/trees/trees.go +++ b/trees/trees.go @@ -9,10 +9,21 @@ // Reference: https://en.wikipedia.org/wiki/Tree_%28data_structure%29 package trees -import "github.com/emirpasic/gods/containers" +import ( + "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/utils" +) // Tree interface that all trees implement type Tree interface { + Comparator() utils.Comparator + New() Tree + Iterator() containers.ReverseIteratorWithKey + Put(key interface{}, value interface{}) + Remove(key interface{}) + Get(key interface{}) (interface{}, bool) + Keys() []interface{} + containers.Container // Empty() bool // Size() int From 0e4eb1c32cd40c6496644e33179e67186701ae32 Mon Sep 17 00:00:00 2001 From: Benjamin Scher Purcell Date: Sun, 26 Feb 2017 20:10:35 -0600 Subject: [PATCH 125/320] convert treemap in the same way as treeset --- maps/treemap/enumerable.go | 9 ++---- maps/treemap/iterator.go | 7 ++--- maps/treemap/treemap.go | 20 +++++++------- maps/treemap/treemap_test.go | 44 ++++++++++++++++++++++++++++++ sets/treeset/treeset.go | 2 +- trees/avltree/avltree.go | 20 ++++++++++++++ trees/redblacktree/redblacktree.go | 20 ++++++++++++++ trees/trees.go | 2 ++ 8 files changed, 102 insertions(+), 22 deletions(-) diff --git a/maps/treemap/enumerable.go b/maps/treemap/enumerable.go index 8cea6d00..5f66ffb8 100644 --- a/maps/treemap/enumerable.go +++ b/maps/treemap/enumerable.go @@ -4,10 +4,7 @@ package treemap -import ( - "github.com/emirpasic/gods/containers" - rbt "github.com/emirpasic/gods/trees/redblacktree" -) +import "github.com/emirpasic/gods/containers" func assertEnumerableImplementation() { var _ containers.EnumerableWithKey = (*Map)(nil) @@ -24,7 +21,7 @@ func (m *Map) Each(f func(key interface{}, value interface{})) { // 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. func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) *Map { - newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)} + newMap := &Map{tree: m.tree.New()} iterator := m.Iterator() for iterator.Next() { key2, value2 := f(iterator.Key(), iterator.Value()) @@ -35,7 +32,7 @@ func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, int // Select returns a new container containing all elements for which the given function returns a true value. func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map { - newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)} + newMap := &Map{tree: m.tree.New()} iterator := m.Iterator() for iterator.Next() { if f(iterator.Key(), iterator.Value()) { diff --git a/maps/treemap/iterator.go b/maps/treemap/iterator.go index 02b5c753..3de1482f 100644 --- a/maps/treemap/iterator.go +++ b/maps/treemap/iterator.go @@ -4,10 +4,7 @@ package treemap -import ( - "github.com/emirpasic/gods/containers" - rbt "github.com/emirpasic/gods/trees/redblacktree" -) +import "github.com/emirpasic/gods/containers" func assertIteratorImplementation() { var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) @@ -15,7 +12,7 @@ func assertIteratorImplementation() { // Iterator holding the iterator's state type Iterator struct { - iterator rbt.Iterator + iterator containers.ReverseIteratorWithKey } // Iterator returns a stateful iterator whose elements are key/value pairs. diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index a1e58ad4..bf621977 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -14,7 +14,8 @@ package treemap import ( "fmt" "github.com/emirpasic/gods/maps" - rbt "github.com/emirpasic/gods/trees/redblacktree" + rbt "github.com/spewspews/gods/trees/redblacktree" + "github.com/spewspews/gods/trees" "github.com/emirpasic/gods/utils" "strings" ) @@ -25,7 +26,7 @@ func assertMapImplementation() { // Map holds the elements in a red-black tree type Map struct { - tree *rbt.Tree + tree trees.Tree } // NewWith instantiates a tree map with the custom comparator. @@ -43,6 +44,11 @@ func NewWithStringComparator() *Map { return &Map{tree: rbt.NewWithStringComparator()} } +// NewWithTree instantiates a new empty map with given tree +func NewWithTree(tree trees.Tree) *Map { + return &Map{tree: tree} +} + // Put inserts key-value pair into the map. // Key should adhere to the comparator's type assertion, otherwise method panics. func (m *Map) Put(key interface{}, value interface{}) { @@ -90,19 +96,13 @@ func (m *Map) Clear() { // Min returns the minimum key and its value from the tree map. // Returns nil, nil if map is empty. func (m *Map) Min() (key interface{}, value interface{}) { - if node := m.tree.Left(); node != nil { - return node.Key, node.Value - } - return nil, nil + return m.tree.Min() } // Max returns the maximum key and its value from the tree map. // Returns nil, nil if map is empty. func (m *Map) Max() (key interface{}, value interface{}) { - if node := m.tree.Right(); node != nil { - return node.Key, node.Value - } - return nil, nil + return m.tree.Max() } // String returns a string representation of container diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 0039601a..4aa3e5e4 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -7,6 +7,8 @@ package treemap import ( "fmt" "testing" + + "github.com/spewspews/gods/trees/avltree" ) func TestMapPut(t *testing.T) { @@ -51,6 +53,48 @@ func TestMapPut(t *testing.T) { } } +func TestMapAVLPut(t *testing.T) { + m := NewWithTree(avltree.NewWithIntComparator()) + m.Put(5, "e") + m.Put(6, "f") + m.Put(7, "g") + m.Put(3, "c") + m.Put(4, "d") + m.Put(1, "x") + m.Put(2, "b") + m.Put(1, "a") //overwrite + + if actualValue := m.Size(); actualValue != 7 { + t.Errorf("Got %v expected %v", actualValue, 7) + } + if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "e", "f", "g"}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + // key,expectedValue,expectedFound + tests1 := [][]interface{}{ + {1, "a", true}, + {2, "b", true}, + {3, "c", true}, + {4, "d", true}, + {5, "e", true}, + {6, "f", true}, + {7, "g", true}, + {8, nil, false}, + } + + for _, test := range tests1 { + // retrievals + actualValue, actualFound := m.Get(test[0]) + if actualValue != test[1] || actualFound != test[2] { + t.Errorf("Got %v expected %v", actualValue, test[1]) + } + } + +} func TestMapRemove(t *testing.T) { m := NewWithIntComparator() m.Put(5, "e") diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index baa168a9..ee56cc57 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -46,7 +46,7 @@ func NewWithStringComparator() *Set { } // NewWithTree instantiates a new empty set with given tree -func NewWithTree(tree trees.Tree) (set *Set) { +func NewWithTree(tree trees.Tree) *Set { return &Set{tree: tree} } diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index f446e191..fe9cf407 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -386,6 +386,26 @@ func (t *Tree) Right() *Node { return t.bottom(1) } +// Min returns the minimum key value pair of the AVL tree +// or nils if the tree is empty. +func (t *Tree) Min() (interface{}, interface{}) { + n := t.bottom(0) + if n == nil { + return nil, nil + } + return n.Key, n.Value +} + +// Max returns the minimum key value pair of the AVL tree +// or nils if the tree is empty. +func (t *Tree) Max() (interface{}, interface{}) { + n := t.bottom(1) + if n == nil { + return nil, nil + } + return n.Key, n.Value +} + func (t *Tree) bottom(d int) *Node { n := t.Root if n == nil { diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 3c39694c..611aeae1 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -203,6 +203,26 @@ func (tree *Tree) Right() *Node { return parent } +// Min returns the minimum key value pair of the AVL tree +// or nils if the tree is empty. +func (t *Tree) Min() (interface{}, interface{}) { + n := t.Left() + if n == nil { + return nil, nil + } + return n.Key, n.Value +} + +// Max returns the minimum key value pair of the AVL tree +// or nils if the tree is empty. +func (t *Tree) Max() (interface{}, interface{}) { + n := t.Right() + if n == nil { + return nil, nil + } + return n.Key, n.Value +} + // Floor Finds floor node of the input key, return the floor node or nil if no ceiling is found. // Second return parameter is true if floor was found, otherwise false. // diff --git a/trees/trees.go b/trees/trees.go index 52b2b942..d79dcee2 100644 --- a/trees/trees.go +++ b/trees/trees.go @@ -23,6 +23,8 @@ type Tree interface { Remove(key interface{}) Get(key interface{}) (interface{}, bool) Keys() []interface{} + Min() (interface{}, interface{}) + Max() (interface{}, interface{}) containers.Container // Empty() bool From dfbd06908b8ebf28fadd92b27a2b4a0fc3ea59bd Mon Sep 17 00:00:00 2001 From: Benjamin Scher Purcell Date: Sun, 26 Feb 2017 20:14:08 -0600 Subject: [PATCH 126/320] fix golint issues --- trees/redblacktree/redblacktree.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 611aeae1..aba9866a 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -61,13 +61,13 @@ func NewWithStringComparator() *Tree { } // Comparator returns the comparator function for the tree. -func (t *Tree) Comparator() utils.Comparator { - return t.comparator +func (tree *Tree) Comparator() utils.Comparator { + return tree.comparator } // New returns a new empty tree with the same comparator. -func (t *Tree) New() trees.Tree { - return &Tree{comparator: t.comparator} +func (tree *Tree) New() trees.Tree { + return &Tree{comparator: tree.comparator} } // Put inserts node into the tree. @@ -205,8 +205,8 @@ func (tree *Tree) Right() *Node { // Min returns the minimum key value pair of the AVL tree // or nils if the tree is empty. -func (t *Tree) Min() (interface{}, interface{}) { - n := t.Left() +func (tree *Tree) Min() (interface{}, interface{}) { + n := tree.Left() if n == nil { return nil, nil } @@ -215,8 +215,8 @@ func (t *Tree) Min() (interface{}, interface{}) { // Max returns the minimum key value pair of the AVL tree // or nils if the tree is empty. -func (t *Tree) Max() (interface{}, interface{}) { - n := t.Right() +func (tree *Tree) Max() (interface{}, interface{}) { + n := tree.Right() if n == nil { return nil, nil } From 6da2e38be569da361d6eaaa5f20e7ea023e71771 Mon Sep 17 00:00:00 2001 From: Benjamin Scher Purcell Date: Sun, 26 Feb 2017 20:20:24 -0600 Subject: [PATCH 127/320] fix import paths back to emirpasic --- maps/treemap/treemap.go | 4 ++-- maps/treemap/treemap_test.go | 2 +- sets/treeset/enumerable.go | 2 +- sets/treeset/iterator.go | 2 +- sets/treeset/treeset.go | 4 ++-- sets/treeset/treeset_test.go | 2 +- trees/avltree/avltree.go | 2 +- trees/redblacktree/redblacktree.go | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index bf621977..10a3a011 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -14,8 +14,8 @@ package treemap import ( "fmt" "github.com/emirpasic/gods/maps" - rbt "github.com/spewspews/gods/trees/redblacktree" - "github.com/spewspews/gods/trees" + "github.com/emirpasic/gods/trees" + rbt "github.com/emirpasic/gods/trees/redblacktree" "github.com/emirpasic/gods/utils" "strings" ) diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 4aa3e5e4..16534407 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -8,7 +8,7 @@ import ( "fmt" "testing" - "github.com/spewspews/gods/trees/avltree" + "github.com/emirpasic/gods/trees/avltree" ) func TestMapPut(t *testing.T) { diff --git a/sets/treeset/enumerable.go b/sets/treeset/enumerable.go index db3ce9e2..6f2835e6 100644 --- a/sets/treeset/enumerable.go +++ b/sets/treeset/enumerable.go @@ -6,7 +6,7 @@ package treeset import ( "github.com/emirpasic/gods/containers" - rbt "github.com/spewspews/gods/trees/redblacktree" + rbt "github.com/emirpasic/gods/trees/redblacktree" ) func assertEnumerableImplementation() { diff --git a/sets/treeset/iterator.go b/sets/treeset/iterator.go index 9f76f66c..64b32757 100644 --- a/sets/treeset/iterator.go +++ b/sets/treeset/iterator.go @@ -6,7 +6,7 @@ package treeset import ( "github.com/emirpasic/gods/containers" - "github.com/spewspews/gods/trees" + "github.com/emirpasic/gods/trees" ) func assertIteratorImplementation() { diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index ee56cc57..99b890d4 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -14,9 +14,9 @@ import ( "strings" "github.com/emirpasic/gods/sets" + "github.com/emirpasic/gods/trees" + rbt "github.com/emirpasic/gods/trees/redblacktree" "github.com/emirpasic/gods/utils" - "github.com/spewspews/gods/trees" - rbt "github.com/spewspews/gods/trees/redblacktree" ) func assertSetImplementation() { diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index e5d5c1eb..d5fb3b23 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -8,7 +8,7 @@ import ( "fmt" "testing" - "github.com/spewspews/gods/trees/avltree" + "github.com/emirpasic/gods/trees/avltree" ) func TestSetAdd(t *testing.T) { diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index fe9cf407..0efd682f 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -12,8 +12,8 @@ import ( "io/ioutil" "log" + "github.com/emirpasic/gods/trees" "github.com/emirpasic/gods/utils" - "github.com/spewspews/gods/trees" ) func assertTreeImplementation() { diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index aba9866a..a47e3274 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -14,8 +14,8 @@ package redblacktree import ( "fmt" + "github.com/emirpasic/gods/trees" "github.com/emirpasic/gods/utils" - "github.com/spewspews/gods/trees" ) func assertTreeImplementation() { From 5507a9ec4d0fbadca73d938ba43b217b31e15bec Mon Sep 17 00:00:00 2001 From: Benjamin Scher Purcell Date: Sun, 26 Feb 2017 20:30:24 -0600 Subject: [PATCH 128/320] Revert "fix import paths back to emirpasic" The paths have to point to spewspews for the build to succeed This reverts commit 6da2e38be569da361d6eaaa5f20e7ea023e71771. --- maps/treemap/treemap.go | 4 ++-- maps/treemap/treemap_test.go | 2 +- sets/treeset/enumerable.go | 2 +- sets/treeset/iterator.go | 2 +- sets/treeset/treeset.go | 4 ++-- sets/treeset/treeset_test.go | 2 +- trees/avltree/avltree.go | 2 +- trees/redblacktree/redblacktree.go | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index 10a3a011..bf621977 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -14,8 +14,8 @@ package treemap import ( "fmt" "github.com/emirpasic/gods/maps" - "github.com/emirpasic/gods/trees" - rbt "github.com/emirpasic/gods/trees/redblacktree" + rbt "github.com/spewspews/gods/trees/redblacktree" + "github.com/spewspews/gods/trees" "github.com/emirpasic/gods/utils" "strings" ) diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 16534407..4aa3e5e4 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -8,7 +8,7 @@ import ( "fmt" "testing" - "github.com/emirpasic/gods/trees/avltree" + "github.com/spewspews/gods/trees/avltree" ) func TestMapPut(t *testing.T) { diff --git a/sets/treeset/enumerable.go b/sets/treeset/enumerable.go index 6f2835e6..db3ce9e2 100644 --- a/sets/treeset/enumerable.go +++ b/sets/treeset/enumerable.go @@ -6,7 +6,7 @@ package treeset import ( "github.com/emirpasic/gods/containers" - rbt "github.com/emirpasic/gods/trees/redblacktree" + rbt "github.com/spewspews/gods/trees/redblacktree" ) func assertEnumerableImplementation() { diff --git a/sets/treeset/iterator.go b/sets/treeset/iterator.go index 64b32757..9f76f66c 100644 --- a/sets/treeset/iterator.go +++ b/sets/treeset/iterator.go @@ -6,7 +6,7 @@ package treeset import ( "github.com/emirpasic/gods/containers" - "github.com/emirpasic/gods/trees" + "github.com/spewspews/gods/trees" ) func assertIteratorImplementation() { diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 99b890d4..ee56cc57 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -14,9 +14,9 @@ import ( "strings" "github.com/emirpasic/gods/sets" - "github.com/emirpasic/gods/trees" - rbt "github.com/emirpasic/gods/trees/redblacktree" "github.com/emirpasic/gods/utils" + "github.com/spewspews/gods/trees" + rbt "github.com/spewspews/gods/trees/redblacktree" ) func assertSetImplementation() { diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index d5fb3b23..e5d5c1eb 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -8,7 +8,7 @@ import ( "fmt" "testing" - "github.com/emirpasic/gods/trees/avltree" + "github.com/spewspews/gods/trees/avltree" ) func TestSetAdd(t *testing.T) { diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index 0efd682f..fe9cf407 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -12,8 +12,8 @@ import ( "io/ioutil" "log" - "github.com/emirpasic/gods/trees" "github.com/emirpasic/gods/utils" + "github.com/spewspews/gods/trees" ) func assertTreeImplementation() { diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index a47e3274..aba9866a 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -14,8 +14,8 @@ package redblacktree import ( "fmt" - "github.com/emirpasic/gods/trees" "github.com/emirpasic/gods/utils" + "github.com/spewspews/gods/trees" ) func assertTreeImplementation() { From b8c9d1188f4f2a1478acea6653d0f09fe3284dcb Mon Sep 17 00:00:00 2001 From: Benjamin Scher Purcell Date: Sun, 26 Feb 2017 21:00:43 -0600 Subject: [PATCH 129/320] fix travis errors --- maps/treebidimap/enumerable.go | 4 ++-- maps/treebidimap/iterator.go | 7 ++----- maps/treebidimap/treebidimap.go | 22 ++++++++++++---------- sets/treeset/enumerable.go | 7 ++----- trees/trees.go | 6 +----- 5 files changed, 19 insertions(+), 27 deletions(-) diff --git a/maps/treebidimap/enumerable.go b/maps/treebidimap/enumerable.go index d5d829ab..6ac702b8 100644 --- a/maps/treebidimap/enumerable.go +++ b/maps/treebidimap/enumerable.go @@ -21,7 +21,7 @@ func (m *Map) Each(f func(key interface{}, value interface{})) { // 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. func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) *Map { - newMap := NewWith(m.keyComparator, m.valueComparator) + newMap := NewWithTrees(m.forwardMap.New(), m.inverseMap.New()) iterator := m.Iterator() for iterator.Next() { key2, value2 := f(iterator.Key(), iterator.Value()) @@ -32,7 +32,7 @@ func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, int // Select returns a new container containing all elements for which the given function returns a true value. func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map { - newMap := NewWith(m.keyComparator, m.valueComparator) + newMap := NewWithTrees(m.forwardMap.New(), m.inverseMap.New()) iterator := m.Iterator() for iterator.Next() { if f(iterator.Key(), iterator.Value()) { diff --git a/maps/treebidimap/iterator.go b/maps/treebidimap/iterator.go index af9e27ae..83295912 100644 --- a/maps/treebidimap/iterator.go +++ b/maps/treebidimap/iterator.go @@ -4,10 +4,7 @@ package treebidimap -import ( - "github.com/emirpasic/gods/containers" - rbt "github.com/emirpasic/gods/trees/redblacktree" -) +import "github.com/emirpasic/gods/containers" func assertIteratorImplementation() { var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) @@ -15,7 +12,7 @@ func assertIteratorImplementation() { // Iterator holding the iterator's state type Iterator struct { - iterator rbt.Iterator + iterator containers.ReverseIteratorWithKey } // Iterator returns a stateful iterator whose elements are key/value pairs. diff --git a/maps/treebidimap/treebidimap.go b/maps/treebidimap/treebidimap.go index 87eff9f7..4812de67 100644 --- a/maps/treebidimap/treebidimap.go +++ b/maps/treebidimap/treebidimap.go @@ -19,10 +19,12 @@ package treebidimap import ( "fmt" + "strings" + "github.com/emirpasic/gods/maps" - "github.com/emirpasic/gods/trees/redblacktree" "github.com/emirpasic/gods/utils" - "strings" + "github.com/spewspews/gods/trees" + "github.com/spewspews/gods/trees/redblacktree" ) func assertMapImplementation() { @@ -31,10 +33,8 @@ func assertMapImplementation() { // Map holds the elements in two red-black trees. type Map struct { - forwardMap redblacktree.Tree - inverseMap redblacktree.Tree - keyComparator utils.Comparator - valueComparator utils.Comparator + forwardMap trees.Tree + inverseMap trees.Tree } type data struct { @@ -45,10 +45,8 @@ type data struct { // NewWith instantiates a bidirectional map. func NewWith(keyComparator utils.Comparator, valueComparator utils.Comparator) *Map { return &Map{ - forwardMap: *redblacktree.NewWith(keyComparator), - inverseMap: *redblacktree.NewWith(valueComparator), - keyComparator: keyComparator, - valueComparator: valueComparator, + forwardMap: redblacktree.NewWith(keyComparator), + inverseMap: redblacktree.NewWith(valueComparator), } } @@ -62,6 +60,10 @@ func NewWithStringComparators() *Map { return NewWith(utils.StringComparator, utils.StringComparator) } +func NewWithTrees(forwardTree trees.Tree, inverseTree trees.Tree) *Map { + return &Map{forwardMap: forwardTree, inverseMap: inverseTree} +} + // Put inserts element into the map. func (m *Map) Put(key interface{}, value interface{}) { if d, ok := m.forwardMap.Get(key); ok { diff --git a/sets/treeset/enumerable.go b/sets/treeset/enumerable.go index db3ce9e2..9a3cb621 100644 --- a/sets/treeset/enumerable.go +++ b/sets/treeset/enumerable.go @@ -4,10 +4,7 @@ package treeset -import ( - "github.com/emirpasic/gods/containers" - rbt "github.com/spewspews/gods/trees/redblacktree" -) +import "github.com/emirpasic/gods/containers" func assertEnumerableImplementation() { var _ containers.EnumerableWithIndex = (*Set)(nil) @@ -34,7 +31,7 @@ func (set *Set) Map(f func(index int, value interface{}) interface{}) *Set { // 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 := &Set{tree: rbt.NewWith(set.tree.Comparator())} + newSet := NewWithTree(set.tree.New()) iterator := set.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { diff --git a/trees/trees.go b/trees/trees.go index d79dcee2..4a13b836 100644 --- a/trees/trees.go +++ b/trees/trees.go @@ -9,14 +9,10 @@ // Reference: https://en.wikipedia.org/wiki/Tree_%28data_structure%29 package trees -import ( - "github.com/emirpasic/gods/containers" - "github.com/emirpasic/gods/utils" -) +import "github.com/emirpasic/gods/containers" // Tree interface that all trees implement type Tree interface { - Comparator() utils.Comparator New() Tree Iterator() containers.ReverseIteratorWithKey Put(key interface{}, value interface{}) From c49ab09deabe9ca1a110525688f86d6be6a8d2fa Mon Sep 17 00:00:00 2001 From: Benjamin Scher Purcell Date: Sun, 26 Feb 2017 21:18:37 -0600 Subject: [PATCH 130/320] fix more travis issues --- trees/binaryheap/binaryheap.go | 7 ++++--- trees/btree/btree.go | 32 ++++++++++++++++++++++++++++---- trees/btree/iterator.go | 4 ++-- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index 70b28cf5..e69d4d5d 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -13,14 +13,15 @@ package binaryheap import ( "fmt" + "strings" + + "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/lists/arraylist" - "github.com/emirpasic/gods/trees" "github.com/emirpasic/gods/utils" - "strings" ) func assertTreeImplementation() { - var _ trees.Tree = (*Heap)(nil) + var _ containers.Container = (*Heap)(nil) } // Heap holds elements in an array-list diff --git a/trees/btree/btree.go b/trees/btree/btree.go index 5f866997..9ba6f5be 100644 --- a/trees/btree/btree.go +++ b/trees/btree/btree.go @@ -19,7 +19,7 @@ package btree import ( "bytes" "fmt" - "github.com/emirpasic/gods/trees" + "github.com/spewspews/gods/trees" "github.com/emirpasic/gods/utils" "strings" ) @@ -31,7 +31,7 @@ func assertTreeImplementation() { // Tree holds elements of the B-tree type Tree struct { Root *Node // Root node - Comparator utils.Comparator // Key comparator + comparator utils.Comparator // Key comparator size int // Total number of keys in the tree m int // order (maximum number of children) } @@ -54,7 +54,7 @@ func NewWith(order int, comparator utils.Comparator) *Tree { if order < 3 { panic("Invalid order, should be at least 3") } - return &Tree{m: order, Comparator: comparator} + return &Tree{m: order, comparator: comparator} } // NewWithIntComparator instantiates a B-tree with the order (maximum number of children) and the IntComparator, i.e. keys are of type int. @@ -105,6 +105,11 @@ func (tree *Tree) Remove(key interface{}) { } } +// New returns an empty tree with the same comparator +func (tree *Tree) New() trees.Tree { + return &Tree{m: tree.m, comparator: tree.comparator} +} + // Empty returns true if tree does not contain any nodes func (tree *Tree) Empty() bool { return tree.size == 0 @@ -167,6 +172,15 @@ func (tree *Tree) LeftValue() interface{} { return nil } +// Min returns the minimum key value pair in the tree. +func (tree *Tree) Min() (interface{}, interface{}) { + n := tree.Left() + if n == nil { + return nil, nil + } + return n.Entries[0].Key, n.Entries[0].Value +} + // Right returns the right-most (max) node or nil if tree is empty. func (tree *Tree) Right() *Node { return tree.right(tree.Root) @@ -188,6 +202,16 @@ func (tree *Tree) RightValue() interface{} { return nil } +// Max returns the minimum key value pair in the tree. +func (tree *Tree) Max() (interface{}, interface{}) { + n := tree.Right() + if n == nil { + return nil, nil + } + l := len(n.Entries)-1 + return n.Entries[l].Key, n.Entries[l].Value +} + // String returns a string representation of container (for debugging purposes) func (tree *Tree) String() string { var buffer bytes.Buffer @@ -266,7 +290,7 @@ func (tree *Tree) search(node *Node, key interface{}) (index int, found bool) { var mid int for low <= high { mid = (high + low) / 2 - compare := tree.Comparator(key, node.Entries[mid].Key) + compare := tree.comparator(key, node.Entries[mid].Key) switch { case compare > 0: low = mid + 1 diff --git a/trees/btree/iterator.go b/trees/btree/iterator.go index 840db687..c01c5193 100644 --- a/trees/btree/iterator.go +++ b/trees/btree/iterator.go @@ -25,8 +25,8 @@ const ( ) // Iterator returns a stateful iterator whose elements are key/value pairs. -func (tree *Tree) Iterator() Iterator { - return Iterator{tree: tree, node: nil, position: begin} +func (tree *Tree) Iterator() containers.ReverseIteratorWithKey { + return &Iterator{tree: tree, node: nil, position: begin} } // Next moves the iterator to the next element and returns true if there was a next element in the container. From 38b9436208fb039c598de76f69056b78fc2a6805 Mon Sep 17 00:00:00 2001 From: Benjamin Scher Purcell Date: Sun, 26 Feb 2017 21:45:46 -0600 Subject: [PATCH 131/320] fix tests --- trees/avltree/avltree_test.go | 41 +++++++++---------------- trees/btree/btree_test.go | 41 +++++++++---------------- trees/redblacktree/redblacktree_test.go | 41 +++++++++---------------- 3 files changed, 45 insertions(+), 78 deletions(-) diff --git a/trees/avltree/avltree_test.go b/trees/avltree/avltree_test.go index 7af00914..2e72db3f 100644 --- a/trees/avltree/avltree_test.go +++ b/trees/avltree/avltree_test.go @@ -477,25 +477,17 @@ func TestAVLTreeIteratorBegin(t *testing.T) { tree.Put(2, "b") it := tree.Iterator() - if it.node != nil { - t.Errorf("Got %v expected %v", it.node, nil) - } - it.Begin() - if it.node != nil { - t.Errorf("Got %v expected %v", it.node, nil) - } - + i := 0 for it.Next() { + i++ } - - it.Begin() - - if it.node != nil { - t.Errorf("Got %v expected %v", it.node, nil) + if i != 3 { + t.Errorf("Got %d expected %d\n", i, tree.Size()) } + it.Begin() it.Next() if key, value := it.Key(), it.Value(); key != 1 || value != "a" { t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") @@ -504,25 +496,22 @@ func TestAVLTreeIteratorBegin(t *testing.T) { func TestAVLTreeIteratorEnd(t *testing.T) { tree := NewWithIntComparator() - it := tree.Iterator() - - if it.node != nil { - t.Errorf("Got %v expected %v", it.node, nil) - } - - it.End() - if it.node != nil { - t.Errorf("Got %v expected %v", it.node, nil) - } - tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") + it := tree.Iterator() + it.End() - if it.node != nil { - t.Errorf("Got %v expected %v", it.node, nil) + + i := 0 + for it.Prev() { + i++ + } + if i != 3 { + t.Errorf("Got %d expected %d\n", i, tree.Size()) } + it.End() it.Prev() if key, value := it.Key(), it.Value(); key != 3 || value != "c" { t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index 4705bc10..67890e61 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -929,25 +929,17 @@ func TestBTreeIteratorBegin(t *testing.T) { tree.Put(2, "b") it := tree.Iterator() - if it.node != nil { - t.Errorf("Got %v expected %v", it.node, nil) - } - it.Begin() - if it.node != nil { - t.Errorf("Got %v expected %v", it.node, nil) - } - + i := 0 for it.Next() { + i++ } - - it.Begin() - - if it.node != nil { - t.Errorf("Got %v expected %v", it.node, nil) + if i != 3 { + t.Errorf("Got %d expected %d\n", i, tree.Size()) } + it.Begin() it.Next() if key, value := it.Key(), it.Value(); key != 1 || value != "a" { t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") @@ -956,25 +948,22 @@ func TestBTreeIteratorBegin(t *testing.T) { func TestBTreeIteratorEnd(t *testing.T) { tree := NewWithIntComparator(3) - it := tree.Iterator() - - if it.node != nil { - t.Errorf("Got %v expected %v", it.node, nil) - } - - it.End() - if it.node != nil { - t.Errorf("Got %v expected %v", it.node, nil) - } - tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") + it := tree.Iterator() + it.End() - if it.node != nil { - t.Errorf("Got %v expected %v", it.node, nil) + + i := 0 + for it.Prev() { + i++ + } + if i != 3 { + t.Errorf("Got %d expected %d\n", i, tree.Size()) } + it.End() it.Prev() if key, value := it.Key(), it.Value(); key != 3 || value != "c" { t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 714defcf..f2e10b7a 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -477,25 +477,17 @@ func TestRedBlackTreeIteratorBegin(t *testing.T) { tree.Put(2, "b") it := tree.Iterator() - if it.node != nil { - t.Errorf("Got %v expected %v", it.node, nil) - } - it.Begin() - if it.node != nil { - t.Errorf("Got %v expected %v", it.node, nil) - } - + i := 0 for it.Next() { + i++ } - - it.Begin() - - if it.node != nil { - t.Errorf("Got %v expected %v", it.node, nil) + if i != 3 { + t.Errorf("Got %d expected %d\n", i, tree.Size()) } + it.Begin() it.Next() if key, value := it.Key(), it.Value(); key != 1 || value != "a" { t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") @@ -504,25 +496,22 @@ func TestRedBlackTreeIteratorBegin(t *testing.T) { func TestRedBlackTreeIteratorEnd(t *testing.T) { tree := NewWithIntComparator() - it := tree.Iterator() - - if it.node != nil { - t.Errorf("Got %v expected %v", it.node, nil) - } - - it.End() - if it.node != nil { - t.Errorf("Got %v expected %v", it.node, nil) - } - tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") + it := tree.Iterator() + it.End() - if it.node != nil { - t.Errorf("Got %v expected %v", it.node, nil) + + i := 0 + for it.Prev() { + i++ + } + if i != 3 { + t.Errorf("Got %d expected %d\n", i, tree.Size()) } + it.End() it.Prev() if key, value := it.Key(), it.Value(); key != 3 || value != "c" { t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") From 9407a8206e69f6b94c5b903bb788fb69d55eb6c8 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 3 Mar 2017 23:00:46 +0100 Subject: [PATCH 132/320] - update readme about contributions (should go into development) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a833b131..46d8afb3 100644 --- a/README.md +++ b/README.md @@ -1253,7 +1253,7 @@ This takes a while, so test within sub-packages: Biggest contribution towards this library is to use it and give us feedback for further improvements and additions. -For direct contributions, _pull request_ into master or ask to become a contributor. +For direct contributions, _pull request_ into development branch or ask to become a contributor. Coding style: From 3389248bfca5c19e184ae3d5f6404729c6739720 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 3 Mar 2017 23:24:20 +0100 Subject: [PATCH 133/320] - time comparator fmt and documentation update --- utils/comparator.go | 30 +++++++++++++++--------------- utils/comparator_test.go | 39 +++++++++++++++++++-------------------- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/utils/comparator.go b/utils/comparator.go index b5f0f79b..6a9afbf3 100644 --- a/utils/comparator.go +++ b/utils/comparator.go @@ -53,21 +53,6 @@ func IntComparator(a, b interface{}) int { } } -// TimeComparator provides a basic comparison on time.Time -func TimeComparator(a, b interface{}) int { - aAsserted := a.(time.Time) - bAsserted := b.(time.Time) - - switch { - case aAsserted.After(bAsserted) : - return 1 - case aAsserted.Before(bAsserted): - return -1 - default: - return 0 - } -} - // Int8Comparator provides a basic comparison on int8 func Int8Comparator(a, b interface{}) int { aAsserted := a.(int8) @@ -249,3 +234,18 @@ func RuneComparator(a, b interface{}) int { return 0 } } + +// TimeComparator provides a basic comparison on time.Time +func TimeComparator(a, b interface{}) int { + aAsserted := a.(time.Time) + bAsserted := b.(time.Time) + + switch { + case aAsserted.After(bAsserted): + return 1 + case aAsserted.Before(bAsserted): + return -1 + default: + return 0 + } +} diff --git a/utils/comparator_test.go b/utils/comparator_test.go index 00d028f2..40efbd37 100644 --- a/utils/comparator_test.go +++ b/utils/comparator_test.go @@ -31,20 +31,22 @@ func TestIntComparator(t *testing.T) { } } +func TestStringComparator(t *testing.T) { -func TestTimeComparator(t *testing.T) { - - now := time.Now() - - // i1,i2,expected + // s1,s2,expected tests := [][]interface{}{ - {now, now, 0}, - {now.Add(24 * 7 * 2 * time.Hour), now, 1}, - {now, now.Add(24 * 7 * 2 * time.Hour), -1}, + {"a", "a", 0}, + {"a", "b", -1}, + {"b", "a", 1}, + {"aa", "aab", -1}, + {"", "", 0}, + {"a", "", 1}, + {"", "a", -1}, + {"", "aaaaaaa", -1}, } for _, test := range tests { - actual := TimeComparator(test[0], test[1]) + actual := StringComparator(test[0], test[1]) expected := test[2] if actual != expected { t.Errorf("Got %v expected %v", actual, expected) @@ -52,22 +54,19 @@ func TestTimeComparator(t *testing.T) { } } -func TestStringComparator(t *testing.T) { +func TestTimeComparator(t *testing.T) { - // s1,s2,expected + now := time.Now() + + // i1,i2,expected tests := [][]interface{}{ - {"a", "a", 0}, - {"a", "b", -1}, - {"b", "a", 1}, - {"aa", "aab", -1}, - {"", "", 0}, - {"a", "", 1}, - {"", "a", -1}, - {"", "aaaaaaa", -1}, + {now, now, 0}, + {now.Add(24 * 7 * 2 * time.Hour), now, 1}, + {now, now.Add(24 * 7 * 2 * time.Hour), -1}, } for _, test := range tests { - actual := StringComparator(test[0], test[1]) + actual := TimeComparator(test[0], test[1]) expected := test[2] if actual != expected { t.Errorf("Got %v expected %v", actual, expected) From 9e8ccee73d6de5ce4d67b8642199b887eff1e36e Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 3 Mar 2017 23:28:12 +0100 Subject: [PATCH 134/320] - time comparator fmt and documentation update --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 1afbecd1..3ba27dfe 100644 --- a/README.md +++ b/README.md @@ -771,6 +771,8 @@ func Float64Comparator(a, b interface{}) int func ByteComparator(a, b interface{}) int func RuneComparator(a, b interface{}) int + +func TimeComparator(a, b interface{}) int ``` Writing custom comparators is easy: From cac4f90f91a5ae02621d2613785a4e6d30a5a765 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 5 Mar 2017 20:41:29 +0100 Subject: [PATCH 135/320] - move license of avl tree to root's license --- LICENSE | 20 +++++++++++++++++++- trees/avltree/LICENSE | 13 ------------- 2 files changed, 19 insertions(+), 14 deletions(-) delete mode 100644 trees/avltree/LICENSE diff --git a/LICENSE b/LICENSE index 89e196c3..e5e449b6 100644 --- a/LICENSE +++ b/LICENSE @@ -20,4 +20,22 @@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------- + +AVL Tree: + +Copyright (c) 2017 Benjamin Scher Purcell + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/trees/avltree/LICENSE b/trees/avltree/LICENSE deleted file mode 100644 index 985d32d1..00000000 --- a/trees/avltree/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright (c) 2017 Benjamin Scher Purcell - -Permission to use, copy, modify, and distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. From b5004c7e71414c2c7469c2db3a7c9d1584be44f5 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 5 Mar 2017 20:48:04 +0100 Subject: [PATCH 136/320] - fix import path --- trees/avltree/avltree.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index fe9cf407..f7c54572 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -13,7 +13,7 @@ import ( "log" "github.com/emirpasic/gods/utils" - "github.com/spewspews/gods/trees" + "github.com/emirpasic/gods/trees" ) func assertTreeImplementation() { From 6c67eb0b066158312d23594b2931b9bef5dacc80 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 5 Mar 2017 20:48:18 +0100 Subject: [PATCH 137/320] - revert some of changes coming from avl tree merge --- maps/treebidimap/enumerable.go | 4 +- maps/treebidimap/iterator.go | 7 +++- maps/treebidimap/treebidimap.go | 22 +++++------ maps/treemap/enumerable.go | 9 +++-- maps/treemap/iterator.go | 7 +++- maps/treemap/treemap.go | 20 +++++----- maps/treemap/treemap_test.go | 44 ---------------------- sets/treeset/enumerable.go | 9 +++-- sets/treeset/iterator.go | 6 +-- sets/treeset/treeset.go | 13 ++----- sets/treeset/treeset_test.go | 20 ---------- trees/binaryheap/binaryheap.go | 7 ++-- trees/btree/btree.go | 32 ++-------------- trees/btree/btree_test.go | 41 +++++++++++++-------- trees/btree/iterator.go | 12 +++--- trees/redblacktree/iterator.go | 16 ++++---- trees/redblacktree/redblacktree.go | 49 +++++-------------------- trees/redblacktree/redblacktree_test.go | 41 +++++++++++++-------- trees/trees.go | 9 ----- 19 files changed, 132 insertions(+), 236 deletions(-) diff --git a/maps/treebidimap/enumerable.go b/maps/treebidimap/enumerable.go index 6ac702b8..d5d829ab 100644 --- a/maps/treebidimap/enumerable.go +++ b/maps/treebidimap/enumerable.go @@ -21,7 +21,7 @@ func (m *Map) Each(f func(key interface{}, value interface{})) { // 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. func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) *Map { - newMap := NewWithTrees(m.forwardMap.New(), m.inverseMap.New()) + newMap := NewWith(m.keyComparator, m.valueComparator) iterator := m.Iterator() for iterator.Next() { key2, value2 := f(iterator.Key(), iterator.Value()) @@ -32,7 +32,7 @@ func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, int // Select returns a new container containing all elements for which the given function returns a true value. func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map { - newMap := NewWithTrees(m.forwardMap.New(), m.inverseMap.New()) + newMap := NewWith(m.keyComparator, m.valueComparator) iterator := m.Iterator() for iterator.Next() { if f(iterator.Key(), iterator.Value()) { diff --git a/maps/treebidimap/iterator.go b/maps/treebidimap/iterator.go index 83295912..af9e27ae 100644 --- a/maps/treebidimap/iterator.go +++ b/maps/treebidimap/iterator.go @@ -4,7 +4,10 @@ package treebidimap -import "github.com/emirpasic/gods/containers" +import ( + "github.com/emirpasic/gods/containers" + rbt "github.com/emirpasic/gods/trees/redblacktree" +) func assertIteratorImplementation() { var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) @@ -12,7 +15,7 @@ func assertIteratorImplementation() { // Iterator holding the iterator's state type Iterator struct { - iterator containers.ReverseIteratorWithKey + iterator rbt.Iterator } // Iterator returns a stateful iterator whose elements are key/value pairs. diff --git a/maps/treebidimap/treebidimap.go b/maps/treebidimap/treebidimap.go index 4812de67..87eff9f7 100644 --- a/maps/treebidimap/treebidimap.go +++ b/maps/treebidimap/treebidimap.go @@ -19,12 +19,10 @@ package treebidimap import ( "fmt" - "strings" - "github.com/emirpasic/gods/maps" + "github.com/emirpasic/gods/trees/redblacktree" "github.com/emirpasic/gods/utils" - "github.com/spewspews/gods/trees" - "github.com/spewspews/gods/trees/redblacktree" + "strings" ) func assertMapImplementation() { @@ -33,8 +31,10 @@ func assertMapImplementation() { // Map holds the elements in two red-black trees. type Map struct { - forwardMap trees.Tree - inverseMap trees.Tree + forwardMap redblacktree.Tree + inverseMap redblacktree.Tree + keyComparator utils.Comparator + valueComparator utils.Comparator } type data struct { @@ -45,8 +45,10 @@ type data struct { // NewWith instantiates a bidirectional map. func NewWith(keyComparator utils.Comparator, valueComparator utils.Comparator) *Map { return &Map{ - forwardMap: redblacktree.NewWith(keyComparator), - inverseMap: redblacktree.NewWith(valueComparator), + forwardMap: *redblacktree.NewWith(keyComparator), + inverseMap: *redblacktree.NewWith(valueComparator), + keyComparator: keyComparator, + valueComparator: valueComparator, } } @@ -60,10 +62,6 @@ func NewWithStringComparators() *Map { return NewWith(utils.StringComparator, utils.StringComparator) } -func NewWithTrees(forwardTree trees.Tree, inverseTree trees.Tree) *Map { - return &Map{forwardMap: forwardTree, inverseMap: inverseTree} -} - // Put inserts element into the map. func (m *Map) Put(key interface{}, value interface{}) { if d, ok := m.forwardMap.Get(key); ok { diff --git a/maps/treemap/enumerable.go b/maps/treemap/enumerable.go index 5f66ffb8..8cea6d00 100644 --- a/maps/treemap/enumerable.go +++ b/maps/treemap/enumerable.go @@ -4,7 +4,10 @@ package treemap -import "github.com/emirpasic/gods/containers" +import ( + "github.com/emirpasic/gods/containers" + rbt "github.com/emirpasic/gods/trees/redblacktree" +) func assertEnumerableImplementation() { var _ containers.EnumerableWithKey = (*Map)(nil) @@ -21,7 +24,7 @@ func (m *Map) Each(f func(key interface{}, value interface{})) { // 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. func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) *Map { - newMap := &Map{tree: m.tree.New()} + newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)} iterator := m.Iterator() for iterator.Next() { key2, value2 := f(iterator.Key(), iterator.Value()) @@ -32,7 +35,7 @@ func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, int // Select returns a new container containing all elements for which the given function returns a true value. func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map { - newMap := &Map{tree: m.tree.New()} + newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)} iterator := m.Iterator() for iterator.Next() { if f(iterator.Key(), iterator.Value()) { diff --git a/maps/treemap/iterator.go b/maps/treemap/iterator.go index 3de1482f..02b5c753 100644 --- a/maps/treemap/iterator.go +++ b/maps/treemap/iterator.go @@ -4,7 +4,10 @@ package treemap -import "github.com/emirpasic/gods/containers" +import ( + "github.com/emirpasic/gods/containers" + rbt "github.com/emirpasic/gods/trees/redblacktree" +) func assertIteratorImplementation() { var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) @@ -12,7 +15,7 @@ func assertIteratorImplementation() { // Iterator holding the iterator's state type Iterator struct { - iterator containers.ReverseIteratorWithKey + iterator rbt.Iterator } // Iterator returns a stateful iterator whose elements are key/value pairs. diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index bf621977..a1e58ad4 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -14,8 +14,7 @@ package treemap import ( "fmt" "github.com/emirpasic/gods/maps" - rbt "github.com/spewspews/gods/trees/redblacktree" - "github.com/spewspews/gods/trees" + rbt "github.com/emirpasic/gods/trees/redblacktree" "github.com/emirpasic/gods/utils" "strings" ) @@ -26,7 +25,7 @@ func assertMapImplementation() { // Map holds the elements in a red-black tree type Map struct { - tree trees.Tree + tree *rbt.Tree } // NewWith instantiates a tree map with the custom comparator. @@ -44,11 +43,6 @@ func NewWithStringComparator() *Map { return &Map{tree: rbt.NewWithStringComparator()} } -// NewWithTree instantiates a new empty map with given tree -func NewWithTree(tree trees.Tree) *Map { - return &Map{tree: tree} -} - // Put inserts key-value pair into the map. // Key should adhere to the comparator's type assertion, otherwise method panics. func (m *Map) Put(key interface{}, value interface{}) { @@ -96,13 +90,19 @@ func (m *Map) Clear() { // Min returns the minimum key and its value from the tree map. // Returns nil, nil if map is empty. func (m *Map) Min() (key interface{}, value interface{}) { - return m.tree.Min() + if node := m.tree.Left(); node != nil { + return node.Key, node.Value + } + return nil, nil } // Max returns the maximum key and its value from the tree map. // Returns nil, nil if map is empty. func (m *Map) Max() (key interface{}, value interface{}) { - return m.tree.Max() + if node := m.tree.Right(); node != nil { + return node.Key, node.Value + } + return nil, nil } // String returns a string representation of container diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 4aa3e5e4..0039601a 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -7,8 +7,6 @@ package treemap import ( "fmt" "testing" - - "github.com/spewspews/gods/trees/avltree" ) func TestMapPut(t *testing.T) { @@ -53,48 +51,6 @@ func TestMapPut(t *testing.T) { } } -func TestMapAVLPut(t *testing.T) { - m := NewWithTree(avltree.NewWithIntComparator()) - m.Put(5, "e") - m.Put(6, "f") - m.Put(7, "g") - m.Put(3, "c") - m.Put(4, "d") - m.Put(1, "x") - m.Put(2, "b") - m.Put(1, "a") //overwrite - - if actualValue := m.Size(); actualValue != 7 { - t.Errorf("Got %v expected %v", actualValue, 7) - } - if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "e", "f", "g"}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - - // key,expectedValue,expectedFound - tests1 := [][]interface{}{ - {1, "a", true}, - {2, "b", true}, - {3, "c", true}, - {4, "d", true}, - {5, "e", true}, - {6, "f", true}, - {7, "g", true}, - {8, nil, false}, - } - - for _, test := range tests1 { - // retrievals - actualValue, actualFound := m.Get(test[0]) - if actualValue != test[1] || actualFound != test[2] { - t.Errorf("Got %v expected %v", actualValue, test[1]) - } - } - -} func TestMapRemove(t *testing.T) { m := NewWithIntComparator() m.Put(5, "e") diff --git a/sets/treeset/enumerable.go b/sets/treeset/enumerable.go index 9a3cb621..59a0913a 100644 --- a/sets/treeset/enumerable.go +++ b/sets/treeset/enumerable.go @@ -4,7 +4,10 @@ package treeset -import "github.com/emirpasic/gods/containers" +import ( + "github.com/emirpasic/gods/containers" + rbt "github.com/emirpasic/gods/trees/redblacktree" +) func assertEnumerableImplementation() { var _ containers.EnumerableWithIndex = (*Set)(nil) @@ -21,7 +24,7 @@ func (set *Set) Each(f func(index int, value interface{})) { // 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 := &Set{tree: set.tree.New()} + newSet := &Set{tree: rbt.NewWith(set.tree.Comparator)} iterator := set.Iterator() for iterator.Next() { newSet.Add(f(iterator.Index(), iterator.Value())) @@ -31,7 +34,7 @@ func (set *Set) Map(f func(index int, value interface{}) interface{}) *Set { // 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 := NewWithTree(set.tree.New()) + newSet := &Set{tree: rbt.NewWith(set.tree.Comparator)} iterator := set.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { diff --git a/sets/treeset/iterator.go b/sets/treeset/iterator.go index 9f76f66c..2cb465f8 100644 --- a/sets/treeset/iterator.go +++ b/sets/treeset/iterator.go @@ -6,7 +6,7 @@ package treeset import ( "github.com/emirpasic/gods/containers" - "github.com/spewspews/gods/trees" + rbt "github.com/emirpasic/gods/trees/redblacktree" ) func assertIteratorImplementation() { @@ -16,8 +16,8 @@ func assertIteratorImplementation() { // Iterator returns a stateful iterator whose values can be fetched by an index. type Iterator struct { index int - iterator containers.ReverseIteratorWithKey - tree trees.Tree + iterator rbt.Iterator + tree *rbt.Tree } // Iterator holding the iterator's state diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index ee56cc57..9ead6341 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -11,12 +11,10 @@ package treeset import ( "fmt" - "strings" - "github.com/emirpasic/gods/sets" + rbt "github.com/emirpasic/gods/trees/redblacktree" "github.com/emirpasic/gods/utils" - "github.com/spewspews/gods/trees" - rbt "github.com/spewspews/gods/trees/redblacktree" + "strings" ) func assertSetImplementation() { @@ -25,7 +23,7 @@ func assertSetImplementation() { // Set holds elements in a red-black tree type Set struct { - tree trees.Tree + tree *rbt.Tree } var itemExists = struct{}{} @@ -45,11 +43,6 @@ func NewWithStringComparator() *Set { return &Set{tree: rbt.NewWithStringComparator()} } -// NewWithTree instantiates a new empty set with given tree -func NewWithTree(tree trees.Tree) *Set { - return &Set{tree: tree} -} - // Add adds the items (one or more) to the set. func (set *Set) Add(items ...interface{}) { for _, item := range items { diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index e5d5c1eb..881adc21 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -7,8 +7,6 @@ package treeset import ( "fmt" "testing" - - "github.com/spewspews/gods/trees/avltree" ) func TestSetAdd(t *testing.T) { @@ -29,24 +27,6 @@ func TestSetAdd(t *testing.T) { } } -func TestSetAVLAdd(t *testing.T) { - set := NewWithTree(avltree.NewWithIntComparator()) - 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) - } - if actualValue, expectedValue := fmt.Sprintf("%d%d%d", set.Values()...), "123"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } -} - func TestSetContains(t *testing.T) { set := NewWithIntComparator() set.Add(3, 1, 2) diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index e69d4d5d..70b28cf5 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -13,15 +13,14 @@ package binaryheap import ( "fmt" - "strings" - - "github.com/emirpasic/gods/containers" "github.com/emirpasic/gods/lists/arraylist" + "github.com/emirpasic/gods/trees" "github.com/emirpasic/gods/utils" + "strings" ) func assertTreeImplementation() { - var _ containers.Container = (*Heap)(nil) + var _ trees.Tree = (*Heap)(nil) } // Heap holds elements in an array-list diff --git a/trees/btree/btree.go b/trees/btree/btree.go index 9ba6f5be..5f866997 100644 --- a/trees/btree/btree.go +++ b/trees/btree/btree.go @@ -19,7 +19,7 @@ package btree import ( "bytes" "fmt" - "github.com/spewspews/gods/trees" + "github.com/emirpasic/gods/trees" "github.com/emirpasic/gods/utils" "strings" ) @@ -31,7 +31,7 @@ func assertTreeImplementation() { // Tree holds elements of the B-tree type Tree struct { Root *Node // Root node - comparator utils.Comparator // Key comparator + Comparator utils.Comparator // Key comparator size int // Total number of keys in the tree m int // order (maximum number of children) } @@ -54,7 +54,7 @@ func NewWith(order int, comparator utils.Comparator) *Tree { if order < 3 { panic("Invalid order, should be at least 3") } - return &Tree{m: order, comparator: comparator} + return &Tree{m: order, Comparator: comparator} } // NewWithIntComparator instantiates a B-tree with the order (maximum number of children) and the IntComparator, i.e. keys are of type int. @@ -105,11 +105,6 @@ func (tree *Tree) Remove(key interface{}) { } } -// New returns an empty tree with the same comparator -func (tree *Tree) New() trees.Tree { - return &Tree{m: tree.m, comparator: tree.comparator} -} - // Empty returns true if tree does not contain any nodes func (tree *Tree) Empty() bool { return tree.size == 0 @@ -172,15 +167,6 @@ func (tree *Tree) LeftValue() interface{} { return nil } -// Min returns the minimum key value pair in the tree. -func (tree *Tree) Min() (interface{}, interface{}) { - n := tree.Left() - if n == nil { - return nil, nil - } - return n.Entries[0].Key, n.Entries[0].Value -} - // Right returns the right-most (max) node or nil if tree is empty. func (tree *Tree) Right() *Node { return tree.right(tree.Root) @@ -202,16 +188,6 @@ func (tree *Tree) RightValue() interface{} { return nil } -// Max returns the minimum key value pair in the tree. -func (tree *Tree) Max() (interface{}, interface{}) { - n := tree.Right() - if n == nil { - return nil, nil - } - l := len(n.Entries)-1 - return n.Entries[l].Key, n.Entries[l].Value -} - // String returns a string representation of container (for debugging purposes) func (tree *Tree) String() string { var buffer bytes.Buffer @@ -290,7 +266,7 @@ func (tree *Tree) search(node *Node, key interface{}) (index int, found bool) { var mid int for low <= high { mid = (high + low) / 2 - compare := tree.comparator(key, node.Entries[mid].Key) + compare := tree.Comparator(key, node.Entries[mid].Key) switch { case compare > 0: low = mid + 1 diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index 67890e61..4705bc10 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -929,17 +929,25 @@ func TestBTreeIteratorBegin(t *testing.T) { tree.Put(2, "b") it := tree.Iterator() + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + it.Begin() - i := 0 - for it.Next() { - i++ + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) } - if i != 3 { - t.Errorf("Got %d expected %d\n", i, tree.Size()) + + for it.Next() { } it.Begin() + + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + it.Next() if key, value := it.Key(), it.Value(); key != 1 || value != "a" { t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") @@ -948,22 +956,25 @@ func TestBTreeIteratorBegin(t *testing.T) { func TestBTreeIteratorEnd(t *testing.T) { tree := NewWithIntComparator(3) - tree.Put(3, "c") - tree.Put(1, "a") - tree.Put(2, "b") it := tree.Iterator() - it.End() - - i := 0 - for it.Prev() { - i++ + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) } - if i != 3 { - t.Errorf("Got %d expected %d\n", i, tree.Size()) + + it.End() + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) } + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") it.End() + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + it.Prev() if key, value := it.Key(), it.Value(); key != 3 || value != "c" { t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") diff --git a/trees/btree/iterator.go b/trees/btree/iterator.go index c01c5193..48d24963 100644 --- a/trees/btree/iterator.go +++ b/trees/btree/iterator.go @@ -25,8 +25,8 @@ const ( ) // Iterator returns a stateful iterator whose elements are key/value pairs. -func (tree *Tree) Iterator() containers.ReverseIteratorWithKey { - return &Iterator{tree: tree, node: nil, position: begin} +func (tree *Tree) Iterator() Iterator { + return Iterator{tree: tree, node: nil, position: begin} } // Next moves the iterator to the next element and returns true if there was a next element in the container. @@ -80,11 +80,11 @@ func (iterator *Iterator) Next() bool { } } -end: + end: iterator.End() return false -between: + between: iterator.position = between return true } @@ -139,11 +139,11 @@ func (iterator *Iterator) Prev() bool { } } -begin: + begin: iterator.Begin() return false -between: + between: iterator.position = between return true } diff --git a/trees/redblacktree/iterator.go b/trees/redblacktree/iterator.go index 56bf5a5f..794e881b 100644 --- a/trees/redblacktree/iterator.go +++ b/trees/redblacktree/iterator.go @@ -24,8 +24,8 @@ const ( ) // Iterator returns a stateful iterator whose elements are key/value pairs. -func (tree *Tree) Iterator() containers.ReverseIteratorWithKey { - return &Iterator{tree: tree, node: nil, position: begin} +func (tree *Tree) Iterator() Iterator { + return Iterator{tree: tree, node: nil, position: begin} } // Next moves the iterator to the next element and returns true if there was a next element in the container. @@ -55,18 +55,18 @@ func (iterator *Iterator) Next() bool { node := iterator.node for iterator.node.Parent != nil { iterator.node = iterator.node.Parent - if iterator.tree.comparator(node.Key, iterator.node.Key) <= 0 { + if iterator.tree.Comparator(node.Key, iterator.node.Key) <= 0 { goto between } } } -end: + end: iterator.node = nil iterator.position = end return false -between: + between: iterator.position = between return true } @@ -97,18 +97,18 @@ func (iterator *Iterator) Prev() bool { node := iterator.node for iterator.node.Parent != nil { iterator.node = iterator.node.Parent - if iterator.tree.comparator(node.Key, iterator.node.Key) >= 0 { + if iterator.tree.Comparator(node.Key, iterator.node.Key) >= 0 { goto between } } } -begin: + begin: iterator.node = nil iterator.position = begin return false -between: + between: iterator.position = between return true } diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index aba9866a..f9c9bc91 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -13,9 +13,8 @@ package redblacktree import ( "fmt" - + "github.com/emirpasic/gods/trees" "github.com/emirpasic/gods/utils" - "github.com/spewspews/gods/trees" ) func assertTreeImplementation() { @@ -32,7 +31,7 @@ const ( type Tree struct { Root *Node size int - comparator utils.Comparator + Comparator utils.Comparator } // Node is a single element within the tree @@ -47,27 +46,17 @@ type Node struct { // NewWith instantiates a red-black tree with the custom comparator. func NewWith(comparator utils.Comparator) *Tree { - return &Tree{comparator: comparator} + return &Tree{Comparator: comparator} } // NewWithIntComparator instantiates a red-black tree with the IntComparator, i.e. keys are of type int. func NewWithIntComparator() *Tree { - return &Tree{comparator: utils.IntComparator} + return &Tree{Comparator: utils.IntComparator} } // NewWithStringComparator instantiates a red-black tree with the StringComparator, i.e. keys are of type string. func NewWithStringComparator() *Tree { - return &Tree{comparator: utils.StringComparator} -} - -// Comparator returns the comparator function for the tree. -func (tree *Tree) Comparator() utils.Comparator { - return tree.comparator -} - -// New returns a new empty tree with the same comparator. -func (tree *Tree) New() trees.Tree { - return &Tree{comparator: tree.comparator} + return &Tree{Comparator: utils.StringComparator} } // Put inserts node into the tree. @@ -80,7 +69,7 @@ func (tree *Tree) Put(key interface{}, value interface{}) { node := tree.Root loop := true for loop { - compare := tree.comparator(key, node.Key) + compare := tree.Comparator(key, node.Key) switch { case compare == 0: node.Key = key @@ -203,26 +192,6 @@ func (tree *Tree) Right() *Node { return parent } -// Min returns the minimum key value pair of the AVL tree -// or nils if the tree is empty. -func (tree *Tree) Min() (interface{}, interface{}) { - n := tree.Left() - if n == nil { - return nil, nil - } - return n.Key, n.Value -} - -// Max returns the minimum key value pair of the AVL tree -// or nils if the tree is empty. -func (tree *Tree) Max() (interface{}, interface{}) { - n := tree.Right() - if n == nil { - return nil, nil - } - return n.Key, n.Value -} - // Floor Finds floor node of the input key, return the floor node or nil if no ceiling is found. // Second return parameter is true if floor was found, otherwise false. // @@ -235,7 +204,7 @@ func (tree *Tree) Floor(key interface{}) (floor *Node, found bool) { found = false node := tree.Root for node != nil { - compare := tree.comparator(key, node.Key) + compare := tree.Comparator(key, node.Key) switch { case compare == 0: return node, true @@ -264,7 +233,7 @@ func (tree *Tree) Ceiling(key interface{}) (ceiling *Node, found bool) { found = false node := tree.Root for node != nil { - compare := tree.comparator(key, node.Key) + compare := tree.Comparator(key, node.Key) switch { case compare == 0: return node, true @@ -331,7 +300,7 @@ func output(node *Node, prefix string, isTail bool, str *string) { func (tree *Tree) lookup(key interface{}) *Node { node := tree.Root for node != nil { - compare := tree.comparator(key, node.Key) + compare := tree.Comparator(key, node.Key) switch { case compare == 0: return node diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index f2e10b7a..714defcf 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -477,17 +477,25 @@ func TestRedBlackTreeIteratorBegin(t *testing.T) { tree.Put(2, "b") it := tree.Iterator() + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + it.Begin() - i := 0 - for it.Next() { - i++ + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) } - if i != 3 { - t.Errorf("Got %d expected %d\n", i, tree.Size()) + + for it.Next() { } it.Begin() + + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + it.Next() if key, value := it.Key(), it.Value(); key != 1 || value != "a" { t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") @@ -496,22 +504,25 @@ func TestRedBlackTreeIteratorBegin(t *testing.T) { func TestRedBlackTreeIteratorEnd(t *testing.T) { tree := NewWithIntComparator() - tree.Put(3, "c") - tree.Put(1, "a") - tree.Put(2, "b") it := tree.Iterator() - it.End() - - i := 0 - for it.Prev() { - i++ + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) } - if i != 3 { - t.Errorf("Got %d expected %d\n", i, tree.Size()) + + it.End() + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) } + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") it.End() + if it.node != nil { + t.Errorf("Got %v expected %v", it.node, nil) + } + it.Prev() if key, value := it.Key(), it.Value(); key != 3 || value != "c" { t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") diff --git a/trees/trees.go b/trees/trees.go index 4a13b836..a5a7427d 100644 --- a/trees/trees.go +++ b/trees/trees.go @@ -13,15 +13,6 @@ import "github.com/emirpasic/gods/containers" // Tree interface that all trees implement type Tree interface { - New() Tree - Iterator() containers.ReverseIteratorWithKey - Put(key interface{}, value interface{}) - Remove(key interface{}) - Get(key interface{}) (interface{}, bool) - Keys() []interface{} - Min() (interface{}, interface{}) - Max() (interface{}, interface{}) - containers.Container // Empty() bool // Size() int From da92196c082ab169b7c0fb9b86ceb6f528c18309 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 5 Mar 2017 20:49:46 +0100 Subject: [PATCH 138/320] - update read me on merge branch (leave master, author can always change the target branch to something else before merging into master) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ba27dfe..b2f59400 100644 --- a/README.md +++ b/README.md @@ -1255,7 +1255,7 @@ This takes a while, so test within sub-packages: Biggest contribution towards this library is to use it and give us feedback for further improvements and additions. -For direct contributions, _pull request_ into development branch or ask to become a contributor. +For direct contributions, _pull request_ into master branch or ask to become a contributor. Coding style: From dbba07eb570723f92f5f03f2a7ef3c4fde059b42 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 5 Mar 2017 20:50:19 +0100 Subject: [PATCH 139/320] - go fmt/vet --- trees/avltree/avltree.go | 2 +- trees/btree/iterator.go | 8 ++++---- trees/redblacktree/iterator.go | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index f7c54572..0efd682f 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -12,8 +12,8 @@ import ( "io/ioutil" "log" - "github.com/emirpasic/gods/utils" "github.com/emirpasic/gods/trees" + "github.com/emirpasic/gods/utils" ) func assertTreeImplementation() { diff --git a/trees/btree/iterator.go b/trees/btree/iterator.go index 48d24963..840db687 100644 --- a/trees/btree/iterator.go +++ b/trees/btree/iterator.go @@ -80,11 +80,11 @@ func (iterator *Iterator) Next() bool { } } - end: +end: iterator.End() return false - between: +between: iterator.position = between return true } @@ -139,11 +139,11 @@ func (iterator *Iterator) Prev() bool { } } - begin: +begin: iterator.Begin() return false - between: +between: iterator.position = between return true } diff --git a/trees/redblacktree/iterator.go b/trees/redblacktree/iterator.go index 794e881b..90b84afe 100644 --- a/trees/redblacktree/iterator.go +++ b/trees/redblacktree/iterator.go @@ -61,12 +61,12 @@ func (iterator *Iterator) Next() bool { } } - end: +end: iterator.node = nil iterator.position = end return false - between: +between: iterator.position = between return true } @@ -103,12 +103,12 @@ func (iterator *Iterator) Prev() bool { } } - begin: +begin: iterator.node = nil iterator.position = begin return false - between: +between: iterator.position = between return true } From 6f20e11a99879867fb7349069ef5e2cf7fae1685 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 5 Mar 2017 20:54:33 +0100 Subject: [PATCH 140/320] - remove logging and panics from avl tree --- trees/avltree/avltree.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index 0efd682f..90ed692a 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -9,9 +9,6 @@ package avltree import ( "fmt" - "io/ioutil" - "log" - "github.com/emirpasic/gods/trees" "github.com/emirpasic/gods/utils" ) @@ -20,8 +17,6 @@ func assertTreeImplementation() { var _ trees.Tree = new(Tree) } -var dbgLog = log.New(ioutil.Discard, "avltree: ", log.LstdFlags) - // Tree holds elements of the AVL tree. type Tree struct { Root *Node @@ -304,23 +299,17 @@ func removeFix(c int8, t **Node) bool { } func singlerot(c int8, s *Node) *Node { - dbgLog.Printf("singlerot: enter %p:%v %d\n", s, s, c) s.b = 0 s = rotate(c, s) s.b = 0 - dbgLog.Printf("singlerot: exit %p:%v\n", s, s) return s } func doublerot(c int8, s *Node) *Node { - dbgLog.Printf("doublerot: enter %p:%v %d\n", s, s, c) a := (c + 1) / 2 r := s.c[a] s.c[a] = rotate(-c, s.c[a]) p := rotate(c, s) - if r.p != p || s.p != p { - panic("doublerot: bad parents") - } switch { default: @@ -335,12 +324,10 @@ func doublerot(c int8, s *Node) *Node { } p.b = 0 - dbgLog.Printf("doublerot: exit %p:%v\n", s, s) return p } func rotate(c int8, s *Node) *Node { - dbgLog.Printf("rotate: enter %p:%v %d\n", s, s, c) a := (c + 1) / 2 r := s.c[a] s.c[a] = r.c[a^1] @@ -350,7 +337,6 @@ func rotate(c int8, s *Node) *Node { r.c[a^1] = s r.p = s.p s.p = r - dbgLog.Printf("rotate: exit %p:%v\n", r, r) return r } From f480e9419a65f1654567b51f273dcd5111462762 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 5 Mar 2017 20:57:53 +0100 Subject: [PATCH 141/320] - simplify avl tree by exposing its comparator , i.e. del getter for comparator --- trees/avltree/avltree.go | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index 90ed692a..a0c698c8 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -21,7 +21,7 @@ func assertTreeImplementation() { type Tree struct { Root *Node size int - comparator utils.Comparator + Comparator utils.Comparator } // Node is a single element within the tree @@ -35,27 +35,22 @@ type Node struct { // NewWith instantiates an AVL tree with the custom comparator. func NewWith(comparator utils.Comparator) *Tree { - return &Tree{comparator: comparator} + return &Tree{Comparator: comparator} } // NewWithIntComparator instantiates an AVL tree with the IntComparator, i.e. keys are of type int. func NewWithIntComparator() *Tree { - return &Tree{comparator: utils.IntComparator} + return &Tree{Comparator: utils.IntComparator} } // NewWithStringComparator instantiates an AVL tree with the StringComparator, i.e. keys are of type string. func NewWithStringComparator() *Tree { - return &Tree{comparator: utils.StringComparator} -} - -// Comparator returns the comparator function for the tree. -func (t *Tree) Comparator() utils.Comparator { - return t.comparator + return &Tree{Comparator: utils.StringComparator} } // New returns a new empty tree with the same comparator. func (t *Tree) New() trees.Tree { - return &Tree{comparator: t.comparator} + return &Tree{Comparator: t.Comparator} } // Size returns the number of elements stored in the tree. @@ -80,7 +75,7 @@ func (t *Tree) Clear() { func (t *Tree) Get(key interface{}) (value interface{}, found bool) { n := t.Root for n != nil { - cmp := t.comparator(key, n.Key) + cmp := t.Comparator(key, n.Key) switch { case cmp == 0: return n.Value, true @@ -105,7 +100,7 @@ func (t *Tree) Floor(key interface{}) (floor *Node, found bool) { found = false n := t.Root for n != nil { - c := t.comparator(key, n.Key) + c := t.Comparator(key, n.Key) switch { case c == 0: return n, true @@ -134,7 +129,7 @@ func (t *Tree) Ceiling(key interface{}) (floor *Node, found bool) { found = false n := t.Root for n != nil { - c := t.comparator(key, n.Key) + c := t.Comparator(key, n.Key) switch { case c == 0: return n, true @@ -163,7 +158,7 @@ func (t *Tree) Put(key interface{}, value interface{}) { return true } - c := t.comparator(key, q.Key) + c := t.Comparator(key, q.Key) if c == 0 { q.Key = key q.Value = value @@ -197,7 +192,7 @@ func (t *Tree) Remove(key interface{}) { return false } - c := t.comparator(key, q.Key) + c := t.Comparator(key, q.Key) if c == 0 { t.size-- if q.c[1] == nil { From 59734f81644071cd2890e3b789ddeda30e8f3fae Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 5 Mar 2017 21:03:01 +0100 Subject: [PATCH 142/320] - avl tree: expose children and parent nodes, can be useful when extending structure to have access to these --- trees/avltree/avltree.go | 102 +++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index a0c698c8..11163495 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -19,18 +19,18 @@ func assertTreeImplementation() { // Tree holds elements of the AVL tree. type Tree struct { - Root *Node - size int - Comparator utils.Comparator + Root *Node // Root node + Comparator utils.Comparator // Key comparator + size int // Total number of keys in the tree } // Node is a single element within the tree type Node struct { - Key interface{} - Value interface{} - c [2]*Node - p *Node - b int8 + Key interface{} + Value interface{} + Parent *Node // Parent node + Children [2]*Node // Children nodes + b int8 } // NewWith instantiates an AVL tree with the custom comparator. @@ -80,9 +80,9 @@ func (t *Tree) Get(key interface{}) (value interface{}, found bool) { case cmp == 0: return n.Value, true case cmp < 0: - n = n.c[0] + n = n.Children[0] case cmp > 0: - n = n.c[1] + n = n.Children[1] } } return nil, false @@ -105,10 +105,10 @@ func (t *Tree) Floor(key interface{}) (floor *Node, found bool) { case c == 0: return n, true case c < 0: - n = n.c[0] + n = n.Children[0] case c > 0: floor, found = n, true - n = n.c[1] + n = n.Children[1] } } if found { @@ -135,9 +135,9 @@ func (t *Tree) Ceiling(key interface{}) (floor *Node, found bool) { return n, true case c < 0: floor, found = n, true - n = n.c[0] + n = n.Children[0] case c > 0: - n = n.c[1] + n = n.Children[1] } } if found { @@ -154,7 +154,7 @@ func (t *Tree) Put(key interface{}, value interface{}) { q := *qp if q == nil { t.size++ - *qp = &Node{Key: key, Value: value, p: p} + *qp = &Node{Key: key, Value: value, Parent: p} return true } @@ -172,7 +172,7 @@ func (t *Tree) Put(key interface{}, value interface{}) { } a := (c + 1) / 2 var fix bool - fix = put(q, &q.c[a]) + fix = put(q, &q.Children[a]) if fix { return putFix(int8(c), qp) } @@ -195,14 +195,14 @@ func (t *Tree) Remove(key interface{}) { c := t.Comparator(key, q.Key) if c == 0 { t.size-- - if q.c[1] == nil { - if q.c[0] != nil { - q.c[0].p = q.p + if q.Children[1] == nil { + if q.Children[0] != nil { + q.Children[0].Parent = q.Parent } - *qp = q.c[0] + *qp = q.Children[0] return true } - fix := removeMin(&q.c[1], &q.Key, &q.Value) + fix := removeMin(&q.Children[1], &q.Key, &q.Value) if fix { return removeFix(-1, qp) } @@ -215,7 +215,7 @@ func (t *Tree) Remove(key interface{}) { c = 1 } a := (c + 1) / 2 - fix := remove(&q.c[a]) + fix := remove(&q.Children[a]) if fix { return removeFix(int8(-c), qp) } @@ -227,16 +227,16 @@ func (t *Tree) Remove(key interface{}) { func removeMin(qp **Node, minKey *interface{}, minVal *interface{}) bool { q := *qp - if q.c[0] == nil { + if q.Children[0] == nil { *minKey = q.Key *minVal = q.Value - if q.c[1] != nil { - q.c[1].p = q.p + if q.Children[1] != nil { + q.Children[1].Parent = q.Parent } - *qp = q.c[1] + *qp = q.Children[1] return true } - fix := removeMin(&q.c[0], minKey, minVal) + fix := removeMin(&q.Children[0], minKey, minVal) if fix { return removeFix(1, qp) } @@ -255,7 +255,7 @@ func putFix(c int8, t **Node) bool { return false } - if s.c[(c+1)/2].b == c { + if s.Children[(c+1)/2].b == c { s = singlerot(c, s) } else { s = doublerot(c, s) @@ -277,14 +277,14 @@ func removeFix(c int8, t **Node) bool { } a := (c + 1) / 2 - if s.c[a].b == 0 { + if s.Children[a].b == 0 { s = rotate(c, s) s.b = -c *t = s return false } - if s.c[a].b == c { + if s.Children[a].b == c { s = singlerot(c, s) } else { s = doublerot(c, s) @@ -302,8 +302,8 @@ func singlerot(c int8, s *Node) *Node { func doublerot(c int8, s *Node) *Node { a := (c + 1) / 2 - r := s.c[a] - s.c[a] = rotate(-c, s.c[a]) + r := s.Children[a] + s.Children[a] = rotate(-c, s.Children[a]) p := rotate(c, s) switch { @@ -324,14 +324,14 @@ func doublerot(c int8, s *Node) *Node { func rotate(c int8, s *Node) *Node { a := (c + 1) / 2 - r := s.c[a] - s.c[a] = r.c[a^1] - if s.c[a] != nil { - s.c[a].p = s + r := s.Children[a] + s.Children[a] = r.Children[a^1] + if s.Children[a] != nil { + s.Children[a].Parent = s } - r.c[a^1] = s - r.p = s.p - s.p = r + r.Children[a^1] = s + r.Parent = s.Parent + s.Parent = r return r } @@ -393,7 +393,7 @@ func (t *Tree) bottom(d int) *Node { return nil } - for c := n.c[d]; c != nil; c = n.c[d] { + for c := n.Children[d]; c != nil; c = n.Children[d] { n = c } return n @@ -416,18 +416,18 @@ func (n *Node) walk1(a int) *Node { return nil } - if n.c[a] != nil { - n = n.c[a] - for n.c[a^1] != nil { - n = n.c[a^1] + if n.Children[a] != nil { + n = n.Children[a] + for n.Children[a^1] != nil { + n = n.Children[a^1] } return n } - p := n.p - for p != nil && p.c[a] == n { + p := n.Parent + for p != nil && p.Children[a] == n { n = p - p = p.p + p = p.Parent } return p } @@ -446,14 +446,14 @@ func (n *Node) String() string { } func output(node *Node, prefix string, isTail bool, str *string) { - if node.c[0] != nil { + if node.Children[0] != nil { newPrefix := prefix if isTail { newPrefix += "│ " } else { newPrefix += " " } - output(node.c[0], newPrefix, false, str) + output(node.Children[0], newPrefix, false, str) } *str += prefix if isTail { @@ -462,13 +462,13 @@ func output(node *Node, prefix string, isTail bool, str *string) { *str += "┌── " } *str += node.String() + "\n" - if node.c[1] != nil { + if node.Children[1] != nil { newPrefix := prefix if isTail { newPrefix += " " } else { newPrefix += "│ " } - output(node.c[1], newPrefix, true, str) + output(node.Children[1], newPrefix, true, str) } } From 31294e57deb707f279937caf9d429bd909bd912a Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 5 Mar 2017 21:04:53 +0100 Subject: [PATCH 143/320] - remove copy-constructor like initialization in avl tree, could be ambiguous for clients of what the output might be. an explicit initialization with explicit comparator is a lot more obvious, more code, but more obvious. --- trees/avltree/avltree.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index 11163495..d535ffc4 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -48,11 +48,6 @@ func NewWithStringComparator() *Tree { return &Tree{Comparator: utils.StringComparator} } -// New returns a new empty tree with the same comparator. -func (t *Tree) New() trees.Tree { - return &Tree{Comparator: t.Comparator} -} - // Size returns the number of elements stored in the tree. func (t *Tree) Size() int { return t.size From d6611c11d355999f2e6cba832883be196c156f44 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 5 Mar 2017 21:09:28 +0100 Subject: [PATCH 144/320] - getting rid of min/max from avl tree for now, until we figure out if these should be implemented on all trees (probably, yes) --- trees/avltree/avltree.go | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index d535ffc4..cecb0532 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -362,26 +362,6 @@ func (t *Tree) Right() *Node { return t.bottom(1) } -// Min returns the minimum key value pair of the AVL tree -// or nils if the tree is empty. -func (t *Tree) Min() (interface{}, interface{}) { - n := t.bottom(0) - if n == nil { - return nil, nil - } - return n.Key, n.Value -} - -// Max returns the minimum key value pair of the AVL tree -// or nils if the tree is empty. -func (t *Tree) Max() (interface{}, interface{}) { - n := t.bottom(1) - if n == nil { - return nil, nil - } - return n.Key, n.Value -} - func (t *Tree) bottom(d int) *Node { n := t.Root if n == nil { From 9f8722300a1673db4b176c823d32b03ba736d610 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 5 Mar 2017 21:26:42 +0100 Subject: [PATCH 145/320] - AVL tree, remove dynamic func initialization within a func, simply extract those put/remove func on its own --- trees/avltree/avltree.go | 112 +++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index cecb0532..868a0c8e 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -5,6 +5,8 @@ // Package avltree implements an AVL balanced binary tree. // // Structure is not thread safe. +// +// References: https://en.wikipedia.org/wiki/AVL_tree package avltree import ( @@ -144,80 +146,78 @@ func (t *Tree) Ceiling(key interface{}) (floor *Node, found bool) { // Put inserts node into the tree. // Key should adhere to the comparator's type assertion, otherwise method panics. func (t *Tree) Put(key interface{}, value interface{}) { - var put func(*Node, **Node) bool - put = func(p *Node, qp **Node) bool { - q := *qp - if q == nil { - t.size++ - *qp = &Node{Key: key, Value: value, Parent: p} - return true - } + t.put(key, value, nil, &t.Root) +} - c := t.Comparator(key, q.Key) - if c == 0 { - q.Key = key - q.Value = value - return false - } +func (t *Tree) put(key interface{}, value interface{}, p *Node, qp **Node) bool { + q := *qp + if q == nil { + t.size++ + *qp = &Node{Key: key, Value: value, Parent: p} + return true + } - if c < 0 { - c = -1 - } else { - c = 1 - } - a := (c + 1) / 2 - var fix bool - fix = put(q, &q.Children[a]) - if fix { - return putFix(int8(c), qp) - } + c := t.Comparator(key, q.Key) + if c == 0 { + q.Key = key + q.Value = value return false } - put(nil, &t.Root) + if c < 0 { + c = -1 + } else { + c = 1 + } + a := (c + 1) / 2 + var fix bool + fix = t.put(key, value, q, &q.Children[a]) + if fix { + return putFix(int8(c), qp) + } + return false } // Remove remove the node from the tree by key. // Key should adhere to the comparator's type assertion, otherwise method panics. func (t *Tree) Remove(key interface{}) { - var remove func(**Node) bool - remove = func(qp **Node) bool { - q := *qp - if q == nil { - return false - } + t.remove(key, &t.Root) +} - c := t.Comparator(key, q.Key) - if c == 0 { - t.size-- - if q.Children[1] == nil { - if q.Children[0] != nil { - q.Children[0].Parent = q.Parent - } - *qp = q.Children[0] - return true - } - fix := removeMin(&q.Children[1], &q.Key, &q.Value) - if fix { - return removeFix(-1, qp) - } - return false - } +func (t *Tree) remove(key interface{}, qp **Node) bool { + q := *qp + if q == nil { + return false + } - if c < 0 { - c = -1 - } else { - c = 1 + c := t.Comparator(key, q.Key) + if c == 0 { + t.size-- + if q.Children[1] == nil { + if q.Children[0] != nil { + q.Children[0].Parent = q.Parent + } + *qp = q.Children[0] + return true } - a := (c + 1) / 2 - fix := remove(&q.Children[a]) + fix := removeMin(&q.Children[1], &q.Key, &q.Value) if fix { - return removeFix(int8(-c), qp) + return removeFix(-1, qp) } return false } - remove(&t.Root) + if c < 0 { + c = -1 + } else { + c = 1 + } + a := (c + 1) / 2 + fix := t.remove(key, &q.Children[a]) + if fix { + return removeFix(int8(-c), qp) + } + return false } func removeMin(qp **Node, minKey *interface{}, minVal *interface{}) bool { From 240822f445e48bcd678e2d2e5f17fde1b3095284 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 5 Mar 2017 21:33:07 +0100 Subject: [PATCH 146/320] - avl tree: reshuffle functions around to resemble the red-black tree ordering of functions (makes it easier to maintain code of various trees) --- trees/avltree/avltree.go | 138 +++++++++++++++++++-------------------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index 868a0c8e..7da52cdd 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -50,20 +50,10 @@ func NewWithStringComparator() *Tree { return &Tree{Comparator: utils.StringComparator} } -// Size returns the number of elements stored in the tree. -func (t *Tree) Size() int { - return t.size -} - -// Empty returns true if tree does not contain any nodes. -func (t *Tree) Empty() bool { - return t.size == 0 -} - -// Clear removes all nodes from the tree. -func (t *Tree) Clear() { - t.Root = nil - t.size = 0 +// Put inserts node into the tree. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (t *Tree) Put(key interface{}, value interface{}) { + t.put(key, value, nil, &t.Root) } // Get searches the node in the tree by key and returns its value or nil if key is not found in tree. @@ -85,6 +75,54 @@ func (t *Tree) Get(key interface{}) (value interface{}, found bool) { return nil, false } +// Remove remove the node from the tree by key. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (t *Tree) Remove(key interface{}) { + t.remove(key, &t.Root) +} + +// Empty returns true if tree does not contain any nodes. +func (t *Tree) Empty() bool { + return t.size == 0 +} + +// Size returns the number of elements stored in the tree. +func (t *Tree) Size() int { + return t.size +} + +// Keys returns all keys in-order +func (t *Tree) Keys() []interface{} { + keys := make([]interface{}, t.size) + it := t.Iterator() + for i := 0; it.Next(); i++ { + keys[i] = it.Key() + } + return keys +} + +// Values returns all values in-order based on the key. +func (t *Tree) Values() []interface{} { + values := make([]interface{}, t.size) + it := t.Iterator() + for i := 0; it.Next(); i++ { + values[i] = it.Value() + } + return values +} + +// Left returns the minimum element of the AVL tree +// or nil if the tree is empty. +func (t *Tree) Left() *Node { + return t.bottom(0) +} + +// Right returns the maximum element of the AVL tree +// or nil if the tree is empty. +func (t *Tree) Right() *Node { + return t.bottom(1) +} + // Floor Finds floor node of the input key, return the floor node or nil if no ceiling is found. // Second return parameter is true if floor was found, otherwise false. // @@ -143,10 +181,23 @@ func (t *Tree) Ceiling(key interface{}) (floor *Node, found bool) { return nil, false } -// Put inserts node into the tree. -// Key should adhere to the comparator's type assertion, otherwise method panics. -func (t *Tree) Put(key interface{}, value interface{}) { - t.put(key, value, nil, &t.Root) +// Clear removes all nodes from the tree. +func (t *Tree) Clear() { + t.Root = nil + t.size = 0 +} + +// String returns a string representation of container +func (t *Tree) String() string { + str := "AVLTree\n" + if !t.Empty() { + output(t.Root, "", true, &str) + } + return str +} + +func (n *Node) String() string { + return fmt.Sprintf("%v", n.Key) } func (t *Tree) put(key interface{}, value interface{}, p *Node, qp **Node) bool { @@ -178,12 +229,6 @@ func (t *Tree) put(key interface{}, value interface{}, p *Node, qp **Node) bool return false } -// Remove remove the node from the tree by key. -// Key should adhere to the comparator's type assertion, otherwise method panics. -func (t *Tree) Remove(key interface{}) { - t.remove(key, &t.Root) -} - func (t *Tree) remove(key interface{}, qp **Node) bool { q := *qp if q == nil { @@ -330,38 +375,6 @@ func rotate(c int8, s *Node) *Node { return r } -// Keys returns all keys in-order -func (t *Tree) Keys() []interface{} { - keys := make([]interface{}, t.size) - it := t.Iterator() - for i := 0; it.Next(); i++ { - keys[i] = it.Key() - } - return keys -} - -// Values returns all values in-order based on the key. -func (t *Tree) Values() []interface{} { - values := make([]interface{}, t.size) - it := t.Iterator() - for i := 0; it.Next(); i++ { - values[i] = it.Value() - } - return values -} - -// Left returns the minimum element of the AVL tree -// or nil if the tree is empty. -func (t *Tree) Left() *Node { - return t.bottom(0) -} - -// Right returns the maximum element of the AVL tree -// or nil if the tree is empty. -func (t *Tree) Right() *Node { - return t.bottom(1) -} - func (t *Tree) bottom(d int) *Node { n := t.Root if n == nil { @@ -407,19 +420,6 @@ func (n *Node) walk1(a int) *Node { return p } -// String returns a string representation of container -func (t *Tree) String() string { - str := "AVLTree\n" - if !t.Empty() { - output(t.Root, "", true, &str) - } - return str -} - -func (n *Node) String() string { - return fmt.Sprintf("%v", n.Key) -} - func output(node *Node, prefix string, isTail bool, str *string) { if node.Children[0] != nil { newPrefix := prefix From bf32da08f23f313b1f6765e2ed9c1a46a0eb1d4a Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 5 Mar 2017 21:47:47 +0100 Subject: [PATCH 147/320] - mimicking iterator behavior as with red-black tree (copied/pasted same test from red-black tree and fixed the iterator logic) --- trees/avltree/avltree_test.go | 42 +++++++++++++--------- trees/avltree/iterator.go | 66 +++++++++++++++++++---------------- 2 files changed, 62 insertions(+), 46 deletions(-) diff --git a/trees/avltree/avltree_test.go b/trees/avltree/avltree_test.go index 2e72db3f..2e791d2a 100644 --- a/trees/avltree/avltree_test.go +++ b/trees/avltree/avltree_test.go @@ -1,4 +1,3 @@ -// Copyright (c) 2017, Benjamin Scher Purcell. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -477,17 +476,25 @@ func TestAVLTreeIteratorBegin(t *testing.T) { tree.Put(2, "b") it := tree.Iterator() + if it.Key() != nil { + t.Errorf("Got %v expected %v", it.Key(), nil) + } + it.Begin() - i := 0 - for it.Next() { - i++ + if it.Key() != nil { + t.Errorf("Got %v expected %v", it.Key(), nil) } - if i != 3 { - t.Errorf("Got %d expected %d\n", i, tree.Size()) + + for it.Next() { } it.Begin() + + if it.Key() != nil { + t.Errorf("Got %v expected %v", it.Key(), nil) + } + it.Next() if key, value := it.Key(), it.Value(); key != 1 || value != "a" { t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a") @@ -496,22 +503,25 @@ func TestAVLTreeIteratorBegin(t *testing.T) { func TestAVLTreeIteratorEnd(t *testing.T) { tree := NewWithIntComparator() - tree.Put(3, "c") - tree.Put(1, "a") - tree.Put(2, "b") it := tree.Iterator() - it.End() - - i := 0 - for it.Prev() { - i++ + if it.Key() != nil { + t.Errorf("Got %v expected %v", it.Key(), nil) } - if i != 3 { - t.Errorf("Got %d expected %d\n", i, tree.Size()) + + it.End() + if it.Key() != nil { + t.Errorf("Got %v expected %v", it.Key(), nil) } + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") it.End() + if it.Key() != nil { + t.Errorf("Got %v expected %v", it.Key(), nil) + } + it.Prev() if key, value := it.Key(), it.Value(); key != 3 || value != "c" { t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") diff --git a/trees/avltree/iterator.go b/trees/avltree/iterator.go index b61bc829..bf2ff149 100644 --- a/trees/avltree/iterator.go +++ b/trees/avltree/iterator.go @@ -32,17 +32,17 @@ func (tree *Tree) Iterator() containers.ReverseIteratorWithKey { // 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. // Modifies the state of the iterator. -func (iter *Iterator) Next() bool { - switch iter.position { +func (iterator *Iterator) Next() bool { + switch iterator.position { case begin: - iter.position = between - iter.node = iter.tree.Left() + iterator.position = between + iterator.node = iterator.tree.Left() case between: - iter.node = iter.node.Next() + iterator.node = iterator.node.Next() } - if iter.node == nil { - iter.position = end + if iterator.node == nil { + iterator.position = end return false } return true @@ -52,17 +52,17 @@ func (iter *Iterator) Next() bool { // If Prev() returns true, then next element's key and value can be retrieved by Key() and Value(). // If Prev() 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 (iter *Iterator) Prev() bool { - switch iter.position { +func (iterator *Iterator) Prev() bool { + switch iterator.position { case end: - iter.position = between - iter.node = iter.tree.Right() + iterator.position = between + iterator.node = iterator.tree.Right() case between: - iter.node = iter.node.Prev() + iterator.node = iterator.node.Prev() } - if iter.node == nil { - iter.position = begin + if iterator.node == nil { + iterator.position = begin return false } return true @@ -70,42 +70,48 @@ func (iter *Iterator) Prev() bool { // Value returns the current element's value. // Does not modify the state of the iterator. -func (iter *Iterator) Value() interface{} { - return iter.node.Value +func (iterator *Iterator) Value() interface{} { + if iterator.node == nil { + return nil + } + return iterator.node.Value } // Key returns the current element's key. // Does not modify the state of the iterator. -func (iter *Iterator) Key() interface{} { - return iter.node.Key +func (iterator *Iterator) Key() interface{} { + if iterator.node == nil { + return nil + } + return iterator.node.Key } // Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. -func (iter *Iterator) Begin() { - iter.node = nil - iter.position = begin +func (iterator *Iterator) Begin() { + iterator.node = nil + iterator.position = begin } // End moves the iterator past the last element (one-past-the-end). // Call Prev() to fetch the last element if any. -func (iter *Iterator) End() { - iter.node = nil - iter.position = end +func (iterator *Iterator) End() { + iterator.node = nil + iterator.position = 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator -func (iter *Iterator) First() bool { - iter.Begin() - return iter.Next() +func (iterator *Iterator) First() bool { + iterator.Begin() + return iterator.Next() } // 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. -func (iter *Iterator) Last() bool { - iter.End() - return iter.Prev() +func (iterator *Iterator) Last() bool { + iterator.End() + return iterator.Prev() } From 42299026d89ad42e3a248642f4429c6f6ce60516 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 5 Mar 2017 22:25:29 +0100 Subject: [PATCH 148/320] - flip the output of avl tree (swap left with right children in output to mimick the output given by red-black tree) --- trees/avltree/avltree.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index 7da52cdd..1efdae4c 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -421,14 +421,14 @@ func (n *Node) walk1(a int) *Node { } func output(node *Node, prefix string, isTail bool, str *string) { - if node.Children[0] != nil { + if node.Children[1] != nil { newPrefix := prefix if isTail { newPrefix += "│ " } else { newPrefix += " " } - output(node.Children[0], newPrefix, false, str) + output(node.Children[1], newPrefix, false, str) } *str += prefix if isTail { @@ -437,13 +437,13 @@ func output(node *Node, prefix string, isTail bool, str *string) { *str += "┌── " } *str += node.String() + "\n" - if node.Children[1] != nil { + if node.Children[0] != nil { newPrefix := prefix if isTail { newPrefix += " " } else { newPrefix += "│ " } - output(node.Children[1], newPrefix, true, str) + output(node.Children[0], newPrefix, true, str) } } From 65ced7c4221a1772721da03cce98013e147bbe27 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 5 Mar 2017 22:31:38 +0100 Subject: [PATCH 149/320] - avl tree documentation and example --- README.md | 61 +++++++++++++++++++++++++++++++++++++++++++++ examples/avltree.go | 50 +++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 examples/avltree.go diff --git a/README.md b/README.md index b2f59400..9881ceef 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Implementation of various data structures and algorithms in Go. - [TreeBidiMap](#treebidimap) - [Trees](#trees) - [RedBlackTree](#redblacktree) + - [AVLTree](#avltree) - [BTree](#btree) - [BinaryHeap](#binaryheap) - [Functions](#functions) @@ -70,6 +71,7 @@ Containers are either ordered or unordered. All ordered containers provide [stat | [HashBidiMap](#hashbidimap) | no | no | no | key* | | [TreeBidiMap](#treebidimap) | yes | yes* | yes | key* | | [RedBlackTree](#redblacktree) | yes | yes* | no | key | +| [AVLTree](#avltree) | yes | yes* | no | key | | [BTree](#btree) | yes | yes* | no | key | | [BinaryHeap](#binaryheap) | yes | yes* | no | index | | | | *reversible | | *bidirectional | @@ -589,6 +591,65 @@ func main() { Extending the red-black tree's functionality has been demonstrated in the following [example](https://github.com/emirpasic/gods/blob/master/examples/redblacktreeextended.go). +#### AVLTree + +AVL [tree](#trees) is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. Lookup, insertion, and deletion all take O(log n) time in both the average and worst cases, where n is the number of nodes in the tree prior to the operation. Insertions and deletions may require the tree to be rebalanced by one or more tree rotations. + +AVL trees are often compared with red–black trees because both support the same set of operations and take O(log n) time for the basic operations. For lookup-intensive applications, AVL trees are faster than red–black trees because they are more strictly balanced. [Wikipedia](https://en.wikipedia.org/wiki/AVL_tree) + +Implements [Tree](#trees) and [ReverseIteratorWithKey](#reverseiteratorwithkey) interfaces. + +


AVL tree with balance factors (green)

+ +```go +package main + +import ( + "fmt" + avl "github.com/emirpasic/gods/trees/avltree" +) + +func main() { + tree := avl.NewWithIntComparator() // empty(keys are of type int) + + tree.Put(1, "x") // 1->x + tree.Put(2, "b") // 1->x, 2->b (in order) + tree.Put(1, "a") // 1->a, 2->b (in order, replacement) + tree.Put(3, "c") // 1->a, 2->b, 3->c (in order) + tree.Put(4, "d") // 1->a, 2->b, 3->c, 4->d (in order) + tree.Put(5, "e") // 1->a, 2->b, 3->c, 4->d, 5->e (in order) + tree.Put(6, "f") // 1->a, 2->b, 3->c, 4->d, 5->e, 6->f (in order) + + fmt.Println(tree) + // + // AVLTree + // │ ┌── 6 + // │ ┌── 5 + // └── 4 + // │ ┌── 3 + // └── 2 + // └── 1 + + + _ = tree.Values() // []interface {}{"a", "b", "c", "d", "e", "f"} (in order) + _ = tree.Keys() // []interface {}{1, 2, 3, 4, 5, 6} (in order) + + tree.Remove(2) // 1->a, 3->c, 4->d, 5->e, 6->f (in order) + fmt.Println(tree) + // + // AVLTree + // │ ┌── 6 + // │ ┌── 5 + // └── 4 + // └── 3 + // └── 1 + + tree.Clear() // empty + tree.Empty() // true + tree.Size() // 0 +} +``` + #### BTree B-tree is a self-balancing tree data structure that keeps data sorted and allows searches, sequential access, insertions, and deletions in logarithmic time. The B-tree is a generalization of a binary search tree in that a node can have more than two children. diff --git a/examples/avltree.go b/examples/avltree.go new file mode 100644 index 00000000..bd3f96e8 --- /dev/null +++ b/examples/avltree.go @@ -0,0 +1,50 @@ +// 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 examples + +import ( + "fmt" + avl "github.com/emirpasic/gods/trees/avltree" +) + +// AVLTreeExample to demonstrate basic usage of AVLTree +func AVLTreeExample() { + tree := avl.NewWithIntComparator() // empty(keys are of type int) + + tree.Put(1, "x") // 1->x + tree.Put(2, "b") // 1->x, 2->b (in order) + tree.Put(1, "a") // 1->a, 2->b (in order, replacement) + tree.Put(3, "c") // 1->a, 2->b, 3->c (in order) + tree.Put(4, "d") // 1->a, 2->b, 3->c, 4->d (in order) + tree.Put(5, "e") // 1->a, 2->b, 3->c, 4->d, 5->e (in order) + tree.Put(6, "f") // 1->a, 2->b, 3->c, 4->d, 5->e, 6->f (in order) + + fmt.Println(tree) + // + // AVLTree + // │ ┌── 6 + // │ ┌── 5 + // └── 4 + // │ ┌── 3 + // └── 2 + // └── 1 + + _ = tree.Values() // []interface {}{"a", "b", "c", "d", "e", "f"} (in order) + _ = tree.Keys() // []interface {}{1, 2, 3, 4, 5, 6} (in order) + + tree.Remove(2) // 1->a, 3->c, 4->d, 5->e, 6->f (in order) + fmt.Println(tree) + // + // AVLTree + // │ ┌── 6 + // │ ┌── 5 + // └── 4 + // └── 3 + // └── 1 + + tree.Clear() // empty + tree.Empty() // true + tree.Size() // 0 +} From e78a91731a87b80a4972e40b4b2f44c640f8df62 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 5 Mar 2017 23:33:34 +0100 Subject: [PATCH 150/320] - Fix doubly linked list's element's prev pointer when inserting --- lists/doublylinkedlist/doublylinkedlist.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index c82575b2..bd85b184 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -259,18 +259,22 @@ func (list *List) Insert(index int, values ...interface{}) { if i == 0 { list.first = newElement } else { + newElement.prev = beforeElement beforeElement.next = newElement } beforeElement = newElement } + oldNextElement.prev = beforeElement beforeElement.next = oldNextElement } else { oldNextElement := beforeElement.next for _, value := range values { newElement := &element{value: value} + newElement.prev = beforeElement beforeElement.next = newElement beforeElement = newElement } + oldNextElement.prev = beforeElement beforeElement.next = oldNextElement } } From 0dcb10bcabf5e02c6eae40c07b586a5e4a2e7298 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 6 Mar 2017 01:05:01 +0100 Subject: [PATCH 151/320] - JSON serialization for all lists --- containers/containers.go | 2 ++ containers/serialization.go | 17 ++++++++++ lists/arraylist/arraylist_test.go | 26 ++++++++++++++++ lists/arraylist/serialization.go | 29 +++++++++++++++++ .../doublylinkedlist/doublylinkedlist_test.go | 26 ++++++++++++++++ lists/doublylinkedlist/serialization.go | 31 +++++++++++++++++++ lists/singlylinkedlist/serialization.go | 31 +++++++++++++++++++ 7 files changed, 162 insertions(+) create mode 100644 containers/serialization.go create mode 100644 lists/arraylist/serialization.go create mode 100644 lists/doublylinkedlist/serialization.go create mode 100644 lists/singlylinkedlist/serialization.go diff --git a/containers/containers.go b/containers/containers.go index 91a57c7d..c35ab36d 100644 --- a/containers/containers.go +++ b/containers/containers.go @@ -9,6 +9,8 @@ // Iterators provide stateful iterators. // // Enumerable provides Ruby inspired (each, select, map, find, any?, etc.) container functions. +// +// Serialization provides serializers (marshalers) and deserializers (unmarshalers). package containers import "github.com/emirpasic/gods/utils" diff --git a/containers/serialization.go b/containers/serialization.go new file mode 100644 index 00000000..d7c90c83 --- /dev/null +++ b/containers/serialization.go @@ -0,0 +1,17 @@ +// 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 containers + +// JSONSerializer provides JSON serialization +type JSONSerializer interface { + // ToJSON outputs the JSON representation of containers's elements. + ToJSON() ([]byte, error) +} + +// JSONDeserializer provides JSON deserialization +type JSONDeserializer interface { + // FromJSON populates containers's elements from the input JSON representation. + FromJSON([]byte) error +} diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 67317e06..58fd8b1e 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -426,6 +426,32 @@ func TestListIteratorLast(t *testing.T) { } } +func TestListSerialization(t *testing.T) { + list := New() + list.Add("a", "b", "c") + + var err error + assert := func() { + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := list.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + json, err := list.ToJSON() + assert() + + err = list.FromJSON(json) + assert() +} + func benchmarkGet(b *testing.B, list *List, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { diff --git a/lists/arraylist/serialization.go b/lists/arraylist/serialization.go new file mode 100644 index 00000000..2f283fb9 --- /dev/null +++ b/lists/arraylist/serialization.go @@ -0,0 +1,29 @@ +// 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 arraylist + +import ( + "encoding/json" + "github.com/emirpasic/gods/containers" +) + +func assertSerializationImplementation() { + var _ containers.JSONSerializer = (*List)(nil) + var _ containers.JSONDeserializer = (*List)(nil) +} + +// ToJSON outputs the JSON representation of list's elements. +func (list *List) ToJSON() ([]byte, error) { + return json.Marshal(list.elements[:list.size]) +} + +// FromJSON populates list's elements from the input JSON representation. +func (list *List) FromJSON(data []byte) error { + err := json.Unmarshal(data, &list.elements) + if err == nil { + list.size = len(list.elements) + } + return err +} diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index fa663445..5fea3d0a 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -426,6 +426,32 @@ func TestListIteratorLast(t *testing.T) { } } +func TestListSerialization(t *testing.T) { + list := New() + list.Add("a", "b", "c") + + var err error + assert := func() { + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := list.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + json, err := list.ToJSON() + assert() + + err = list.FromJSON(json) + assert() +} + func benchmarkGet(b *testing.B, list *List, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { diff --git a/lists/doublylinkedlist/serialization.go b/lists/doublylinkedlist/serialization.go new file mode 100644 index 00000000..6018d80f --- /dev/null +++ b/lists/doublylinkedlist/serialization.go @@ -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 doublylinkedlist + +import ( + "encoding/json" + "github.com/emirpasic/gods/containers" +) + +func assertSerializationImplementation() { + var _ containers.JSONSerializer = (*List)(nil) + var _ containers.JSONDeserializer = (*List)(nil) +} + +// ToJSON outputs the JSON representation of list's elements. +func (list *List) ToJSON() ([]byte, error) { + return json.Marshal(list.Values()) +} + +// FromJSON populates list's elements from the input JSON representation. +func (list *List) FromJSON(data []byte) error { + elements := []interface{}{} + err := json.Unmarshal(data, &elements) + if err == nil { + list.Clear() + list.Add(elements...) + } + return err +} diff --git a/lists/singlylinkedlist/serialization.go b/lists/singlylinkedlist/serialization.go new file mode 100644 index 00000000..324f1d9a --- /dev/null +++ b/lists/singlylinkedlist/serialization.go @@ -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 singlylinkedlist + +import ( + "encoding/json" + "github.com/emirpasic/gods/containers" +) + +func assertSerializationImplementation() { + var _ containers.JSONSerializer = (*List)(nil) + var _ containers.JSONDeserializer = (*List)(nil) +} + +// ToJSON outputs the JSON representation of list's elements. +func (list *List) ToJSON() ([]byte, error) { + return json.Marshal(list.Values()) +} + +// FromJSON populates list's elements from the input JSON representation. +func (list *List) FromJSON(data []byte) error { + elements := []interface{}{} + err := json.Unmarshal(data, &elements) + if err == nil { + list.Clear() + list.Add(elements...) + } + return err +} From 696bb0e577e405f90b4f1e508cd0b55d9bcbb91b Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 6 Mar 2017 01:12:33 +0100 Subject: [PATCH 152/320] - JSON serialization for all lists (test for singly linked list) --- .../singlylinkedlist/singlylinkedlist_test.go | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index 0a45929f..27daacc4 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -345,6 +345,32 @@ func TestListIteratorFirst(t *testing.T) { } } +func TestListSerialization(t *testing.T) { + list := New() + list.Add("a", "b", "c") + + var err error + assert := func() { + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := list.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + json, err := list.ToJSON() + assert() + + err = list.FromJSON(json) + assert() +} + func benchmarkGet(b *testing.B, list *List, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { From 50b47dce4b3f881f69c3287b868e7b1d98d77bc1 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 6 Mar 2017 01:28:09 +0100 Subject: [PATCH 153/320] - JSON serialization for all sets --- sets/hashset/hashset_test.go | 26 ++++++++++++++++++++++++++ sets/hashset/serialization.go | 31 +++++++++++++++++++++++++++++++ sets/treeset/serialization.go | 31 +++++++++++++++++++++++++++++++ sets/treeset/treeset_test.go | 26 ++++++++++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 sets/hashset/serialization.go create mode 100644 sets/treeset/serialization.go diff --git a/sets/hashset/hashset_test.go b/sets/hashset/hashset_test.go index b868631d..280a6b30 100644 --- a/sets/hashset/hashset_test.go +++ b/sets/hashset/hashset_test.go @@ -62,6 +62,32 @@ func TestSetRemove(t *testing.T) { } } +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++ { diff --git a/sets/hashset/serialization.go b/sets/hashset/serialization.go new file mode 100644 index 00000000..af7bfe8e --- /dev/null +++ b/sets/hashset/serialization.go @@ -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 hashset + +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 +} diff --git a/sets/treeset/serialization.go b/sets/treeset/serialization.go new file mode 100644 index 00000000..10b15998 --- /dev/null +++ b/sets/treeset/serialization.go @@ -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 treeset + +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 +} diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index 881adc21..0f4b667d 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -327,6 +327,32 @@ func TestSetIteratorLast(t *testing.T) { } } +func TestSetSerialization(t *testing.T) { + set := NewWithStringComparator() + 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++ { From 0887bbc9f45364c1ff57984c2103e4d6f1e6dcd4 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 6 Mar 2017 03:40:29 +0100 Subject: [PATCH 154/320] - ToString function to convert to string from any type --- utils/utils.go | 37 ++++++++++++++++ utils/utils_test.go | 104 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 utils/utils_test.go diff --git a/utils/utils.go b/utils/utils.go index 120f1a71..1ad49cbc 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -8,3 +8,40 @@ // - sorting // - comparators package utils + +import ( + "fmt" + "strconv" +) + +// ToString converts a value to string. +func ToString(value interface{}) string { + switch value.(type) { + case string: + return value.(string) + case int8: + return strconv.FormatInt(int64(value.(int8)), 10) + case int16: + return strconv.FormatInt(int64(value.(int16)), 10) + case int32: + return strconv.FormatInt(int64(value.(int32)), 10) + case int64: + return strconv.FormatInt(int64(value.(int64)), 10) + case uint8: + return strconv.FormatUint(uint64(value.(uint8)), 10) + case uint16: + return strconv.FormatUint(uint64(value.(uint16)), 10) + case uint32: + return strconv.FormatUint(uint64(value.(uint32)), 10) + case uint64: + return strconv.FormatUint(uint64(value.(uint64)), 10) + case float32: + return strconv.FormatFloat(float64(value.(float32)), 'g', -1, 64) + case float64: + return strconv.FormatFloat(float64(value.(float64)), 'g', -1, 64) + case bool: + return strconv.FormatBool(value.(bool)) + default: + return fmt.Sprintf("%+v", value) + } +} diff --git a/utils/utils_test.go b/utils/utils_test.go new file mode 100644 index 00000000..f5b3edce --- /dev/null +++ b/utils/utils_test.go @@ -0,0 +1,104 @@ +// 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 utils + +import ( + "strings" + "testing" +) + +func TestToStringInts(t *testing.T) { + var value interface{} + + value = int8(1) + if actualValue, expectedValue := ToString(value), "1"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + value = int16(1) + if actualValue, expectedValue := ToString(value), "1"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + value = int32(1) + if actualValue, expectedValue := ToString(value), "1"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + value = int64(1) + if actualValue, expectedValue := ToString(value), "1"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + value = rune(1) + if actualValue, expectedValue := ToString(value), "1"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + +func TestToStringUInts(t *testing.T) { + var value interface{} + + value = uint8(1) + if actualValue, expectedValue := ToString(value), "1"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + value = uint16(1) + if actualValue, expectedValue := ToString(value), "1"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + value = uint32(1) + if actualValue, expectedValue := ToString(value), "1"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + value = uint64(1) + if actualValue, expectedValue := ToString(value), "1"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + value = byte(1) + if actualValue, expectedValue := ToString(value), "1"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + +func TestToStringFloats(t *testing.T) { + var value interface{} + + value = float32(1.123456) + if actualValue, expectedValue := ToString(value), "1.123456"; !strings.HasPrefix(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + value = float32(1.123456) + if actualValue, expectedValue := ToString(value), "1.123456"; !strings.HasPrefix(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + +func TestToStringOther(t *testing.T) { + var value interface{} + + value = "abc" + if actualValue, expectedValue := ToString(value), "abc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + value = true + if actualValue, expectedValue := ToString(value), "true"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + type T struct { + id int + name string + } + + if actualValue, expectedValue := ToString(T{1, "abc"}), "{id:1 name:abc}"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} From 706042c8bc192ff5e6e098cb85a3b78617145615 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 6 Mar 2017 03:44:02 +0100 Subject: [PATCH 155/320] - hash map (de)serialization --- maps/hashmap/hashmap_test.go | 31 ++++++++++++++++++++++++++++ maps/hashmap/serialization.go | 38 +++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 maps/hashmap/serialization.go diff --git a/maps/hashmap/hashmap_test.go b/maps/hashmap/hashmap_test.go index 119e9edc..7122574d 100644 --- a/maps/hashmap/hashmap_test.go +++ b/maps/hashmap/hashmap_test.go @@ -118,6 +118,37 @@ func TestMapRemove(t *testing.T) { } } +func TestMapSerialization(t *testing.T) { + m := New() + m.Put("a", 1.0) + m.Put("b", 2.0) + m.Put("c", 3.0) + + var err error + assert := func() { + if actualValue, expectedValue := m.Keys(), []interface{}{"a", "b", "c"}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := m.Values(), []interface{}{1.0, 2.0, 3.0}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := m.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + json, err := m.ToJSON() + assert() + + err = m.FromJSON(json) + assert() +} + func sameElements(a []interface{}, b []interface{}) bool { if len(a) != len(b) { return false diff --git a/maps/hashmap/serialization.go b/maps/hashmap/serialization.go new file mode 100644 index 00000000..b8e9026e --- /dev/null +++ b/maps/hashmap/serialization.go @@ -0,0 +1,38 @@ +// 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 hashmap + +import ( + "encoding/json" + "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/utils" +) + +func assertSerializationImplementation() { + var _ containers.JSONSerializer = (*Map)(nil) + var _ containers.JSONDeserializer = (*Map)(nil) +} + +// ToJSON outputs the JSON representation of list's elements. +func (m *Map) ToJSON() ([]byte, error) { + elements := make(map[string]interface{}) + for key, value := range m.m { + elements[utils.ToString(key)] = value + } + return json.Marshal(&elements) +} + +// FromJSON populates list's elements from the input JSON representation. +func (m *Map) FromJSON(data []byte) error { + elements := make(map[string]interface{}) + err := json.Unmarshal(data, &elements) + if err == nil { + m.Clear() + for key, value := range elements { + m.m[key] = value + } + } + return err +} From b3ac670248db667ea35cba6571b6484ca49d52ce Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 6 Mar 2017 03:49:30 +0100 Subject: [PATCH 156/320] - all stacks (de)serialization --- stacks/arraystack/arraystack_test.go | 29 +++++++++++++++++++ stacks/arraystack/serialization.go | 22 ++++++++++++++ .../linkedliststack/linkedliststack_test.go | 29 +++++++++++++++++++ stacks/linkedliststack/serialization.go | 22 ++++++++++++++ 4 files changed, 102 insertions(+) create mode 100644 stacks/arraystack/serialization.go create mode 100644 stacks/linkedliststack/serialization.go diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index 48f6be4e..62ba7fdb 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -5,6 +5,7 @@ package arraystack import ( + "fmt" "testing" ) @@ -231,6 +232,34 @@ func TestStackIteratorLast(t *testing.T) { } } +func TestStackSerialization(t *testing.T) { + stack := New() + stack.Push("a") + stack.Push("b") + stack.Push("c") + + var err error + assert := func() { + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", stack.Values()...), "cba"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := stack.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + json, err := stack.ToJSON() + assert() + + err = stack.FromJSON(json) + assert() +} + func benchmarkPush(b *testing.B, stack *Stack, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { diff --git a/stacks/arraystack/serialization.go b/stacks/arraystack/serialization.go new file mode 100644 index 00000000..d1ad81d3 --- /dev/null +++ b/stacks/arraystack/serialization.go @@ -0,0 +1,22 @@ +// 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 arraystack + +import "github.com/emirpasic/gods/containers" + +func assertSerializationImplementation() { + var _ containers.JSONSerializer = (*Stack)(nil) + var _ containers.JSONDeserializer = (*Stack)(nil) +} + +// ToJSON outputs the JSON representation of list's elements. +func (stack *Stack) ToJSON() ([]byte, error) { + return stack.list.ToJSON() +} + +// FromJSON populates list's elements from the input JSON representation. +func (stack *Stack) FromJSON(data []byte) error { + return stack.list.FromJSON(data) +} diff --git a/stacks/linkedliststack/linkedliststack_test.go b/stacks/linkedliststack/linkedliststack_test.go index 8fb0f437..f7b6f956 100644 --- a/stacks/linkedliststack/linkedliststack_test.go +++ b/stacks/linkedliststack/linkedliststack_test.go @@ -5,6 +5,7 @@ package linkedliststack import ( + "fmt" "testing" ) @@ -147,6 +148,34 @@ func TestStackIteratorFirst(t *testing.T) { } } +func TestStackSerialization(t *testing.T) { + stack := New() + stack.Push("a") + stack.Push("b") + stack.Push("c") + + var err error + assert := func() { + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", stack.Values()...), "cba"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := stack.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + json, err := stack.ToJSON() + assert() + + err = stack.FromJSON(json) + assert() +} + func benchmarkPush(b *testing.B, stack *Stack, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { diff --git a/stacks/linkedliststack/serialization.go b/stacks/linkedliststack/serialization.go new file mode 100644 index 00000000..ac6a68c8 --- /dev/null +++ b/stacks/linkedliststack/serialization.go @@ -0,0 +1,22 @@ +// 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 linkedliststack + +import "github.com/emirpasic/gods/containers" + +func assertSerializationImplementation() { + var _ containers.JSONSerializer = (*Stack)(nil) + var _ containers.JSONDeserializer = (*Stack)(nil) +} + +// ToJSON outputs the JSON representation of list's elements. +func (stack *Stack) ToJSON() ([]byte, error) { + return stack.list.ToJSON() +} + +// FromJSON populates list's elements from the input JSON representation. +func (stack *Stack) FromJSON(data []byte) error { + return stack.list.FromJSON(data) +} From 911a9d76cfef31d4a337106453e858601c269057 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 6 Mar 2017 03:55:12 +0100 Subject: [PATCH 157/320] - hash bidi map (de)serialization --- maps/hashbidimap/hashbidimap_test.go | 31 ++++++++++++++++++++++++++ maps/hashbidimap/serialization.go | 33 ++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 maps/hashbidimap/serialization.go diff --git a/maps/hashbidimap/hashbidimap_test.go b/maps/hashbidimap/hashbidimap_test.go index 5527a033..96e46889 100644 --- a/maps/hashbidimap/hashbidimap_test.go +++ b/maps/hashbidimap/hashbidimap_test.go @@ -150,6 +150,37 @@ func TestMapGetKey(t *testing.T) { } } +func TestMapSerialization(t *testing.T) { + m := New() + m.Put("a", 1.0) + m.Put("b", 2.0) + m.Put("c", 3.0) + + var err error + assert := func() { + if actualValue, expectedValue := m.Keys(), []interface{}{"a", "b", "c"}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := m.Values(), []interface{}{1.0, 2.0, 3.0}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := m.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + json, err := m.ToJSON() + assert() + + err = m.FromJSON(json) + assert() +} + func sameElements(a []interface{}, b []interface{}) bool { if len(a) != len(b) { return false diff --git a/maps/hashbidimap/serialization.go b/maps/hashbidimap/serialization.go new file mode 100644 index 00000000..9f6247ef --- /dev/null +++ b/maps/hashbidimap/serialization.go @@ -0,0 +1,33 @@ +// 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 hashbidimap + +import ( + "encoding/json" + "github.com/emirpasic/gods/containers" +) + +func assertSerializationImplementation() { + var _ containers.JSONSerializer = (*Map)(nil) + var _ containers.JSONDeserializer = (*Map)(nil) +} + +// ToJSON outputs the JSON representation of list's elements. +func (m *Map) ToJSON() ([]byte, error) { + return m.forwardMap.ToJSON() +} + +// FromJSON populates list's elements from the input JSON representation. +func (m *Map) FromJSON(data []byte) error { + elements := make(map[string]interface{}) + err := json.Unmarshal(data, &elements) + if err == nil { + m.Clear() + for key, value := range elements { + m.Put(key, value) + } + } + return err +} From 7eadb02f45042e48774e0e4d7fd14dcfade0f103 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 6 Mar 2017 04:18:23 +0100 Subject: [PATCH 158/320] - all trees (de)serialization --- trees/avltree/avltree_test.go | 31 ++++++++++++++++++++ trees/avltree/serialization.go | 39 +++++++++++++++++++++++++ trees/binaryheap/binaryheap_test.go | 32 ++++++++++++++++++++ trees/binaryheap/serialization.go | 22 ++++++++++++++ trees/btree/btree_test.go | 31 ++++++++++++++++++++ trees/btree/serialization.go | 39 +++++++++++++++++++++++++ trees/redblacktree/redblacktree_test.go | 31 ++++++++++++++++++++ trees/redblacktree/serialization.go | 39 +++++++++++++++++++++++++ 8 files changed, 264 insertions(+) create mode 100644 trees/avltree/serialization.go create mode 100644 trees/binaryheap/serialization.go create mode 100644 trees/btree/serialization.go create mode 100644 trees/redblacktree/serialization.go diff --git a/trees/avltree/avltree_test.go b/trees/avltree/avltree_test.go index 2e791d2a..99c2adf6 100644 --- a/trees/avltree/avltree_test.go +++ b/trees/avltree/avltree_test.go @@ -556,6 +556,37 @@ func TestAVLTreeIteratorLast(t *testing.T) { } } +func TestAVLTreeSerialization(t *testing.T) { + tree := NewWithStringComparator() + tree.Put("c", "3") + tree.Put("b", "2") + tree.Put("a", "1") + + var err error + assert := func() { + if actualValue, expectedValue := tree.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := tree.Keys(); actualValue[0].(string) != "a" || actualValue[1].(string) != "b" || actualValue[2].(string) != "c" { + t.Errorf("Got %v expected %v", actualValue, "[a,b,c]") + } + if actualValue := tree.Values(); actualValue[0].(string) != "1" || actualValue[1].(string) != "2" || actualValue[2].(string) != "3" { + t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + json, err := tree.ToJSON() + assert() + + err = tree.FromJSON(json) + assert() +} + func benchmarkGet(b *testing.B, tree *Tree, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { diff --git a/trees/avltree/serialization.go b/trees/avltree/serialization.go new file mode 100644 index 00000000..0630d877 --- /dev/null +++ b/trees/avltree/serialization.go @@ -0,0 +1,39 @@ +// 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 avltree + +import ( + "encoding/json" + "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/utils" +) + +func assertSerializationImplementation() { + var _ containers.JSONSerializer = (*Tree)(nil) + var _ containers.JSONDeserializer = (*Tree)(nil) +} + +// ToJSON outputs the JSON representation of list's elements. +func (tree *Tree) ToJSON() ([]byte, error) { + elements := make(map[string]interface{}) + it := tree.Iterator() + for it.Next() { + elements[utils.ToString(it.Key())] = it.Value() + } + return json.Marshal(&elements) +} + +// FromJSON populates list's elements from the input JSON representation. +func (tree *Tree) FromJSON(data []byte) error { + elements := make(map[string]interface{}) + err := json.Unmarshal(data, &elements) + if err == nil { + tree.Clear() + for key, value := range elements { + tree.Put(key, value) + } + } + return err +} diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go index a20d6471..cf978137 100644 --- a/trees/binaryheap/binaryheap_test.go +++ b/trees/binaryheap/binaryheap_test.go @@ -259,6 +259,38 @@ func TestBinaryHeapIteratorLast(t *testing.T) { } } +func TestBinaryHeapSerialization(t *testing.T) { + heap := NewWithStringComparator() + + heap.Push("c") // ["c"] + heap.Push("b") // ["b","c"] + heap.Push("a") // ["a","c","b"]("b" swapped with "a", hence last) + + var err error + assert := func() { + if actualValue := heap.Values(); actualValue[0].(string) != "a" || actualValue[1].(string) != "c" || actualValue[2].(string) != "b" { + t.Errorf("Got %v expected %v", actualValue, "[1,3,2]") + } + if actualValue := heap.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := heap.Peek(); actualValue != "a" || !ok { + t.Errorf("Got %v expected %v", actualValue, "a") + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + json, err := heap.ToJSON() + assert() + + err = heap.FromJSON(json) + assert() +} + func benchmarkPush(b *testing.B, heap *Heap, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { diff --git a/trees/binaryheap/serialization.go b/trees/binaryheap/serialization.go new file mode 100644 index 00000000..299319bd --- /dev/null +++ b/trees/binaryheap/serialization.go @@ -0,0 +1,22 @@ +// 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 binaryheap + +import "github.com/emirpasic/gods/containers" + +func assertSerializationImplementation() { + var _ containers.JSONSerializer = (*Heap)(nil) + var _ containers.JSONDeserializer = (*Heap)(nil) +} + +// ToJSON outputs the JSON representation of list's elements. +func (heap *Heap) ToJSON() ([]byte, error) { + return heap.list.ToJSON() +} + +// FromJSON populates list's elements from the input JSON representation. +func (heap *Heap) FromJSON(data []byte) error { + return heap.list.FromJSON(data) +} diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index 4705bc10..4d69665b 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -1074,6 +1074,37 @@ func assertValidTreeNode(t *testing.T, node *Node, expectedEntries int, expected } } +func TestBTreeSerialization(t *testing.T) { + tree := NewWithStringComparator(3) + tree.Put("c", "3") + tree.Put("b", "2") + tree.Put("a", "1") + + var err error + assert := func() { + if actualValue, expectedValue := tree.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := tree.Keys(); actualValue[0].(string) != "a" || actualValue[1].(string) != "b" || actualValue[2].(string) != "c" { + t.Errorf("Got %v expected %v", actualValue, "[a,b,c]") + } + if actualValue := tree.Values(); actualValue[0].(string) != "1" || actualValue[1].(string) != "2" || actualValue[2].(string) != "3" { + t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + json, err := tree.ToJSON() + assert() + + err = tree.FromJSON(json) + assert() +} + func benchmarkGet(b *testing.B, tree *Tree, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { diff --git a/trees/btree/serialization.go b/trees/btree/serialization.go new file mode 100644 index 00000000..95c817e1 --- /dev/null +++ b/trees/btree/serialization.go @@ -0,0 +1,39 @@ +// 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 btree + +import ( + "encoding/json" + "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/utils" +) + +func assertSerializationImplementation() { + var _ containers.JSONSerializer = (*Tree)(nil) + var _ containers.JSONDeserializer = (*Tree)(nil) +} + +// ToJSON outputs the JSON representation of list's elements. +func (tree *Tree) ToJSON() ([]byte, error) { + elements := make(map[string]interface{}) + it := tree.Iterator() + for it.Next() { + elements[utils.ToString(it.Key())] = it.Value() + } + return json.Marshal(&elements) +} + +// FromJSON populates list's elements from the input JSON representation. +func (tree *Tree) FromJSON(data []byte) error { + elements := make(map[string]interface{}) + err := json.Unmarshal(data, &elements) + if err == nil { + tree.Clear() + for key, value := range elements { + tree.Put(key, value) + } + } + return err +} diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 714defcf..74c3d8a0 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -557,6 +557,37 @@ func TestRedBlackTreeIteratorLast(t *testing.T) { } } +func TestRedBlackTreeSerialization(t *testing.T) { + tree := NewWithStringComparator() + tree.Put("c", "3") + tree.Put("b", "2") + tree.Put("a", "1") + + var err error + assert := func() { + if actualValue, expectedValue := tree.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := tree.Keys(); actualValue[0].(string) != "a" || actualValue[1].(string) != "b" || actualValue[2].(string) != "c" { + t.Errorf("Got %v expected %v", actualValue, "[a,b,c]") + } + if actualValue := tree.Values(); actualValue[0].(string) != "1" || actualValue[1].(string) != "2" || actualValue[2].(string) != "3" { + t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + json, err := tree.ToJSON() + assert() + + err = tree.FromJSON(json) + assert() +} + func benchmarkGet(b *testing.B, tree *Tree, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { diff --git a/trees/redblacktree/serialization.go b/trees/redblacktree/serialization.go new file mode 100644 index 00000000..7969fc55 --- /dev/null +++ b/trees/redblacktree/serialization.go @@ -0,0 +1,39 @@ +// 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 redblacktree + +import ( + "encoding/json" + "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/utils" +) + +func assertSerializationImplementation() { + var _ containers.JSONSerializer = (*Tree)(nil) + var _ containers.JSONDeserializer = (*Tree)(nil) +} + +// ToJSON outputs the JSON representation of list's elements. +func (tree *Tree) ToJSON() ([]byte, error) { + elements := make(map[string]interface{}) + it := tree.Iterator() + for it.Next() { + elements[utils.ToString(it.Key())] = it.Value() + } + return json.Marshal(&elements) +} + +// FromJSON populates list's elements from the input JSON representation. +func (tree *Tree) FromJSON(data []byte) error { + elements := make(map[string]interface{}) + err := json.Unmarshal(data, &elements) + if err == nil { + tree.Clear() + for key, value := range elements { + tree.Put(key, value) + } + } + return err +} From 232f8d8a62b386dd2a8a51880b7162f31b84ee23 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 6 Mar 2017 04:35:57 +0100 Subject: [PATCH 159/320] - tree-map and tree-bidi-map (de)serialization --- maps/treebidimap/serialization.go | 39 ++++++++++++++++++++++++++++ maps/treebidimap/treebidimap_test.go | 31 ++++++++++++++++++++++ maps/treemap/serialization.go | 22 ++++++++++++++++ maps/treemap/treemap_test.go | 31 ++++++++++++++++++++++ 4 files changed, 123 insertions(+) create mode 100644 maps/treebidimap/serialization.go create mode 100644 maps/treemap/serialization.go diff --git a/maps/treebidimap/serialization.go b/maps/treebidimap/serialization.go new file mode 100644 index 00000000..f9a78507 --- /dev/null +++ b/maps/treebidimap/serialization.go @@ -0,0 +1,39 @@ +// 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 treebidimap + +import ( + "encoding/json" + "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/utils" +) + +func assertSerializationImplementation() { + var _ containers.JSONSerializer = (*Map)(nil) + var _ containers.JSONDeserializer = (*Map)(nil) +} + +// ToJSON outputs the JSON representation of list's elements. +func (m *Map) ToJSON() ([]byte, error) { + elements := make(map[string]interface{}) + it := m.Iterator() + for it.Next() { + elements[utils.ToString(it.Key())] = it.Value() + } + return json.Marshal(&elements) +} + +// FromJSON populates list's elements from the input JSON representation. +func (m *Map) FromJSON(data []byte) error { + elements := make(map[string]interface{}) + err := json.Unmarshal(data, &elements) + if err == nil { + m.Clear() + for key, value := range elements { + m.Put(key, value) + } + } + return err +} diff --git a/maps/treebidimap/treebidimap_test.go b/maps/treebidimap/treebidimap_test.go index c504e97f..0ef5165f 100644 --- a/maps/treebidimap/treebidimap_test.go +++ b/maps/treebidimap/treebidimap_test.go @@ -473,6 +473,37 @@ func TestMapIteratorLast(t *testing.T) { } } +func TestMapSerialization(t *testing.T) { + m := NewWithStringComparators() + m.Put("a", "1") + m.Put("b", "2") + m.Put("c", "3") + + var err error + assert := func() { + if actualValue := m.Keys(); actualValue[0].(string) != "a" || actualValue[1].(string) != "b" || actualValue[2].(string) != "c" { + t.Errorf("Got %v expected %v", actualValue, "[a,b,c]") + } + if actualValue := m.Values(); actualValue[0].(string) != "1" || actualValue[1].(string) != "2" || actualValue[2].(string) != "3" { + t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + } + if actualValue, expectedValue := m.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + json, err := m.ToJSON() + assert() + + err = m.FromJSON(json) + assert() +} + func benchmarkGet(b *testing.B, m *Map, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { diff --git a/maps/treemap/serialization.go b/maps/treemap/serialization.go new file mode 100644 index 00000000..25f4a6fd --- /dev/null +++ b/maps/treemap/serialization.go @@ -0,0 +1,22 @@ +// 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 treemap + +import "github.com/emirpasic/gods/containers" + +func assertSerializationImplementation() { + var _ containers.JSONSerializer = (*Map)(nil) + var _ containers.JSONDeserializer = (*Map)(nil) +} + +// ToJSON outputs the JSON representation of list's elements. +func (m *Map) ToJSON() ([]byte, error) { + return m.tree.ToJSON() +} + +// FromJSON populates list's elements from the input JSON representation. +func (m *Map) FromJSON(data []byte) error { + return m.tree.FromJSON(data) +} diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 0039601a..a73e8734 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -440,6 +440,37 @@ func TestMapIteratorLast(t *testing.T) { } } +func TestMapSerialization(t *testing.T) { + m := NewWithStringComparator() + m.Put("a", "1") + m.Put("b", "2") + m.Put("c", "3") + + var err error + assert := func() { + if actualValue := m.Keys(); actualValue[0].(string) != "a" || actualValue[1].(string) != "b" || actualValue[2].(string) != "c" { + t.Errorf("Got %v expected %v", actualValue, "[a,b,c]") + } + if actualValue := m.Values(); actualValue[0].(string) != "1" || actualValue[1].(string) != "2" || actualValue[2].(string) != "3" { + t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + } + if actualValue, expectedValue := m.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + json, err := m.ToJSON() + assert() + + err = m.FromJSON(json) + assert() +} + func benchmarkGet(b *testing.B, m *Map, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { From 42d0c04ae7629ca4645c4d548f9335396229a2ff Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 6 Mar 2017 04:58:03 +0100 Subject: [PATCH 160/320] - serialization example --- examples/serialization.go | 51 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 examples/serialization.go diff --git a/examples/serialization.go b/examples/serialization.go new file mode 100644 index 00000000..72a1ebf4 --- /dev/null +++ b/examples/serialization.go @@ -0,0 +1,51 @@ +package examples + +import ( + "fmt" + "github.com/emirpasic/gods/lists/arraylist" + "github.com/emirpasic/gods/maps/hashmap" +) + +// ListSerializationExample demonstrates how to serialize and deserialize lists to and from JSON +func ListSerializationExample() { + list := arraylist.New() + list.Add("a", "b", "c") + + // Serialization (marshalling) + json, err := list.ToJSON() + if err != nil { + fmt.Println(err) + } + fmt.Println(string(json)) // ["a","b","c"] + + // Deserialization (unmarshalling) + json = []byte(`["a","b"]`) + err = list.FromJSON(json) + if err != nil { + fmt.Println(err) + } + fmt.Println(list) // ArrayList ["a","b"] +} + +// MapSerializationExample demonstrates how to serialize and deserialize maps to and from JSON +func MapSerializationExample() { + m := hashmap.New() + m.Put("a", "1") + m.Put("b", "2") + m.Put("c", "3") + + // Serialization (marshalling) + json, err := m.ToJSON() + if err != nil { + fmt.Println(err) + } + fmt.Println(string(json)) // {"a":"1","b":"2","c":"3"} + + // Deserialization (unmarshalling) + json = []byte(`{"a":"1","b":"2"}`) + err = m.FromJSON(json) + if err != nil { + fmt.Println(err) + } + fmt.Println(m) // HashMap {"a":"1","b":"2"} +} From 2752136e4c76b410502ff5979067ea7a2c95b960 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 6 Mar 2017 05:18:15 +0100 Subject: [PATCH 161/320] - update documentation on serialization --- README.md | 130 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 115 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 9881ceef..cdc1830e 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,9 @@ Implementation of various data structures and algorithms in Go. - [Enumerable](#enumerable) - [EnumerableWithIndex](#enumerablewithindex) - [EnumerableWithKey](#enumerablewithkey) + - [Serialization](#serialization) + - [JSONSerializer](#jsonserializer) + - [JSONDeserializer](#jsondeserializer) - [Sort](#sort) - [Container](#container) - [Appendix](#appendix) @@ -104,7 +107,7 @@ type List interface { A [list](#lists) backed by a dynamic array that grows and shrinks implicitly. -Implements [List](#lists), [IteratorWithIndex](#iteratorwithindex) and [EnumerableWithIndex](#enumerablewithindex) interfaces. +Implements [List](#lists), [IteratorWithIndex](#iteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -141,7 +144,7 @@ func main() { A [list](#lists) where each element points to the next element in the list. -Implements [List](#lists), [IteratorWithIndex](#iteratorwithindex) and [EnumerableWithIndex](#enumerablewithindex) interfaces. +Implements [List](#lists), [IteratorWithIndex](#iteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -178,7 +181,7 @@ func main() { A [list](#lists) where each element points to the next and previous elements in the list. -Implements [List](#lists), [IteratorWithIndex](#iteratorwithindex) and [EnumerableWithIndex](#enumerablewithindex) interfaces. +Implements [List](#lists), [IteratorWithIndex](#iteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -235,7 +238,7 @@ type Set interface { A [set](#sets) backed by a hash table (actually a Go's map). It makes no guarantees as to the iteration order of the set. -Implements [Set](#sets) interface. +Implements [Set](#sets), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -262,7 +265,7 @@ func main() { A [set](#sets) backed by a [red-black tree](#redblacktree) to keep the elements ordered with respect to the [comparator](#comparator). -Implements [Set](#sets), [IteratorWithIndex](#iteratorwithindex) and [EnumerableWithIndex](#enumerablewithindex) interfaces. +Implements [Set](#sets), [IteratorWithIndex](#iteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -309,7 +312,7 @@ type Stack interface { A [stack](#stacks) based on a [linked list](#singlylinkedlist). -Implements [Stack](#stacks) and [IteratorWithIndex](#iteratorwithindex) interfaces. +Implements [Stack](#stacks), [IteratorWithIndex](#iteratorwithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -336,7 +339,7 @@ func main() { A [stack](#stacks) based on a [array list](#arraylist). -Implements [Stack](#stacks) and [IteratorWithIndex](#iteratorwithindex) interfaces. +Implements [Stack](#stacks), [IteratorWithIndex](#iteratorwithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -394,7 +397,7 @@ type BidiMap interface { A [map](#maps) based on hash tables. Keys are unordered. -Implements [Map](#maps) interface. +Implements [Map](#maps), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -421,7 +424,7 @@ func main() { A [map](#maps) based on [red-black tree](#redblacktree). Keys are ordered ordered with respect to the [comparator](#comparator). -Implements [Map](#maps), [IteratorWithKey](#iteratorwithkey) and [EnumerableWithKey](#enumerablewithkey) interfaces. +Implements [Map](#maps), [IteratorWithKey](#iteratorwithkey), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -452,7 +455,7 @@ func main() { A [map](#maps) based on two hashmaps. Keys are unordered. -Implements [BidiMap](#maps) interface. +Implements [BidiMap](#maps), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -481,7 +484,7 @@ func main() { A [map](#maps) based on red-black tree. This map guarantees that the map will be in both ascending key and value order. Other than key and value ordering, the goal with this structure is to avoid duplication of elements (unlike in [HashBidiMap](#hashbidimap)), which can be significant if contained elements are large. -Implements [BidiMap](#maps), [IteratorWithKey](#iteratorwithkey) and [EnumerableWithKey](#enumerablewithkey) interfaces. +Implements [BidiMap](#maps), [IteratorWithKey](#iteratorwithkey), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -531,7 +534,7 @@ A red–black [tree](#trees) is a binary search tree with an extra bit of data p The balancing of the tree is not perfect but it is good enough to allow it to guarantee searching in O(log n) time, where n is the total number of elements in the tree. The insertion and deletion operations, along with the tree rearrangement and recoloring, are also performed in O(log n) time. [Wikipedia](http://en.wikipedia.org/wiki/Red%E2%80%93black_tree) -Implements [Tree](#trees) and [ReverseIteratorWithKey](#reverseiteratorwithkey) interfaces. +Implements [Tree](#trees), [ReverseIteratorWithKey](#reverseiteratorwithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.

@@ -597,7 +600,7 @@ AVL [tree](#trees) is a self-balancing binary search tree. In an AVL tree, the h AVL trees are often compared with red–black trees because both support the same set of operations and take O(log n) time for the basic operations. For lookup-intensive applications, AVL trees are faster than red–black trees because they are more strictly balanced. [Wikipedia](https://en.wikipedia.org/wiki/AVL_tree) -Implements [Tree](#trees) and [ReverseIteratorWithKey](#reverseiteratorwithkey) interfaces. +Implements [Tree](#trees), [ReverseIteratorWithKey](#reverseiteratorwithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.


AVL tree with balance factors (green)

@@ -664,7 +667,7 @@ According to Knuth's definition, a B-tree of order m is a tree which satisfies t Each internal node’s keys act as separation values which divide its subtrees. For example, if an internal node has 3 child nodes (or subtrees) then it must have 2 keys: a1 and a2. All values in the leftmost subtree will be less than a1, all values in the middle subtree will be between a1 and a2, and all values in the rightmost subtree will be greater than a2.[Wikipedia](http://en.wikipedia.org/wiki/Red%E2%80%93black_tree) -Implements [Tree](#trees) and [ReverseIteratorWithKey](#reverseiteratorwithkey) interfaces. +Implements [Tree](#trees), [ReverseIteratorWithKey](#reverseiteratorwithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.

@@ -736,7 +739,7 @@ A binary heap is a [tree](#trees) created using a binary tree. It can be seen as All nodes are either greater than or equal to or less than or equal to each of its children, according to a comparison predicate defined for the heap. [Wikipedia](http://en.wikipedia.org/wiki/Binary_heap) -Implements [Tree](#trees) and [ReverseIteratorWithIndex](#reverseiteratorwithindex) interfaces. +Implements [Tree](#trees), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.

@@ -1214,6 +1217,103 @@ func main() { } ``` +### Serialization + +All data structures can be serialized (marshalled) and deserialized (unmarshalled). Currently only JSON support is available. + +#### JSONSerializer + +Outputs the container into its JSON representation. + +Typical usage for key-value structures: +```go +package main + +import ( + "fmt" + "github.com/emirpasic/gods/maps/hashmap" +) + +func main() { + m := hashmap.New() + m.Put("a", "1") + m.Put("b", "2") + m.Put("c", "3") + + json, err := m.ToJSON() + if err != nil { + fmt.Println(err) + } + fmt.Println(string(json)) // {"a":"1","b":"2","c":"3"} +``` + +Typical usage for value-only structures: +```go +package main + +import ( + "fmt" + "github.com/emirpasic/gods/lists/arraylist" +) + +func main() { + list := arraylist.New() + list.Add("a", "b", "c") + + json, err := list.ToJSON() + if err != nil { + fmt.Println(err) + } + fmt.Println(string(json)) // ["a","b","c"] +} +``` + +#### JSONDeserializer + +Populates the container with elements from the input JSON representation. + +Typical usage for key-value structures: +```go +package main + +import ( + "fmt" + "github.com/emirpasic/gods/lists/arraylist" +) + +func main() { + list := arraylist.New() + + json := []byte(`["a","b"]`) + err := list.FromJSON(json) + if err != nil { + fmt.Println(err) + } + fmt.Println(list) // ArrayList ["a","b"] +} +``` + +Typical usage for value-only structures: +```go +package main + +import ( + "fmt" + "github.com/emirpasic/gods/lists/arraylist" +) + +func main() { + list := arraylist.New() + list.Add("a", "b", "c") + + json, err := list.ToJSON() + if err != nil { + fmt.Println(err) + } + fmt.Println(string(json)) // ["a","b","c"] +} +``` + ### Sort Sort is a general purpose sort function. From febc429423db72ef7baf54adbd6bbec4e383fb62 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 6 Mar 2017 05:23:07 +0100 Subject: [PATCH 162/320] - update documentation on serialization --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cdc1830e..f9b415e0 100644 --- a/README.md +++ b/README.md @@ -1304,13 +1304,13 @@ import ( func main() { list := arraylist.New() - list.Add("a", "b", "c") - json, err := list.ToJSON() + json := []byte(`["a","b"]`) + err := list.FromJSON(json) if err != nil { fmt.Println(err) } - fmt.Println(string(json)) // ["a","b","c"] + fmt.Println(list) // ArrayList ["a","b"] } ``` From 08df807efe23681926e72be57595430bd5c705f9 Mon Sep 17 00:00:00 2001 From: Benjamin Scher Purcell Date: Thu, 6 Apr 2017 11:33:07 -0500 Subject: [PATCH 163/320] speed up redblack put performance --- trees/redblacktree/redblacktree.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index f9c9bc91..b012d244 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -62,9 +62,10 @@ func NewWithStringComparator() *Tree { // Put inserts node into the tree. // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree) Put(key interface{}, value interface{}) { - insertedNode := &Node{Key: key, Value: value, color: red} + var insertedNode *Node if tree.Root == nil { - tree.Root = insertedNode + tree.Root = &Node{Key: key, Value: value, color: red} + insertedNode = tree.Root } else { node := tree.Root loop := true @@ -77,14 +78,16 @@ func (tree *Tree) Put(key interface{}, value interface{}) { return case compare < 0: if node.Left == nil { - node.Left = insertedNode + node.Left = &Node{Key: key, Value: value, color: red} + insertedNode = node.Left loop = false } else { node = node.Left } case compare > 0: if node.Right == nil { - node.Right = insertedNode + node.Right = &Node{Key: key, Value: value, color: red} + insertedNode = node.Right loop = false } else { node = node.Right From 4673683cbc5c7e26942370ebfbead1f4b767f70d Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 12 Sep 2017 12:48:36 +0200 Subject: [PATCH 164/320] Update enumerable.go --- containers/enumerable.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/containers/enumerable.go b/containers/enumerable.go index b0b56e4d..ac48b545 100644 --- a/containers/enumerable.go +++ b/containers/enumerable.go @@ -11,7 +11,7 @@ type EnumerableWithIndex interface { // Map invokes the given function once for each element and returns a // container containing the values returned by the given function. - // TODO need help on how to enforce this in containers (don't want to type assert when chaining) + // TODO would appreciate help on how to enforce this in containers (don't want to type assert when chaining) // Map(func(index int, value interface{}) interface{}) Container // Select returns a new container containing all elements for which the given function returns a true value. From e8e0d26a6f86bf6f9e87be3274344634173e8a7e Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 12 Sep 2017 15:15:00 +0200 Subject: [PATCH 165/320] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index f9b415e0..d9befd74 100644 --- a/README.md +++ b/README.md @@ -1434,3 +1434,8 @@ go fmt ./... && gofmt -s -w . && go vet ./... && go get ./... && go test ./... & ### License This library is distributed under the BSD-style license found in the [LICENSE](https://github.com/emirpasic/gods/blob/master/LICENSE) file. + +### Sponsors + +## BrowserStack +[BrowserStack](https://www.browserstack.com/?ref=webhook) is a cloud-based cross-browser testing tool that enables developers to test their websites across various browsers on different operating systems and mobile devices, without requiring users to install virtual machines, devices or emulators. From c4fc0ef8b1fa112dc494a06438c99670c779d150 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 12 Sep 2017 15:16:29 +0200 Subject: [PATCH 166/320] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d9befd74..568a5f01 100644 --- a/README.md +++ b/README.md @@ -1437,5 +1437,5 @@ This library is distributed under the BSD-style license found in the [LICENSE](h ### Sponsors -## BrowserStack +## BrowserStack [BrowserStack](https://www.browserstack.com/?ref=webhook) is a cloud-based cross-browser testing tool that enables developers to test their websites across various browsers on different operating systems and mobile devices, without requiring users to install virtual machines, devices or emulators. From 12451bdcc697ceb2d3e8bfbefff6036fc2b9b889 Mon Sep 17 00:00:00 2001 From: Spriithy Date: Thu, 28 Sep 2017 14:22:00 +0200 Subject: [PATCH 167/320] Added bulk constructors for arraylists & (doubly)-linked-lists --- lists/arraylist/arraylist.go | 10 +++++++++- lists/doublylinkedlist/doublylinkedlist.go | 10 +++++++++- lists/singlylinkedlist/singlylinkedlist.go | 10 +++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index f9e35439..c1af31fd 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -11,9 +11,10 @@ package arraylist import ( "fmt" + "strings" + "github.com/emirpasic/gods/lists" "github.com/emirpasic/gods/utils" - "strings" ) func assertListImplementation() { @@ -36,6 +37,13 @@ func New() *List { return &List{} } +// Of instantiates a new list of the given values +func Of(values ...interface{}) *List { + list := New() + list.Add(values) + return list +} + // Add appends a value at the end of the list func (list *List) Add(values ...interface{}) { list.growBy(len(values)) diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index bd85b184..51e4aee5 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -11,9 +11,10 @@ package doublylinkedlist import ( "fmt" + "strings" + "github.com/emirpasic/gods/lists" "github.com/emirpasic/gods/utils" - "strings" ) func assertListImplementation() { @@ -38,6 +39,13 @@ func New() *List { return &List{} } +// Of instantiates a new list of the given values +func Of(values ...interface{}) *List { + list := New() + list.Add(values) + return list +} + // Add appends a value (one or more) at the end of the list (same as Append()) func (list *List) Add(values ...interface{}) { for _, value := range values { diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 139925bd..d48afc86 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -11,9 +11,10 @@ package singlylinkedlist import ( "fmt" + "strings" + "github.com/emirpasic/gods/lists" "github.com/emirpasic/gods/utils" - "strings" ) func assertListImplementation() { @@ -37,6 +38,13 @@ func New() *List { return &List{} } +// Of instantiates a new list of the given values +func Of(values ...interface{}) *List { + list := New() + list.Add(values) + return list +} + // Add appends a value (one or more) at the end of the list (same as Append()) func (list *List) Add(values ...interface{}) { for _, value := range values { From 576b60622470f971f19f8ddbd40909bab91eb3bd Mon Sep 17 00:00:00 2001 From: Eugenio Cano-Manuel Date: Mon, 2 Oct 2017 23:05:41 +0100 Subject: [PATCH 168/320] replaced ^\s for ^ in code examples --- README.md | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 568a5f01..7ea8f98e 100644 --- a/README.md +++ b/README.md @@ -87,13 +87,13 @@ Implements [Container](#containers) interface. ```go type List interface { - Get(index int) (interface{}, bool) + Get(index int) (interface{}, bool) Remove(index int) Add(values ...interface{}) Contains(values ...interface{}) bool Sort(comparator utils.Comparator) - Swap(index1, index2 int) - Insert(index int, values ...interface{}) + Swap(index1, index2 int) + Insert(index int, values ...interface{}) containers.Container // Empty() bool @@ -114,7 +114,7 @@ package main import ( "github.com/emirpasic/gods/lists/arraylist" - "github.com/emirpasic/gods/utils" + "github.com/emirpasic/gods/utils" ) func main() { @@ -135,8 +135,8 @@ func main() { _ = list.Size() // 0 list.Add("a") // ["a"] list.Clear() // [] - list.Insert(0, "b") // ["b"] - list.Insert(0, "a") // ["a","b"] + list.Insert(0, "b") // ["b"] + list.Insert(0, "a") // ["a","b"] } ``` @@ -172,8 +172,8 @@ func main() { _ = list.Size() // 0 list.Add("a") // ["a"] list.Clear() // [] - list.Insert(0, "b") // ["b"] - list.Insert(0, "a") // ["a","b"] + list.Insert(0, "b") // ["b"] + list.Insert(0, "a") // ["a","b"] } ``` @@ -209,8 +209,8 @@ func main() { _ = list.Size() // 0 list.Add("a") // ["a"] list.Clear() // [] - list.Insert(0, "b") // ["b"] - list.Insert(0, "a") // ["a","b"] + list.Insert(0, "b") // ["b"] + list.Insert(0, "a") // ["a","b"] } ``` @@ -222,7 +222,7 @@ Implements [Container](#containers) interface. ```go type Set interface { - Add(elements ...interface{}) + Add(elements ...interface{}) Remove(elements ...interface{}) Contains(elements ...interface{}) bool @@ -370,7 +370,7 @@ Implements [Container](#containers) interface. ```go type Map interface { - Put(key interface{}, value interface{}) + Put(key interface{}, value interface{}) Get(key interface{}) (value interface{}, found bool) Remove(key interface{}) Keys() []interface{} @@ -445,9 +445,9 @@ func main() { m.Empty() // true m.Size() // 0 - // Other: - m.Min() // Returns the minimum key and its value from map. - m.Max() // Returns the maximum key and its value from map. + // Other: + m.Min() // Returns the minimum key and its value from map. + m.Max() // Returns the maximum key and its value from map. } ``` @@ -584,11 +584,11 @@ func main() { tree.Empty() // true tree.Size() // 0 - // Other: - tree.Left() // gets the left-most (min) node - tree.Right() // get the right-most (max) node - tree.Floor(1) // get the floor node - tree.Ceiling(1) // get the ceiling node + // Other: + tree.Left() // gets the left-most (min) node + tree.Right() // get the right-most (max) node + tree.Floor(1) // get the floor node + tree.Ceiling(1) // get the ceiling node } ``` @@ -898,7 +898,7 @@ Typical usage: it := list.Iterator() for it.Next() { index, value := it.Index(), it.Value() - ... + ... } ``` @@ -925,7 +925,7 @@ Typical usage: it := tree.Iterator() for it.Next() { key, value := it.Key(), it.Value() - ... + ... } ``` @@ -952,7 +952,7 @@ Typical usage of iteration in reverse: it := list.Iterator() for it.End(); it.Prev(); { index, value := it.Index(), it.Value() - ... + ... } ``` @@ -973,7 +973,7 @@ Typical usage of iteration in reverse: it := tree.Iterator() for it.End(); it.Prev(); { key, value := it.Key(), it.Value() - ... + ... } ``` @@ -1354,13 +1354,13 @@ package main import ( "github.com/emirpasic/gods/lists/arraylist" - "github.com/emirpasic/gods/utils" + "github.com/emirpasic/gods/utils" ) func main() { list := arraylist.New() - list.Add(2, 1, 3) - values := GetSortedValues(container, utils.StringComparator) // [1, 2, 3] + list.Add(2, 1, 3) + values := GetSortedValues(container, utils.StringComparator) // [1, 2, 3] } ``` From 39cc6fb03a9e133ddf8f7d337ecb22dbfbcf3add Mon Sep 17 00:00:00 2001 From: Davor Kapsa Date: Fri, 13 Oct 2017 19:11:23 +0200 Subject: [PATCH 169/320] travis: update go versions --- .travis.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index b7fa8691..5477990c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,11 @@ language: go go: - - 1.1 - - 1.2 - - 1.3 - - 1.4 - - 1.5 - - 1.6 - - 1.7 + - 1.1.x + - 1.2.x + - 1.3.x + - 1.4.x + - 1.5.x + - 1.6.x + - 1.7.x + - 1.8.x - tip From f246a54621c93d64a821cd2d505546212ec73e67 Mon Sep 17 00:00:00 2001 From: Mahadev Date: Tue, 26 Dec 2017 19:18:50 +0530 Subject: [PATCH 170/320] Add IndexOf method to ArrayList --- lists/arraylist/arraylist.go | 12 ++++++++++++ lists/arraylist/arraylist_test.go | 30 +++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index f9e35439..e2fbcec1 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -98,6 +98,18 @@ func (list *List) Values() []interface{} { return newElements } +//IndexOf returns index of provided element +func (list *List) IndexOf(value interface{}) int{ + if list.size == 0 { + return -1 + } + for index, element := range list.elements { + if element == value { + return index + } + } + return -1 +} // Empty returns true if list does not contain any elements. func (list *List) Empty() bool { return list.size == 0 diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 58fd8b1e..abbb2aa4 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -6,8 +6,9 @@ package arraylist import ( "fmt" - "github.com/emirpasic/gods/utils" "testing" + + "github.com/emirpasic/gods/utils" ) func TestListAdd(t *testing.T) { @@ -25,6 +26,33 @@ func TestListAdd(t *testing.T) { } } +func TestListIndexOf(t *testing.T) { + list := New() + + expectedIndex := -1 + if index := list.IndexOf("a"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) + } + + list.Add("a") + list.Add("b", "c") + + expectedIndex = 0 + if index := list.IndexOf("a"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) + } + + expectedIndex = 1 + if index := list.IndexOf("b"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) + } + + expectedIndex = 2 + if index := list.IndexOf("c"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) + } +} + func TestListRemove(t *testing.T) { list := New() list.Add("a") From e709a4b5ea88c8f3f566c8c8cea95a3e529d52a4 Mon Sep 17 00:00:00 2001 From: Mahadev Date: Tue, 26 Dec 2017 19:19:18 +0530 Subject: [PATCH 171/320] Add IndexOf method to SinglyLinkedList --- lists/singlylinkedlist/singlylinkedlist.go | 12 +++++++++ .../singlylinkedlist/singlylinkedlist_test.go | 27 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 139925bd..3182af3d 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -154,6 +154,18 @@ func (list *List) Values() []interface{} { return values } +//IndexOf returns index of provided element +func (list *List) IndexOf(value interface{}) int{ + if list.size == 0 { + return -1 + } + for index, element := range list.Values() { + if element == value { + return index + } + } + return -1 +} // Empty returns true if list does not contain any elements. func (list *List) Empty() bool { return list.size == 0 diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index 27daacc4..0bebbb32 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -133,6 +133,33 @@ func TestListValues(t *testing.T) { } } +func TestListIndexOf(t *testing.T) { + list := New() + + expectedIndex := -1 + if index := list.IndexOf("a"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) + } + + list.Add("a") + list.Add("b", "c") + + expectedIndex = 0 + if index := list.IndexOf("a"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) + } + + expectedIndex = 1 + if index := list.IndexOf("b"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) + } + + expectedIndex = 2 + if index := list.IndexOf("c"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) + } +} + func TestListInsert(t *testing.T) { list := New() list.Insert(0, "b", "c") From 8a171863a010a24600ffbb2d86bcc2fe95083671 Mon Sep 17 00:00:00 2001 From: Mahadev Date: Tue, 26 Dec 2017 19:19:36 +0530 Subject: [PATCH 172/320] Add IndexOf method to DoublyLinkedList --- lists/doublylinkedlist/doublylinkedlist.go | 12 +++++++++ .../doublylinkedlist/doublylinkedlist_test.go | 27 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index bd85b184..881e0f7b 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -173,6 +173,18 @@ func (list *List) Values() []interface{} { return values } +//IndexOf returns index of provided element +func (list *List) IndexOf(value interface{}) int { + if list.size == 0 { + return -1 + } + for index, element := range list.Values() { + if element == value { + return index + } + } + return -1 +} // Empty returns true if list does not contain any elements. func (list *List) Empty() bool { return list.size == 0 diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 5fea3d0a..444e2721 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -133,6 +133,33 @@ func TestListValues(t *testing.T) { } } +func TestListIndexOf(t *testing.T) { + list := New() + + expectedIndex := -1 + if index := list.IndexOf("a"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) + } + + list.Add("a") + list.Add("b", "c") + + expectedIndex = 0 + if index := list.IndexOf("a"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) + } + + expectedIndex = 1 + if index := list.IndexOf("b"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) + } + + expectedIndex = 2 + if index := list.IndexOf("c"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) + } +} + func TestListInsert(t *testing.T) { list := New() list.Insert(0, "b", "c") From 5d06966e290097265c9b334eb0da46054fa06c99 Mon Sep 17 00:00:00 2001 From: xtutu Date: Tue, 12 Jun 2018 13:41:35 +0800 Subject: [PATCH 173/320] optimize array list --- lists/arraylist/arraylist.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index e2fbcec1..c6298ef9 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -157,14 +157,8 @@ func (list *List) Insert(index int, values ...interface{}) { l := len(values) list.growBy(l) list.size += l - // Shift old to right - for i := list.size - 1; i >= index+l; i-- { - list.elements[i] = list.elements[i-l] - } - // Insert new - for i, value := range values { - list.elements[index+i] = value - } + copy(list.elements[index+l:], list.elements[index:list.size - l]) + copy(list.elements[index:], values) } // String returns a string representation of container From 55e94ab1e363f3bf2aee3fdd113d7c5d998aa707 Mon Sep 17 00:00:00 2001 From: ia Date: Sun, 17 Jun 2018 01:02:33 +0200 Subject: [PATCH 174/320] all: gofmt Run standard gofmt command on project root. - go version go1.10.3 darwin/amd64 Signed-off-by: ia --- lists/arraylist/arraylist.go | 13 +++++++------ lists/arraylist/arraylist_test.go | 16 ++++++++-------- lists/doublylinkedlist/doublylinkedlist.go | 1 + lists/doublylinkedlist/doublylinkedlist_test.go | 16 ++++++++-------- lists/singlylinkedlist/singlylinkedlist.go | 3 ++- lists/singlylinkedlist/singlylinkedlist_test.go | 16 ++++++++-------- 6 files changed, 34 insertions(+), 31 deletions(-) diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index e2fbcec1..9cb98d8e 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -99,17 +99,18 @@ func (list *List) Values() []interface{} { } //IndexOf returns index of provided element -func (list *List) IndexOf(value interface{}) int{ +func (list *List) IndexOf(value interface{}) int { if list.size == 0 { return -1 } - for index, element := range list.elements { - if element == value { - return index - } + for index, element := range list.elements { + if element == value { + return index } - return -1 + } + return -1 } + // Empty returns true if list does not contain any elements. func (list *List) Empty() bool { return list.size == 0 diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index abbb2aa4..3e31e3dc 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -30,26 +30,26 @@ func TestListIndexOf(t *testing.T) { list := New() expectedIndex := -1 - if index := list.IndexOf("a"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("a"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } list.Add("a") list.Add("b", "c") expectedIndex = 0 - if index := list.IndexOf("a"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("a"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } expectedIndex = 1 - if index := list.IndexOf("b"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("b"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } expectedIndex = 2 - if index := list.IndexOf("c"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("c"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } } diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 881e0f7b..ab0e1bc2 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -185,6 +185,7 @@ func (list *List) IndexOf(value interface{}) int { } return -1 } + // Empty returns true if list does not contain any elements. func (list *List) Empty() bool { return list.size == 0 diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 444e2721..4794da93 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -137,26 +137,26 @@ func TestListIndexOf(t *testing.T) { list := New() expectedIndex := -1 - if index := list.IndexOf("a"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("a"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } list.Add("a") list.Add("b", "c") expectedIndex = 0 - if index := list.IndexOf("a"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("a"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } expectedIndex = 1 - if index := list.IndexOf("b"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("b"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } expectedIndex = 2 - if index := list.IndexOf("c"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("c"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } } diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 3182af3d..45ee69c5 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -155,7 +155,7 @@ func (list *List) Values() []interface{} { } //IndexOf returns index of provided element -func (list *List) IndexOf(value interface{}) int{ +func (list *List) IndexOf(value interface{}) int { if list.size == 0 { return -1 } @@ -166,6 +166,7 @@ func (list *List) IndexOf(value interface{}) int{ } return -1 } + // Empty returns true if list does not contain any elements. func (list *List) Empty() bool { return list.size == 0 diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index 0bebbb32..36e080d5 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -137,26 +137,26 @@ func TestListIndexOf(t *testing.T) { list := New() expectedIndex := -1 - if index := list.IndexOf("a"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("a"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } list.Add("a") list.Add("b", "c") expectedIndex = 0 - if index := list.IndexOf("a"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("a"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } expectedIndex = 1 - if index := list.IndexOf("b"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("b"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } expectedIndex = 2 - if index := list.IndexOf("c"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("c"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } } From 076c527d931f9e9307bdc553152cc834bbd184ab Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sun, 17 Jun 2018 14:41:40 +0200 Subject: [PATCH 175/320] Revert "gofmt" --- lists/arraylist/arraylist.go | 13 ++++++------- lists/arraylist/arraylist_test.go | 16 ++++++++-------- lists/doublylinkedlist/doublylinkedlist.go | 1 - lists/doublylinkedlist/doublylinkedlist_test.go | 16 ++++++++-------- lists/singlylinkedlist/singlylinkedlist.go | 3 +-- lists/singlylinkedlist/singlylinkedlist_test.go | 16 ++++++++-------- 6 files changed, 31 insertions(+), 34 deletions(-) diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index 9cb98d8e..e2fbcec1 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -99,18 +99,17 @@ func (list *List) Values() []interface{} { } //IndexOf returns index of provided element -func (list *List) IndexOf(value interface{}) int { +func (list *List) IndexOf(value interface{}) int{ if list.size == 0 { return -1 } - for index, element := range list.elements { - if element == value { - return index + for index, element := range list.elements { + if element == value { + return index + } } - } - return -1 + return -1 } - // Empty returns true if list does not contain any elements. func (list *List) Empty() bool { return list.size == 0 diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 3e31e3dc..abbb2aa4 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -30,26 +30,26 @@ func TestListIndexOf(t *testing.T) { list := New() expectedIndex := -1 - if index := list.IndexOf("a"); index != expectedIndex { - t.Errorf("Got %v expected %v", index, expectedIndex) + if index := list.IndexOf("a"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) } list.Add("a") list.Add("b", "c") expectedIndex = 0 - if index := list.IndexOf("a"); index != expectedIndex { - t.Errorf("Got %v expected %v", index, expectedIndex) + if index := list.IndexOf("a"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) } expectedIndex = 1 - if index := list.IndexOf("b"); index != expectedIndex { - t.Errorf("Got %v expected %v", index, expectedIndex) + if index := list.IndexOf("b"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) } expectedIndex = 2 - if index := list.IndexOf("c"); index != expectedIndex { - t.Errorf("Got %v expected %v", index, expectedIndex) + if index := list.IndexOf("c"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) } } diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index ab0e1bc2..881e0f7b 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -185,7 +185,6 @@ func (list *List) IndexOf(value interface{}) int { } return -1 } - // Empty returns true if list does not contain any elements. func (list *List) Empty() bool { return list.size == 0 diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 4794da93..444e2721 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -137,26 +137,26 @@ func TestListIndexOf(t *testing.T) { list := New() expectedIndex := -1 - if index := list.IndexOf("a"); index != expectedIndex { - t.Errorf("Got %v expected %v", index, expectedIndex) + if index := list.IndexOf("a"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) } list.Add("a") list.Add("b", "c") expectedIndex = 0 - if index := list.IndexOf("a"); index != expectedIndex { - t.Errorf("Got %v expected %v", index, expectedIndex) + if index := list.IndexOf("a"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) } expectedIndex = 1 - if index := list.IndexOf("b"); index != expectedIndex { - t.Errorf("Got %v expected %v", index, expectedIndex) + if index := list.IndexOf("b"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) } expectedIndex = 2 - if index := list.IndexOf("c"); index != expectedIndex { - t.Errorf("Got %v expected %v", index, expectedIndex) + if index := list.IndexOf("c"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) } } diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 45ee69c5..3182af3d 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -155,7 +155,7 @@ func (list *List) Values() []interface{} { } //IndexOf returns index of provided element -func (list *List) IndexOf(value interface{}) int { +func (list *List) IndexOf(value interface{}) int{ if list.size == 0 { return -1 } @@ -166,7 +166,6 @@ func (list *List) IndexOf(value interface{}) int { } return -1 } - // Empty returns true if list does not contain any elements. func (list *List) Empty() bool { return list.size == 0 diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index 36e080d5..0bebbb32 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -137,26 +137,26 @@ func TestListIndexOf(t *testing.T) { list := New() expectedIndex := -1 - if index := list.IndexOf("a"); index != expectedIndex { - t.Errorf("Got %v expected %v", index, expectedIndex) + if index := list.IndexOf("a"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) } list.Add("a") list.Add("b", "c") expectedIndex = 0 - if index := list.IndexOf("a"); index != expectedIndex { - t.Errorf("Got %v expected %v", index, expectedIndex) + if index := list.IndexOf("a"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) } expectedIndex = 1 - if index := list.IndexOf("b"); index != expectedIndex { - t.Errorf("Got %v expected %v", index, expectedIndex) + if index := list.IndexOf("b"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) } expectedIndex = 2 - if index := list.IndexOf("c"); index != expectedIndex { - t.Errorf("Got %v expected %v", index, expectedIndex) + if index := list.IndexOf("c"); index != expectedIndex{ + t.Errorf("Got %v expected %v",index,expectedIndex) } } From 65869799a07fa3148760469b8474b04f1f99cba8 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 18 Jun 2018 13:13:01 +0200 Subject: [PATCH 176/320] Revert "Revert "gofmt"" --- lists/arraylist/arraylist.go | 13 +++++++------ lists/arraylist/arraylist_test.go | 16 ++++++++-------- lists/doublylinkedlist/doublylinkedlist.go | 1 + lists/doublylinkedlist/doublylinkedlist_test.go | 16 ++++++++-------- lists/singlylinkedlist/singlylinkedlist.go | 3 ++- lists/singlylinkedlist/singlylinkedlist_test.go | 16 ++++++++-------- 6 files changed, 34 insertions(+), 31 deletions(-) diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index e2fbcec1..9cb98d8e 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -99,17 +99,18 @@ func (list *List) Values() []interface{} { } //IndexOf returns index of provided element -func (list *List) IndexOf(value interface{}) int{ +func (list *List) IndexOf(value interface{}) int { if list.size == 0 { return -1 } - for index, element := range list.elements { - if element == value { - return index - } + for index, element := range list.elements { + if element == value { + return index } - return -1 + } + return -1 } + // Empty returns true if list does not contain any elements. func (list *List) Empty() bool { return list.size == 0 diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index abbb2aa4..3e31e3dc 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -30,26 +30,26 @@ func TestListIndexOf(t *testing.T) { list := New() expectedIndex := -1 - if index := list.IndexOf("a"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("a"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } list.Add("a") list.Add("b", "c") expectedIndex = 0 - if index := list.IndexOf("a"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("a"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } expectedIndex = 1 - if index := list.IndexOf("b"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("b"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } expectedIndex = 2 - if index := list.IndexOf("c"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("c"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } } diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 881e0f7b..ab0e1bc2 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -185,6 +185,7 @@ func (list *List) IndexOf(value interface{}) int { } return -1 } + // Empty returns true if list does not contain any elements. func (list *List) Empty() bool { return list.size == 0 diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 444e2721..4794da93 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -137,26 +137,26 @@ func TestListIndexOf(t *testing.T) { list := New() expectedIndex := -1 - if index := list.IndexOf("a"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("a"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } list.Add("a") list.Add("b", "c") expectedIndex = 0 - if index := list.IndexOf("a"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("a"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } expectedIndex = 1 - if index := list.IndexOf("b"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("b"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } expectedIndex = 2 - if index := list.IndexOf("c"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("c"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } } diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 3182af3d..45ee69c5 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -155,7 +155,7 @@ func (list *List) Values() []interface{} { } //IndexOf returns index of provided element -func (list *List) IndexOf(value interface{}) int{ +func (list *List) IndexOf(value interface{}) int { if list.size == 0 { return -1 } @@ -166,6 +166,7 @@ func (list *List) IndexOf(value interface{}) int{ } return -1 } + // Empty returns true if list does not contain any elements. func (list *List) Empty() bool { return list.size == 0 diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index 0bebbb32..36e080d5 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -137,26 +137,26 @@ func TestListIndexOf(t *testing.T) { list := New() expectedIndex := -1 - if index := list.IndexOf("a"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("a"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } list.Add("a") list.Add("b", "c") expectedIndex = 0 - if index := list.IndexOf("a"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("a"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } expectedIndex = 1 - if index := list.IndexOf("b"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("b"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } expectedIndex = 2 - if index := list.IndexOf("c"); index != expectedIndex{ - t.Errorf("Got %v expected %v",index,expectedIndex) + if index := list.IndexOf("c"); index != expectedIndex { + t.Errorf("Got %v expected %v", index, expectedIndex) } } From 92a8a1f980acaf0d6725a93b1d2091e203819c23 Mon Sep 17 00:00:00 2001 From: Mateusz Kozak Date: Wed, 8 Aug 2018 22:06:04 +0200 Subject: [PATCH 177/320] Update README.md fix example on how to deserialize key-value JSON --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7ea8f98e..1a545fae 100644 --- a/README.md +++ b/README.md @@ -1278,18 +1278,18 @@ package main import ( "fmt" - "github.com/emirpasic/gods/lists/arraylist" + "github.com/emirpasic/gods/maps/hashmap" ) func main() { - list := arraylist.New() + hm := hashmap.New() - json := []byte(`["a","b"]`) - err := list.FromJSON(json) + json := []byte(`{"a":"1","b":"2"}`) + err := hm.FromJSON(json) if err != nil { fmt.Println(err) } - fmt.Println(list) // ArrayList ["a","b"] + fmt.Println(hm) // HashMap map[b:2 a:1] } ``` From 1078d101894d0948bb488cb34206282d715aab68 Mon Sep 17 00:00:00 2001 From: loxp Date: Wed, 15 Aug 2018 17:23:51 +0800 Subject: [PATCH 178/320] Add Floor and Ceiling method to Treemap --- maps/treemap/treemap.go | 22 +++++++++++++++ maps/treemap/treemap_test.go | 54 ++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index a1e58ad4..2105b668 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -105,6 +105,28 @@ func (m *Map) Max() (key interface{}, value interface{}) { return nil, nil } +// Floor searches the floor element in the map by key. +// Returns floor key, floor value, true if floor key is found. +// Returns nil, nil, false if floor key is not found. +func (m *Map) Floor(key interface{}) (retKey interface{}, retValue interface{}, found bool) { + ret, found := m.tree.Floor(key) + if !found { + return nil, nil, false + } + return ret.Key, ret.Value, true +} + +// Ceiling searches the ceiling element in the map by key. +// Returns ceiling key, ceiling value, true if a ceiling key is found. +// Returns nil, nil, false if ceiling key is not found. +func (m *Map) Ceiling(key interface{}) (retKey interface{}, retValue interface{}, found bool) { + ret, found := m.tree.Ceiling(key) + if !found { + return nil, nil, false + } + return ret.Key, ret.Value, true +} + // String returns a string representation of container func (m *Map) String() string { str := "TreeMap\nmap[" diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index a73e8734..da82bdc8 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -289,6 +289,60 @@ func TestMapChaining(t *testing.T) { } } +func TestMapFloor(t *testing.T) { + m := NewWithIntComparator() + m.Put(7, "g") + m.Put(3, "c") + m.Put(1, "a") + + // key,expectedKey,expectedValue,expectedFound + tests1 := [][]interface{}{ + {-1, nil, nil, false}, + {0, nil, nil, false}, + {1, 1, "a", true}, + {2, 1, "a", true}, + {3, 3, "c", true}, + {4, 3, "c", true}, + {7, 7, "g", true}, + {8, 7, "g", true}, + } + + for _, test := range tests1 { + // retrievals + actualKey, actualValue, actualFound := m.Floor(test[0]) + if actualKey != test[1] || actualValue != test[2] || actualFound != test[3] { + t.Errorf("Got %v, %v, %v, expected %v, %v, %v", actualKey, actualValue, actualFound, test[1], test[2], test[3]) + } + } +} + +func TestMapCeiling(t *testing.T) { + m := NewWithIntComparator() + m.Put(7, "g") + m.Put(3, "c") + m.Put(1, "a") + + // key,expectedKey,expectedValue,expectedFound + tests1 := [][]interface{}{ + {-1, 1, "a", true}, + {0, 1, "a", true}, + {1, 1, "a", true}, + {2, 3, "c", true}, + {3, 3, "c", true}, + {4, 7, "g", true}, + {7, 7, "g", true}, + {8, nil, nil, false}, + } + + for _, test := range tests1 { + // retrievals + actualKey, actualValue, actualFound := m.Ceiling(test[0]) + if actualKey != test[1] || actualValue != test[2] || actualFound != test[3] { + t.Errorf("Got %v, %v, %v, expected %v, %v, %v", actualKey, actualValue, actualFound, test[1], test[2], test[3]) + } + } +} + func TestMapIteratorNextOnEmpty(t *testing.T) { m := NewWithStringComparator() it := m.Iterator() From 8557a87b9f8de99b9a612ad2b06ab9142b10fe10 Mon Sep 17 00:00:00 2001 From: emirpasic Date: Wed, 19 Sep 2018 05:05:43 +0200 Subject: [PATCH 179/320] fmt --- lists/arraylist/arraylist.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index 3fb2db4f..1ace92a2 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -158,7 +158,7 @@ func (list *List) Insert(index int, values ...interface{}) { l := len(values) list.growBy(l) list.size += l - copy(list.elements[index+l:], list.elements[index:list.size - l]) + copy(list.elements[index+l:], list.elements[index:list.size-l]) copy(list.elements[index:], values) } From de5d8947371fff34340affe84302558eed019057 Mon Sep 17 00:00:00 2001 From: emirpasic Date: Wed, 19 Sep 2018 05:40:24 +0200 Subject: [PATCH 180/320] - update documentation, closes #73 --- README.md | 2 +- examples/README.md | 29 +++++++++++++++++++ examples/{ => arraylist}/arraylist.go | 4 +-- examples/{ => arraystack}/arraystack.go | 4 +-- examples/{ => avltree}/avltree.go | 4 +-- examples/{ => binaryheap}/binaryheap.go | 4 +-- examples/{ => btree}/btree.go | 4 +-- .../customcomparator.go | 4 +-- .../doublylinkedlist.go | 4 +-- .../enumerablewithindex.go | 4 +-- .../enumerablewithkey.go | 4 +-- examples/{ => hashbidimap}/hashbidimap.go | 4 +-- examples/{ => hashmap}/hashmap.go | 4 +-- examples/{ => hashset}/hashset.go | 4 +-- .../iteratorwithindex.go | 4 +-- .../{ => iteratorwithkey}/iteratorwithkey.go | 4 +-- .../{ => linkedliststack}/linkedliststack.go | 4 +-- examples/{ => redblacktree}/redblacktree.go | 4 +-- .../redblacktreeextended.go | 4 +-- examples/{ => serialization}/serialization.go | 2 +- .../singlylinkedlist.go | 4 +-- examples/{ => sort}/sort.go | 4 +-- examples/{ => treebidimap}/treebidimap.go | 4 +-- examples/{ => treemap}/treemap.go | 4 +-- examples/{ => treeset}/treeset.go | 4 +-- 25 files changed, 75 insertions(+), 46 deletions(-) create mode 100644 examples/README.md rename examples/{ => arraylist}/arraylist.go (96%) rename examples/{ => arraystack}/arraystack.go (94%) rename examples/{ => avltree}/avltree.go (96%) rename examples/{ => binaryheap}/binaryheap.go (97%) rename examples/{ => btree}/btree.go (97%) rename examples/{ => customcomparator}/customcomparator.go (94%) rename examples/{ => doublylinkedlist}/doublylinkedlist.go (95%) rename examples/{ => enumerablewithindex}/enumerablewithindex.go (97%) rename examples/{ => enumerablewithkey}/enumerablewithkey.go (97%) rename examples/{ => hashbidimap}/hashbidimap.go (95%) rename examples/{ => hashmap}/hashmap.go (94%) rename examples/{ => hashset}/hashset.go (94%) rename examples/{ => iteratorwithindex}/iteratorwithindex.go (96%) rename examples/{ => iteratorwithkey}/iteratorwithkey.go (96%) rename examples/{ => linkedliststack}/linkedliststack.go (93%) rename examples/{ => redblacktree}/redblacktree.go (96%) rename examples/{ => redblacktreeextended}/redblacktreeextended.go (98%) rename examples/{ => serialization}/serialization.go (98%) rename examples/{ => singlylinkedlist}/singlylinkedlist.go (95%) rename examples/{ => sort}/sort.go (94%) rename examples/{ => treebidimap}/treebidimap.go (95%) rename examples/{ => treemap}/treemap.go (95%) rename examples/{ => treeset}/treeset.go (95%) diff --git a/README.md b/README.md index 1a545fae..cfcdb6c2 100644 --- a/README.md +++ b/README.md @@ -592,7 +592,7 @@ func main() { } ``` -Extending the red-black tree's functionality has been demonstrated in the following [example](https://github.com/emirpasic/gods/blob/master/examples/redblacktreeextended.go). +Extending the red-black tree's functionality has been demonstrated in the following [example](https://github.com/emirpasic/gods/blob/master/examples/redblacktreeextended/redblacktreeextended.go). #### AVLTree diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000..8a1e8cae --- /dev/null +++ b/examples/README.md @@ -0,0 +1,29 @@ +# GoDS (Go Data Structures) + +Various examples on how to use data structures. + +## Examples + +- [ArrayList](https://github.com/emirpasic/gods/blob/master/examples/arraylist/arraylist.go) +- [ArrayStack](https://github.com/emirpasic/gods/blob/master/examples/arraystack/arraystack.go) +- [AVLTree](https://github.com/emirpasic/gods/blob/master/examples/avltree/avltree.go) +- [BinaryHeap](https://github.com/emirpasic/gods/blob/master/examples/binaryheap/binaryheap.go) +- [BTree](https://github.com/emirpasic/gods/blob/master/examples/btree/btree.go) +- [Custom Comparator](https://github.com/emirpasic/gods/blob/master/examples/customcomparator/customcomparator.go) +- [DoublyLinkedList](https://github.com/emirpasic/gods/blob/master/examples/doublylinkedlist/doublylinkedlist.go) +- [EnumerableWithIndex](https://github.com/emirpasic/gods/blob/master/examples/enumerablewithindex/enumerablewithindex.go) +- [EnumerableWithKey](https://github.com/emirpasic/gods/blob/master/examples/enumerablewithkey/enumerablewithkey.go) +- [HashBidiMap](https://github.com/emirpasic/gods/blob/master/examples/hashbidimap/hashbidimap.go) +- [HashMap](https://github.com/emirpasic/gods/blob/master/examples/hashmap/hashmap.go) +- [HashSet](https://github.com/emirpasic/gods/blob/master/examples/hashset/hashset.go) +- [IteratorWithIndex](https://github.com/emirpasic/gods/blob/master/examples/iteratorwithindex/iteratorwithindex.go) +- [iteratorwithkey](https://github.com/emirpasic/gods/blob/master/examples/iteratorwithkey/iteratorwithkey.go) +- [IteratorWithKey](https://github.com/emirpasic/gods/blob/master/examples/linkedliststack/linkedliststack.go) +- [RedBlackTree](https://github.com/emirpasic/gods/blob/master/examples/redblacktree/redblacktree.go) +- [RedBlackTreeExtended](https://github.com/emirpasic/gods/blob/master/examples/redblacktreeextended/redblacktreeextended.go) +- [Serialization](https://github.com/emirpasic/gods/blob/master/examples/serialization/serialization.go) +- [SinglyLinkedList](https://github.com/emirpasic/gods/blob/master/examples/singlylinkedlist/singlylinkedlist.go) +- [Sort](https://github.com/emirpasic/gods/blob/master/examples/sort/sort.go) +- [TreeBidiMap](https://github.com/emirpasic/gods/blob/master/examples/treebidimap/treebidimap.go) +- [TreeMap](https://github.com/emirpasic/gods/blob/master/examples/treemap/treemap.go) +- [TreeSet](https://github.com/emirpasic/gods/blob/master/examples/treeset/treeset.go) diff --git a/examples/arraylist.go b/examples/arraylist/arraylist.go similarity index 96% rename from examples/arraylist.go rename to examples/arraylist/arraylist.go index 8e983fa8..4d4fbd90 100644 --- a/examples/arraylist.go +++ b/examples/arraylist/arraylist.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import ( "github.com/emirpasic/gods/lists/arraylist" @@ -10,7 +10,7 @@ import ( ) // ArrayListExample to demonstrate basic usage of ArrayList -func ArrayListExample() { +func main() { list := arraylist.New() list.Add("a") // ["a"] list.Add("c", "b") // ["a","c","b"] diff --git a/examples/arraystack.go b/examples/arraystack/arraystack.go similarity index 94% rename from examples/arraystack.go rename to examples/arraystack/arraystack.go index 84c2d89c..aa06eaf7 100644 --- a/examples/arraystack.go +++ b/examples/arraystack/arraystack.go @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import "github.com/emirpasic/gods/stacks/arraystack" // ArrayStackExample to demonstrate basic usage of ArrayStack -func ArrayStackExample() { +func main() { stack := arraystack.New() // empty stack.Push(1) // 1 stack.Push(2) // 1, 2 diff --git a/examples/avltree.go b/examples/avltree/avltree.go similarity index 96% rename from examples/avltree.go rename to examples/avltree/avltree.go index bd3f96e8..b6d1aabc 100644 --- a/examples/avltree.go +++ b/examples/avltree/avltree.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import ( "fmt" @@ -10,7 +10,7 @@ import ( ) // AVLTreeExample to demonstrate basic usage of AVLTree -func AVLTreeExample() { +func main() { tree := avl.NewWithIntComparator() // empty(keys are of type int) tree.Put(1, "x") // 1->x diff --git a/examples/binaryheap.go b/examples/binaryheap/binaryheap.go similarity index 97% rename from examples/binaryheap.go rename to examples/binaryheap/binaryheap.go index c56dc279..4bc93813 100644 --- a/examples/binaryheap.go +++ b/examples/binaryheap/binaryheap.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import ( "github.com/emirpasic/gods/trees/binaryheap" @@ -10,7 +10,7 @@ import ( ) // BinaryHeapExample to demonstrate basic usage of BinaryHeap -func BinaryHeapExample() { +func main() { // Min-heap heap := binaryheap.NewWithIntComparator() // empty (min-heap) diff --git a/examples/btree.go b/examples/btree/btree.go similarity index 97% rename from examples/btree.go rename to examples/btree/btree.go index b9076965..ea61b03f 100644 --- a/examples/btree.go +++ b/examples/btree/btree.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import ( "fmt" @@ -10,7 +10,7 @@ import ( ) // BTreeExample to demonstrate basic usage of BTree -func BTreeExample() { +func main() { tree := btree.NewWithIntComparator(3) // empty (keys are of type int) tree.Put(1, "x") // 1->x diff --git a/examples/customcomparator.go b/examples/customcomparator/customcomparator.go similarity index 94% rename from examples/customcomparator.go rename to examples/customcomparator/customcomparator.go index 4c9f8de7..b61d9698 100644 --- a/examples/customcomparator.go +++ b/examples/customcomparator/customcomparator.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import ( "fmt" @@ -33,7 +33,7 @@ func byID(a, b interface{}) int { } // CustomComparatorExample to demonstrate basic usage of CustomComparator -func CustomComparatorExample() { +func main() { set := treeset.NewWith(byID) set.Add(User{2, "Second"}) diff --git a/examples/doublylinkedlist.go b/examples/doublylinkedlist/doublylinkedlist.go similarity index 95% rename from examples/doublylinkedlist.go rename to examples/doublylinkedlist/doublylinkedlist.go index 95a64a21..99ec995c 100644 --- a/examples/doublylinkedlist.go +++ b/examples/doublylinkedlist/doublylinkedlist.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import ( dll "github.com/emirpasic/gods/lists/doublylinkedlist" @@ -10,7 +10,7 @@ import ( ) // DoublyLinkedListExample to demonstrate basic usage of DoublyLinkedList -func DoublyLinkedListExample() { +func main() { list := dll.New() list.Add("a") // ["a"] list.Append("b") // ["a","b"] (same as Add()) diff --git a/examples/enumerablewithindex.go b/examples/enumerablewithindex/enumerablewithindex.go similarity index 97% rename from examples/enumerablewithindex.go rename to examples/enumerablewithindex/enumerablewithindex.go index a33399ad..95459117 100644 --- a/examples/enumerablewithindex.go +++ b/examples/enumerablewithindex/enumerablewithindex.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import ( "fmt" @@ -18,7 +18,7 @@ func printSet(txt string, set *treeset.Set) { } // EnumerableWithIndexExample to demonstrate basic usage of EnumerableWithIndex -func EnumerableWithIndexExample() { +func main() { set := treeset.NewWithIntComparator() set.Add(2, 3, 4, 2, 5, 6, 7, 8) printSet("Initial", set) // [ 2 3 4 5 6 7 8 ] diff --git a/examples/enumerablewithkey.go b/examples/enumerablewithkey/enumerablewithkey.go similarity index 97% rename from examples/enumerablewithkey.go rename to examples/enumerablewithkey/enumerablewithkey.go index c9123abc..7f05040d 100644 --- a/examples/enumerablewithkey.go +++ b/examples/enumerablewithkey/enumerablewithkey.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import ( "fmt" @@ -18,7 +18,7 @@ func printMap(txt string, m *treemap.Map) { } // EunumerableWithKeyExample to demonstrate basic usage of EunumerableWithKey -func EunumerableWithKeyExample() { +func main() { m := treemap.NewWithStringComparator() m.Put("g", 7) m.Put("f", 6) diff --git a/examples/hashbidimap.go b/examples/hashbidimap/hashbidimap.go similarity index 95% rename from examples/hashbidimap.go rename to examples/hashbidimap/hashbidimap.go index 861fff90..26350b8c 100644 --- a/examples/hashbidimap.go +++ b/examples/hashbidimap/hashbidimap.go @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import "github.com/emirpasic/gods/maps/hashbidimap" // HashBidiMapExample to demonstrate basic usage of HashMap -func HashBidiMapExample() { +func main() { m := hashbidimap.New() // empty m.Put(1, "x") // 1->x m.Put(3, "b") // 1->x, 3->b (random order) diff --git a/examples/hashmap.go b/examples/hashmap/hashmap.go similarity index 94% rename from examples/hashmap.go rename to examples/hashmap/hashmap.go index f49c0425..2fda79e6 100644 --- a/examples/hashmap.go +++ b/examples/hashmap/hashmap.go @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import "github.com/emirpasic/gods/maps/hashmap" // HashMapExample to demonstrate basic usage of HashMap -func HashMapExample() { +func main() { m := hashmap.New() // empty m.Put(1, "x") // 1->x m.Put(2, "b") // 2->b, 1->x (random order) diff --git a/examples/hashset.go b/examples/hashset/hashset.go similarity index 94% rename from examples/hashset.go rename to examples/hashset/hashset.go index 5fe2bd0e..6c366e51 100644 --- a/examples/hashset.go +++ b/examples/hashset/hashset.go @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import "github.com/emirpasic/gods/sets/hashset" // HashSetExample to demonstrate basic usage of HashSet -func HashSetExample() { +func main() { set := hashset.New() // empty (keys are of type int) set.Add(1) // 1 set.Add(2, 2, 3, 4, 5) // 3, 1, 2, 4, 5 (random order, duplicates ignored) diff --git a/examples/iteratorwithindex.go b/examples/iteratorwithindex/iteratorwithindex.go similarity index 96% rename from examples/iteratorwithindex.go rename to examples/iteratorwithindex/iteratorwithindex.go index 86d6bd16..d15c439f 100644 --- a/examples/iteratorwithindex.go +++ b/examples/iteratorwithindex/iteratorwithindex.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import ( "fmt" @@ -10,7 +10,7 @@ import ( ) // IteratorWithIndexExample to demonstrate basic usage of IteratorWithIndex -func IteratorWithIndexExample() { +func main() { set := treeset.NewWithStringComparator() set.Add("a", "b", "c") it := set.Iterator() diff --git a/examples/iteratorwithkey.go b/examples/iteratorwithkey/iteratorwithkey.go similarity index 96% rename from examples/iteratorwithkey.go rename to examples/iteratorwithkey/iteratorwithkey.go index 94e5618e..4efeb7e1 100644 --- a/examples/iteratorwithkey.go +++ b/examples/iteratorwithkey/iteratorwithkey.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import ( "fmt" @@ -10,7 +10,7 @@ import ( ) // IteratorWithKeyExample to demonstrate basic usage of IteratorWithKey -func IteratorWithKeyExample() { +func main() { m := treemap.NewWithIntComparator() m.Put(1, "a") m.Put(2, "b") diff --git a/examples/linkedliststack.go b/examples/linkedliststack/linkedliststack.go similarity index 93% rename from examples/linkedliststack.go rename to examples/linkedliststack/linkedliststack.go index 46ddf408..e9f1a68e 100644 --- a/examples/linkedliststack.go +++ b/examples/linkedliststack/linkedliststack.go @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import lls "github.com/emirpasic/gods/stacks/linkedliststack" // LinkedListStackExample to demonstrate basic usage of LinkedListStack -func LinkedListStackExample() { +func main() { stack := lls.New() // empty stack.Push(1) // 1 stack.Push(2) // 1, 2 diff --git a/examples/redblacktree.go b/examples/redblacktree/redblacktree.go similarity index 96% rename from examples/redblacktree.go rename to examples/redblacktree/redblacktree.go index ad36e6c6..b7d9803f 100644 --- a/examples/redblacktree.go +++ b/examples/redblacktree/redblacktree.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import ( "fmt" @@ -10,7 +10,7 @@ import ( ) // RedBlackTreeExample to demonstrate basic usage of RedBlackTree -func RedBlackTreeExample() { +func main() { tree := rbt.NewWithIntComparator() // empty(keys are of type int) tree.Put(1, "x") // 1->x diff --git a/examples/redblacktreeextended.go b/examples/redblacktreeextended/redblacktreeextended.go similarity index 98% rename from examples/redblacktreeextended.go rename to examples/redblacktreeextended/redblacktreeextended.go index 9823a6b9..6e901299 100644 --- a/examples/redblacktreeextended.go +++ b/examples/redblacktreeextended/redblacktreeextended.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package redblacktreeextended import ( "fmt" @@ -81,7 +81,7 @@ func print(tree *RedBlackTreeExtended) { } // RedBlackTreeExtendedExample main method on how to use the custom red-black tree above -func RedBlackTreeExtendedExample() { +func main() { tree := RedBlackTreeExtended{rbt.NewWithIntComparator()} tree.Put(1, "a") // 1->x (in order) diff --git a/examples/serialization.go b/examples/serialization/serialization.go similarity index 98% rename from examples/serialization.go rename to examples/serialization/serialization.go index 72a1ebf4..2f94c5ed 100644 --- a/examples/serialization.go +++ b/examples/serialization/serialization.go @@ -1,4 +1,4 @@ -package examples +package serialization import ( "fmt" diff --git a/examples/singlylinkedlist.go b/examples/singlylinkedlist/singlylinkedlist.go similarity index 95% rename from examples/singlylinkedlist.go rename to examples/singlylinkedlist/singlylinkedlist.go index 5d3036ad..93b4ccaf 100644 --- a/examples/singlylinkedlist.go +++ b/examples/singlylinkedlist/singlylinkedlist.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import ( sll "github.com/emirpasic/gods/lists/singlylinkedlist" @@ -10,7 +10,7 @@ import ( ) // SinglyLinkedListExample to demonstrate basic usage of SinglyLinkedList -func SinglyLinkedListExample() { +func main() { list := sll.New() list.Add("a") // ["a"] list.Append("b") // ["a","b"] (same as Add()) diff --git a/examples/sort.go b/examples/sort/sort.go similarity index 94% rename from examples/sort.go rename to examples/sort/sort.go index 854b95b8..9f0bd2ac 100644 --- a/examples/sort.go +++ b/examples/sort/sort.go @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import "github.com/emirpasic/gods/utils" // SortExample to demonstrate basic usage of basic sort -func SortExample() { +func main() { strings := []interface{}{} // [] strings = append(strings, "d") // ["d"] strings = append(strings, "a") // ["d","a"] diff --git a/examples/treebidimap.go b/examples/treebidimap/treebidimap.go similarity index 95% rename from examples/treebidimap.go rename to examples/treebidimap/treebidimap.go index f4138cb2..0c63f122 100644 --- a/examples/treebidimap.go +++ b/examples/treebidimap/treebidimap.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import ( "github.com/emirpasic/gods/maps/treebidimap" @@ -10,7 +10,7 @@ import ( ) // TreeBidiMapExample to demonstrate basic usage of TreeBidiMap -func TreeBidiMapExample() { +func main() { m := treebidimap.NewWith(utils.IntComparator, utils.StringComparator) m.Put(1, "x") // 1->x m.Put(3, "b") // 1->x, 3->b (ordered) diff --git a/examples/treemap.go b/examples/treemap/treemap.go similarity index 95% rename from examples/treemap.go rename to examples/treemap/treemap.go index 0f4e8d65..66b62cc4 100644 --- a/examples/treemap.go +++ b/examples/treemap/treemap.go @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import "github.com/emirpasic/gods/maps/treemap" // TreeMapExample to demonstrate basic usage of TreeMap -func TreeMapExample() { +func main() { m := treemap.NewWithIntComparator() // empty (keys are of type int) m.Put(1, "x") // 1->x m.Put(2, "b") // 1->x, 2->b (in order) diff --git a/examples/treeset.go b/examples/treeset/treeset.go similarity index 95% rename from examples/treeset.go rename to examples/treeset/treeset.go index 23caa161..15a7f81a 100644 --- a/examples/treeset.go +++ b/examples/treeset/treeset.go @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package examples +package main import "github.com/emirpasic/gods/sets/treeset" // TreeSetExample to demonstrate basic usage of TreeSet -func TreeSetExample() { +func main() { set := treeset.NewWithIntComparator() // empty set.Add(1) // 1 set.Add(2, 2, 3, 4, 5) // 1, 2, 3, 4, 5 (in order, duplicates ignored) From 843fdb4848f33df9a222e85e6a9d721c18d9ab41 Mon Sep 17 00:00:00 2001 From: Blake Miner Date: Wed, 19 Sep 2018 14:41:47 -0400 Subject: [PATCH 181/320] Added `Set(index, value)` method to all Lists (closes #86) Added tests --- lists/arraylist/arraylist.go | 19 ++++++++++- lists/arraylist/arraylist_test.go | 21 ++++++++++++ lists/doublylinkedlist/doublylinkedlist.go | 34 ++++++++++++++++++- .../doublylinkedlist/doublylinkedlist_test.go | 29 +++++++++++++++- lists/lists.go | 1 + lists/singlylinkedlist/singlylinkedlist.go | 23 ++++++++++++- .../singlylinkedlist/singlylinkedlist_test.go | 24 ++++++++++++- 7 files changed, 146 insertions(+), 5 deletions(-) diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index 1ace92a2..e0919eb3 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -11,9 +11,10 @@ package arraylist import ( "fmt" + "strings" + "github.com/emirpasic/gods/lists" "github.com/emirpasic/gods/utils" - "strings" ) func assertListImplementation() { @@ -162,6 +163,22 @@ func (list *List) Insert(index int, values ...interface{}) { copy(list.elements[index:], values) } +// Set the value at specified index +// Does not do anything if position is negative or bigger than list's size +// Note: position equal to list's size is valid, i.e. append. +func (list *List) Set(index int, value interface{}) { + + if !list.withinRange(index) { + // Append + if index == list.size { + list.Add(value) + } + return + } + + list.elements[index] = value +} + // String returns a string representation of container func (list *List) String() string { str := "ArrayList\n" diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 3e31e3dc..c4d9a7c6 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -178,6 +178,27 @@ func TestListInsert(t *testing.T) { } } +func TestListSet(t *testing.T) { + list := New() + list.Set(0, "a") + list.Set(1, "b") + if actualValue := list.Size(); actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, 2) + } + list.Set(2, "c") // append + if actualValue := list.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + list.Set(4, "d") // ignore + list.Set(1, "bb") // update + if actualValue := list.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abbc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + func TestListEach(t *testing.T) { list := New() list.Add("a", "b", "c") diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index ab0e1bc2..836d867c 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -11,9 +11,10 @@ package doublylinkedlist import ( "fmt" + "strings" + "github.com/emirpasic/gods/lists" "github.com/emirpasic/gods/utils" - "strings" ) func assertListImplementation() { @@ -292,6 +293,37 @@ func (list *List) Insert(index int, values ...interface{}) { } } +// Sets value at specified index position +// Does not do anything if position is negative or bigger than list's size +// Note: position equal to list's size is valid, i.e. append. +func (list *List) Set(index int, value interface{}) { + + if !list.withinRange(index) { + // Append + if index == list.size { + list.Add(value) + } + return + } + + var foundElement *element + // determine traversal direction, last to first or first to last + if list.size-index < index { + foundElement = list.last + for e := list.size - 1; e != index; { + fmt.Println("Set last", index, value, foundElement, foundElement.prev) + e, foundElement = e-1, foundElement.prev + } + } else { + foundElement = list.first + for e := 0; e != index; { + e, foundElement = e+1, foundElement.next + } + } + + foundElement.value = value +} + // String returns a string representation of container func (list *List) String() string { str := "DoublyLinkedList\n" diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 4794da93..1f0d5a6f 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -6,8 +6,9 @@ package doublylinkedlist import ( "fmt" - "github.com/emirpasic/gods/utils" "testing" + + "github.com/emirpasic/gods/utils" ) func TestListAdd(t *testing.T) { @@ -177,6 +178,32 @@ func TestListInsert(t *testing.T) { } } +func TestListSet(t *testing.T) { + list := New() + list.Set(0, "a") + list.Set(1, "b") + if actualValue := list.Size(); actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, 2) + } + list.Set(2, "c") // append + if actualValue := list.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + list.Set(4, "d") // ignore + list.Set(1, "bb") // update + if actualValue := list.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abbc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + list.Set(2, "cc") // last to first traversal + list.Set(0, "aa") // first to last traversal + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "aabbcc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + func TestListEach(t *testing.T) { list := New() list.Add("a", "b", "c") diff --git a/lists/lists.go b/lists/lists.go index 3b1d3239..1f6bb08e 100644 --- a/lists/lists.go +++ b/lists/lists.go @@ -23,6 +23,7 @@ type List interface { Sort(comparator utils.Comparator) Swap(index1, index2 int) Insert(index int, values ...interface{}) + Set(index int, value interface{}) containers.Container // Empty() bool diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 45ee69c5..2d0f0bb6 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -11,9 +11,10 @@ package singlylinkedlist import ( "fmt" + "strings" + "github.com/emirpasic/gods/lists" "github.com/emirpasic/gods/utils" - "strings" ) func assertListImplementation() { @@ -260,6 +261,26 @@ func (list *List) Insert(index int, values ...interface{}) { } } +// Sets value at specified index +// Does not do anything if position is negative or bigger than list's size +// Note: position equal to list's size is valid, i.e. append. +func (list *List) Set(index int, value interface{}) { + + if !list.withinRange(index) { + // Append + if index == list.size { + list.Add(value) + } + return + } + + foundElement := list.first + for e := 0; e != index; { + e, foundElement = e+1, foundElement.next + } + foundElement.value = value +} + // String returns a string representation of container func (list *List) String() string { str := "SinglyLinkedList\n" diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index 36e080d5..de1cd0dc 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -6,8 +6,9 @@ package singlylinkedlist import ( "fmt" - "github.com/emirpasic/gods/utils" "testing" + + "github.com/emirpasic/gods/utils" ) func TestListAdd(t *testing.T) { @@ -177,6 +178,27 @@ func TestListInsert(t *testing.T) { } } +func TestListSet(t *testing.T) { + list := New() + list.Set(0, "a") + list.Set(1, "b") + if actualValue := list.Size(); actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, 2) + } + list.Set(2, "c") // append + if actualValue := list.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + list.Set(4, "d") // ignore + list.Set(1, "bb") // update + if actualValue := list.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abbc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + func TestListEach(t *testing.T) { list := New() list.Add("a", "b", "c") From 17852f48a5325227d387d60c74d43f4bd2369142 Mon Sep 17 00:00:00 2001 From: emirpasic Date: Thu, 20 Sep 2018 17:44:34 +0200 Subject: [PATCH 182/320] - update documentation and comments --- README.md | 1 + lists/arraylist/arraylist_test.go | 2 +- lists/doublylinkedlist/doublylinkedlist.go | 2 +- lists/singlylinkedlist/singlylinkedlist.go | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cfcdb6c2..492f373e 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ type List interface { Sort(comparator utils.Comparator) Swap(index1, index2 int) Insert(index int, values ...interface{}) + Set(index int, value interface{}) containers.Container // Empty() bool diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index c4d9a7c6..ced20c5c 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -189,7 +189,7 @@ func TestListSet(t *testing.T) { if actualValue := list.Size(); actualValue != 3 { t.Errorf("Got %v expected %v", actualValue, 3) } - list.Set(4, "d") // ignore + list.Set(4, "d") // ignore list.Set(1, "bb") // update if actualValue := list.Size(); actualValue != 3 { t.Errorf("Got %v expected %v", actualValue, 3) diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 836d867c..97ddbada 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -293,7 +293,7 @@ func (list *List) Insert(index int, values ...interface{}) { } } -// Sets value at specified index position +// Set value at specified index position // Does not do anything if position is negative or bigger than list's size // Note: position equal to list's size is valid, i.e. append. func (list *List) Set(index int, value interface{}) { diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 2d0f0bb6..95eabd32 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -261,7 +261,7 @@ func (list *List) Insert(index int, values ...interface{}) { } } -// Sets value at specified index +// Set value at specified index // Does not do anything if position is negative or bigger than list's size // Note: position equal to list's size is valid, i.e. append. func (list *List) Set(index int, value interface{}) { From 370f7ab252bf7f9f3e8832a0d67c06aee657d027 Mon Sep 17 00:00:00 2001 From: emirpasic Date: Thu, 20 Sep 2018 18:07:43 +0200 Subject: [PATCH 183/320] - fix https://github.com/emirpasic/gods/issues/85 --- trees/redblacktree/redblacktree.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index b012d244..ecc199e7 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -64,6 +64,8 @@ func NewWithStringComparator() *Tree { func (tree *Tree) Put(key interface{}, value interface{}) { var insertedNode *Node if tree.Root == nil { + // Assert key is of comparator's type for initial tree + tree.Comparator(key, key) tree.Root = &Node{Key: key, Value: value, color: red} insertedNode = tree.Root } else { From c6630349c445d3a0bd1dda57ac17bfcb9b308e2d Mon Sep 17 00:00:00 2001 From: emirpasic Date: Thu, 20 Sep 2018 18:40:32 +0200 Subject: [PATCH 184/320] - bulk initialization for lists --- lists/arraylist/arraylist.go | 15 ++++------ lists/arraylist/arraylist_test.go | 29 +++++++++++++++++-- lists/doublylinkedlist/doublylinkedlist.go | 15 ++++------ .../doublylinkedlist/doublylinkedlist_test.go | 26 +++++++++++++++++ lists/singlylinkedlist/singlylinkedlist.go | 15 ++++------ .../singlylinkedlist/singlylinkedlist_test.go | 26 +++++++++++++++++ 6 files changed, 97 insertions(+), 29 deletions(-) diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index 34eeb4e2..15fe5f68 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -32,15 +32,12 @@ const ( shrinkFactor = float32(0.25) // shrink when size is 25% of capacity (0 means never shrink) ) -// New instantiates a new empty list -func New() *List { - return &List{} -} - -// Of instantiates a new list of the given values -func Of(values ...interface{}) *List { - list := New() - list.Add(values) +// New instantiates a new list and adds the passed values, if any, to the list +func New(values ...interface{}) *List { + list := &List{} + if len(values) > 0 { + list.Add(values...) + } return list } diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index ced20c5c..0d7eae48 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -6,11 +6,36 @@ package arraylist import ( "fmt" - "testing" - "github.com/emirpasic/gods/utils" + "testing" ) +func TestListNew(t *testing.T) { + list1 := New() + + if actualValue := list1.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + + list2 := New(1, "b") + + if actualValue := list2.Size(); actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, 2) + } + + if actualValue, ok := list2.Get(0); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } + + if actualValue, ok := list2.Get(1); actualValue != "b" || !ok { + t.Errorf("Got %v expected %v", actualValue, "b") + } + + if actualValue, ok := list2.Get(2); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } +} + func TestListAdd(t *testing.T) { list := New() list.Add("a") diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 5daf5eb3..be282517 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -34,15 +34,12 @@ type element struct { next *element } -// New instantiates a new empty list -func New() *List { - return &List{} -} - -// Of instantiates a new list of the given values -func Of(values ...interface{}) *List { - list := New() - list.Add(values) +// New instantiates a new list and adds the passed values, if any, to the list +func New(values ...interface{}) *List { + list := &List{} + if len(values) > 0 { + list.Add(values...) + } return list } diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 1f0d5a6f..596bd2e4 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -11,6 +11,32 @@ import ( "github.com/emirpasic/gods/utils" ) +func TestListNew(t *testing.T) { + list1 := New() + + if actualValue := list1.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + + list2 := New(1, "b") + + if actualValue := list2.Size(); actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, 2) + } + + if actualValue, ok := list2.Get(0); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } + + if actualValue, ok := list2.Get(1); actualValue != "b" || !ok { + t.Errorf("Got %v expected %v", actualValue, "b") + } + + if actualValue, ok := list2.Get(2); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } +} + func TestListAdd(t *testing.T) { list := New() list.Add("a") diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 86e58a98..803d70cd 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -33,15 +33,12 @@ type element struct { next *element } -// New instantiates a new empty list -func New() *List { - return &List{} -} - -// Of instantiates a new list of the given values -func Of(values ...interface{}) *List { - list := New() - list.Add(values) +// New instantiates a new list and adds the passed values, if any, to the list +func New(values ...interface{}) *List { + list := &List{} + if len(values) > 0 { + list.Add(values...) + } return list } diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index de1cd0dc..9b6fe59c 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -11,6 +11,32 @@ import ( "github.com/emirpasic/gods/utils" ) +func TestListNew(t *testing.T) { + list1 := New() + + if actualValue := list1.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + + list2 := New(1, "b") + + if actualValue := list2.Size(); actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, 2) + } + + if actualValue, ok := list2.Get(0); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } + + if actualValue, ok := list2.Get(1); actualValue != "b" || !ok { + t.Errorf("Got %v expected %v", actualValue, "b") + } + + if actualValue, ok := list2.Get(2); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } +} + func TestListAdd(t *testing.T) { list := New() list.Add("a") From 1befeeefc9097a114c62e57f1be20f31c38c7907 Mon Sep 17 00:00:00 2001 From: emirpasic Date: Thu, 20 Sep 2018 23:55:51 +0200 Subject: [PATCH 185/320] - fix comments --- lists/arraylist/arraylist.go | 2 +- lists/doublylinkedlist/doublylinkedlist.go | 2 +- lists/singlylinkedlist/singlylinkedlist.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index 15fe5f68..bfedac9e 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -61,7 +61,7 @@ func (list *List) Get(index int) (interface{}, bool) { return list.elements[index], true } -// Remove removes one or more elements from the list with the supplied indices. +// Remove removes the element at the given index from the list. func (list *List) Remove(index int) { if !list.withinRange(index) { diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index be282517..9035e38e 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -100,7 +100,7 @@ func (list *List) Get(index int) (interface{}, bool) { return element.value, true } -// Remove removes one or more elements from the list with the supplied indices. +// Remove removes the element at the given index from the list. func (list *List) Remove(index int) { if !list.withinRange(index) { diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 803d70cd..b61df78f 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -90,7 +90,7 @@ func (list *List) Get(index int) (interface{}, bool) { return element.value, true } -// Remove removes one or more elements from the list with the supplied indices. +// Remove removes the element at the given index from the list. func (list *List) Remove(index int) { if !list.withinRange(index) { From 413aad030416e2632d07afbb70487ee4c7e98c50 Mon Sep 17 00:00:00 2001 From: emirpasic Date: Fri, 21 Sep 2018 01:09:03 +0200 Subject: [PATCH 186/320] - fix treeset iterator Last() function --- sets/treeset/iterator.go | 2 +- sets/treeset/treeset_test.go | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sets/treeset/iterator.go b/sets/treeset/iterator.go index 2cb465f8..9dd62893 100644 --- a/sets/treeset/iterator.go +++ b/sets/treeset/iterator.go @@ -85,5 +85,5 @@ func (iterator *Iterator) First() bool { // Modifies the state of the iterator. func (iterator *Iterator) Last() bool { iterator.End() - return iterator.iterator.Last() + return iterator.Prev() } diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index 0f4b667d..0dfe39b7 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -265,10 +265,10 @@ func TestSetIteratorPrev(t *testing.T) { } func TestSetIteratorBegin(t *testing.T) { - m := NewWithStringComparator() - it := m.Iterator() + set := NewWithStringComparator() + it := set.Iterator() it.Begin() - m.Add("a", "b", "c") + set.Add("a", "b", "c") for it.Next() { } it.Begin() @@ -322,8 +322,8 @@ func TestSetIteratorLast(t *testing.T) { if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if index, value := it.Index(), it.Value(); index != 3 || value != "c" { - t.Errorf("Got %v,%v expected %v,%v", index, value, 3, "c") + if index, value := it.Index(), it.Value(); index != 2 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "c") } } From b5b20b02b34b6d6be0aa9a132d15a2516f07a0f3 Mon Sep 17 00:00:00 2001 From: emirpasic Date: Fri, 21 Sep 2018 01:55:06 +0200 Subject: [PATCH 187/320] - linkedhashset implementation + iterator + serialization + tests + example + enumerable + documentation --- examples/linkedhashset/linkedhashset.go | 23 ++ sets/linkedhashset/enumerable.go | 79 ++++ sets/linkedhashset/iterator.go | 77 ++++ sets/linkedhashset/linkedhashset.go | 118 ++++++ sets/linkedhashset/linkedhashset_test.go | 498 +++++++++++++++++++++++ sets/linkedhashset/serialization.go | 31 ++ 6 files changed, 826 insertions(+) create mode 100644 examples/linkedhashset/linkedhashset.go create mode 100644 sets/linkedhashset/enumerable.go create mode 100644 sets/linkedhashset/iterator.go create mode 100644 sets/linkedhashset/linkedhashset.go create mode 100644 sets/linkedhashset/linkedhashset_test.go create mode 100644 sets/linkedhashset/serialization.go diff --git a/examples/linkedhashset/linkedhashset.go b/examples/linkedhashset/linkedhashset.go new file mode 100644 index 00000000..689d212d --- /dev/null +++ b/examples/linkedhashset/linkedhashset.go @@ -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 +} diff --git a/sets/linkedhashset/enumerable.go b/sets/linkedhashset/enumerable.go new file mode 100644 index 00000000..ad6ac967 --- /dev/null +++ b/sets/linkedhashset/enumerable.go @@ -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 +} diff --git a/sets/linkedhashset/iterator.go b/sets/linkedhashset/iterator.go new file mode 100644 index 00000000..dfdbfc56 --- /dev/null +++ b/sets/linkedhashset/iterator.go @@ -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() +} diff --git a/sets/linkedhashset/linkedhashset.go b/sets/linkedhashset/linkedhashset.go new file mode 100644 index 00000000..a9fb2aea --- /dev/null +++ b/sets/linkedhashset/linkedhashset.go @@ -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 +} diff --git a/sets/linkedhashset/linkedhashset_test.go b/sets/linkedhashset/linkedhashset_test.go new file mode 100644 index 00000000..cf3746e0 --- /dev/null +++ b/sets/linkedhashset/linkedhashset_test.go @@ -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) +} diff --git a/sets/linkedhashset/serialization.go b/sets/linkedhashset/serialization.go new file mode 100644 index 00000000..806b908f --- /dev/null +++ b/sets/linkedhashset/serialization.go @@ -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 +} From 555738833ba5448aedf9cf809506503a90432e5f Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 21 Sep 2018 02:04:55 +0200 Subject: [PATCH 188/320] Add LinkedHashSet documentation --- README.md | 71 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 492f373e..9c1dd322 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Implementation of various data structures and algorithms in Go. - [Sets](#sets) - [HashSet](#hashset) - [TreeSet](#treeset) + - [LinkedHashSet](#linkedhashset) - [Stacks](#stacks) - [LinkedListStack](#linkedliststack) - [ArrayStack](#arraystack) @@ -60,24 +61,30 @@ type Container interface { Containers are either ordered or unordered. All ordered containers provide [stateful iterators](#iterator) and some of them allow [enumerable functions](#enumerable). -| Container | Ordered | [Iterator](#iterator) | [Enumerable](#enumerable) | Referenced by | -| :--- | :---: | :---: | :---: | :---: | -| [ArrayList](#arraylist) | yes | yes* | yes | index | -| [SinglyLinkedList](#singlylinkedlist) | yes | yes | yes | index | -| [DoublyLinkedList](#doublylinkedlist) | yes | yes* | yes | index | -| [HashSet](#hashset) | no | no | no | index | -| [TreeSet](#treeset) | yes | yes* | yes | index | -| [LinkedListStack](#linkedliststack) | yes | yes | no | index | -| [ArrayStack](#arraystack) | yes | yes* | no | index | -| [HashMap](#hashmap) | no | no | no | key | -| [TreeMap](#treemap) | yes | yes* | yes | key | -| [HashBidiMap](#hashbidimap) | no | no | no | key* | -| [TreeBidiMap](#treebidimap) | yes | yes* | yes | key* | -| [RedBlackTree](#redblacktree) | yes | yes* | no | key | -| [AVLTree](#avltree) | yes | yes* | no | key | -| [BTree](#btree) | yes | yes* | no | key | -| [BinaryHeap](#binaryheap) | yes | yes* | no | index | -| | | *reversible | | *bidirectional | +| **Data** | **Structure** | **Ordered** | **[Iterator](#iterator)** | **[Enumerable](#enumerable)** | **Referenced by** | +| :--- | :--- | :---: | :---: | :---: | :---: | +| **[Lists](#lists)** | +| | [ArrayList](#arraylist) | yes | yes* | yes | index | +| | [SinglyLinkedList](#singlylinkedlist) | yes | yes | yes | index | +| | [DoublyLinkedList](#doublylinkedlist) | yes | yes* | yes | index | +| **[Sets](#sets)** | +| | [HashSet](#hashset) | no | no | no | index | +| | [TreeSet](#treeset) | yes | yes* | yes | index | +| | [LinkedHashSet](#linkedhashset) | yes | yes* | yes | index | +| **[Stacks](#stacks)** | +| | [LinkedListStack](#linkedliststack) | yes | yes | no | index | +| | [ArrayStack](#arraystack) | yes | yes* | no | index | +| **[Maps](#maps)** | +| | [HashMap](#hashmap) | no | no | no | key | +| | [TreeMap](#treemap) | yes | yes* | yes | key | +| | [HashBidiMap](#hashbidimap) | no | no | no | key* | +| **[Trees](#trees)** | +| | [TreeBidiMap](#treebidimap) | yes | yes* | yes | key* | +| | [RedBlackTree](#redblacktree) | yes | yes* | no | key | +| | [AVLTree](#avltree) | yes | yes* | no | key | +| | [BTree](#btree) | yes | yes* | no | key | +| | [BinaryHeap](#binaryheap) | yes | yes* | no | index | +| | | | *reversible | | *bidirectional | ### Lists @@ -289,6 +296,34 @@ func main() { } ``` +#### LinkedHashSet + +A [set](#sets) that preserves insertion-order. Data structure is backed by a hash table to store values and [doubly-linked list](#doublylinkedlist) to store insertion ordering. + +Implements [Set](#sets), [IteratorWithIndex](#iteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. + +```go +package main + +import "github.com/emirpasic/gods/sets/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.Add(4) // 5, 4, 3, 2, 1 (duplicates ignored, insertion-order unchanged) + 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 +} +``` + ### Stacks A stack that represents a last-in-first-out (LIFO) data structure. The usual push and pop operations are provided, as well as a method to peek at the top item on the stack. From bc82528e1e6ee24eb7292cc10ac772281bfb7648 Mon Sep 17 00:00:00 2001 From: emirpasic Date: Fri, 21 Sep 2018 02:27:02 +0200 Subject: [PATCH 189/320] Sets bulk intialization --- sets/hashset/hashset.go | 10 +++++++--- sets/hashset/hashset_test.go | 17 +++++++++++++++++ sets/linkedhashset/linkedhashset.go | 10 +++++++--- sets/linkedhashset/linkedhashset_test.go | 14 ++++++++++++++ sets/treeset/treeset.go | 24 ++++++++++++++++++------ sets/treeset/treeset_test.go | 14 ++++++++++++++ 6 files changed, 77 insertions(+), 12 deletions(-) diff --git a/sets/hashset/hashset.go b/sets/hashset/hashset.go index 9669d384..815d0490 100644 --- a/sets/hashset/hashset.go +++ b/sets/hashset/hashset.go @@ -26,9 +26,13 @@ type Set struct { var itemExists = struct{}{} -// New instantiates a new empty set -func New() *Set { - return &Set{items: make(map[interface{}]struct{})} +// New instantiates a new empty set and adds the passed values, if any, to the set +func New(values ...interface{}) *Set { + set := &Set{items: make(map[interface{}]struct{})} + if len(values) > 0 { + set.Add(values...) + } + return set } // Add adds the items (one or more) to the set. diff --git a/sets/hashset/hashset_test.go b/sets/hashset/hashset_test.go index 280a6b30..cf63c899 100644 --- a/sets/hashset/hashset_test.go +++ b/sets/hashset/hashset_test.go @@ -8,6 +8,23 @@ import ( "testing" ) +func TestSetNew(t *testing.T) { + set := New(2, 1) + + if actualValue := set.Size(); actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue := set.Contains(1); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + if actualValue := set.Contains(2); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + if actualValue := set.Contains(3); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, true) + } +} + func TestSetAdd(t *testing.T) { set := New() set.Add() diff --git a/sets/linkedhashset/linkedhashset.go b/sets/linkedhashset/linkedhashset.go index a9fb2aea..6bce5f63 100644 --- a/sets/linkedhashset/linkedhashset.go +++ b/sets/linkedhashset/linkedhashset.go @@ -30,12 +30,16 @@ type Set struct { var itemExists = struct{}{} -// New instantiates a new empty set -func New() *Set { - return &Set{ +// New instantiates a new empty set and adds the passed values, if any, to the set +func New(values ...interface{}) *Set { + set := &Set{ items: make(map[interface{}]struct{}), list: doublylinkedlist.New(), } + if len(values) > 0 { + set.Add(values...) + } + return set } // Add adds the items (one or more) to the set. diff --git a/sets/linkedhashset/linkedhashset_test.go b/sets/linkedhashset/linkedhashset_test.go index cf3746e0..10b6da2d 100644 --- a/sets/linkedhashset/linkedhashset_test.go +++ b/sets/linkedhashset/linkedhashset_test.go @@ -9,6 +9,20 @@ import ( "testing" ) +func TestSetNew(t *testing.T) { + set := New(2, 1) + if actualValue := set.Size(); actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, 2) + } + values := set.Values() + if actualValue := values[0]; actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue := values[1]; actualValue != 1 { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + func TestSetAdd(t *testing.T) { set := New() set.Add() diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 9ead6341..7efbf2dc 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -29,18 +29,30 @@ type Set struct { var itemExists = struct{}{} // NewWith instantiates a new empty set with the custom comparator. -func NewWith(comparator utils.Comparator) *Set { - return &Set{tree: rbt.NewWith(comparator)} +func NewWith(comparator utils.Comparator, values ...interface{}) *Set { + set := &Set{tree: rbt.NewWith(comparator)} + if len(values) > 0 { + set.Add(values...) + } + return set } // NewWithIntComparator instantiates a new empty set with the IntComparator, i.e. keys are of type int. -func NewWithIntComparator() *Set { - return &Set{tree: rbt.NewWithIntComparator()} +func NewWithIntComparator(values ...interface{}) *Set { + set := &Set{tree: rbt.NewWithIntComparator()} + if len(values) > 0 { + set.Add(values...) + } + return set } // NewWithStringComparator instantiates a new empty set with the StringComparator, i.e. keys are of type string. -func NewWithStringComparator() *Set { - return &Set{tree: rbt.NewWithStringComparator()} +func NewWithStringComparator(values ...interface{}) *Set { + set := &Set{tree: rbt.NewWithStringComparator()} + if len(values) > 0 { + set.Add(values...) + } + return set } // Add adds the items (one or more) to the set. diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index 0dfe39b7..b3cfca9d 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -9,6 +9,20 @@ import ( "testing" ) +func TestSetNew(t *testing.T) { + set := NewWithIntComparator(2, 1) + if actualValue := set.Size(); actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, 2) + } + values := set.Values() + if actualValue := values[0]; actualValue != 1 { + t.Errorf("Got %v expected %v", actualValue, 1) + } + if actualValue := values[1]; actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, 2) + } +} + func TestSetAdd(t *testing.T) { set := NewWithIntComparator() set.Add() From bd99060a93d22e74ebfc5881e7f3b37a0b83fbc3 Mon Sep 17 00:00:00 2001 From: emirpasic Date: Fri, 21 Sep 2018 02:43:37 +0200 Subject: [PATCH 190/320] - update comments and documentation --- README.md | 10 +++++----- sets/linkedhashset/linkedhashset.go | 4 +++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 9c1dd322..3816525b 100644 --- a/README.md +++ b/README.md @@ -63,22 +63,22 @@ Containers are either ordered or unordered. All ordered containers provide [stat | **Data** | **Structure** | **Ordered** | **[Iterator](#iterator)** | **[Enumerable](#enumerable)** | **Referenced by** | | :--- | :--- | :---: | :---: | :---: | :---: | -| **[Lists](#lists)** | +| [Lists](#lists) | | | [ArrayList](#arraylist) | yes | yes* | yes | index | | | [SinglyLinkedList](#singlylinkedlist) | yes | yes | yes | index | | | [DoublyLinkedList](#doublylinkedlist) | yes | yes* | yes | index | -| **[Sets](#sets)** | +| [Sets](#sets) | | | [HashSet](#hashset) | no | no | no | index | | | [TreeSet](#treeset) | yes | yes* | yes | index | | | [LinkedHashSet](#linkedhashset) | yes | yes* | yes | index | -| **[Stacks](#stacks)** | +| [Stacks](#stacks) | | | [LinkedListStack](#linkedliststack) | yes | yes | no | index | | | [ArrayStack](#arraystack) | yes | yes* | no | index | -| **[Maps](#maps)** | +| [Maps](#maps) | | | [HashMap](#hashmap) | no | no | no | key | | | [TreeMap](#treemap) | yes | yes* | yes | key | | | [HashBidiMap](#hashbidimap) | no | no | no | key* | -| **[Trees](#trees)** | +| [Trees](#trees) | | | [TreeBidiMap](#treebidimap) | yes | yes* | yes | key* | | | [RedBlackTree](#redblacktree) | yes | yes* | no | key | | | [AVLTree](#avltree) | yes | yes* | no | key | diff --git a/sets/linkedhashset/linkedhashset.go b/sets/linkedhashset/linkedhashset.go index 6bce5f63..234fe46b 100644 --- a/sets/linkedhashset/linkedhashset.go +++ b/sets/linkedhashset/linkedhashset.go @@ -2,7 +2,9 @@ // 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. +// Package linkedhashset is a set that preserves insertion-order. +// +// It is backed by a hash table 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. // From 73e1b206f92a3bdcc977a57f7ec07e062b9f6bff Mon Sep 17 00:00:00 2001 From: emirpasic Date: Fri, 21 Sep 2018 03:20:36 +0200 Subject: [PATCH 191/320] - linkedhashset simplification --- sets/linkedhashset/iterator.go | 2 +- sets/linkedhashset/linkedhashset.go | 36 ++++++++++++----------------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/sets/linkedhashset/iterator.go b/sets/linkedhashset/iterator.go index dfdbfc56..3d190d91 100644 --- a/sets/linkedhashset/iterator.go +++ b/sets/linkedhashset/iterator.go @@ -20,7 +20,7 @@ type Iterator struct { // Iterator returns a stateful iterator whose values can be fetched by an index. func (set *Set) Iterator() Iterator { - return Iterator{iterator: set.list.Iterator()} + return Iterator{iterator: set.ordering.Iterator()} } // Next moves the iterator to the next element and returns true if there was a next element in the container. diff --git a/sets/linkedhashset/linkedhashset.go b/sets/linkedhashset/linkedhashset.go index 234fe46b..e589a127 100644 --- a/sets/linkedhashset/linkedhashset.go +++ b/sets/linkedhashset/linkedhashset.go @@ -26,8 +26,8 @@ func assertSetImplementation() { // Set holds elements in go's native map type Set struct { - items map[interface{}]struct{} - list *doublylinkedlist.List + table map[interface{}]struct{} + ordering *doublylinkedlist.List } var itemExists = struct{}{} @@ -35,8 +35,8 @@ var itemExists = struct{}{} // New instantiates a new empty set and adds the passed values, if any, to the set func New(values ...interface{}) *Set { set := &Set{ - items: make(map[interface{}]struct{}), - list: doublylinkedlist.New(), + table: make(map[interface{}]struct{}), + ordering: doublylinkedlist.New(), } if len(values) > 0 { set.Add(values...) @@ -48,13 +48,10 @@ func New(values ...interface{}) *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 + if _, contains := set.table[item]; !contains { + set.table[item] = itemExists + set.ordering.Append(item) } - - set.items[item] = itemExists - set.list.Append(item) } } @@ -62,14 +59,11 @@ func (set *Set) Add(items ...interface{}) { // Slow operation, worst-case O(n^2). func (set *Set) Remove(items ...interface{}) { for _, item := range items { - - if _, contains := set.items[item]; !contains { - continue + if _, contains := set.table[item]; contains { + delete(set.table, item) + index := set.ordering.IndexOf(item) + set.ordering.Remove(index) } - - delete(set.items, item) - index := set.list.IndexOf(item) - set.list.Remove(index) } } @@ -78,7 +72,7 @@ func (set *Set) Remove(items ...interface{}) { // 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 { + if _, contains := set.table[item]; !contains { return false } } @@ -92,13 +86,13 @@ func (set *Set) Empty() bool { // Size returns number of elements within the set. func (set *Set) Size() int { - return set.list.Size() + return set.ordering.Size() } // Clear clears all values in the set. func (set *Set) Clear() { - set.items = make(map[interface{}]struct{}) - set.list.Clear() + set.table = make(map[interface{}]struct{}) + set.ordering.Clear() } // Values returns all items in the set. From 5123d6be01ca9cb3e3a8b03a57eb999385f357a1 Mon Sep 17 00:00:00 2001 From: emirpasic Date: Fri, 21 Sep 2018 04:45:26 +0200 Subject: [PATCH 192/320] - fix comments/documentation, rigorous serialization testing --- maps/hashbidimap/serialization.go | 4 +- maps/hashmap/serialization.go | 4 +- maps/treebidimap/serialization.go | 4 +- maps/treebidimap/treebidimap_test.go | 62 ++++++++++++++++--------- maps/treemap/serialization.go | 4 +- maps/treemap/treemap_test.go | 62 ++++++++++++++++--------- sets/hashset/serialization.go | 4 +- sets/linkedhashset/serialization.go | 4 +- sets/treeset/serialization.go | 4 +- stacks/arraystack/serialization.go | 4 +- stacks/linkedliststack/serialization.go | 4 +- trees/avltree/serialization.go | 4 +- trees/binaryheap/serialization.go | 4 +- trees/btree/serialization.go | 4 +- trees/redblacktree/serialization.go | 4 +- 15 files changed, 106 insertions(+), 70 deletions(-) diff --git a/maps/hashbidimap/serialization.go b/maps/hashbidimap/serialization.go index 9f6247ef..3db41d42 100644 --- a/maps/hashbidimap/serialization.go +++ b/maps/hashbidimap/serialization.go @@ -14,12 +14,12 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Map)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the map. func (m *Map) ToJSON() ([]byte, error) { return m.forwardMap.ToJSON() } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the map from the input JSON representation. func (m *Map) FromJSON(data []byte) error { elements := make(map[string]interface{}) err := json.Unmarshal(data, &elements) diff --git a/maps/hashmap/serialization.go b/maps/hashmap/serialization.go index b8e9026e..b06eb7ef 100644 --- a/maps/hashmap/serialization.go +++ b/maps/hashmap/serialization.go @@ -15,7 +15,7 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Map)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the map. func (m *Map) ToJSON() ([]byte, error) { elements := make(map[string]interface{}) for key, value := range m.m { @@ -24,7 +24,7 @@ func (m *Map) ToJSON() ([]byte, error) { return json.Marshal(&elements) } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the map from the input JSON representation. func (m *Map) FromJSON(data []byte) error { elements := make(map[string]interface{}) err := json.Unmarshal(data, &elements) diff --git a/maps/treebidimap/serialization.go b/maps/treebidimap/serialization.go index f9a78507..17204f99 100644 --- a/maps/treebidimap/serialization.go +++ b/maps/treebidimap/serialization.go @@ -15,7 +15,7 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Map)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the map. func (m *Map) ToJSON() ([]byte, error) { elements := make(map[string]interface{}) it := m.Iterator() @@ -25,7 +25,7 @@ func (m *Map) ToJSON() ([]byte, error) { return json.Marshal(&elements) } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the map from the input JSON representation. func (m *Map) FromJSON(data []byte) error { elements := make(map[string]interface{}) err := json.Unmarshal(data, &elements) diff --git a/maps/treebidimap/treebidimap_test.go b/maps/treebidimap/treebidimap_test.go index 0ef5165f..bc7f4fa2 100644 --- a/maps/treebidimap/treebidimap_test.go +++ b/maps/treebidimap/treebidimap_test.go @@ -473,35 +473,53 @@ func TestMapIteratorLast(t *testing.T) { } } +//noinspection GoBoolExpressions func TestMapSerialization(t *testing.T) { - m := NewWithStringComparators() - m.Put("a", "1") - m.Put("b", "2") - m.Put("c", "3") - - var err error - assert := func() { - if actualValue := m.Keys(); actualValue[0].(string) != "a" || actualValue[1].(string) != "b" || actualValue[2].(string) != "c" { - t.Errorf("Got %v expected %v", actualValue, "[a,b,c]") - } - if actualValue := m.Values(); actualValue[0].(string) != "1" || actualValue[1].(string) != "2" || actualValue[2].(string) != "3" { - t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + for i := 0; i < 10; i++ { + original := NewWith(utils.StringComparator, utils.StringComparator) + original.Put("d", "4") + original.Put("e", "5") + original.Put("c", "3") + original.Put("b", "2") + original.Put("a", "1") + + assert := func(m *Map, txt string) { + if actualValue := m.Keys(); false || + actualValue[0].(string) != "a" || + actualValue[1].(string) != "b" || + actualValue[2].(string) != "c" || + actualValue[3].(string) != "d" || + actualValue[4].(string) != "e" { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[a,b,c,d,e]") + } + if actualValue := m.Values(); false || + actualValue[0].(string) != "1" || + actualValue[1].(string) != "2" || + actualValue[2].(string) != "3" || + actualValue[3].(string) != "4" || + actualValue[4].(string) != "5" { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[1,2,3,4,5]") + } + if actualValue, expectedValue := m.Size(), 5; actualValue != expectedValue { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, expectedValue) + } } - if actualValue, expectedValue := m.Size(), 3; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) + + assert(original, "A") + + serialized, err := original.ToJSON() + if err != nil { + t.Errorf("Got error %v", err) } + assert(original, "B") + + deserialized := NewWith(utils.StringComparator, utils.StringComparator) + err = deserialized.FromJSON(serialized) if err != nil { t.Errorf("Got error %v", err) } + assert(deserialized, "C") } - - assert() - - json, err := m.ToJSON() - assert() - - err = m.FromJSON(json) - assert() } func benchmarkGet(b *testing.B, m *Map, size int) { diff --git a/maps/treemap/serialization.go b/maps/treemap/serialization.go index 25f4a6fd..d856300d 100644 --- a/maps/treemap/serialization.go +++ b/maps/treemap/serialization.go @@ -11,12 +11,12 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Map)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the map. func (m *Map) ToJSON() ([]byte, error) { return m.tree.ToJSON() } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the map from the input JSON representation. func (m *Map) FromJSON(data []byte) error { return m.tree.FromJSON(data) } diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index a73e8734..d718c91c 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -440,35 +440,53 @@ func TestMapIteratorLast(t *testing.T) { } } +//noinspection GoBoolExpressions func TestMapSerialization(t *testing.T) { - m := NewWithStringComparator() - m.Put("a", "1") - m.Put("b", "2") - m.Put("c", "3") - - var err error - assert := func() { - if actualValue := m.Keys(); actualValue[0].(string) != "a" || actualValue[1].(string) != "b" || actualValue[2].(string) != "c" { - t.Errorf("Got %v expected %v", actualValue, "[a,b,c]") - } - if actualValue := m.Values(); actualValue[0].(string) != "1" || actualValue[1].(string) != "2" || actualValue[2].(string) != "3" { - t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + for i := 0; i < 10; i++ { + original := NewWithStringComparator() + original.Put("d", "4") + original.Put("e", "5") + original.Put("c", "3") + original.Put("b", "2") + original.Put("a", "1") + + assert := func(m *Map, txt string) { + if actualValue := m.Keys(); false || + actualValue[0].(string) != "a" || + actualValue[1].(string) != "b" || + actualValue[2].(string) != "c" || + actualValue[3].(string) != "d" || + actualValue[4].(string) != "e" { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[a,b,c,d,e]") + } + if actualValue := m.Values(); false || + actualValue[0].(string) != "1" || + actualValue[1].(string) != "2" || + actualValue[2].(string) != "3" || + actualValue[3].(string) != "4" || + actualValue[4].(string) != "5" { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[1,2,3,4,5]") + } + if actualValue, expectedValue := m.Size(), 5; actualValue != expectedValue { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, expectedValue) + } } - if actualValue, expectedValue := m.Size(), 3; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) + + assert(original, "A") + + serialized, err := original.ToJSON() + if err != nil { + t.Errorf("Got error %v", err) } + assert(original, "B") + + deserialized := NewWithStringComparator() + err = deserialized.FromJSON(serialized) if err != nil { t.Errorf("Got error %v", err) } + assert(deserialized, "C") } - - assert() - - json, err := m.ToJSON() - assert() - - err = m.FromJSON(json) - assert() } func benchmarkGet(b *testing.B, m *Map, size int) { diff --git a/sets/hashset/serialization.go b/sets/hashset/serialization.go index af7bfe8e..7b8506df 100644 --- a/sets/hashset/serialization.go +++ b/sets/hashset/serialization.go @@ -14,12 +14,12 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Set)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the set. func (set *Set) ToJSON() ([]byte, error) { return json.Marshal(set.Values()) } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the set from the input JSON representation. func (set *Set) FromJSON(data []byte) error { elements := []interface{}{} err := json.Unmarshal(data, &elements) diff --git a/sets/linkedhashset/serialization.go b/sets/linkedhashset/serialization.go index 806b908f..7e7d2911 100644 --- a/sets/linkedhashset/serialization.go +++ b/sets/linkedhashset/serialization.go @@ -14,12 +14,12 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Set)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the set. func (set *Set) ToJSON() ([]byte, error) { return json.Marshal(set.Values()) } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the set from the input JSON representation. func (set *Set) FromJSON(data []byte) error { elements := []interface{}{} err := json.Unmarshal(data, &elements) diff --git a/sets/treeset/serialization.go b/sets/treeset/serialization.go index 10b15998..a53bfccf 100644 --- a/sets/treeset/serialization.go +++ b/sets/treeset/serialization.go @@ -14,12 +14,12 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Set)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the set. func (set *Set) ToJSON() ([]byte, error) { return json.Marshal(set.Values()) } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the set from the input JSON representation. func (set *Set) FromJSON(data []byte) error { elements := []interface{}{} err := json.Unmarshal(data, &elements) diff --git a/stacks/arraystack/serialization.go b/stacks/arraystack/serialization.go index d1ad81d3..c4ff5497 100644 --- a/stacks/arraystack/serialization.go +++ b/stacks/arraystack/serialization.go @@ -11,12 +11,12 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Stack)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the stack. func (stack *Stack) ToJSON() ([]byte, error) { return stack.list.ToJSON() } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the stack from the input JSON representation. func (stack *Stack) FromJSON(data []byte) error { return stack.list.FromJSON(data) } diff --git a/stacks/linkedliststack/serialization.go b/stacks/linkedliststack/serialization.go index ac6a68c8..63337a1f 100644 --- a/stacks/linkedliststack/serialization.go +++ b/stacks/linkedliststack/serialization.go @@ -11,12 +11,12 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Stack)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the stack. func (stack *Stack) ToJSON() ([]byte, error) { return stack.list.ToJSON() } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the stack from the input JSON representation. func (stack *Stack) FromJSON(data []byte) error { return stack.list.FromJSON(data) } diff --git a/trees/avltree/serialization.go b/trees/avltree/serialization.go index 0630d877..363de7f4 100644 --- a/trees/avltree/serialization.go +++ b/trees/avltree/serialization.go @@ -15,7 +15,7 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Tree)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the tree. func (tree *Tree) ToJSON() ([]byte, error) { elements := make(map[string]interface{}) it := tree.Iterator() @@ -25,7 +25,7 @@ func (tree *Tree) ToJSON() ([]byte, error) { return json.Marshal(&elements) } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the tree from the input JSON representation. func (tree *Tree) FromJSON(data []byte) error { elements := make(map[string]interface{}) err := json.Unmarshal(data, &elements) diff --git a/trees/binaryheap/serialization.go b/trees/binaryheap/serialization.go index 299319bd..00d0c771 100644 --- a/trees/binaryheap/serialization.go +++ b/trees/binaryheap/serialization.go @@ -11,12 +11,12 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Heap)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the heap. func (heap *Heap) ToJSON() ([]byte, error) { return heap.list.ToJSON() } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the heap from the input JSON representation. func (heap *Heap) FromJSON(data []byte) error { return heap.list.FromJSON(data) } diff --git a/trees/btree/serialization.go b/trees/btree/serialization.go index 95c817e1..43851676 100644 --- a/trees/btree/serialization.go +++ b/trees/btree/serialization.go @@ -15,7 +15,7 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Tree)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the tree. func (tree *Tree) ToJSON() ([]byte, error) { elements := make(map[string]interface{}) it := tree.Iterator() @@ -25,7 +25,7 @@ func (tree *Tree) ToJSON() ([]byte, error) { return json.Marshal(&elements) } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the tree from the input JSON representation. func (tree *Tree) FromJSON(data []byte) error { elements := make(map[string]interface{}) err := json.Unmarshal(data, &elements) diff --git a/trees/redblacktree/serialization.go b/trees/redblacktree/serialization.go index 7969fc55..a1b8a779 100644 --- a/trees/redblacktree/serialization.go +++ b/trees/redblacktree/serialization.go @@ -15,7 +15,7 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Tree)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the tree. func (tree *Tree) ToJSON() ([]byte, error) { elements := make(map[string]interface{}) it := tree.Iterator() @@ -25,7 +25,7 @@ func (tree *Tree) ToJSON() ([]byte, error) { return json.Marshal(&elements) } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the tree from the input JSON representation. func (tree *Tree) FromJSON(data []byte) error { elements := make(map[string]interface{}) err := json.Unmarshal(data, &elements) From cbce19f31eeae796f107111ce703b4de31862d64 Mon Sep 17 00:00:00 2001 From: emirpasic Date: Fri, 21 Sep 2018 05:17:50 +0200 Subject: [PATCH 193/320] - linked hash map core implementation + iterator + enumerable + tests + serialization (TODO: examples + documentation) --- maps/linkedhashmap/enumerable.go | 80 +++ maps/linkedhashmap/iterator.go | 81 +++ maps/linkedhashmap/linkedhashmap.go | 109 ++++ maps/linkedhashmap/linkedhashmap_test.go | 643 +++++++++++++++++++++++ maps/linkedhashmap/serialization.go | 103 ++++ maps/treebidimap/treebidimap_test.go | 52 +- maps/treemap/treemap_test.go | 52 +- 7 files changed, 1068 insertions(+), 52 deletions(-) create mode 100644 maps/linkedhashmap/enumerable.go create mode 100644 maps/linkedhashmap/iterator.go create mode 100644 maps/linkedhashmap/linkedhashmap.go create mode 100644 maps/linkedhashmap/linkedhashmap_test.go create mode 100644 maps/linkedhashmap/serialization.go diff --git a/maps/linkedhashmap/enumerable.go b/maps/linkedhashmap/enumerable.go new file mode 100644 index 00000000..644b00fd --- /dev/null +++ b/maps/linkedhashmap/enumerable.go @@ -0,0 +1,80 @@ +// 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 linkedhashmap + +import "github.com/emirpasic/gods/containers" + +func assertEnumerableImplementation() { + var _ containers.EnumerableWithKey = (*Map)(nil) +} + +// Each calls the given function once for each element, passing that element's key and value. +func (m *Map) Each(f func(key interface{}, value interface{})) { + iterator := m.Iterator() + for iterator.Next() { + f(iterator.Key(), iterator.Value()) + } +} + +// 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. +func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) *Map { + newMap := New() + iterator := m.Iterator() + for iterator.Next() { + key2, value2 := f(iterator.Key(), iterator.Value()) + newMap.Put(key2, value2) + } + return newMap +} + +// Select returns a new container containing all elements for which the given function returns a true value. +func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map { + newMap := New() + iterator := m.Iterator() + for iterator.Next() { + if f(iterator.Key(), iterator.Value()) { + newMap.Put(iterator.Key(), iterator.Value()) + } + } + return newMap +} + +// Any passes each element of the container to the given function and +// returns true if the function ever returns true for any element. +func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool { + iterator := m.Iterator() + for iterator.Next() { + if f(iterator.Key(), 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 (m *Map) All(f func(key interface{}, value interface{}) bool) bool { + iterator := m.Iterator() + for iterator.Next() { + if !f(iterator.Key(), iterator.Value()) { + return false + } + } + return true +} + +// 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. +func (m *Map) Find(f func(key interface{}, value interface{}) bool) (interface{}, interface{}) { + iterator := m.Iterator() + for iterator.Next() { + if f(iterator.Key(), iterator.Value()) { + return iterator.Key(), iterator.Value() + } + } + return nil, nil +} diff --git a/maps/linkedhashmap/iterator.go b/maps/linkedhashmap/iterator.go new file mode 100644 index 00000000..d846efce --- /dev/null +++ b/maps/linkedhashmap/iterator.go @@ -0,0 +1,81 @@ +// 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 linkedhashmap + +import ( + "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/lists/doublylinkedlist" +) + +func assertIteratorImplementation() { + var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) +} + +// Iterator holding the iterator's state +type Iterator struct { + iterator doublylinkedlist.Iterator + table map[interface{}]interface{} +} + +// Iterator returns a stateful iterator whose elements are key/value pairs. +func (m *Map) Iterator() Iterator { + return Iterator{ + iterator: m.ordering.Iterator(), + table: m.table} +} + +// 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. +// 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 key and value can be retrieved by Key() 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{} { + key := iterator.iterator.Value() + return iterator.table[key] +} + +// Key returns the current element's key. +// Does not modify the state of the iterator. +func (iterator *Iterator) Key() interface{} { + return iterator.iterator.Value() +} + +// 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 key and value can be retrieved by Key() 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 key and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Last() bool { + return iterator.iterator.Last() +} diff --git a/maps/linkedhashmap/linkedhashmap.go b/maps/linkedhashmap/linkedhashmap.go new file mode 100644 index 00000000..02e23912 --- /dev/null +++ b/maps/linkedhashmap/linkedhashmap.go @@ -0,0 +1,109 @@ +// 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 linkedhashmap is a map that preserves insertion-order. +// +// It is backed by a hash table to store values and doubly-linked list to store ordering. +// +// Structure is not thread safe. +// +// Reference: http://en.wikipedia.org/wiki/Associative_array +package linkedhashmap + +import ( + "fmt" + "github.com/emirpasic/gods/lists/doublylinkedlist" + "github.com/emirpasic/gods/maps" + "strings" +) + +func assertMapImplementation() { + var _ maps.Map = (*Map)(nil) +} + +// Map holds the elements in a red-black tree +type Map struct { + table map[interface{}]interface{} + ordering *doublylinkedlist.List +} + +// New instantiates a linked-hash-map. +func New() *Map { + return &Map{ + table: make(map[interface{}]interface{}), + ordering: doublylinkedlist.New(), + } +} + +// Put inserts key-value pair into the map. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (m *Map) Put(key interface{}, value interface{}) { + if _, contains := m.table[key]; !contains { + m.ordering.Append(key) + } + m.table[key] = value +} + +// Get searches the element in the map by key and returns its value or nil if key is not found in tree. +// Second return parameter is true if key was found, otherwise false. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (m *Map) Get(key interface{}) (value interface{}, found bool) { + value = m.table[key] + found = value != nil + return +} + +// Remove removes the element from the map by key. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (m *Map) Remove(key interface{}) { + if _, contains := m.table[key]; contains { + delete(m.table, key) + index := m.ordering.IndexOf(key) + m.ordering.Remove(index) + } +} + +// Empty returns true if map does not contain any elements +func (m *Map) Empty() bool { + return m.Size() == 0 +} + +// Size returns number of elements in the map. +func (m *Map) Size() int { + return m.ordering.Size() +} + +// Keys returns all keys in-order +func (m *Map) Keys() []interface{} { + return m.ordering.Values() +} + +// Values returns all values in-order based on the key. +func (m *Map) Values() []interface{} { + values := make([]interface{}, m.Size()) + count := 0 + it := m.Iterator() + for it.Next() { + values[count] = it.Value() + count++ + } + return values +} + +// Clear removes all elements from the map. +func (m *Map) Clear() { + m.table = make(map[interface{}]interface{}) + m.ordering.Clear() +} + +// String returns a string representation of container +func (m *Map) String() string { + str := "LinkedHashMap\nmap[" + it := m.Iterator() + for it.Next() { + str += fmt.Sprintf("%v:%v ", it.Key(), it.Value()) + } + return strings.TrimRight(str, " ") + "]" + +} diff --git a/maps/linkedhashmap/linkedhashmap_test.go b/maps/linkedhashmap/linkedhashmap_test.go new file mode 100644 index 00000000..78437f14 --- /dev/null +++ b/maps/linkedhashmap/linkedhashmap_test.go @@ -0,0 +1,643 @@ +// 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 linkedhashmap + +import ( + "fmt" + "testing" +) + +func TestMapPut(t *testing.T) { + m := New() + m.Put(5, "e") + m.Put(6, "f") + m.Put(7, "g") + m.Put(3, "c") + m.Put(4, "d") + m.Put(1, "x") + m.Put(2, "b") + m.Put(1, "a") //overwrite + + if actualValue := m.Size(); actualValue != 7 { + t.Errorf("Got %v expected %v", actualValue, 7) + } + if actualValue, expectedValue := m.Keys(), []interface{}{5, 6, 7, 3, 4, 1, 2}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := m.Values(), []interface{}{"e", "f", "g", "c", "d", "a", "b"}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + // key,expectedValue,expectedFound + tests1 := [][]interface{}{ + {1, "a", true}, + {2, "b", true}, + {3, "c", true}, + {4, "d", true}, + {5, "e", true}, + {6, "f", true}, + {7, "g", true}, + {8, nil, false}, + } + + for _, test := range tests1 { + // retrievals + actualValue, actualFound := m.Get(test[0]) + if actualValue != test[1] || actualFound != test[2] { + t.Errorf("Got %v expected %v", actualValue, test[1]) + } + } +} + +func TestMapRemove(t *testing.T) { + m := New() + m.Put(5, "e") + m.Put(6, "f") + m.Put(7, "g") + m.Put(3, "c") + m.Put(4, "d") + m.Put(1, "x") + m.Put(2, "b") + m.Put(1, "a") //overwrite + + m.Remove(5) + m.Remove(6) + m.Remove(7) + m.Remove(8) + m.Remove(5) + + if actualValue, expectedValue := m.Keys(), []interface{}{3, 4, 1, 2}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + if actualValue, expectedValue := m.Values(), []interface{}{"c", "d", "a", "b"}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := m.Size(); actualValue != 4 { + t.Errorf("Got %v expected %v", actualValue, 4) + } + + tests2 := [][]interface{}{ + {1, "a", true}, + {2, "b", true}, + {3, "c", true}, + {4, "d", true}, + {5, nil, false}, + {6, nil, false}, + {7, nil, false}, + {8, nil, false}, + } + + for _, test := range tests2 { + actualValue, actualFound := m.Get(test[0]) + if actualValue != test[1] || actualFound != test[2] { + t.Errorf("Got %v expected %v", actualValue, test[1]) + } + } + + m.Remove(1) + m.Remove(4) + m.Remove(2) + m.Remove(3) + m.Remove(2) + m.Remove(2) + + if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := m.Size(); actualValue != 0 { + t.Errorf("Got %v expected %v", actualValue, 0) + } + if actualValue := m.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } +} + +func sameElements(a []interface{}, b []interface{}) bool { + // If one is nil, the other must also be nil. + if (a == nil) != (b == nil) { + return false + } + + if len(a) != len(b) { + return false + } + + for i := range a { + if a[i] != b[i] { + return false + } + } + + return true +} + +func TestMapEach(t *testing.T) { + m := New() + m.Put("c", 1) + m.Put("a", 2) + m.Put("b", 3) + count := 0 + m.Each(func(key interface{}, value interface{}) { + count++ + if actualValue, expectedValue := count, value; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + switch value { + case 1: + if actualValue, expectedValue := key, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := key, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 3: + if actualValue, expectedValue := key, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + }) +} + +func TestMapMap(t *testing.T) { + m := New() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + mappedMap := m.Map(func(key1 interface{}, value1 interface{}) (key2 interface{}, value2 interface{}) { + return key1, value1.(int) * value1.(int) + }) + if actualValue, _ := mappedMap.Get("c"); actualValue != 9 { + t.Errorf("Got %v expected %v", actualValue, "mapped: c") + } + if actualValue, _ := mappedMap.Get("a"); actualValue != 1 { + t.Errorf("Got %v expected %v", actualValue, "mapped: a") + } + if actualValue, _ := mappedMap.Get("b"); actualValue != 4 { + t.Errorf("Got %v expected %v", actualValue, "mapped: b") + } + if mappedMap.Size() != 3 { + t.Errorf("Got %v expected %v", mappedMap.Size(), 3) + } +} + +func TestMapSelect(t *testing.T) { + m := New() + m.Put("c", 3) + m.Put("b", 1) + m.Put("a", 2) + selectedMap := m.Select(func(key interface{}, value interface{}) bool { + return key.(string) >= "a" && key.(string) <= "b" + }) + if actualValue, _ := selectedMap.Get("b"); actualValue != 1 { + t.Errorf("Got %v expected %v", actualValue, "value: a") + } + if actualValue, _ := selectedMap.Get("a"); actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, "value: b") + } + if selectedMap.Size() != 2 { + t.Errorf("Got %v expected %v", selectedMap.Size(), 2) + } +} + +func TestMapAny(t *testing.T) { + m := New() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + any := m.Any(func(key interface{}, value interface{}) bool { + return value.(int) == 3 + }) + if any != true { + t.Errorf("Got %v expected %v", any, true) + } + any = m.Any(func(key interface{}, value interface{}) bool { + return value.(int) == 4 + }) + if any != false { + t.Errorf("Got %v expected %v", any, false) + } +} + +func TestMapAll(t *testing.T) { + m := New() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + all := m.All(func(key interface{}, value interface{}) bool { + return key.(string) >= "a" && key.(string) <= "c" + }) + if all != true { + t.Errorf("Got %v expected %v", all, true) + } + all = m.All(func(key interface{}, value interface{}) bool { + return key.(string) >= "a" && key.(string) <= "b" + }) + if all != false { + t.Errorf("Got %v expected %v", all, false) + } +} + +func TestMapFind(t *testing.T) { + m := New() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + foundKey, foundValue := m.Find(func(key interface{}, value interface{}) bool { + return key.(string) == "c" + }) + if foundKey != "c" || foundValue != 3 { + t.Errorf("Got %v -> %v expected %v -> %v", foundKey, foundValue, "c", 3) + } + foundKey, foundValue = m.Find(func(key interface{}, value interface{}) bool { + return key.(string) == "x" + }) + if foundKey != nil || foundValue != nil { + t.Errorf("Got %v at %v expected %v at %v", foundValue, foundKey, nil, nil) + } +} + +func TestMapChaining(t *testing.T) { + m := New() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + chainedMap := m.Select(func(key interface{}, value interface{}) bool { + return value.(int) > 1 + }).Map(func(key interface{}, value interface{}) (interface{}, interface{}) { + return key.(string) + key.(string), value.(int) * value.(int) + }) + if actualValue := chainedMap.Size(); actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, found := chainedMap.Get("aa"); actualValue != nil || found { + t.Errorf("Got %v expected %v", actualValue, nil) + } + if actualValue, found := chainedMap.Get("bb"); actualValue != 4 || !found { + t.Errorf("Got %v expected %v", actualValue, 4) + } + if actualValue, found := chainedMap.Get("cc"); actualValue != 9 || !found { + t.Errorf("Got %v expected %v", actualValue, 9) + } +} + +func TestMapIteratorNextOnEmpty(t *testing.T) { + m := New() + it := m.Iterator() + it = m.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty map") + } +} + +func TestMapIteratorPrevOnEmpty(t *testing.T) { + m := New() + it := m.Iterator() + it = m.Iterator() + for it.Prev() { + t.Errorf("Shouldn't iterate on empty map") + } +} + +func TestMapIteratorNext(t *testing.T) { + m := New() + m.Put("c", 1) + m.Put("a", 2) + m.Put("b", 3) + + it := m.Iterator() + count := 0 + for it.Next() { + count++ + key := it.Key() + value := it.Value() + switch key { + case "c": + if actualValue, expectedValue := value, 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case "a": + if actualValue, expectedValue := value, 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case "b": + if actualValue, expectedValue := value, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := value, count; 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 TestMapIteratorPrev(t *testing.T) { + m := New() + m.Put("c", 1) + m.Put("a", 2) + m.Put("b", 3) + + it := m.Iterator() + for it.Next() { + } + countDown := m.Size() + for it.Prev() { + key := it.Key() + value := it.Value() + switch key { + case "c": + if actualValue, expectedValue := value, 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case "a": + if actualValue, expectedValue := value, 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case "b": + if actualValue, expectedValue := value, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := value, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + countDown-- + } + if actualValue, expectedValue := countDown, 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + +func TestMapIteratorBegin(t *testing.T) { + m := New() + it := m.Iterator() + it.Begin() + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + for it.Next() { + } + it.Begin() + it.Next() + if key, value := it.Key(), it.Value(); key != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") + } +} + +func TestMapTreeIteratorEnd(t *testing.T) { + m := New() + it := m.Iterator() + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + it.End() + it.Prev() + if key, value := it.Key(), it.Value(); key != 2 || value != "b" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 2, "b") + } +} + +func TestMapIteratorFirst(t *testing.T) { + m := New() + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + it := m.Iterator() + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if key, value := it.Key(), it.Value(); key != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") + } +} + +func TestMapIteratorLast(t *testing.T) { + m := New() + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + it := m.Iterator() + if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if key, value := it.Key(), it.Value(); key != 2 || value != "b" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 2, "b") + } +} + +func TestMapSerialization(t *testing.T) { + for i := 0; i < 10; i++ { + original := New() + original.Put("d", "4") + original.Put("e", "5") + original.Put("c", "3") + original.Put("b", "2") + original.Put("a", "1") + + assertSerialization(original, "A", t) + + serialized, err := original.ToJSON() + if err != nil { + t.Errorf("Got error %v", err) + } + assertSerialization(original, "B", t) + + deserialized := New() + err = deserialized.FromJSON(serialized) + if err != nil { + t.Errorf("Got error %v", err) + } + assertSerialization(deserialized, "C", t) + } +} + +//noinspection GoBoolExpressions +func assertSerialization(m *Map, txt string, t *testing.T) { + if actualValue := m.Keys(); false || + actualValue[0].(string) != "d" || + actualValue[1].(string) != "e" || + actualValue[2].(string) != "c" || + actualValue[3].(string) != "b" || + actualValue[4].(string) != "a" { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[d,e,c,b,a]") + } + if actualValue := m.Values(); false || + actualValue[0].(string) != "4" || + actualValue[1].(string) != "5" || + actualValue[2].(string) != "3" || + actualValue[3].(string) != "2" || + actualValue[4].(string) != "1" { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[4,5,3,2,1]") + } + if actualValue, expectedValue := m.Size(), 5; actualValue != expectedValue { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, expectedValue) + } +} + +func benchmarkGet(b *testing.B, m *Map, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + m.Get(n) + } + } +} + +func benchmarkPut(b *testing.B, m *Map, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + } +} + +func benchmarkRemove(b *testing.B, m *Map, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + m.Remove(n) + } + } +} + +func BenchmarkTreeMapGet100(b *testing.B) { + b.StopTimer() + size := 100 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkTreeMapGet1000(b *testing.B) { + b.StopTimer() + size := 1000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkTreeMapGet10000(b *testing.B) { + b.StopTimer() + size := 10000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkTreeMapGet100000(b *testing.B) { + b.StopTimer() + size := 100000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkTreeMapPut100(b *testing.B) { + b.StopTimer() + size := 100 + m := New() + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkTreeMapPut1000(b *testing.B) { + b.StopTimer() + size := 1000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkTreeMapPut10000(b *testing.B) { + b.StopTimer() + size := 10000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkTreeMapPut100000(b *testing.B) { + b.StopTimer() + size := 100000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkTreeMapRemove100(b *testing.B) { + b.StopTimer() + size := 100 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} + +func BenchmarkTreeMapRemove1000(b *testing.B) { + b.StopTimer() + size := 1000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} + +func BenchmarkTreeMapRemove10000(b *testing.B) { + b.StopTimer() + size := 10000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} + +func BenchmarkTreeMapRemove100000(b *testing.B) { + b.StopTimer() + size := 100000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} diff --git a/maps/linkedhashmap/serialization.go b/maps/linkedhashmap/serialization.go new file mode 100644 index 00000000..4f723cf6 --- /dev/null +++ b/maps/linkedhashmap/serialization.go @@ -0,0 +1,103 @@ +// 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 linkedhashmap + +import ( + "bytes" + "encoding/json" + "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/utils" +) + +func assertSerializationImplementation() { + var _ containers.JSONSerializer = (*Map)(nil) + var _ containers.JSONDeserializer = (*Map)(nil) +} + +// ToJSON outputs the JSON representation of map. +func (m *Map) ToJSON() ([]byte, error) { + var b []byte + buf := bytes.NewBuffer(b) + + buf.WriteRune('{') + + it := m.Iterator() + lastIndex := m.Size() - 1 + index := 0 + + for it.Next() { + km, err := json.Marshal(it.Key()) + if err != nil { + return nil, err + } + buf.Write(km) + + buf.WriteRune(':') + + vm, err := json.Marshal(it.Value()) + if err != nil { + return nil, err + } + buf.Write(vm) + + if index != lastIndex { + buf.WriteRune(',') + } + + index++ + } + + buf.WriteRune('}') + + return buf.Bytes(), nil +} + +// FromJSON populates map from the input JSON representation. +//func (m *Map) FromJSON(data []byte) error { +// elements := make(map[string]interface{}) +// err := json.Unmarshal(data, &elements) +// if err == nil { +// m.Clear() +// for key, value := range elements { +// m.Put(key, value) +// } +// } +// return err +//} + +// FromJSON populates map from the input JSON representation. +func (m *Map) FromJSON(data []byte) error { + elements := make(map[string]interface{}) + err := json.Unmarshal(data, &elements) + if err != nil { + return err + } + + index := make(map[string]int) + var keys []interface{} + for key := range elements { + keys = append(keys, key) + esc, _ := json.Marshal(key) + index[key] = bytes.Index(data, esc) + } + + byIndex := func(a, b interface{}) int { + key1 := a.(string) + key2 := b.(string) + index1 := index[key1] + index2 := index[key2] + return index1 - index2 + } + + utils.Sort(keys, byIndex) + + m.Clear() + + for _, key := range keys { + m.Put(key, elements[key.(string)]) + } + + return nil +} diff --git a/maps/treebidimap/treebidimap_test.go b/maps/treebidimap/treebidimap_test.go index bc7f4fa2..686b5782 100644 --- a/maps/treebidimap/treebidimap_test.go +++ b/maps/treebidimap/treebidimap_test.go @@ -473,7 +473,6 @@ func TestMapIteratorLast(t *testing.T) { } } -//noinspection GoBoolExpressions func TestMapSerialization(t *testing.T) { for i := 0; i < 10; i++ { original := NewWith(utils.StringComparator, utils.StringComparator) @@ -483,42 +482,43 @@ func TestMapSerialization(t *testing.T) { original.Put("b", "2") original.Put("a", "1") - assert := func(m *Map, txt string) { - if actualValue := m.Keys(); false || - actualValue[0].(string) != "a" || - actualValue[1].(string) != "b" || - actualValue[2].(string) != "c" || - actualValue[3].(string) != "d" || - actualValue[4].(string) != "e" { - t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[a,b,c,d,e]") - } - if actualValue := m.Values(); false || - actualValue[0].(string) != "1" || - actualValue[1].(string) != "2" || - actualValue[2].(string) != "3" || - actualValue[3].(string) != "4" || - actualValue[4].(string) != "5" { - t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[1,2,3,4,5]") - } - if actualValue, expectedValue := m.Size(), 5; actualValue != expectedValue { - t.Errorf("[%s] Got %v expected %v", txt, actualValue, expectedValue) - } - } - - assert(original, "A") + assertSerialization(original, "A", t) serialized, err := original.ToJSON() if err != nil { t.Errorf("Got error %v", err) } - assert(original, "B") + assertSerialization(original, "B", t) deserialized := NewWith(utils.StringComparator, utils.StringComparator) err = deserialized.FromJSON(serialized) if err != nil { t.Errorf("Got error %v", err) } - assert(deserialized, "C") + assertSerialization(deserialized, "C", t) + } +} + +//noinspection GoBoolExpressions +func assertSerialization(m *Map, txt string, t *testing.T) { + if actualValue := m.Keys(); false || + actualValue[0].(string) != "a" || + actualValue[1].(string) != "b" || + actualValue[2].(string) != "c" || + actualValue[3].(string) != "d" || + actualValue[4].(string) != "e" { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[a,b,c,d,e]") + } + if actualValue := m.Values(); false || + actualValue[0].(string) != "1" || + actualValue[1].(string) != "2" || + actualValue[2].(string) != "3" || + actualValue[3].(string) != "4" || + actualValue[4].(string) != "5" { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[1,2,3,4,5]") + } + if actualValue, expectedValue := m.Size(), 5; actualValue != expectedValue { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, expectedValue) } } diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index d718c91c..bb054b3b 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -440,7 +440,6 @@ func TestMapIteratorLast(t *testing.T) { } } -//noinspection GoBoolExpressions func TestMapSerialization(t *testing.T) { for i := 0; i < 10; i++ { original := NewWithStringComparator() @@ -450,42 +449,43 @@ func TestMapSerialization(t *testing.T) { original.Put("b", "2") original.Put("a", "1") - assert := func(m *Map, txt string) { - if actualValue := m.Keys(); false || - actualValue[0].(string) != "a" || - actualValue[1].(string) != "b" || - actualValue[2].(string) != "c" || - actualValue[3].(string) != "d" || - actualValue[4].(string) != "e" { - t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[a,b,c,d,e]") - } - if actualValue := m.Values(); false || - actualValue[0].(string) != "1" || - actualValue[1].(string) != "2" || - actualValue[2].(string) != "3" || - actualValue[3].(string) != "4" || - actualValue[4].(string) != "5" { - t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[1,2,3,4,5]") - } - if actualValue, expectedValue := m.Size(), 5; actualValue != expectedValue { - t.Errorf("[%s] Got %v expected %v", txt, actualValue, expectedValue) - } - } - - assert(original, "A") + assertSerialization(original, "A", t) serialized, err := original.ToJSON() if err != nil { t.Errorf("Got error %v", err) } - assert(original, "B") + assertSerialization(original, "B", t) deserialized := NewWithStringComparator() err = deserialized.FromJSON(serialized) if err != nil { t.Errorf("Got error %v", err) } - assert(deserialized, "C") + assertSerialization(deserialized, "C", t) + } +} + +//noinspection GoBoolExpressions +func assertSerialization(m *Map, txt string, t *testing.T) { + if actualValue := m.Keys(); false || + actualValue[0].(string) != "a" || + actualValue[1].(string) != "b" || + actualValue[2].(string) != "c" || + actualValue[3].(string) != "d" || + actualValue[4].(string) != "e" { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[a,b,c,d,e]") + } + if actualValue := m.Values(); false || + actualValue[0].(string) != "1" || + actualValue[1].(string) != "2" || + actualValue[2].(string) != "3" || + actualValue[3].(string) != "4" || + actualValue[4].(string) != "5" { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[1,2,3,4,5]") + } + if actualValue, expectedValue := m.Size(), 5; actualValue != expectedValue { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, expectedValue) } } From 465885c5a3f6d8a37a2f426309e5e1bd9ef031d8 Mon Sep 17 00:00:00 2001 From: emirpasic Date: Fri, 21 Sep 2018 05:35:29 +0200 Subject: [PATCH 194/320] - linked hashmap documentation and example --- README.md | 32 ++++++++++++++++++++++++- examples/linkedhashmap/linkedhashmap.go | 23 ++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 examples/linkedhashmap/linkedhashmap.go diff --git a/README.md b/README.md index 3816525b..79f1a236 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Implementation of various data structures and algorithms in Go. - [Maps](#maps) - [HashMap](#hashmap) - [TreeMap](#treemap) + - [LinkedHashMap](#linkedhashmap) - [HashBidiMap](#hashbidimap) - [TreeBidiMap](#treebidimap) - [Trees](#trees) @@ -77,9 +78,10 @@ Containers are either ordered or unordered. All ordered containers provide [stat | [Maps](#maps) | | | [HashMap](#hashmap) | no | no | no | key | | | [TreeMap](#treemap) | yes | yes* | yes | key | +| | [LinkedHashMap](#linkedhashmap) | yes | yes* | yes | key | | | [HashBidiMap](#hashbidimap) | no | no | no | key* | -| [Trees](#trees) | | | [TreeBidiMap](#treebidimap) | yes | yes* | yes | key* | +| [Trees](#trees) | | | [RedBlackTree](#redblacktree) | yes | yes* | no | key | | | [AVLTree](#avltree) | yes | yes* | no | key | | | [BTree](#btree) | yes | yes* | no | key | @@ -487,6 +489,34 @@ func main() { } ``` +#### LinkedHashMap + +A [map](#maps) that preserves insertion-order. It is backed by a hash table to store values and [doubly-linked list](doublylinkedlist) to store ordering. + +Implements [Map](#maps), [IteratorWithKey](#iteratorwithkey), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. + +```go +package main + +import "github.com/emirpasic/gods/maps/linkedhashmap" + +func main() { + m := linkedhashmap.New() // empty (keys are of type int) + m.Put(2, "b") // 2->b + m.Put(1, "x") // 2->b, 1->x (insertion-order) + m.Put(1, "a") // 2->b, 1->a (insertion-order) + _, _ = m.Get(2) // b, true + _, _ = m.Get(3) // nil, false + _ = m.Values() // []interface {}{"b", "a"} (insertion-order) + _ = m.Keys() // []interface {}{2, 1} (insertion-order) + m.Remove(1) // 2->b + m.Clear() // empty + m.Empty() // true + m.Size() // 0 +} + +``` + #### HashBidiMap A [map](#maps) based on two hashmaps. Keys are unordered. diff --git a/examples/linkedhashmap/linkedhashmap.go b/examples/linkedhashmap/linkedhashmap.go new file mode 100644 index 00000000..64434817 --- /dev/null +++ b/examples/linkedhashmap/linkedhashmap.go @@ -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/maps/linkedhashmap" + +// LinkedHashMapExample to demonstrate basic usage of LinkedHashMapExample +func main() { + m := linkedhashmap.New() // empty (keys are of type int) + m.Put(2, "b") // 2->b + m.Put(1, "x") // 2->b, 1->x (insertion-order) + m.Put(1, "a") // 2->b, 1->a (insertion-order) + _, _ = m.Get(2) // b, true + _, _ = m.Get(3) // nil, false + _ = m.Values() // []interface {}{"b", "a"} (insertion-order) + _ = m.Keys() // []interface {}{2, 1} (insertion-order) + m.Remove(1) // 2->b + m.Clear() // empty + m.Empty() // true + m.Size() // 0 +} From 4bc610bb3fd6208d3a7820db6c3a5f2f14bd4ba7 Mon Sep 17 00:00:00 2001 From: emirpasic Date: Sun, 23 Sep 2018 01:35:23 +0200 Subject: [PATCH 195/320] TreeMap Floor and Ceiling functions --- maps/treemap/treemap.go | 44 +++++++----- maps/treemap/treemap_test.go | 110 +++++++++++++++-------------- trees/redblacktree/redblacktree.go | 6 +- 3 files changed, 87 insertions(+), 73 deletions(-) diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index 2105b668..a8e1dc5c 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -105,26 +105,38 @@ func (m *Map) Max() (key interface{}, value interface{}) { return nil, nil } -// Floor searches the floor element in the map by key. -// Returns floor key, floor value, true if floor key is found. -// Returns nil, nil, false if floor key is not found. -func (m *Map) Floor(key interface{}) (retKey interface{}, retValue interface{}, found bool) { - ret, found := m.tree.Floor(key) - if !found { - return nil, nil, false +// Floor finds the floor key-value pair for the input key. +// In case that no floor is found, then both returned values will be nil. +// It's generally enough to check the first value (key) for nil, which determines if floor was found. +// +// Floor key is defined as the largest key that is smaller than or equal to the given key. +// A floor key may not be found, either because the map is empty, or because +// all keys in the map are larger than the given key. +// +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (m *Map) Floor(key interface{}) (foundKey interface{}, foundValue interface{}) { + node, found := m.tree.Floor(key) + if found { + return node.Key, node.Value } - return ret.Key, ret.Value, true + return nil, nil } -// Ceiling searches the ceiling element in the map by key. -// Returns ceiling key, ceiling value, true if a ceiling key is found. -// Returns nil, nil, false if ceiling key is not found. -func (m *Map) Ceiling(key interface{}) (retKey interface{}, retValue interface{}, found bool) { - ret, found := m.tree.Ceiling(key) - if !found { - return nil, nil, false +// Ceiling finds the ceiling key-value pair for the input key. +// In case that no ceiling is found, then both returned values will be nil. +// It's generally enough to check the first value (key) for nil, which determines if ceiling was found. +// +// Ceiling key is defined as the smallest key that is larger than or equal to the given key. +// A ceiling key may not be found, either because the map is empty, or because +// all keys in the map are smaller than the given key. +// +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (m *Map) Ceiling(key interface{}) (foundKey interface{}, foundValue interface{}) { + node, found := m.tree.Ceiling(key) + if found { + return node.Key, node.Value } - return ret.Key, ret.Value, true + return nil, nil } // String returns a string representation of container diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index a08587d6..0ee162ec 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -118,6 +118,62 @@ func TestMapRemove(t *testing.T) { } } +func TestMapFloor(t *testing.T) { + m := NewWithIntComparator() + m.Put(7, "g") + m.Put(3, "c") + m.Put(1, "a") + + // key,expectedKey,expectedValue,expectedFound + tests1 := [][]interface{}{ + {-1, nil, nil, false}, + {0, nil, nil, false}, + {1, 1, "a", true}, + {2, 1, "a", true}, + {3, 3, "c", true}, + {4, 3, "c", true}, + {7, 7, "g", true}, + {8, 7, "g", true}, + } + + for _, test := range tests1 { + // retrievals + actualKey, actualValue := m.Floor(test[0]) + actualFound := actualKey != nil && actualValue != nil + if actualKey != test[1] || actualValue != test[2] || actualFound != test[3] { + t.Errorf("Got %v, %v, %v, expected %v, %v, %v", actualKey, actualValue, actualFound, test[1], test[2], test[3]) + } + } +} + +func TestMapCeiling(t *testing.T) { + m := NewWithIntComparator() + m.Put(7, "g") + m.Put(3, "c") + m.Put(1, "a") + + // key,expectedKey,expectedValue,expectedFound + tests1 := [][]interface{}{ + {-1, 1, "a", true}, + {0, 1, "a", true}, + {1, 1, "a", true}, + {2, 3, "c", true}, + {3, 3, "c", true}, + {4, 7, "g", true}, + {7, 7, "g", true}, + {8, nil, nil, false}, + } + + for _, test := range tests1 { + // retrievals + actualKey, actualValue := m.Ceiling(test[0]) + actualFound := actualKey != nil && actualValue != nil + if actualKey != test[1] || actualValue != test[2] || actualFound != test[3] { + t.Errorf("Got %v, %v, %v, expected %v, %v, %v", actualKey, actualValue, actualFound, test[1], test[2], test[3]) + } + } +} + func sameElements(a []interface{}, b []interface{}) bool { if len(a) != len(b) { return false @@ -289,60 +345,6 @@ func TestMapChaining(t *testing.T) { } } -func TestMapFloor(t *testing.T) { - m := NewWithIntComparator() - m.Put(7, "g") - m.Put(3, "c") - m.Put(1, "a") - - // key,expectedKey,expectedValue,expectedFound - tests1 := [][]interface{}{ - {-1, nil, nil, false}, - {0, nil, nil, false}, - {1, 1, "a", true}, - {2, 1, "a", true}, - {3, 3, "c", true}, - {4, 3, "c", true}, - {7, 7, "g", true}, - {8, 7, "g", true}, - } - - for _, test := range tests1 { - // retrievals - actualKey, actualValue, actualFound := m.Floor(test[0]) - if actualKey != test[1] || actualValue != test[2] || actualFound != test[3] { - t.Errorf("Got %v, %v, %v, expected %v, %v, %v", actualKey, actualValue, actualFound, test[1], test[2], test[3]) - } - } -} - -func TestMapCeiling(t *testing.T) { - m := NewWithIntComparator() - m.Put(7, "g") - m.Put(3, "c") - m.Put(1, "a") - - // key,expectedKey,expectedValue,expectedFound - tests1 := [][]interface{}{ - {-1, 1, "a", true}, - {0, 1, "a", true}, - {1, 1, "a", true}, - {2, 3, "c", true}, - {3, 3, "c", true}, - {4, 7, "g", true}, - {7, 7, "g", true}, - {8, nil, nil, false}, - } - - for _, test := range tests1 { - // retrievals - actualKey, actualValue, actualFound := m.Ceiling(test[0]) - if actualKey != test[1] || actualValue != test[2] || actualFound != test[3] { - t.Errorf("Got %v, %v, %v, expected %v, %v, %v", actualKey, actualValue, actualFound, test[1], test[2], test[3]) - } - } -} - func TestMapIteratorNextOnEmpty(t *testing.T) { m := NewWithStringComparator() it := m.Iterator() diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index ecc199e7..8301ffd7 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -197,12 +197,12 @@ func (tree *Tree) Right() *Node { return parent } -// Floor Finds floor node of the input key, return the floor node or nil if no ceiling is found. +// Floor Finds floor node of the input key, return the floor node or nil if no floor is found. // Second return parameter is true if floor was found, otherwise false. // // Floor node is defined as the largest node that is smaller than or equal to the given node. // A floor node may not be found, either because the tree is empty, or because -// all nodes in the tree is larger than the given node. +// all nodes in the tree are larger than the given node. // // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree) Floor(key interface{}) (floor *Node, found bool) { @@ -231,7 +231,7 @@ func (tree *Tree) Floor(key interface{}) (floor *Node, found bool) { // // Ceiling node is defined as the smallest node that is larger than or equal to the given node. // A ceiling node may not be found, either because the tree is empty, or because -// all nodes in the tree is smaller than the given node. +// all nodes in the tree are smaller than the given node. // // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree) Ceiling(key interface{}) (ceiling *Node, found bool) { From 7bbe2d9e0b7b2f6f9e7e5b4590ba1df2ac0ad05f Mon Sep 17 00:00:00 2001 From: Harald Nordgren Date: Sat, 20 Oct 2018 12:11:13 +0200 Subject: [PATCH 196/320] Bump Travis versions --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 5477990c..93bbdba0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,4 +8,7 @@ go: - 1.6.x - 1.7.x - 1.8.x + - 1.9.x + - 1.10.x + - 1.11.x - tip From 3978ee8254e3a47ecbe6c8e4378a155fee2bdea8 Mon Sep 17 00:00:00 2001 From: "Iskander (Alex) Sharipov" Date: Thu, 24 Jan 2019 08:59:56 +0300 Subject: [PATCH 197/320] utils: remove excessive type assertions Assign type switch variable to get properly-typed value inside case clauses. Signed-off-by: Iskander Sharipov --- utils/utils.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/utils/utils.go b/utils/utils.go index 1ad49cbc..d305a7c8 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -16,31 +16,31 @@ import ( // ToString converts a value to string. func ToString(value interface{}) string { - switch value.(type) { + switch value := value.(type) { case string: - return value.(string) + return value case int8: - return strconv.FormatInt(int64(value.(int8)), 10) + return strconv.FormatInt(int64(value), 10) case int16: - return strconv.FormatInt(int64(value.(int16)), 10) + return strconv.FormatInt(int64(value), 10) case int32: - return strconv.FormatInt(int64(value.(int32)), 10) + return strconv.FormatInt(int64(value), 10) case int64: - return strconv.FormatInt(int64(value.(int64)), 10) + return strconv.FormatInt(int64(value), 10) case uint8: - return strconv.FormatUint(uint64(value.(uint8)), 10) + return strconv.FormatUint(uint64(value), 10) case uint16: - return strconv.FormatUint(uint64(value.(uint16)), 10) + return strconv.FormatUint(uint64(value), 10) case uint32: - return strconv.FormatUint(uint64(value.(uint32)), 10) + return strconv.FormatUint(uint64(value), 10) case uint64: - return strconv.FormatUint(uint64(value.(uint64)), 10) + return strconv.FormatUint(uint64(value), 10) case float32: - return strconv.FormatFloat(float64(value.(float32)), 'g', -1, 64) + return strconv.FormatFloat(float64(value), 'g', -1, 64) case float64: - return strconv.FormatFloat(float64(value.(float64)), 'g', -1, 64) + return strconv.FormatFloat(float64(value), 'g', -1, 64) case bool: - return strconv.FormatBool(value.(bool)) + return strconv.FormatBool(value) default: return fmt.Sprintf("%+v", value) } From 87aa46c680b38d4a1076f8b84bef03cc644b1f7f Mon Sep 17 00:00:00 2001 From: own2pwn <7850039+own2pwn@users.noreply.github.com> Date: Sun, 3 Mar 2019 03:39:45 +0300 Subject: [PATCH 198/320] typo fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 79f1a236..01c53f2e 100644 --- a/README.md +++ b/README.md @@ -460,7 +460,7 @@ func main() { #### TreeMap -A [map](#maps) based on [red-black tree](#redblacktree). Keys are ordered ordered with respect to the [comparator](#comparator). +A [map](#maps) based on [red-black tree](#redblacktree). Keys are ordered with respect to the [comparator](#comparator). Implements [Map](#maps), [IteratorWithKey](#iteratorwithkey), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. From a733df2d7b52c1fc1970fcd3016f81bdd5408e17 Mon Sep 17 00:00:00 2001 From: navigaid Date: Sun, 14 Apr 2019 13:28:45 +0800 Subject: [PATCH 199/320] fix linkedhashmap.Map comment error In linkedhashmap.go there is a line of comment saying "Map holds the elements in a red-black tree", which is not true. The linkedhashmap holds it's elements in a regular hash table, and uses doubly-linked list to store key ordering. --- maps/linkedhashmap/linkedhashmap.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maps/linkedhashmap/linkedhashmap.go b/maps/linkedhashmap/linkedhashmap.go index 02e23912..45c4e35e 100644 --- a/maps/linkedhashmap/linkedhashmap.go +++ b/maps/linkedhashmap/linkedhashmap.go @@ -22,7 +22,7 @@ func assertMapImplementation() { var _ maps.Map = (*Map)(nil) } -// Map holds the elements in a red-black tree +// Map holds the elements in a regular hash table, and uses doubly-linked list to store key ordering. type Map struct { table map[interface{}]interface{} ordering *doublylinkedlist.List From ab5242f706826a336bf8516e9773494074f13030 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Thu, 13 Jun 2019 19:07:49 +0200 Subject: [PATCH 200/320] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 93bbdba0..61733e4e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: go go: - - 1.1.x - 1.2.x - 1.3.x - 1.4.x @@ -11,4 +10,5 @@ go: - 1.9.x - 1.10.x - 1.11.x + - 1.12.x - tip From 7c93e37d099cdebd710f6497decd6ef3b1e5a62d Mon Sep 17 00:00:00 2001 From: dennis Date: Mon, 24 Jun 2019 17:06:03 +0800 Subject: [PATCH 201/320] README: fix BTree commit --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 01c53f2e..7346b994 100644 --- a/README.md +++ b/README.md @@ -770,14 +770,15 @@ func main() { _ = tree.Values() // []interface {}{"a", "b", "c", "d", "e", "f", "g"} (in order) _ = tree.Keys() // []interface {}{1, 2, 3, 4, 5, 6, 7} (in order) - tree.Remove(2) // 1->a, 3->c, 4->d, 5->e, 6->f (in order) + tree.Remove(2) // 1->a, 3->c, 4->d, 5->e, 6->f, 7->g (in order) fmt.Println(tree) // BTree // 1 // 3 // 4 // 5 - // 6 + // 6 + // 7 tree.Clear() // empty tree.Empty() // true From 482308b06528606459689e05055f7e474d88a100 Mon Sep 17 00:00:00 2001 From: Steve Traugott Date: Sun, 6 Oct 2019 22:29:36 -0700 Subject: [PATCH 202/320] rename sort example to godsort Closes #123. --- examples/{sort/sort.go => godsort/godsort.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{sort/sort.go => godsort/godsort.go} (100%) diff --git a/examples/sort/sort.go b/examples/godsort/godsort.go similarity index 100% rename from examples/sort/sort.go rename to examples/godsort/godsort.go From 3ba27e24d33ff91a9a61fe26859c430103678023 Mon Sep 17 00:00:00 2001 From: yuanjin Date: Mon, 13 Jan 2020 10:23:14 +0800 Subject: [PATCH 203/320] - fix utils test --- utils/utils_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils_test.go b/utils/utils_test.go index f5b3edce..afbca1b9 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -74,7 +74,7 @@ func TestToStringFloats(t *testing.T) { if actualValue, expectedValue := ToString(value), "1.123456"; !strings.HasPrefix(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - value = float32(1.123456) + value = float64(1.123456) if actualValue, expectedValue := ToString(value), "1.123456"; !strings.HasPrefix(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } From edc20eca0a6fa0fc1971971fc8b118d866a0b0f6 Mon Sep 17 00:00:00 2001 From: yuanjin Date: Mon, 13 Jan 2020 17:12:56 +0800 Subject: [PATCH 204/320] - fix arraylist test --- lists/arraylist/arraylist_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 0d7eae48..63d97d41 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -125,7 +125,7 @@ func TestListSwap(t *testing.T) { list.Add("b", "c") list.Swap(0, 1) if actualValue, ok := list.Get(0); actualValue != "b" || !ok { - t.Errorf("Got %v expected %v", actualValue, "c") + t.Errorf("Got %v expected %v", actualValue, "b") } } From 3e279ba9abcc8891d92d8b4affbfc9335cc208c2 Mon Sep 17 00:00:00 2001 From: doshiraki Date: Sat, 1 Feb 2020 18:49:49 +0900 Subject: [PATCH 205/320] I modified Prev and Next Because it uses Compare function. --- trees/redblacktree/iterator.go | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/trees/redblacktree/iterator.go b/trees/redblacktree/iterator.go index 90b84afe..e81f1a53 100644 --- a/trees/redblacktree/iterator.go +++ b/trees/redblacktree/iterator.go @@ -51,13 +51,11 @@ func (iterator *Iterator) Next() bool { } goto between } - if iterator.node.Parent != nil { + for iterator.node.Parent != nil { node := iterator.node - for iterator.node.Parent != nil { - iterator.node = iterator.node.Parent - if iterator.tree.Comparator(node.Key, iterator.node.Key) <= 0 { - goto between - } + iterator.node = iterator.node.Parent + if node == iterator.node.Left { + goto between } } @@ -93,13 +91,11 @@ func (iterator *Iterator) Prev() bool { } goto between } - if iterator.node.Parent != nil { + for iterator.node.Parent != nil { node := iterator.node - for iterator.node.Parent != nil { - iterator.node = iterator.node.Parent - if iterator.tree.Comparator(node.Key, iterator.node.Key) >= 0 { - goto between - } + iterator.node = iterator.node.Parent + if node == iterator.node.Right { + goto between } } From 3439eab70ca38153ca551e3fbbe0cff8bd456bba Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 31 Mar 2020 20:56:00 +0200 Subject: [PATCH 206/320] Add 1.13 and 1.14 versions to tests --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 61733e4e..406b5ce0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,4 +11,6 @@ go: - 1.10.x - 1.11.x - 1.12.x + - 1.13.x + - 1.14.x - tip From 962a86dc9203e5ffe19a0e49abc8a2b245bb11dc Mon Sep 17 00:00:00 2001 From: Paul Cruickshank Date: Mon, 29 Jun 2020 16:24:04 +0100 Subject: [PATCH 207/320] Create an iterator at a specific node --- trees/redblacktree/iterator.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/trees/redblacktree/iterator.go b/trees/redblacktree/iterator.go index 90b84afe..9cde5e43 100644 --- a/trees/redblacktree/iterator.go +++ b/trees/redblacktree/iterator.go @@ -28,6 +28,11 @@ func (tree *Tree) Iterator() Iterator { return Iterator{tree: tree, node: nil, position: begin} } +// IteratorAt returns a stateful iterator whose elements are key/value pairs that is initialised at a particular node. +func (tree *Tree) IteratorAt(node *Node) Iterator { + return Iterator{tree: tree, node: node, position: between} +} + // 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. From 419d73a3b60232bc6cdc93834e0767756f0bec0e Mon Sep 17 00:00:00 2001 From: Marcelo Da cruz pinto Date: Wed, 12 Aug 2020 22:42:05 -0700 Subject: [PATCH 208/320] Simple implementation of set intersection --- sets/hashset/hashset.go | 11 +++++++++++ sets/hashset/hashset_test.go | 12 ++++++++++++ sets/linkedhashset/linkedhashset.go | 11 +++++++++++ sets/linkedhashset/linkedhashset_test.go | 12 ++++++++++++ sets/treeset/treeset.go | 11 +++++++++++ sets/treeset/treeset_test.go | 12 ++++++++++++ 6 files changed, 69 insertions(+) diff --git a/sets/hashset/hashset.go b/sets/hashset/hashset.go index 815d0490..e49696ed 100644 --- a/sets/hashset/hashset.go +++ b/sets/hashset/hashset.go @@ -97,3 +97,14 @@ func (set *Set) String() string { str += strings.Join(items, ", ") return str } + +// Intersection returns the intersection between two sets +func (set *Set) Intersection(another *Set) *Set { + result := New() + for item, _ := range another.items { + if set.Contains(item) { + result.Add(item) + } + } + return result +} diff --git a/sets/hashset/hashset_test.go b/sets/hashset/hashset_test.go index cf63c899..c6f48f1e 100644 --- a/sets/hashset/hashset_test.go +++ b/sets/hashset/hashset_test.go @@ -105,6 +105,18 @@ func TestSetSerialization(t *testing.T) { assert() } +func TestSetIntersection(t *testing.T) { + set := New("a", "b", "c", "d") + anotherSet := New("c", "d", "f", "g") + intersection := set.Intersection(anotherSet) + if actualValue, expectedValue := intersection.Size(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := set.Contains("c", "d"); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } +} + func benchmarkContains(b *testing.B, set *Set, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { diff --git a/sets/linkedhashset/linkedhashset.go b/sets/linkedhashset/linkedhashset.go index e589a127..df4deb30 100644 --- a/sets/linkedhashset/linkedhashset.go +++ b/sets/linkedhashset/linkedhashset.go @@ -116,3 +116,14 @@ func (set *Set) String() string { str += strings.Join(items, ", ") return str } + +// Intersection returns the intersection between two sets +func (set *Set) Intersection(another *Set) *Set { + result := New() + for item, _ := range another.table { + if set.Contains(item) { + result.Add(item) + } + } + return result +} diff --git a/sets/linkedhashset/linkedhashset_test.go b/sets/linkedhashset/linkedhashset_test.go index 10b6da2d..728c5ff6 100644 --- a/sets/linkedhashset/linkedhashset_test.go +++ b/sets/linkedhashset/linkedhashset_test.go @@ -358,6 +358,18 @@ func TestSetSerialization(t *testing.T) { assert() } +func TestSetIntersection(t *testing.T) { + set := New("a", "b", "c", "d") + anotherSet := New("c", "d", "f", "g") + intersection := set.Intersection(anotherSet) + if actualValue, expectedValue := intersection.Size(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := set.Contains("c", "d"); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } +} + func benchmarkContains(b *testing.B, set *Set, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 7efbf2dc..fd23610c 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -111,3 +111,14 @@ func (set *Set) String() string { str += strings.Join(items, ", ") return str } + +// Intersection returns the intersection between two sets +func (set *Set) Intersection(another *Set) *Set { + result := NewWith(set.tree.Comparator) + for _, item := range another.Values() { + if set.Contains(item) { + result.Add(item) + } + } + return result +} diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index b3cfca9d..81d1a7a0 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -367,6 +367,18 @@ func TestSetSerialization(t *testing.T) { assert() } +func TestSetIntersection(t *testing.T) { + set := NewWithStringComparator("a", "b", "c", "d") + anotherSet := NewWithStringComparator("c", "d", "f", "g") + intersection := set.Intersection(anotherSet) + if actualValue, expectedValue := intersection.Size(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := set.Contains("c", "d"); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } +} + func benchmarkContains(b *testing.B, set *Set, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { From 508e436ad1a892e575245ac0d1ed9d088ce29802 Mon Sep 17 00:00:00 2001 From: Marcelo Da cruz pinto Date: Thu, 13 Aug 2020 08:40:32 -0700 Subject: [PATCH 209/320] Adding Intersection function to the Set interface --- sets/sets.go | 1 + 1 file changed, 1 insertion(+) diff --git a/sets/sets.go b/sets/sets.go index 25732971..a81ec14c 100644 --- a/sets/sets.go +++ b/sets/sets.go @@ -16,6 +16,7 @@ type Set interface { Add(elements ...interface{}) Remove(elements ...interface{}) Contains(elements ...interface{}) bool + Intersection(another *Set) *Set containers.Container // Empty() bool From d0504361562032ae47d19a7830429527c1aca590 Mon Sep 17 00:00:00 2001 From: nagesh4193 <70690392+nagesh4193@users.noreply.github.com> Date: Wed, 14 Oct 2020 13:01:32 +0530 Subject: [PATCH 210/320] Added Power Support ppc64le --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 406b5ce0..a0408ceb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,7 @@ language: go +arch: + - amd64 + - ppc64le go: - 1.2.x - 1.3.x From 53bbe088258a37ebc35d74bfcf6737180e3c0726 Mon Sep 17 00:00:00 2001 From: nagesh4193 <70690392+nagesh4193@users.noreply.github.com> Date: Wed, 14 Oct 2020 17:41:00 +0530 Subject: [PATCH 211/320] Added Power Support ppc64le --- .travis.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.travis.yml b/.travis.yml index a0408ceb..209cfb79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,3 +17,11 @@ go: - 1.13.x - 1.14.x - tip +jobs: + exclude: + - arch: ppc64le + go: 1.2.x + - arch: ppc64le + go: 1.3.x + - arch: ppc64le + go: 1.4.x From 9500fd4d47e952ad507d93d4cc11fe280d80e093 Mon Sep 17 00:00:00 2001 From: nagesh4193 <70690392+nagesh4193@users.noreply.github.com> Date: Wed, 14 Oct 2020 18:00:53 +0530 Subject: [PATCH 212/320] Added Power Support ppc64le --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 209cfb79..77c04702 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ go: - 1.14.x - tip jobs: - exclude: + exclude: # Excluded for power support as the lower versions are not supported - arch: ppc64le go: 1.2.x - arch: ppc64le From 222ea6c374b56edba40b7bf88f75c3fd05a7e48d Mon Sep 17 00:00:00 2001 From: AryanAhadinia Date: Wed, 13 Jan 2021 23:15:29 +0330 Subject: [PATCH 213/320] Add queue interface --- queues/queues.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 queues/queues.go diff --git a/queues/queues.go b/queues/queues.go new file mode 100644 index 00000000..959a0a5c --- /dev/null +++ b/queues/queues.go @@ -0,0 +1,26 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package queues provides an abstract Queue interface. +// +// In computer science, a queue is a collection of entities that are maintained in a sequence and can be modified by the addition of entities at one end of the sequence and the removal of entities from the other end of the sequence. By convention, the end of the sequence at which elements are added is called the back, tail, or rear of the queue, and the end at which elements are removed is called the head or front of the queue, analogously to the words used when people line up to wait for goods or services. +// The operation of adding an element to the rear of the queue is known as enqueue, and the operation of removing an element from the front is known as dequeue. Other operations may also be allowed, often including a peek or front operation that returns the value of the next element to be dequeued without remove it. +// +// Reference: https://en.wikipedia.org/wiki/Queue_(abstract_data_type) +package queues + +import "github.com/emirpasic/gods/containers" + +// Queue interface that all queues implement +type Queue interface { + Enqueue(value interface{}) + Dequeue() (value interface{}, ok bool) + Peek() (value interface{}, ok bool) + + containers.Container + // Empty() bool + // Size() int + // Clear() + // Values() []interface{} +} From 386e3be5861f1464770530755b8969be9331e8ee Mon Sep 17 00:00:00 2001 From: AryanAhadinia Date: Wed, 13 Jan 2021 23:15:58 +0330 Subject: [PATCH 214/320] Add arrayqueue --- queues/arrayqueue/arrayqueue.go | 87 +++++++++ queues/arrayqueue/arrayqueue_test.go | 278 +++++++++++++++++++++++++++ queues/arrayqueue/iterator.go | 84 ++++++++ queues/arrayqueue/serialization.go | 22 +++ 4 files changed, 471 insertions(+) create mode 100644 queues/arrayqueue/arrayqueue.go create mode 100644 queues/arrayqueue/arrayqueue_test.go create mode 100644 queues/arrayqueue/iterator.go create mode 100644 queues/arrayqueue/serialization.go diff --git a/queues/arrayqueue/arrayqueue.go b/queues/arrayqueue/arrayqueue.go new file mode 100644 index 00000000..11bc9953 --- /dev/null +++ b/queues/arrayqueue/arrayqueue.go @@ -0,0 +1,87 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package arrayqueue implements a queue backed by a array-list. +// +// Structure is not thread safe. +// +// Reference: https://en.wikipedia.org/wiki/Queue_(abstract_data_type) +package arrayqueue + +import ( + "fmt" + "strings" + + "github.com/emirpasic/gods/lists/arraylist" + "github.com/emirpasic/gods/queues" +) + +func assertQueueImplementation() { + var _ queues.Queue = (*Queue)(nil) +} + +// Queue holds elements in an array-list +type Queue struct { + list *arraylist.List +} + +// New instantiates a new empty queue +func New() *Queue { + return &Queue{list: arraylist.New()} +} + +// Enqueue adds a value to the end of the queue +func (queue *Queue) Enqueue(value interface{}) { + queue.list.Add(value) +} + +// Dequeue removes first element of the queue and returns it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to dequeue. +func (queue *Queue) Dequeue() (value interface{}, ok bool) { + value, ok = queue.list.Get(0) + queue.list.Remove(0) + return +} + +// Peek returns first element of the queue without removing it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to peek. +func (queue *Queue) Peek() (value interface{}, ok bool) { + return queue.list.Get(0) +} + +// Empty returns true if queue does not contain any elements. +func (queue *Queue) Empty() bool { + return queue.list.Empty() +} + +// Size returns number of elements within the queue. +func (queue *Queue) Size() int { + return queue.list.Size() +} + +// Clear removes all elements from the queue. +func (queue *Queue) Clear() { + queue.list.Clear() +} + +// Values returns all elements in the queue (FIFO order). +func (queue *Queue) Values() []interface{} { + return queue.list.Values() +} + +// String returns a string representation of container +func (queue *Queue) String() string { + str := "ArrayQueue\n" + values := []string{} + for _, value := range queue.list.Values() { + values = append(values, fmt.Sprintf("%v", value)) + } + str += strings.Join(values, ", ") + return str +} + +// Check that the index is within bounds of the list +func (queue *Queue) withinRange(index int) bool { + return index >= 0 && index < queue.list.Size() +} diff --git a/queues/arrayqueue/arrayqueue_test.go b/queues/arrayqueue/arrayqueue_test.go new file mode 100644 index 00000000..d86a3f05 --- /dev/null +++ b/queues/arrayqueue/arrayqueue_test.go @@ -0,0 +1,278 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package arrayqueue + +import ( + "fmt" + "testing" +) + +func TestQueueEnqueue(t *testing.T) { + queue := New() + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + + if actualValue := queue.Values(); actualValue[0].(int) != 1 || actualValue[1].(int) != 2 || actualValue[2].(int) != 3 { + t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + } + if actualValue := queue.Empty(); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, false) + } + if actualValue := queue.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + +func TestQueuePeek(t *testing.T) { + queue := New() + if actualValue, ok := queue.Peek(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + +func TestQueueDequeue(t *testing.T) { + queue := New() + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + queue.Dequeue() + if actualValue, ok := queue.Peek(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, ok := queue.Dequeue(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, ok := queue.Dequeue(); actualValue != 3 || !ok { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Dequeue(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + if actualValue := queue.Values(); len(actualValue) != 0 { + t.Errorf("Got %v expected %v", actualValue, "[]") + } +} + +func TestQueueIterator(t *testing.T) { + queue := New() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + // Iterator + it := queue.Iterator() + count := 0 + for it.Next() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; 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) + } + + queue.Clear() + it = queue.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty queue") + } +} + +func TestQueueIteratorBegin(t *testing.T) { + queue := New() + it := queue.Iterator() + it.Begin() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("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 TestQueueIteratorFirst(t *testing.T) { + queue := New() + it := queue.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + 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 TestQueueSerialization(t *testing.T) { + queue := New() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + var err error + assert := func() { + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", queue.Values()...), "abc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := queue.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + json, err := queue.ToJSON() + assert() + + err = queue.FromJSON(json) + assert() +} + +func benchmarkEnqueue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + } +} + +func benchmarkDequeue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Dequeue() + } + } +} + +func BenchmarkLinkedListQueueDequeue100(b *testing.B) { + b.StopTimer() + size := 100 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkLinkedListQueueDequeue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkLinkedListQueueDequeue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkLinkedListQueueDequeue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkLinkedListQueueEnqueue100(b *testing.B) { + b.StopTimer() + size := 100 + stack := New() + b.StartTimer() + benchmarkEnqueue(b, stack, size) +} + +func BenchmarkLinkedListQueueEnqueue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkLinkedListQueueEnqueue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkLinkedListQueueEnqueue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} diff --git a/queues/arrayqueue/iterator.go b/queues/arrayqueue/iterator.go new file mode 100644 index 00000000..5e41319b --- /dev/null +++ b/queues/arrayqueue/iterator.go @@ -0,0 +1,84 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package arrayqueue + +import "github.com/emirpasic/gods/containers" + +func assertIteratorImplementation() { + var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +type Iterator struct { + queue *Queue + index int +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +func (queue *Queue) Iterator() Iterator { + return Iterator{queue: queue, index: -1} +} + +// 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 { + if iterator.index < iterator.queue.Size() { + iterator.index++ + } + return iterator.queue.withinRange(iterator.index) +} + +// 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 { + if iterator.index >= 0 { + iterator.index-- + } + return iterator.queue.withinRange(iterator.index) +} + +// Value returns the current element's value. +// Does not modify the state of the iterator. +func (iterator *Iterator) Value() interface{} { + value, _ := iterator.queue.list.Get(iterator.index) // in order (FIFO) + return value +} + +// Index returns the current element's index. +// Does not modify the state of the iterator. +func (iterator *Iterator) Index() int { + return 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.index = -1 +} + +// 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.index = iterator.queue.Size() +} + +// 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 { + iterator.Begin() + return iterator.Next() +} + +// 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 { + iterator.End() + return iterator.Prev() +} diff --git a/queues/arrayqueue/serialization.go b/queues/arrayqueue/serialization.go new file mode 100644 index 00000000..45d554f6 --- /dev/null +++ b/queues/arrayqueue/serialization.go @@ -0,0 +1,22 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package arrayqueue + +import "github.com/emirpasic/gods/containers" + +func assertSerializationImplementation() { + var _ containers.JSONSerializer = (*Queue)(nil) + var _ containers.JSONDeserializer = (*Queue)(nil) +} + +// ToJSON outputs the JSON representation of the queue. +func (queue *Queue) ToJSON() ([]byte, error) { + return queue.list.ToJSON() +} + +// FromJSON populates the queue from the input JSON representation. +func (queue *Queue) FromJSON(data []byte) error { + return queue.list.FromJSON(data) +} From 327ef4525be9ba4157c58595a4d7b566b9c26531 Mon Sep 17 00:00:00 2001 From: AryanAhadinia Date: Wed, 13 Jan 2021 23:16:11 +0330 Subject: [PATCH 215/320] Add linkedlistqueue --- queues/linkedlistqueue/iterator.go | 60 ++++ queues/linkedlistqueue/linkedlistqueue.go | 87 ++++++ .../linkedlistqueue/linkedlistqueue_test.go | 278 ++++++++++++++++++ queues/linkedlistqueue/serialization.go | 22 ++ 4 files changed, 447 insertions(+) create mode 100644 queues/linkedlistqueue/iterator.go create mode 100644 queues/linkedlistqueue/linkedlistqueue.go create mode 100644 queues/linkedlistqueue/linkedlistqueue_test.go create mode 100644 queues/linkedlistqueue/serialization.go diff --git a/queues/linkedlistqueue/iterator.go b/queues/linkedlistqueue/iterator.go new file mode 100644 index 00000000..82afb086 --- /dev/null +++ b/queues/linkedlistqueue/iterator.go @@ -0,0 +1,60 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package linkedlistqueue + +import "github.com/emirpasic/gods/containers" + +func assertIteratorImplementation() { + var _ containers.IteratorWithIndex = (*Iterator)(nil) +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +type Iterator struct { + queue *Queue + index int +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +func (queue *Queue) Iterator() Iterator { + return Iterator{queue: queue, index: -1} +} + +// 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 { + if iterator.index < iterator.queue.Size() { + iterator.index++ + } + return iterator.queue.withinRange(iterator.index) +} + +// Value returns the current element's value. +// Does not modify the state of the iterator. +func (iterator *Iterator) Value() interface{} { + value, _ := iterator.queue.list.Get(iterator.index) // in order (FIFO) + return value +} + +// Index returns the current element's index. +// Does not modify the state of the iterator. +func (iterator *Iterator) Index() int { + return 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.index = -1 +} + +// 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 { + iterator.Begin() + return iterator.Next() +} diff --git a/queues/linkedlistqueue/linkedlistqueue.go b/queues/linkedlistqueue/linkedlistqueue.go new file mode 100644 index 00000000..d777a59f --- /dev/null +++ b/queues/linkedlistqueue/linkedlistqueue.go @@ -0,0 +1,87 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package linkedlistqueue implements a queue backed by a singly-linked list. +// +// Structure is not thread safe. +// +// Reference: https://en.wikipedia.org/wiki/Queue_(abstract_data_type) +package linkedlistqueue + +import ( + "fmt" + "strings" + + "github.com/emirpasic/gods/lists/singlylinkedlist" + "github.com/emirpasic/gods/queues" +) + +func assertQueueImplementation() { + var _ queues.Queue = (*Queue)(nil) +} + +// Queue holds elements in a singly-linked-list +type Queue struct { + list *singlylinkedlist.List +} + +// New instantiates a new empty queue +func New() *Queue { + return &Queue{list: &singlylinkedlist.List{}} +} + +// Enqueue adds a value to the end of the queue +func (queue *Queue) Enqueue(value interface{}) { + queue.list.Add(value) +} + +// Dequeue removes first element of the queue and returns it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to dequeue. +func (queue *Queue) Dequeue() (value interface{}, ok bool) { + value, ok = queue.list.Get(0) + queue.list.Remove(0) + return +} + +// Peek returns first element of the queue without removing it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to peek. +func (queue *Queue) Peek() (value interface{}, ok bool) { + return queue.list.Get(0) +} + +// Empty returns true if queue does not contain any elements. +func (queue *Queue) Empty() bool { + return queue.list.Empty() +} + +// Size returns number of elements within the queue. +func (queue *Queue) Size() int { + return queue.list.Size() +} + +// Clear removes all elements from the queue. +func (queue *Queue) Clear() { + queue.list.Clear() +} + +// Values returns all elements in the queue (FIFO order). +func (queue *Queue) Values() []interface{} { + return queue.list.Values() +} + +// String returns a string representation of container +func (queue *Queue) String() string { + str := "LinkedListQueue\n" + values := []string{} + for _, value := range queue.list.Values() { + values = append(values, fmt.Sprintf("%v", value)) + } + str += strings.Join(values, ", ") + return str +} + +// Check that the index is within bounds of the list +func (queue *Queue) withinRange(index int) bool { + return index >= 0 && index < queue.list.Size() +} diff --git a/queues/linkedlistqueue/linkedlistqueue_test.go b/queues/linkedlistqueue/linkedlistqueue_test.go new file mode 100644 index 00000000..fd640ce5 --- /dev/null +++ b/queues/linkedlistqueue/linkedlistqueue_test.go @@ -0,0 +1,278 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package linkedlistqueue + +import ( + "fmt" + "testing" +) + +func TestQueueEnqueue(t *testing.T) { + queue := New() + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + + if actualValue := queue.Values(); actualValue[0].(int) != 1 || actualValue[1].(int) != 2 || actualValue[2].(int) != 3 { + t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + } + if actualValue := queue.Empty(); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, false) + } + if actualValue := queue.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + +func TestQueuePeek(t *testing.T) { + queue := New() + if actualValue, ok := queue.Peek(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + +func TestQueueDequeue(t *testing.T) { + queue := New() + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + queue.Dequeue() + if actualValue, ok := queue.Peek(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, ok := queue.Dequeue(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, ok := queue.Dequeue(); actualValue != 3 || !ok { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Dequeue(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + if actualValue := queue.Values(); len(actualValue) != 0 { + t.Errorf("Got %v expected %v", actualValue, "[]") + } +} + +func TestQueueIterator(t *testing.T) { + queue := New() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + // Iterator + it := queue.Iterator() + count := 0 + for it.Next() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; 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) + } + + queue.Clear() + it = queue.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty queue") + } +} + +func TestQueueIteratorBegin(t *testing.T) { + queue := New() + it := queue.Iterator() + it.Begin() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("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 TestQueueIteratorFirst(t *testing.T) { + queue := New() + it := queue.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + 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 TestQueueSerialization(t *testing.T) { + queue := New() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + var err error + assert := func() { + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", queue.Values()...), "abc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := queue.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + json, err := queue.ToJSON() + assert() + + err = queue.FromJSON(json) + assert() +} + +func benchmarkEnqueue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + } +} + +func benchmarkDequeue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Dequeue() + } + } +} + +func BenchmarkLinkedListQueueDequeue100(b *testing.B) { + b.StopTimer() + size := 100 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkLinkedListQueueDequeue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkLinkedListQueueDequeue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkLinkedListQueueDequeue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkLinkedListQueueEnqueue100(b *testing.B) { + b.StopTimer() + size := 100 + stack := New() + b.StartTimer() + benchmarkEnqueue(b, stack, size) +} + +func BenchmarkLinkedListQueueEnqueue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkLinkedListQueueEnqueue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkLinkedListQueueEnqueue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} diff --git a/queues/linkedlistqueue/serialization.go b/queues/linkedlistqueue/serialization.go new file mode 100644 index 00000000..ccd1038f --- /dev/null +++ b/queues/linkedlistqueue/serialization.go @@ -0,0 +1,22 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package linkedlistqueue + +import "github.com/emirpasic/gods/containers" + +func assertSerializationImplementation() { + var _ containers.JSONSerializer = (*Queue)(nil) + var _ containers.JSONDeserializer = (*Queue)(nil) +} + +// ToJSON outputs the JSON representation of the queue. +func (queue *Queue) ToJSON() ([]byte, error) { + return queue.list.ToJSON() +} + +// FromJSON populates the queue from the input JSON representation. +func (queue *Queue) FromJSON(data []byte) error { + return queue.list.FromJSON(data) +} From b2f992450dd0503d6ab42feb3556cc6fc17367c5 Mon Sep 17 00:00:00 2001 From: AryanAhadinia Date: Wed, 13 Jan 2021 23:17:01 +0330 Subject: [PATCH 216/320] Add queue to README --- README.md | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/README.md b/README.md index 7346b994..dd110332 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,9 @@ Implementation of various data structures and algorithms in Go. - [ArrayList](#arraylist) - [SinglyLinkedList](#singlylinkedlist) - [DoublyLinkedList](#doublylinkedlist) + - [Queues](#queues) + - [LinkedListQueue](#linkedlistqueue) + - [ArrayQueue](#arrayqueue) - [Sets](#sets) - [HashSet](#hashset) - [TreeSet](#treeset) @@ -68,6 +71,9 @@ Containers are either ordered or unordered. All ordered containers provide [stat | | [ArrayList](#arraylist) | yes | yes* | yes | index | | | [SinglyLinkedList](#singlylinkedlist) | yes | yes | yes | index | | | [DoublyLinkedList](#doublylinkedlist) | yes | yes* | yes | index | +| [Queues](#queues) | +| | [LinkedListQueues](#linkedlistqueues) | yes | yes | no | index | +| | [ArrayQueues](#arrayqueues) | yes | yes* | no | index | | [Sets](#sets) | | | [HashSet](#hashset) | no | no | no | index | | | [TreeSet](#treeset) | yes | yes* | yes | index | @@ -400,6 +406,80 @@ func main() { } ``` +### Queues + +A queue that represents a first-in-first-out (FIFO) data structure. The usual enqueue and dequeue operations are provided, as well as a method to peek at the first item in the queue. + +Implements [Container](#containers) interface. + +```go +type Queue interface { + Enqueue(value interface{}) + Dequeue() (value interface{}, ok bool) + Peek() (value interface{}, ok bool) + + containers.Container + // Empty() bool + // Size() int + // Clear() + // Values() []interface{} +} +``` + +#### LinkedListQueue + +A [queue](#queues) based on a [linked list](#singlylinkedlist). + +Implements [Queue](#queues), [IteratorWithIndex](#iteratorwithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. + +```go +package main + +import ll1 "github.com/emirpasic/gods/stacks/linkedlistqueue" + +func main() { + queue := llq.New() // empty + queue.Enqueue(1) // 1 + queue.Enqueue(2) // 1, 2 + queue.Values() // 1, 2 + _, _ = queue.Peek() // 1, true + _, _ = queue.Dequeue() // 1, true + _, _ = queue.Dequeue() // 2, true + _, _ = queue.Dequeue() // nil, false + queue.Enqueue(1) // 1 + queue.Clear() // empty + queue.Empty() // true + queue.Size() // 0 +} +``` + +#### ArrayStack + +A [queue](#queues) based on a [array list](#arraylist). + +Implements [Queue](#queues), [IteratorWithIndex](#iteratorwithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. + +```go +package main + +import ll1 "github.com/emirpasic/gods/stacks/linkedlistqueue" + +func main() { + queue := llq.New() // empty + queue.Enqueue(1) // 1 + queue.Enqueue(2) // 1, 2 + queue.Values() // 1, 2 + _, _ = queue.Peek() // 1, true + _, _ = queue.Dequeue() // 1, true + _, _ = queue.Dequeue() // 2, true + _, _ = queue.Dequeue() // nil, false + queue.Enqueue(1) // 1 + queue.Clear() // empty + queue.Empty() // true + queue.Size() // 0 +} +``` + ### Maps A Map is a data structure that maps keys to values. A map cannot contain duplicate keys and each key can map to at most one value. From 3c9a1ea06fc4a088542304040693fc13c6c1e876 Mon Sep 17 00:00:00 2001 From: Aryan Ahadinia <62179268+AryanAhadinia@users.noreply.github.com> Date: Wed, 20 Jan 2021 11:37:49 +0330 Subject: [PATCH 217/320] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dd110332..ca68aa12 100644 --- a/README.md +++ b/README.md @@ -453,7 +453,7 @@ func main() { } ``` -#### ArrayStack +#### ArrayQueue A [queue](#queues) based on a [array list](#arraylist). From c9a2dcad62ad67eae246af2ebe23b5aff84e15cf Mon Sep 17 00:00:00 2001 From: mshadow Date: Thu, 8 Apr 2021 15:19:55 +0800 Subject: [PATCH 218/320] Implements json.Marshaler and json.Unmarshaler --- lists/arraylist/serialization.go | 12 ++++++++++++ lists/doublylinkedlist/serialization.go | 12 ++++++++++++ lists/singlylinkedlist/serialization.go | 12 ++++++++++++ maps/hashbidimap/serialization.go | 12 ++++++++++++ maps/hashmap/serialization.go | 12 ++++++++++++ maps/linkedhashmap/serialization.go | 12 ++++++++++++ maps/treebidimap/serialization.go | 12 ++++++++++++ maps/treemap/serialization.go | 18 +++++++++++++++++- sets/hashset/serialization.go | 12 ++++++++++++ sets/linkedhashset/serialization.go | 12 ++++++++++++ sets/treeset/serialization.go | 12 ++++++++++++ stacks/arraystack/serialization.go | 18 +++++++++++++++++- stacks/linkedliststack/serialization.go | 18 +++++++++++++++++- trees/avltree/serialization.go | 12 ++++++++++++ trees/binaryheap/serialization.go | 18 +++++++++++++++++- trees/btree/serialization.go | 12 ++++++++++++ trees/redblacktree/serialization.go | 12 ++++++++++++ 17 files changed, 224 insertions(+), 4 deletions(-) diff --git a/lists/arraylist/serialization.go b/lists/arraylist/serialization.go index 2f283fb9..eeaaa4d2 100644 --- a/lists/arraylist/serialization.go +++ b/lists/arraylist/serialization.go @@ -12,6 +12,8 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*List)(nil) var _ containers.JSONDeserializer = (*List)(nil) + var _ json.Marshaler = (*List)(nil) + var _ json.Unmarshaler = (*List)(nil) } // ToJSON outputs the JSON representation of list's elements. @@ -27,3 +29,13 @@ func (list *List) FromJSON(data []byte) error { } return err } + +// @implements json.Unmarshaler +func (list *List) UnmarshalJSON(bytes []byte) error { + return list.FromJSON(bytes) +} + +// @implements json.Marshaler +func (list *List) MarshalJSON() ([]byte, error) { + return list.ToJSON() +} diff --git a/lists/doublylinkedlist/serialization.go b/lists/doublylinkedlist/serialization.go index 6018d80f..a61d9ba6 100644 --- a/lists/doublylinkedlist/serialization.go +++ b/lists/doublylinkedlist/serialization.go @@ -12,6 +12,8 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*List)(nil) var _ containers.JSONDeserializer = (*List)(nil) + var _ json.Marshaler = (*List)(nil) + var _ json.Unmarshaler = (*List)(nil) } // ToJSON outputs the JSON representation of list's elements. @@ -29,3 +31,13 @@ func (list *List) FromJSON(data []byte) error { } return err } + +// @implements json.Unmarshaler +func (list *List) UnmarshalJSON(bytes []byte) error { + return list.FromJSON(bytes) +} + +// @implements json.Marshaler +func (list *List) MarshalJSON() ([]byte, error) { + return list.ToJSON() +} diff --git a/lists/singlylinkedlist/serialization.go b/lists/singlylinkedlist/serialization.go index 324f1d9a..74ce75ff 100644 --- a/lists/singlylinkedlist/serialization.go +++ b/lists/singlylinkedlist/serialization.go @@ -12,6 +12,8 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*List)(nil) var _ containers.JSONDeserializer = (*List)(nil) + var _ json.Marshaler = (*List)(nil) + var _ json.Unmarshaler = (*List)(nil) } // ToJSON outputs the JSON representation of list's elements. @@ -29,3 +31,13 @@ func (list *List) FromJSON(data []byte) error { } return err } + +// @implements json.Unmarshaler +func (list *List) UnmarshalJSON(bytes []byte) error { + return list.FromJSON(bytes) +} + +// @implements json.Marshaler +func (list *List) MarshalJSON() ([]byte, error) { + return list.ToJSON() +} diff --git a/maps/hashbidimap/serialization.go b/maps/hashbidimap/serialization.go index 3db41d42..e05c4e8a 100644 --- a/maps/hashbidimap/serialization.go +++ b/maps/hashbidimap/serialization.go @@ -12,6 +12,8 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Map)(nil) var _ containers.JSONDeserializer = (*Map)(nil) + var _ json.Marshaler = (*Map)(nil) + var _ json.Unmarshaler = (*Map)(nil) } // ToJSON outputs the JSON representation of the map. @@ -31,3 +33,13 @@ func (m *Map) FromJSON(data []byte) error { } return err } + +// @implements json.Unmarshaler +func (m *Map) UnmarshalJSON(bytes []byte) error { + return m.FromJSON(bytes) +} + +// @implements json.Marshaler +func (m *Map) MarshalJSON() ([]byte, error) { + return m.ToJSON() +} diff --git a/maps/hashmap/serialization.go b/maps/hashmap/serialization.go index b06eb7ef..8fe78fa9 100644 --- a/maps/hashmap/serialization.go +++ b/maps/hashmap/serialization.go @@ -13,6 +13,8 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Map)(nil) var _ containers.JSONDeserializer = (*Map)(nil) + var _ json.Marshaler = (*Map)(nil) + var _ json.Unmarshaler = (*Map)(nil) } // ToJSON outputs the JSON representation of the map. @@ -36,3 +38,13 @@ func (m *Map) FromJSON(data []byte) error { } return err } + +// @implements json.Unmarshaler +func (m *Map) UnmarshalJSON(bytes []byte) error { + return m.FromJSON(bytes) +} + +// @implements json.Marshaler +func (m *Map) MarshalJSON() ([]byte, error) { + return m.ToJSON() +} diff --git a/maps/linkedhashmap/serialization.go b/maps/linkedhashmap/serialization.go index 4f723cf6..a628b914 100644 --- a/maps/linkedhashmap/serialization.go +++ b/maps/linkedhashmap/serialization.go @@ -14,6 +14,8 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Map)(nil) var _ containers.JSONDeserializer = (*Map)(nil) + var _ json.Marshaler = (*Map)(nil) + var _ json.Unmarshaler = (*Map)(nil) } // ToJSON outputs the JSON representation of map. @@ -101,3 +103,13 @@ func (m *Map) FromJSON(data []byte) error { return nil } + +// @implements json.Unmarshaler +func (m *Map) UnmarshalJSON(bytes []byte) error { + return m.FromJSON(bytes) +} + +// @implements json.Marshaler +func (m *Map) MarshalJSON() ([]byte, error) { + return m.ToJSON() +} diff --git a/maps/treebidimap/serialization.go b/maps/treebidimap/serialization.go index 17204f99..488d2a0f 100644 --- a/maps/treebidimap/serialization.go +++ b/maps/treebidimap/serialization.go @@ -13,6 +13,8 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Map)(nil) var _ containers.JSONDeserializer = (*Map)(nil) + var _ json.Marshaler = (*Map)(nil) + var _ json.Unmarshaler = (*Map)(nil) } // ToJSON outputs the JSON representation of the map. @@ -37,3 +39,13 @@ func (m *Map) FromJSON(data []byte) error { } return err } + +// @implements json.Unmarshaler +func (m *Map) UnmarshalJSON(bytes []byte) error { + return m.FromJSON(bytes) +} + +// @implements json.Marshaler +func (m *Map) MarshalJSON() ([]byte, error) { + return m.ToJSON() +} diff --git a/maps/treemap/serialization.go b/maps/treemap/serialization.go index d856300d..d6b2d101 100644 --- a/maps/treemap/serialization.go +++ b/maps/treemap/serialization.go @@ -4,11 +4,17 @@ package treemap -import "github.com/emirpasic/gods/containers" +import ( + "encoding/json" + + "github.com/emirpasic/gods/containers" +) func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Map)(nil) var _ containers.JSONDeserializer = (*Map)(nil) + var _ json.Marshaler = (*Map)(nil) + var _ json.Unmarshaler = (*Map)(nil) } // ToJSON outputs the JSON representation of the map. @@ -20,3 +26,13 @@ func (m *Map) ToJSON() ([]byte, error) { func (m *Map) FromJSON(data []byte) error { return m.tree.FromJSON(data) } + +// @implements json.Unmarshaler +func (m *Map) UnmarshalJSON(bytes []byte) error { + return m.FromJSON(bytes) +} + +// @implements json.Marshaler +func (m *Map) MarshalJSON() ([]byte, error) { + return m.ToJSON() +} diff --git a/sets/hashset/serialization.go b/sets/hashset/serialization.go index 7b8506df..f93b0cbc 100644 --- a/sets/hashset/serialization.go +++ b/sets/hashset/serialization.go @@ -12,6 +12,8 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Set)(nil) var _ containers.JSONDeserializer = (*Set)(nil) + var _ json.Marshaler = (*Set)(nil) + var _ json.Unmarshaler = (*Set)(nil) } // ToJSON outputs the JSON representation of the set. @@ -29,3 +31,13 @@ func (set *Set) FromJSON(data []byte) error { } return err } + +// @implements json.Unmarshaler +func (set *Set) UnmarshalJSON(bytes []byte) error { + return set.FromJSON(bytes) +} + +// @implements json.Marshaler +func (set *Set) MarshalJSON() ([]byte, error) { + return set.ToJSON() +} diff --git a/sets/linkedhashset/serialization.go b/sets/linkedhashset/serialization.go index 7e7d2911..4e84be9e 100644 --- a/sets/linkedhashset/serialization.go +++ b/sets/linkedhashset/serialization.go @@ -12,6 +12,8 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Set)(nil) var _ containers.JSONDeserializer = (*Set)(nil) + var _ json.Marshaler = (*Set)(nil) + var _ json.Unmarshaler = (*Set)(nil) } // ToJSON outputs the JSON representation of the set. @@ -29,3 +31,13 @@ func (set *Set) FromJSON(data []byte) error { } return err } + +// @implements json.Unmarshaler +func (set *Set) UnmarshalJSON(bytes []byte) error { + return set.FromJSON(bytes) +} + +// @implements json.Marshaler +func (set *Set) MarshalJSON() ([]byte, error) { + return set.ToJSON() +} diff --git a/sets/treeset/serialization.go b/sets/treeset/serialization.go index a53bfccf..a74ad6da 100644 --- a/sets/treeset/serialization.go +++ b/sets/treeset/serialization.go @@ -12,6 +12,8 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Set)(nil) var _ containers.JSONDeserializer = (*Set)(nil) + var _ json.Marshaler = (*Set)(nil) + var _ json.Unmarshaler = (*Set)(nil) } // ToJSON outputs the JSON representation of the set. @@ -29,3 +31,13 @@ func (set *Set) FromJSON(data []byte) error { } return err } + +// @implements json.Unmarshaler +func (set *Set) UnmarshalJSON(bytes []byte) error { + return set.FromJSON(bytes) +} + +// @implements json.Marshaler +func (set *Set) MarshalJSON() ([]byte, error) { + return set.ToJSON() +} diff --git a/stacks/arraystack/serialization.go b/stacks/arraystack/serialization.go index c4ff5497..6d26fa72 100644 --- a/stacks/arraystack/serialization.go +++ b/stacks/arraystack/serialization.go @@ -4,11 +4,17 @@ package arraystack -import "github.com/emirpasic/gods/containers" +import ( + "encoding/json" + + "github.com/emirpasic/gods/containers" +) func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Stack)(nil) var _ containers.JSONDeserializer = (*Stack)(nil) + var _ json.Marshaler = (*Stack)(nil) + var _ json.Unmarshaler = (*Stack)(nil) } // ToJSON outputs the JSON representation of the stack. @@ -20,3 +26,13 @@ func (stack *Stack) ToJSON() ([]byte, error) { func (stack *Stack) FromJSON(data []byte) error { return stack.list.FromJSON(data) } + +// @implements json.Unmarshaler +func (stack *Stack) UnmarshalJSON(bytes []byte) error { + return stack.FromJSON(bytes) +} + +// @implements json.Marshaler +func (stack *Stack) MarshalJSON() ([]byte, error) { + return stack.ToJSON() +} diff --git a/stacks/linkedliststack/serialization.go b/stacks/linkedliststack/serialization.go index 63337a1f..fce1511e 100644 --- a/stacks/linkedliststack/serialization.go +++ b/stacks/linkedliststack/serialization.go @@ -4,11 +4,17 @@ package linkedliststack -import "github.com/emirpasic/gods/containers" +import ( + "encoding/json" + + "github.com/emirpasic/gods/containers" +) func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Stack)(nil) var _ containers.JSONDeserializer = (*Stack)(nil) + var _ json.Marshaler = (*Stack)(nil) + var _ json.Unmarshaler = (*Stack)(nil) } // ToJSON outputs the JSON representation of the stack. @@ -20,3 +26,13 @@ func (stack *Stack) ToJSON() ([]byte, error) { func (stack *Stack) FromJSON(data []byte) error { return stack.list.FromJSON(data) } + +// @implements json.Unmarshaler +func (stack *Stack) UnmarshalJSON(bytes []byte) error { + return stack.FromJSON(bytes) +} + +// @implements json.Marshaler +func (stack *Stack) MarshalJSON() ([]byte, error) { + return stack.ToJSON() +} diff --git a/trees/avltree/serialization.go b/trees/avltree/serialization.go index 363de7f4..79d4e5e9 100644 --- a/trees/avltree/serialization.go +++ b/trees/avltree/serialization.go @@ -13,6 +13,8 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Tree)(nil) var _ containers.JSONDeserializer = (*Tree)(nil) + var _ json.Marshaler = (*Tree)(nil) + var _ json.Unmarshaler = (*Tree)(nil) } // ToJSON outputs the JSON representation of the tree. @@ -37,3 +39,13 @@ func (tree *Tree) FromJSON(data []byte) error { } return err } + +// @implements json.Unmarshaler +func (tree *Tree) UnmarshalJSON(bytes []byte) error { + return tree.FromJSON(bytes) +} + +// @implements json.Marshaler +func (tree *Tree) MarshalJSON() ([]byte, error) { + return tree.ToJSON() +} diff --git a/trees/binaryheap/serialization.go b/trees/binaryheap/serialization.go index 00d0c771..e0d2a939 100644 --- a/trees/binaryheap/serialization.go +++ b/trees/binaryheap/serialization.go @@ -4,11 +4,17 @@ package binaryheap -import "github.com/emirpasic/gods/containers" +import ( + "encoding/json" + + "github.com/emirpasic/gods/containers" +) func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Heap)(nil) var _ containers.JSONDeserializer = (*Heap)(nil) + var _ json.Marshaler = (*Heap)(nil) + var _ json.Unmarshaler = (*Heap)(nil) } // ToJSON outputs the JSON representation of the heap. @@ -20,3 +26,13 @@ func (heap *Heap) ToJSON() ([]byte, error) { func (heap *Heap) FromJSON(data []byte) error { return heap.list.FromJSON(data) } + +// @implements json.Unmarshaler +func (heap *Heap) UnmarshalJSON(bytes []byte) error { + return heap.FromJSON(bytes) +} + +// @implements json.Marshaler +func (heap *Heap) MarshalJSON() ([]byte, error) { + return heap.ToJSON() +} diff --git a/trees/btree/serialization.go b/trees/btree/serialization.go index 43851676..75ef7280 100644 --- a/trees/btree/serialization.go +++ b/trees/btree/serialization.go @@ -13,6 +13,8 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Tree)(nil) var _ containers.JSONDeserializer = (*Tree)(nil) + var _ json.Marshaler = (*Tree)(nil) + var _ json.Unmarshaler = (*Tree)(nil) } // ToJSON outputs the JSON representation of the tree. @@ -37,3 +39,13 @@ func (tree *Tree) FromJSON(data []byte) error { } return err } + +// @implements json.Unmarshaler +func (tree *Tree) UnmarshalJSON(bytes []byte) error { + return tree.FromJSON(bytes) +} + +// @implements json.Marshaler +func (tree *Tree) MarshalJSON() ([]byte, error) { + return tree.ToJSON() +} diff --git a/trees/redblacktree/serialization.go b/trees/redblacktree/serialization.go index a1b8a779..84c48216 100644 --- a/trees/redblacktree/serialization.go +++ b/trees/redblacktree/serialization.go @@ -13,6 +13,8 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Tree)(nil) var _ containers.JSONDeserializer = (*Tree)(nil) + var _ json.Marshaler = (*Tree)(nil) + var _ json.Unmarshaler = (*Tree)(nil) } // ToJSON outputs the JSON representation of the tree. @@ -37,3 +39,13 @@ func (tree *Tree) FromJSON(data []byte) error { } return err } + +// @implements json.Unmarshaler +func (tree *Tree) UnmarshalJSON(bytes []byte) error { + return tree.FromJSON(bytes) +} + +// @implements json.Marshaler +func (tree *Tree) MarshalJSON() ([]byte, error) { + return tree.ToJSON() +} From 2ca267d33974f512b9b53e2c8bb99ae14395c90e Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 5 Apr 2022 08:59:27 +0200 Subject: [PATCH 219/320] Update travis to latest golang versions --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 77c04702..35734be8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,10 @@ go: - 1.12.x - 1.13.x - 1.14.x + - 1.15.x + - 1.16.x + - 1.17.x + - 1.18.x - tip jobs: exclude: # Excluded for power support as the lower versions are not supported From e95c27926ac22798b5c65a331e3f4bd03f4f421e Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 5 Apr 2022 09:30:10 +0200 Subject: [PATCH 220/320] Add .circleci/config.yml --- .circleci/config.yml | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..1b9032bc --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,42 @@ +# Use the latest 2.1 version of CircleCI pipeline process engine. +# See: https://circleci.com/docs/2.0/configuration-reference +version: 2.1 + +# Define a job to be invoked later in a workflow. +# See: https://circleci.com/docs/2.0/configuration-reference/#jobs +jobs: + build: + working_directory: ~/repo + # Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub. + # See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor + docker: + - image: circleci/golang:1.15.8 + # Add steps to the job + # See: https://circleci.com/docs/2.0/configuration-reference/#steps + steps: + - checkout + - restore_cache: + keys: + - go-mod-v4-{{ checksum "go.sum" }} + - run: + name: Install Dependencies + command: go mod download + - save_cache: + key: go-mod-v4-{{ checksum "go.sum" }} + paths: + - "/go/pkg/mod" + - run: + name: Run tests + command: | + mkdir -p /tmp/test-reports + gotestsum --junitfile /tmp/test-reports/unit-tests.xml + - store_test_results: + path: /tmp/test-reports + +# Invoke jobs via workflows +# See: https://circleci.com/docs/2.0/configuration-reference/#workflows +workflows: + sample: # This is the name of the workflow, feel free to change it to better match your workflow. + # Inside the workflow, you define the jobs you want to run. + jobs: + - build From a6a23a940fa59ac36a674b1b3f544c35347b42e6 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 5 Apr 2022 09:41:11 +0200 Subject: [PATCH 221/320] Switching to CircleCI --- .travis.yml | 27 --------------------------- go.mod | 3 +++ 2 files changed, 3 insertions(+), 27 deletions(-) delete mode 100644 .travis.yml create mode 100644 go.mod diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 77c04702..00000000 --- a/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: go -arch: - - amd64 - - ppc64le -go: - - 1.2.x - - 1.3.x - - 1.4.x - - 1.5.x - - 1.6.x - - 1.7.x - - 1.8.x - - 1.9.x - - 1.10.x - - 1.11.x - - 1.12.x - - 1.13.x - - 1.14.x - - tip -jobs: - exclude: # Excluded for power support as the lower versions are not supported - - arch: ppc64le - go: 1.2.x - - arch: ppc64le - go: 1.3.x - - arch: ppc64le - go: 1.4.x diff --git a/go.mod b/go.mod new file mode 100644 index 00000000..5160ad04 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/emirpasic/gods + +go 1.2 From 1ecec7b3bc5cc9e8e080005a7b9bacc1ec2123fb Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 5 Apr 2022 09:44:49 +0200 Subject: [PATCH 222/320] Switching to CircleCI --- .circleci/config.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1b9032bc..bcd16478 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -15,16 +15,6 @@ jobs: # See: https://circleci.com/docs/2.0/configuration-reference/#steps steps: - checkout - - restore_cache: - keys: - - go-mod-v4-{{ checksum "go.sum" }} - - run: - name: Install Dependencies - command: go mod download - - save_cache: - key: go-mod-v4-{{ checksum "go.sum" }} - paths: - - "/go/pkg/mod" - run: name: Run tests command: | From bf2f98b8a3031a0a4c9e3a821ab9cd718789b6b9 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 10:57:57 +0200 Subject: [PATCH 223/320] Switching to CircleCI --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7346b994..34c2febc 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![GoDoc](https://godoc.org/github.com/emirpasic/gods?status.svg)](https://godoc.org/github.com/emirpasic/gods) [![Build Status](https://travis-ci.org/emirpasic/gods.svg)](https://travis-ci.org/emirpasic/gods) [![Go Report Card](https://goreportcard.com/badge/github.com/emirpasic/gods)](https://goreportcard.com/report/github.com/emirpasic/gods) [![PyPI](https://img.shields.io/pypi/l/Django.svg?maxAge=2592000)](https://github.com/emirpasic/gods/blob/master/LICENSE) +[![GoDoc](https://godoc.org/github.com/emirpasic/gods?status.svg)](https://godoc.org/github.com/emirpasic/gods) [![Build Status](https://circleci.com/gh/emirpasic/gods.svg?style=svg)](https://circleci.com/gh/emirpasic/gods) [![Go Report Card](https://goreportcard.com/badge/github.com/emirpasic/gods)](https://goreportcard.com/report/github.com/emirpasic/gods) [![PyPI](https://img.shields.io/pypi/l/Django.svg?maxAge=2592000)](https://github.com/emirpasic/gods/blob/master/LICENSE) # GoDS (Go Data Structures) From bf2ab81353858afb1c7887918f246b430bf97f5b Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 11:08:43 +0200 Subject: [PATCH 224/320] Switching to CircleCI --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 34c2febc..035fc341 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![GoDoc](https://godoc.org/github.com/emirpasic/gods?status.svg)](https://godoc.org/github.com/emirpasic/gods) [![Build Status](https://circleci.com/gh/emirpasic/gods.svg?style=svg)](https://circleci.com/gh/emirpasic/gods) [![Go Report Card](https://goreportcard.com/badge/github.com/emirpasic/gods)](https://goreportcard.com/report/github.com/emirpasic/gods) [![PyPI](https://img.shields.io/pypi/l/Django.svg?maxAge=2592000)](https://github.com/emirpasic/gods/blob/master/LICENSE) +[![GoDoc](https://godoc.org/github.com/emirpasic/gods?status.svg)](https://godoc.org/github.com/emirpasic/gods) [![Build Status](https://circleci.com/gh/emirpasic/gods/tree/master.svg?style=shield)](https://circleci.com/gh/emirpasic/gods?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/emirpasic/gods)](https://goreportcard.com/report/github.com/emirpasic/gods) [![PyPI](https://img.shields.io/pypi/l/Django.svg?maxAge=2592000)](https://github.com/emirpasic/gods/blob/master/LICENSE) # GoDS (Go Data Structures) From 7168f7acb71320473cc38013e66c09e11dc7d302 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 11:34:35 +0200 Subject: [PATCH 225/320] Switching to CircleCI --- .circleci/config.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index bcd16478..44bb201d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,6 +20,16 @@ jobs: command: | mkdir -p /tmp/test-reports gotestsum --junitfile /tmp/test-reports/unit-tests.xml + - run: + name: Lint + command: | + go get github.com/golang/lint/golint + golint -set_exit_status <> + - run: + name: Calculate cyclomatic complexity + command: | + go get github.com/fzipp/gocyclo + gocyclo -avg -over 15 . - store_test_results: path: /tmp/test-reports From bc06b657429f7c64cf16980e262dadc83ca656c0 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 17:45:46 +0200 Subject: [PATCH 226/320] Switching to CircleCI --- .circleci/config.yml | 52 ++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 44bb201d..6c96382b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,42 +1,52 @@ -# Use the latest 2.1 version of CircleCI pipeline process engine. -# See: https://circleci.com/docs/2.0/configuration-reference version: 2.1 -# Define a job to be invoked later in a workflow. -# See: https://circleci.com/docs/2.0/configuration-reference/#jobs jobs: - build: - working_directory: ~/repo - # Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub. - # See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor + test: + working_directory: /go/src/github.com/emirpasic/gods docker: - - image: circleci/golang:1.15.8 - # Add steps to the job - # See: https://circleci.com/docs/2.0/configuration-reference/#steps + - image: circleci/golang:<> steps: - checkout - run: - name: Run tests + name: Print Go version (go version) + command: | + go version + - run: + name: Run tests (gotestsum) command: | mkdir -p /tmp/test-reports gotestsum --junitfile /tmp/test-reports/unit-tests.xml - run: - name: Lint + name: Lint (golint) command: | - go get github.com/golang/lint/golint + go install github.com/golang/lint/golint@latest golint -set_exit_status <> - run: - name: Calculate cyclomatic complexity + name: Enforce formatted code (go fmt) + command: | + ! go fmt <> 2>&1 | read + - run: + name: Examine and report suspicious constructs (go vet) command: | - go get github.com/fzipp/gocyclo + go vet -v <> + - run: + name: Calculate cyclomatic complexity (gocyclo) + command: | + go install github.com/fzipp/gocyclo@latest gocyclo -avg -over 15 . + - run: + name: Check for unchecked errors (errcheck) + command: | + go install github.com/kisielk/errcheck@latest + errcheck <> - store_test_results: path: /tmp/test-reports -# Invoke jobs via workflows -# See: https://circleci.com/docs/2.0/configuration-reference/#workflows workflows: - sample: # This is the name of the workflow, feel free to change it to better match your workflow. - # Inside the workflow, you define the jobs you want to run. + test: jobs: - - build + - test: + matrix: + parameters: + version: ["latest", "1.18", "1.17", "1.2"] +# version: ["latest", "1.18", "1.17", "1.16", "1.15", "1.14", "1.13", "1.12", "1.11", "1.10", "1.9", "1.8", "1.7", "1.6", "1.5", "1.4", "1.3", "1.2"] \ No newline at end of file From bd369902f671d340060016e44cb554daf15095aa Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 18:01:44 +0200 Subject: [PATCH 227/320] Switching to CircleCI --- .circleci/config.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6c96382b..88b64cbc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,6 +2,10 @@ version: 2.1 jobs: test: + parameters: + version: + type: string + default: "latest" working_directory: /go/src/github.com/emirpasic/gods docker: - image: circleci/golang:<> From ff2f625e52a8122a9c584a9ecbbc56fea39f372c Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 18:03:28 +0200 Subject: [PATCH 228/320] Switching to CircleCI --- .circleci/config.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 88b64cbc..bfd08373 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -24,15 +24,15 @@ jobs: name: Lint (golint) command: | go install github.com/golang/lint/golint@latest - golint -set_exit_status <> + golint -set_exit_status ./... - run: name: Enforce formatted code (go fmt) command: | - ! go fmt <> 2>&1 | read + ! go fmt ./... 2>&1 | read - run: name: Examine and report suspicious constructs (go vet) command: | - go vet -v <> + go vet -v ./... - run: name: Calculate cyclomatic complexity (gocyclo) command: | @@ -42,7 +42,7 @@ jobs: name: Check for unchecked errors (errcheck) command: | go install github.com/kisielk/errcheck@latest - errcheck <> + errcheck ./... - store_test_results: path: /tmp/test-reports From 85aee54be6d00a8887d92f4d762b342fdd7e9854 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 18:06:05 +0200 Subject: [PATCH 229/320] Switching to CircleCI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index bfd08373..3f5a9104 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,7 +8,7 @@ jobs: default: "latest" working_directory: /go/src/github.com/emirpasic/gods docker: - - image: circleci/golang:<> + - image: cimg/go:<> steps: - checkout - run: From 550e1ae8aa3c5b2b6989d16003142c66276583c7 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 18:12:01 +0200 Subject: [PATCH 230/320] Switching to CircleCI --- .circleci/config.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3f5a9104..2cfbd380 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,9 +6,9 @@ jobs: version: type: string default: "latest" - working_directory: /go/src/github.com/emirpasic/gods + working_directory: ~/gods docker: - - image: cimg/go:<> + - image: circleci/golang:<> steps: - checkout - run: @@ -52,5 +52,4 @@ workflows: - test: matrix: parameters: - version: ["latest", "1.18", "1.17", "1.2"] -# version: ["latest", "1.18", "1.17", "1.16", "1.15", "1.14", "1.13", "1.12", "1.11", "1.10", "1.9", "1.8", "1.7", "1.6", "1.5", "1.4", "1.3", "1.2"] \ No newline at end of file + version: ["1.18", "1.17", "1.10"] \ No newline at end of file From 3b09037abdde86e9191f0d8a3e3359d498278063 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 18:13:12 +0200 Subject: [PATCH 231/320] Switching to CircleCI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2cfbd380..79430814 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,7 +8,7 @@ jobs: default: "latest" working_directory: ~/gods docker: - - image: circleci/golang:<> + - image: cimg/go:<> steps: - checkout - run: From 65063055ad3c53096f0452aa7952119c7d420a7b Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 18:23:04 +0200 Subject: [PATCH 232/320] Switching to CircleCI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 79430814..b4866b4e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -23,7 +23,7 @@ jobs: - run: name: Lint (golint) command: | - go install github.com/golang/lint/golint@latest + go install golang.org/x/lint/golint@latest golint -set_exit_status ./... - run: name: Enforce formatted code (go fmt) From 522b95113b4e43720cadd77e1aaf6c95fdb7f4ec Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 18:28:29 +0200 Subject: [PATCH 233/320] Switching to CircleCI --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b4866b4e..fcc813ae 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -36,8 +36,8 @@ jobs: - run: name: Calculate cyclomatic complexity (gocyclo) command: | - go install github.com/fzipp/gocyclo@latest - gocyclo -avg -over 15 . + go install github.com/fzipp/gocyclo/cmd/gocyclo@latest + gocyclo -avg -over 15 ../gods - run: name: Check for unchecked errors (errcheck) command: | From a0035b3f6e7db4446b1539e5a9855c054244ac8b Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 18:38:30 +0200 Subject: [PATCH 234/320] Switching to CircleCI --- .circleci/config.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index fcc813ae..1d9cc730 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,6 +9,8 @@ jobs: working_directory: ~/gods docker: - image: cimg/go:<> + environment: + TEST_RESULTS: /tmp/test-results steps: - checkout - run: @@ -16,10 +18,14 @@ jobs: command: | go version - run: - name: Run tests (gotestsum) - command: | - mkdir -p /tmp/test-reports - gotestsum --junitfile /tmp/test-reports/unit-tests.xml + name: Run tests and calculate coverage + command: | + mkdir -p $TEST_RESULTS + go test -coverprofile=c.out + go tool cover -html=c.out -o coverage.html + mv coverage.html $TEST_RESULTS + go test -v ./... | go tool test2json > $TEST_RESULTS/test2json-output.json + gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml - run: name: Lint (golint) command: | From 97f1ce01d44c4af44eda349ef0592d1319c8e0aa Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 18:39:37 +0200 Subject: [PATCH 235/320] Switching to CircleCI --- .circleci/config.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1d9cc730..15e74e68 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,13 +19,13 @@ jobs: go version - run: name: Run tests and calculate coverage - command: | - mkdir -p $TEST_RESULTS - go test -coverprofile=c.out - go tool cover -html=c.out -o coverage.html - mv coverage.html $TEST_RESULTS - go test -v ./... | go tool test2json > $TEST_RESULTS/test2json-output.json - gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml + command: | + mkdir -p $TEST_RESULTS + go test -coverprofile=c.out + go tool cover -html=c.out -o coverage.html + mv coverage.html $TEST_RESULTS + go test -v ./... | go tool test2json > $TEST_RESULTS/test2json-output.json + gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml - run: name: Lint (golint) command: | From d732d41ff91b13f51c01a24c42d3671d018de135 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 18:41:29 +0200 Subject: [PATCH 236/320] Switching to CircleCI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 15e74e68..969ccd2d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,7 +21,7 @@ jobs: name: Run tests and calculate coverage command: | mkdir -p $TEST_RESULTS - go test -coverprofile=c.out + go test -coverprofile=c.out ./... go tool cover -html=c.out -o coverage.html mv coverage.html $TEST_RESULTS go test -v ./... | go tool test2json > $TEST_RESULTS/test2json-output.json From c829b322e8cb4482709a052736ede18f51b4ebf6 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 18:45:45 +0200 Subject: [PATCH 237/320] Switching to CircleCI --- .circleci/config.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 969ccd2d..ac2e6751 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -18,14 +18,17 @@ jobs: command: | go version - run: - name: Run tests and calculate coverage + name: Run tests + command: | + go test -v ./... | go tool test2json > $TEST_RESULTS/test2json-output.json + gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml + - run: + name: Calculate test coverage command: | mkdir -p $TEST_RESULTS - go test -coverprofile=c.out ./... + go test -coverprofile=c.out ./... > /dev/null go tool cover -html=c.out -o coverage.html mv coverage.html $TEST_RESULTS - go test -v ./... | go tool test2json > $TEST_RESULTS/test2json-output.json - gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml - run: name: Lint (golint) command: | From 2cdadcd618b69de7c9557fff8072e62edffea3fa Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 18:46:38 +0200 Subject: [PATCH 238/320] Switching to CircleCI --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index ac2e6751..5f730249 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,6 +20,7 @@ jobs: - run: name: Run tests command: | + mkdir -p $TEST_RESULTS go test -v ./... | go tool test2json > $TEST_RESULTS/test2json-output.json gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml - run: From 662feda68150887c24f94455d808dc951a356b04 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 18:48:45 +0200 Subject: [PATCH 239/320] Switching to CircleCI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5f730249..ba587d63 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,7 +10,7 @@ jobs: docker: - image: cimg/go:<> environment: - TEST_RESULTS: /tmp/test-results + TEST_RESULTS: /tmp/test-reports steps: - checkout - run: From bba4a1d8e9409472a0cd31f28bc7065bb38cf12e Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 18:51:29 +0200 Subject: [PATCH 240/320] Switching to CircleCI --- .circleci/config.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ba587d63..6f00ff61 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,7 +10,7 @@ jobs: docker: - image: cimg/go:<> environment: - TEST_RESULTS: /tmp/test-reports + TEST_RESULTS: /tmp/test-results steps: - checkout - run: @@ -53,8 +53,11 @@ jobs: command: | go install github.com/kisielk/errcheck@latest errcheck ./... + - store_artifacts: + path: /tmp/test-results + destination: raw-test-output - store_test_results: - path: /tmp/test-reports + path: /tmp/test-results workflows: test: From d54e8a49d89d3f8676049f4cd1417c5dfecbd48c Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 19:15:14 +0200 Subject: [PATCH 241/320] Switching to CircleCI --- .circleci/config.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6f00ff61..8ed5746c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,11 +6,14 @@ jobs: version: type: string default: "latest" - working_directory: ~/gods docker: - image: cimg/go:<> environment: TEST_RESULTS: /tmp/test-results + GOROOT: "" + GOPATH: "${HOME}/${CIRCLE_PROJECT_REPONAME}" + REPO_PATH: "${GOPATH}/src/github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}" + working_directory: ${CIRCLE_PROJECT_REPONAME} steps: - checkout - run: @@ -47,7 +50,7 @@ jobs: name: Calculate cyclomatic complexity (gocyclo) command: | go install github.com/fzipp/gocyclo/cmd/gocyclo@latest - gocyclo -avg -over 15 ../gods + gocyclo -avg -over 15 ../${CIRCLE_PROJECT_REPONAME} - run: name: Check for unchecked errors (errcheck) command: | From 62c8f37a00f6ca95d983db891f10f42ff19a0ad1 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 19:55:47 +0200 Subject: [PATCH 242/320] Switching to CircleCI --- .circleci/config.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8ed5746c..4f5a8fbd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,15 +5,14 @@ jobs: parameters: version: type: string - default: "latest" + default: latest docker: - image: cimg/go:<> environment: TEST_RESULTS: /tmp/test-results - GOROOT: "" - GOPATH: "${HOME}/${CIRCLE_PROJECT_REPONAME}" - REPO_PATH: "${GOPATH}/src/github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}" - working_directory: ${CIRCLE_PROJECT_REPONAME} + GOPATH: ${HOME}/go + REPO_PATH: ${GOPATH}/src/github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME} + working_directory: $CIRCLE_PROJECT_REPONAME steps: - checkout - run: From bb331d1e99c533cd50a1ad0a59ba1a38c510b14d Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 19:58:14 +0200 Subject: [PATCH 243/320] Switching to CircleCI --- .circleci/config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4f5a8fbd..74a49599 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,13 +12,14 @@ jobs: TEST_RESULTS: /tmp/test-results GOPATH: ${HOME}/go REPO_PATH: ${GOPATH}/src/github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME} - working_directory: $CIRCLE_PROJECT_REPONAME + working_directory: ${REPO_PATH} steps: - checkout - run: name: Print Go version (go version) command: | go version + pwd - run: name: Run tests command: | From f9ca9bae3ee1305d466649ffa9e4aa2e0e1f0b8e Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:00:18 +0200 Subject: [PATCH 244/320] Switching to CircleCI --- .circleci/config.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 74a49599..684c534e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,9 +10,10 @@ jobs: - image: cimg/go:<> environment: TEST_RESULTS: /tmp/test-results + PROJECT_NAME: gods GOPATH: ${HOME}/go - REPO_PATH: ${GOPATH}/src/github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME} - working_directory: ${REPO_PATH} + PROJECT_PATH: ${GOPATH}/src/github.com/${CIRCLE_PROJECT_USERNAME}/${PROJECT_NAME} + working_directory: ${PROJECT_PATH} steps: - checkout - run: @@ -50,7 +51,7 @@ jobs: name: Calculate cyclomatic complexity (gocyclo) command: | go install github.com/fzipp/gocyclo/cmd/gocyclo@latest - gocyclo -avg -over 15 ../${CIRCLE_PROJECT_REPONAME} + gocyclo -avg -over 15 ../${PROJECT_NAME} - run: name: Check for unchecked errors (errcheck) command: | From 2d480b396591e7bd9956fb982f17db03fd490b1a Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:02:28 +0200 Subject: [PATCH 245/320] Switching to CircleCI --- .circleci/config.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 684c534e..1f24152a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -15,6 +15,11 @@ jobs: PROJECT_PATH: ${GOPATH}/src/github.com/${CIRCLE_PROJECT_USERNAME}/${PROJECT_NAME} working_directory: ${PROJECT_PATH} steps: + - run: + name: Create directories + command: | + mkdir -p PROJECT_PATH + mkdir -p $TEST_RESULTS - checkout - run: name: Print Go version (go version) @@ -24,13 +29,11 @@ jobs: - run: name: Run tests command: | - mkdir -p $TEST_RESULTS go test -v ./... | go tool test2json > $TEST_RESULTS/test2json-output.json gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml - run: name: Calculate test coverage command: | - mkdir -p $TEST_RESULTS go test -coverprofile=c.out ./... > /dev/null go tool cover -html=c.out -o coverage.html mv coverage.html $TEST_RESULTS From ed2e66b1dc4490387918ee05d20f8c200cf9444e Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:05:34 +0200 Subject: [PATCH 246/320] Switching to CircleCI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1f24152a..49f25c39 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -18,7 +18,7 @@ jobs: - run: name: Create directories command: | - mkdir -p PROJECT_PATH + mkdir -p $PROJECT_PATH mkdir -p $TEST_RESULTS - checkout - run: From 3e18023259d4c2add8ccd170f1ec73d1ccff0cc0 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:10:33 +0200 Subject: [PATCH 247/320] Switching to CircleCI --- .circleci/config.yml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 49f25c39..eeff2e47 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,16 +10,10 @@ jobs: - image: cimg/go:<> environment: TEST_RESULTS: /tmp/test-results - PROJECT_NAME: gods GOPATH: ${HOME}/go - PROJECT_PATH: ${GOPATH}/src/github.com/${CIRCLE_PROJECT_USERNAME}/${PROJECT_NAME} - working_directory: ${PROJECT_PATH} + PROJECT_PATH: ${GOPATH}/src/github.com/emirpasic/gods + working_directory: ~/src/github.com/emirpasic/gods steps: - - run: - name: Create directories - command: | - mkdir -p $PROJECT_PATH - mkdir -p $TEST_RESULTS - checkout - run: name: Print Go version (go version) @@ -29,6 +23,7 @@ jobs: - run: name: Run tests command: | + mkdir -p $TEST_RESULTS go test -v ./... | go tool test2json > $TEST_RESULTS/test2json-output.json gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml - run: @@ -54,7 +49,7 @@ jobs: name: Calculate cyclomatic complexity (gocyclo) command: | go install github.com/fzipp/gocyclo/cmd/gocyclo@latest - gocyclo -avg -over 15 ../${PROJECT_NAME} + gocyclo -avg -over 15 ../gods - run: name: Check for unchecked errors (errcheck) command: | From 27e9ad878708a21be032d9a6f742d91e7fadbf3d Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:11:35 +0200 Subject: [PATCH 248/320] Switching to CircleCI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index eeff2e47..3e152676 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,7 +10,7 @@ jobs: - image: cimg/go:<> environment: TEST_RESULTS: /tmp/test-results - GOPATH: ${HOME}/go + GOPATH: ~/go PROJECT_PATH: ${GOPATH}/src/github.com/emirpasic/gods working_directory: ~/src/github.com/emirpasic/gods steps: From eee4c73dbdbeb5ff36f3762d9b22d0e5124314ce Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:13:20 +0200 Subject: [PATCH 249/320] Switching to CircleCI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3e152676..3f2d5288 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,7 +10,7 @@ jobs: - image: cimg/go:<> environment: TEST_RESULTS: /tmp/test-results - GOPATH: ~/go + GOPATH: $HOME/go PROJECT_PATH: ${GOPATH}/src/github.com/emirpasic/gods working_directory: ~/src/github.com/emirpasic/gods steps: From f8d4389b461f9a325615ca0474b2cbefebbdcefa Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:14:08 +0200 Subject: [PATCH 250/320] Switching to CircleCI --- .circleci/config.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3f2d5288..0cc769ae 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -11,8 +11,7 @@ jobs: environment: TEST_RESULTS: /tmp/test-results GOPATH: $HOME/go - PROJECT_PATH: ${GOPATH}/src/github.com/emirpasic/gods - working_directory: ~/src/github.com/emirpasic/gods + working_directory: ~/go/src/github.com/emirpasic/gods steps: - checkout - run: From 7478be5d1755b57437af0299220e519f7c8f375d Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:15:05 +0200 Subject: [PATCH 251/320] Switching to CircleCI --- .circleci/config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0cc769ae..6744de94 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -13,12 +13,13 @@ jobs: GOPATH: $HOME/go working_directory: ~/go/src/github.com/emirpasic/gods steps: - - checkout - run: name: Print Go version (go version) command: | go version pwd + echo $HOME + - checkout - run: name: Run tests command: | From 8c1095677a26066f366946b2ffdce543317358f8 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:16:47 +0200 Subject: [PATCH 252/320] Switching to CircleCI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6744de94..b325d7df 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -16,9 +16,9 @@ jobs: - run: name: Print Go version (go version) command: | - go version pwd echo $HOME + go version - checkout - run: name: Run tests From c91beb083159e7cd81f4187f14b210c8969e204d Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:18:23 +0200 Subject: [PATCH 253/320] Switching to CircleCI --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b325d7df..f446e9b9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,8 +10,8 @@ jobs: - image: cimg/go:<> environment: TEST_RESULTS: /tmp/test-results - GOPATH: $HOME/go - working_directory: ~/go/src/github.com/emirpasic/gods + GOPATH: /home/circleci/go + working_directory: /home/circleci/go/src/github.com/emirpasic/gods steps: - run: name: Print Go version (go version) From 68d62ab739d492d6b2aefbce2c3e782e98654784 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:31:07 +0200 Subject: [PATCH 254/320] Switching to CircleCI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f446e9b9..dca5efd3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,7 +35,7 @@ jobs: - run: name: Lint (golint) command: | - go install golang.org/x/lint/golint@latest + go install golang.org/x/lint/golint@latest || go get -u golang.org/x/lint/golint golint -set_exit_status ./... - run: name: Enforce formatted code (go fmt) From 23ff506555b6c89d51abfe8cccc9181b02192c76 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:36:40 +0200 Subject: [PATCH 255/320] Switching to CircleCI --- .circleci/config.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index dca5efd3..89b0f950 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -11,6 +11,7 @@ jobs: environment: TEST_RESULTS: /tmp/test-results GOPATH: /home/circleci/go + GO111MODULE: on working_directory: /home/circleci/go/src/github.com/emirpasic/gods steps: - run: @@ -35,7 +36,7 @@ jobs: - run: name: Lint (golint) command: | - go install golang.org/x/lint/golint@latest || go get -u golang.org/x/lint/golint + go install golang.org/x/lint/golint@latest golint -set_exit_status ./... - run: name: Enforce formatted code (go fmt) @@ -67,4 +68,4 @@ workflows: - test: matrix: parameters: - version: ["1.18", "1.17", "1.10"] \ No newline at end of file + version: ["1.18", "1.17", "1.10", "1.11"] \ No newline at end of file From dabe253199db94005d6f04ccd87ed0c7e0d3c638 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:40:14 +0200 Subject: [PATCH 256/320] Switching to CircleCI --- .circleci/config.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 89b0f950..de5e28b9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -11,14 +11,12 @@ jobs: environment: TEST_RESULTS: /tmp/test-results GOPATH: /home/circleci/go - GO111MODULE: on + GO111MODULE: "on" working_directory: /home/circleci/go/src/github.com/emirpasic/gods steps: - run: name: Print Go version (go version) command: | - pwd - echo $HOME go version - checkout - run: From 6b76fcbc81d7621790cdc6560f7aac5e58669271 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:45:43 +0200 Subject: [PATCH 257/320] Switching to CircleCI --- .circleci/config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index de5e28b9..435e49dd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -23,11 +23,13 @@ jobs: name: Run tests command: | mkdir -p $TEST_RESULTS + go install gotest.tools/gotestsum@latest go test -v ./... | go tool test2json > $TEST_RESULTS/test2json-output.json gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml - run: name: Calculate test coverage command: | + mkdir -p $TEST_RESULTS go test -coverprofile=c.out ./... > /dev/null go tool cover -html=c.out -o coverage.html mv coverage.html $TEST_RESULTS From 371a50d22c629c4041fe20a53c82660bd1f787ab Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:48:06 +0200 Subject: [PATCH 258/320] Switching to CircleCI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 435e49dd..6a5cc8de 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -23,7 +23,7 @@ jobs: name: Run tests command: | mkdir -p $TEST_RESULTS - go install gotest.tools/gotestsum@latest + go install gotest.tools/gotestsum@latest || gotest.tools/gotestsum go test -v ./... | go tool test2json > $TEST_RESULTS/test2json-output.json gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml - run: From 31fccfff72017a2d10b929900309fbbbad0268ac Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:51:53 +0200 Subject: [PATCH 259/320] Switching to CircleCI --- .circleci/config.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6a5cc8de..244e84bf 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -23,7 +23,7 @@ jobs: name: Run tests command: | mkdir -p $TEST_RESULTS - go install gotest.tools/gotestsum@latest || gotest.tools/gotestsum + go install gotest.tools/gotestsum@latest || go get gotest.tools/gotestsum go test -v ./... | go tool test2json > $TEST_RESULTS/test2json-output.json gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml - run: @@ -36,7 +36,7 @@ jobs: - run: name: Lint (golint) command: | - go install golang.org/x/lint/golint@latest + go install golang.org/x/lint/golint@latest || go get golang.org/x/lint/golint golint -set_exit_status ./... - run: name: Enforce formatted code (go fmt) @@ -49,12 +49,12 @@ jobs: - run: name: Calculate cyclomatic complexity (gocyclo) command: | - go install github.com/fzipp/gocyclo/cmd/gocyclo@latest + go install github.com/fzipp/gocyclo/cmd/gocyclo@latest || go get github.com/fzipp/gocyclo gocyclo -avg -over 15 ../gods - run: name: Check for unchecked errors (errcheck) command: | - go install github.com/kisielk/errcheck@latest + go install github.com/kisielk/errcheck@latest || go get github.com/kisielk/errcheck errcheck ./... - store_artifacts: path: /tmp/test-results From 10343eeeaf7c35437ed50d64020575531e2a8464 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:54:12 +0200 Subject: [PATCH 260/320] Switching to CircleCI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 244e84bf..6776746f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -23,7 +23,7 @@ jobs: name: Run tests command: | mkdir -p $TEST_RESULTS - go install gotest.tools/gotestsum@latest || go get gotest.tools/gotestsum + go install gotest.tools/gotestsum@latest || go get github.com/gotestyourself/gotestsum/gotestsum go test -v ./... | go tool test2json > $TEST_RESULTS/test2json-output.json gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml - run: From f871cf9f85e3a8b2986cc084f691b02424ecefd9 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:55:23 +0200 Subject: [PATCH 261/320] Switching to CircleCI --- .circleci/config.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6776746f..61df7c9f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -11,7 +11,6 @@ jobs: environment: TEST_RESULTS: /tmp/test-results GOPATH: /home/circleci/go - GO111MODULE: "on" working_directory: /home/circleci/go/src/github.com/emirpasic/gods steps: - run: From 915a2bc13e400744477cfcf7a8d510ca919115fe Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:56:08 +0200 Subject: [PATCH 262/320] Switching to CircleCI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 61df7c9f..a25ceccf 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,7 +22,7 @@ jobs: name: Run tests command: | mkdir -p $TEST_RESULTS - go install gotest.tools/gotestsum@latest || go get github.com/gotestyourself/gotestsum/gotestsum + go install gotest.tools/gotestsum@latest || go get gotest.tools/gotestsum go test -v ./... | go tool test2json > $TEST_RESULTS/test2json-output.json gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml - run: From f602a98ae47ead22be694fd7e4b9bed6e2faa381 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:58:34 +0200 Subject: [PATCH 263/320] Switching to CircleCI --- .circleci/config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a25ceccf..6b50a573 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,7 +22,8 @@ jobs: name: Run tests command: | mkdir -p $TEST_RESULTS - go install gotest.tools/gotestsum@latest || go get gotest.tools/gotestsum +# go install gotest.tools/gotestsum@latest || go get gotest.tools/gotestsum + go get gotest.tools/gotestsum go test -v ./... | go tool test2json > $TEST_RESULTS/test2json-output.json gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml - run: From 3a92202c302c60018367ca45e069b27468e9ca38 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 20:59:06 +0200 Subject: [PATCH 264/320] Switching to CircleCI --- .circleci/config.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6b50a573..c54e36f5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,7 +22,6 @@ jobs: name: Run tests command: | mkdir -p $TEST_RESULTS -# go install gotest.tools/gotestsum@latest || go get gotest.tools/gotestsum go get gotest.tools/gotestsum go test -v ./... | go tool test2json > $TEST_RESULTS/test2json-output.json gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml From 46fd454eed882be94b2c58c9ff704f4bb71cf7d2 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 21:00:06 +0200 Subject: [PATCH 265/320] Switching to CircleCI --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index c54e36f5..4e4b45c4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -11,6 +11,7 @@ jobs: environment: TEST_RESULTS: /tmp/test-results GOPATH: /home/circleci/go + GO111MODULE: "on" working_directory: /home/circleci/go/src/github.com/emirpasic/gods steps: - run: From 2d64eb43be9b981098d779a3531572a1883c0227 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 21:01:43 +0200 Subject: [PATCH 266/320] Switching to CircleCI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4e4b45c4..2283d899 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -68,4 +68,4 @@ workflows: - test: matrix: parameters: - version: ["1.18", "1.17", "1.10", "1.11"] \ No newline at end of file + version: ["1.18", "1.17", "1.12"] \ No newline at end of file From fc28a203fb77419c98db0f2d5bfd39363eefc2e8 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 21:03:49 +0200 Subject: [PATCH 267/320] Switching to CircleCI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2283d899..cea5d35a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -49,7 +49,7 @@ jobs: - run: name: Calculate cyclomatic complexity (gocyclo) command: | - go install github.com/fzipp/gocyclo/cmd/gocyclo@latest || go get github.com/fzipp/gocyclo + go install github.com/fzipp/gocyclo/cmd/gocyclo@latest || go get github.com/fzipp/gocyclo/cmd/gocyclo gocyclo -avg -over 15 ../gods - run: name: Check for unchecked errors (errcheck) From 76d2e78a21cc8099908a1b1dc4cf6a28ff4091ed Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 21:05:33 +0200 Subject: [PATCH 268/320] Switching to CircleCI --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index cea5d35a..2f0c3b33 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -36,7 +36,7 @@ jobs: - run: name: Lint (golint) command: | - go install golang.org/x/lint/golint@latest || go get golang.org/x/lint/golint + go get golang.org/x/lint/golint golint -set_exit_status ./... - run: name: Enforce formatted code (go fmt) @@ -49,12 +49,12 @@ jobs: - run: name: Calculate cyclomatic complexity (gocyclo) command: | - go install github.com/fzipp/gocyclo/cmd/gocyclo@latest || go get github.com/fzipp/gocyclo/cmd/gocyclo + go get github.com/fzipp/gocyclo/cmd/gocyclo gocyclo -avg -over 15 ../gods - run: name: Check for unchecked errors (errcheck) command: | - go install github.com/kisielk/errcheck@latest || go get github.com/kisielk/errcheck + go get github.com/kisielk/errcheck errcheck ./... - store_artifacts: path: /tmp/test-results From c76ef961a2aaff06fde3131791195bb5f450ad55 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 21:09:11 +0200 Subject: [PATCH 269/320] Switching to CircleCI --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2f0c3b33..c78b35de 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,6 +12,7 @@ jobs: TEST_RESULTS: /tmp/test-results GOPATH: /home/circleci/go GO111MODULE: "on" + PATH: $PATH:/home/circleci/go/bin working_directory: /home/circleci/go/src/github.com/emirpasic/gods steps: - run: From aafef2ee7bcb95c190223d7b2cbdad35309a3b54 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 21:19:14 +0200 Subject: [PATCH 270/320] Switching to CircleCI --- .circleci/config.yml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c78b35de..5ceddd8b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,10 +10,7 @@ jobs: - image: cimg/go:<> environment: TEST_RESULTS: /tmp/test-results - GOPATH: /home/circleci/go - GO111MODULE: "on" - PATH: $PATH:/home/circleci/go/bin - working_directory: /home/circleci/go/src/github.com/emirpasic/gods + working_directory: ~/gods steps: - run: name: Print Go version (go version) @@ -24,7 +21,7 @@ jobs: name: Run tests command: | mkdir -p $TEST_RESULTS - go get gotest.tools/gotestsum + go install gotest.tools/gotestsum@latest go test -v ./... | go tool test2json > $TEST_RESULTS/test2json-output.json gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml - run: @@ -37,7 +34,7 @@ jobs: - run: name: Lint (golint) command: | - go get golang.org/x/lint/golint + go install golang.org/x/lint/golint@latest golint -set_exit_status ./... - run: name: Enforce formatted code (go fmt) @@ -50,12 +47,12 @@ jobs: - run: name: Calculate cyclomatic complexity (gocyclo) command: | - go get github.com/fzipp/gocyclo/cmd/gocyclo + go install github.com/fzipp/gocyclo/cmd/gocyclo@latest gocyclo -avg -over 15 ../gods - run: name: Check for unchecked errors (errcheck) command: | - go get github.com/kisielk/errcheck + go install github.com/kisielk/errcheck@latest errcheck ./... - store_artifacts: path: /tmp/test-results @@ -69,4 +66,4 @@ workflows: - test: matrix: parameters: - version: ["1.18", "1.17", "1.12"] \ No newline at end of file + version: ["1.18", "1.17", "1.10", "1.12"] \ No newline at end of file From 340b511e02df272d17c3a62a48f5dabe95b43dd5 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 21:21:24 +0200 Subject: [PATCH 271/320] Switching to CircleCI --- .circleci/config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5ceddd8b..d4b80047 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -66,4 +66,5 @@ workflows: - test: matrix: parameters: - version: ["1.18", "1.17", "1.10", "1.12"] \ No newline at end of file + # To test with and without generics (versions prior to 1.18) + version: ["1.18", "1.17"] \ No newline at end of file From 4209f34363ff02a557023314de01debe9dced9c1 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 6 Apr 2022 22:13:07 +0200 Subject: [PATCH 272/320] Update license badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 035fc341..c76b8f3a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![GoDoc](https://godoc.org/github.com/emirpasic/gods?status.svg)](https://godoc.org/github.com/emirpasic/gods) [![Build Status](https://circleci.com/gh/emirpasic/gods/tree/master.svg?style=shield)](https://circleci.com/gh/emirpasic/gods?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/emirpasic/gods)](https://goreportcard.com/report/github.com/emirpasic/gods) [![PyPI](https://img.shields.io/pypi/l/Django.svg?maxAge=2592000)](https://github.com/emirpasic/gods/blob/master/LICENSE) +[![GoDoc](https://godoc.org/github.com/emirpasic/gods?status.svg)](https://godoc.org/github.com/emirpasic/gods) [![Build Status](https://circleci.com/gh/emirpasic/gods/tree/master.svg?style=shield)](https://circleci.com/gh/emirpasic/gods?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/emirpasic/gods)](https://goreportcard.com/report/github.com/emirpasic/gods) [![PyPI](https://img.shields.io/badge/License-BSD_2--Clause-green.svg)](https://github.com/emirpasic/gods/blob/master/LICENSE) # GoDS (Go Data Structures) From 08ae493e8a735a88bbef2b02ed737845c20f00ea Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 12 Apr 2022 01:20:56 +0200 Subject: [PATCH 273/320] Implement NextTo and PrevTo for all iterators and containers (index or key, forward-only or reversable) --- README.md | 76 +++++++++++- containers/iterator.go | 24 ++++ .../iteratorwithindex/iteratorwithindex.go | 29 +++++ examples/iteratorwithkey/iteratorwithkey.go | 36 +++++- lists/arraylist/arraylist_test.go | 101 ++++++++++++++++ lists/arraylist/iterator.go | 28 +++++ .../doublylinkedlist/doublylinkedlist_test.go | 101 ++++++++++++++++ lists/doublylinkedlist/iterator.go | 28 +++++ lists/singlylinkedlist/iterator.go | 14 +++ .../singlylinkedlist/singlylinkedlist_test.go | 50 ++++++++ maps/linkedhashmap/iterator.go | 28 +++++ maps/linkedhashmap/linkedhashmap_test.go | 109 ++++++++++++++++- maps/treebidimap/iterator.go | 28 +++++ maps/treebidimap/treebidimap_test.go | 109 ++++++++++++++++- maps/treemap/iterator.go | 28 +++++ maps/treemap/treemap_test.go | 109 ++++++++++++++++- sets/linkedhashset/iterator.go | 28 +++++ sets/linkedhashset/linkedhashset_test.go | 101 ++++++++++++++++ sets/treeset/iterator.go | 28 +++++ sets/treeset/treeset_test.go | 101 ++++++++++++++++ stacks/arraystack/arraystack_test.go | 107 +++++++++++++++++ stacks/arraystack/iterator.go | 28 +++++ stacks/linkedliststack/iterator.go | 14 +++ .../linkedliststack/linkedliststack_test.go | 53 +++++++++ trees/avltree/avltree_test.go | 107 +++++++++++++++++ trees/avltree/iterator.go | 28 +++++ trees/binaryheap/binaryheap_test.go | 111 +++++++++++++++++- trees/binaryheap/iterator.go | 28 +++++ trees/btree/btree_test.go | 107 +++++++++++++++++ trees/btree/iterator.go | 28 +++++ trees/redblacktree/iterator.go | 28 +++++ trees/redblacktree/redblacktree_test.go | 107 +++++++++++++++++ 32 files changed, 1889 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index c76b8f3a..fa67f214 100644 --- a/README.md +++ b/README.md @@ -983,6 +983,22 @@ for it.Begin(); it.Next(); { } ``` +Seeking to a specific element: + +```go +// Seek function, i.e. find element starting with "b" +seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") +} + +// Seek to the condition and continue traversal from that point (forward). +// assumes it.Begin() was called. +for found := it.NextTo(seek); found; found = it.Next() { + index, value := it.Index(), it.Value() + ... +} +``` + #### IteratorWithKey An [iterator](#iterator) whose elements are referenced by a key. @@ -1010,6 +1026,22 @@ for it.Begin(); it.Next(); { } ``` +Seeking to a specific element from the current iterator position: + +```go +// Seek function, i.e. find element starting with "b" +seek := func(key interface{}, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") +} + +// Seek to the condition and continue traversal from that point (forward). +// assumes it.Begin() was called. +for found := it.NextTo(seek); found; found = it.Next() { + key, value := it.Key(), it.Value() + ... +} +``` + #### ReverseIteratorWithIndex An [iterator](#iterator) whose elements are referenced by an index. Provides all functions as [IteratorWithIndex](#iteratorwithindex), but can also be used for reverse iteration. @@ -1031,6 +1063,22 @@ if it.Last() { } ``` +Seeking to a specific element: + +```go +// Seek function, i.e. find element starting with "b" +seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") +} + +// Seek to the condition and continue traversal from that point (in reverse). +// assumes it.End() was called. +for found := it.PrevTo(seek); found; found = it.Prev() { + index, value := it.Index(), it.Value() + ... +} +``` + #### ReverseIteratorWithKey An [iterator](#iterator) whose elements are referenced by a key. Provides all functions as [IteratorWithKey](#iteratorwithkey), but can also be used for reverse iteration. @@ -1052,6 +1100,20 @@ if it.Last() { } ``` +```go +// Seek function, i.e. find element starting with "b" +seek := func(key interface{}, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") +} + +// Seek to the condition and continue traversal from that point (in reverse). +// assumes it.End() was called. +for found := it.PrevTo(seek); found; found = it.Prev() { + key, value := it.Key(), it.Value() + ... +} +``` + ### Enumerable Enumerable functions for ordered containers that implement [EnumerableWithIndex](#enumerablewithindex) or [EnumerableWithKey](#enumerablewithkey) interfaces. @@ -1489,13 +1551,19 @@ Coding style: ```shell # Install tooling and set path: -go get github.com/golang/lint/golint -go get github.com/fzipp/gocyclo -go get github.com/kisielk/errcheck +go install gotest.tools/gotestsum@latest +go install golang.org/x/lint/golint@latest +go install github.com/kisielk/errcheck@latest export PATH=$PATH:$GOPATH/bin # Fix errors and warnings: -go fmt ./... && gofmt -s -w . && go vet ./... && go get ./... && go test ./... && golint ./... && gocyclo -avg -over 15 . && errcheck ./... +go fmt ./... && +go test -v ./... && +golint -set_exit_status ./... && +! go fmt ./... 2>&1 | read && +go vet -v ./... && +gocyclo -avg -over 15 ../gods && +errcheck ./... ``` ### License diff --git a/containers/iterator.go b/containers/iterator.go index f1a52a36..73994ec8 100644 --- a/containers/iterator.go +++ b/containers/iterator.go @@ -28,6 +28,12 @@ type IteratorWithIndex interface { // If First() returns true, then first element's index and value can be retrieved by Index() and Value(). // Modifies the state of the iterator. First() bool + + // NextTo moves the iterator to the next element from current position that satisfies the condition given by the + // 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 } // IteratorWithKey is a stateful iterator for ordered containers whose elements are key value pairs. @@ -54,6 +60,12 @@ type IteratorWithKey interface { // If First() returns true, then first element's key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. First() bool + + // NextTo moves the iterator to the next element from current position that satisfies the condition given by the + // 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 } // ReverseIteratorWithIndex is stateful iterator for ordered containers whose values can be fetched by an index. @@ -80,6 +92,12 @@ type ReverseIteratorWithIndex interface { // Modifies the state of the iterator. Last() bool + // PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the + // 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 + IteratorWithIndex } @@ -105,5 +123,11 @@ type ReverseIteratorWithKey interface { // Modifies the state of the iterator. Last() bool + // PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the + // 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 + IteratorWithKey } diff --git a/examples/iteratorwithindex/iteratorwithindex.go b/examples/iteratorwithindex/iteratorwithindex.go index d15c439f..4cbc87e0 100644 --- a/examples/iteratorwithindex/iteratorwithindex.go +++ b/examples/iteratorwithindex/iteratorwithindex.go @@ -7,6 +7,7 @@ package main import ( "fmt" "github.com/emirpasic/gods/sets/treeset" + "strings" ) // IteratorWithIndexExample to demonstrate basic usage of IteratorWithIndex @@ -48,4 +49,32 @@ func main() { fmt.Print("\nLast index: ", it.Index()) // Last index: 3 fmt.Print("\nLast value: ", it.Value()) // Last value: c } + + // Seek element starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + it.Begin() + for found := it.NextTo(seek); found; found = it.Next() { + fmt.Print("\nNextTo index: ", it.Index()) + fmt.Print("\nNextTo value: ", it.Value()) + } /* + NextTo index: 1 + NextTo value: "b" + NextTo index: 2 + NextTo value: "c" + */ + + it.End() + for found := it.PrevTo(seek); found; found = it.Prev() { + fmt.Print("\nNextTo index: ", it.Index()) + fmt.Print("\nNextTo value: ", it.Value()) + } /* + NextTo index: 1 + NextTo value: "b" + NextTo index: 0 + NextTo value: "a" + */ + } diff --git a/examples/iteratorwithkey/iteratorwithkey.go b/examples/iteratorwithkey/iteratorwithkey.go index 4efeb7e1..521e43b2 100644 --- a/examples/iteratorwithkey/iteratorwithkey.go +++ b/examples/iteratorwithkey/iteratorwithkey.go @@ -7,14 +7,15 @@ package main import ( "fmt" "github.com/emirpasic/gods/maps/treemap" + "strings" ) // IteratorWithKeyExample to demonstrate basic usage of IteratorWithKey func main() { m := treemap.NewWithIntComparator() - m.Put(1, "a") - m.Put(2, "b") - m.Put(3, "a") + m.Put(0, "a") + m.Put(1, "b") + m.Put(2, "c") it := m.Iterator() fmt.Print("\nForward iteration\n") @@ -47,7 +48,34 @@ func main() { } if it.Last() { - fmt.Print("\nLast key: ", it.Key()) // Last key: 3 + fmt.Print("\nLast key: ", it.Key()) // Last key: 2 fmt.Print("\nLast value: ", it.Value()) // Last value: c } + + // Seek key-value pair whose value starts with "b" + seek := func(key interface{}, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + it.Begin() + for found := it.NextTo(seek); found; found = it.Next() { + fmt.Print("\nNextTo key: ", it.Key()) + fmt.Print("\nNextTo value: ", it.Value()) + } /* + NextTo key: 1 + NextTo value: "b" + NextTo key: 2 + NextTo value: "c" + */ + + it.End() + for found := it.PrevTo(seek); found; found = it.Prev() { + fmt.Print("\nNextTo key: ", it.Key()) + fmt.Print("\nNextTo value: ", it.Value()) + } /* + NextTo key: 1 + NextTo value: "b" + NextTo key: 0 + NextTo value: "a" + */ } diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 63d97d41..88d7689c 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -7,6 +7,7 @@ package arraylist import ( "fmt" "github.com/emirpasic/gods/utils" + "strings" "testing" ) @@ -500,6 +501,106 @@ func TestListIteratorLast(t *testing.T) { } } +func TestListIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + list := New() + it := list.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + } + + // NextTo (not found) + { + list := New() + list.Add("xx", "yy") + it := list.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + } + + // NextTo (found) + { + list := New() + list.Add("aa", "bb", "cc") + it := list.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + +func TestListIteratorPrevTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // PrevTo (empty) + { + list := New() + it := list.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + } + + // PrevTo (not found) + { + list := New() + list.Add("xx", "yy") + it := list.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + } + + // PrevTo (found) + { + list := New() + list.Add("aa", "bb", "cc") + it := list.Iterator() + it.End() + if !it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Prev() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "aa" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") + } + if it.Prev() { + t.Errorf("Should not go before first element") + } + } +} + func TestListSerialization(t *testing.T) { list := New() list.Add("a", "b", "c") diff --git a/lists/arraylist/iterator.go b/lists/arraylist/iterator.go index 38a93f3a..2fefbb65 100644 --- a/lists/arraylist/iterator.go +++ b/lists/arraylist/iterator.go @@ -81,3 +81,31 @@ func (iterator *Iterator) Last() bool { iterator.End() return iterator.Prev() } + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { + for iterator.Next() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} + +// PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool { + for iterator.Prev() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 596bd2e4..2e6b0c92 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -6,6 +6,7 @@ package doublylinkedlist import ( "fmt" + "strings" "testing" "github.com/emirpasic/gods/utils" @@ -506,6 +507,106 @@ func TestListIteratorLast(t *testing.T) { } } +func TestListIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + list := New() + it := list.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + } + + // NextTo (not found) + { + list := New() + list.Add("xx", "yy") + it := list.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + } + + // NextTo (found) + { + list := New() + list.Add("aa", "bb", "cc") + it := list.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + +func TestListIteratorPrevTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // PrevTo (empty) + { + list := New() + it := list.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + } + + // PrevTo (not found) + { + list := New() + list.Add("xx", "yy") + it := list.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + } + + // PrevTo (found) + { + list := New() + list.Add("aa", "bb", "cc") + it := list.Iterator() + it.End() + if !it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Prev() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "aa" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") + } + if it.Prev() { + t.Errorf("Should not go before first element") + } + } +} + func TestListSerialization(t *testing.T) { list := New() list.Add("a", "b", "c") diff --git a/lists/doublylinkedlist/iterator.go b/lists/doublylinkedlist/iterator.go index 040921d0..55fb0bcf 100644 --- a/lists/doublylinkedlist/iterator.go +++ b/lists/doublylinkedlist/iterator.go @@ -102,3 +102,31 @@ func (iterator *Iterator) Last() bool { iterator.End() return iterator.Prev() } + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { + for iterator.Next() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} + +// PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool { + for iterator.Prev() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} diff --git a/lists/singlylinkedlist/iterator.go b/lists/singlylinkedlist/iterator.go index 48605c26..5f25ff13 100644 --- a/lists/singlylinkedlist/iterator.go +++ b/lists/singlylinkedlist/iterator.go @@ -68,3 +68,17 @@ func (iterator *Iterator) First() bool { iterator.Begin() return iterator.Next() } + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { + for iterator.Next() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index 9b6fe59c..3023a8ee 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -6,6 +6,7 @@ package singlylinkedlist import ( "fmt" + "strings" "testing" "github.com/emirpasic/gods/utils" @@ -420,6 +421,55 @@ func TestListIteratorFirst(t *testing.T) { } } +func TestListIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + list := New() + it := list.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + } + + // NextTo (not found) + { + list := New() + list.Add("xx", "yy") + it := list.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + } + + // NextTo (found) + { + list := New() + list.Add("aa", "bb", "cc") + it := list.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + func TestListSerialization(t *testing.T) { list := New() list.Add("a", "b", "c") diff --git a/maps/linkedhashmap/iterator.go b/maps/linkedhashmap/iterator.go index d846efce..17f3bb36 100644 --- a/maps/linkedhashmap/iterator.go +++ b/maps/linkedhashmap/iterator.go @@ -79,3 +79,31 @@ func (iterator *Iterator) First() bool { func (iterator *Iterator) Last() bool { return iterator.iterator.Last() } + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) NextTo(f func(key interface{}, value interface{}) bool) bool { + for iterator.Next() { + key, value := iterator.Key(), iterator.Value() + if f(key, value) { + return true + } + } + return false +} + +// PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) PrevTo(f func(key interface{}, value interface{}) bool) bool { + for iterator.Prev() { + key, value := iterator.Key(), iterator.Value() + if f(key, value) { + return true + } + } + return false +} diff --git a/maps/linkedhashmap/linkedhashmap_test.go b/maps/linkedhashmap/linkedhashmap_test.go index 78437f14..912e7f31 100644 --- a/maps/linkedhashmap/linkedhashmap_test.go +++ b/maps/linkedhashmap/linkedhashmap_test.go @@ -6,6 +6,7 @@ package linkedhashmap import ( "fmt" + "strings" "testing" ) @@ -399,7 +400,7 @@ func TestMapIteratorBegin(t *testing.T) { } } -func TestMapTreeIteratorEnd(t *testing.T) { +func TestMapIteratorEnd(t *testing.T) { m := New() it := m.Iterator() m.Put(3, "c") @@ -440,6 +441,112 @@ func TestMapIteratorLast(t *testing.T) { } } +func TestMapIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index interface{}, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + m := New() + it := m.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty map") + } + } + + // NextTo (not found) + { + m := New() + m.Put(0, "xx") + m.Put(1, "yy") + it := m.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty map") + } + } + + // NextTo (found) + { + m := New() + m.Put(0, "aa") + m.Put(1, "bb") + m.Put(2, "cc") + it := m.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty map") + } + if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Key(), it.Value(); index != 2 || value.(string) != "cc" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + +func TestMapIteratorPrevTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index interface{}, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // PrevTo (empty) + { + m := New() + it := m.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty map") + } + } + + // PrevTo (not found) + { + m := New() + m.Put(0, "xx") + m.Put(1, "yy") + it := m.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty map") + } + } + + // PrevTo (found) + { + m := New() + m.Put(0, "aa") + m.Put(1, "bb") + m.Put(2, "cc") + it := m.Iterator() + it.End() + if !it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty map") + } + if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Prev() { + t.Errorf("Should go to first element") + } + if index, value := it.Key(), it.Value(); index != 0 || value.(string) != "aa" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") + } + if it.Prev() { + t.Errorf("Should not go before first element") + } + } +} + func TestMapSerialization(t *testing.T) { for i := 0; i < 10; i++ { original := New() diff --git a/maps/treebidimap/iterator.go b/maps/treebidimap/iterator.go index af9e27ae..72e99831 100644 --- a/maps/treebidimap/iterator.go +++ b/maps/treebidimap/iterator.go @@ -75,3 +75,31 @@ func (iterator *Iterator) First() bool { func (iterator *Iterator) Last() bool { return iterator.iterator.Last() } + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) NextTo(f func(key interface{}, value interface{}) bool) bool { + for iterator.Next() { + key, value := iterator.Key(), iterator.Value() + if f(key, value) { + return true + } + } + return false +} + +// PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) PrevTo(f func(key interface{}, value interface{}) bool) bool { + for iterator.Prev() { + key, value := iterator.Key(), iterator.Value() + if f(key, value) { + return true + } + } + return false +} diff --git a/maps/treebidimap/treebidimap_test.go b/maps/treebidimap/treebidimap_test.go index 686b5782..e1150fcc 100644 --- a/maps/treebidimap/treebidimap_test.go +++ b/maps/treebidimap/treebidimap_test.go @@ -7,6 +7,7 @@ package treebidimap import ( "fmt" "github.com/emirpasic/gods/utils" + "strings" "testing" ) @@ -432,7 +433,7 @@ func TestMapIteratorBegin(t *testing.T) { } } -func TestMapTreeIteratorEnd(t *testing.T) { +func TestMapIteratorEnd(t *testing.T) { m := NewWith(utils.IntComparator, utils.StringComparator) it := m.Iterator() m.Put(3, "c") @@ -473,6 +474,112 @@ func TestMapIteratorLast(t *testing.T) { } } +func TestMapIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index interface{}, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + m := NewWith(utils.IntComparator, utils.StringComparator) + it := m.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty map") + } + } + + // NextTo (not found) + { + m := NewWith(utils.IntComparator, utils.StringComparator) + m.Put(0, "xx") + m.Put(1, "yy") + it := m.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty map") + } + } + + // NextTo (found) + { + m := NewWith(utils.IntComparator, utils.StringComparator) + m.Put(0, "aa") + m.Put(1, "bb") + m.Put(2, "cc") + it := m.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty map") + } + if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Key(), it.Value(); index != 2 || value.(string) != "cc" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + +func TestMapIteratorPrevTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index interface{}, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // PrevTo (empty) + { + m := NewWith(utils.IntComparator, utils.StringComparator) + it := m.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty map") + } + } + + // PrevTo (not found) + { + m := NewWith(utils.IntComparator, utils.StringComparator) + m.Put(0, "xx") + m.Put(1, "yy") + it := m.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty map") + } + } + + // PrevTo (found) + { + m := NewWith(utils.IntComparator, utils.StringComparator) + m.Put(0, "aa") + m.Put(1, "bb") + m.Put(2, "cc") + it := m.Iterator() + it.End() + if !it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty map") + } + if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Prev() { + t.Errorf("Should go to first element") + } + if index, value := it.Key(), it.Value(); index != 0 || value.(string) != "aa" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") + } + if it.Prev() { + t.Errorf("Should not go before first element") + } + } +} + func TestMapSerialization(t *testing.T) { for i := 0; i < 10; i++ { original := NewWith(utils.StringComparator, utils.StringComparator) diff --git a/maps/treemap/iterator.go b/maps/treemap/iterator.go index 02b5c753..e7950a1c 100644 --- a/maps/treemap/iterator.go +++ b/maps/treemap/iterator.go @@ -75,3 +75,31 @@ func (iterator *Iterator) First() bool { func (iterator *Iterator) Last() bool { return iterator.iterator.Last() } + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) NextTo(f func(key interface{}, value interface{}) bool) bool { + for iterator.Next() { + key, value := iterator.Key(), iterator.Value() + if f(key, value) { + return true + } + } + return false +} + +// PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) PrevTo(f func(key interface{}, value interface{}) bool) bool { + for iterator.Prev() { + key, value := iterator.Key(), iterator.Value() + if f(key, value) { + return true + } + } + return false +} diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 0ee162ec..05155a21 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -6,6 +6,7 @@ package treemap import ( "fmt" + "strings" "testing" ) @@ -455,7 +456,7 @@ func TestMapIteratorBegin(t *testing.T) { } } -func TestMapTreeIteratorEnd(t *testing.T) { +func TestMapIteratorEnd(t *testing.T) { m := NewWithIntComparator() it := m.Iterator() m.Put(3, "c") @@ -496,6 +497,112 @@ func TestMapIteratorLast(t *testing.T) { } } +func TestMapIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index interface{}, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + m := NewWithIntComparator() + it := m.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty map") + } + } + + // NextTo (not found) + { + m := NewWithIntComparator() + m.Put(0, "xx") + m.Put(1, "yy") + it := m.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty map") + } + } + + // NextTo (found) + { + m := NewWithIntComparator() + m.Put(0, "aa") + m.Put(1, "bb") + m.Put(2, "cc") + it := m.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty map") + } + if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Key(), it.Value(); index != 2 || value.(string) != "cc" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + +func TestMapIteratorPrevTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index interface{}, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // PrevTo (empty) + { + m := NewWithIntComparator() + it := m.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty map") + } + } + + // PrevTo (not found) + { + m := NewWithIntComparator() + m.Put(0, "xx") + m.Put(1, "yy") + it := m.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty map") + } + } + + // PrevTo (found) + { + m := NewWithIntComparator() + m.Put(0, "aa") + m.Put(1, "bb") + m.Put(2, "cc") + it := m.Iterator() + it.End() + if !it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty map") + } + if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Prev() { + t.Errorf("Should go to first element") + } + if index, value := it.Key(), it.Value(); index != 0 || value.(string) != "aa" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") + } + if it.Prev() { + t.Errorf("Should not go before first element") + } + } +} + func TestMapSerialization(t *testing.T) { for i := 0; i < 10; i++ { original := NewWithStringComparator() diff --git a/sets/linkedhashset/iterator.go b/sets/linkedhashset/iterator.go index 3d190d91..5aa176c9 100644 --- a/sets/linkedhashset/iterator.go +++ b/sets/linkedhashset/iterator.go @@ -75,3 +75,31 @@ func (iterator *Iterator) First() bool { func (iterator *Iterator) Last() bool { return iterator.iterator.Last() } + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { + for iterator.Next() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} + +// PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool { + for iterator.Prev() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} diff --git a/sets/linkedhashset/linkedhashset_test.go b/sets/linkedhashset/linkedhashset_test.go index 10b6da2d..b77e5ecd 100644 --- a/sets/linkedhashset/linkedhashset_test.go +++ b/sets/linkedhashset/linkedhashset_test.go @@ -6,6 +6,7 @@ package linkedhashset import ( "fmt" + "strings" "testing" ) @@ -332,6 +333,106 @@ func TestSetIteratorLast(t *testing.T) { } } +func TestSetIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + set := New() + it := set.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty set") + } + } + + // NextTo (not found) + { + set := New() + set.Add("xx", "yy") + it := set.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty set") + } + } + + // NextTo (found) + { + set := New() + set.Add("aa", "bb", "cc") + it := set.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty set") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + +func TestSetIteratorPrevTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // PrevTo (empty) + { + set := New() + it := set.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty set") + } + } + + // PrevTo (not found) + { + set := New() + set.Add("xx", "yy") + it := set.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty set") + } + } + + // PrevTo (found) + { + set := New() + set.Add("aa", "bb", "cc") + it := set.Iterator() + it.End() + if !it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty set") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Prev() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "aa" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") + } + if it.Prev() { + t.Errorf("Should not go before first element") + } + } +} + func TestSetSerialization(t *testing.T) { set := New() set.Add("a", "b", "c") diff --git a/sets/treeset/iterator.go b/sets/treeset/iterator.go index 9dd62893..377d8b69 100644 --- a/sets/treeset/iterator.go +++ b/sets/treeset/iterator.go @@ -87,3 +87,31 @@ func (iterator *Iterator) Last() bool { iterator.End() return iterator.Prev() } + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { + for iterator.Next() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} + +// PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool { + for iterator.Prev() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index b3cfca9d..85718873 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -6,6 +6,7 @@ package treeset import ( "fmt" + "strings" "testing" ) @@ -341,6 +342,106 @@ func TestSetIteratorLast(t *testing.T) { } } +func TestSetIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + set := NewWithStringComparator() + it := set.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty set") + } + } + + // NextTo (not found) + { + set := NewWithStringComparator() + set.Add("xx", "yy") + it := set.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty set") + } + } + + // NextTo (found) + { + set := NewWithStringComparator() + set.Add("aa", "bb", "cc") + it := set.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty set") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + +func TestSetIteratorPrevTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // PrevTo (empty) + { + set := NewWithStringComparator() + it := set.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty set") + } + } + + // PrevTo (not found) + { + set := NewWithStringComparator() + set.Add("xx", "yy") + it := set.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty set") + } + } + + // PrevTo (found) + { + set := NewWithStringComparator() + set.Add("aa", "bb", "cc") + it := set.Iterator() + it.End() + if !it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty set") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Prev() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "aa" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") + } + if it.Prev() { + t.Errorf("Should not go before first element") + } + } +} + func TestSetSerialization(t *testing.T) { set := NewWithStringComparator() set.Add("a", "b", "c") diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index 62ba7fdb..0596217b 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -6,6 +6,7 @@ package arraystack import ( "fmt" + "strings" "testing" ) @@ -232,6 +233,112 @@ func TestStackIteratorLast(t *testing.T) { } } +func TestStackIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + stack := New() + it := stack.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty stack") + } + } + + // NextTo (not found) + { + stack := New() + stack.Push("xx") + stack.Push("yy") + it := stack.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty stack") + } + } + + // NextTo (found) + { + stack := New() + stack.Push("aa") + stack.Push("bb") + stack.Push("cc") + it := stack.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty stack") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "aa" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "aa") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + +func TestStackIteratorPrevTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // PrevTo (empty) + { + stack := New() + it := stack.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty stack") + } + } + + // PrevTo (not found) + { + stack := New() + stack.Push("xx") + stack.Push("yy") + it := stack.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty stack") + } + } + + // PrevTo (found) + { + stack := New() + stack.Push("aa") + stack.Push("bb") + stack.Push("cc") + it := stack.Iterator() + it.End() + if !it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty stack") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Prev() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "cc" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "cc") + } + if it.Prev() { + t.Errorf("Should not go before first element") + } + } +} + func TestStackSerialization(t *testing.T) { stack := New() stack.Push("a") diff --git a/stacks/arraystack/iterator.go b/stacks/arraystack/iterator.go index 48f9bf88..df592f0e 100644 --- a/stacks/arraystack/iterator.go +++ b/stacks/arraystack/iterator.go @@ -82,3 +82,31 @@ func (iterator *Iterator) Last() bool { iterator.End() return iterator.Prev() } + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { + for iterator.Next() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} + +// PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool { + for iterator.Prev() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} diff --git a/stacks/linkedliststack/iterator.go b/stacks/linkedliststack/iterator.go index 4c7eafaf..875f922b 100644 --- a/stacks/linkedliststack/iterator.go +++ b/stacks/linkedliststack/iterator.go @@ -58,3 +58,17 @@ func (iterator *Iterator) First() bool { iterator.Begin() return iterator.Next() } + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { + for iterator.Next() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} diff --git a/stacks/linkedliststack/linkedliststack_test.go b/stacks/linkedliststack/linkedliststack_test.go index f7b6f956..aeebc310 100644 --- a/stacks/linkedliststack/linkedliststack_test.go +++ b/stacks/linkedliststack/linkedliststack_test.go @@ -6,6 +6,7 @@ package linkedliststack import ( "fmt" + "strings" "testing" ) @@ -148,6 +149,58 @@ func TestStackIteratorFirst(t *testing.T) { } } +func TestStackIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + stack := New() + it := stack.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty stack") + } + } + + // NextTo (not found) + { + stack := New() + stack.Push("xx") + stack.Push("yy") + it := stack.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty stack") + } + } + + // NextTo (found) + { + stack := New() + stack.Push("aa") + stack.Push("bb") + stack.Push("cc") + it := stack.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty stack") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "aa" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "aa") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + func TestStackSerialization(t *testing.T) { stack := New() stack.Push("a") diff --git a/trees/avltree/avltree_test.go b/trees/avltree/avltree_test.go index 99c2adf6..16bf3017 100644 --- a/trees/avltree/avltree_test.go +++ b/trees/avltree/avltree_test.go @@ -5,6 +5,7 @@ package avltree import ( "fmt" + "strings" "testing" ) @@ -556,6 +557,112 @@ func TestAVLTreeIteratorLast(t *testing.T) { } } +func TestAVLTreeIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index interface{}, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + tree := NewWithIntComparator() + it := tree.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty tree") + } + } + + // NextTo (not found) + { + tree := NewWithIntComparator() + tree.Put(0, "xx") + tree.Put(1, "yy") + it := tree.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty tree") + } + } + + // NextTo (found) + { + tree := NewWithIntComparator() + tree.Put(2, "cc") + tree.Put(0, "aa") + tree.Put(1, "bb") + it := tree.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty tree") + } + if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Key(), it.Value(); index != 2 || value.(string) != "cc" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + +func TestAVLTreeIteratorPrevTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index interface{}, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // PrevTo (empty) + { + tree := NewWithIntComparator() + it := tree.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty tree") + } + } + + // PrevTo (not found) + { + tree := NewWithIntComparator() + tree.Put(0, "xx") + tree.Put(1, "yy") + it := tree.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty tree") + } + } + + // PrevTo (found) + { + tree := NewWithIntComparator() + tree.Put(2, "cc") + tree.Put(0, "aa") + tree.Put(1, "bb") + it := tree.Iterator() + it.End() + if !it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty tree") + } + if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Prev() { + t.Errorf("Should go to first element") + } + if index, value := it.Key(), it.Value(); index != 0 || value.(string) != "aa" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") + } + if it.Prev() { + t.Errorf("Should not go before first element") + } + } +} + func TestAVLTreeSerialization(t *testing.T) { tree := NewWithStringComparator() tree.Put("c", "3") diff --git a/trees/avltree/iterator.go b/trees/avltree/iterator.go index bf2ff149..d4a1585e 100644 --- a/trees/avltree/iterator.go +++ b/trees/avltree/iterator.go @@ -115,3 +115,31 @@ func (iterator *Iterator) Last() bool { iterator.End() return iterator.Prev() } + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) NextTo(f func(key interface{}, value interface{}) bool) bool { + for iterator.Next() { + key, value := iterator.Key(), iterator.Value() + if f(key, value) { + return true + } + } + return false +} + +// PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) PrevTo(f func(key interface{}, value interface{}) bool) bool { + for iterator.Prev() { + key, value := iterator.Key(), iterator.Value() + if f(key, value) { + return true + } + } + return false +} diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go index cf978137..7a3d0605 100644 --- a/trees/binaryheap/binaryheap_test.go +++ b/trees/binaryheap/binaryheap_test.go @@ -6,6 +6,7 @@ package binaryheap import ( "math/rand" + "strings" "testing" ) @@ -198,7 +199,7 @@ func TestBinaryHeapIteratorBegin(t *testing.T) { } } -func TestListIteratorEnd(t *testing.T) { +func TestBinaryHeapIteratorEnd(t *testing.T) { heap := NewWithIntComparator() it := heap.Iterator() @@ -225,7 +226,7 @@ func TestListIteratorEnd(t *testing.T) { } } -func TestStackIteratorFirst(t *testing.T) { +func TestBinaryHeapIteratorFirst(t *testing.T) { heap := NewWithIntComparator() it := heap.Iterator() if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { @@ -259,6 +260,112 @@ func TestBinaryHeapIteratorLast(t *testing.T) { } } +func TestBinaryHeapIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + tree := NewWithStringComparator() + it := tree.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + } + + // NextTo (not found) + { + tree := NewWithStringComparator() + tree.Push("xx") + tree.Push("yy") + it := tree.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + } + + // NextTo (found) + { + tree := NewWithStringComparator() + tree.Push("aa") + tree.Push("bb") + tree.Push("cc") + it := tree.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + +func TestBinaryHeapIteratorPrevTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // PrevTo (empty) + { + tree := NewWithStringComparator() + it := tree.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + } + + // PrevTo (not found) + { + tree := NewWithStringComparator() + tree.Push("xx") + tree.Push("yy") + it := tree.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + } + + // PrevTo (found) + { + tree := NewWithStringComparator() + tree.Push("aa") + tree.Push("bb") + tree.Push("cc") + it := tree.Iterator() + it.End() + if !it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Prev() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "aa" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") + } + if it.Prev() { + t.Errorf("Should not go before first element") + } + } +} + func TestBinaryHeapSerialization(t *testing.T) { heap := NewWithStringComparator() diff --git a/trees/binaryheap/iterator.go b/trees/binaryheap/iterator.go index beeb8d70..343fa52c 100644 --- a/trees/binaryheap/iterator.go +++ b/trees/binaryheap/iterator.go @@ -82,3 +82,31 @@ func (iterator *Iterator) Last() bool { iterator.End() return iterator.Prev() } + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { + for iterator.Next() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} + +// PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool { + for iterator.Prev() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index 4d69665b..f4edaf1f 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -6,6 +6,7 @@ package btree import ( "fmt" + "strings" "testing" ) @@ -1074,6 +1075,112 @@ func assertValidTreeNode(t *testing.T, node *Node, expectedEntries int, expected } } +func TestBTreeIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index interface{}, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + tree := NewWithIntComparator(3) + it := tree.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty tree") + } + } + + // NextTo (not found) + { + tree := NewWithIntComparator(3) + tree.Put(0, "xx") + tree.Put(1, "yy") + it := tree.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty tree") + } + } + + // NextTo (found) + { + tree := NewWithIntComparator(3) + tree.Put(2, "cc") + tree.Put(0, "aa") + tree.Put(1, "bb") + it := tree.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty tree") + } + if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Key(), it.Value(); index != 2 || value.(string) != "cc" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + +func TestBTreeIteratorPrevTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index interface{}, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // PrevTo (empty) + { + tree := NewWithIntComparator(3) + it := tree.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty tree") + } + } + + // PrevTo (not found) + { + tree := NewWithIntComparator(3) + tree.Put(0, "xx") + tree.Put(1, "yy") + it := tree.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty tree") + } + } + + // PrevTo (found) + { + tree := NewWithIntComparator(3) + tree.Put(2, "cc") + tree.Put(0, "aa") + tree.Put(1, "bb") + it := tree.Iterator() + it.End() + if !it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty tree") + } + if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Prev() { + t.Errorf("Should go to first element") + } + if index, value := it.Key(), it.Value(); index != 0 || value.(string) != "aa" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") + } + if it.Prev() { + t.Errorf("Should not go before first element") + } + } +} + func TestBTreeSerialization(t *testing.T) { tree := NewWithStringComparator(3) tree.Put("c", "3") diff --git a/trees/btree/iterator.go b/trees/btree/iterator.go index 840db687..ed0cb154 100644 --- a/trees/btree/iterator.go +++ b/trees/btree/iterator.go @@ -191,3 +191,31 @@ func (iterator *Iterator) Last() bool { iterator.End() return iterator.Prev() } + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) NextTo(f func(key interface{}, value interface{}) bool) bool { + for iterator.Next() { + key, value := iterator.Key(), iterator.Value() + if f(key, value) { + return true + } + } + return false +} + +// PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) PrevTo(f func(key interface{}, value interface{}) bool) bool { + for iterator.Prev() { + key, value := iterator.Key(), iterator.Value() + if f(key, value) { + return true + } + } + return false +} diff --git a/trees/redblacktree/iterator.go b/trees/redblacktree/iterator.go index 9cde5e43..881b67dd 100644 --- a/trees/redblacktree/iterator.go +++ b/trees/redblacktree/iterator.go @@ -159,3 +159,31 @@ func (iterator *Iterator) Last() bool { iterator.End() return iterator.Prev() } + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) NextTo(f func(key interface{}, value interface{}) bool) bool { + for iterator.Next() { + key, value := iterator.Key(), iterator.Value() + if f(key, value) { + return true + } + } + return false +} + +// PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) PrevTo(f func(key interface{}, value interface{}) bool) bool { + for iterator.Prev() { + key, value := iterator.Key(), iterator.Value() + if f(key, value) { + return true + } + } + return false +} diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 74c3d8a0..730a1f3a 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -6,6 +6,7 @@ package redblacktree import ( "fmt" + "strings" "testing" ) @@ -557,6 +558,112 @@ func TestRedBlackTreeIteratorLast(t *testing.T) { } } +func TestRedBlackTreeIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index interface{}, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + tree := NewWithIntComparator() + it := tree.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty tree") + } + } + + // NextTo (not found) + { + tree := NewWithIntComparator() + tree.Put(0, "xx") + tree.Put(1, "yy") + it := tree.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty tree") + } + } + + // NextTo (found) + { + tree := NewWithIntComparator() + tree.Put(2, "cc") + tree.Put(0, "aa") + tree.Put(1, "bb") + it := tree.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty tree") + } + if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Key(), it.Value(); index != 2 || value.(string) != "cc" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + +func TestRedBlackTreeIteratorPrevTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index interface{}, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // PrevTo (empty) + { + tree := NewWithIntComparator() + it := tree.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty tree") + } + } + + // PrevTo (not found) + { + tree := NewWithIntComparator() + tree.Put(0, "xx") + tree.Put(1, "yy") + it := tree.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty tree") + } + } + + // PrevTo (found) + { + tree := NewWithIntComparator() + tree.Put(2, "cc") + tree.Put(0, "aa") + tree.Put(1, "bb") + it := tree.Iterator() + it.End() + if !it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty tree") + } + if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Prev() { + t.Errorf("Should go to first element") + } + if index, value := it.Key(), it.Value(); index != 0 || value.(string) != "aa" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") + } + if it.Prev() { + t.Errorf("Should not go before first element") + } + } +} + func TestRedBlackTreeSerialization(t *testing.T) { tree := NewWithStringComparator() tree.Put("c", "3") From 69d218401163c13c474abc1d08b61fdfae63621b Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 12 Apr 2022 03:33:59 +0200 Subject: [PATCH 274/320] Implement GetNode() for BTree AVLTree and RedBlackTree and Node() function for their iterators --- trees/avltree/avltree.go | 30 ++++++++++++++-- trees/avltree/avltree_test.go | 44 +++++++++++++++++++++++ trees/avltree/iterator.go | 6 ++++ trees/btree/btree.go | 20 +++++++++++ trees/btree/btree_test.go | 46 +++++++++++++++++++++++++ trees/btree/iterator.go | 6 ++++ trees/redblacktree/iterator.go | 6 ++++ trees/redblacktree/redblacktree.go | 22 ++++++++++++ trees/redblacktree/redblacktree_test.go | 46 +++++++++++++++++++++++++ 9 files changed, 224 insertions(+), 2 deletions(-) diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index 1efdae4c..fd1a4053 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -60,19 +60,29 @@ func (t *Tree) Put(key interface{}, value interface{}) { // Second return parameter is true if key was found, otherwise false. // Key should adhere to the comparator's type assertion, otherwise method panics. func (t *Tree) Get(key interface{}) (value interface{}, found bool) { + n := t.GetNode(key) + if n != nil { + return n.Value, true + } + return nil, false +} + +// GetNode searches the node in the tree by key and returns its node or nil if key is not found in tree. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (t *Tree) GetNode(key interface{}) *Node { n := t.Root for n != nil { cmp := t.Comparator(key, n.Key) switch { case cmp == 0: - return n.Value, true + return n case cmp < 0: n = n.Children[0] case cmp > 0: n = n.Children[1] } } - return nil, false + return n } // Remove remove the node from the tree by key. @@ -91,6 +101,22 @@ func (t *Tree) Size() int { return t.size } +// Size returns the number of elements stored in the subtree. +// Computed dynamically on each call, i.e. the subtree is traversed to count the number of the nodes. +func (n *Node) Size() int { + if n == nil { + return 0 + } + size := 1 + if n.Children[0] != nil { + size += n.Children[0].Size() + } + if n.Children[1] != nil { + size += n.Children[1].Size() + } + return size +} + // Keys returns all keys in-order func (t *Tree) Keys() []interface{} { keys := make([]interface{}, t.size) diff --git a/trees/avltree/avltree_test.go b/trees/avltree/avltree_test.go index 16bf3017..9cc300a4 100644 --- a/trees/avltree/avltree_test.go +++ b/trees/avltree/avltree_test.go @@ -9,6 +9,50 @@ import ( "testing" ) +func TestAVLTreeGet(t *testing.T) { + tree := NewWithIntComparator() + + if actualValue := tree.Size(); actualValue != 0 { + t.Errorf("Got %v expected %v", actualValue, 0) + } + + if actualValue := tree.GetNode(2).Size(); actualValue != 0 { + t.Errorf("Got %v expected %v", actualValue, 0) + } + + tree.Put(1, "x") // 1->x + tree.Put(2, "b") // 1->x, 2->b (in order) + tree.Put(1, "a") // 1->a, 2->b (in order, replacement) + tree.Put(3, "c") // 1->a, 2->b, 3->c (in order) + tree.Put(4, "d") // 1->a, 2->b, 3->c, 4->d (in order) + tree.Put(5, "e") // 1->a, 2->b, 3->c, 4->d, 5->e (in order) + tree.Put(6, "f") // 1->a, 2->b, 3->c, 4->d, 5->e, 6->f (in order) + // + // AVLTree + // │ ┌── 6 + // │ ┌── 5 + // └── 4 + // │ ┌── 3 + // └── 2 + // └── 1 + + if actualValue := tree.Size(); actualValue != 6 { + t.Errorf("Got %v expected %v", actualValue, 6) + } + + if actualValue := tree.GetNode(2).Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + + if actualValue := tree.GetNode(4).Size(); actualValue != 6 { + t.Errorf("Got %v expected %v", actualValue, 6) + } + + if actualValue := tree.GetNode(7).Size(); actualValue != 0 { + t.Errorf("Got %v expected %v", actualValue, 0) + } +} + func TestAVLTreePut(t *testing.T) { tree := NewWithIntComparator() tree.Put(5, "e") diff --git a/trees/avltree/iterator.go b/trees/avltree/iterator.go index d4a1585e..c4d69f4d 100644 --- a/trees/avltree/iterator.go +++ b/trees/avltree/iterator.go @@ -86,6 +86,12 @@ func (iterator *Iterator) Key() interface{} { return iterator.node.Key } +// Node returns the current element's node. +// Does not modify the state of the iterator. +func (iterator *Iterator) Node() *Node { + return iterator.node +} + // Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. func (iterator *Iterator) Begin() { diff --git a/trees/btree/btree.go b/trees/btree/btree.go index 5f866997..523358ad 100644 --- a/trees/btree/btree.go +++ b/trees/btree/btree.go @@ -95,6 +95,13 @@ func (tree *Tree) Get(key interface{}) (value interface{}, found bool) { return nil, false } +// GetNode searches the node in the tree by key and returns its node or nil if key is not found in tree. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (tree *Tree) GetNode(key interface{}) *Node { + node, _, _ := tree.searchRecursively(tree.Root, key) + return node +} + // Remove remove the node from the tree by key. // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree) Remove(key interface{}) { @@ -115,6 +122,19 @@ func (tree *Tree) Size() int { return tree.size } +// Size returns the number of elements stored in the subtree. +// Computed dynamically on each call, i.e. the subtree is traversed to count the number of the nodes. +func (node *Node) Size() int { + if node == nil { + return 0 + } + size := 1 + for _, child := range node.Children { + size += child.Size() + } + return size +} + // Keys returns all keys in-order func (tree *Tree) Keys() []interface{} { keys := make([]interface{}, tree.size) diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index f4edaf1f..5bf5cb4d 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -74,6 +74,52 @@ func TestBTreeGet2(t *testing.T) { } } +func TestBTreeGet3(t *testing.T) { + tree := NewWithIntComparator(3) + + if actualValue := tree.Size(); actualValue != 0 { + t.Errorf("Got %v expected %v", actualValue, 0) + } + + if actualValue := tree.GetNode(2).Size(); actualValue != 0 { + t.Errorf("Got %v expected %v", actualValue, 0) + } + + tree.Put(1, "x") // 1->x + tree.Put(2, "b") // 1->x, 2->b (in order) + tree.Put(1, "a") // 1->a, 2->b (in order, replacement) + tree.Put(3, "c") // 1->a, 2->b, 3->c (in order) + tree.Put(4, "d") // 1->a, 2->b, 3->c, 4->d (in order) + tree.Put(5, "e") // 1->a, 2->b, 3->c, 4->d, 5->e (in order) + tree.Put(6, "f") // 1->a, 2->b, 3->c, 4->d, 5->e, 6->f (in order) + tree.Put(7, "g") // 1->a, 2->b, 3->c, 4->d, 5->e, 6->f, 7->g (in order) + + // BTree + // 1 + // 2 + // 3 + // 4 + // 5 + // 6 + // 7 + + if actualValue := tree.Size(); actualValue != 7 { + t.Errorf("Got %v expected %v", actualValue, 7) + } + + if actualValue := tree.GetNode(2).Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + + if actualValue := tree.GetNode(4).Size(); actualValue != 7 { + t.Errorf("Got %v expected %v", actualValue, 7) + } + + if actualValue := tree.GetNode(8).Size(); actualValue != 0 { + t.Errorf("Got %v expected %v", actualValue, 0) + } +} + func TestBTreePut1(t *testing.T) { // https://upload.wikimedia.org/wikipedia/commons/3/33/B_tree_insertion_example.png tree := NewWithIntComparator(3) diff --git a/trees/btree/iterator.go b/trees/btree/iterator.go index ed0cb154..c74b6464 100644 --- a/trees/btree/iterator.go +++ b/trees/btree/iterator.go @@ -160,6 +160,12 @@ func (iterator *Iterator) Key() interface{} { return iterator.entry.Key } +// Node returns the current element's node. +// Does not modify the state of the iterator. +func (iterator *Iterator) Node() *Node { + return iterator.node +} + // Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. func (iterator *Iterator) Begin() { diff --git a/trees/redblacktree/iterator.go b/trees/redblacktree/iterator.go index 881b67dd..79d6ab3a 100644 --- a/trees/redblacktree/iterator.go +++ b/trees/redblacktree/iterator.go @@ -130,6 +130,12 @@ func (iterator *Iterator) Key() interface{} { return iterator.node.Key } +// Node returns the current element's node. +// Does not modify the state of the iterator. +func (iterator *Iterator) Node() *Node { + return iterator.node +} + // Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. func (iterator *Iterator) Begin() { diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 8301ffd7..cce9fe0a 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -113,6 +113,12 @@ func (tree *Tree) Get(key interface{}) (value interface{}, found bool) { return nil, false } +// GetNode searches the node in the tree by key and returns its node or nil if key is not found in tree. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (tree *Tree) GetNode(key interface{}) *Node { + return tree.lookup(key) +} + // Remove remove the node from the tree by key. // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree) Remove(key interface{}) { @@ -155,6 +161,22 @@ func (tree *Tree) Size() int { return tree.size } +// Size returns the number of elements stored in the subtree. +// Computed dynamically on each call, i.e. the subtree is traversed to count the number of the nodes. +func (node *Node) Size() int { + if node == nil { + return 0 + } + size := 1 + if node.Left != nil { + size += node.Left.Size() + } + if node.Right != nil { + size += node.Right.Size() + } + return size +} + // Keys returns all keys in-order func (tree *Tree) Keys() []interface{} { keys := make([]interface{}, tree.size) diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 730a1f3a..3abe6c1a 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -10,6 +10,52 @@ import ( "testing" ) +func TestRedBlackTreeGet(t *testing.T) { + tree := NewWithIntComparator() + + if actualValue := tree.Size(); actualValue != 0 { + t.Errorf("Got %v expected %v", actualValue, 0) + } + + if actualValue := tree.GetNode(2).Size(); actualValue != 0 { + t.Errorf("Got %v expected %v", actualValue, 0) + } + + tree.Put(1, "x") // 1->x + tree.Put(2, "b") // 1->x, 2->b (in order) + tree.Put(1, "a") // 1->a, 2->b (in order, replacement) + tree.Put(3, "c") // 1->a, 2->b, 3->c (in order) + tree.Put(4, "d") // 1->a, 2->b, 3->c, 4->d (in order) + tree.Put(5, "e") // 1->a, 2->b, 3->c, 4->d, 5->e (in order) + tree.Put(6, "f") // 1->a, 2->b, 3->c, 4->d, 5->e, 6->f (in order) + + fmt.Println(tree) + // + // RedBlackTree + // │ ┌── 6 + // │ ┌── 5 + // │ ┌── 4 + // │ │ └── 3 + // └── 2 + // └── 1 + + if actualValue := tree.Size(); actualValue != 6 { + t.Errorf("Got %v expected %v", actualValue, 6) + } + + if actualValue := tree.GetNode(4).Size(); actualValue != 4 { + t.Errorf("Got %v expected %v", actualValue, 4) + } + + if actualValue := tree.GetNode(2).Size(); actualValue != 6 { + t.Errorf("Got %v expected %v", actualValue, 6) + } + + if actualValue := tree.GetNode(8).Size(); actualValue != 0 { + t.Errorf("Got %v expected %v", actualValue, 0) + } +} + func TestRedBlackTreePut(t *testing.T) { tree := NewWithIntComparator() tree.Put(5, "e") From 1f0b87f0e17d460400ba4ab1f1b9f172ef39bafa Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 12 Apr 2022 04:31:44 +0200 Subject: [PATCH 275/320] Implements json.Marshaler and json.Unmarshaler interfaces --- containers/serialization.go | 4 ++++ lists/arraylist/arraylist_test.go | 10 ++++++++-- lists/arraylist/serialization.go | 6 ++---- lists/doublylinkedlist/doublylinkedlist_test.go | 10 ++++++++-- lists/doublylinkedlist/serialization.go | 6 ++---- lists/singlylinkedlist/serialization.go | 6 ++---- lists/singlylinkedlist/singlylinkedlist_test.go | 10 ++++++++-- maps/hashbidimap/hashbidimap_test.go | 10 ++++++++-- maps/hashbidimap/serialization.go | 6 ++---- maps/hashmap/hashmap_test.go | 10 ++++++++-- maps/hashmap/serialization.go | 6 ++---- maps/linkedhashmap/linkedhashmap_test.go | 11 +++++++++++ maps/linkedhashmap/serialization.go | 6 ++---- maps/treebidimap/serialization.go | 6 ++---- maps/treebidimap/treebidimap_test.go | 11 +++++++++++ maps/treemap/serialization.go | 8 ++------ maps/treemap/treemap_test.go | 11 +++++++++++ sets/hashset/hashset_test.go | 10 ++++++++-- sets/hashset/serialization.go | 6 ++---- sets/linkedhashset/linkedhashset_test.go | 10 ++++++++-- sets/linkedhashset/serialization.go | 6 ++---- sets/treeset/serialization.go | 6 ++---- sets/treeset/treeset_test.go | 10 ++++++++-- stacks/arraystack/arraystack_test.go | 10 ++++++++-- stacks/arraystack/serialization.go | 8 ++------ stacks/linkedliststack/linkedliststack_test.go | 10 ++++++++-- stacks/linkedliststack/serialization.go | 8 ++------ trees/avltree/avltree_test.go | 10 ++++++++-- trees/avltree/serialization.go | 6 ++---- trees/binaryheap/binaryheap_test.go | 10 ++++++++-- trees/binaryheap/serialization.go | 8 ++------ trees/btree/btree_test.go | 10 ++++++++-- trees/btree/serialization.go | 6 ++---- trees/redblacktree/redblacktree_test.go | 10 ++++++++-- trees/redblacktree/serialization.go | 6 ++---- 35 files changed, 183 insertions(+), 104 deletions(-) diff --git a/containers/serialization.go b/containers/serialization.go index d7c90c83..fd9cbe23 100644 --- a/containers/serialization.go +++ b/containers/serialization.go @@ -8,10 +8,14 @@ package containers type JSONSerializer interface { // ToJSON outputs the JSON representation of containers's elements. ToJSON() ([]byte, error) + // MarshalJSON @implements json.Marshaler + MarshalJSON() ([]byte, error) } // JSONDeserializer provides JSON deserialization type JSONDeserializer interface { // FromJSON populates containers's elements from the input JSON representation. FromJSON([]byte) error + // UnmarshalJSON @implements json.Unmarshaler + UnmarshalJSON([]byte) error } diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 88d7689c..2a704d17 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -5,6 +5,7 @@ package arraylist import ( + "encoding/json" "fmt" "github.com/emirpasic/gods/utils" "strings" @@ -620,11 +621,16 @@ func TestListSerialization(t *testing.T) { assert() - json, err := list.ToJSON() + bytes, err := list.ToJSON() assert() - err = list.FromJSON(json) + err = list.FromJSON(bytes) assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", list}) + if err != nil { + t.Errorf("Got error %v", err) + } } func benchmarkGet(b *testing.B, list *List, size int) { diff --git a/lists/arraylist/serialization.go b/lists/arraylist/serialization.go index eeaaa4d2..402298f0 100644 --- a/lists/arraylist/serialization.go +++ b/lists/arraylist/serialization.go @@ -12,8 +12,6 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*List)(nil) var _ containers.JSONDeserializer = (*List)(nil) - var _ json.Marshaler = (*List)(nil) - var _ json.Unmarshaler = (*List)(nil) } // ToJSON outputs the JSON representation of list's elements. @@ -30,12 +28,12 @@ func (list *List) FromJSON(data []byte) error { return err } -// @implements json.Unmarshaler +// UnmarshalJSON @implements json.Unmarshaler func (list *List) UnmarshalJSON(bytes []byte) error { return list.FromJSON(bytes) } -// @implements json.Marshaler +// MarshalJSON @implements json.Marshaler func (list *List) MarshalJSON() ([]byte, error) { return list.ToJSON() } diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 2e6b0c92..911da774 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -5,6 +5,7 @@ package doublylinkedlist import ( + "encoding/json" "fmt" "strings" "testing" @@ -626,11 +627,16 @@ func TestListSerialization(t *testing.T) { assert() - json, err := list.ToJSON() + bytes, err := list.ToJSON() assert() - err = list.FromJSON(json) + err = list.FromJSON(bytes) assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", list}) + if err != nil { + t.Errorf("Got error %v", err) + } } func benchmarkGet(b *testing.B, list *List, size int) { diff --git a/lists/doublylinkedlist/serialization.go b/lists/doublylinkedlist/serialization.go index a61d9ba6..ce0fb019 100644 --- a/lists/doublylinkedlist/serialization.go +++ b/lists/doublylinkedlist/serialization.go @@ -12,8 +12,6 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*List)(nil) var _ containers.JSONDeserializer = (*List)(nil) - var _ json.Marshaler = (*List)(nil) - var _ json.Unmarshaler = (*List)(nil) } // ToJSON outputs the JSON representation of list's elements. @@ -32,12 +30,12 @@ func (list *List) FromJSON(data []byte) error { return err } -// @implements json.Unmarshaler +// UnmarshalJSON @implements json.Unmarshaler func (list *List) UnmarshalJSON(bytes []byte) error { return list.FromJSON(bytes) } -// @implements json.Marshaler +// MarshalJSON @implements json.Marshaler func (list *List) MarshalJSON() ([]byte, error) { return list.ToJSON() } diff --git a/lists/singlylinkedlist/serialization.go b/lists/singlylinkedlist/serialization.go index 74ce75ff..adcc5756 100644 --- a/lists/singlylinkedlist/serialization.go +++ b/lists/singlylinkedlist/serialization.go @@ -12,8 +12,6 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*List)(nil) var _ containers.JSONDeserializer = (*List)(nil) - var _ json.Marshaler = (*List)(nil) - var _ json.Unmarshaler = (*List)(nil) } // ToJSON outputs the JSON representation of list's elements. @@ -32,12 +30,12 @@ func (list *List) FromJSON(data []byte) error { return err } -// @implements json.Unmarshaler +// UnmarshalJSON @implements json.Unmarshaler func (list *List) UnmarshalJSON(bytes []byte) error { return list.FromJSON(bytes) } -// @implements json.Marshaler +// MarshalJSON @implements json.Marshaler func (list *List) MarshalJSON() ([]byte, error) { return list.ToJSON() } diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index 3023a8ee..97eb78bb 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -5,6 +5,7 @@ package singlylinkedlist import ( + "encoding/json" "fmt" "strings" "testing" @@ -489,11 +490,16 @@ func TestListSerialization(t *testing.T) { assert() - json, err := list.ToJSON() + bytes, err := list.ToJSON() assert() - err = list.FromJSON(json) + err = list.FromJSON(bytes) assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", list}) + if err != nil { + t.Errorf("Got error %v", err) + } } func benchmarkGet(b *testing.B, list *List, size int) { diff --git a/maps/hashbidimap/hashbidimap_test.go b/maps/hashbidimap/hashbidimap_test.go index 96e46889..8b607f44 100644 --- a/maps/hashbidimap/hashbidimap_test.go +++ b/maps/hashbidimap/hashbidimap_test.go @@ -5,6 +5,7 @@ package hashbidimap import ( + "encoding/json" "fmt" "testing" ) @@ -174,11 +175,16 @@ func TestMapSerialization(t *testing.T) { assert() - json, err := m.ToJSON() + bytes, err := m.ToJSON() assert() - err = m.FromJSON(json) + err = m.FromJSON(bytes) assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", m}) + if err != nil { + t.Errorf("Got error %v", err) + } } func sameElements(a []interface{}, b []interface{}) bool { diff --git a/maps/hashbidimap/serialization.go b/maps/hashbidimap/serialization.go index e05c4e8a..dff78017 100644 --- a/maps/hashbidimap/serialization.go +++ b/maps/hashbidimap/serialization.go @@ -12,8 +12,6 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Map)(nil) var _ containers.JSONDeserializer = (*Map)(nil) - var _ json.Marshaler = (*Map)(nil) - var _ json.Unmarshaler = (*Map)(nil) } // ToJSON outputs the JSON representation of the map. @@ -34,12 +32,12 @@ func (m *Map) FromJSON(data []byte) error { return err } -// @implements json.Unmarshaler +// UnmarshalJSON @implements json.Unmarshaler func (m *Map) UnmarshalJSON(bytes []byte) error { return m.FromJSON(bytes) } -// @implements json.Marshaler +// MarshalJSON @implements json.Marshaler func (m *Map) MarshalJSON() ([]byte, error) { return m.ToJSON() } diff --git a/maps/hashmap/hashmap_test.go b/maps/hashmap/hashmap_test.go index 7122574d..14966806 100644 --- a/maps/hashmap/hashmap_test.go +++ b/maps/hashmap/hashmap_test.go @@ -5,6 +5,7 @@ package hashmap import ( + "encoding/json" "fmt" "testing" ) @@ -142,11 +143,16 @@ func TestMapSerialization(t *testing.T) { assert() - json, err := m.ToJSON() + bytes, err := m.ToJSON() assert() - err = m.FromJSON(json) + err = m.FromJSON(bytes) assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", m}) + if err != nil { + t.Errorf("Got error %v", err) + } } func sameElements(a []interface{}, b []interface{}) bool { diff --git a/maps/hashmap/serialization.go b/maps/hashmap/serialization.go index 8fe78fa9..dc2e2598 100644 --- a/maps/hashmap/serialization.go +++ b/maps/hashmap/serialization.go @@ -13,8 +13,6 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Map)(nil) var _ containers.JSONDeserializer = (*Map)(nil) - var _ json.Marshaler = (*Map)(nil) - var _ json.Unmarshaler = (*Map)(nil) } // ToJSON outputs the JSON representation of the map. @@ -39,12 +37,12 @@ func (m *Map) FromJSON(data []byte) error { return err } -// @implements json.Unmarshaler +// UnmarshalJSON @implements json.Unmarshaler func (m *Map) UnmarshalJSON(bytes []byte) error { return m.FromJSON(bytes) } -// @implements json.Marshaler +// MarshalJSON @implements json.Marshaler func (m *Map) MarshalJSON() ([]byte, error) { return m.ToJSON() } diff --git a/maps/linkedhashmap/linkedhashmap_test.go b/maps/linkedhashmap/linkedhashmap_test.go index 912e7f31..ac7b9940 100644 --- a/maps/linkedhashmap/linkedhashmap_test.go +++ b/maps/linkedhashmap/linkedhashmap_test.go @@ -5,6 +5,7 @@ package linkedhashmap import ( + "encoding/json" "fmt" "strings" "testing" @@ -571,6 +572,16 @@ func TestMapSerialization(t *testing.T) { } assertSerialization(deserialized, "C", t) } + + m := New() + m.Put("a", 1.0) + m.Put("b", 2.0) + m.Put("c", 3.0) + + _, err := json.Marshal([]interface{}{"a", "b", "c", m}) + if err != nil { + t.Errorf("Got error %v", err) + } } //noinspection GoBoolExpressions diff --git a/maps/linkedhashmap/serialization.go b/maps/linkedhashmap/serialization.go index a628b914..805421d3 100644 --- a/maps/linkedhashmap/serialization.go +++ b/maps/linkedhashmap/serialization.go @@ -14,8 +14,6 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Map)(nil) var _ containers.JSONDeserializer = (*Map)(nil) - var _ json.Marshaler = (*Map)(nil) - var _ json.Unmarshaler = (*Map)(nil) } // ToJSON outputs the JSON representation of map. @@ -104,12 +102,12 @@ func (m *Map) FromJSON(data []byte) error { return nil } -// @implements json.Unmarshaler +// UnmarshalJSON @implements json.Unmarshaler func (m *Map) UnmarshalJSON(bytes []byte) error { return m.FromJSON(bytes) } -// @implements json.Marshaler +// MarshalJSON @implements json.Marshaler func (m *Map) MarshalJSON() ([]byte, error) { return m.ToJSON() } diff --git a/maps/treebidimap/serialization.go b/maps/treebidimap/serialization.go index 488d2a0f..e7ee0c20 100644 --- a/maps/treebidimap/serialization.go +++ b/maps/treebidimap/serialization.go @@ -13,8 +13,6 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Map)(nil) var _ containers.JSONDeserializer = (*Map)(nil) - var _ json.Marshaler = (*Map)(nil) - var _ json.Unmarshaler = (*Map)(nil) } // ToJSON outputs the JSON representation of the map. @@ -40,12 +38,12 @@ func (m *Map) FromJSON(data []byte) error { return err } -// @implements json.Unmarshaler +// UnmarshalJSON @implements json.Unmarshaler func (m *Map) UnmarshalJSON(bytes []byte) error { return m.FromJSON(bytes) } -// @implements json.Marshaler +// MarshalJSON @implements json.Marshaler func (m *Map) MarshalJSON() ([]byte, error) { return m.ToJSON() } diff --git a/maps/treebidimap/treebidimap_test.go b/maps/treebidimap/treebidimap_test.go index e1150fcc..acd32700 100644 --- a/maps/treebidimap/treebidimap_test.go +++ b/maps/treebidimap/treebidimap_test.go @@ -5,6 +5,7 @@ package treebidimap import ( + "encoding/json" "fmt" "github.com/emirpasic/gods/utils" "strings" @@ -604,6 +605,16 @@ func TestMapSerialization(t *testing.T) { } assertSerialization(deserialized, "C", t) } + + m := NewWith(utils.StringComparator, utils.Float64Comparator) + m.Put("a", 1.0) + m.Put("b", 2.0) + m.Put("c", 3.0) + + _, err := json.Marshal([]interface{}{"a", "b", "c", m}) + if err != nil { + t.Errorf("Got error %v", err) + } } //noinspection GoBoolExpressions diff --git a/maps/treemap/serialization.go b/maps/treemap/serialization.go index d6b2d101..619a6a77 100644 --- a/maps/treemap/serialization.go +++ b/maps/treemap/serialization.go @@ -5,16 +5,12 @@ package treemap import ( - "encoding/json" - "github.com/emirpasic/gods/containers" ) func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Map)(nil) var _ containers.JSONDeserializer = (*Map)(nil) - var _ json.Marshaler = (*Map)(nil) - var _ json.Unmarshaler = (*Map)(nil) } // ToJSON outputs the JSON representation of the map. @@ -27,12 +23,12 @@ func (m *Map) FromJSON(data []byte) error { return m.tree.FromJSON(data) } -// @implements json.Unmarshaler +// UnmarshalJSON @implements json.Unmarshaler func (m *Map) UnmarshalJSON(bytes []byte) error { return m.FromJSON(bytes) } -// @implements json.Marshaler +// MarshalJSON @implements json.Marshaler func (m *Map) MarshalJSON() ([]byte, error) { return m.ToJSON() } diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 05155a21..92e96124 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -5,6 +5,7 @@ package treemap import ( + "encoding/json" "fmt" "strings" "testing" @@ -627,6 +628,16 @@ func TestMapSerialization(t *testing.T) { } assertSerialization(deserialized, "C", t) } + + m := NewWithStringComparator() + m.Put("a", 1.0) + m.Put("b", 2.0) + m.Put("c", 3.0) + + _, err := json.Marshal([]interface{}{"a", "b", "c", m}) + if err != nil { + t.Errorf("Got error %v", err) + } } //noinspection GoBoolExpressions diff --git a/sets/hashset/hashset_test.go b/sets/hashset/hashset_test.go index cf63c899..4351338b 100644 --- a/sets/hashset/hashset_test.go +++ b/sets/hashset/hashset_test.go @@ -5,6 +5,7 @@ package hashset import ( + "encoding/json" "testing" ) @@ -98,11 +99,16 @@ func TestSetSerialization(t *testing.T) { assert() - json, err := set.ToJSON() + bytes, err := set.ToJSON() assert() - err = set.FromJSON(json) + err = set.FromJSON(bytes) assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", set}) + if err != nil { + t.Errorf("Got error %v", err) + } } func benchmarkContains(b *testing.B, set *Set, size int) { diff --git a/sets/hashset/serialization.go b/sets/hashset/serialization.go index f93b0cbc..b0353e83 100644 --- a/sets/hashset/serialization.go +++ b/sets/hashset/serialization.go @@ -12,8 +12,6 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Set)(nil) var _ containers.JSONDeserializer = (*Set)(nil) - var _ json.Marshaler = (*Set)(nil) - var _ json.Unmarshaler = (*Set)(nil) } // ToJSON outputs the JSON representation of the set. @@ -32,12 +30,12 @@ func (set *Set) FromJSON(data []byte) error { return err } -// @implements json.Unmarshaler +// UnmarshalJSON @implements json.Unmarshaler func (set *Set) UnmarshalJSON(bytes []byte) error { return set.FromJSON(bytes) } -// @implements json.Marshaler +// MarshalJSON @implements json.Marshaler func (set *Set) MarshalJSON() ([]byte, error) { return set.ToJSON() } diff --git a/sets/linkedhashset/linkedhashset_test.go b/sets/linkedhashset/linkedhashset_test.go index b77e5ecd..59db9ad9 100644 --- a/sets/linkedhashset/linkedhashset_test.go +++ b/sets/linkedhashset/linkedhashset_test.go @@ -5,6 +5,7 @@ package linkedhashset import ( + "encoding/json" "fmt" "strings" "testing" @@ -452,11 +453,16 @@ func TestSetSerialization(t *testing.T) { assert() - json, err := set.ToJSON() + bytes, err := set.ToJSON() assert() - err = set.FromJSON(json) + err = set.FromJSON(bytes) assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", set}) + if err != nil { + t.Errorf("Got error %v", err) + } } func benchmarkContains(b *testing.B, set *Set, size int) { diff --git a/sets/linkedhashset/serialization.go b/sets/linkedhashset/serialization.go index 4e84be9e..33b3fefd 100644 --- a/sets/linkedhashset/serialization.go +++ b/sets/linkedhashset/serialization.go @@ -12,8 +12,6 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Set)(nil) var _ containers.JSONDeserializer = (*Set)(nil) - var _ json.Marshaler = (*Set)(nil) - var _ json.Unmarshaler = (*Set)(nil) } // ToJSON outputs the JSON representation of the set. @@ -32,12 +30,12 @@ func (set *Set) FromJSON(data []byte) error { return err } -// @implements json.Unmarshaler +// UnmarshalJSON @implements json.Unmarshaler func (set *Set) UnmarshalJSON(bytes []byte) error { return set.FromJSON(bytes) } -// @implements json.Marshaler +// MarshalJSON @implements json.Marshaler func (set *Set) MarshalJSON() ([]byte, error) { return set.ToJSON() } diff --git a/sets/treeset/serialization.go b/sets/treeset/serialization.go index a74ad6da..a17eb780 100644 --- a/sets/treeset/serialization.go +++ b/sets/treeset/serialization.go @@ -12,8 +12,6 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Set)(nil) var _ containers.JSONDeserializer = (*Set)(nil) - var _ json.Marshaler = (*Set)(nil) - var _ json.Unmarshaler = (*Set)(nil) } // ToJSON outputs the JSON representation of the set. @@ -32,12 +30,12 @@ func (set *Set) FromJSON(data []byte) error { return err } -// @implements json.Unmarshaler +// UnmarshalJSON @implements json.Unmarshaler func (set *Set) UnmarshalJSON(bytes []byte) error { return set.FromJSON(bytes) } -// @implements json.Marshaler +// MarshalJSON @implements json.Marshaler func (set *Set) MarshalJSON() ([]byte, error) { return set.ToJSON() } diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index 85718873..20a6f6a3 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -5,6 +5,7 @@ package treeset import ( + "encoding/json" "fmt" "strings" "testing" @@ -461,11 +462,16 @@ func TestSetSerialization(t *testing.T) { assert() - json, err := set.ToJSON() + bytes, err := set.ToJSON() assert() - err = set.FromJSON(json) + err = set.FromJSON(bytes) assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", set}) + if err != nil { + t.Errorf("Got error %v", err) + } } func benchmarkContains(b *testing.B, set *Set, size int) { diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index 0596217b..d15e7eb0 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -5,6 +5,7 @@ package arraystack import ( + "encoding/json" "fmt" "strings" "testing" @@ -360,11 +361,16 @@ func TestStackSerialization(t *testing.T) { assert() - json, err := stack.ToJSON() + bytes, err := stack.ToJSON() assert() - err = stack.FromJSON(json) + err = stack.FromJSON(bytes) assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", stack}) + if err != nil { + t.Errorf("Got error %v", err) + } } func benchmarkPush(b *testing.B, stack *Stack, size int) { diff --git a/stacks/arraystack/serialization.go b/stacks/arraystack/serialization.go index 6d26fa72..1456c9ec 100644 --- a/stacks/arraystack/serialization.go +++ b/stacks/arraystack/serialization.go @@ -5,16 +5,12 @@ package arraystack import ( - "encoding/json" - "github.com/emirpasic/gods/containers" ) func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Stack)(nil) var _ containers.JSONDeserializer = (*Stack)(nil) - var _ json.Marshaler = (*Stack)(nil) - var _ json.Unmarshaler = (*Stack)(nil) } // ToJSON outputs the JSON representation of the stack. @@ -27,12 +23,12 @@ func (stack *Stack) FromJSON(data []byte) error { return stack.list.FromJSON(data) } -// @implements json.Unmarshaler +// UnmarshalJSON @implements json.Unmarshaler func (stack *Stack) UnmarshalJSON(bytes []byte) error { return stack.FromJSON(bytes) } -// @implements json.Marshaler +// MarshalJSON @implements json.Marshaler func (stack *Stack) MarshalJSON() ([]byte, error) { return stack.ToJSON() } diff --git a/stacks/linkedliststack/linkedliststack_test.go b/stacks/linkedliststack/linkedliststack_test.go index aeebc310..6b34e39c 100644 --- a/stacks/linkedliststack/linkedliststack_test.go +++ b/stacks/linkedliststack/linkedliststack_test.go @@ -5,6 +5,7 @@ package linkedliststack import ( + "encoding/json" "fmt" "strings" "testing" @@ -222,11 +223,16 @@ func TestStackSerialization(t *testing.T) { assert() - json, err := stack.ToJSON() + bytes, err := stack.ToJSON() assert() - err = stack.FromJSON(json) + err = stack.FromJSON(bytes) assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", stack}) + if err != nil { + t.Errorf("Got error %v", err) + } } func benchmarkPush(b *testing.B, stack *Stack, size int) { diff --git a/stacks/linkedliststack/serialization.go b/stacks/linkedliststack/serialization.go index fce1511e..3beb7a80 100644 --- a/stacks/linkedliststack/serialization.go +++ b/stacks/linkedliststack/serialization.go @@ -5,16 +5,12 @@ package linkedliststack import ( - "encoding/json" - "github.com/emirpasic/gods/containers" ) func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Stack)(nil) var _ containers.JSONDeserializer = (*Stack)(nil) - var _ json.Marshaler = (*Stack)(nil) - var _ json.Unmarshaler = (*Stack)(nil) } // ToJSON outputs the JSON representation of the stack. @@ -27,12 +23,12 @@ func (stack *Stack) FromJSON(data []byte) error { return stack.list.FromJSON(data) } -// @implements json.Unmarshaler +// UnmarshalJSON @implements json.Unmarshaler func (stack *Stack) UnmarshalJSON(bytes []byte) error { return stack.FromJSON(bytes) } -// @implements json.Marshaler +// MarshalJSON @implements json.Marshaler func (stack *Stack) MarshalJSON() ([]byte, error) { return stack.ToJSON() } diff --git a/trees/avltree/avltree_test.go b/trees/avltree/avltree_test.go index 9cc300a4..37bdd2f6 100644 --- a/trees/avltree/avltree_test.go +++ b/trees/avltree/avltree_test.go @@ -4,6 +4,7 @@ package avltree import ( + "encoding/json" "fmt" "strings" "testing" @@ -731,11 +732,16 @@ func TestAVLTreeSerialization(t *testing.T) { assert() - json, err := tree.ToJSON() + bytes, err := tree.ToJSON() assert() - err = tree.FromJSON(json) + err = tree.FromJSON(bytes) assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", tree}) + if err != nil { + t.Errorf("Got error %v", err) + } } func benchmarkGet(b *testing.B, tree *Tree, size int) { diff --git a/trees/avltree/serialization.go b/trees/avltree/serialization.go index 79d4e5e9..1ccd4a81 100644 --- a/trees/avltree/serialization.go +++ b/trees/avltree/serialization.go @@ -13,8 +13,6 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Tree)(nil) var _ containers.JSONDeserializer = (*Tree)(nil) - var _ json.Marshaler = (*Tree)(nil) - var _ json.Unmarshaler = (*Tree)(nil) } // ToJSON outputs the JSON representation of the tree. @@ -40,12 +38,12 @@ func (tree *Tree) FromJSON(data []byte) error { return err } -// @implements json.Unmarshaler +// UnmarshalJSON @implements json.Unmarshaler func (tree *Tree) UnmarshalJSON(bytes []byte) error { return tree.FromJSON(bytes) } -// @implements json.Marshaler +// MarshalJSON @implements json.Marshaler func (tree *Tree) MarshalJSON() ([]byte, error) { return tree.ToJSON() } diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go index 7a3d0605..e14794f1 100644 --- a/trees/binaryheap/binaryheap_test.go +++ b/trees/binaryheap/binaryheap_test.go @@ -5,6 +5,7 @@ package binaryheap import ( + "encoding/json" "math/rand" "strings" "testing" @@ -391,11 +392,16 @@ func TestBinaryHeapSerialization(t *testing.T) { assert() - json, err := heap.ToJSON() + bytes, err := heap.ToJSON() assert() - err = heap.FromJSON(json) + err = heap.FromJSON(bytes) assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", heap}) + if err != nil { + t.Errorf("Got error %v", err) + } } func benchmarkPush(b *testing.B, heap *Heap, size int) { diff --git a/trees/binaryheap/serialization.go b/trees/binaryheap/serialization.go index e0d2a939..30ccb250 100644 --- a/trees/binaryheap/serialization.go +++ b/trees/binaryheap/serialization.go @@ -5,16 +5,12 @@ package binaryheap import ( - "encoding/json" - "github.com/emirpasic/gods/containers" ) func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Heap)(nil) var _ containers.JSONDeserializer = (*Heap)(nil) - var _ json.Marshaler = (*Heap)(nil) - var _ json.Unmarshaler = (*Heap)(nil) } // ToJSON outputs the JSON representation of the heap. @@ -27,12 +23,12 @@ func (heap *Heap) FromJSON(data []byte) error { return heap.list.FromJSON(data) } -// @implements json.Unmarshaler +// UnmarshalJSON @implements json.Unmarshaler func (heap *Heap) UnmarshalJSON(bytes []byte) error { return heap.FromJSON(bytes) } -// @implements json.Marshaler +// MarshalJSON @implements json.Marshaler func (heap *Heap) MarshalJSON() ([]byte, error) { return heap.ToJSON() } diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index 5bf5cb4d..49c6ab5d 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -5,6 +5,7 @@ package btree import ( + "encoding/json" "fmt" "strings" "testing" @@ -1251,11 +1252,16 @@ func TestBTreeSerialization(t *testing.T) { assert() - json, err := tree.ToJSON() + bytes, err := tree.ToJSON() assert() - err = tree.FromJSON(json) + err = tree.FromJSON(bytes) assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", tree}) + if err != nil { + t.Errorf("Got error %v", err) + } } func benchmarkGet(b *testing.B, tree *Tree, size int) { diff --git a/trees/btree/serialization.go b/trees/btree/serialization.go index 75ef7280..5ff71751 100644 --- a/trees/btree/serialization.go +++ b/trees/btree/serialization.go @@ -13,8 +13,6 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Tree)(nil) var _ containers.JSONDeserializer = (*Tree)(nil) - var _ json.Marshaler = (*Tree)(nil) - var _ json.Unmarshaler = (*Tree)(nil) } // ToJSON outputs the JSON representation of the tree. @@ -40,12 +38,12 @@ func (tree *Tree) FromJSON(data []byte) error { return err } -// @implements json.Unmarshaler +// UnmarshalJSON @implements json.Unmarshaler func (tree *Tree) UnmarshalJSON(bytes []byte) error { return tree.FromJSON(bytes) } -// @implements json.Marshaler +// MarshalJSON @implements json.Marshaler func (tree *Tree) MarshalJSON() ([]byte, error) { return tree.ToJSON() } diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 3abe6c1a..c717648c 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -5,6 +5,7 @@ package redblacktree import ( + "encoding/json" "fmt" "strings" "testing" @@ -734,11 +735,16 @@ func TestRedBlackTreeSerialization(t *testing.T) { assert() - json, err := tree.ToJSON() + bytes, err := tree.ToJSON() assert() - err = tree.FromJSON(json) + err = tree.FromJSON(bytes) assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", tree}) + if err != nil { + t.Errorf("Got error %v", err) + } } func benchmarkGet(b *testing.B, tree *Tree, size int) { diff --git a/trees/redblacktree/serialization.go b/trees/redblacktree/serialization.go index 84c48216..da137771 100644 --- a/trees/redblacktree/serialization.go +++ b/trees/redblacktree/serialization.go @@ -13,8 +13,6 @@ import ( func assertSerializationImplementation() { var _ containers.JSONSerializer = (*Tree)(nil) var _ containers.JSONDeserializer = (*Tree)(nil) - var _ json.Marshaler = (*Tree)(nil) - var _ json.Unmarshaler = (*Tree)(nil) } // ToJSON outputs the JSON representation of the tree. @@ -40,12 +38,12 @@ func (tree *Tree) FromJSON(data []byte) error { return err } -// @implements json.Unmarshaler +// UnmarshalJSON @implements json.Unmarshaler func (tree *Tree) UnmarshalJSON(bytes []byte) error { return tree.FromJSON(bytes) } -// @implements json.Marshaler +// MarshalJSON @implements json.Marshaler func (tree *Tree) MarshalJSON() ([]byte, error) { return tree.ToJSON() } From a27d480bccd86583e924fa59ebd294cc998c7b32 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 12 Apr 2022 05:32:28 +0200 Subject: [PATCH 276/320] Simplify ToString function for types (avoid unnecessary casting) --- utils/utils.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/utils.go b/utils/utils.go index d305a7c8..262c6257 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -26,7 +26,7 @@ func ToString(value interface{}) string { case int32: return strconv.FormatInt(int64(value), 10) case int64: - return strconv.FormatInt(int64(value), 10) + return strconv.FormatInt(value, 10) case uint8: return strconv.FormatUint(uint64(value), 10) case uint16: @@ -34,11 +34,11 @@ func ToString(value interface{}) string { case uint32: return strconv.FormatUint(uint64(value), 10) case uint64: - return strconv.FormatUint(uint64(value), 10) + return strconv.FormatUint(value, 10) case float32: return strconv.FormatFloat(float64(value), 'g', -1, 64) case float64: - return strconv.FormatFloat(float64(value), 'g', -1, 64) + return strconv.FormatFloat(value, 'g', -1, 64) case bool: return strconv.FormatBool(value) default: From 364a244af9003224bfb3c474b25ac829b6462221 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 12 Apr 2022 19:30:54 +0200 Subject: [PATCH 277/320] Enforce String() inteface on Container --- containers/containers.go | 3 ++- containers/containers_test.go | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/containers/containers.go b/containers/containers.go index c35ab36d..a512a3cb 100644 --- a/containers/containers.go +++ b/containers/containers.go @@ -21,10 +21,11 @@ type Container interface { Size() int Clear() Values() []interface{} + String() string } // GetSortedValues returns sorted container's elements with respect to the passed comparator. -// Does not effect the ordering of elements within the container. +// Does not affect the ordering of elements within the container. func GetSortedValues(container Container, comparator utils.Comparator) []interface{} { values := container.Values() if len(values) < 2 { diff --git a/containers/containers_test.go b/containers/containers_test.go index 94cf4f80..60e0332e 100644 --- a/containers/containers_test.go +++ b/containers/containers_test.go @@ -7,7 +7,9 @@ package containers import ( + "fmt" "github.com/emirpasic/gods/utils" + "strings" "testing" ) @@ -32,6 +34,16 @@ func (container ContainerTest) Values() []interface{} { return container.values } +func (container ContainerTest) String() string { + str := "ContainerTest\n" + var values []string + for _, value := range container.values { + values = append(values, fmt.Sprintf("%v", value)) + } + str += strings.Join(values, ", ") + return str +} + func TestGetSortedValuesInts(t *testing.T) { container := ContainerTest{} container.values = []interface{}{5, 1, 3, 2, 4} From d7c0bc86516f33cd10d2694d7960cdea5005aff5 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 12 Apr 2022 22:37:06 +0200 Subject: [PATCH 278/320] Update documentation on JSON serialization with the new json/encoding interface implementation --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fa67f214..44b5f840 100644 --- a/README.md +++ b/README.md @@ -1402,10 +1402,12 @@ func main() { Populates the container with elements from the input JSON representation. Typical usage for key-value structures: + ```go package main import ( + "encoding/json" "fmt" "github.com/emirpasic/gods/maps/hashmap" ) @@ -1413,8 +1415,8 @@ import ( func main() { hm := hashmap.New() - json := []byte(`{"a":"1","b":"2"}`) - err := hm.FromJSON(json) + bytes := []byte(`{"a":"1","b":"2"}`) + err := json.Unmarshal(bytes, &hm) // Same as "hm.FromJSON(bytes)" if err != nil { fmt.Println(err) } @@ -1423,10 +1425,12 @@ func main() { ``` Typical usage for value-only structures: + ```go package main import ( + "encoding/json" "fmt" "github.com/emirpasic/gods/lists/arraylist" ) @@ -1434,8 +1438,8 @@ import ( func main() { list := arraylist.New() - json := []byte(`["a","b"]`) - err := list.FromJSON(json) + bytes := []byte(`["a","b"]`) + err := json.Unmarshal(bytes, &list) // Same as "list.FromJSON(bytes)" if err != nil { fmt.Println(err) } From 74bf8a8b7dc9f769f3c1b2d4b9c3f746beb462b8 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 12 Apr 2022 22:39:12 +0200 Subject: [PATCH 279/320] Update documentation on JSON serialization with the new json/encoding interface implementation --- README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 44b5f840..7cb7dd24 100644 --- a/README.md +++ b/README.md @@ -1355,10 +1355,12 @@ All data structures can be serialized (marshalled) and deserialized (unmarshalle Outputs the container into its JSON representation. Typical usage for key-value structures: + ```go package main import ( + "encoding/json" "fmt" "github.com/emirpasic/gods/maps/hashmap" ) @@ -1369,18 +1371,21 @@ func main() { m.Put("b", "2") m.Put("c", "3") - json, err := m.ToJSON() + bytes, err := json.Marshal(m) // Same as "m.ToJSON(m)" if err != nil { fmt.Println(err) } - fmt.Println(string(json)) // {"a":"1","b":"2","c":"3"} + fmt.Println(string(bytes)) // {"a":"1","b":"2","c":"3"} +} ``` Typical usage for value-only structures: + ```go package main import ( + "encoding/json" "fmt" "github.com/emirpasic/gods/lists/arraylist" ) @@ -1389,11 +1394,11 @@ func main() { list := arraylist.New() list.Add("a", "b", "c") - json, err := list.ToJSON() + bytes, err := json.Marshal(list) // Same as "list.ToJSON(list)" if err != nil { fmt.Println(err) } - fmt.Println(string(json)) // ["a","b","c"] + fmt.Println(string(bytes)) // ["a","b","c"] } ``` From e438e7b77b53520c448304dd0263c4a0b69c9346 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 00:36:42 +0200 Subject: [PATCH 280/320] Set operations: intersection, union, difference --- README.md | 7 +- containers/enumerable.go | 4 - sets/hashset/hashset.go | 55 +++++++++++++ sets/hashset/hashset_test.go | 66 ++++++++++++++++ sets/linkedhashset/linkedhashset.go | 55 +++++++++++++ sets/linkedhashset/linkedhashset_test.go | 66 ++++++++++++++++ sets/sets.go | 3 + sets/treeset/treeset.go | 77 ++++++++++++++++++ sets/treeset/treeset_test.go | 99 ++++++++++++++++++++++++ 9 files changed, 427 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6d1cf062..920847b5 100644 --- a/README.md +++ b/README.md @@ -230,6 +230,8 @@ func main() { A set is a data structure that can store elements and has no repeated values. It is a computer implementation of the mathematical concept of a finite set. Unlike most other collection types, rather than retrieving a specific element from a set, one typically tests an element for membership in a set. This structure is often used to ensure that no duplicates are present in a container. +Set additionally allow set operations such as [intersection](https://en.wikipedia.org/wiki/Intersection_(set_theory)), [union](https://en.wikipedia.org/wiki/Union_(set_theory)), [difference](https://proofwiki.org/wiki/Definition:Set_Difference), etc. + Implements [Container](#containers) interface. ```go @@ -237,7 +239,10 @@ type Set interface { Add(elements ...interface{}) Remove(elements ...interface{}) Contains(elements ...interface{}) bool - + // Intersection(another *Set) *Set + // Union(another *Set) *Set + // Difference(another *Set) *Set + containers.Container // Empty() bool // Size() int diff --git a/containers/enumerable.go b/containers/enumerable.go index ac48b545..70660054 100644 --- a/containers/enumerable.go +++ b/containers/enumerable.go @@ -11,11 +11,9 @@ type EnumerableWithIndex interface { // Map invokes the given function once for each element and returns a // container containing the values returned by the given function. - // TODO would appreciate help on how to enforce this in containers (don't want to type assert when chaining) // Map(func(index int, value interface{}) interface{}) Container // Select returns a new container containing all elements for which the given function returns a true value. - // TODO need help on how to enforce this in containers (don't want to type assert when chaining) // Select(func(index int, value interface{}) bool) Container // Any passes each element of the container to the given function and @@ -39,11 +37,9 @@ type EnumerableWithKey interface { // 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. - // TODO need help on how to enforce this in containers (don't want to type assert when chaining) // Map(func(key interface{}, value interface{}) (interface{}, interface{})) Container // Select returns a new container containing all elements for which the given function returns a true value. - // TODO need help on how to enforce this in containers (don't want to type assert when chaining) // Select(func(key interface{}, value interface{}) bool) Container // Any passes each element of the container to the given function and diff --git a/sets/hashset/hashset.go b/sets/hashset/hashset.go index 815d0490..99808f91 100644 --- a/sets/hashset/hashset.go +++ b/sets/hashset/hashset.go @@ -97,3 +97,58 @@ func (set *Set) String() string { str += strings.Join(items, ", ") return str } + +// Intersection returns the intersection between two sets. +// The new set consists of all elements that are both in "set" and "another". +// Ref: https://en.wikipedia.org/wiki/Intersection_(set_theory) +func (set *Set) Intersection(another *Set) *Set { + result := New() + + // Iterate over smaller set (optimization) + if set.Size() <= another.Size() { + for item, _ := range set.items { + if _, contains := another.items[item]; contains { + result.Add(item) + } + } + } else { + for item, _ := range another.items { + if _, contains := set.items[item]; contains { + result.Add(item) + } + } + } + + return result +} + +// Union returns the union of two sets. +// The new set consists of all elements that are in "set" or "another" (possibly both). +// Ref: https://en.wikipedia.org/wiki/Union_(set_theory) +func (set *Set) Union(another *Set) *Set { + result := New() + + for item, _ := range set.items { + result.Add(item) + } + for item, _ := range another.items { + result.Add(item) + } + + return result +} + +// Difference returns the difference between two sets. +// The new set consists of all elements that are in "set" but not in "another". +// Ref: https://proofwiki.org/wiki/Definition:Set_Difference +func (set *Set) Difference(another *Set) *Set { + result := New() + + for item, _ := range set.items { + if _, contains := another.items[item]; !contains { + result.Add(item) + } + } + + return result +} diff --git a/sets/hashset/hashset_test.go b/sets/hashset/hashset_test.go index 4351338b..ccb50b3c 100644 --- a/sets/hashset/hashset_test.go +++ b/sets/hashset/hashset_test.go @@ -111,6 +111,72 @@ func TestSetSerialization(t *testing.T) { } } +func TestSetIntersection(t *testing.T) { + set := New() + another := New() + + intersection := set.Intersection(another) + if actualValue, expectedValue := intersection.Size(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + set.Add("a", "b", "c", "d") + another.Add("c", "d", "e", "f") + + intersection = set.Intersection(another) + + if actualValue, expectedValue := intersection.Size(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := intersection.Contains("c", "d"); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } +} + +func TestSetUnion(t *testing.T) { + set := New() + another := New() + + union := set.Union(another) + if actualValue, expectedValue := union.Size(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + set.Add("a", "b", "c", "d") + another.Add("c", "d", "e", "f") + + union = set.Union(another) + + if actualValue, expectedValue := union.Size(), 6; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := union.Contains("a", "b", "c", "d", "e", "f"); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } +} + +func TestSetDifference(t *testing.T) { + set := New() + another := New() + + difference := set.Difference(another) + if actualValue, expectedValue := difference.Size(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + set.Add("a", "b", "c", "d") + another.Add("c", "d", "e", "f") + + difference = set.Difference(another) + + if actualValue, expectedValue := difference.Size(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := difference.Contains("a", "b"); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } +} + func benchmarkContains(b *testing.B, set *Set, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { diff --git a/sets/linkedhashset/linkedhashset.go b/sets/linkedhashset/linkedhashset.go index e589a127..46ebdfe6 100644 --- a/sets/linkedhashset/linkedhashset.go +++ b/sets/linkedhashset/linkedhashset.go @@ -116,3 +116,58 @@ func (set *Set) String() string { str += strings.Join(items, ", ") return str } + +// Intersection returns the intersection between two sets. +// The new set consists of all elements that are both in "set" and "another". +// Ref: https://en.wikipedia.org/wiki/Intersection_(set_theory) +func (set *Set) Intersection(another *Set) *Set { + result := New() + + // Iterate over smaller set (optimization) + if set.Size() <= another.Size() { + for item, _ := range set.table { + if _, contains := another.table[item]; contains { + result.Add(item) + } + } + } else { + for item, _ := range another.table { + if _, contains := set.table[item]; contains { + result.Add(item) + } + } + } + + return result +} + +// Union returns the union of two sets. +// The new set consists of all elements that are in "set" or "another" (possibly both). +// Ref: https://en.wikipedia.org/wiki/Union_(set_theory) +func (set *Set) Union(another *Set) *Set { + result := New() + + for item, _ := range set.table { + result.Add(item) + } + for item, _ := range another.table { + result.Add(item) + } + + return result +} + +// Difference returns the difference between two sets. +// The new set consists of all elements that are in "set" but not in "another". +// Ref: https://proofwiki.org/wiki/Definition:Set_Difference +func (set *Set) Difference(another *Set) *Set { + result := New() + + for item, _ := range set.table { + if _, contains := another.table[item]; !contains { + result.Add(item) + } + } + + return result +} diff --git a/sets/linkedhashset/linkedhashset_test.go b/sets/linkedhashset/linkedhashset_test.go index 59db9ad9..7e3c2368 100644 --- a/sets/linkedhashset/linkedhashset_test.go +++ b/sets/linkedhashset/linkedhashset_test.go @@ -465,6 +465,72 @@ func TestSetSerialization(t *testing.T) { } } +func TestSetIntersection(t *testing.T) { + set := New() + another := New() + + intersection := set.Intersection(another) + if actualValue, expectedValue := intersection.Size(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + set.Add("a", "b", "c", "d") + another.Add("c", "d", "e", "f") + + intersection = set.Intersection(another) + + if actualValue, expectedValue := intersection.Size(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := intersection.Contains("c", "d"); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } +} + +func TestSetUnion(t *testing.T) { + set := New() + another := New() + + union := set.Union(another) + if actualValue, expectedValue := union.Size(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + set.Add("a", "b", "c", "d") + another.Add("c", "d", "e", "f") + + union = set.Union(another) + + if actualValue, expectedValue := union.Size(), 6; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := union.Contains("a", "b", "c", "d", "e", "f"); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } +} + +func TestSetDifference(t *testing.T) { + set := New() + another := New() + + difference := set.Difference(another) + if actualValue, expectedValue := difference.Size(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + set.Add("a", "b", "c", "d") + another.Add("c", "d", "e", "f") + + difference = set.Difference(another) + + if actualValue, expectedValue := difference.Size(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := difference.Contains("a", "b"); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } +} + func benchmarkContains(b *testing.B, set *Set, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { diff --git a/sets/sets.go b/sets/sets.go index 25732971..d96801c9 100644 --- a/sets/sets.go +++ b/sets/sets.go @@ -16,6 +16,9 @@ type Set interface { Add(elements ...interface{}) Remove(elements ...interface{}) Contains(elements ...interface{}) bool + // Intersection(another *Set) *Set + // Union(another *Set) *Set + // Difference(another *Set) *Set containers.Container // Empty() bool diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 7efbf2dc..7e7d1d68 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -14,6 +14,7 @@ import ( "github.com/emirpasic/gods/sets" rbt "github.com/emirpasic/gods/trees/redblacktree" "github.com/emirpasic/gods/utils" + "reflect" "strings" ) @@ -111,3 +112,79 @@ func (set *Set) String() string { str += strings.Join(items, ", ") return str } + +// Intersection returns the intersection between two sets. +// The new set consists of all elements that are both in "set" and "another". +// The two sets should have the same comparators, otherwise the result is empty set. +// Ref: https://en.wikipedia.org/wiki/Intersection_(set_theory) +func (set *Set) Intersection(another *Set) *Set { + result := NewWith(set.tree.Comparator) + + setComparator := reflect.ValueOf(set.tree.Comparator) + anotherComparator := reflect.ValueOf(another.tree.Comparator) + if setComparator.Pointer() != anotherComparator.Pointer() { + return result + } + + // Iterate over smaller set (optimization) + if set.Size() <= another.Size() { + for it := set.Iterator(); it.Next(); { + if another.Contains(it.Value()) { + result.Add(it.Value()) + } + } + } else { + for it := another.Iterator(); it.Next(); { + if set.Contains(it.Value()) { + result.Add(it.Value()) + } + } + } + + return result +} + +// Union returns the union of two sets. +// The new set consists of all elements that are in "set" or "another" (possibly both). +// The two sets should have the same comparators, otherwise the result is empty set. +// Ref: https://en.wikipedia.org/wiki/Union_(set_theory) +func (set *Set) Union(another *Set) *Set { + result := NewWith(set.tree.Comparator) + + setComparator := reflect.ValueOf(set.tree.Comparator) + anotherComparator := reflect.ValueOf(another.tree.Comparator) + if setComparator.Pointer() != anotherComparator.Pointer() { + return result + } + + for it := set.Iterator(); it.Next(); { + result.Add(it.Value()) + } + for it := another.Iterator(); it.Next(); { + result.Add(it.Value()) + } + + return result +} + +// Difference returns the difference between two sets. +// The two sets should have the same comparators, otherwise the result is empty set. +// The new set consists of all elements that are in "set" but not in "another". +// Ref: https://proofwiki.org/wiki/Definition:Set_Difference +func (set *Set) Difference(another *Set) *Set { + result := NewWith(set.tree.Comparator) + + setComparator := reflect.ValueOf(set.tree.Comparator) + anotherComparator := reflect.ValueOf(another.tree.Comparator) + if setComparator.Pointer() != anotherComparator.Pointer() { + return result + } + + for it := set.Iterator(); it.Next(); { + if !another.Contains(it.Value()) { + result.Add(it.Value()) + } + } + + return result +} diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index 20a6f6a3..2839d4b2 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -474,6 +474,105 @@ func TestSetSerialization(t *testing.T) { } } +func TestSetIntersection(t *testing.T) { + { + set := NewWithStringComparator() + another := NewWithIntComparator() + set.Add("a", "b", "c", "d") + another.Add(1, 2, 3, 4) + difference := set.Difference(another) + if actualValue, expectedValue := difference.Size(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + + set := NewWithStringComparator() + another := NewWithStringComparator() + + intersection := set.Intersection(another) + if actualValue, expectedValue := intersection.Size(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + set.Add("a", "b", "c", "d") + another.Add("c", "d", "e", "f") + + intersection = set.Intersection(another) + + if actualValue, expectedValue := intersection.Size(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := intersection.Contains("c", "d"); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } +} + +func TestSetUnion(t *testing.T) { + { + set := NewWithStringComparator() + another := NewWithIntComparator() + set.Add("a", "b", "c", "d") + another.Add(1, 2, 3, 4) + difference := set.Difference(another) + if actualValue, expectedValue := difference.Size(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + + set := NewWithStringComparator() + another := NewWithStringComparator() + + union := set.Union(another) + if actualValue, expectedValue := union.Size(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + set.Add("a", "b", "c", "d") + another.Add("c", "d", "e", "f") + + union = set.Union(another) + + if actualValue, expectedValue := union.Size(), 6; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := union.Contains("a", "b", "c", "d", "e", "f"); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } +} + +func TestSetDifference(t *testing.T) { + { + set := NewWithStringComparator() + another := NewWithIntComparator() + set.Add("a", "b", "c", "d") + another.Add(1, 2, 3, 4) + difference := set.Difference(another) + if actualValue, expectedValue := difference.Size(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + + set := NewWithStringComparator() + another := NewWithStringComparator() + + difference := set.Difference(another) + if actualValue, expectedValue := difference.Size(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + set.Add("a", "b", "c", "d") + another.Add("c", "d", "e", "f") + + difference = set.Difference(another) + + if actualValue, expectedValue := difference.Size(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := difference.Contains("a", "b"); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } +} + func benchmarkContains(b *testing.B, set *Set, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { From 74d4456375a0edceed78a2f8ba03151bb5b70b80 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 00:38:38 +0200 Subject: [PATCH 281/320] Fix lint errors --- sets/hashset/hashset.go | 10 +++++----- sets/linkedhashset/linkedhashset.go | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sets/hashset/hashset.go b/sets/hashset/hashset.go index 99808f91..558e628b 100644 --- a/sets/hashset/hashset.go +++ b/sets/hashset/hashset.go @@ -106,13 +106,13 @@ func (set *Set) Intersection(another *Set) *Set { // Iterate over smaller set (optimization) if set.Size() <= another.Size() { - for item, _ := range set.items { + for item := range set.items { if _, contains := another.items[item]; contains { result.Add(item) } } } else { - for item, _ := range another.items { + for item := range another.items { if _, contains := set.items[item]; contains { result.Add(item) } @@ -128,10 +128,10 @@ func (set *Set) Intersection(another *Set) *Set { func (set *Set) Union(another *Set) *Set { result := New() - for item, _ := range set.items { + for item := range set.items { result.Add(item) } - for item, _ := range another.items { + for item := range another.items { result.Add(item) } @@ -144,7 +144,7 @@ func (set *Set) Union(another *Set) *Set { func (set *Set) Difference(another *Set) *Set { result := New() - for item, _ := range set.items { + for item := range set.items { if _, contains := another.items[item]; !contains { result.Add(item) } diff --git a/sets/linkedhashset/linkedhashset.go b/sets/linkedhashset/linkedhashset.go index 46ebdfe6..e028591e 100644 --- a/sets/linkedhashset/linkedhashset.go +++ b/sets/linkedhashset/linkedhashset.go @@ -125,13 +125,13 @@ func (set *Set) Intersection(another *Set) *Set { // Iterate over smaller set (optimization) if set.Size() <= another.Size() { - for item, _ := range set.table { + for item := range set.table { if _, contains := another.table[item]; contains { result.Add(item) } } } else { - for item, _ := range another.table { + for item := range another.table { if _, contains := set.table[item]; contains { result.Add(item) } @@ -147,10 +147,10 @@ func (set *Set) Intersection(another *Set) *Set { func (set *Set) Union(another *Set) *Set { result := New() - for item, _ := range set.table { + for item := range set.table { result.Add(item) } - for item, _ := range another.table { + for item := range another.table { result.Add(item) } @@ -163,7 +163,7 @@ func (set *Set) Union(another *Set) *Set { func (set *Set) Difference(another *Set) *Set { result := New() - for item, _ := range set.table { + for item := range set.table { if _, contains := another.table[item]; !contains { result.Add(item) } From b2dbe95e30107760ed2ccf5bba420fb34e8b9f7d Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 13:06:26 +0200 Subject: [PATCH 282/320] codeconv integration --- .circleci/config.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d4b80047..969f51dc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,5 +1,7 @@ version: 2.1 +orbs: + codecov: codecov/codecov@3.2.2 jobs: test: parameters: @@ -28,9 +30,10 @@ jobs: name: Calculate test coverage command: | mkdir -p $TEST_RESULTS - go test -coverprofile=c.out ./... > /dev/null - go tool cover -html=c.out -o coverage.html + go test -coverprofile=coverage.out ./... > /dev/null + go tool cover -html=coverage.out -o coverage.html mv coverage.html $TEST_RESULTS + - codecov/upload - run: name: Lint (golint) command: | From 5bcba54b52dc5fb1c27e030d5e5b88d0f6f11a59 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 13:23:25 +0200 Subject: [PATCH 283/320] codeconv integration --- .circleci/config.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 969f51dc..04d3bee1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,5 @@ version: 2.1 -orbs: - codecov: codecov/codecov@3.2.2 jobs: test: parameters: @@ -31,9 +29,13 @@ jobs: command: | mkdir -p $TEST_RESULTS go test -coverprofile=coverage.out ./... > /dev/null + go test -race -coverprofile=coverage.txt -covermode=atomic go tool cover -html=coverage.out -o coverage.html mv coverage.html $TEST_RESULTS - - codecov/upload + - run: + name: Upload test coverage + command: | + bash <(curl -s https://codecov.io/bash) - run: name: Lint (golint) command: | @@ -70,4 +72,4 @@ workflows: matrix: parameters: # To test with and without generics (versions prior to 1.18) - version: ["1.18", "1.17"] \ No newline at end of file + version: [ "1.18", "1.17" ] \ No newline at end of file From 138c2712daf34da2b84741d71bd4269c7fce8dca Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 13:24:23 +0200 Subject: [PATCH 284/320] codeconv integration --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 04d3bee1..4ecc8ccb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -29,7 +29,7 @@ jobs: command: | mkdir -p $TEST_RESULTS go test -coverprofile=coverage.out ./... > /dev/null - go test -race -coverprofile=coverage.txt -covermode=atomic + go test -race -coverprofile=coverage.txt -covermode=atomic ./... > /dev/null go tool cover -html=coverage.out -o coverage.html mv coverage.html $TEST_RESULTS - run: From 0d3ddc1d7403a2ab4a20db2f35ec5a048f5da6f1 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 13:30:10 +0200 Subject: [PATCH 285/320] codeconv integration --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 920847b5..ebc0b544 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ -[![GoDoc](https://godoc.org/github.com/emirpasic/gods?status.svg)](https://godoc.org/github.com/emirpasic/gods) [![Build Status](https://circleci.com/gh/emirpasic/gods/tree/master.svg?style=shield)](https://circleci.com/gh/emirpasic/gods?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/emirpasic/gods)](https://goreportcard.com/report/github.com/emirpasic/gods) [![PyPI](https://img.shields.io/badge/License-BSD_2--Clause-green.svg)](https://github.com/emirpasic/gods/blob/master/LICENSE) +[![GoDoc](https://godoc.org/github.com/emirpasic/gods?status.svg)](https://godoc.org/github.com/emirpasic/gods) +[![Build Status](https://circleci.com/gh/emirpasic/gods/tree/master.svg?style=shield)](https://circleci.com/gh/emirpasic/gods?branch=master) +[![Go Report Card](https://goreportcard.com/badge/github.com/emirpasic/gods)](https://goreportcard.com/report/github.com/emirpasic/gods) +[![codecov](https://codecov.io/gh/emirpasic/gods/branch/master/graph/badge.svg)](https://codecov.io/gh/emirpasic/gods) +[![PyPI](https://img.shields.io/badge/License-BSD_2--Clause-green.svg)](https://github.com/emirpasic/gods/blob/master/LICENSE) # GoDS (Go Data Structures) From 363df0e21f5de1efcb84b9836b6fab859c25f154 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 14:44:56 +0200 Subject: [PATCH 286/320] Comparator tests --- utils/comparator_test.go | 195 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) diff --git a/utils/comparator_test.go b/utils/comparator_test.go index 40efbd37..356c5e26 100644 --- a/utils/comparator_test.go +++ b/utils/comparator_test.go @@ -110,3 +110,198 @@ func TestCustomComparator(t *testing.T) { } } } + +func TestInt8ComparatorComparator(t *testing.T) { + tests := [][]interface{}{ + {int8(1), int8(1), 0}, + {int8(0), int8(1), -1}, + {int8(1), int8(0), 1}, + } + for _, test := range tests { + actual := Int8Comparator(test[0], test[1]) + expected := test[2] + if actual != expected { + t.Errorf("Got %v expected %v", actual, expected) + } + } +} + +func TestInt16Comparator(t *testing.T) { + tests := [][]interface{}{ + {int16(1), int16(1), 0}, + {int16(0), int16(1), -1}, + {int16(1), int16(0), 1}, + } + for _, test := range tests { + actual := Int16Comparator(test[0], test[1]) + expected := test[2] + if actual != expected { + t.Errorf("Got %v expected %v", actual, expected) + } + } +} + +func TestInt32Comparator(t *testing.T) { + tests := [][]interface{}{ + {int32(1), int32(1), 0}, + {int32(0), int32(1), -1}, + {int32(1), int32(0), 1}, + } + for _, test := range tests { + actual := Int32Comparator(test[0], test[1]) + expected := test[2] + if actual != expected { + t.Errorf("Got %v expected %v", actual, expected) + } + } +} + +func TestInt64Comparator(t *testing.T) { + tests := [][]interface{}{ + {int64(1), int64(1), 0}, + {int64(0), int64(1), -1}, + {int64(1), int64(0), 1}, + } + for _, test := range tests { + actual := Int64Comparator(test[0], test[1]) + expected := test[2] + if actual != expected { + t.Errorf("Got %v expected %v", actual, expected) + } + } +} + +func TestUIntComparator(t *testing.T) { + tests := [][]interface{}{ + {uint(1), uint(1), 0}, + {uint(0), uint(1), -1}, + {uint(1), uint(0), 1}, + } + for _, test := range tests { + actual := UIntComparator(test[0], test[1]) + expected := test[2] + if actual != expected { + t.Errorf("Got %v expected %v", actual, expected) + } + } +} + +func TestUInt8Comparator(t *testing.T) { + tests := [][]interface{}{ + {uint8(1), uint8(1), 0}, + {uint8(0), uint8(1), -1}, + {uint8(1), uint8(0), 1}, + } + for _, test := range tests { + actual := UInt8Comparator(test[0], test[1]) + expected := test[2] + if actual != expected { + t.Errorf("Got %v expected %v", actual, expected) + } + } +} + +func TestUInt16Comparator(t *testing.T) { + tests := [][]interface{}{ + {uint16(1), uint16(1), 0}, + {uint16(0), uint16(1), -1}, + {uint16(1), uint16(0), 1}, + } + for _, test := range tests { + actual := UInt16Comparator(test[0], test[1]) + expected := test[2] + if actual != expected { + t.Errorf("Got %v expected %v", actual, expected) + } + } +} + +func TestUInt32Comparator(t *testing.T) { + tests := [][]interface{}{ + {uint32(1), uint32(1), 0}, + {uint32(0), uint32(1), -1}, + {uint32(1), uint32(0), 1}, + } + for _, test := range tests { + actual := UInt32Comparator(test[0], test[1]) + expected := test[2] + if actual != expected { + t.Errorf("Got %v expected %v", actual, expected) + } + } +} + +func TestUInt64Comparator(t *testing.T) { + tests := [][]interface{}{ + {uint64(1), uint64(1), 0}, + {uint64(0), uint64(1), -1}, + {uint64(1), uint64(0), 1}, + } + for _, test := range tests { + actual := UInt64Comparator(test[0], test[1]) + expected := test[2] + if actual != expected { + t.Errorf("Got %v expected %v", actual, expected) + } + } +} + +func TestFloat32Comparator(t *testing.T) { + tests := [][]interface{}{ + {float32(1.1), float32(1.1), 0}, + {float32(0.1), float32(1.1), -1}, + {float32(1.1), float32(0.1), 1}, + } + for _, test := range tests { + actual := Float32Comparator(test[0], test[1]) + expected := test[2] + if actual != expected { + t.Errorf("Got %v expected %v", actual, expected) + } + } +} + +func TestFloat64Comparator(t *testing.T) { + tests := [][]interface{}{ + {float64(1.1), float64(1.1), 0}, + {float64(0.1), float64(1.1), -1}, + {float64(1.1), float64(0.1), 1}, + } + for _, test := range tests { + actual := Float64Comparator(test[0], test[1]) + expected := test[2] + if actual != expected { + t.Errorf("Got %v expected %v", actual, expected) + } + } +} + +func TestByteComparator(t *testing.T) { + tests := [][]interface{}{ + {byte(1), byte(1), 0}, + {byte(0), byte(1), -1}, + {byte(1), byte(0), 1}, + } + for _, test := range tests { + actual := ByteComparator(test[0], test[1]) + expected := test[2] + if actual != expected { + t.Errorf("Got %v expected %v", actual, expected) + } + } +} + +func TestRuneComparator(t *testing.T) { + tests := [][]interface{}{ + {rune(1), rune(1), 0}, + {rune(0), rune(1), -1}, + {rune(1), rune(0), 1}, + } + for _, test := range tests { + actual := RuneComparator(test[0], test[1]) + expected := test[2] + if actual != expected { + t.Errorf("Got %v expected %v", actual, expected) + } + } +} From e2b92bbc7ab90ec26e625d7c81e736f166800678 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 15:04:39 +0200 Subject: [PATCH 287/320] Interface implementation assertions moved outside the functions --- lists/arraylist/arraylist.go | 5 ++--- lists/arraylist/enumerable.go | 5 ++--- lists/arraylist/iterator.go | 5 ++--- lists/arraylist/serialization.go | 7 +++---- lists/doublylinkedlist/doublylinkedlist.go | 5 ++--- lists/doublylinkedlist/enumerable.go | 5 ++--- lists/doublylinkedlist/iterator.go | 5 ++--- lists/doublylinkedlist/serialization.go | 7 +++---- lists/singlylinkedlist/enumerable.go | 5 ++--- lists/singlylinkedlist/iterator.go | 5 ++--- lists/singlylinkedlist/serialization.go | 7 +++---- lists/singlylinkedlist/singlylinkedlist.go | 5 ++--- maps/hashbidimap/hashbidimap.go | 5 ++--- maps/hashbidimap/serialization.go | 7 +++---- maps/hashmap/hashmap.go | 5 ++--- maps/hashmap/serialization.go | 7 +++---- maps/linkedhashmap/enumerable.go | 5 ++--- maps/linkedhashmap/iterator.go | 5 ++--- maps/linkedhashmap/linkedhashmap.go | 5 ++--- maps/linkedhashmap/serialization.go | 7 +++---- maps/treebidimap/enumerable.go | 5 ++--- maps/treebidimap/iterator.go | 5 ++--- maps/treebidimap/serialization.go | 7 +++---- maps/treebidimap/treebidimap.go | 5 ++--- maps/treemap/enumerable.go | 5 ++--- maps/treemap/iterator.go | 5 ++--- maps/treemap/serialization.go | 7 +++---- maps/treemap/treemap.go | 5 ++--- sets/hashset/hashset.go | 5 ++--- sets/hashset/serialization.go | 7 +++---- sets/linkedhashset/enumerable.go | 5 ++--- sets/linkedhashset/iterator.go | 5 ++--- sets/linkedhashset/linkedhashset.go | 5 ++--- sets/linkedhashset/serialization.go | 7 +++---- sets/treeset/enumerable.go | 5 ++--- sets/treeset/iterator.go | 5 ++--- sets/treeset/serialization.go | 7 +++---- sets/treeset/treeset.go | 5 ++--- stacks/arraystack/arraystack.go | 5 ++--- stacks/arraystack/iterator.go | 5 ++--- stacks/arraystack/serialization.go | 7 +++---- stacks/linkedliststack/iterator.go | 5 ++--- stacks/linkedliststack/linkedliststack.go | 5 ++--- stacks/linkedliststack/serialization.go | 7 +++---- trees/avltree/avltree.go | 5 ++--- trees/avltree/iterator.go | 5 ++--- trees/avltree/serialization.go | 7 +++---- trees/binaryheap/binaryheap.go | 5 ++--- trees/binaryheap/iterator.go | 5 ++--- trees/binaryheap/serialization.go | 7 +++---- trees/btree/btree.go | 5 ++--- trees/btree/iterator.go | 5 ++--- trees/btree/serialization.go | 7 +++---- trees/redblacktree/iterator.go | 5 ++--- trees/redblacktree/redblacktree.go | 5 ++--- trees/redblacktree/serialization.go | 7 +++---- 56 files changed, 129 insertions(+), 185 deletions(-) diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index bfedac9e..41327bb2 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -17,9 +17,8 @@ import ( "github.com/emirpasic/gods/utils" ) -func assertListImplementation() { - var _ lists.List = (*List)(nil) -} +// Assert List implementation +var _ lists.List = (*List)(nil) // List holds the elements in a slice type List struct { diff --git a/lists/arraylist/enumerable.go b/lists/arraylist/enumerable.go index b3a87388..8bd60b0a 100644 --- a/lists/arraylist/enumerable.go +++ b/lists/arraylist/enumerable.go @@ -6,9 +6,8 @@ package arraylist import "github.com/emirpasic/gods/containers" -func assertEnumerableImplementation() { - var _ containers.EnumerableWithIndex = (*List)(nil) -} +// Assert Enumerable implementation +var _ containers.EnumerableWithIndex = (*List)(nil) // Each calls the given function once for each element, passing that element's index and value. func (list *List) Each(f func(index int, value interface{})) { diff --git a/lists/arraylist/iterator.go b/lists/arraylist/iterator.go index 2fefbb65..f9efe20c 100644 --- a/lists/arraylist/iterator.go +++ b/lists/arraylist/iterator.go @@ -6,9 +6,8 @@ package arraylist import "github.com/emirpasic/gods/containers" -func assertIteratorImplementation() { - var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) -} +// Assert Iterator implementation +var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) // Iterator holding the iterator's state type Iterator struct { diff --git a/lists/arraylist/serialization.go b/lists/arraylist/serialization.go index 402298f0..5e86fe96 100644 --- a/lists/arraylist/serialization.go +++ b/lists/arraylist/serialization.go @@ -9,10 +9,9 @@ import ( "github.com/emirpasic/gods/containers" ) -func assertSerializationImplementation() { - var _ containers.JSONSerializer = (*List)(nil) - var _ containers.JSONDeserializer = (*List)(nil) -} +// Assert Serialization implementation +var _ containers.JSONSerializer = (*List)(nil) +var _ containers.JSONDeserializer = (*List)(nil) // ToJSON outputs the JSON representation of list's elements. func (list *List) ToJSON() ([]byte, error) { diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 9035e38e..ab63de48 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -17,9 +17,8 @@ import ( "github.com/emirpasic/gods/utils" ) -func assertListImplementation() { - var _ lists.List = (*List)(nil) -} +// Assert List implementation +var _ lists.List = (*List)(nil) // List holds the elements, where each element points to the next and previous element type List struct { diff --git a/lists/doublylinkedlist/enumerable.go b/lists/doublylinkedlist/enumerable.go index e6cf60fb..4b14a47f 100644 --- a/lists/doublylinkedlist/enumerable.go +++ b/lists/doublylinkedlist/enumerable.go @@ -6,9 +6,8 @@ package doublylinkedlist import "github.com/emirpasic/gods/containers" -func assertEnumerableImplementation() { - var _ containers.EnumerableWithIndex = (*List)(nil) -} +// Assert Enumerable implementation +var _ containers.EnumerableWithIndex = (*List)(nil) // Each calls the given function once for each element, passing that element's index and value. func (list *List) Each(f func(index int, value interface{})) { diff --git a/lists/doublylinkedlist/iterator.go b/lists/doublylinkedlist/iterator.go index 55fb0bcf..27b34c2e 100644 --- a/lists/doublylinkedlist/iterator.go +++ b/lists/doublylinkedlist/iterator.go @@ -6,9 +6,8 @@ package doublylinkedlist import "github.com/emirpasic/gods/containers" -func assertIteratorImplementation() { - var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) -} +// Assert Iterator implementation +var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) // Iterator holding the iterator's state type Iterator struct { diff --git a/lists/doublylinkedlist/serialization.go b/lists/doublylinkedlist/serialization.go index ce0fb019..f210f9a2 100644 --- a/lists/doublylinkedlist/serialization.go +++ b/lists/doublylinkedlist/serialization.go @@ -9,10 +9,9 @@ import ( "github.com/emirpasic/gods/containers" ) -func assertSerializationImplementation() { - var _ containers.JSONSerializer = (*List)(nil) - var _ containers.JSONDeserializer = (*List)(nil) -} +// Assert Serialization implementation +var _ containers.JSONSerializer = (*List)(nil) +var _ containers.JSONDeserializer = (*List)(nil) // ToJSON outputs the JSON representation of list's elements. func (list *List) ToJSON() ([]byte, error) { diff --git a/lists/singlylinkedlist/enumerable.go b/lists/singlylinkedlist/enumerable.go index 61ac289a..6fdbcb8b 100644 --- a/lists/singlylinkedlist/enumerable.go +++ b/lists/singlylinkedlist/enumerable.go @@ -6,9 +6,8 @@ package singlylinkedlist import "github.com/emirpasic/gods/containers" -func assertEnumerableImplementation() { - var _ containers.EnumerableWithIndex = (*List)(nil) -} +// Assert Enumerable implementation +var _ containers.EnumerableWithIndex = (*List)(nil) // Each calls the given function once for each element, passing that element's index and value. func (list *List) Each(f func(index int, value interface{})) { diff --git a/lists/singlylinkedlist/iterator.go b/lists/singlylinkedlist/iterator.go index 5f25ff13..4e7f1773 100644 --- a/lists/singlylinkedlist/iterator.go +++ b/lists/singlylinkedlist/iterator.go @@ -6,9 +6,8 @@ package singlylinkedlist import "github.com/emirpasic/gods/containers" -func assertIteratorImplementation() { - var _ containers.IteratorWithIndex = (*Iterator)(nil) -} +// Assert Iterator implementation +var _ containers.IteratorWithIndex = (*Iterator)(nil) // Iterator holding the iterator's state type Iterator struct { diff --git a/lists/singlylinkedlist/serialization.go b/lists/singlylinkedlist/serialization.go index adcc5756..588a316c 100644 --- a/lists/singlylinkedlist/serialization.go +++ b/lists/singlylinkedlist/serialization.go @@ -9,10 +9,9 @@ import ( "github.com/emirpasic/gods/containers" ) -func assertSerializationImplementation() { - var _ containers.JSONSerializer = (*List)(nil) - var _ containers.JSONDeserializer = (*List)(nil) -} +// Assert Serialization implementation +var _ containers.JSONSerializer = (*List)(nil) +var _ containers.JSONDeserializer = (*List)(nil) // ToJSON outputs the JSON representation of list's elements. func (list *List) ToJSON() ([]byte, error) { diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index b61df78f..c3e2c675 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -17,9 +17,8 @@ import ( "github.com/emirpasic/gods/utils" ) -func assertListImplementation() { - var _ lists.List = (*List)(nil) -} +// Assert List implementation +var _ lists.List = (*List)(nil) // List holds the elements, where each element points to the next element type List struct { diff --git a/maps/hashbidimap/hashbidimap.go b/maps/hashbidimap/hashbidimap.go index 32985ab2..5a386ec7 100644 --- a/maps/hashbidimap/hashbidimap.go +++ b/maps/hashbidimap/hashbidimap.go @@ -21,9 +21,8 @@ import ( "github.com/emirpasic/gods/maps/hashmap" ) -func assertMapImplementation() { - var _ maps.BidiMap = (*Map)(nil) -} +// Assert Map implementation +var _ maps.BidiMap = (*Map)(nil) // Map holds the elements in two hashmaps. type Map struct { diff --git a/maps/hashbidimap/serialization.go b/maps/hashbidimap/serialization.go index dff78017..dfae0430 100644 --- a/maps/hashbidimap/serialization.go +++ b/maps/hashbidimap/serialization.go @@ -9,10 +9,9 @@ import ( "github.com/emirpasic/gods/containers" ) -func assertSerializationImplementation() { - var _ containers.JSONSerializer = (*Map)(nil) - var _ containers.JSONDeserializer = (*Map)(nil) -} +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Map)(nil) +var _ containers.JSONDeserializer = (*Map)(nil) // ToJSON outputs the JSON representation of the map. func (m *Map) ToJSON() ([]byte, error) { diff --git a/maps/hashmap/hashmap.go b/maps/hashmap/hashmap.go index 3f42ffc1..e945c39f 100644 --- a/maps/hashmap/hashmap.go +++ b/maps/hashmap/hashmap.go @@ -16,9 +16,8 @@ import ( "github.com/emirpasic/gods/maps" ) -func assertMapImplementation() { - var _ maps.Map = (*Map)(nil) -} +// Assert Map implementation +var _ maps.Map = (*Map)(nil) // Map holds the elements in go's native map type Map struct { diff --git a/maps/hashmap/serialization.go b/maps/hashmap/serialization.go index dc2e2598..a86fd864 100644 --- a/maps/hashmap/serialization.go +++ b/maps/hashmap/serialization.go @@ -10,10 +10,9 @@ import ( "github.com/emirpasic/gods/utils" ) -func assertSerializationImplementation() { - var _ containers.JSONSerializer = (*Map)(nil) - var _ containers.JSONDeserializer = (*Map)(nil) -} +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Map)(nil) +var _ containers.JSONDeserializer = (*Map)(nil) // ToJSON outputs the JSON representation of the map. func (m *Map) ToJSON() ([]byte, error) { diff --git a/maps/linkedhashmap/enumerable.go b/maps/linkedhashmap/enumerable.go index 644b00fd..eafcaa5d 100644 --- a/maps/linkedhashmap/enumerable.go +++ b/maps/linkedhashmap/enumerable.go @@ -6,9 +6,8 @@ package linkedhashmap import "github.com/emirpasic/gods/containers" -func assertEnumerableImplementation() { - var _ containers.EnumerableWithKey = (*Map)(nil) -} +// Assert Enumerable implementation +var _ containers.EnumerableWithKey = (*Map)(nil) // Each calls the given function once for each element, passing that element's key and value. func (m *Map) Each(f func(key interface{}, value interface{})) { diff --git a/maps/linkedhashmap/iterator.go b/maps/linkedhashmap/iterator.go index 17f3bb36..4c141780 100644 --- a/maps/linkedhashmap/iterator.go +++ b/maps/linkedhashmap/iterator.go @@ -9,9 +9,8 @@ import ( "github.com/emirpasic/gods/lists/doublylinkedlist" ) -func assertIteratorImplementation() { - var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) -} +// Assert Iterator implementation +var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) // Iterator holding the iterator's state type Iterator struct { diff --git a/maps/linkedhashmap/linkedhashmap.go b/maps/linkedhashmap/linkedhashmap.go index 45c4e35e..d625b3d7 100644 --- a/maps/linkedhashmap/linkedhashmap.go +++ b/maps/linkedhashmap/linkedhashmap.go @@ -18,9 +18,8 @@ import ( "strings" ) -func assertMapImplementation() { - var _ maps.Map = (*Map)(nil) -} +// Assert Map implementation +var _ maps.Map = (*Map)(nil) // Map holds the elements in a regular hash table, and uses doubly-linked list to store key ordering. type Map struct { diff --git a/maps/linkedhashmap/serialization.go b/maps/linkedhashmap/serialization.go index 805421d3..9265f1db 100644 --- a/maps/linkedhashmap/serialization.go +++ b/maps/linkedhashmap/serialization.go @@ -11,10 +11,9 @@ import ( "github.com/emirpasic/gods/utils" ) -func assertSerializationImplementation() { - var _ containers.JSONSerializer = (*Map)(nil) - var _ containers.JSONDeserializer = (*Map)(nil) -} +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Map)(nil) +var _ containers.JSONDeserializer = (*Map)(nil) // ToJSON outputs the JSON representation of map. func (m *Map) ToJSON() ([]byte, error) { diff --git a/maps/treebidimap/enumerable.go b/maps/treebidimap/enumerable.go index d5d829ab..8daef722 100644 --- a/maps/treebidimap/enumerable.go +++ b/maps/treebidimap/enumerable.go @@ -6,9 +6,8 @@ package treebidimap import "github.com/emirpasic/gods/containers" -func assertEnumerableImplementation() { - var _ containers.EnumerableWithKey = (*Map)(nil) -} +// Assert Enumerable implementation +var _ containers.EnumerableWithKey = (*Map)(nil) // Each calls the given function once for each element, passing that element's key and value. func (m *Map) Each(f func(key interface{}, value interface{})) { diff --git a/maps/treebidimap/iterator.go b/maps/treebidimap/iterator.go index 72e99831..9961a110 100644 --- a/maps/treebidimap/iterator.go +++ b/maps/treebidimap/iterator.go @@ -9,9 +9,8 @@ import ( rbt "github.com/emirpasic/gods/trees/redblacktree" ) -func assertIteratorImplementation() { - var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) -} +// Assert Iterator implementation +var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) // Iterator holding the iterator's state type Iterator struct { diff --git a/maps/treebidimap/serialization.go b/maps/treebidimap/serialization.go index e7ee0c20..2cccce64 100644 --- a/maps/treebidimap/serialization.go +++ b/maps/treebidimap/serialization.go @@ -10,10 +10,9 @@ import ( "github.com/emirpasic/gods/utils" ) -func assertSerializationImplementation() { - var _ containers.JSONSerializer = (*Map)(nil) - var _ containers.JSONDeserializer = (*Map)(nil) -} +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Map)(nil) +var _ containers.JSONDeserializer = (*Map)(nil) // ToJSON outputs the JSON representation of the map. func (m *Map) ToJSON() ([]byte, error) { diff --git a/maps/treebidimap/treebidimap.go b/maps/treebidimap/treebidimap.go index 87eff9f7..37af07e0 100644 --- a/maps/treebidimap/treebidimap.go +++ b/maps/treebidimap/treebidimap.go @@ -25,9 +25,8 @@ import ( "strings" ) -func assertMapImplementation() { - var _ maps.BidiMap = (*Map)(nil) -} +// Assert Map implementation +var _ maps.BidiMap = (*Map)(nil) // Map holds the elements in two red-black trees. type Map struct { diff --git a/maps/treemap/enumerable.go b/maps/treemap/enumerable.go index 8cea6d00..34b3704d 100644 --- a/maps/treemap/enumerable.go +++ b/maps/treemap/enumerable.go @@ -9,9 +9,8 @@ import ( rbt "github.com/emirpasic/gods/trees/redblacktree" ) -func assertEnumerableImplementation() { - var _ containers.EnumerableWithKey = (*Map)(nil) -} +// Assert Enumerable implementation +var _ containers.EnumerableWithKey = (*Map)(nil) // Each calls the given function once for each element, passing that element's key and value. func (m *Map) Each(f func(key interface{}, value interface{})) { diff --git a/maps/treemap/iterator.go b/maps/treemap/iterator.go index e7950a1c..becb56db 100644 --- a/maps/treemap/iterator.go +++ b/maps/treemap/iterator.go @@ -9,9 +9,8 @@ import ( rbt "github.com/emirpasic/gods/trees/redblacktree" ) -func assertIteratorImplementation() { - var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) -} +// Assert Iterator implementation +var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) // Iterator holding the iterator's state type Iterator struct { diff --git a/maps/treemap/serialization.go b/maps/treemap/serialization.go index 619a6a77..415a77dd 100644 --- a/maps/treemap/serialization.go +++ b/maps/treemap/serialization.go @@ -8,10 +8,9 @@ import ( "github.com/emirpasic/gods/containers" ) -func assertSerializationImplementation() { - var _ containers.JSONSerializer = (*Map)(nil) - var _ containers.JSONDeserializer = (*Map)(nil) -} +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Map)(nil) +var _ containers.JSONDeserializer = (*Map)(nil) // ToJSON outputs the JSON representation of the map. func (m *Map) ToJSON() ([]byte, error) { diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index a8e1dc5c..a77d16d8 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -19,9 +19,8 @@ import ( "strings" ) -func assertMapImplementation() { - var _ maps.Map = (*Map)(nil) -} +// Assert Map implementation +var _ maps.Map = (*Map)(nil) // Map holds the elements in a red-black tree type Map struct { diff --git a/sets/hashset/hashset.go b/sets/hashset/hashset.go index 558e628b..94399288 100644 --- a/sets/hashset/hashset.go +++ b/sets/hashset/hashset.go @@ -15,9 +15,8 @@ import ( "strings" ) -func assertSetImplementation() { - var _ sets.Set = (*Set)(nil) -} +// Assert Set implementation +var _ sets.Set = (*Set)(nil) // Set holds elements in go's native map type Set struct { diff --git a/sets/hashset/serialization.go b/sets/hashset/serialization.go index b0353e83..583d129d 100644 --- a/sets/hashset/serialization.go +++ b/sets/hashset/serialization.go @@ -9,10 +9,9 @@ import ( "github.com/emirpasic/gods/containers" ) -func assertSerializationImplementation() { - var _ containers.JSONSerializer = (*Set)(nil) - var _ containers.JSONDeserializer = (*Set)(nil) -} +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Set)(nil) +var _ containers.JSONDeserializer = (*Set)(nil) // ToJSON outputs the JSON representation of the set. func (set *Set) ToJSON() ([]byte, error) { diff --git a/sets/linkedhashset/enumerable.go b/sets/linkedhashset/enumerable.go index ad6ac967..fc855722 100644 --- a/sets/linkedhashset/enumerable.go +++ b/sets/linkedhashset/enumerable.go @@ -6,9 +6,8 @@ package linkedhashset import "github.com/emirpasic/gods/containers" -func assertEnumerableImplementation() { - var _ containers.EnumerableWithIndex = (*Set)(nil) -} +// Assert Enumerable implementation +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{})) { diff --git a/sets/linkedhashset/iterator.go b/sets/linkedhashset/iterator.go index 5aa176c9..aa793841 100644 --- a/sets/linkedhashset/iterator.go +++ b/sets/linkedhashset/iterator.go @@ -9,9 +9,8 @@ import ( "github.com/emirpasic/gods/lists/doublylinkedlist" ) -func assertIteratorImplementation() { - var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) -} +// Assert Iterator implementation +var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) // Iterator holding the iterator's state type Iterator struct { diff --git a/sets/linkedhashset/linkedhashset.go b/sets/linkedhashset/linkedhashset.go index e028591e..3bf4e5fe 100644 --- a/sets/linkedhashset/linkedhashset.go +++ b/sets/linkedhashset/linkedhashset.go @@ -20,9 +20,8 @@ import ( "strings" ) -func assertSetImplementation() { - var _ sets.Set = (*Set)(nil) -} +// Assert Set implementation +var _ sets.Set = (*Set)(nil) // Set holds elements in go's native map type Set struct { diff --git a/sets/linkedhashset/serialization.go b/sets/linkedhashset/serialization.go index 33b3fefd..ab2f3b4d 100644 --- a/sets/linkedhashset/serialization.go +++ b/sets/linkedhashset/serialization.go @@ -9,10 +9,9 @@ import ( "github.com/emirpasic/gods/containers" ) -func assertSerializationImplementation() { - var _ containers.JSONSerializer = (*Set)(nil) - var _ containers.JSONDeserializer = (*Set)(nil) -} +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Set)(nil) +var _ containers.JSONDeserializer = (*Set)(nil) // ToJSON outputs the JSON representation of the set. func (set *Set) ToJSON() ([]byte, error) { diff --git a/sets/treeset/enumerable.go b/sets/treeset/enumerable.go index 59a0913a..c774834a 100644 --- a/sets/treeset/enumerable.go +++ b/sets/treeset/enumerable.go @@ -9,9 +9,8 @@ import ( rbt "github.com/emirpasic/gods/trees/redblacktree" ) -func assertEnumerableImplementation() { - var _ containers.EnumerableWithIndex = (*Set)(nil) -} +// Assert Enumerable implementation +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{})) { diff --git a/sets/treeset/iterator.go b/sets/treeset/iterator.go index 377d8b69..88a0bea7 100644 --- a/sets/treeset/iterator.go +++ b/sets/treeset/iterator.go @@ -9,9 +9,8 @@ import ( rbt "github.com/emirpasic/gods/trees/redblacktree" ) -func assertIteratorImplementation() { - var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) -} +// Assert Iterator implementation +var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. type Iterator struct { diff --git a/sets/treeset/serialization.go b/sets/treeset/serialization.go index a17eb780..76d049dd 100644 --- a/sets/treeset/serialization.go +++ b/sets/treeset/serialization.go @@ -9,10 +9,9 @@ import ( "github.com/emirpasic/gods/containers" ) -func assertSerializationImplementation() { - var _ containers.JSONSerializer = (*Set)(nil) - var _ containers.JSONDeserializer = (*Set)(nil) -} +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Set)(nil) +var _ containers.JSONDeserializer = (*Set)(nil) // ToJSON outputs the JSON representation of the set. func (set *Set) ToJSON() ([]byte, error) { diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 7e7d1d68..3507cc90 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -18,9 +18,8 @@ import ( "strings" ) -func assertSetImplementation() { - var _ sets.Set = (*Set)(nil) -} +// Assert Set implementation +var _ sets.Set = (*Set)(nil) // Set holds elements in a red-black tree type Set struct { diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index 9a971e98..78c3dda3 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -16,9 +16,8 @@ import ( "strings" ) -func assertStackImplementation() { - var _ stacks.Stack = (*Stack)(nil) -} +// Assert Stack implementation +var _ stacks.Stack = (*Stack)(nil) // Stack holds elements in an array-list type Stack struct { diff --git a/stacks/arraystack/iterator.go b/stacks/arraystack/iterator.go index df592f0e..c01d7c8b 100644 --- a/stacks/arraystack/iterator.go +++ b/stacks/arraystack/iterator.go @@ -6,9 +6,8 @@ package arraystack import "github.com/emirpasic/gods/containers" -func assertIteratorImplementation() { - var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) -} +// Assert Iterator implementation +var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. type Iterator struct { diff --git a/stacks/arraystack/serialization.go b/stacks/arraystack/serialization.go index 1456c9ec..e65889fb 100644 --- a/stacks/arraystack/serialization.go +++ b/stacks/arraystack/serialization.go @@ -8,10 +8,9 @@ import ( "github.com/emirpasic/gods/containers" ) -func assertSerializationImplementation() { - var _ containers.JSONSerializer = (*Stack)(nil) - var _ containers.JSONDeserializer = (*Stack)(nil) -} +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Stack)(nil) +var _ containers.JSONDeserializer = (*Stack)(nil) // ToJSON outputs the JSON representation of the stack. func (stack *Stack) ToJSON() ([]byte, error) { diff --git a/stacks/linkedliststack/iterator.go b/stacks/linkedliststack/iterator.go index 875f922b..dea086b1 100644 --- a/stacks/linkedliststack/iterator.go +++ b/stacks/linkedliststack/iterator.go @@ -6,9 +6,8 @@ package linkedliststack import "github.com/emirpasic/gods/containers" -func assertIteratorImplementation() { - var _ containers.IteratorWithIndex = (*Iterator)(nil) -} +// Assert Iterator implementation +var _ containers.IteratorWithIndex = (*Iterator)(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. type Iterator struct { diff --git a/stacks/linkedliststack/linkedliststack.go b/stacks/linkedliststack/linkedliststack.go index da5bf2f7..ce69b212 100644 --- a/stacks/linkedliststack/linkedliststack.go +++ b/stacks/linkedliststack/linkedliststack.go @@ -16,9 +16,8 @@ import ( "strings" ) -func assertStackImplementation() { - var _ stacks.Stack = (*Stack)(nil) -} +// Assert Stack implementation +var _ stacks.Stack = (*Stack)(nil) // Stack holds elements in a singly-linked-list type Stack struct { diff --git a/stacks/linkedliststack/serialization.go b/stacks/linkedliststack/serialization.go index 3beb7a80..a82b768c 100644 --- a/stacks/linkedliststack/serialization.go +++ b/stacks/linkedliststack/serialization.go @@ -8,10 +8,9 @@ import ( "github.com/emirpasic/gods/containers" ) -func assertSerializationImplementation() { - var _ containers.JSONSerializer = (*Stack)(nil) - var _ containers.JSONDeserializer = (*Stack)(nil) -} +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Stack)(nil) +var _ containers.JSONDeserializer = (*Stack)(nil) // ToJSON outputs the JSON representation of the stack. func (stack *Stack) ToJSON() ([]byte, error) { diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index fd1a4053..128d3133 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -15,9 +15,8 @@ import ( "github.com/emirpasic/gods/utils" ) -func assertTreeImplementation() { - var _ trees.Tree = new(Tree) -} +// Assert Tree implementation +var _ trees.Tree = new(Tree) // Tree holds elements of the AVL tree. type Tree struct { diff --git a/trees/avltree/iterator.go b/trees/avltree/iterator.go index c4d69f4d..0186e40b 100644 --- a/trees/avltree/iterator.go +++ b/trees/avltree/iterator.go @@ -6,9 +6,8 @@ package avltree import "github.com/emirpasic/gods/containers" -func assertIteratorImplementation() { - var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) -} +// Assert Iterator implementation +var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) // Iterator holding the iterator's state type Iterator struct { diff --git a/trees/avltree/serialization.go b/trees/avltree/serialization.go index 1ccd4a81..257c4040 100644 --- a/trees/avltree/serialization.go +++ b/trees/avltree/serialization.go @@ -10,10 +10,9 @@ import ( "github.com/emirpasic/gods/utils" ) -func assertSerializationImplementation() { - var _ containers.JSONSerializer = (*Tree)(nil) - var _ containers.JSONDeserializer = (*Tree)(nil) -} +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Tree)(nil) +var _ containers.JSONDeserializer = (*Tree)(nil) // ToJSON outputs the JSON representation of the tree. func (tree *Tree) ToJSON() ([]byte, error) { diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index 70b28cf5..b3412c5f 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -19,9 +19,8 @@ import ( "strings" ) -func assertTreeImplementation() { - var _ trees.Tree = (*Heap)(nil) -} +// Assert Tree implementation +var _ trees.Tree = (*Heap)(nil) // Heap holds elements in an array-list type Heap struct { diff --git a/trees/binaryheap/iterator.go b/trees/binaryheap/iterator.go index 343fa52c..8a01b05b 100644 --- a/trees/binaryheap/iterator.go +++ b/trees/binaryheap/iterator.go @@ -6,9 +6,8 @@ package binaryheap import "github.com/emirpasic/gods/containers" -func assertIteratorImplementation() { - var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) -} +// Assert Iterator implementation +var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. type Iterator struct { diff --git a/trees/binaryheap/serialization.go b/trees/binaryheap/serialization.go index 30ccb250..c1fce0a0 100644 --- a/trees/binaryheap/serialization.go +++ b/trees/binaryheap/serialization.go @@ -8,10 +8,9 @@ import ( "github.com/emirpasic/gods/containers" ) -func assertSerializationImplementation() { - var _ containers.JSONSerializer = (*Heap)(nil) - var _ containers.JSONDeserializer = (*Heap)(nil) -} +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Heap)(nil) +var _ containers.JSONDeserializer = (*Heap)(nil) // ToJSON outputs the JSON representation of the heap. func (heap *Heap) ToJSON() ([]byte, error) { diff --git a/trees/btree/btree.go b/trees/btree/btree.go index 523358ad..bb36f93a 100644 --- a/trees/btree/btree.go +++ b/trees/btree/btree.go @@ -24,9 +24,8 @@ import ( "strings" ) -func assertTreeImplementation() { - var _ trees.Tree = (*Tree)(nil) -} +// Assert Tree implementation +var _ trees.Tree = (*Tree)(nil) // Tree holds elements of the B-tree type Tree struct { diff --git a/trees/btree/iterator.go b/trees/btree/iterator.go index c74b6464..fb20955a 100644 --- a/trees/btree/iterator.go +++ b/trees/btree/iterator.go @@ -6,9 +6,8 @@ package btree import "github.com/emirpasic/gods/containers" -func assertIteratorImplementation() { - var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) -} +// Assert Iterator implementation +var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) // Iterator holding the iterator's state type Iterator struct { diff --git a/trees/btree/serialization.go b/trees/btree/serialization.go index 5ff71751..460f6e0b 100644 --- a/trees/btree/serialization.go +++ b/trees/btree/serialization.go @@ -10,10 +10,9 @@ import ( "github.com/emirpasic/gods/utils" ) -func assertSerializationImplementation() { - var _ containers.JSONSerializer = (*Tree)(nil) - var _ containers.JSONDeserializer = (*Tree)(nil) -} +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Tree)(nil) +var _ containers.JSONDeserializer = (*Tree)(nil) // ToJSON outputs the JSON representation of the tree. func (tree *Tree) ToJSON() ([]byte, error) { diff --git a/trees/redblacktree/iterator.go b/trees/redblacktree/iterator.go index ce9bcaf1..e39da7d4 100644 --- a/trees/redblacktree/iterator.go +++ b/trees/redblacktree/iterator.go @@ -6,9 +6,8 @@ package redblacktree import "github.com/emirpasic/gods/containers" -func assertIteratorImplementation() { - var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) -} +// Assert Iterator implementation +var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) // Iterator holding the iterator's state type Iterator struct { diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index cce9fe0a..b335e3df 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -17,9 +17,8 @@ import ( "github.com/emirpasic/gods/utils" ) -func assertTreeImplementation() { - var _ trees.Tree = (*Tree)(nil) -} +// Assert Tree implementation +var _ trees.Tree = (*Tree)(nil) type color bool diff --git a/trees/redblacktree/serialization.go b/trees/redblacktree/serialization.go index da137771..9f2a23c0 100644 --- a/trees/redblacktree/serialization.go +++ b/trees/redblacktree/serialization.go @@ -10,10 +10,9 @@ import ( "github.com/emirpasic/gods/utils" ) -func assertSerializationImplementation() { - var _ containers.JSONSerializer = (*Tree)(nil) - var _ containers.JSONDeserializer = (*Tree)(nil) -} +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Tree)(nil) +var _ containers.JSONDeserializer = (*Tree)(nil) // ToJSON outputs the JSON representation of the tree. func (tree *Tree) ToJSON() ([]byte, error) { From 41012c6c58efc30f16d70f087c04c10255cbf8cf Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 16:52:21 +0200 Subject: [PATCH 288/320] Improve code coverage --- containers/containers_test.go | 2 + lists/arraylist/arraylist_test.go | 13 +++ .../doublylinkedlist/doublylinkedlist_test.go | 35 ++++++++ .../singlylinkedlist/singlylinkedlist_test.go | 35 ++++++++ maps/hashbidimap/hashbidimap_test.go | 14 ++++ maps/hashmap/hashmap_test.go | 14 ++++ maps/linkedhashmap/linkedhashmap_test.go | 13 +++ maps/treebidimap/treebidimap_test.go | 13 +++ maps/treemap/treemap_test.go | 83 ++++++++++++++++++- sets/hashset/hashset_test.go | 14 ++++ sets/linkedhashset/linkedhashset_test.go | 13 +++ sets/treeset/treeset_test.go | 13 +++ stacks/arraystack/arraystack_test.go | 19 +++++ .../linkedliststack/linkedliststack_test.go | 13 +++ trees/avltree/avltree_test.go | 26 +++++- trees/binaryheap/binaryheap_test.go | 13 +++ trees/btree/btree_test.go | 13 +++ trees/redblacktree/redblacktree_test.go | 16 +++- 18 files changed, 359 insertions(+), 3 deletions(-) diff --git a/containers/containers_test.go b/containers/containers_test.go index 60e0332e..e92d123d 100644 --- a/containers/containers_test.go +++ b/containers/containers_test.go @@ -46,6 +46,7 @@ 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) for i := 1; i < container.Size(); i++ { @@ -57,6 +58,7 @@ func TestGetSortedValuesInts(t *testing.T) { 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) for i := 1; i < container.Size(); i++ { diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 2a704d17..d490ba70 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -631,6 +631,19 @@ func TestListSerialization(t *testing.T) { if err != nil { t.Errorf("Got error %v", err) } + + err = json.Unmarshal([]byte(`[1,2,3]`), &list) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestListString(t *testing.T) { + c := New() + c.Add(1) + if !strings.HasPrefix(c.String(), "ArrayList") { + t.Errorf("String should start with container name") + } } func benchmarkGet(b *testing.B, list *List, size int) { diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 911da774..a69c6999 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -54,6 +54,28 @@ func TestListAdd(t *testing.T) { } } +func TestListAppendAndPrepend(t *testing.T) { + list := New() + list.Add("b") + list.Prepend("a") + list.Append("c") + if actualValue := list.Empty(); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, false) + } + if actualValue := list.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := list.Get(0); actualValue != "a" || !ok { + t.Errorf("Got %v expected %v", actualValue, "c") + } + if actualValue, ok := list.Get(1); actualValue != "b" || !ok { + t.Errorf("Got %v expected %v", actualValue, "c") + } + if actualValue, ok := list.Get(2); actualValue != "c" || !ok { + t.Errorf("Got %v expected %v", actualValue, "c") + } +} + func TestListRemove(t *testing.T) { list := New() list.Add("a") @@ -637,6 +659,19 @@ func TestListSerialization(t *testing.T) { if err != nil { t.Errorf("Got error %v", err) } + + err = json.Unmarshal([]byte(`[1,2,3]`), &list) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestListString(t *testing.T) { + c := New() + c.Add(1) + if !strings.HasPrefix(c.String(), "DoublyLinkedList") { + t.Errorf("String should start with container name") + } } func benchmarkGet(b *testing.B, list *List, size int) { diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index 97eb78bb..4d58b7d5 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -54,6 +54,28 @@ func TestListAdd(t *testing.T) { } } +func TestListAppendAndPrepend(t *testing.T) { + list := New() + list.Add("b") + list.Prepend("a") + list.Append("c") + if actualValue := list.Empty(); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, false) + } + if actualValue := list.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := list.Get(0); actualValue != "a" || !ok { + t.Errorf("Got %v expected %v", actualValue, "c") + } + if actualValue, ok := list.Get(1); actualValue != "b" || !ok { + t.Errorf("Got %v expected %v", actualValue, "c") + } + if actualValue, ok := list.Get(2); actualValue != "c" || !ok { + t.Errorf("Got %v expected %v", actualValue, "c") + } +} + func TestListRemove(t *testing.T) { list := New() list.Add("a") @@ -500,6 +522,19 @@ func TestListSerialization(t *testing.T) { if err != nil { t.Errorf("Got error %v", err) } + + err = json.Unmarshal([]byte(`[1,2,3]`), &list) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestListString(t *testing.T) { + c := New() + c.Add(1) + if !strings.HasPrefix(c.String(), "SinglyLinkedList") { + t.Errorf("String should start with container name") + } } func benchmarkGet(b *testing.B, list *List, size int) { diff --git a/maps/hashbidimap/hashbidimap_test.go b/maps/hashbidimap/hashbidimap_test.go index 8b607f44..dd911165 100644 --- a/maps/hashbidimap/hashbidimap_test.go +++ b/maps/hashbidimap/hashbidimap_test.go @@ -7,6 +7,7 @@ package hashbidimap import ( "encoding/json" "fmt" + "strings" "testing" ) @@ -185,6 +186,19 @@ func TestMapSerialization(t *testing.T) { if err != nil { t.Errorf("Got error %v", err) } + + err = json.Unmarshal([]byte(`{"a":1,"b":2}`), &m) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestMapString(t *testing.T) { + c := New() + c.Put("a", 1) + if !strings.HasPrefix(c.String(), "HashBidiMap") { + t.Errorf("String should start with container name") + } } func sameElements(a []interface{}, b []interface{}) bool { diff --git a/maps/hashmap/hashmap_test.go b/maps/hashmap/hashmap_test.go index 14966806..91acca8d 100644 --- a/maps/hashmap/hashmap_test.go +++ b/maps/hashmap/hashmap_test.go @@ -7,6 +7,7 @@ package hashmap import ( "encoding/json" "fmt" + "strings" "testing" ) @@ -153,6 +154,19 @@ func TestMapSerialization(t *testing.T) { if err != nil { t.Errorf("Got error %v", err) } + + err = json.Unmarshal([]byte(`{"a":1,"b":2}`), &m) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestMapString(t *testing.T) { + c := New() + c.Put("a", 1) + if !strings.HasPrefix(c.String(), "HashMap") { + t.Errorf("String should start with container name") + } } func sameElements(a []interface{}, b []interface{}) bool { diff --git a/maps/linkedhashmap/linkedhashmap_test.go b/maps/linkedhashmap/linkedhashmap_test.go index ac7b9940..ca44792c 100644 --- a/maps/linkedhashmap/linkedhashmap_test.go +++ b/maps/linkedhashmap/linkedhashmap_test.go @@ -582,6 +582,19 @@ func TestMapSerialization(t *testing.T) { if err != nil { t.Errorf("Got error %v", err) } + + err = json.Unmarshal([]byte(`{"a":1,"b":2}`), &m) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestMapString(t *testing.T) { + c := New() + c.Put("a", 1) + if !strings.HasPrefix(c.String(), "LinkedHashMap") { + t.Errorf("String should start with container name") + } } //noinspection GoBoolExpressions diff --git a/maps/treebidimap/treebidimap_test.go b/maps/treebidimap/treebidimap_test.go index acd32700..75296e80 100644 --- a/maps/treebidimap/treebidimap_test.go +++ b/maps/treebidimap/treebidimap_test.go @@ -615,6 +615,19 @@ func TestMapSerialization(t *testing.T) { if err != nil { t.Errorf("Got error %v", err) } + + err = json.Unmarshal([]byte(`{"a":1,"b":2}`), &m) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestMapString(t *testing.T) { + c := NewWithStringComparators() + c.Put("a", "a") + if !strings.HasPrefix(c.String(), "TreeBidiMap") { + t.Errorf("String should start with container name") + } } //noinspection GoBoolExpressions diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index 92e96124..f0c96baa 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -7,12 +7,13 @@ package treemap import ( "encoding/json" "fmt" + "github.com/emirpasic/gods/utils" "strings" "testing" ) func TestMapPut(t *testing.T) { - m := NewWithIntComparator() + m := NewWith(utils.IntComparator) m.Put(5, "e") m.Put(6, "f") m.Put(7, "g") @@ -53,6 +54,73 @@ func TestMapPut(t *testing.T) { } } +func TestMapMin(t *testing.T) { + m := NewWithIntComparator() + + if k, v := m.Min(); k != nil || v != nil { + t.Errorf("Got %v->%v expected %v->%v", k, v, nil, nil) + } + + m.Put(5, "e") + m.Put(6, "f") + m.Put(7, "g") + m.Put(3, "c") + m.Put(4, "d") + m.Put(1, "x") + m.Put(2, "b") + m.Put(1, "a") //overwrite + + actualKey, actualValue := m.Min() + expectedKey, expectedValue := 1, "a" + if actualKey != expectedKey { + t.Errorf("Got %v expected %v", actualKey, expectedKey) + } + if actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + +func TestMapMax(t *testing.T) { + m := NewWithIntComparator() + + if k, v := m.Max(); k != nil || v != nil { + t.Errorf("Got %v->%v expected %v->%v", k, v, nil, nil) + } + + m.Put(5, "e") + m.Put(6, "f") + m.Put(7, "g") + m.Put(3, "c") + m.Put(4, "d") + m.Put(1, "x") + m.Put(2, "b") + m.Put(1, "a") //overwrite + + actualKey, actualValue := m.Max() + expectedKey, expectedValue := 7, "g" + if actualKey != expectedKey { + t.Errorf("Got %v expected %v", actualKey, expectedKey) + } + if actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + +func TestMapClear(t *testing.T) { + m := NewWithIntComparator() + m.Put(5, "e") + m.Put(6, "f") + m.Put(7, "g") + m.Put(3, "c") + if actualValue, expectedValue := m.Size(), 4; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + m.Clear() + if actualValue, expectedValue := m.Size(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + func TestMapRemove(t *testing.T) { m := NewWithIntComparator() m.Put(5, "e") @@ -638,6 +706,19 @@ func TestMapSerialization(t *testing.T) { if err != nil { t.Errorf("Got error %v", err) } + + err = json.Unmarshal([]byte(`{"a":1,"b":2}`), &m) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestMapString(t *testing.T) { + c := NewWithStringComparator() + c.Put("a", 1) + if !strings.HasPrefix(c.String(), "TreeMap") { + t.Errorf("String should start with container name") + } } //noinspection GoBoolExpressions diff --git a/sets/hashset/hashset_test.go b/sets/hashset/hashset_test.go index ccb50b3c..fe516b79 100644 --- a/sets/hashset/hashset_test.go +++ b/sets/hashset/hashset_test.go @@ -6,6 +6,7 @@ package hashset import ( "encoding/json" + "strings" "testing" ) @@ -109,6 +110,19 @@ func TestSetSerialization(t *testing.T) { if err != nil { t.Errorf("Got error %v", err) } + + err = json.Unmarshal([]byte(`[1,2,3]`), &set) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestSetString(t *testing.T) { + c := New() + c.Add(1) + if !strings.HasPrefix(c.String(), "HashSet") { + t.Errorf("String should start with container name") + } } func TestSetIntersection(t *testing.T) { diff --git a/sets/linkedhashset/linkedhashset_test.go b/sets/linkedhashset/linkedhashset_test.go index 7e3c2368..3f857ea9 100644 --- a/sets/linkedhashset/linkedhashset_test.go +++ b/sets/linkedhashset/linkedhashset_test.go @@ -463,6 +463,19 @@ func TestSetSerialization(t *testing.T) { if err != nil { t.Errorf("Got error %v", err) } + + err = json.Unmarshal([]byte(`[1,2,3]`), &set) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestSetString(t *testing.T) { + c := New() + c.Add(1) + if !strings.HasPrefix(c.String(), "LinkedHashSet") { + t.Errorf("String should start with container name") + } } func TestSetIntersection(t *testing.T) { diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index 2839d4b2..9e7c6707 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -472,6 +472,19 @@ func TestSetSerialization(t *testing.T) { if err != nil { t.Errorf("Got error %v", err) } + + err = json.Unmarshal([]byte(`["1","2","3"]`), &set) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestSetString(t *testing.T) { + c := NewWithIntComparator() + c.Add(1) + if !strings.HasPrefix(c.String(), "TreeSet") { + t.Errorf("String should start with container name") + } } func TestSetIntersection(t *testing.T) { diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index d15e7eb0..eba42870 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -116,6 +116,12 @@ func TestStackIteratorNext(t *testing.T) { if actualValue, expectedValue := count, 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } + + stack.Clear() + it = stack.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty stack") + } } func TestStackIteratorPrev(t *testing.T) { @@ -371,6 +377,19 @@ func TestStackSerialization(t *testing.T) { if err != nil { t.Errorf("Got error %v", err) } + + err = json.Unmarshal([]byte(`[1,2,3]`), &stack) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestStackString(t *testing.T) { + c := New() + c.Push(1) + if !strings.HasPrefix(c.String(), "ArrayStack") { + t.Errorf("String should start with container name") + } } func benchmarkPush(b *testing.B, stack *Stack, size int) { diff --git a/stacks/linkedliststack/linkedliststack_test.go b/stacks/linkedliststack/linkedliststack_test.go index 6b34e39c..f491fd3a 100644 --- a/stacks/linkedliststack/linkedliststack_test.go +++ b/stacks/linkedliststack/linkedliststack_test.go @@ -233,6 +233,19 @@ func TestStackSerialization(t *testing.T) { if err != nil { t.Errorf("Got error %v", err) } + + err = json.Unmarshal([]byte(`[1,2,3]`), &stack) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestStackString(t *testing.T) { + c := New() + c.Push(1) + if !strings.HasPrefix(c.String(), "LinkedListStack") { + t.Errorf("String should start with container name") + } } func benchmarkPush(b *testing.B, stack *Stack, size int) { diff --git a/trees/avltree/avltree_test.go b/trees/avltree/avltree_test.go index 37bdd2f6..ce27d6aa 100644 --- a/trees/avltree/avltree_test.go +++ b/trees/avltree/avltree_test.go @@ -6,6 +6,7 @@ package avltree import ( "encoding/json" "fmt" + "github.com/emirpasic/gods/utils" "strings" "testing" ) @@ -263,6 +264,7 @@ func TestAVLTreeIterator1Next(t *testing.T) { // └── 2 // └── 1 it := tree.Iterator() + count := 0 for it.Next() { count++ @@ -709,7 +711,8 @@ func TestAVLTreeIteratorPrevTo(t *testing.T) { } func TestAVLTreeSerialization(t *testing.T) { - tree := NewWithStringComparator() + tree := NewWith(utils.StringComparator) + tree = NewWithStringComparator() tree.Put("c", "3") tree.Put("b", "2") tree.Put("a", "1") @@ -742,6 +745,27 @@ func TestAVLTreeSerialization(t *testing.T) { if err != nil { t.Errorf("Got error %v", err) } + + err = json.Unmarshal([]byte(`{"a":1,"b":2}`), &tree) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestAVLTreeString(t *testing.T) { + c := NewWithIntComparator() + c.Put(1, 1) + c.Put(2, 1) + c.Put(3, 1) + c.Put(4, 1) + c.Put(5, 1) + c.Put(6, 1) + c.Put(7, 1) + c.Put(8, 1) + + if !strings.HasPrefix(c.String(), "AVLTree") { + t.Errorf("String should start with container name") + } } func benchmarkGet(b *testing.B, tree *Tree, size int) { diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go index e14794f1..26d99ea9 100644 --- a/trees/binaryheap/binaryheap_test.go +++ b/trees/binaryheap/binaryheap_test.go @@ -402,6 +402,19 @@ func TestBinaryHeapSerialization(t *testing.T) { if err != nil { t.Errorf("Got error %v", err) } + + err = json.Unmarshal([]byte(`[1,2,3]`), &heap) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestBTreeString(t *testing.T) { + c := NewWithIntComparator() + c.Push(1) + if !strings.HasPrefix(c.String(), "BinaryHeap") { + t.Errorf("String should start with container name") + } } func benchmarkPush(b *testing.B, heap *Heap, size int) { diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index 49c6ab5d..f8b6e615 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -1262,6 +1262,19 @@ func TestBTreeSerialization(t *testing.T) { if err != nil { t.Errorf("Got error %v", err) } + + err = json.Unmarshal([]byte(`{"a":1,"b":2}`), &tree) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestBTreeString(t *testing.T) { + c := NewWithStringComparator(3) + c.Put("a", 1) + if !strings.HasPrefix(c.String(), "BTree") { + t.Errorf("String should start with container name") + } } func benchmarkGet(b *testing.B, tree *Tree, size int) { diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index c717648c..5de39b65 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -7,6 +7,7 @@ package redblacktree import ( "encoding/json" "fmt" + "github.com/emirpasic/gods/utils" "strings" "testing" ) @@ -200,7 +201,7 @@ func TestRedBlackTreeLeftAndRight(t *testing.T) { } func TestRedBlackTreeCeilingAndFloor(t *testing.T) { - tree := NewWithIntComparator() + tree := NewWith(utils.IntComparator) if node, found := tree.Floor(0); node != nil || found { t.Errorf("Got %v expected %v", node, "") @@ -745,6 +746,19 @@ func TestRedBlackTreeSerialization(t *testing.T) { if err != nil { t.Errorf("Got error %v", err) } + + err = json.Unmarshal([]byte(`{"a":1,"b":2}`), &tree) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestRedBlackTreeString(t *testing.T) { + c := NewWithStringComparator() + c.Put("a", 1) + if !strings.HasPrefix(c.String(), "RedBlackTree") { + t.Errorf("String should start with container name") + } } func benchmarkGet(b *testing.B, tree *Tree, size int) { From 92b8f18bff460e28795ede089f37e6fa9c60dc0b Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 17:06:48 +0200 Subject: [PATCH 289/320] Integrate sourcegraph badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ebc0b544..e595950f 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![Build Status](https://circleci.com/gh/emirpasic/gods/tree/master.svg?style=shield)](https://circleci.com/gh/emirpasic/gods?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/emirpasic/gods)](https://goreportcard.com/report/github.com/emirpasic/gods) [![codecov](https://codecov.io/gh/emirpasic/gods/branch/master/graph/badge.svg)](https://codecov.io/gh/emirpasic/gods) +[![Sourcegraph](https://sourcegraph.com/github.com/emirpasic/gods/-/badge.svg)](https://sourcegraph.com/github.com/emirpasic/gods?badge) [![PyPI](https://img.shields.io/badge/License-BSD_2--Clause-green.svg)](https://github.com/emirpasic/gods/blob/master/LICENSE) # GoDS (Go Data Structures) From 05959cbe35254bfcd83f6f267d6b3abf767e1fc1 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 17:10:29 +0200 Subject: [PATCH 290/320] Add release badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e595950f..987e02a0 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![Go Report Card](https://goreportcard.com/badge/github.com/emirpasic/gods)](https://goreportcard.com/report/github.com/emirpasic/gods) [![codecov](https://codecov.io/gh/emirpasic/gods/branch/master/graph/badge.svg)](https://codecov.io/gh/emirpasic/gods) [![Sourcegraph](https://sourcegraph.com/github.com/emirpasic/gods/-/badge.svg)](https://sourcegraph.com/github.com/emirpasic/gods?badge) +[![Release](https://img.shields.io/github/release/emirpasic/gods.svg?style=flat-square)](https://github.com/emirpasic/gods/releases) [![PyPI](https://img.shields.io/badge/License-BSD_2--Clause-green.svg)](https://github.com/emirpasic/gods/blob/master/LICENSE) # GoDS (Go Data Structures) From 08ae1866404490e7052071d3c6f06397c16db44c Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 18:51:34 +0200 Subject: [PATCH 291/320] Create dependabot.yml --- .github/dependabot.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..b9f86196 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +# Ref: https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "daily" From f70d3dd117a972e75079e216206c2b565c2f7394 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 19:04:55 +0200 Subject: [PATCH 292/320] Create codeql-analysis.yml --- .github/workflows/codeql-analysis.yml | 70 +++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000..d0649bf9 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,70 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] + schedule: + - cron: '30 4 * * 5' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'go' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://git.io/codeql-language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 From 6356a9e470526088021889594560fe7c8335dbbb Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 19:25:13 +0200 Subject: [PATCH 293/320] Create sonarcloud.yml --- .github/workflows/sonarcloud.yml | 68 ++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 .github/workflows/sonarcloud.yml diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml new file mode 100644 index 00000000..1b59cd31 --- /dev/null +++ b/.github/workflows/sonarcloud.yml @@ -0,0 +1,68 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +# This workflow helps you trigger a SonarCloud analysis of your code and populates +# GitHub Code Scanning alerts with the vulnerabilities found. +# Free for open source project. + +# 1. Login to SonarCloud.io using your GitHub account + +# 2. Import your project on SonarCloud +# * Add your GitHub organization first, then add your repository as a new project. +# * Please note that many languages are eligible for automatic analysis, +# which means that the analysis will start automatically without the need to set up GitHub Actions. +# * This behavior can be changed in Administration > Analysis Method. +# +# 3. Follow the SonarCloud in-product tutorial +# * a. Copy/paste the Project Key and the Organization Key into the args parameter below +# (You'll find this information in SonarCloud. Click on "Information" at the bottom left) +# +# * b. Generate a new token and add it to your Github repository's secrets using the name SONAR_TOKEN +# (On SonarCloud, click on your avatar on top-right > My account > Security +# or go directly to https://sonarcloud.io/account/security/) + +# Feel free to take a look at our documentation (https://docs.sonarcloud.io/getting-started/github/) +# or reach out to our community forum if you need some help (https://community.sonarsource.com/c/help/sc/9) + +name: SonarCloud analysis + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + workflow_dispatch: + +permissions: + pull-requests: read # allows SonarCloud to decorate PRs with analysis results + +jobs: + Analysis: + runs-on: ubuntu-latest + + steps: + - name: Analyze with SonarCloud + + # You can pin the exact commit or the version. + # uses: SonarSource/sonarcloud-github-action@de2e56b42aa84d0b1c5b622644ac17e505c9a049 + uses: SonarSource/sonarcloud-github-action@de2e56b42aa84d0b1c5b622644ac17e505c9a049 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} # Generate a token on Sonarcloud.io, add it to the secrets of this repo with the name SONAR_TOKEN (Settings > Secrets > Actions > add new repository secret) + with: + # Additional arguments for the sonarcloud scanner + args: + # Unique keys of your project and organization. You can find them in SonarCloud > Information (bottom-left menu) + # mandatory + -Dsonar.projectKey=gods + -Dsonar.organization=emirpasic + # Comma-separated paths to directories containing main source files. + #-Dsonar.sources= # optional, default is project base directory + # When you need the analysis to take place in a directory other than the one from which it was launched + #-Dsonar.projectBaseDir= # optional, default is . + # Comma-separated paths to directories containing test source files. + #-Dsonar.tests= # optional. For more info about Code Coverage, please refer to https://docs.sonarcloud.io/enriching/test-coverage/overview/ + # Adds more detail to both client and server-side analysis logs, activating DEBUG mode for the scanner, and adding client-side environment variables and system properties to the server-side log of analysis report processing. + #-Dsonar.verbose= # optional, default is false From 1dd397e12cd5073097e648c53e0481f2a049c600 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 19:40:28 +0200 Subject: [PATCH 294/320] SonarQube fixes --- trees/avltree/avltree_test.go | 88 +++++-------------------- trees/btree/btree_test.go | 88 +++++-------------------- trees/redblacktree/redblacktree_test.go | 88 +++++-------------------- 3 files changed, 48 insertions(+), 216 deletions(-) diff --git a/trees/avltree/avltree_test.go b/trees/avltree/avltree_test.go index ce27d6aa..114b5a5e 100644 --- a/trees/avltree/avltree_test.go +++ b/trees/avltree/avltree_test.go @@ -269,15 +269,8 @@ func TestAVLTreeIterator1Next(t *testing.T) { for it.Next() { count++ key := it.Key() - switch key { - case count: - if actualValue, expectedValue := key, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := key, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { @@ -308,15 +301,8 @@ func TestAVLTreeIterator1Prev(t *testing.T) { countDown := tree.size for it.Prev() { key := it.Key() - switch key { - case countDown: - if actualValue, expectedValue := key, countDown; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := key, countDown; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } countDown-- } @@ -335,15 +321,8 @@ func TestAVLTreeIterator2Next(t *testing.T) { for it.Next() { count++ key := it.Key() - switch key { - case count: - if actualValue, expectedValue := key, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := key, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { @@ -362,15 +341,8 @@ func TestAVLTreeIterator2Prev(t *testing.T) { countDown := tree.size for it.Prev() { key := it.Key() - switch key { - case countDown: - if actualValue, expectedValue := key, countDown; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := key, countDown; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } countDown-- } @@ -387,15 +359,8 @@ func TestAVLTreeIterator3Next(t *testing.T) { for it.Next() { count++ key := it.Key() - switch key { - case count: - if actualValue, expectedValue := key, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := key, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { @@ -412,15 +377,8 @@ func TestAVLTreeIterator3Prev(t *testing.T) { countDown := tree.size for it.Prev() { key := it.Key() - switch key { - case countDown: - if actualValue, expectedValue := key, countDown; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := key, countDown; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } countDown-- } @@ -456,15 +414,8 @@ func TestAVLTreeIterator4Next(t *testing.T) { for it.Next() { count++ value := it.Value() - switch value { - case count: - if actualValue, expectedValue := value, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := value, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { @@ -500,15 +451,8 @@ func TestAVLTreeIterator4Prev(t *testing.T) { } for it.Prev() { value := it.Value() - switch value { - case count: - if actualValue, expectedValue := value, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := value, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } count-- } diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index f8b6e615..c0a5c32b 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -749,15 +749,8 @@ func TestBTreeIterator1Next(t *testing.T) { for it.Next() { count++ key := it.Key() - switch key { - case count: - if actualValue, expectedValue := key, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := key, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { @@ -781,15 +774,8 @@ func TestBTreeIterator1Prev(t *testing.T) { countDown := tree.size for it.Prev() { key := it.Key() - switch key { - case countDown: - if actualValue, expectedValue := key, countDown; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := key, countDown; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } countDown-- } @@ -808,15 +794,8 @@ func TestBTreeIterator2Next(t *testing.T) { for it.Next() { count++ key := it.Key() - switch key { - case count: - if actualValue, expectedValue := key, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := key, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { @@ -835,15 +814,8 @@ func TestBTreeIterator2Prev(t *testing.T) { countDown := tree.size for it.Prev() { key := it.Key() - switch key { - case countDown: - if actualValue, expectedValue := key, countDown; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := key, countDown; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } countDown-- } @@ -860,15 +832,8 @@ func TestBTreeIterator3Next(t *testing.T) { for it.Next() { count++ key := it.Key() - switch key { - case count: - if actualValue, expectedValue := key, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := key, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { @@ -885,15 +850,8 @@ func TestBTreeIterator3Prev(t *testing.T) { countDown := tree.size for it.Prev() { key := it.Key() - switch key { - case countDown: - if actualValue, expectedValue := key, countDown; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := key, countDown; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } countDown-- } @@ -919,15 +877,8 @@ func TestBTreeIterator4Next(t *testing.T) { for it.Next() { count++ value := it.Value() - switch value { - case count: - if actualValue, expectedValue := value, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := value, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { @@ -953,15 +904,8 @@ func TestBTreeIterator4Prev(t *testing.T) { } for it.Prev() { value := it.Value() - switch value { - case count: - if actualValue, expectedValue := value, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := value, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } count-- } diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 5de39b65..4c0f519a 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -271,15 +271,8 @@ func TestRedBlackTreeIterator1Next(t *testing.T) { for it.Next() { count++ key := it.Key() - switch key { - case count: - if actualValue, expectedValue := key, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := key, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { @@ -310,15 +303,8 @@ func TestRedBlackTreeIterator1Prev(t *testing.T) { countDown := tree.size for it.Prev() { key := it.Key() - switch key { - case countDown: - if actualValue, expectedValue := key, countDown; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := key, countDown; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } countDown-- } @@ -337,15 +323,8 @@ func TestRedBlackTreeIterator2Next(t *testing.T) { for it.Next() { count++ key := it.Key() - switch key { - case count: - if actualValue, expectedValue := key, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := key, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { @@ -364,15 +343,8 @@ func TestRedBlackTreeIterator2Prev(t *testing.T) { countDown := tree.size for it.Prev() { key := it.Key() - switch key { - case countDown: - if actualValue, expectedValue := key, countDown; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := key, countDown; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } countDown-- } @@ -389,15 +361,8 @@ func TestRedBlackTreeIterator3Next(t *testing.T) { for it.Next() { count++ key := it.Key() - switch key { - case count: - if actualValue, expectedValue := key, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := key, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { @@ -414,15 +379,8 @@ func TestRedBlackTreeIterator3Prev(t *testing.T) { countDown := tree.size for it.Prev() { key := it.Key() - switch key { - case countDown: - if actualValue, expectedValue := key, countDown; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := key, countDown; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } countDown-- } @@ -458,15 +416,8 @@ func TestRedBlackTreeIterator4Next(t *testing.T) { for it.Next() { count++ value := it.Value() - switch value { - case count: - if actualValue, expectedValue := value, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := value, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { @@ -502,15 +453,8 @@ func TestRedBlackTreeIterator4Prev(t *testing.T) { } for it.Prev() { value := it.Value() - switch value { - case count: - if actualValue, expectedValue := value, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - default: - if actualValue, expectedValue := value, count; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } count-- } From 08cf24a0a054ffe2b026f7aae0cbe1938e3e3d7c Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 19:43:49 +0200 Subject: [PATCH 295/320] SonarQube badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 987e02a0..46812107 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ [![codecov](https://codecov.io/gh/emirpasic/gods/branch/master/graph/badge.svg)](https://codecov.io/gh/emirpasic/gods) [![Sourcegraph](https://sourcegraph.com/github.com/emirpasic/gods/-/badge.svg)](https://sourcegraph.com/github.com/emirpasic/gods?badge) [![Release](https://img.shields.io/github/release/emirpasic/gods.svg?style=flat-square)](https://github.com/emirpasic/gods/releases) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=gods&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=gods) [![PyPI](https://img.shields.io/badge/License-BSD_2--Clause-green.svg)](https://github.com/emirpasic/gods/blob/master/LICENSE) # GoDS (Go Data Structures) From 9e4f7a11c43942929515330510d2cbb38dc87f52 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 20:19:17 +0200 Subject: [PATCH 296/320] SonarQube --- .github/workflows/sonarcloud.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 1b59cd31..c9c60456 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -58,6 +58,7 @@ jobs: # mandatory -Dsonar.projectKey=gods -Dsonar.organization=emirpasic + -Dsonar.coverage.exclusions=**/*_test.go # Comma-separated paths to directories containing main source files. #-Dsonar.sources= # optional, default is project base directory # When you need the analysis to take place in a directory other than the one from which it was launched From 4665f56318f5014c9fe21ec67593c9f375f66334 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 20:29:10 +0200 Subject: [PATCH 297/320] tmp --- .github/workflows/sonarcloud.yml | 69 -------------------------------- 1 file changed, 69 deletions(-) delete mode 100644 .github/workflows/sonarcloud.yml diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml deleted file mode 100644 index c9c60456..00000000 --- a/.github/workflows/sonarcloud.yml +++ /dev/null @@ -1,69 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -# This workflow helps you trigger a SonarCloud analysis of your code and populates -# GitHub Code Scanning alerts with the vulnerabilities found. -# Free for open source project. - -# 1. Login to SonarCloud.io using your GitHub account - -# 2. Import your project on SonarCloud -# * Add your GitHub organization first, then add your repository as a new project. -# * Please note that many languages are eligible for automatic analysis, -# which means that the analysis will start automatically without the need to set up GitHub Actions. -# * This behavior can be changed in Administration > Analysis Method. -# -# 3. Follow the SonarCloud in-product tutorial -# * a. Copy/paste the Project Key and the Organization Key into the args parameter below -# (You'll find this information in SonarCloud. Click on "Information" at the bottom left) -# -# * b. Generate a new token and add it to your Github repository's secrets using the name SONAR_TOKEN -# (On SonarCloud, click on your avatar on top-right > My account > Security -# or go directly to https://sonarcloud.io/account/security/) - -# Feel free to take a look at our documentation (https://docs.sonarcloud.io/getting-started/github/) -# or reach out to our community forum if you need some help (https://community.sonarsource.com/c/help/sc/9) - -name: SonarCloud analysis - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - workflow_dispatch: - -permissions: - pull-requests: read # allows SonarCloud to decorate PRs with analysis results - -jobs: - Analysis: - runs-on: ubuntu-latest - - steps: - - name: Analyze with SonarCloud - - # You can pin the exact commit or the version. - # uses: SonarSource/sonarcloud-github-action@de2e56b42aa84d0b1c5b622644ac17e505c9a049 - uses: SonarSource/sonarcloud-github-action@de2e56b42aa84d0b1c5b622644ac17e505c9a049 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} # Generate a token on Sonarcloud.io, add it to the secrets of this repo with the name SONAR_TOKEN (Settings > Secrets > Actions > add new repository secret) - with: - # Additional arguments for the sonarcloud scanner - args: - # Unique keys of your project and organization. You can find them in SonarCloud > Information (bottom-left menu) - # mandatory - -Dsonar.projectKey=gods - -Dsonar.organization=emirpasic - -Dsonar.coverage.exclusions=**/*_test.go - # Comma-separated paths to directories containing main source files. - #-Dsonar.sources= # optional, default is project base directory - # When you need the analysis to take place in a directory other than the one from which it was launched - #-Dsonar.projectBaseDir= # optional, default is . - # Comma-separated paths to directories containing test source files. - #-Dsonar.tests= # optional. For more info about Code Coverage, please refer to https://docs.sonarcloud.io/enriching/test-coverage/overview/ - # Adds more detail to both client and server-side analysis logs, activating DEBUG mode for the scanner, and adding client-side environment variables and system properties to the server-side log of analysis report processing. - #-Dsonar.verbose= # optional, default is false From 74d62f4f1ed33caa0e315d52955a009b336c33b3 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 20:46:44 +0200 Subject: [PATCH 298/320] SonarQube --- trees/btree/btree.go | 9 +++------ trees/btree/btree_test.go | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/trees/btree/btree.go b/trees/btree/btree.go index bb36f93a..eae4576b 100644 --- a/trees/btree/btree.go +++ b/trees/btree/btree.go @@ -210,8 +210,7 @@ func (tree *Tree) RightValue() interface{} { // String returns a string representation of container (for debugging purposes) func (tree *Tree) String() string { var buffer bytes.Buffer - if _, err := buffer.WriteString("BTree\n"); err != nil { - } + buffer.WriteString("BTree\n") if !tree.Empty() { tree.output(&buffer, tree.Root, 0, true) } @@ -228,10 +227,8 @@ func (tree *Tree) output(buffer *bytes.Buffer, node *Node, level int, isTail boo tree.output(buffer, node.Children[e], level+1, true) } if e < len(node.Entries) { - if _, err := buffer.WriteString(strings.Repeat(" ", level)); err != nil { - } - if _, err := buffer.WriteString(fmt.Sprintf("%v", node.Entries[e].Key) + "\n"); err != nil { - } + buffer.WriteString(strings.Repeat(" ", level)) + buffer.WriteString(fmt.Sprintf("%v", node.Entries[e].Key) + "\n") } } } diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index c0a5c32b..8dcb2581 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -1001,7 +1001,7 @@ func TestBTreeIteratorLast(t *testing.T) { } } -func TestBTree_search(t *testing.T) { +func TestBTreeSearch(t *testing.T) { { tree := NewWithIntComparator(3) tree.Root = &Node{Entries: []*Entry{}, Children: make([]*Node, 0)} From 6bf61e32bee262e5cc97231fc29bc22c17a7e59a Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 23:05:57 +0200 Subject: [PATCH 299/320] Implements queues, LinkedListQueue and ArrayQueue --- README.md | 99 +++- examples/arrayqueue/arrayqqueue.go | 23 + examples/linkedlistqueue/linkedlistqueue.go | 23 + queues/arrayqueue/arrayqueue.go | 88 ++++ queues/arrayqueue/arrayqueue_test.go | 494 ++++++++++++++++++ queues/arrayqueue/iterator.go | 111 ++++ queues/arrayqueue/serialization.go | 33 ++ queues/linkedlistqueue/iterator.go | 73 +++ queues/linkedlistqueue/linkedlistqueue.go | 88 ++++ .../linkedlistqueue/linkedlistqueue_test.go | 357 +++++++++++++ queues/linkedlistqueue/serialization.go | 33 ++ queues/queues.go | 27 + 12 files changed, 1442 insertions(+), 7 deletions(-) create mode 100644 examples/arrayqueue/arrayqqueue.go create mode 100644 examples/linkedlistqueue/linkedlistqueue.go create mode 100644 queues/arrayqueue/arrayqueue.go create mode 100644 queues/arrayqueue/arrayqueue_test.go create mode 100644 queues/arrayqueue/iterator.go create mode 100644 queues/arrayqueue/serialization.go create mode 100644 queues/linkedlistqueue/iterator.go create mode 100644 queues/linkedlistqueue/linkedlistqueue.go create mode 100644 queues/linkedlistqueue/linkedlistqueue_test.go create mode 100644 queues/linkedlistqueue/serialization.go create mode 100644 queues/queues.go diff --git a/README.md b/README.md index 46812107..35723484 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,9 @@ Implementation of various data structures and algorithms in Go. - [AVLTree](#avltree) - [BTree](#btree) - [BinaryHeap](#binaryheap) + - [Queues](#queues) + - [LinkedListQueue](#linkedlistqueue) + - [ArrayQueue](#arrayqueue) - [Functions](#functions) - [Comparator](#comparator) - [Iterator](#iterator) @@ -94,6 +97,9 @@ Containers are either ordered or unordered. All ordered containers provide [stat | | [AVLTree](#avltree) | yes | yes* | no | key | | | [BTree](#btree) | yes | yes* | no | key | | | [BinaryHeap](#binaryheap) | yes | yes* | no | index | +| [Queues](#queues) | +| | [LinkedListQueues](#linkedlistqueues) | yes | yes | no | index | +| | [ArrayQueues](#arrayqueues) | yes | yes* | no | index | | | | | *reversible | | *bidirectional | ### Lists @@ -126,7 +132,7 @@ type List interface { A [list](#lists) backed by a dynamic array that grows and shrinks implicitly. -Implements [List](#lists), [IteratorWithIndex](#iteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. +Implements [List](#lists), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -200,7 +206,7 @@ func main() { A [list](#lists) where each element points to the next and previous elements in the list. -Implements [List](#lists), [IteratorWithIndex](#iteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. +Implements [List](#lists), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -290,7 +296,7 @@ func main() { A [set](#sets) backed by a [red-black tree](#redblacktree) to keep the elements ordered with respect to the [comparator](#comparator). -Implements [Set](#sets), [IteratorWithIndex](#iteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. +Implements [Set](#sets), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -317,7 +323,7 @@ func main() { A [set](#sets) that preserves insertion-order. Data structure is backed by a hash table to store values and [doubly-linked list](#doublylinkedlist) to store insertion ordering. -Implements [Set](#sets), [IteratorWithIndex](#iteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. +Implements [Set](#sets), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -479,7 +485,7 @@ func main() { A [map](#maps) based on [red-black tree](#redblacktree). Keys are ordered with respect to the [comparator](#comparator). -Implements [Map](#maps), [IteratorWithKey](#iteratorwithkey), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. +Implements [Map](#maps), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -510,7 +516,7 @@ func main() { A [map](#maps) that preserves insertion-order. It is backed by a hash table to store values and [doubly-linked list](doublylinkedlist) to store ordering. -Implements [Map](#maps), [IteratorWithKey](#iteratorwithkey), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. +Implements [Map](#maps), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -567,7 +573,7 @@ func main() { A [map](#maps) based on red-black tree. This map guarantees that the map will be in both ascending key and value order. Other than key and value ordering, the goal with this structure is to avoid duplication of elements (unlike in [HashBidiMap](#hashbidimap)), which can be significant if contained elements are large. -Implements [BidiMap](#maps), [IteratorWithKey](#iteratorwithkey), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. +Implements [BidiMap](#maps), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -864,6 +870,85 @@ func main() { } ``` +### Queues + +A queue that represents a first-in-first-out (FIFO) data structure. The usual enqueue and dequeue operations are provided, as well as a method to peek at the first item in the queue. + +

+ +Implements [Container](#containers) interface. + +```go +type Queue interface { + Enqueue(value interface{}) + Dequeue() (value interface{}, ok bool) + Peek() (value interface{}, ok bool) + + containers.Container + // Empty() bool + // Size() int + // Clear() + // Values() []interface{} + // String() string +} +``` + +#### LinkedListQueue + +A [queue](#queues) based on a [linked list](#singlylinkedlist). + +Implements [Queue](#queues), [IteratorWithIndex](#iteratorwithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. + +```go +package main + +import llq "github.com/emirpasic/gods/queues/linkedlistqueue" + +// LinkedListQueueExample to demonstrate basic usage of LinkedListQueue +func main() { + queue := llq.New() // empty + queue.Enqueue(1) // 1 + queue.Enqueue(2) // 1, 2 + _ = queue.Values() // 1, 2 (FIFO order) + _, _ = queue.Peek() // 1,true + _, _ = queue.Dequeue() // 1, true + _, _ = queue.Dequeue() // 2, true + _, _ = queue.Dequeue() // nil, false (nothing to deque) + queue.Enqueue(1) // 1 + queue.Clear() // empty + queue.Empty() // true + _ = queue.Size() // 0 +} +``` + +#### ArrayQueue + +A [queue](#queues) based on a [array list](#arraylist). + +Implements [Queue](#queues), [ReverseIteratorWithIndex](#iteratorwithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. + +```go +package main + +import aq "github.com/emirpasic/gods/queues/arrayqueue" + +// ArrayQueueExample to demonstrate basic usage of ArrayQueue +func main() { + queue := aq.New() // empty + queue.Enqueue(1) // 1 + queue.Enqueue(2) // 1, 2 + _ = queue.Values() // 1, 2 (FIFO order) + _, _ = queue.Peek() // 1,true + _, _ = queue.Dequeue() // 1, true + _, _ = queue.Dequeue() // 2, true + _, _ = queue.Dequeue() // nil, false (nothing to deque) + queue.Enqueue(1) // 1 + queue.Clear() // empty + queue.Empty() // true + _ = queue.Size() // 0 +} +``` + ## Functions Various helper functions used throughout the library. diff --git a/examples/arrayqueue/arrayqqueue.go b/examples/arrayqueue/arrayqqueue.go new file mode 100644 index 00000000..13b88187 --- /dev/null +++ b/examples/arrayqueue/arrayqqueue.go @@ -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 aq "github.com/emirpasic/gods/queues/arrayqueue" + +// ArrayQueueExample to demonstrate basic usage of ArrayQueue +func main() { + queue := aq.New() // empty + queue.Enqueue(1) // 1 + queue.Enqueue(2) // 1, 2 + _ = queue.Values() // 1, 2 (FIFO order) + _, _ = queue.Peek() // 1,true + _, _ = queue.Dequeue() // 1, true + _, _ = queue.Dequeue() // 2, true + _, _ = queue.Dequeue() // nil, false (nothing to deque) + queue.Enqueue(1) // 1 + queue.Clear() // empty + queue.Empty() // true + _ = queue.Size() // 0 +} diff --git a/examples/linkedlistqueue/linkedlistqueue.go b/examples/linkedlistqueue/linkedlistqueue.go new file mode 100644 index 00000000..d6800b5f --- /dev/null +++ b/examples/linkedlistqueue/linkedlistqueue.go @@ -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 llq "github.com/emirpasic/gods/queues/linkedlistqueue" + +// LinkedListQueueExample to demonstrate basic usage of LinkedListQueue +func main() { + queue := llq.New() // empty + queue.Enqueue(1) // 1 + queue.Enqueue(2) // 1, 2 + _ = queue.Values() // 1, 2 (FIFO order) + _, _ = queue.Peek() // 1,true + _, _ = queue.Dequeue() // 1, true + _, _ = queue.Dequeue() // 2, true + _, _ = queue.Dequeue() // nil, false (nothing to deque) + queue.Enqueue(1) // 1 + queue.Clear() // empty + queue.Empty() // true + _ = queue.Size() // 0 +} diff --git a/queues/arrayqueue/arrayqueue.go b/queues/arrayqueue/arrayqueue.go new file mode 100644 index 00000000..8d480e90 --- /dev/null +++ b/queues/arrayqueue/arrayqueue.go @@ -0,0 +1,88 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package arrayqueue implements a queue backed by array list. +// +// Structure is not thread safe. +// +// Reference: https://en.wikipedia.org/wiki/Queue_(abstract_data_type) +package arrayqueue + +import ( + "fmt" + "strings" + + "github.com/emirpasic/gods/lists/arraylist" + "github.com/emirpasic/gods/queues" +) + +// Assert Queue implementation +var _ queues.Queue = (*Queue)(nil) + +// Queue holds elements in an array-list +type Queue struct { + list *arraylist.List +} + +// New instantiates a new empty queue +func New() *Queue { + return &Queue{list: arraylist.New()} +} + +// Enqueue adds a value to the end of the queue +func (queue *Queue) Enqueue(value interface{}) { + queue.list.Add(value) +} + +// Dequeue removes first element of the queue and returns it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to dequeue. +func (queue *Queue) Dequeue() (value interface{}, ok bool) { + value, ok = queue.list.Get(0) + if ok { + queue.list.Remove(0) + } + return +} + +// Peek returns first element of the queue without removing it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to peek. +func (queue *Queue) Peek() (value interface{}, ok bool) { + return queue.list.Get(0) +} + +// Empty returns true if queue does not contain any elements. +func (queue *Queue) Empty() bool { + return queue.list.Empty() +} + +// Size returns number of elements within the queue. +func (queue *Queue) Size() int { + return queue.list.Size() +} + +// Clear removes all elements from the queue. +func (queue *Queue) Clear() { + queue.list.Clear() +} + +// Values returns all elements in the queue (FIFO order). +func (queue *Queue) Values() []interface{} { + return queue.list.Values() +} + +// String returns a string representation of container +func (queue *Queue) String() string { + str := "ArrayQueue\n" + values := []string{} + for _, value := range queue.list.Values() { + values = append(values, fmt.Sprintf("%v", value)) + } + str += strings.Join(values, ", ") + return str +} + +// Check that the index is within bounds of the list +func (queue *Queue) withinRange(index int) bool { + return index >= 0 && index < queue.list.Size() +} diff --git a/queues/arrayqueue/arrayqueue_test.go b/queues/arrayqueue/arrayqueue_test.go new file mode 100644 index 00000000..b704dbf5 --- /dev/null +++ b/queues/arrayqueue/arrayqueue_test.go @@ -0,0 +1,494 @@ +// 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 arrayqueue + +import ( + "encoding/json" + "fmt" + "strings" + "testing" +) + +func TestQueueEnqueue(t *testing.T) { + queue := New() + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + + if actualValue := queue.Values(); actualValue[0].(int) != 1 || actualValue[1].(int) != 2 || actualValue[2].(int) != 3 { + t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + } + if actualValue := queue.Empty(); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, false) + } + if actualValue := queue.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + +func TestQueuePeek(t *testing.T) { + queue := New() + if actualValue, ok := queue.Peek(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + +func TestQueueDequeue(t *testing.T) { + queue := New() + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + queue.Dequeue() + if actualValue, ok := queue.Peek(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, ok := queue.Dequeue(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, ok := queue.Dequeue(); actualValue != 3 || !ok { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Dequeue(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + if actualValue := queue.Values(); len(actualValue) != 0 { + t.Errorf("Got %v expected %v", actualValue, "[]") + } +} + +func TestQueueIteratorOnEmpty(t *testing.T) { + queue := New() + it := queue.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty queue") + } +} + +func TestQueueIteratorNext(t *testing.T) { + queue := New() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + it := queue.Iterator() + count := 0 + for it.Next() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; 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) + } + + queue.Clear() + it = queue.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty queue") + } +} + +func TestQueueIteratorPrev(t *testing.T) { + queue := New() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + it := queue.Iterator() + for it.Next() { + } + count := 0 + for it.Prev() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := index, 3-count; 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 TestQueueIteratorBegin(t *testing.T) { + queue := New() + it := queue.Iterator() + it.Begin() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("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 TestQueueIteratorEnd(t *testing.T) { + queue := New() + it := queue.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) + } + + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + it.End() + if index := it.Index(); index != queue.Size() { + t.Errorf("Got %v expected %v", index, queue.Size()) + } + + it.Prev() + if index, value := it.Index(), it.Value(); index != queue.Size()-1 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, queue.Size()-1, "c") + } +} + +func TestQueueIteratorFirst(t *testing.T) { + queue := New() + it := queue.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + 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 TestQueueIteratorLast(t *testing.T) { + queue := New() + it := queue.Iterator() + if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + 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, 2, "c") + } +} + +func TestQueueIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + queue := New() + it := queue.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + } + + // NextTo (not found) + { + queue := New() + queue.Enqueue("xx") + queue.Enqueue("yy") + it := queue.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + } + + // NextTo (found) + { + queue := New() + queue.Enqueue("aa") + queue.Enqueue("bb") + queue.Enqueue("cc") + it := queue.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + +func TestQueueIteratorPrevTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // PrevTo (empty) + { + queue := New() + it := queue.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + } + + // PrevTo (not found) + { + queue := New() + queue.Enqueue("xx") + queue.Enqueue("yy") + it := queue.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + } + + // PrevTo (found) + { + queue := New() + queue.Enqueue("aa") + queue.Enqueue("bb") + queue.Enqueue("cc") + it := queue.Iterator() + it.End() + if !it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Prev() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "aa" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") + } + if it.Prev() { + t.Errorf("Should not go before first element") + } + } +} + +func TestQueueSerialization(t *testing.T) { + queue := New() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + var err error + assert := func() { + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", queue.Values()...), "abc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := queue.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + bytes, err := queue.ToJSON() + assert() + + err = queue.FromJSON(bytes) + assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", queue}) + if err != nil { + t.Errorf("Got error %v", err) + } + + err = json.Unmarshal([]byte(`[1,2,3]`), &queue) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestQueueString(t *testing.T) { + c := New() + c.Enqueue(1) + if !strings.HasPrefix(c.String(), "ArrayQueue") { + t.Errorf("String should start with container name") + } +} + +func benchmarkEnqueue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + } +} + +func benchmarkDequeue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Dequeue() + } + } +} + +func BenchmarkArrayQueueDequeue100(b *testing.B) { + b.StopTimer() + size := 100 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueDequeue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueDequeue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueDequeue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue100(b *testing.B) { + b.StopTimer() + size := 100 + queue := New() + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} diff --git a/queues/arrayqueue/iterator.go b/queues/arrayqueue/iterator.go new file mode 100644 index 00000000..51a30f9a --- /dev/null +++ b/queues/arrayqueue/iterator.go @@ -0,0 +1,111 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package arrayqueue + +import "github.com/emirpasic/gods/containers" + +// Assert Iterator implementation +var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) + +// Iterator returns a stateful iterator whose values can be fetched by an index. +type Iterator struct { + queue *Queue + index int +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +func (queue *Queue) Iterator() Iterator { + return Iterator{queue: queue, index: -1} +} + +// 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 { + if iterator.index < iterator.queue.Size() { + iterator.index++ + } + return iterator.queue.withinRange(iterator.index) +} + +// 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 { + if iterator.index >= 0 { + iterator.index-- + } + return iterator.queue.withinRange(iterator.index) +} + +// Value returns the current element's value. +// Does not modify the state of the iterator. +func (iterator *Iterator) Value() interface{} { + value, _ := iterator.queue.list.Get(iterator.index) + return value +} + +// Index returns the current element's index. +// Does not modify the state of the iterator. +func (iterator *Iterator) Index() int { + return 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.index = -1 +} + +// 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.index = iterator.queue.Size() +} + +// 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 { + iterator.Begin() + return iterator.Next() +} + +// 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 { + iterator.End() + return iterator.Prev() +} + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { + for iterator.Next() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} + +// PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool { + for iterator.Prev() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} diff --git a/queues/arrayqueue/serialization.go b/queues/arrayqueue/serialization.go new file mode 100644 index 00000000..a33a82f9 --- /dev/null +++ b/queues/arrayqueue/serialization.go @@ -0,0 +1,33 @@ +// 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 arrayqueue + +import ( + "github.com/emirpasic/gods/containers" +) + +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Queue)(nil) +var _ containers.JSONDeserializer = (*Queue)(nil) + +// ToJSON outputs the JSON representation of the queue. +func (queue *Queue) ToJSON() ([]byte, error) { + return queue.list.ToJSON() +} + +// FromJSON populates the queue from the input JSON representation. +func (queue *Queue) FromJSON(data []byte) error { + return queue.list.FromJSON(data) +} + +// UnmarshalJSON @implements json.Unmarshaler +func (queue *Queue) UnmarshalJSON(bytes []byte) error { + return queue.FromJSON(bytes) +} + +// MarshalJSON @implements json.Marshaler +func (queue *Queue) MarshalJSON() ([]byte, error) { + return queue.ToJSON() +} diff --git a/queues/linkedlistqueue/iterator.go b/queues/linkedlistqueue/iterator.go new file mode 100644 index 00000000..cf47b191 --- /dev/null +++ b/queues/linkedlistqueue/iterator.go @@ -0,0 +1,73 @@ +// 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 linkedlistqueue + +import "github.com/emirpasic/gods/containers" + +// Assert Iterator implementation +var _ containers.IteratorWithIndex = (*Iterator)(nil) + +// Iterator returns a stateful iterator whose values can be fetched by an index. +type Iterator struct { + queue *Queue + index int +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +func (queue *Queue) Iterator() Iterator { + return Iterator{queue: queue, index: -1} +} + +// 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 { + if iterator.index < iterator.queue.Size() { + iterator.index++ + } + return iterator.queue.withinRange(iterator.index) +} + +// Value returns the current element's value. +// Does not modify the state of the iterator. +func (iterator *Iterator) Value() interface{} { + value, _ := iterator.queue.list.Get(iterator.index) + return value +} + +// Index returns the current element's index. +// Does not modify the state of the iterator. +func (iterator *Iterator) Index() int { + return 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.index = -1 +} + +// 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 { + iterator.Begin() + return iterator.Next() +} + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { + for iterator.Next() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} diff --git a/queues/linkedlistqueue/linkedlistqueue.go b/queues/linkedlistqueue/linkedlistqueue.go new file mode 100644 index 00000000..fdb94636 --- /dev/null +++ b/queues/linkedlistqueue/linkedlistqueue.go @@ -0,0 +1,88 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package linkedlistqueue implements a queue backed by a singly-linked list. +// +// Structure is not thread safe. +// +// Reference: https://en.wikipedia.org/wiki/Queue_(abstract_data_type) +package linkedlistqueue + +import ( + "fmt" + "strings" + + "github.com/emirpasic/gods/lists/singlylinkedlist" + "github.com/emirpasic/gods/queues" +) + +// Assert Queue implementation +var _ queues.Queue = (*Queue)(nil) + +// Queue holds elements in a singly-linked-list +type Queue struct { + list *singlylinkedlist.List +} + +// New instantiates a new empty queue +func New() *Queue { + return &Queue{list: &singlylinkedlist.List{}} +} + +// Enqueue adds a value to the end of the queue +func (queue *Queue) Enqueue(value interface{}) { + queue.list.Add(value) +} + +// Dequeue removes first element of the queue and returns it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to dequeue. +func (queue *Queue) Dequeue() (value interface{}, ok bool) { + value, ok = queue.list.Get(0) + if ok { + queue.list.Remove(0) + } + return +} + +// Peek returns first element of the queue without removing it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to peek. +func (queue *Queue) Peek() (value interface{}, ok bool) { + return queue.list.Get(0) +} + +// Empty returns true if queue does not contain any elements. +func (queue *Queue) Empty() bool { + return queue.list.Empty() +} + +// Size returns number of elements within the queue. +func (queue *Queue) Size() int { + return queue.list.Size() +} + +// Clear removes all elements from the queue. +func (queue *Queue) Clear() { + queue.list.Clear() +} + +// Values returns all elements in the queue (FIFO order). +func (queue *Queue) Values() []interface{} { + return queue.list.Values() +} + +// String returns a string representation of container +func (queue *Queue) String() string { + str := "LinkedListQueue\n" + values := []string{} + for _, value := range queue.list.Values() { + values = append(values, fmt.Sprintf("%v", value)) + } + str += strings.Join(values, ", ") + return str +} + +// Check that the index is within bounds of the list +func (queue *Queue) withinRange(index int) bool { + return index >= 0 && index < queue.list.Size() +} diff --git a/queues/linkedlistqueue/linkedlistqueue_test.go b/queues/linkedlistqueue/linkedlistqueue_test.go new file mode 100644 index 00000000..e8e7c749 --- /dev/null +++ b/queues/linkedlistqueue/linkedlistqueue_test.go @@ -0,0 +1,357 @@ +// 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 linkedlistqueue + +import ( + "encoding/json" + "fmt" + "strings" + "testing" +) + +func TestQueueEnqueue(t *testing.T) { + queue := New() + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + + if actualValue := queue.Values(); actualValue[0].(int) != 1 || actualValue[1].(int) != 2 || actualValue[2].(int) != 3 { + t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + } + if actualValue := queue.Empty(); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, false) + } + if actualValue := queue.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + +func TestQueuePeek(t *testing.T) { + queue := New() + if actualValue, ok := queue.Peek(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + +func TestQueueDequeue(t *testing.T) { + queue := New() + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + queue.Dequeue() + if actualValue, ok := queue.Peek(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, ok := queue.Dequeue(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, ok := queue.Dequeue(); actualValue != 3 || !ok { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Dequeue(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + if actualValue := queue.Values(); len(actualValue) != 0 { + t.Errorf("Got %v expected %v", actualValue, "[]") + } +} + +func TestQueueIteratorOnEmpty(t *testing.T) { + queue := New() + it := queue.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty queue") + } +} + +func TestQueueIteratorNext(t *testing.T) { + queue := New() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + it := queue.Iterator() + count := 0 + for it.Next() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; 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) + } + + queue.Clear() + it = queue.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty queue") + } +} + +func TestQueueIteratorBegin(t *testing.T) { + queue := New() + it := queue.Iterator() + it.Begin() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("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 TestQueueIteratorFirst(t *testing.T) { + queue := New() + it := queue.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + 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 TestQueueIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + queue := New() + it := queue.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + } + + // NextTo (not found) + { + queue := New() + queue.Enqueue("xx") + queue.Enqueue("yy") + it := queue.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + } + + // NextTo (found) + { + queue := New() + queue.Enqueue("aa") + queue.Enqueue("bb") + queue.Enqueue("cc") + it := queue.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + +func TestQueueSerialization(t *testing.T) { + queue := New() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + var err error + assert := func() { + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", queue.Values()...), "abc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := queue.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + bytes, err := queue.ToJSON() + assert() + + err = queue.FromJSON(bytes) + assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", queue}) + if err != nil { + t.Errorf("Got error %v", err) + } + + err = json.Unmarshal([]byte(`[1,2,3]`), &queue) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestQueueString(t *testing.T) { + c := New() + c.Enqueue(1) + if !strings.HasPrefix(c.String(), "LinkedListQueue") { + t.Errorf("String should start with container name") + } +} + +func benchmarkEnqueue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + } +} + +func benchmarkDequeue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Dequeue() + } + } +} + +func BenchmarkArrayQueueDequeue100(b *testing.B) { + b.StopTimer() + size := 100 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueDequeue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueDequeue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueDequeue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue100(b *testing.B) { + b.StopTimer() + size := 100 + queue := New() + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} diff --git a/queues/linkedlistqueue/serialization.go b/queues/linkedlistqueue/serialization.go new file mode 100644 index 00000000..2b34c8e4 --- /dev/null +++ b/queues/linkedlistqueue/serialization.go @@ -0,0 +1,33 @@ +// 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 linkedlistqueue + +import ( + "github.com/emirpasic/gods/containers" +) + +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Queue)(nil) +var _ containers.JSONDeserializer = (*Queue)(nil) + +// ToJSON outputs the JSON representation of the queue. +func (queue *Queue) ToJSON() ([]byte, error) { + return queue.list.ToJSON() +} + +// FromJSON populates the queue from the input JSON representation. +func (queue *Queue) FromJSON(data []byte) error { + return queue.list.FromJSON(data) +} + +// UnmarshalJSON @implements json.Unmarshaler +func (queue *Queue) UnmarshalJSON(bytes []byte) error { + return queue.FromJSON(bytes) +} + +// MarshalJSON @implements json.Marshaler +func (queue *Queue) MarshalJSON() ([]byte, error) { + return queue.ToJSON() +} diff --git a/queues/queues.go b/queues/queues.go new file mode 100644 index 00000000..80239d48 --- /dev/null +++ b/queues/queues.go @@ -0,0 +1,27 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package queues provides an abstract Queue interface. +// +// In computer science, a queue is a collection of entities that are maintained in a sequence and can be modified by the addition of entities at one end of the sequence and the removal of entities from the other end of the sequence. By convention, the end of the sequence at which elements are added is called the back, tail, or rear of the queue, and the end at which elements are removed is called the head or front of the queue, analogously to the words used when people line up to wait for goods or services. +// The operation of adding an element to the rear of the queue is known as enqueue, and the operation of removing an element from the front is known as dequeue. Other operations may also be allowed, often including a peek or front operation that returns the value of the next element to be dequeued without remove it. +// +// Reference: https://en.wikipedia.org/wiki/Queue_(abstract_data_type) +package queues + +import "github.com/emirpasic/gods/containers" + +// Queue interface that all queues implement +type Queue interface { + Enqueue(value interface{}) + Dequeue() (value interface{}, ok bool) + Peek() (value interface{}, ok bool) + + containers.Container + // Empty() bool + // Size() int + // Clear() + // Values() []interface{} + // String() string +} From 5b2385446eb64b06747c2985bc00490999fc6c73 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 23:14:04 +0200 Subject: [PATCH 300/320] Documentation fix --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 35723484..0c7b25bb 100644 --- a/README.md +++ b/README.md @@ -98,8 +98,8 @@ Containers are either ordered or unordered. All ordered containers provide [stat | | [BTree](#btree) | yes | yes* | no | key | | | [BinaryHeap](#binaryheap) | yes | yes* | no | index | | [Queues](#queues) | -| | [LinkedListQueues](#linkedlistqueues) | yes | yes | no | index | -| | [ArrayQueues](#arrayqueues) | yes | yes* | no | index | +| | [LinkedListQueue](#linkedlistqueue) | yes | yes | no | index | +| | [ArrayQueue](#arrayqueue) | yes | yes* | no | index | | | | | *reversible | | *bidirectional | ### Lists From 9606c1a0e837fea6727781c2053626b1d8bac5a9 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Thu, 14 Apr 2022 03:31:07 +0200 Subject: [PATCH 301/320] Implements CircularBuffer --- README.md | 77 ++- queues/circularbuffer/circularbuffer.go | 153 +++++ queues/circularbuffer/circularbuffer_test.go | 687 +++++++++++++++++++ queues/circularbuffer/iterator.go | 112 +++ queues/circularbuffer/serialization.go | 41 ++ 5 files changed, 1049 insertions(+), 21 deletions(-) create mode 100644 queues/circularbuffer/circularbuffer.go create mode 100644 queues/circularbuffer/circularbuffer_test.go create mode 100644 queues/circularbuffer/iterator.go create mode 100644 queues/circularbuffer/serialization.go diff --git a/README.md b/README.md index 0c7b25bb..0925a5a1 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ Implementation of various data structures and algorithms in Go. - [Queues](#queues) - [LinkedListQueue](#linkedlistqueue) - [ArrayQueue](#arrayqueue) + - [CircularBuffer](#circularbuffer) - [Functions](#functions) - [Comparator](#comparator) - [Iterator](#iterator) @@ -67,40 +68,41 @@ type Container interface { Size() int Clear() Values() []interface{} - String() string + String() string } ``` Containers are either ordered or unordered. All ordered containers provide [stateful iterators](#iterator) and some of them allow [enumerable functions](#enumerable). -| **Data** | **Structure** | **Ordered** | **[Iterator](#iterator)** | **[Enumerable](#enumerable)** | **Referenced by** | -| :--- | :--- | :---: | :---: | :---: | :---: | +| **Data** | **Structure** | **Ordered** | **[Iterator](#iterator)** | **[Enumerable](#enumerable)** | **Referenced by** | +| :--- |:--------------------------------------| :---: | :---: | :---: | :---: | | [Lists](#lists) | -| | [ArrayList](#arraylist) | yes | yes* | yes | index | +| | [ArrayList](#arraylist) | yes | yes* | yes | index | | | [SinglyLinkedList](#singlylinkedlist) | yes | yes | yes | index | | | [DoublyLinkedList](#doublylinkedlist) | yes | yes* | yes | index | | [Sets](#sets) | -| | [HashSet](#hashset) | no | no | no | index | -| | [TreeSet](#treeset) | yes | yes* | yes | index | -| | [LinkedHashSet](#linkedhashset) | yes | yes* | yes | index | +| | [HashSet](#hashset) | no | no | no | index | +| | [TreeSet](#treeset) | yes | yes* | yes | index | +| | [LinkedHashSet](#linkedhashset) | yes | yes* | yes | index | | [Stacks](#stacks) | -| | [LinkedListStack](#linkedliststack) | yes | yes | no | index | -| | [ArrayStack](#arraystack) | yes | yes* | no | index | +| | [LinkedListStack](#linkedliststack) | yes | yes | no | index | +| | [ArrayStack](#arraystack) | yes | yes* | no | index | | [Maps](#maps) | -| | [HashMap](#hashmap) | no | no | no | key | -| | [TreeMap](#treemap) | yes | yes* | yes | key | -| | [LinkedHashMap](#linkedhashmap) | yes | yes* | yes | key | -| | [HashBidiMap](#hashbidimap) | no | no | no | key* | -| | [TreeBidiMap](#treebidimap) | yes | yes* | yes | key* | +| | [HashMap](#hashmap) | no | no | no | key | +| | [TreeMap](#treemap) | yes | yes* | yes | key | +| | [LinkedHashMap](#linkedhashmap) | yes | yes* | yes | key | +| | [HashBidiMap](#hashbidimap) | no | no | no | key* | +| | [TreeBidiMap](#treebidimap) | yes | yes* | yes | key* | | [Trees](#trees) | -| | [RedBlackTree](#redblacktree) | yes | yes* | no | key | -| | [AVLTree](#avltree) | yes | yes* | no | key | -| | [BTree](#btree) | yes | yes* | no | key | -| | [BinaryHeap](#binaryheap) | yes | yes* | no | index | +| | [RedBlackTree](#redblacktree) | yes | yes* | no | key | +| | [AVLTree](#avltree) | yes | yes* | no | key | +| | [BTree](#btree) | yes | yes* | no | key | +| | [BinaryHeap](#binaryheap) | yes | yes* | no | index | | [Queues](#queues) | -| | [LinkedListQueue](#linkedlistqueue) | yes | yes | no | index | -| | [ArrayQueue](#arrayqueue) | yes | yes* | no | index | -| | | | *reversible | | *bidirectional | +| | [LinkedListQueue](#linkedlistqueue) | yes | yes | no | index | +| | [ArrayQueue](#arrayqueue) | yes | yes* | no | index | +| | [CircularBuffer](#circularbuffer) | yes | yes* | no | index | +| | | | *reversible | | *bidirectional | ### Lists @@ -949,6 +951,39 @@ func main() { } ``` +#### CircularBuffer + +A circular buffer, circular [queue](#queues), cyclic buffer or ring buffer is a data structure that uses a single, fixed-size buffer as if it were connected end-to-end. This structure lends itself easily to buffering data streams. + +

+ +Implements [Queue](#queues), [ReverseIteratorWithIndex](#iteratorwithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. + +```go +package main + +import cb "github.com/emirpasic/gods/queues/circularbuffer" + +// CircularBufferExample to demonstrate basic usage of CircularBuffer +func main() { + queue := cb.New(3) // empty (max size is 3) + queue.Enqueue(1) // 1 + queue.Enqueue(2) // 1, 2 + queue.Enqueue(3) // 1, 2, 3 + _ = queue.Values() // 1, 2, 3 + queue.Enqueue(3) // 4, 2, 3 + _, _ = queue.Peek() // 4,true + _, _ = queue.Dequeue() // 4, true + _, _ = queue.Dequeue() // 2, true + _, _ = queue.Dequeue() // 3, true + _, _ = queue.Dequeue() // nil, false (nothing to deque) + queue.Enqueue(1) // 1 + queue.Clear() // empty + queue.Empty() // true + _ = queue.Size() // 0 +} +``` + ## Functions Various helper functions used throughout the library. diff --git a/queues/circularbuffer/circularbuffer.go b/queues/circularbuffer/circularbuffer.go new file mode 100644 index 00000000..f74a55b1 --- /dev/null +++ b/queues/circularbuffer/circularbuffer.go @@ -0,0 +1,153 @@ +// Copyright (c) 2021, 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 circularbuffer implements the circular buffer. +// +// In computer science, a circular buffer, circular queue, cyclic buffer or ring buffer is a data structure that uses a single, fixed-size buffer as if it were connected end-to-end. This structure lends itself easily to buffering data streams. +// +// Structure is not thread safe. +// +// Reference: https://en.wikipedia.org/wiki/Circular_buffer +package circularbuffer + +import ( + "fmt" + "strings" + + "github.com/emirpasic/gods/queues" +) + +// Assert Queue implementation +var _ queues.Queue = (*Queue)(nil) + +// Queue holds values in a slice. +type Queue struct { + values []interface{} + start int + end int + full bool + maxSize int + size int +} + +// New instantiates a new empty queue with the specified size of maximum number of elements that it can hold. +// This max size of the buffer cannot be changed. +func New(maxSize int) *Queue { + if maxSize < 1 { + panic("Invalid maxSize, should be at least 1") + } + queue := &Queue{maxSize: maxSize} + queue.Clear() + return queue +} + +// Enqueue adds a value to the end of the queue +func (queue *Queue) Enqueue(value interface{}) { + if queue.Full() { + queue.Dequeue() + } + queue.values[queue.end] = value + queue.end = queue.end + 1 + if queue.end >= queue.maxSize { + queue.end = 0 + } + if queue.end == queue.start { + queue.full = true + } + + queue.size = queue.calculateSize() +} + +// Dequeue removes first element of the queue and returns it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to dequeue. +func (queue *Queue) Dequeue() (value interface{}, ok bool) { + if queue.Empty() { + return nil, false + } + + value, ok = queue.values[queue.start], true + + if value != nil { + queue.values[queue.start] = nil + queue.start = queue.start + 1 + if queue.start >= queue.maxSize { + queue.start = 0 + } + queue.full = false + } + + queue.size = queue.size - 1 + + return +} + +// Peek returns first element of the queue without removing it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to peek. +func (queue *Queue) Peek() (value interface{}, ok bool) { + if queue.Empty() { + return nil, false + } + return queue.values[queue.start], true +} + +// Empty returns true if queue does not contain any elements. +func (queue *Queue) Empty() bool { + return queue.Size() == 0 +} + +// Full returns true if the queue is full, i.e. has reached the maximum number of elements that it can hold. +func (queue *Queue) Full() bool { + return queue.Size() == queue.maxSize +} + +// Size returns number of elements within the queue. +func (queue *Queue) Size() int { + return queue.size +} + +// Clear removes all elements from the queue. +func (queue *Queue) Clear() { + queue.values = make([]interface{}, queue.maxSize, queue.maxSize) + queue.start = 0 + queue.end = 0 + queue.full = false + queue.size = 0 +} + +// Values returns all elements in the queue (FIFO order). +func (queue *Queue) Values() []interface{} { + values := make([]interface{}, queue.Size(), queue.Size()) + for i := 0; i < queue.Size(); i++ { + values[i] = queue.values[(queue.start+i)%queue.maxSize] + } + return values +} + +// String returns a string representation of container +func (queue *Queue) String() string { + str := "CircularBuffer\n" + var values []string + for _, value := range queue.Values() { + values = append(values, fmt.Sprintf("%v", value)) + } + str += strings.Join(values, ", ") + return str +} + +// Check that the index is within bounds of the list +func (queue *Queue) withinRange(index int) bool { + return index >= 0 && index < queue.size +} + +func (queue *Queue) calculateSize() int { + if queue.end < queue.start { + return queue.maxSize - queue.start + queue.end + } else if queue.end == queue.start { + if queue.full { + return queue.maxSize + } + return 0 + } + return queue.end - queue.start +} diff --git a/queues/circularbuffer/circularbuffer_test.go b/queues/circularbuffer/circularbuffer_test.go new file mode 100644 index 00000000..2f826073 --- /dev/null +++ b/queues/circularbuffer/circularbuffer_test.go @@ -0,0 +1,687 @@ +// 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 circularbuffer + +import ( + "encoding/json" + "fmt" + "strings" + "testing" +) + +func TestQueueEnqueue(t *testing.T) { + queue := New(3) + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + + if actualValue := queue.Values(); actualValue[0].(int) != 1 || actualValue[1].(int) != 2 || actualValue[2].(int) != 3 { + t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + } + if actualValue := queue.Empty(); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, false) + } + if actualValue := queue.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + +func TestQueuePeek(t *testing.T) { + queue := New(3) + if actualValue, ok := queue.Peek(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + +func TestQueueDequeue(t *testing.T) { + queue := New(3) + if actualValue, expectedValue := queue.Empty(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := queue.Full(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := queue.Size(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + queue.Enqueue(1) + if actualValue, expectedValue := queue.Size(), 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + queue.Enqueue(2) + if actualValue, expectedValue := queue.Size(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + queue.Enqueue(3) + if actualValue, expectedValue := queue.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := queue.Empty(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := queue.Full(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + queue.Dequeue() + if actualValue, expectedValue := queue.Size(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + if actualValue, ok := queue.Peek(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, expectedValue := queue.Size(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + if actualValue, ok := queue.Dequeue(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, expectedValue := queue.Size(), 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + if actualValue, ok := queue.Dequeue(); actualValue != 3 || !ok { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, expectedValue := queue.Size(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := queue.Empty(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := queue.Full(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + if actualValue, ok := queue.Dequeue(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + if actualValue, expectedValue := queue.Size(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + if actualValue := queue.Full(); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, false) + } + if actualValue := queue.Values(); len(actualValue) != 0 { + t.Errorf("Got %v expected %v", actualValue, "[]") + } +} + +func TestQueueDequeueFull(t *testing.T) { + queue := New(2) + if actualValue, expectedValue := queue.Empty(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := queue.Full(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := queue.Size(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + queue.Enqueue(1) + if actualValue, expectedValue := queue.Size(), 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + queue.Enqueue(2) + if actualValue, expectedValue := queue.Size(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := queue.Full(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + + queue.Enqueue(3) // overwrites 1 + if actualValue, expectedValue := queue.Size(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, ok := queue.Peek(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + + if actualValue, ok := queue.Dequeue(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, expectedValue := queue.Size(), 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + if actualValue, ok := queue.Peek(); actualValue != 3 || !ok { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, expectedValue := queue.Size(), 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + if actualValue, ok := queue.Dequeue(); actualValue != 3 || !ok { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, expectedValue := queue.Size(), 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + if actualValue, ok := queue.Dequeue(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + if actualValue, expectedValue := queue.Empty(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := queue.Full(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := queue.Values(); len(actualValue) != 0 { + t.Errorf("Got %v expected %v", actualValue, "[]") + } +} + +func TestQueueIteratorOnEmpty(t *testing.T) { + queue := New(3) + it := queue.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty queue") + } +} + +func TestQueueIteratorNext(t *testing.T) { + queue := New(3) + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + it := queue.Iterator() + count := 0 + for it.Next() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; 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) + } + + queue.Clear() + it = queue.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty queue") + } +} + +func TestQueueIteratorPrev(t *testing.T) { + queue := New(3) + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + it := queue.Iterator() + for it.Next() { + } + count := 0 + for it.Prev() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := index, 3-count; 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 TestQueueIteratorBegin(t *testing.T) { + queue := New(3) + it := queue.Iterator() + it.Begin() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("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 TestQueueIteratorEnd(t *testing.T) { + queue := New(3) + it := queue.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) + } + + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + it.End() + if index := it.Index(); index != queue.Size() { + t.Errorf("Got %v expected %v", index, queue.Size()) + } + + it.Prev() + if index, value := it.Index(), it.Value(); index != queue.Size()-1 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, queue.Size()-1, "c") + } +} + +func TestQueueIteratorFirst(t *testing.T) { + queue := New(3) + it := queue.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + 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 TestQueueIteratorLast(t *testing.T) { + queue := New(3) + it := queue.Iterator() + if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + 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, 2, "c") + } +} + +func TestQueueIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + queue := New(3) + it := queue.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + } + + // NextTo (not found) + { + queue := New(3) + queue.Enqueue("xx") + queue.Enqueue("yy") + it := queue.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + } + + // NextTo (found) + { + queue := New(3) + queue.Enqueue("aa") + queue.Enqueue("bb") + queue.Enqueue("cc") + it := queue.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + +func TestQueueIteratorPrevTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // PrevTo (empty) + { + queue := New(3) + it := queue.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + } + + // PrevTo (not found) + { + queue := New(3) + queue.Enqueue("xx") + queue.Enqueue("yy") + it := queue.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + } + + // PrevTo (found) + { + queue := New(3) + queue.Enqueue("aa") + queue.Enqueue("bb") + queue.Enqueue("cc") + it := queue.Iterator() + it.End() + if !it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Prev() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "aa" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") + } + if it.Prev() { + t.Errorf("Should not go before first element") + } + } +} + +func TestQueueIterator(t *testing.T) { + queue := New(2) + + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") // overwrites "a" + + it := queue.Iterator() + + if actualIndex, expectedIndex := it.Index(), -1; actualIndex != expectedIndex { + t.Errorf("Got %v expected %v", actualIndex, expectedIndex) + } + + if !it.Next() { + t.Errorf("Still has some") + } + + if actualValue, actualIndex, expectedValue, expectedIndex := it.Value(), it.Index(), "b", 0; actualValue != expectedValue || actualIndex != expectedIndex { + t.Errorf("Got %v expected %v, Got %v expected %v", actualValue, expectedValue, actualIndex, expectedIndex) + } + + if !it.Next() { + t.Errorf("Still has some") + } + + if actualValue, actualIndex, expectedValue, expectedIndex := it.Value(), it.Index(), "c", 1; actualValue != expectedValue || actualIndex != expectedIndex { + t.Errorf("Got %v expected %v, Got %v expected %v", actualValue, expectedValue, actualIndex, expectedIndex) + } + + if it.Next() { + t.Errorf("Should have reached the end") + } + + if actualIndex, expectedIndex := it.Index(), 2; actualIndex != expectedIndex { + t.Errorf("Got %v expected %v", actualIndex, expectedIndex) + } + + if it.Next() { + t.Errorf("Should have reached the end") + } + + if !it.Prev() { + t.Errorf("Still has some") + } + + if actualValue, actualIndex, expectedValue, expectedIndex := it.Value(), it.Index(), "c", 1; actualValue != expectedValue || actualIndex != expectedIndex { + t.Errorf("Got %v expected %v, Got %v expected %v", actualValue, expectedValue, actualIndex, expectedIndex) + } + + if !it.Prev() { + t.Errorf("Still has some") + } + + if actualValue, actualIndex, expectedValue, expectedIndex := it.Value(), it.Index(), "b", 0; actualValue != expectedValue || actualIndex != expectedIndex { + t.Errorf("Got %v expected %v, Got %v expected %v", actualValue, expectedValue, actualIndex, expectedIndex) + } + + if it.Prev() { + t.Errorf("Nothing before this") + } + + if actualIndex, expectedIndex := it.Index(), -1; actualIndex != expectedIndex { + t.Errorf("Got %v expected %v", actualIndex, expectedIndex) + } +} + +func TestQueueSerialization(t *testing.T) { + queue := New(3) + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + var err error + assert := func() { + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", queue.Values()...), "abc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := queue.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + bytes, err := queue.ToJSON() + assert() + + err = queue.FromJSON(bytes) + assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", queue}) + if err != nil { + t.Errorf("Got error %v", err) + } + + err = json.Unmarshal([]byte(`[1,2,3]`), &queue) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestQueueString(t *testing.T) { + c := New(3) + c.Enqueue(1) + if !strings.HasPrefix(c.String(), "CircularBuffer") { + t.Errorf("String should start with container name") + } +} + +func benchmarkEnqueue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + } +} + +func benchmarkDequeue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Dequeue() + } + } +} + +func BenchmarkArrayQueueDequeue100(b *testing.B) { + b.StopTimer() + size := 100 + queue := New(3) + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueDequeue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := New(3) + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueDequeue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := New(3) + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueDequeue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := New(3) + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue100(b *testing.B) { + b.StopTimer() + size := 100 + queue := New(3) + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := New(3) + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := New(3) + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := New(3) + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} diff --git a/queues/circularbuffer/iterator.go b/queues/circularbuffer/iterator.go new file mode 100644 index 00000000..dae30ce4 --- /dev/null +++ b/queues/circularbuffer/iterator.go @@ -0,0 +1,112 @@ +// Copyright (c) 2021, 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 circularbuffer + +import "github.com/emirpasic/gods/containers" + +// Assert Iterator implementation +var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) + +// Iterator returns a stateful iterator whose values can be fetched by an index. +type Iterator struct { + queue *Queue + index int +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +func (queue *Queue) Iterator() Iterator { + return Iterator{queue: queue, index: -1} +} + +// 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 { + if iterator.index < iterator.queue.size { + iterator.index++ + } + return iterator.queue.withinRange(iterator.index) +} + +// 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 { + if iterator.index >= 0 { + iterator.index-- + } + return iterator.queue.withinRange(iterator.index) +} + +// Value returns the current element's value. +// Does not modify the state of the iterator. +func (iterator *Iterator) Value() interface{} { + index := (iterator.index + iterator.queue.start) % iterator.queue.maxSize + value := iterator.queue.values[index] + return value +} + +// Index returns the current element's index. +// Does not modify the state of the iterator. +func (iterator *Iterator) Index() int { + return 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.index = -1 +} + +// 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.index = iterator.queue.size +} + +// 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 { + iterator.Begin() + return iterator.Next() +} + +// 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 { + iterator.End() + return iterator.Prev() +} + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { + for iterator.Next() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} + +// PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool { + for iterator.Prev() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} diff --git a/queues/circularbuffer/serialization.go b/queues/circularbuffer/serialization.go new file mode 100644 index 00000000..da2543d0 --- /dev/null +++ b/queues/circularbuffer/serialization.go @@ -0,0 +1,41 @@ +// 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 circularbuffer + +import ( + "encoding/json" + "github.com/emirpasic/gods/containers" +) + +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Queue)(nil) +var _ containers.JSONDeserializer = (*Queue)(nil) + +// ToJSON outputs the JSON representation of queue's elements. +func (queue *Queue) ToJSON() ([]byte, error) { + return json.Marshal(queue.values[:queue.maxSize]) +} + +// FromJSON populates list's elements from the input JSON representation. +func (queue *Queue) FromJSON(data []byte) error { + var values []interface{} + err := json.Unmarshal(data, &values) + if err == nil { + for _, value := range values { + queue.Enqueue(value) + } + } + return err +} + +// UnmarshalJSON @implements json.Unmarshaler +func (queue *Queue) UnmarshalJSON(bytes []byte) error { + return queue.FromJSON(bytes) +} + +// MarshalJSON @implements json.Marshaler +func (queue *Queue) MarshalJSON() ([]byte, error) { + return queue.ToJSON() +} From 60093dc4a3b1578824e5fd369cd9a2946231f77c Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Thu, 14 Apr 2022 10:41:20 +0200 Subject: [PATCH 302/320] circualbuffer example --- examples/circularbuffer/circularbuffer.go | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 examples/circularbuffer/circularbuffer.go diff --git a/examples/circularbuffer/circularbuffer.go b/examples/circularbuffer/circularbuffer.go new file mode 100644 index 00000000..3bd5f2ae --- /dev/null +++ b/examples/circularbuffer/circularbuffer.go @@ -0,0 +1,26 @@ +// 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 cb "github.com/emirpasic/gods/queues/circularbuffer" + +// CircularBufferExample to demonstrate basic usage of CircularBuffer +func main() { + queue := cb.New(3) // empty (max size is 3) + queue.Enqueue(1) // 1 + queue.Enqueue(2) // 1, 2 + queue.Enqueue(3) // 1, 2, 3 + _ = queue.Values() // 1, 2, 3 + queue.Enqueue(3) // 4, 2, 3 + _, _ = queue.Peek() // 4,true + _, _ = queue.Dequeue() // 4, true + _, _ = queue.Dequeue() // 2, true + _, _ = queue.Dequeue() // 3, true + _, _ = queue.Dequeue() // nil, false (nothing to deque) + queue.Enqueue(1) // 1 + queue.Clear() // empty + queue.Empty() // true + _ = queue.Size() // 0 +} From 33e824351c01a31a351346e75d415a1742be5bfb Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Thu, 14 Apr 2022 11:38:57 +0200 Subject: [PATCH 303/320] Fix circular buffer tests --- queues/circularbuffer/circularbuffer_test.go | 168 ++++++------------- 1 file changed, 55 insertions(+), 113 deletions(-) diff --git a/queues/circularbuffer/circularbuffer_test.go b/queues/circularbuffer/circularbuffer_test.go index 2f826073..676ea7eb 100644 --- a/queues/circularbuffer/circularbuffer_test.go +++ b/queues/circularbuffer/circularbuffer_test.go @@ -48,122 +48,80 @@ func TestQueuePeek(t *testing.T) { } func TestQueueDequeue(t *testing.T) { - queue := New(3) - if actualValue, expectedValue := queue.Empty(), true; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := queue.Full(), false; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := queue.Size(), 0; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - queue.Enqueue(1) - if actualValue, expectedValue := queue.Size(), 1; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) + assert := func(actualValue interface{}, expectedValue interface{}) { + if actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } } + queue := New(3) + assert(queue.Empty(), true) + assert(queue.Empty(), true) + assert(queue.Full(), false) + assert(queue.Size(), 0) + queue.Enqueue(1) + assert(queue.Size(), 1) queue.Enqueue(2) - if actualValue, expectedValue := queue.Size(), 2; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + assert(queue.Size(), 2) queue.Enqueue(3) - if actualValue, expectedValue := queue.Size(), 3; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := queue.Empty(), false; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := queue.Full(), true; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + assert(queue.Size(), 3) + assert(queue.Empty(), false) + assert(queue.Full(), true) queue.Dequeue() - if actualValue, expectedValue := queue.Size(), 2; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + assert(queue.Size(), 2) if actualValue, ok := queue.Peek(); actualValue != 2 || !ok { t.Errorf("Got %v expected %v", actualValue, 2) } - if actualValue, expectedValue := queue.Size(), 2; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + assert(queue.Size(), 2) if actualValue, ok := queue.Dequeue(); actualValue != 2 || !ok { t.Errorf("Got %v expected %v", actualValue, 2) } - if actualValue, expectedValue := queue.Size(), 1; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + assert(queue.Size(), 1) if actualValue, ok := queue.Dequeue(); actualValue != 3 || !ok { t.Errorf("Got %v expected %v", actualValue, 3) } - if actualValue, expectedValue := queue.Size(), 0; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := queue.Empty(), true; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := queue.Full(), false; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + assert(queue.Size(), 0) + assert(queue.Empty(), true) + assert(queue.Full(), false) if actualValue, ok := queue.Dequeue(); actualValue != nil || ok { t.Errorf("Got %v expected %v", actualValue, nil) } - if actualValue, expectedValue := queue.Size(), 0; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + assert(queue.Size(), 0) - if actualValue := queue.Empty(); actualValue != true { - t.Errorf("Got %v expected %v", actualValue, true) - } - if actualValue := queue.Full(); actualValue != false { - t.Errorf("Got %v expected %v", actualValue, false) - } - if actualValue := queue.Values(); len(actualValue) != 0 { - t.Errorf("Got %v expected %v", actualValue, "[]") - } + assert(queue.Empty(), true) + assert(queue.Full(), false) + assert(len(queue.Values()), 0) } func TestQueueDequeueFull(t *testing.T) { - queue := New(2) - if actualValue, expectedValue := queue.Empty(), true; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := queue.Full(), false; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := queue.Size(), 0; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) + assert := func(actualValue interface{}, expectedValue interface{}) { + if actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } } + queue := New(2) + assert(queue.Empty(), true) + assert(queue.Full(), false) + assert(queue.Size(), 0) + queue.Enqueue(1) - if actualValue, expectedValue := queue.Size(), 1; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + assert(queue.Size(), 1) queue.Enqueue(2) - if actualValue, expectedValue := queue.Size(), 2; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := queue.Full(), true; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + assert(queue.Size(), 2) + assert(queue.Full(), true) if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { t.Errorf("Got %v expected %v", actualValue, 2) } - queue.Enqueue(3) // overwrites 1 - if actualValue, expectedValue := queue.Size(), 2; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, ok := queue.Peek(); actualValue != 2 || !ok { - t.Errorf("Got %v expected %v", actualValue, 2) - } + assert(queue.Size(), 2) if actualValue, ok := queue.Dequeue(); actualValue != 2 || !ok { t.Errorf("Got %v expected %v", actualValue, 2) @@ -182,22 +140,14 @@ func TestQueueDequeueFull(t *testing.T) { if actualValue, ok := queue.Dequeue(); actualValue != 3 || !ok { t.Errorf("Got %v expected %v", actualValue, 3) } - if actualValue, expectedValue := queue.Size(), 0; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + assert(queue.Size(), 0) if actualValue, ok := queue.Dequeue(); actualValue != nil || ok { t.Errorf("Got %v expected %v", actualValue, nil) } - if actualValue, expectedValue := queue.Empty(), true; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := queue.Full(), false; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue := queue.Values(); len(actualValue) != 0 { - t.Errorf("Got %v expected %v", actualValue, "[]") - } + assert(queue.Empty(), true) + assert(queue.Full(), false) + assert(len(queue.Values()), 0) } func TestQueueIteratorOnEmpty(t *testing.T) { @@ -474,6 +424,12 @@ func TestQueueIteratorPrevTo(t *testing.T) { } func TestQueueIterator(t *testing.T) { + assert := func(actualValue interface{}, expectedValue interface{}) { + if actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + queue := New(2) queue.Enqueue("a") @@ -486,53 +442,39 @@ func TestQueueIterator(t *testing.T) { t.Errorf("Got %v expected %v", actualIndex, expectedIndex) } - if !it.Next() { - t.Errorf("Still has some") - } + assert(it.Next(), true) if actualValue, actualIndex, expectedValue, expectedIndex := it.Value(), it.Index(), "b", 0; actualValue != expectedValue || actualIndex != expectedIndex { t.Errorf("Got %v expected %v, Got %v expected %v", actualValue, expectedValue, actualIndex, expectedIndex) } - if !it.Next() { - t.Errorf("Still has some") - } + assert(it.Next(), true) if actualValue, actualIndex, expectedValue, expectedIndex := it.Value(), it.Index(), "c", 1; actualValue != expectedValue || actualIndex != expectedIndex { t.Errorf("Got %v expected %v, Got %v expected %v", actualValue, expectedValue, actualIndex, expectedIndex) } - if it.Next() { - t.Errorf("Should have reached the end") - } + assert(it.Next(), false) if actualIndex, expectedIndex := it.Index(), 2; actualIndex != expectedIndex { t.Errorf("Got %v expected %v", actualIndex, expectedIndex) } - if it.Next() { - t.Errorf("Should have reached the end") - } + assert(it.Next(), false) - if !it.Prev() { - t.Errorf("Still has some") - } + assert(it.Prev(), true) if actualValue, actualIndex, expectedValue, expectedIndex := it.Value(), it.Index(), "c", 1; actualValue != expectedValue || actualIndex != expectedIndex { t.Errorf("Got %v expected %v, Got %v expected %v", actualValue, expectedValue, actualIndex, expectedIndex) } - if !it.Prev() { - t.Errorf("Still has some") - } + assert(it.Prev(), true) if actualValue, actualIndex, expectedValue, expectedIndex := it.Value(), it.Index(), "b", 0; actualValue != expectedValue || actualIndex != expectedIndex { t.Errorf("Got %v expected %v, Got %v expected %v", actualValue, expectedValue, actualIndex, expectedIndex) } - if it.Prev() { - t.Errorf("Nothing before this") - } + assert(it.Prev(), false) if actualIndex, expectedIndex := it.Index(), -1; actualIndex != expectedIndex { t.Errorf("Got %v expected %v", actualIndex, expectedIndex) From 6b0ffefe7f7ccad3bf653f453401b49a3d05048e Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 15 Apr 2022 00:07:42 +0200 Subject: [PATCH 304/320] Fix iterator in binary heap --- trees/binaryheap/binaryheap.go | 10 +++-- trees/binaryheap/binaryheap_test.go | 66 ++++++++++++++--------------- trees/binaryheap/iterator.go | 36 +++++++++++++++- 3 files changed, 74 insertions(+), 38 deletions(-) diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index b3412c5f..e658f257 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -97,15 +97,19 @@ func (heap *Heap) Clear() { // Values returns all elements in the heap. func (heap *Heap) Values() []interface{} { - return heap.list.Values() + values := make([]interface{}, heap.list.Size(), heap.list.Size()) + for it := heap.Iterator(); it.Next(); { + values[it.Index()] = it.Value() + } + return values } // String returns a string representation of container func (heap *Heap) String() string { str := "BinaryHeap\n" values := []string{} - for _, value := range heap.list.Values() { - values = append(values, fmt.Sprintf("%v", value)) + for it := heap.Iterator(); it.Next(); { + values = append(values, fmt.Sprintf("%v", it.Value())) } str += strings.Join(values, ", ") return str diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go index 26d99ea9..bb5c42b1 100644 --- a/trees/binaryheap/binaryheap_test.go +++ b/trees/binaryheap/binaryheap_test.go @@ -18,11 +18,11 @@ func TestBinaryHeapPush(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, true) } - heap.Push(3) // [3] - heap.Push(2) // [2,3] - heap.Push(1) // [1,3,2](2 swapped with 1, hence last) + heap.Push(3) + heap.Push(2) + heap.Push(1) - if actualValue := heap.Values(); actualValue[0].(int) != 1 || actualValue[1].(int) != 3 || actualValue[2].(int) != 2 { + if actualValue := heap.Values(); actualValue[0].(int) != 1 || actualValue[1].(int) != 2 || actualValue[2].(int) != 3 { t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") } if actualValue := heap.Empty(); actualValue != false { @@ -56,10 +56,10 @@ func TestBinaryHeapPop(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, true) } - heap.Push(3) // [3] - heap.Push(2) // [2,3] - heap.Push(1) // [1,3,2](2 swapped with 1, hence last) - heap.Pop() // [3,2] + heap.Push(3) + heap.Push(2) + heap.Push(1) + heap.Pop() if actualValue, ok := heap.Peek(); actualValue != 2 || !ok { t.Errorf("Got %v expected %v", actualValue, 2) @@ -110,9 +110,9 @@ func TestBinaryHeapIteratorOnEmpty(t *testing.T) { func TestBinaryHeapIteratorNext(t *testing.T) { heap := NewWithIntComparator() - heap.Push(3) // [3] - heap.Push(2) // [2,3] - heap.Push(1) // [1,3,2](2 swapped with 1, hence last) + heap.Push(3) + heap.Push(2) + heap.Push(1) it := heap.Iterator() count := 0 @@ -126,11 +126,11 @@ func TestBinaryHeapIteratorNext(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } case 1: - if actualValue, expectedValue := value, 3; actualValue != expectedValue { + if actualValue, expectedValue := value, 2; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } case 2: - if actualValue, expectedValue := value, 2; actualValue != expectedValue { + if actualValue, expectedValue := value, 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } default: @@ -147,9 +147,9 @@ func TestBinaryHeapIteratorNext(t *testing.T) { func TestBinaryHeapIteratorPrev(t *testing.T) { heap := NewWithIntComparator() - heap.Push(3) // [3] - heap.Push(2) // [2,3] - heap.Push(1) // [1,3,2](2 swapped with 1, hence last) + heap.Push(3) + heap.Push(2) + heap.Push(1) it := heap.Iterator() for it.Next() { @@ -165,11 +165,11 @@ func TestBinaryHeapIteratorPrev(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } case 1: - if actualValue, expectedValue := value, 3; actualValue != expectedValue { + if actualValue, expectedValue := value, 2; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } case 2: - if actualValue, expectedValue := value, 2; actualValue != expectedValue { + if actualValue, expectedValue := value, 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } default: @@ -213,17 +213,17 @@ func TestBinaryHeapIteratorEnd(t *testing.T) { t.Errorf("Got %v expected %v", index, 0) } - heap.Push(3) // [3] - heap.Push(2) // [2,3] - heap.Push(1) // [1,3,2](2 swapped with 1, hence last) + heap.Push(3) + heap.Push(2) + heap.Push(1) it.End() if index := it.Index(); index != heap.Size() { t.Errorf("Got %v expected %v", index, heap.Size()) } it.Prev() - if index, value := it.Index(), it.Value(); index != heap.Size()-1 || value != 2 { - t.Errorf("Got %v,%v expected %v,%v", index, value, heap.Size()-1, 2) + if index, value := it.Index(), it.Value(); index != heap.Size()-1 || value != 3 { + t.Errorf("Got %v,%v expected %v,%v", index, value, heap.Size()-1, 3) } } @@ -233,9 +233,9 @@ func TestBinaryHeapIteratorFirst(t *testing.T) { if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - heap.Push(3) // [3] - heap.Push(2) // [2,3] - heap.Push(1) // [1,3,2](2 swapped with 1, hence last) + heap.Push(3) + heap.Push(2) + heap.Push(1) if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } @@ -252,12 +252,12 @@ func TestBinaryHeapIteratorLast(t *testing.T) { } tree.Push(2) tree.Push(3) - tree.Push(1) // [1,3,2](2 swapped with 1, hence last) + tree.Push(1) 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 != 2 { - t.Errorf("Got %v,%v expected %v,%v", index, value, 2, 2) + if index, value := it.Index(), it.Value(); index != 2 || value != 3 { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, 3) } } @@ -370,13 +370,13 @@ func TestBinaryHeapIteratorPrevTo(t *testing.T) { func TestBinaryHeapSerialization(t *testing.T) { heap := NewWithStringComparator() - heap.Push("c") // ["c"] - heap.Push("b") // ["b","c"] - heap.Push("a") // ["a","c","b"]("b" swapped with "a", hence last) + heap.Push("c") + heap.Push("b") + heap.Push("a") var err error assert := func() { - if actualValue := heap.Values(); actualValue[0].(string) != "a" || actualValue[1].(string) != "c" || actualValue[2].(string) != "b" { + if actualValue := heap.Values(); actualValue[0].(string) != "a" || actualValue[1].(string) != "b" || actualValue[2].(string) != "c" { t.Errorf("Got %v expected %v", actualValue, "[1,3,2]") } if actualValue := heap.Size(); actualValue != 3 { diff --git a/trees/binaryheap/iterator.go b/trees/binaryheap/iterator.go index 8a01b05b..f2179633 100644 --- a/trees/binaryheap/iterator.go +++ b/trees/binaryheap/iterator.go @@ -4,7 +4,9 @@ package binaryheap -import "github.com/emirpasic/gods/containers" +import ( + "github.com/emirpasic/gods/containers" +) // Assert Iterator implementation var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) @@ -44,7 +46,19 @@ func (iterator *Iterator) Prev() bool { // Value returns the current element's value. // Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { - value, _ := iterator.heap.list.Get(iterator.index) + start, end := evaluateRange(iterator.index) + if end > iterator.heap.Size() { + end = iterator.heap.Size() + } + tmpHeap := NewWith(iterator.heap.Comparator) + for n := start; n < end; n++ { + value, _ := iterator.heap.list.Get(n) + tmpHeap.Push(value) + } + for n := 0; n < iterator.index-start; n++ { + tmpHeap.Pop() + } + value, _ := tmpHeap.Pop() return value } @@ -109,3 +123,21 @@ func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool } return false } + +// numOfBits counts the number of bits of an int +func numOfBits(n int) uint { + var count uint + for n != 0 { + count++ + n >>= 1 + } + return count +} + +// evaluateRange evaluates the index range [start,end) of same level nodes in the heap as the index +func evaluateRange(index int) (start int, end int) { + bits := numOfBits(index+1) - 1 + start = 1< Date: Fri, 15 Apr 2022 01:01:35 +0200 Subject: [PATCH 305/320] Implements PriorityQueue --- README.md | 51 ++ examples/priorityqueue/priorityqueue.go | 44 ++ queues/priorityqueue/iterator.go | 92 ++++ queues/priorityqueue/priorityqueue.go | 86 ++++ queues/priorityqueue/priorityqueue_test.go | 570 +++++++++++++++++++++ queues/priorityqueue/serialization.go | 33 ++ 6 files changed, 876 insertions(+) create mode 100644 examples/priorityqueue/priorityqueue.go create mode 100644 queues/priorityqueue/iterator.go create mode 100644 queues/priorityqueue/priorityqueue.go create mode 100644 queues/priorityqueue/priorityqueue_test.go create mode 100644 queues/priorityqueue/serialization.go diff --git a/README.md b/README.md index 0925a5a1..a584a2ae 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ Implementation of various data structures and algorithms in Go. - [LinkedListQueue](#linkedlistqueue) - [ArrayQueue](#arrayqueue) - [CircularBuffer](#circularbuffer) + - [PriorityQueue](#priorityqueue) - [Functions](#functions) - [Comparator](#comparator) - [Iterator](#iterator) @@ -102,6 +103,7 @@ Containers are either ordered or unordered. All ordered containers provide [stat | | [LinkedListQueue](#linkedlistqueue) | yes | yes | no | index | | | [ArrayQueue](#arrayqueue) | yes | yes* | no | index | | | [CircularBuffer](#circularbuffer) | yes | yes* | no | index | +| | [PriorityQueue](#priorityqueue) | yes | yes* | no | index | | | | | *reversible | | *bidirectional | ### Lists @@ -984,6 +986,55 @@ func main() { } ``` +#### PriorityQueue + +A priority queue is a special type of [queue](#queues) in which each element is associated with a priority value. And, elements are served on the basis of their priority. That is, higher priority elements are served first. However, if elements with the same priority occur, they are served according to their order in the queue. + +Implements [Queue](#queues), [ReverseIteratorWithIndex](#iteratorwithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. + +```go +package main + +import ( + pq "github.com/emirpasic/gods/queues/priorityqueue" + "github.com/emirpasic/gods/utils" +) + +// Element is an entry in the priority queue +type Element struct { + name string + priority int +} + +// Comparator function (sort by element's priority value in descending order) +func byPriority(a, b interface{}) int { + priorityA := a.(Element).priority + priorityB := b.(Element).priority + return -utils.IntComparator(priorityA, priorityB) // "-" descending order +} + +// PriorityQueueExample to demonstrate basic usage of BinaryHeap +func main() { + a := Element{name: "a", priority: 1} + b := Element{name: "b", priority: 2} + c := Element{name: "c", priority: 3} + + queue := pq.NewWith(byPriority) // empty + queue.Enqueue(a) // {a 1} + queue.Enqueue(c) // {c 3}, {a 1} + queue.Enqueue(b) // {c 3}, {b 2}, {a 1} + _ = queue.Values() // [{c 3} {b 2} {a 1}] + _, _ = queue.Peek() // {c 3} true + _, _ = queue.Dequeue() // {c 3} true + _, _ = queue.Dequeue() // {b 2} true + _, _ = queue.Dequeue() // {a 1} true + _, _ = queue.Dequeue() // false (nothing to dequeue) + queue.Clear() // empty + _ = queue.Empty() // true + _ = queue.Size() // 0 +} +``` + ## Functions Various helper functions used throughout the library. diff --git a/examples/priorityqueue/priorityqueue.go b/examples/priorityqueue/priorityqueue.go new file mode 100644 index 00000000..11fd1e57 --- /dev/null +++ b/examples/priorityqueue/priorityqueue.go @@ -0,0 +1,44 @@ +// 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 ( + pq "github.com/emirpasic/gods/queues/priorityqueue" + "github.com/emirpasic/gods/utils" +) + +// Element is an entry in the priority queue +type Element struct { + name string + priority int +} + +// Comparator function (sort by element's priority value in descending order) +func byPriority(a, b interface{}) int { + priorityA := a.(Element).priority + priorityB := b.(Element).priority + return -utils.IntComparator(priorityA, priorityB) // "-" descending order +} + +// PriorityQueueExample to demonstrate basic usage of BinaryHeap +func main() { + a := Element{name: "a", priority: 1} + b := Element{name: "b", priority: 2} + c := Element{name: "c", priority: 3} + + queue := pq.NewWith(byPriority) // empty + queue.Enqueue(a) // {a 1} + queue.Enqueue(c) // {c 3}, {a 1} + queue.Enqueue(b) // {c 3}, {b 2}, {a 1} + _ = queue.Values() // [{c 3} {b 2} {a 1}] + _, _ = queue.Peek() // {c 3} true + _, _ = queue.Dequeue() // {c 3} true + _, _ = queue.Dequeue() // {b 2} true + _, _ = queue.Dequeue() // {a 1} true + _, _ = queue.Dequeue() // false (nothing to dequeue) + queue.Clear() // empty + _ = queue.Empty() // true + _ = queue.Size() // 0 +} diff --git a/queues/priorityqueue/iterator.go b/queues/priorityqueue/iterator.go new file mode 100644 index 00000000..ea6181a2 --- /dev/null +++ b/queues/priorityqueue/iterator.go @@ -0,0 +1,92 @@ +// 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 priorityqueue + +import ( + "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/trees/binaryheap" +) + +// Assert Iterator implementation +var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) + +// Iterator returns a stateful iterator whose values can be fetched by an index. +type Iterator struct { + iterator binaryheap.Iterator +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +func (queue *Queue) Iterator() Iterator { + return Iterator{iterator: queue.heap.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() +} + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { + return iterator.iterator.NextTo(f) +} + +// PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the +// 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. +func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool { + return iterator.iterator.PrevTo(f) +} diff --git a/queues/priorityqueue/priorityqueue.go b/queues/priorityqueue/priorityqueue.go new file mode 100644 index 00000000..3a7e6f22 --- /dev/null +++ b/queues/priorityqueue/priorityqueue.go @@ -0,0 +1,86 @@ +// 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 priorityqueue implements a priority queue backed by binary queue. +// +// An unbounded priority queue based on a priority queue. +// The elements of the priority queue are ordered by a comparator provided at queue construction time. +// +// The heap of this queue is the least/smallest element with respect to the specified ordering. +// If multiple elements are tied for least value, the heap is one of those elements arbitrarily. +// +// Structure is not thread safe. +// +// References: https://en.wikipedia.org/wiki/Priority_queue +package priorityqueue + +import ( + "fmt" + "github.com/emirpasic/gods/queues" + "github.com/emirpasic/gods/trees/binaryheap" + "github.com/emirpasic/gods/utils" + "strings" +) + +// Assert Queue implementation +var _ queues.Queue = (*Queue)(nil) + +// Queue holds elements in an array-list +type Queue struct { + heap *binaryheap.Heap + Comparator utils.Comparator +} + +// NewWith instantiates a new empty queue with the custom comparator. +func NewWith(comparator utils.Comparator) *Queue { + return &Queue{heap: binaryheap.NewWith(comparator), Comparator: comparator} +} + +// Enqueue adds a value to the end of the queue +func (queue *Queue) Enqueue(value interface{}) { + queue.heap.Push(value) +} + +// Dequeue removes first element of the queue and returns it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to dequeue. +func (queue *Queue) Dequeue() (value interface{}, ok bool) { + return queue.heap.Pop() +} + +// Peek returns top element on the queue without removing it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to peek. +func (queue *Queue) Peek() (value interface{}, ok bool) { + return queue.heap.Peek() +} + +// Empty returns true if queue does not contain any elements. +func (queue *Queue) Empty() bool { + return queue.heap.Empty() +} + +// Size returns number of elements within the queue. +func (queue *Queue) Size() int { + return queue.heap.Size() +} + +// Clear removes all elements from the queue. +func (queue *Queue) Clear() { + queue.heap.Clear() +} + +// Values returns all elements in the queue. +func (queue *Queue) Values() []interface{} { + return queue.heap.Values() +} + +// String returns a string representation of container +func (queue *Queue) String() string { + str := "PriorityQueue\n" + values := make([]string, queue.heap.Size(), queue.heap.Size()) + for index, value := range queue.heap.Values() { + values[index] = fmt.Sprintf("%v", value) + } + str += strings.Join(values, ", ") + return str +} diff --git a/queues/priorityqueue/priorityqueue_test.go b/queues/priorityqueue/priorityqueue_test.go new file mode 100644 index 00000000..7615fcad --- /dev/null +++ b/queues/priorityqueue/priorityqueue_test.go @@ -0,0 +1,570 @@ +// 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 priorityqueue + +import ( + "encoding/json" + "fmt" + "github.com/emirpasic/gods/utils" + "math/rand" + "strings" + "testing" +) + +type Element struct { + priority int + name string +} + +func (element Element) String() string { + return fmt.Sprintf("{%v %v}", element.priority, element.name) +} + +// Comparator function (sort by priority value in descending order) +func byPriority(a, b interface{}) int { + return -utils.IntComparator( // Note "-" for descending order + a.(Element).priority, + b.(Element).priority, + ) +} + +func TestBinaryQueueEnqueue(t *testing.T) { + queue := NewWith(byPriority) + + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + + a := Element{name: "a", priority: 1} + c := Element{name: "c", priority: 3} + b := Element{name: "b", priority: 2} + + queue.Enqueue(a) + queue.Enqueue(c) + queue.Enqueue(b) + + it := queue.Iterator() + count := 0 + for it.Next() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value.(Element).name, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value.(Element).name, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value.(Element).name, "a"; 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 := queue.Values(); actualValue[0].(Element).name != "c" || actualValue[1].(Element).name != "b" || actualValue[2].(Element).name != "a" { + t.Errorf("Got %v expected %v", actualValue, `[{3 c} {2 b} {1 a}]`) + } +} + +func TestBinaryQueueEnqueueBulk(t *testing.T) { + queue := NewWith(utils.IntComparator) + + queue.Enqueue(15) + queue.Enqueue(20) + queue.Enqueue(3) + queue.Enqueue(1) + queue.Enqueue(2) + + if actualValue, ok := queue.Dequeue(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } + if actualValue, ok := queue.Dequeue(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, ok := queue.Dequeue(); actualValue != 3 || !ok { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Dequeue(); actualValue != 15 || !ok { + t.Errorf("Got %v expected %v", actualValue, 15) + } + if actualValue, ok := queue.Dequeue(); actualValue != 20 || !ok { + t.Errorf("Got %v expected %v", actualValue, 20) + } +} + +func TestBinaryQueueDequeue(t *testing.T) { + queue := NewWith(utils.IntComparator) + + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + + queue.Enqueue(3) + queue.Enqueue(2) + queue.Enqueue(1) + queue.Dequeue() // removes 1 + + if actualValue, ok := queue.Dequeue(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, ok := queue.Dequeue(); actualValue != 3 || !ok { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Dequeue(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + if actualValue := queue.Values(); len(actualValue) != 0 { + t.Errorf("Got %v expected %v", actualValue, "[]") + } +} + +func TestBinaryQueueRandom(t *testing.T) { + queue := NewWith(utils.IntComparator) + + rand.Seed(3) + for i := 0; i < 10000; i++ { + r := int(rand.Int31n(30)) + queue.Enqueue(r) + } + + prev, _ := queue.Dequeue() + for !queue.Empty() { + curr, _ := queue.Dequeue() + if prev.(int) > curr.(int) { + t.Errorf("Queue property invalidated. prev: %v current: %v", prev, curr) + } + prev = curr + } +} + +func TestBinaryQueueIteratorOnEmpty(t *testing.T) { + queue := NewWith(utils.IntComparator) + it := queue.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty queue") + } +} + +func TestBinaryQueueIteratorNext(t *testing.T) { + queue := NewWith(utils.IntComparator) + queue.Enqueue(3) + queue.Enqueue(2) + queue.Enqueue(1) + + it := queue.Iterator() + count := 0 + for it.Next() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, 3; 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 TestBinaryQueueIteratorPrev(t *testing.T) { + queue := NewWith(utils.IntComparator) + queue.Enqueue(3) + queue.Enqueue(2) + queue.Enqueue(1) + + it := queue.Iterator() + for it.Next() { + } + count := 0 + for it.Prev() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := index, 3-count; 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 TestBinaryQueueIteratorBegin(t *testing.T) { + queue := NewWith(utils.IntComparator) + it := queue.Iterator() + it.Begin() + queue.Enqueue(2) + queue.Enqueue(3) + queue.Enqueue(1) + for it.Next() { + } + it.Begin() + it.Next() + if index, value := it.Index(), it.Value(); index != 0 || value != 1 { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, 1) + } +} + +func TestBinaryQueueIteratorEnd(t *testing.T) { + queue := NewWith(utils.IntComparator) + it := queue.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) + } + + queue.Enqueue(3) + queue.Enqueue(2) + queue.Enqueue(1) + it.End() + if index := it.Index(); index != queue.Size() { + t.Errorf("Got %v expected %v", index, queue.Size()) + } + + it.Prev() + if index, value := it.Index(), it.Value(); index != queue.Size()-1 || value != 3 { + t.Errorf("Got %v,%v expected %v,%v", index, value, queue.Size()-1, 3) + } +} + +func TestBinaryQueueIteratorFirst(t *testing.T) { + queue := NewWith(utils.IntComparator) + it := queue.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + queue.Enqueue(3) // [3] + queue.Enqueue(2) // [2,3] + queue.Enqueue(1) // [1,3,2](2 swapped with 1, hence last) + 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 != 1 { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, 1) + } +} + +func TestBinaryQueueIteratorLast(t *testing.T) { + tree := NewWith(utils.IntComparator) + it := tree.Iterator() + if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + tree.Enqueue(2) + tree.Enqueue(3) + tree.Enqueue(1) + 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 != 3 { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, 3) + } +} + +func TestBinaryQueueIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + tree := NewWith(utils.StringComparator) + it := tree.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + } + + // NextTo (not found) + { + tree := NewWith(utils.StringComparator) + tree.Enqueue("xx") + tree.Enqueue("yy") + it := tree.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + } + + // NextTo (found) + { + tree := NewWith(utils.StringComparator) + tree.Enqueue("aa") + tree.Enqueue("bb") + tree.Enqueue("cc") + it := tree.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + +func TestBinaryQueueIteratorPrevTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // PrevTo (empty) + { + tree := NewWith(utils.StringComparator) + it := tree.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + } + + // PrevTo (not found) + { + tree := NewWith(utils.StringComparator) + tree.Enqueue("xx") + tree.Enqueue("yy") + it := tree.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + } + + // PrevTo (found) + { + tree := NewWith(utils.StringComparator) + tree.Enqueue("aa") + tree.Enqueue("bb") + tree.Enqueue("cc") + it := tree.Iterator() + it.End() + if !it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty list") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Prev() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "aa" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") + } + if it.Prev() { + t.Errorf("Should not go before first element") + } + } +} + +func TestBinaryQueueSerialization(t *testing.T) { + queue := NewWith(utils.StringComparator) + + queue.Enqueue("c") + queue.Enqueue("b") + queue.Enqueue("a") + + var err error + assert := func() { + if actualValue := queue.Values(); actualValue[0].(string) != "a" || actualValue[1].(string) != "b" || actualValue[2].(string) != "c" { + t.Errorf("Got %v expected %v", actualValue, "[1,3,2]") + } + if actualValue := queue.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Peek(); actualValue != "a" || !ok { + t.Errorf("Got %v expected %v", actualValue, "a") + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + bytes, err := queue.ToJSON() + assert() + + err = queue.FromJSON(bytes) + assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", queue}) + if err != nil { + t.Errorf("Got error %v", err) + } + + err = json.Unmarshal([]byte(`[1,2,3]`), &queue) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestBTreeString(t *testing.T) { + c := NewWith(byPriority) + c.Enqueue(1) + if !strings.HasPrefix(c.String(), "PriorityQueue") { + t.Errorf("String should start with container name") + } +} + +func benchmarkEnqueue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + } +} + +func benchmarkDequeue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Dequeue() + } + } +} + +func BenchmarkBinaryQueueDequeue100(b *testing.B) { + b.StopTimer() + size := 100 + queue := NewWith(byPriority) + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkBinaryQueueDequeue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := NewWith(byPriority) + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkBinaryQueueDequeue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := NewWith(byPriority) + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkBinaryQueueDequeue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := NewWith(byPriority) + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkBinaryQueueEnqueue100(b *testing.B) { + b.StopTimer() + size := 100 + queue := NewWith(byPriority) + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkBinaryQueueEnqueue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := NewWith(byPriority) + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkBinaryQueueEnqueue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := NewWith(byPriority) + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkBinaryQueueEnqueue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := NewWith(byPriority) + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} diff --git a/queues/priorityqueue/serialization.go b/queues/priorityqueue/serialization.go new file mode 100644 index 00000000..6072a168 --- /dev/null +++ b/queues/priorityqueue/serialization.go @@ -0,0 +1,33 @@ +// 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 priorityqueue + +import ( + "github.com/emirpasic/gods/containers" +) + +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Queue)(nil) +var _ containers.JSONDeserializer = (*Queue)(nil) + +// ToJSON outputs the JSON representation of the queue. +func (queue *Queue) ToJSON() ([]byte, error) { + return queue.heap.ToJSON() +} + +// FromJSON populates the queue from the input JSON representation. +func (queue *Queue) FromJSON(data []byte) error { + return queue.heap.FromJSON(data) +} + +// UnmarshalJSON @implements json.Unmarshaler +func (queue *Queue) UnmarshalJSON(bytes []byte) error { + return queue.FromJSON(bytes) +} + +// MarshalJSON @implements json.Marshaler +func (queue *Queue) MarshalJSON() ([]byte, error) { + return queue.ToJSON() +} From 2bf1bd3affa6ac9ec6b22de266cd4677ff75f428 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 15 Apr 2022 01:04:03 +0200 Subject: [PATCH 306/320] Implements PriorityQueue --- queues/priorityqueue/priorityqueue_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/queues/priorityqueue/priorityqueue_test.go b/queues/priorityqueue/priorityqueue_test.go index 7615fcad..1036fdbb 100644 --- a/queues/priorityqueue/priorityqueue_test.go +++ b/queues/priorityqueue/priorityqueue_test.go @@ -101,6 +101,11 @@ func TestBinaryQueueEnqueueBulk(t *testing.T) { if actualValue, ok := queue.Dequeue(); actualValue != 20 || !ok { t.Errorf("Got %v expected %v", actualValue, 20) } + + queue.Clear() + if actualValue := queue.Empty(); !actualValue { + t.Errorf("Got %v expected %v", actualValue, true) + } } func TestBinaryQueueDequeue(t *testing.T) { From e63524608b64baeeaeb3469c8cbd49aa9f2c7ed1 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Fri, 15 Apr 2022 02:17:46 +0200 Subject: [PATCH 307/320] Testing funding.yml --- .github/FUNDING.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..8a4f7704 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: godatastructures +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] \ No newline at end of file From b486cc91bf4bc89e2213067cc005c30a3738a780 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 18 Apr 2022 20:14:01 +0200 Subject: [PATCH 308/320] Fix in ArrayList.Contains function against nil values --- lists/arraylist/arraylist.go | 4 ++-- lists/arraylist/arraylist_test.go | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index 41327bb2..60ce4583 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -82,8 +82,8 @@ func (list *List) Contains(values ...interface{}) bool { for _, searchValue := range values { found := false - for _, element := range list.elements { - if element == searchValue { + for index := 0; index < list.size; index++ { + if list.elements[index] == searchValue { found = true break } diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index d490ba70..3b7c8d77 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -164,6 +164,9 @@ func TestListContains(t *testing.T) { if actualValue := list.Contains("a"); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } + if actualValue := list.Contains(nil); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, false) + } if actualValue := list.Contains("a", "b", "c"); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } From 789e39cb69fcc60ba1ad3b64e2f9511315590d09 Mon Sep 17 00:00:00 2001 From: Ryoh Akiyoshi Date: Sat, 15 Oct 2022 23:59:12 +0900 Subject: [PATCH 309/320] fix documentation --- trees/avltree/avltree.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index 128d3133..ec2765cd 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -148,7 +148,7 @@ func (t *Tree) Right() *Node { return t.bottom(1) } -// Floor Finds floor node of the input key, return the floor node or nil if no ceiling is found. +// Floor Finds floor node of the input key, return the floor node or nil if no floor is found. // Second return parameter is true if floor was found, otherwise false. // // Floor node is defined as the largest node that is smaller than or equal to the given node. From 9f3e98d84ae0755196be26ae099772039420c539 Mon Sep 17 00:00:00 2001 From: Ugur SEN Date: Wed, 18 Jan 2023 03:01:29 +0300 Subject: [PATCH 310/320] Benchmark bug fixed(interface conversion). go test -run=NO_TEST -bench . -benchmem -benchtime 1s This command gives an error (panic: interface conversion: interface {} is int, not priorityqueue.Element) and to fix this enqueue(n)s changed to enqueu(Element{})s. --- queues/priorityqueue/priorityqueue_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/queues/priorityqueue/priorityqueue_test.go b/queues/priorityqueue/priorityqueue_test.go index 1036fdbb..6c0db896 100644 --- a/queues/priorityqueue/priorityqueue_test.go +++ b/queues/priorityqueue/priorityqueue_test.go @@ -476,7 +476,7 @@ func TestBTreeString(t *testing.T) { func benchmarkEnqueue(b *testing.B, queue *Queue, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { - queue.Enqueue(n) + queue.Enqueue(Element{}) } } } @@ -494,7 +494,7 @@ func BenchmarkBinaryQueueDequeue100(b *testing.B) { size := 100 queue := NewWith(byPriority) for n := 0; n < size; n++ { - queue.Enqueue(n) + queue.Enqueue(Element{}) } b.StartTimer() benchmarkDequeue(b, queue, size) @@ -505,7 +505,7 @@ func BenchmarkBinaryQueueDequeue1000(b *testing.B) { size := 1000 queue := NewWith(byPriority) for n := 0; n < size; n++ { - queue.Enqueue(n) + queue.Enqueue(Element{}) } b.StartTimer() benchmarkDequeue(b, queue, size) @@ -516,7 +516,7 @@ func BenchmarkBinaryQueueDequeue10000(b *testing.B) { size := 10000 queue := NewWith(byPriority) for n := 0; n < size; n++ { - queue.Enqueue(n) + queue.Enqueue(Element{}) } b.StartTimer() benchmarkDequeue(b, queue, size) @@ -527,7 +527,7 @@ func BenchmarkBinaryQueueDequeue100000(b *testing.B) { size := 100000 queue := NewWith(byPriority) for n := 0; n < size; n++ { - queue.Enqueue(n) + queue.Enqueue(Element{}) } b.StartTimer() benchmarkDequeue(b, queue, size) @@ -546,7 +546,7 @@ func BenchmarkBinaryQueueEnqueue1000(b *testing.B) { size := 1000 queue := NewWith(byPriority) for n := 0; n < size; n++ { - queue.Enqueue(n) + queue.Enqueue(Element{}) } b.StartTimer() benchmarkEnqueue(b, queue, size) @@ -557,7 +557,7 @@ func BenchmarkBinaryQueueEnqueue10000(b *testing.B) { size := 10000 queue := NewWith(byPriority) for n := 0; n < size; n++ { - queue.Enqueue(n) + queue.Enqueue(Element{}) } b.StartTimer() benchmarkEnqueue(b, queue, size) @@ -568,7 +568,7 @@ func BenchmarkBinaryQueueEnqueue100000(b *testing.B) { size := 100000 queue := NewWith(byPriority) for n := 0; n < size; n++ { - queue.Enqueue(n) + queue.Enqueue(Element{}) } b.StartTimer() benchmarkEnqueue(b, queue, size) From 608766492ea660cb1674a7f71d37889b16cbbb45 Mon Sep 17 00:00:00 2001 From: Ben Kogan Date: Mon, 4 Sep 2023 00:44:46 -0400 Subject: [PATCH 311/320] fix: doublylinkedlist insertion with last to first traversal --- lists/doublylinkedlist/doublylinkedlist.go | 9 +++++---- .../doublylinkedlist/doublylinkedlist_test.go | 19 +++++++++++++------ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index ab63de48..d0e2b3a6 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -177,7 +177,7 @@ func (list *List) Values() []interface{} { return values } -//IndexOf returns index of provided element +// IndexOf returns index of provided element func (list *List) IndexOf(value interface{}) int { if list.size == 0 { return -1 @@ -252,15 +252,14 @@ func (list *List) Insert(index int, values ...interface{}) { return } - list.size += len(values) - var beforeElement *element var foundElement *element // determine traversal direction, last to first or first to last if list.size-index < index { foundElement = list.last + beforeElement = list.last.prev for e := list.size - 1; e != index; e, foundElement = e-1, foundElement.prev { - beforeElement = foundElement.prev + beforeElement = beforeElement.prev } } else { foundElement = list.first @@ -294,6 +293,8 @@ func (list *List) Insert(index int, values ...interface{}) { oldNextElement.prev = beforeElement beforeElement.next = oldNextElement } + + list.size += len(values) } // Set value at specified index position diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index a69c6999..312d5ff2 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -213,17 +213,24 @@ func TestListIndexOf(t *testing.T) { func TestListInsert(t *testing.T) { list := New() - list.Insert(0, "b", "c") + list.Insert(0, "b", "c", "d") list.Insert(0, "a") list.Insert(10, "x") // ignore - if actualValue := list.Size(); actualValue != 3 { - t.Errorf("Got %v expected %v", actualValue, 3) - } - list.Insert(3, "d") // append if actualValue := list.Size(); actualValue != 4 { t.Errorf("Got %v expected %v", actualValue, 4) } - if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", list.Values()...), "abcd"; actualValue != expectedValue { + list.Insert(4, "g") // append + if actualValue := list.Size(); actualValue != 5 { + t.Errorf("Got %v expected %v", actualValue, 5) + } + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s", list.Values()...), "abcdg"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + list.Insert(4, "e", "f") // last to first traversal + if actualValue := list.Size(); actualValue != 7 { + t.Errorf("Got %v expected %v", actualValue, 7) + } + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s", list.Values()...), "abcdefg"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } From 14f714261f50e6d3e4af1cd29e4ae11ffdedab94 Mon Sep 17 00:00:00 2001 From: Paul Chesnais Date: Sat, 6 Jan 2024 19:06:17 -0500 Subject: [PATCH 312/320] Generics migration (#237) * Generics migration This attempts to migrate this library in the least invasive way by preserving as much of the original API as possible. It does not change the tests in a meaningful way nor does it attempt to upgrade any logic that can be simplified or improved with generics. This is purely an API migration, and still requires a lot of additional work to be fully ready. * Fix a few broken tests around serialization * Add v2 suffix * Temporarily change mod name for testing * Rename module to /v2 --- containers/containers.go | 25 +- containers/containers_test.go | 48 +-- containers/enumerable.go | 20 +- containers/iterator.go | 30 +- examples/arraylist/arraylist.go | 9 +- examples/arrayqueue/arrayqqueue.go | 4 +- examples/arraystack/arraystack.go | 26 +- examples/avltree/avltree.go | 5 +- examples/binaryheap/binaryheap.go | 37 +-- examples/btree/btree.go | 5 +- examples/circularbuffer/circularbuffer.go | 32 +- examples/customcomparator/customcomparator.go | 13 +- examples/doublylinkedlist/doublylinkedlist.go | 9 +- .../enumerablewithindex.go | 37 +-- .../enumerablewithkey/enumerablewithkey.go | 39 +-- examples/godsort/godsort.go | 17 -- examples/hashbidimap/hashbidimap.go | 30 +- examples/hashmap/hashmap.go | 26 +- examples/hashset/hashset.go | 26 +- .../iteratorwithindex/iteratorwithindex.go | 9 +- examples/iteratorwithkey/iteratorwithkey.go | 9 +- examples/linkedhashmap/linkedhashmap.go | 26 +- examples/linkedhashset/linkedhashset.go | 26 +- examples/linkedlistqueue/linkedlistqueue.go | 26 +- examples/linkedliststack/linkedliststack.go | 26 +- examples/priorityqueue/priorityqueue.go | 11 +- examples/redblacktree/redblacktree.go | 5 +- .../redblacktreeextended.go | 35 +-- examples/serialization/serialization.go | 9 +- examples/singlylinkedlist/singlylinkedlist.go | 9 +- examples/treebidimap/treebidimap.go | 5 +- examples/treemap/treemap.go | 26 +- examples/treeset/treeset.go | 26 +- go.mod | 4 +- go.sum | 2 + lists/arraylist/arraylist.go | 68 +++-- lists/arraylist/arraylist_test.go | 203 ++++++------- lists/arraylist/enumerable.go | 23 +- lists/arraylist/iterator.go | 32 +- lists/arraylist/serialization.go | 15 +- lists/doublylinkedlist/doublylinkedlist.go | 84 +++--- .../doublylinkedlist/doublylinkedlist_test.go | 241 +++++++-------- lists/doublylinkedlist/enumerable.go | 23 +- lists/doublylinkedlist/iterator.go | 34 +-- lists/doublylinkedlist/serialization.go | 17 +- lists/lists.go | 20 +- lists/singlylinkedlist/enumerable.go | 22 +- lists/singlylinkedlist/iterator.go | 26 +- lists/singlylinkedlist/serialization.go | 17 +- lists/singlylinkedlist/singlylinkedlist.go | 80 ++--- .../singlylinkedlist/singlylinkedlist_test.go | 187 ++++++------ maps/hashbidimap/hashbidimap.go | 37 +-- maps/hashbidimap/hashbidimap_test.go | 112 +++---- maps/hashbidimap/serialization.go | 32 +- maps/hashmap/hashmap.go | 37 +-- maps/hashmap/hashmap_test.go | 130 +++----- maps/hashmap/serialization.go | 32 +- maps/linkedhashmap/enumerable.go | 22 +- maps/linkedhashmap/iterator.go | 39 +-- maps/linkedhashmap/linkedhashmap.go | 48 +-- maps/linkedhashmap/linkedhashmap_test.go | 269 +++++++---------- maps/linkedhashmap/serialization.go | 38 ++- maps/maps.go | 20 +- maps/treebidimap/enumerable.go | 22 +- maps/treebidimap/iterator.go | 36 +-- maps/treebidimap/serialization.go | 40 ++- maps/treebidimap/treebidimap.go | 95 +++--- maps/treebidimap/treebidimap_test.go | 231 +++++++------- maps/treemap/enumerable.go | 24 +- maps/treemap/iterator.go | 34 +-- maps/treemap/serialization.go | 14 +- maps/treemap/treemap.go | 77 +++-- maps/treemap/treemap_test.go | 283 ++++++++---------- queues/arrayqueue/arrayqueue.go | 32 +- queues/arrayqueue/arrayqueue_test.go | 88 +++--- queues/arrayqueue/iterator.go | 32 +- queues/arrayqueue/serialization.go | 14 +- queues/circularbuffer/circularbuffer.go | 57 ++-- queues/circularbuffer/circularbuffer_test.go | 94 +++--- queues/circularbuffer/iterator.go | 32 +- queues/circularbuffer/serialization.go | 17 +- queues/linkedlistqueue/iterator.go | 24 +- queues/linkedlistqueue/linkedlistqueue.go | 32 +- .../linkedlistqueue/linkedlistqueue_test.go | 68 ++--- queues/linkedlistqueue/serialization.go | 14 +- queues/priorityqueue/iterator.go | 34 +-- queues/priorityqueue/priorityqueue.go | 40 +-- queues/priorityqueue/priorityqueue_test.go | 98 +++--- queues/priorityqueue/serialization.go | 14 +- queues/queues.go | 12 +- sets/hashset/hashset.go | 45 +-- sets/hashset/hashset_test.go | 55 ++-- sets/hashset/serialization.go | 17 +- sets/linkedhashset/enumerable.go | 23 +- sets/linkedhashset/iterator.go | 34 +-- sets/linkedhashset/linkedhashset.go | 53 ++-- sets/linkedhashset/linkedhashset_test.go | 160 +++++----- sets/linkedhashset/serialization.go | 17 +- sets/sets.go | 17 +- sets/treeset/enumerable.go | 25 +- sets/treeset/iterator.go | 36 +-- sets/treeset/serialization.go | 17 +- sets/treeset/treeset.go | 60 ++-- sets/treeset/treeset_test.go | 187 +++++------- stacks/arraystack/arraystack.go | 35 +-- stacks/arraystack/arraystack_test.go | 88 +++--- stacks/arraystack/iterator.go | 32 +- stacks/arraystack/serialization.go | 14 +- stacks/linkedliststack/iterator.go | 24 +- stacks/linkedliststack/linkedliststack.go | 33 +- .../linkedliststack/linkedliststack_test.go | 66 ++-- stacks/linkedliststack/serialization.go | 14 +- stacks/stacks.go | 12 +- testutils/testutils.go | 18 ++ trees/avltree/avltree.go | 161 +++++----- trees/avltree/avltree_test.go | 185 ++++++------ trees/avltree/iterator.go | 40 +-- trees/avltree/serialization.go | 37 +-- trees/binaryheap/binaryheap.go | 59 ++-- trees/binaryheap/binaryheap_test.go | 97 +++--- trees/binaryheap/iterator.go | 32 +- trees/binaryheap/serialization.go | 14 +- trees/btree/btree.go | 191 ++++++------ trees/btree/btree_test.go | 184 ++++++------ trees/btree/iterator.go | 38 +-- trees/btree/serialization.go | 35 ++- trees/redblacktree/iterator.go | 40 +-- trees/redblacktree/redblacktree.go | 137 +++++---- trees/redblacktree/redblacktree_test.go | 159 +++++----- trees/redblacktree/serialization.go | 22 +- trees/trees.go | 6 +- utils/comparator.go | 238 +-------------- utils/comparator_test.go | 279 +---------------- utils/sort.go | 29 -- utils/sort_test.go | 104 ------- 135 files changed, 3249 insertions(+), 4078 deletions(-) delete mode 100644 examples/godsort/godsort.go create mode 100644 go.sum create mode 100644 testutils/testutils.go delete mode 100644 utils/sort.go delete mode 100644 utils/sort_test.go diff --git a/containers/containers.go b/containers/containers.go index a512a3cb..1c016aa6 100644 --- a/containers/containers.go +++ b/containers/containers.go @@ -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 } diff --git a/containers/containers_test.go b/containers/containers_test.go index e92d123d..06763b43 100644 --- a/containers/containers_test.go +++ b/containers/containers_test.go @@ -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 { @@ -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!") } } diff --git a/containers/enumerable.go b/containers/enumerable.go index 70660054..1121388c 100644 --- a/containers/enumerable.go +++ b/containers/enumerable.go @@ -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. @@ -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. @@ -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) } diff --git a/containers/iterator.go b/containers/iterator.go index 73994ec8..68f4b5d5 100644 --- a/containers/iterator.go +++ b/containers/iterator.go @@ -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. @@ -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. @@ -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. @@ -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. @@ -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. @@ -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. @@ -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] } diff --git a/examples/arraylist/arraylist.go b/examples/arraylist/arraylist.go index 4d4fbd90..fb98d64c 100644 --- a/examples/arraylist/arraylist.go +++ b/examples/arraylist/arraylist.go @@ -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 diff --git a/examples/arrayqueue/arrayqqueue.go b/examples/arrayqueue/arrayqqueue.go index 13b88187..bc4c4584 100644 --- a/examples/arrayqueue/arrayqqueue.go +++ b/examples/arrayqueue/arrayqqueue.go @@ -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) diff --git a/examples/arraystack/arraystack.go b/examples/arraystack/arraystack.go index aa06eaf7..1a54f370 100644 --- a/examples/arraystack/arraystack.go +++ b/examples/arraystack/arraystack.go @@ -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 } diff --git a/examples/avltree/avltree.go b/examples/avltree/avltree.go index b6d1aabc..5499ae0d 100644 --- a/examples/avltree/avltree.go +++ b/examples/avltree/avltree.go @@ -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) diff --git a/examples/binaryheap/binaryheap.go b/examples/binaryheap/binaryheap.go index 4bc93813..ad680389 100644 --- a/examples/binaryheap/binaryheap.go +++ b/examples/binaryheap/binaryheap.go @@ -5,32 +5,33 @@ package main import ( - "github.com/emirpasic/gods/trees/binaryheap" - "github.com/emirpasic/gods/utils" + "cmp" + + "github.com/emirpasic/gods/v2/trees/binaryheap" ) // BinaryHeapExample to demonstrate basic usage of BinaryHeap func main() { // Min-heap - heap := binaryheap.NewWithIntComparator() // empty (min-heap) - heap.Push(2) // 2 - heap.Push(3) // 2, 3 - heap.Push(1) // 1, 3, 2 - heap.Values() // 1, 3, 2 - _, _ = heap.Peek() // 1,true - _, _ = heap.Pop() // 1, true - _, _ = heap.Pop() // 2, true - _, _ = heap.Pop() // 3, true - _, _ = heap.Pop() // nil, false (nothing to pop) - heap.Push(1) // 1 - heap.Clear() // empty - heap.Empty() // true - heap.Size() // 0 + heap := binaryheap.New[int]() // empty (min-heap) + heap.Push(2) // 2 + heap.Push(3) // 2, 3 + heap.Push(1) // 1, 3, 2 + heap.Values() // 1, 3, 2 + _, _ = heap.Peek() // 1,true + _, _ = heap.Pop() // 1, true + _, _ = heap.Pop() // 2, true + _, _ = heap.Pop() // 3, true + _, _ = heap.Pop() // nil, false (nothing to pop) + heap.Push(1) // 1 + heap.Clear() // empty + heap.Empty() // true + heap.Size() // 0 // Max-heap - inverseIntComparator := func(a, b interface{}) int { - return -utils.IntComparator(a, b) + inverseIntComparator := func(a, b int) int { + return -cmp.Compare(a, b) } heap = binaryheap.NewWith(inverseIntComparator) // empty (min-heap) heap.Push(2) // 2 diff --git a/examples/btree/btree.go b/examples/btree/btree.go index ea61b03f..fdf87d11 100644 --- a/examples/btree/btree.go +++ b/examples/btree/btree.go @@ -6,12 +6,13 @@ package main import ( "fmt" - "github.com/emirpasic/gods/trees/btree" + + "github.com/emirpasic/gods/v2/trees/btree" ) // BTreeExample to demonstrate basic usage of BTree func main() { - tree := btree.NewWithIntComparator(3) // empty (keys are of type int) + tree := btree.New[int, string](3) // empty (keys are of type int) tree.Put(1, "x") // 1->x tree.Put(2, "b") // 1->x, 2->b (in order) diff --git a/examples/circularbuffer/circularbuffer.go b/examples/circularbuffer/circularbuffer.go index 3bd5f2ae..1d230033 100644 --- a/examples/circularbuffer/circularbuffer.go +++ b/examples/circularbuffer/circularbuffer.go @@ -4,23 +4,23 @@ package main -import cb "github.com/emirpasic/gods/queues/circularbuffer" +import cb "github.com/emirpasic/gods/v2/queues/circularbuffer" // CircularBufferExample to demonstrate basic usage of CircularBuffer func main() { - queue := cb.New(3) // empty (max size is 3) - queue.Enqueue(1) // 1 - queue.Enqueue(2) // 1, 2 - queue.Enqueue(3) // 1, 2, 3 - _ = queue.Values() // 1, 2, 3 - queue.Enqueue(3) // 4, 2, 3 - _, _ = queue.Peek() // 4,true - _, _ = queue.Dequeue() // 4, true - _, _ = queue.Dequeue() // 2, true - _, _ = queue.Dequeue() // 3, true - _, _ = queue.Dequeue() // nil, false (nothing to deque) - queue.Enqueue(1) // 1 - queue.Clear() // empty - queue.Empty() // true - _ = queue.Size() // 0 + queue := cb.New[int](3) // empty (max size is 3) + queue.Enqueue(1) // 1 + queue.Enqueue(2) // 1, 2 + queue.Enqueue(3) // 1, 2, 3 + _ = queue.Values() // 1, 2, 3 + queue.Enqueue(3) // 4, 2, 3 + _, _ = queue.Peek() // 4,true + _, _ = queue.Dequeue() // 4, true + _, _ = queue.Dequeue() // 2, true + _, _ = queue.Dequeue() // 3, true + _, _ = queue.Dequeue() // nil, false (nothing to deque) + queue.Enqueue(1) // 1 + queue.Clear() // empty + queue.Empty() // true + _ = queue.Size() // 0 } diff --git a/examples/customcomparator/customcomparator.go b/examples/customcomparator/customcomparator.go index b61d9698..0a5d9572 100644 --- a/examples/customcomparator/customcomparator.go +++ b/examples/customcomparator/customcomparator.go @@ -6,7 +6,8 @@ package main import ( "fmt" - "github.com/emirpasic/gods/sets/treeset" + + "github.com/emirpasic/gods/v2/sets/treeset" ) // User model (id and name) @@ -16,16 +17,12 @@ type User struct { } // Comparator function (sort by IDs) -func byID(a, b interface{}) int { - - // Type assertion, program will panic if this is not respected - c1 := a.(User) - c2 := b.(User) +func byID(a, b User) int { switch { - case c1.id > c2.id: + case a.id > b.id: return 1 - case c1.id < c2.id: + case a.id < b.id: return -1 default: return 0 diff --git a/examples/doublylinkedlist/doublylinkedlist.go b/examples/doublylinkedlist/doublylinkedlist.go index 99ec995c..53b4a897 100644 --- a/examples/doublylinkedlist/doublylinkedlist.go +++ b/examples/doublylinkedlist/doublylinkedlist.go @@ -5,17 +5,18 @@ package main import ( - dll "github.com/emirpasic/gods/lists/doublylinkedlist" - "github.com/emirpasic/gods/utils" + "cmp" + + dll "github.com/emirpasic/gods/v2/lists/doublylinkedlist" ) // DoublyLinkedListExample to demonstrate basic usage of DoublyLinkedList func main() { - list := dll.New() + list := dll.New[string]() list.Add("a") // ["a"] list.Append("b") // ["a","b"] (same as Add()) list.Prepend("c") // ["c","a","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 diff --git a/examples/enumerablewithindex/enumerablewithindex.go b/examples/enumerablewithindex/enumerablewithindex.go index 95459117..f3dd7419 100644 --- a/examples/enumerablewithindex/enumerablewithindex.go +++ b/examples/enumerablewithindex/enumerablewithindex.go @@ -6,12 +6,13 @@ package main import ( "fmt" - "github.com/emirpasic/gods/sets/treeset" + + "github.com/emirpasic/gods/v2/sets/treeset" ) -func printSet(txt string, set *treeset.Set) { +func printSet(txt string, set *treeset.Set[int]) { fmt.Print(txt, "[ ") - set.Each(func(index int, value interface{}) { + set.Each(func(index int, value int) { fmt.Print(value, " ") }) fmt.Println("]") @@ -19,41 +20,41 @@ func printSet(txt string, set *treeset.Set) { // EnumerableWithIndexExample to demonstrate basic usage of EnumerableWithIndex func main() { - set := treeset.NewWithIntComparator() + set := treeset.New[int]() set.Add(2, 3, 4, 2, 5, 6, 7, 8) printSet("Initial", set) // [ 2 3 4 5 6 7 8 ] - even := set.Select(func(index int, value interface{}) bool { - return value.(int)%2 == 0 + even := set.Select(func(index int, value int) bool { + return value%2 == 0 }) printSet("Even numbers", even) // [ 2 4 6 8 ] - foundIndex, foundValue := set.Find(func(index int, value interface{}) bool { - return value.(int)%2 == 0 && value.(int)%3 == 0 + foundIndex, foundValue := set.Find(func(index int, value int) bool { + return value%2 == 0 && value%3 == 0 }) if foundIndex != -1 { fmt.Println("Number divisible by 2 and 3 found is", foundValue, "at index", foundIndex) // value: 6, index: 4 } - square := set.Map(func(index int, value interface{}) interface{} { - return value.(int) * value.(int) + square := set.Map(func(index int, value int) int { + return value * value }) printSet("Numbers squared", square) // [ 4 9 16 25 36 49 64 ] - bigger := set.Any(func(index int, value interface{}) bool { - return value.(int) > 5 + bigger := set.Any(func(index int, value int) bool { + return value > 5 }) fmt.Println("Set contains a number bigger than 5 is ", bigger) // true - positive := set.All(func(index int, value interface{}) bool { - return value.(int) > 0 + positive := set.All(func(index int, value int) bool { + return value > 0 }) fmt.Println("All numbers are positive is", positive) // true - evenNumbersSquared := set.Select(func(index int, value interface{}) bool { - return value.(int)%2 == 0 - }).Map(func(index int, value interface{}) interface{} { - return value.(int) * value.(int) + evenNumbersSquared := set.Select(func(index int, value int) bool { + return value%2 == 0 + }).Map(func(index int, value int) int { + return value * value }) printSet("Chaining", evenNumbersSquared) // [ 4 16 36 64 ] } diff --git a/examples/enumerablewithkey/enumerablewithkey.go b/examples/enumerablewithkey/enumerablewithkey.go index 7f05040d..0bfa4c08 100644 --- a/examples/enumerablewithkey/enumerablewithkey.go +++ b/examples/enumerablewithkey/enumerablewithkey.go @@ -6,12 +6,13 @@ package main import ( "fmt" - "github.com/emirpasic/gods/maps/treemap" + + "github.com/emirpasic/gods/v2/maps/treemap" ) -func printMap(txt string, m *treemap.Map) { +func printMap(txt string, m *treemap.Map[string, int]) { fmt.Print(txt, " { ") - m.Each(func(key interface{}, value interface{}) { + m.Each(func(key string, value int) { fmt.Print(key, ":", value, " ") }) fmt.Println("}") @@ -19,7 +20,7 @@ func printMap(txt string, m *treemap.Map) { // EunumerableWithKeyExample to demonstrate basic usage of EunumerableWithKey func main() { - m := treemap.NewWithStringComparator() + m := treemap.New[string, int]() m.Put("g", 7) m.Put("f", 6) m.Put("e", 5) @@ -29,37 +30,37 @@ func main() { m.Put("a", 1) printMap("Initial", m) // { a:1 b:2 c:3 d:4 e:5 f:6 g:7 } - even := m.Select(func(key interface{}, value interface{}) bool { - return value.(int)%2 == 0 + even := m.Select(func(key string, value int) bool { + return value%2 == 0 }) printMap("Elements with even values", even) // { b:2 d:4 f:6 } - foundKey, foundValue := m.Find(func(key interface{}, value interface{}) bool { - return value.(int)%2 == 0 && value.(int)%3 == 0 + foundKey, foundValue := m.Find(func(key string, value int) bool { + return value%2 == 0 && value%3 == 0 }) - if foundKey != nil { + if foundKey != "" { fmt.Println("Element with value divisible by 2 and 3 found is", foundValue, "with key", foundKey) // value: 6, index: 4 } - square := m.Map(func(key interface{}, value interface{}) (interface{}, interface{}) { - return key.(string) + key.(string), value.(int) * value.(int) + square := m.Map(func(key string, value int) (string, int) { + return key + key, value * value }) printMap("Elements' values squared and letters duplicated", square) // { aa:1 bb:4 cc:9 dd:16 ee:25 ff:36 gg:49 } - bigger := m.Any(func(key interface{}, value interface{}) bool { - return value.(int) > 5 + bigger := m.Any(func(key string, value int) bool { + return value > 5 }) fmt.Println("Map contains element whose value is bigger than 5 is", bigger) // true - positive := m.All(func(key interface{}, value interface{}) bool { - return value.(int) > 0 + positive := m.All(func(key string, value int) bool { + return value > 0 }) fmt.Println("All map's elements have positive values is", positive) // true - evenNumbersSquared := m.Select(func(key interface{}, value interface{}) bool { - return value.(int)%2 == 0 - }).Map(func(key interface{}, value interface{}) (interface{}, interface{}) { - return key, value.(int) * value.(int) + evenNumbersSquared := m.Select(func(key string, value int) bool { + return value%2 == 0 + }).Map(func(key string, value int) (string, int) { + return key, value * value }) printMap("Chaining", evenNumbersSquared) // { b:4 d:16 f:36 } } diff --git a/examples/godsort/godsort.go b/examples/godsort/godsort.go deleted file mode 100644 index 9f0bd2ac..00000000 --- a/examples/godsort/godsort.go +++ /dev/null @@ -1,17 +0,0 @@ -// 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/utils" - -// SortExample to demonstrate basic usage of basic sort -func main() { - strings := []interface{}{} // [] - strings = append(strings, "d") // ["d"] - strings = append(strings, "a") // ["d","a"] - strings = append(strings, "b") // ["d","a",b" - strings = append(strings, "c") // ["d","a",b","c"] - utils.Sort(strings, utils.StringComparator) // ["a","b","c","d"] -} diff --git a/examples/hashbidimap/hashbidimap.go b/examples/hashbidimap/hashbidimap.go index 26350b8c..cc297668 100644 --- a/examples/hashbidimap/hashbidimap.go +++ b/examples/hashbidimap/hashbidimap.go @@ -4,22 +4,22 @@ package main -import "github.com/emirpasic/gods/maps/hashbidimap" +import "github.com/emirpasic/gods/v2/maps/hashbidimap" // HashBidiMapExample to demonstrate basic usage of HashMap func main() { - m := hashbidimap.New() // empty - m.Put(1, "x") // 1->x - m.Put(3, "b") // 1->x, 3->b (random order) - m.Put(1, "a") // 1->a, 3->b (random order) - m.Put(2, "b") // 1->a, 2->b (random order) - _, _ = m.GetKey("a") // 1, true - _, _ = m.Get(2) // b, true - _, _ = m.Get(3) // nil, false - _ = m.Values() // []interface {}{"a", "b"} (random order) - _ = m.Keys() // []interface {}{1, 2} (random order) - m.Remove(1) // 2->b - m.Clear() // empty - m.Empty() // true - m.Size() // 0 + m := hashbidimap.New[int, string]() // empty + m.Put(1, "x") // 1->x + m.Put(3, "b") // 1->x, 3->b (random order) + m.Put(1, "a") // 1->a, 3->b (random order) + m.Put(2, "b") // 1->a, 2->b (random order) + _, _ = m.GetKey("a") // 1, true + _, _ = m.Get(2) // b, true + _, _ = m.Get(3) // nil, false + _ = m.Values() // []interface {}{"a", "b"} (random order) + _ = m.Keys() // []interface {}{1, 2} (random order) + m.Remove(1) // 2->b + m.Clear() // empty + m.Empty() // true + m.Size() // 0 } diff --git a/examples/hashmap/hashmap.go b/examples/hashmap/hashmap.go index 2fda79e6..4be346d5 100644 --- a/examples/hashmap/hashmap.go +++ b/examples/hashmap/hashmap.go @@ -4,20 +4,20 @@ package main -import "github.com/emirpasic/gods/maps/hashmap" +import "github.com/emirpasic/gods/v2/maps/hashmap" // HashMapExample to demonstrate basic usage of HashMap func main() { - m := hashmap.New() // empty - m.Put(1, "x") // 1->x - m.Put(2, "b") // 2->b, 1->x (random order) - m.Put(1, "a") // 2->b, 1->a (random order) - _, _ = m.Get(2) // b, true - _, _ = m.Get(3) // nil, false - _ = m.Values() // []interface {}{"b", "a"} (random order) - _ = m.Keys() // []interface {}{1, 2} (random order) - m.Remove(1) // 2->b - m.Clear() // empty - m.Empty() // true - m.Size() // 0 + m := hashmap.New[int, string]() // empty + m.Put(1, "x") // 1->x + m.Put(2, "b") // 2->b, 1->x (random order) + m.Put(1, "a") // 2->b, 1->a (random order) + _, _ = m.Get(2) // b, true + _, _ = m.Get(3) // nil, false + _ = m.Values() // []interface {}{"b", "a"} (random order) + _ = m.Keys() // []interface {}{1, 2} (random order) + m.Remove(1) // 2->b + m.Clear() // empty + m.Empty() // true + m.Size() // 0 } diff --git a/examples/hashset/hashset.go b/examples/hashset/hashset.go index 6c366e51..eccff89a 100644 --- a/examples/hashset/hashset.go +++ b/examples/hashset/hashset.go @@ -4,20 +4,20 @@ package main -import "github.com/emirpasic/gods/sets/hashset" +import "github.com/emirpasic/gods/v2/sets/hashset" // HashSetExample to demonstrate basic usage of HashSet func main() { - set := hashset.New() // empty (keys are of type int) - set.Add(1) // 1 - set.Add(2, 2, 3, 4, 5) // 3, 1, 2, 4, 5 (random order, duplicates ignored) - set.Remove(4) // 5, 3, 2, 1 (random order) - set.Remove(2, 3) // 1, 5 (random order) - set.Contains(1) // true - set.Contains(1, 5) // true - set.Contains(1, 6) // false - _ = set.Values() // []int{5,1} (random order) - set.Clear() // empty - set.Empty() // true - set.Size() // 0 + set := hashset.New[int]() // empty (keys are of type int) + set.Add(1) // 1 + set.Add(2, 2, 3, 4, 5) // 3, 1, 2, 4, 5 (random order, duplicates ignored) + set.Remove(4) // 5, 3, 2, 1 (random order) + set.Remove(2, 3) // 1, 5 (random order) + set.Contains(1) // true + set.Contains(1, 5) // true + set.Contains(1, 6) // false + _ = set.Values() // []int{5,1} (random order) + set.Clear() // empty + set.Empty() // true + set.Size() // 0 } diff --git a/examples/iteratorwithindex/iteratorwithindex.go b/examples/iteratorwithindex/iteratorwithindex.go index 4cbc87e0..d68cf283 100644 --- a/examples/iteratorwithindex/iteratorwithindex.go +++ b/examples/iteratorwithindex/iteratorwithindex.go @@ -6,13 +6,14 @@ package main import ( "fmt" - "github.com/emirpasic/gods/sets/treeset" "strings" + + "github.com/emirpasic/gods/v2/sets/treeset" ) // IteratorWithIndexExample to demonstrate basic usage of IteratorWithIndex func main() { - set := treeset.NewWithStringComparator() + set := treeset.New[string]() set.Add("a", "b", "c") it := set.Iterator() @@ -51,8 +52,8 @@ func main() { } // Seek element starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } it.Begin() diff --git a/examples/iteratorwithkey/iteratorwithkey.go b/examples/iteratorwithkey/iteratorwithkey.go index 521e43b2..32396082 100644 --- a/examples/iteratorwithkey/iteratorwithkey.go +++ b/examples/iteratorwithkey/iteratorwithkey.go @@ -6,13 +6,14 @@ package main import ( "fmt" - "github.com/emirpasic/gods/maps/treemap" "strings" + + "github.com/emirpasic/gods/v2/maps/treemap" ) // IteratorWithKeyExample to demonstrate basic usage of IteratorWithKey func main() { - m := treemap.NewWithIntComparator() + m := treemap.New[int, string]() m.Put(0, "a") m.Put(1, "b") m.Put(2, "c") @@ -53,8 +54,8 @@ func main() { } // Seek key-value pair whose value starts with "b" - seek := func(key interface{}, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(key int, value string) bool { + return strings.HasSuffix(value, "b") } it.Begin() diff --git a/examples/linkedhashmap/linkedhashmap.go b/examples/linkedhashmap/linkedhashmap.go index 64434817..fe33f49d 100644 --- a/examples/linkedhashmap/linkedhashmap.go +++ b/examples/linkedhashmap/linkedhashmap.go @@ -4,20 +4,20 @@ package main -import "github.com/emirpasic/gods/maps/linkedhashmap" +import "github.com/emirpasic/gods/v2/maps/linkedhashmap" // LinkedHashMapExample to demonstrate basic usage of LinkedHashMapExample func main() { - m := linkedhashmap.New() // empty (keys are of type int) - m.Put(2, "b") // 2->b - m.Put(1, "x") // 2->b, 1->x (insertion-order) - m.Put(1, "a") // 2->b, 1->a (insertion-order) - _, _ = m.Get(2) // b, true - _, _ = m.Get(3) // nil, false - _ = m.Values() // []interface {}{"b", "a"} (insertion-order) - _ = m.Keys() // []interface {}{2, 1} (insertion-order) - m.Remove(1) // 2->b - m.Clear() // empty - m.Empty() // true - m.Size() // 0 + m := linkedhashmap.New[int, string]() // empty (keys are of type int) + m.Put(2, "b") // 2->b + m.Put(1, "x") // 2->b, 1->x (insertion-order) + m.Put(1, "a") // 2->b, 1->a (insertion-order) + _, _ = m.Get(2) // b, true + _, _ = m.Get(3) // nil, false + _ = m.Values() // []interface {}{"b", "a"} (insertion-order) + _ = m.Keys() // []interface {}{2, 1} (insertion-order) + m.Remove(1) // 2->b + m.Clear() // empty + m.Empty() // true + m.Size() // 0 } diff --git a/examples/linkedhashset/linkedhashset.go b/examples/linkedhashset/linkedhashset.go index 689d212d..e6a5d69c 100644 --- a/examples/linkedhashset/linkedhashset.go +++ b/examples/linkedhashset/linkedhashset.go @@ -4,20 +4,20 @@ package main -import "github.com/emirpasic/gods/sets/linkedhashset" +import "github.com/emirpasic/gods/v2/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 + set := linkedhashset.New[int]() // 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 } diff --git a/examples/linkedlistqueue/linkedlistqueue.go b/examples/linkedlistqueue/linkedlistqueue.go index d6800b5f..2a61d2f5 100644 --- a/examples/linkedlistqueue/linkedlistqueue.go +++ b/examples/linkedlistqueue/linkedlistqueue.go @@ -4,20 +4,20 @@ package main -import llq "github.com/emirpasic/gods/queues/linkedlistqueue" +import llq "github.com/emirpasic/gods/v2/queues/linkedlistqueue" // LinkedListQueueExample to demonstrate basic usage of LinkedListQueue func main() { - queue := llq.New() // empty - queue.Enqueue(1) // 1 - queue.Enqueue(2) // 1, 2 - _ = queue.Values() // 1, 2 (FIFO order) - _, _ = queue.Peek() // 1,true - _, _ = queue.Dequeue() // 1, true - _, _ = queue.Dequeue() // 2, true - _, _ = queue.Dequeue() // nil, false (nothing to deque) - queue.Enqueue(1) // 1 - queue.Clear() // empty - queue.Empty() // true - _ = queue.Size() // 0 + queue := llq.New[int]() // empty + queue.Enqueue(1) // 1 + queue.Enqueue(2) // 1, 2 + _ = queue.Values() // 1, 2 (FIFO order) + _, _ = queue.Peek() // 1,true + _, _ = queue.Dequeue() // 1, true + _, _ = queue.Dequeue() // 2, true + _, _ = queue.Dequeue() // nil, false (nothing to deque) + queue.Enqueue(1) // 1 + queue.Clear() // empty + queue.Empty() // true + _ = queue.Size() // 0 } diff --git a/examples/linkedliststack/linkedliststack.go b/examples/linkedliststack/linkedliststack.go index e9f1a68e..81ace6c6 100644 --- a/examples/linkedliststack/linkedliststack.go +++ b/examples/linkedliststack/linkedliststack.go @@ -4,20 +4,20 @@ package main -import lls "github.com/emirpasic/gods/stacks/linkedliststack" +import lls "github.com/emirpasic/gods/v2/stacks/linkedliststack" // LinkedListStackExample to demonstrate basic usage of LinkedListStack func main() { - stack := lls.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 := lls.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 } diff --git a/examples/priorityqueue/priorityqueue.go b/examples/priorityqueue/priorityqueue.go index 11fd1e57..e77f2210 100644 --- a/examples/priorityqueue/priorityqueue.go +++ b/examples/priorityqueue/priorityqueue.go @@ -5,8 +5,9 @@ package main import ( - pq "github.com/emirpasic/gods/queues/priorityqueue" - "github.com/emirpasic/gods/utils" + "cmp" + + pq "github.com/emirpasic/gods/v2/queues/priorityqueue" ) // Element is an entry in the priority queue @@ -16,10 +17,8 @@ type Element struct { } // Comparator function (sort by element's priority value in descending order) -func byPriority(a, b interface{}) int { - priorityA := a.(Element).priority - priorityB := b.(Element).priority - return -utils.IntComparator(priorityA, priorityB) // "-" descending order +func byPriority(a, b Element) int { + return -cmp.Compare(a.priority, b.priority) // "-" descending order } // PriorityQueueExample to demonstrate basic usage of BinaryHeap diff --git a/examples/redblacktree/redblacktree.go b/examples/redblacktree/redblacktree.go index b7d9803f..6661b166 100644 --- a/examples/redblacktree/redblacktree.go +++ b/examples/redblacktree/redblacktree.go @@ -6,12 +6,13 @@ package main import ( "fmt" - rbt "github.com/emirpasic/gods/trees/redblacktree" + + rbt "github.com/emirpasic/gods/v2/trees/redblacktree" ) // RedBlackTreeExample to demonstrate basic usage of RedBlackTree func main() { - tree := rbt.NewWithIntComparator() // empty(keys are of type int) + tree := rbt.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) diff --git a/examples/redblacktreeextended/redblacktreeextended.go b/examples/redblacktreeextended/redblacktreeextended.go index 6e901299..602dfecc 100644 --- a/examples/redblacktreeextended/redblacktreeextended.go +++ b/examples/redblacktreeextended/redblacktreeextended.go @@ -6,53 +6,54 @@ package redblacktreeextended import ( "fmt" - rbt "github.com/emirpasic/gods/trees/redblacktree" + + rbt "github.com/emirpasic/gods/v2/trees/redblacktree" ) // RedBlackTreeExtended to demonstrate how to extend a RedBlackTree to include new functions -type RedBlackTreeExtended struct { - *rbt.Tree +type RedBlackTreeExtended[K comparable, V any] struct { + *rbt.Tree[K, V] } // GetMin gets the min value and flag if found -func (tree *RedBlackTreeExtended) GetMin() (value interface{}, found bool) { +func (tree *RedBlackTreeExtended[K, V]) GetMin() (value V, found bool) { node, found := tree.getMinFromNode(tree.Root) - if node != nil { + if found { return node.Value, found } - return nil, false + return value, false } // GetMax gets the max value and flag if found -func (tree *RedBlackTreeExtended) GetMax() (value interface{}, found bool) { +func (tree *RedBlackTreeExtended[K, V]) GetMax() (value V, found bool) { node, found := tree.getMaxFromNode(tree.Root) - if node != nil { + if found { return node.Value, found } - return nil, false + return value, false } // RemoveMin removes the min value and flag if found -func (tree *RedBlackTreeExtended) RemoveMin() (value interface{}, deleted bool) { +func (tree *RedBlackTreeExtended[K, V]) RemoveMin() (value V, deleted bool) { node, found := tree.getMinFromNode(tree.Root) if found { tree.Remove(node.Key) return node.Value, found } - return nil, false + return value, false } // RemoveMax removes the max value and flag if found -func (tree *RedBlackTreeExtended) RemoveMax() (value interface{}, deleted bool) { +func (tree *RedBlackTreeExtended[K, V]) RemoveMax() (value V, deleted bool) { node, found := tree.getMaxFromNode(tree.Root) if found { tree.Remove(node.Key) return node.Value, found } - return nil, false + return value, false } -func (tree *RedBlackTreeExtended) getMinFromNode(node *rbt.Node) (foundNode *rbt.Node, found bool) { +func (tree *RedBlackTreeExtended[K, V]) getMinFromNode(node *rbt.Node[K, V]) (foundNode *rbt.Node[K, V], found bool) { if node == nil { return nil, false } @@ -62,7 +63,7 @@ func (tree *RedBlackTreeExtended) getMinFromNode(node *rbt.Node) (foundNode *rbt return tree.getMinFromNode(node.Left) } -func (tree *RedBlackTreeExtended) getMaxFromNode(node *rbt.Node) (foundNode *rbt.Node, found bool) { +func (tree *RedBlackTreeExtended[K, V]) getMaxFromNode(node *rbt.Node[K, V]) (foundNode *rbt.Node[K, V], found bool) { if node == nil { return nil, false } @@ -72,7 +73,7 @@ func (tree *RedBlackTreeExtended) getMaxFromNode(node *rbt.Node) (foundNode *rbt return tree.getMaxFromNode(node.Right) } -func print(tree *RedBlackTreeExtended) { +func print(tree *RedBlackTreeExtended[int, string]) { max, _ := tree.GetMax() min, _ := tree.GetMin() fmt.Printf("Value for max key: %v \n", max) @@ -82,7 +83,7 @@ func print(tree *RedBlackTreeExtended) { // RedBlackTreeExtendedExample main method on how to use the custom red-black tree above func main() { - tree := RedBlackTreeExtended{rbt.NewWithIntComparator()} + tree := RedBlackTreeExtended[int, string]{rbt.New[int, string]()} tree.Put(1, "a") // 1->x (in order) tree.Put(2, "b") // 1->x, 2->b (in order) diff --git a/examples/serialization/serialization.go b/examples/serialization/serialization.go index 2f94c5ed..c03252ce 100644 --- a/examples/serialization/serialization.go +++ b/examples/serialization/serialization.go @@ -2,13 +2,14 @@ package serialization import ( "fmt" - "github.com/emirpasic/gods/lists/arraylist" - "github.com/emirpasic/gods/maps/hashmap" + + "github.com/emirpasic/gods/v2/lists/arraylist" + "github.com/emirpasic/gods/v2/maps/hashmap" ) // ListSerializationExample demonstrates how to serialize and deserialize lists to and from JSON func ListSerializationExample() { - list := arraylist.New() + list := arraylist.New[string]() list.Add("a", "b", "c") // Serialization (marshalling) @@ -29,7 +30,7 @@ func ListSerializationExample() { // MapSerializationExample demonstrates how to serialize and deserialize maps to and from JSON func MapSerializationExample() { - m := hashmap.New() + m := hashmap.New[string, string]() m.Put("a", "1") m.Put("b", "2") m.Put("c", "3") diff --git a/examples/singlylinkedlist/singlylinkedlist.go b/examples/singlylinkedlist/singlylinkedlist.go index 93b4ccaf..3d327848 100644 --- a/examples/singlylinkedlist/singlylinkedlist.go +++ b/examples/singlylinkedlist/singlylinkedlist.go @@ -5,17 +5,18 @@ package main import ( - sll "github.com/emirpasic/gods/lists/singlylinkedlist" - "github.com/emirpasic/gods/utils" + "cmp" + + sll "github.com/emirpasic/gods/v2/lists/singlylinkedlist" ) // SinglyLinkedListExample to demonstrate basic usage of SinglyLinkedList func main() { - list := sll.New() + list := sll.New[string]() list.Add("a") // ["a"] list.Append("b") // ["a","b"] (same as Add()) list.Prepend("c") // ["c","a","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 diff --git a/examples/treebidimap/treebidimap.go b/examples/treebidimap/treebidimap.go index 0c63f122..f378eca2 100644 --- a/examples/treebidimap/treebidimap.go +++ b/examples/treebidimap/treebidimap.go @@ -5,13 +5,12 @@ package main import ( - "github.com/emirpasic/gods/maps/treebidimap" - "github.com/emirpasic/gods/utils" + "github.com/emirpasic/gods/v2/maps/treebidimap" ) // TreeBidiMapExample to demonstrate basic usage of TreeBidiMap func main() { - m := treebidimap.NewWith(utils.IntComparator, utils.StringComparator) + m := treebidimap.New[int, string]() m.Put(1, "x") // 1->x m.Put(3, "b") // 1->x, 3->b (ordered) m.Put(1, "a") // 1->a, 3->b (ordered) diff --git a/examples/treemap/treemap.go b/examples/treemap/treemap.go index 66b62cc4..4a1a21b2 100644 --- a/examples/treemap/treemap.go +++ b/examples/treemap/treemap.go @@ -4,20 +4,20 @@ package main -import "github.com/emirpasic/gods/maps/treemap" +import "github.com/emirpasic/gods/v2/maps/treemap" // TreeMapExample to demonstrate basic usage of TreeMap func main() { - m := treemap.NewWithIntComparator() // empty (keys are of type int) - m.Put(1, "x") // 1->x - m.Put(2, "b") // 1->x, 2->b (in order) - m.Put(1, "a") // 1->a, 2->b (in order) - _, _ = m.Get(2) // b, true - _, _ = m.Get(3) // nil, false - _ = m.Values() // []interface {}{"a", "b"} (in order) - _ = m.Keys() // []interface {}{1, 2} (in order) - m.Remove(1) // 2->b - m.Clear() // empty - m.Empty() // true - m.Size() // 0 + m := treemap.New[int, string]() // empty + m.Put(1, "x") // 1->x + m.Put(2, "b") // 1->x, 2->b (in order) + m.Put(1, "a") // 1->a, 2->b (in order) + _, _ = m.Get(2) // b, true + _, _ = m.Get(3) // nil, false + _ = m.Values() // []interface {}{"a", "b"} (in order) + _ = m.Keys() // []interface {}{1, 2} (in order) + m.Remove(1) // 2->b + m.Clear() // empty + m.Empty() // true + m.Size() // 0 } diff --git a/examples/treeset/treeset.go b/examples/treeset/treeset.go index 15a7f81a..e56b148e 100644 --- a/examples/treeset/treeset.go +++ b/examples/treeset/treeset.go @@ -4,20 +4,20 @@ package main -import "github.com/emirpasic/gods/sets/treeset" +import "github.com/emirpasic/gods/v2/sets/treeset" // TreeSetExample to demonstrate basic usage of TreeSet func main() { - set := treeset.NewWithIntComparator() // empty - set.Add(1) // 1 - set.Add(2, 2, 3, 4, 5) // 1, 2, 3, 4, 5 (in order, duplicates ignored) - set.Remove(4) // 1, 2, 3, 5 (in order) - set.Remove(2, 3) // 1, 5 (in order) - set.Contains(1) // true - set.Contains(1, 5) // true - set.Contains(1, 6) // false - _ = set.Values() // []int{1,5} (in order) - set.Clear() // empty - set.Empty() // true - set.Size() // 0 + set := treeset.New[int]() // empty + set.Add(1) // 1 + set.Add(2, 2, 3, 4, 5) // 1, 2, 3, 4, 5 (in order, duplicates ignored) + set.Remove(4) // 1, 2, 3, 5 (in order) + set.Remove(2, 3) // 1, 5 (in order) + set.Contains(1) // true + set.Contains(1, 5) // true + set.Contains(1, 6) // false + _ = set.Values() // []int{1,5} (in order) + set.Clear() // empty + set.Empty() // true + set.Size() // 0 } diff --git a/go.mod b/go.mod index 5160ad04..4d864ff5 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ -module github.com/emirpasic/gods +module github.com/emirpasic/gods/v2 -go 1.2 +go 1.21 diff --git a/go.sum b/go.sum new file mode 100644 index 00000000..b5ad6665 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index 60ce4583..e67ff292 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -11,18 +11,19 @@ package arraylist import ( "fmt" + "slices" "strings" - "github.com/emirpasic/gods/lists" - "github.com/emirpasic/gods/utils" + "github.com/emirpasic/gods/v2/lists" + "github.com/emirpasic/gods/v2/utils" ) // Assert List implementation -var _ lists.List = (*List)(nil) +var _ lists.List[int] = (*List[int])(nil) // List holds the elements in a slice -type List struct { - elements []interface{} +type List[T comparable] struct { + elements []T size int } @@ -32,8 +33,8 @@ const ( ) // New instantiates a new list and adds the passed values, if any, to the list -func New(values ...interface{}) *List { - list := &List{} +func New[T comparable](values ...T) *List[T] { + list := &List[T]{} if len(values) > 0 { list.Add(values...) } @@ -41,7 +42,7 @@ func New(values ...interface{}) *List { } // Add appends a value at the end of the list -func (list *List) Add(values ...interface{}) { +func (list *List[T]) Add(values ...T) { list.growBy(len(values)) for _, value := range values { list.elements[list.size] = value @@ -51,23 +52,24 @@ func (list *List) Add(values ...interface{}) { // Get returns the element at index. // Second return parameter is true if index is within bounds of the array and array is not empty, otherwise false. -func (list *List) Get(index int) (interface{}, bool) { +func (list *List[T]) Get(index int) (T, bool) { if !list.withinRange(index) { - return nil, false + var t T + return t, false } return list.elements[index], true } // Remove removes the element at the given index from the list. -func (list *List) Remove(index int) { +func (list *List[T]) Remove(index int) { if !list.withinRange(index) { return } - list.elements[index] = nil // cleanup reference + clear(list.elements[index : index+1]) copy(list.elements[index:], list.elements[index+1:list.size]) // shift to the left by one (slow operation, need ways to optimize this) list.size-- @@ -78,7 +80,7 @@ func (list *List) Remove(index int) { // All elements have to be present in the set for the method to return true. // Performance time complexity of n^2. // Returns true if no arguments are passed at all, i.e. set is always super-set of empty set. -func (list *List) Contains(values ...interface{}) bool { +func (list *List[T]) Contains(values ...T) bool { for _, searchValue := range values { found := false @@ -96,14 +98,14 @@ func (list *List) Contains(values ...interface{}) bool { } // Values returns all elements in the list. -func (list *List) Values() []interface{} { - newElements := make([]interface{}, list.size, list.size) +func (list *List[T]) Values() []T { + newElements := make([]T, list.size, list.size) copy(newElements, list.elements[:list.size]) return newElements } -//IndexOf returns index of provided element -func (list *List) IndexOf(value interface{}) int { +// IndexOf returns index of provided element +func (list *List[T]) IndexOf(value T) int { if list.size == 0 { return -1 } @@ -116,31 +118,31 @@ func (list *List) IndexOf(value interface{}) int { } // Empty returns true if list does not contain any elements. -func (list *List) Empty() bool { +func (list *List[T]) Empty() bool { return list.size == 0 } // Size returns number of elements within the list. -func (list *List) Size() int { +func (list *List[T]) Size() int { return list.size } // Clear removes all elements from the list. -func (list *List) Clear() { +func (list *List[T]) Clear() { list.size = 0 - list.elements = []interface{}{} + list.elements = []T{} } // Sort sorts values (in-place) using. -func (list *List) Sort(comparator utils.Comparator) { +func (list *List[T]) Sort(comparator utils.Comparator[T]) { if len(list.elements) < 2 { return } - utils.Sort(list.elements[:list.size], comparator) + slices.SortFunc(list.elements[:list.size], comparator) } // Swap swaps the two values at the specified positions. -func (list *List) Swap(i, j int) { +func (list *List[T]) Swap(i, j int) { if list.withinRange(i) && list.withinRange(j) { list.elements[i], list.elements[j] = list.elements[j], list.elements[i] } @@ -149,7 +151,7 @@ func (list *List) Swap(i, j int) { // Insert inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right. // Does not do anything if position is negative or bigger than list's size // Note: position equal to list's size is valid, i.e. append. -func (list *List) Insert(index int, values ...interface{}) { +func (list *List[T]) Insert(index int, values ...T) { if !list.withinRange(index) { // Append @@ -169,7 +171,7 @@ func (list *List) Insert(index int, values ...interface{}) { // Set the value at specified index // Does not do anything if position is negative or bigger than list's size // Note: position equal to list's size is valid, i.e. append. -func (list *List) Set(index int, value interface{}) { +func (list *List[T]) Set(index int, value T) { if !list.withinRange(index) { // Append @@ -183,9 +185,9 @@ func (list *List) Set(index int, value interface{}) { } // String returns a string representation of container -func (list *List) String() string { +func (list *List[T]) String() string { str := "ArrayList\n" - values := []string{} + values := make([]string, 0, list.size) for _, value := range list.elements[:list.size] { values = append(values, fmt.Sprintf("%v", value)) } @@ -194,18 +196,18 @@ func (list *List) String() string { } // Check that the index is within bounds of the list -func (list *List) withinRange(index int) bool { +func (list *List[T]) withinRange(index int) bool { return index >= 0 && index < list.size } -func (list *List) resize(cap int) { - newElements := make([]interface{}, cap, cap) +func (list *List[T]) resize(cap int) { + newElements := make([]T, cap, cap) copy(newElements, list.elements) list.elements = newElements } // Expand the array if necessary, i.e. capacity will be reached if we add n elements -func (list *List) growBy(n int) { +func (list *List[T]) growBy(n int) { // When capacity is reached, grow by a factor of growthFactor and add number of elements currentCapacity := cap(list.elements) if list.size+n >= currentCapacity { @@ -215,7 +217,7 @@ func (list *List) growBy(n int) { } // Shrink the array if necessary, i.e. when size is shrinkFactor percent of current capacity -func (list *List) shrink() { +func (list *List[T]) shrink() { if shrinkFactor == 0.0 { return } diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 3b7c8d77..614b436d 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -5,21 +5,21 @@ package arraylist import ( + "cmp" "encoding/json" - "fmt" - "github.com/emirpasic/gods/utils" + "slices" "strings" "testing" ) func TestListNew(t *testing.T) { - list1 := New() + list1 := New[int]() if actualValue := list1.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - list2 := New(1, "b") + list2 := New[int](1, 2) if actualValue := list2.Size(); actualValue != 2 { t.Errorf("Got %v expected %v", actualValue, 2) @@ -29,17 +29,17 @@ func TestListNew(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, 1) } - if actualValue, ok := list2.Get(1); actualValue != "b" || !ok { - t.Errorf("Got %v expected %v", actualValue, "b") + if actualValue, ok := list2.Get(1); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) } - if actualValue, ok := list2.Get(2); actualValue != nil || ok { - t.Errorf("Got %v expected %v", actualValue, nil) + if actualValue, ok := list2.Get(2); actualValue != 0 || ok { + t.Errorf("Got %v expected %v", actualValue, 0) } } func TestListAdd(t *testing.T) { - list := New() + list := New[string]() list.Add("a") list.Add("b", "c") if actualValue := list.Empty(); actualValue != false { @@ -54,7 +54,7 @@ func TestListAdd(t *testing.T) { } func TestListIndexOf(t *testing.T) { - list := New() + list := New[string]() expectedIndex := -1 if index := list.IndexOf("a"); index != expectedIndex { @@ -81,12 +81,12 @@ func TestListIndexOf(t *testing.T) { } func TestListRemove(t *testing.T) { - list := New() + list := New[string]() list.Add("a") list.Add("b", "c") list.Remove(2) - if actualValue, ok := list.Get(2); actualValue != nil || ok { - t.Errorf("Got %v expected %v", actualValue, nil) + if actualValue, ok := list.Get(2); actualValue != "" || ok { + t.Errorf("Got %v expected %v", actualValue, "") } list.Remove(1) list.Remove(0) @@ -100,7 +100,7 @@ func TestListRemove(t *testing.T) { } func TestListGet(t *testing.T) { - list := New() + list := New[string]() list.Add("a") list.Add("b", "c") if actualValue, ok := list.Get(0); actualValue != "a" || !ok { @@ -112,8 +112,8 @@ func TestListGet(t *testing.T) { if actualValue, ok := list.Get(2); actualValue != "c" || !ok { t.Errorf("Got %v expected %v", actualValue, "c") } - if actualValue, ok := list.Get(3); actualValue != nil || ok { - t.Errorf("Got %v expected %v", actualValue, nil) + if actualValue, ok := list.Get(3); actualValue != "" || ok { + t.Errorf("Got %v expected %v", actualValue, "") } list.Remove(0) if actualValue, ok := list.Get(0); actualValue != "b" || !ok { @@ -122,7 +122,7 @@ func TestListGet(t *testing.T) { } func TestListSwap(t *testing.T) { - list := New() + list := New[string]() list.Add("a") list.Add("b", "c") list.Swap(0, 1) @@ -132,21 +132,21 @@ func TestListSwap(t *testing.T) { } func TestListSort(t *testing.T) { - list := New() - list.Sort(utils.StringComparator) + list := New[string]() + list.Sort(cmp.Compare[string]) list.Add("e", "f", "g", "a", "b", "c", "d") - list.Sort(utils.StringComparator) + list.Sort(cmp.Compare[string]) for i := 1; i < list.Size(); i++ { a, _ := list.Get(i - 1) b, _ := list.Get(i) - if a.(string) > b.(string) { + if a > b { t.Errorf("Not sorted! %s > %s", a, b) } } } func TestListClear(t *testing.T) { - list := New() + list := New[string]() list.Add("e", "f", "g", "a", "b", "c", "d") list.Clear() if actualValue := list.Empty(); actualValue != true { @@ -158,13 +158,13 @@ func TestListClear(t *testing.T) { } func TestListContains(t *testing.T) { - list := New() + list := New[string]() list.Add("a") list.Add("b", "c") if actualValue := list.Contains("a"); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - if actualValue := list.Contains(nil); actualValue != false { + if actualValue := list.Contains(""); actualValue != false { t.Errorf("Got %v expected %v", actualValue, false) } if actualValue := list.Contains("a", "b", "c"); actualValue != true { @@ -183,16 +183,16 @@ func TestListContains(t *testing.T) { } func TestListValues(t *testing.T) { - list := New() + list := New[string]() list.Add("a") list.Add("b", "c") - if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abc"; actualValue != expectedValue { + if actualValue, expectedValue := list.Values(), []string{"a", "b", "c"}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } func TestListInsert(t *testing.T) { - list := New() + list := New[string]() list.Insert(0, "b", "c") list.Insert(0, "a") list.Insert(10, "x") // ignore @@ -203,13 +203,13 @@ func TestListInsert(t *testing.T) { if actualValue := list.Size(); actualValue != 4 { t.Errorf("Got %v expected %v", actualValue, 4) } - if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", list.Values()...), "abcd"; actualValue != expectedValue { + if actualValue, expectedValue := strings.Join(list.Values(), ""), "abcd"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } func TestListSet(t *testing.T) { - list := New() + list := New[string]() list.Set(0, "a") list.Set(1, "b") if actualValue := list.Size(); actualValue != 2 { @@ -224,15 +224,15 @@ func TestListSet(t *testing.T) { if actualValue := list.Size(); actualValue != 3 { t.Errorf("Got %v expected %v", actualValue, 3) } - if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abbc"; actualValue != expectedValue { + if actualValue, expectedValue := list.Values(), []string{"a", "bb", "c"}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } func TestListEach(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - list.Each(func(index int, value interface{}) { + list.Each(func(index int, value string) { switch index { case 0: if actualValue, expectedValue := value, "a"; actualValue != expectedValue { @@ -253,10 +253,10 @@ func TestListEach(t *testing.T) { } func TestListMap(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - mappedList := list.Map(func(index int, value interface{}) interface{} { - return "mapped: " + value.(string) + mappedList := list.Map(func(index int, value string) string { + return "mapped: " + value }) if actualValue, _ := mappedList.Get(0); actualValue != "mapped: a" { t.Errorf("Got %v expected %v", actualValue, "mapped: a") @@ -273,10 +273,10 @@ func TestListMap(t *testing.T) { } func TestListSelect(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - selectedList := list.Select(func(index int, value interface{}) bool { - return value.(string) >= "a" && value.(string) <= "b" + selectedList := list.Select(func(index int, value string) bool { + return value >= "a" && value <= "b" }) if actualValue, _ := selectedList.Get(0); actualValue != "a" { t.Errorf("Got %v expected %v", actualValue, "value: a") @@ -290,60 +290,60 @@ func TestListSelect(t *testing.T) { } func TestListAny(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - any := list.Any(func(index int, value interface{}) bool { - return value.(string) == "c" + any := list.Any(func(index int, value string) bool { + return value == "c" }) if any != true { t.Errorf("Got %v expected %v", any, true) } - any = list.Any(func(index int, value interface{}) bool { - return value.(string) == "x" + any = list.Any(func(index int, value string) bool { + return value == "x" }) if any != false { t.Errorf("Got %v expected %v", any, false) } } func TestListAll(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - all := list.All(func(index int, value interface{}) bool { - return value.(string) >= "a" && value.(string) <= "c" + all := list.All(func(index int, value string) bool { + return value >= "a" && value <= "c" }) if all != true { t.Errorf("Got %v expected %v", all, true) } - all = list.All(func(index int, value interface{}) bool { - return value.(string) >= "a" && value.(string) <= "b" + all = list.All(func(index int, value string) bool { + return value >= "a" && value <= "b" }) if all != false { t.Errorf("Got %v expected %v", all, false) } } func TestListFind(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - foundIndex, foundValue := list.Find(func(index int, value interface{}) bool { - return value.(string) == "c" + foundIndex, foundValue := list.Find(func(index int, value string) bool { + return value == "c" }) if foundValue != "c" || foundIndex != 2 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, "c", 2) } - foundIndex, foundValue = list.Find(func(index int, value interface{}) bool { - return value.(string) == "x" + foundIndex, foundValue = list.Find(func(index int, value string) bool { + return value == "x" }) - if foundValue != nil || foundIndex != -1 { + if foundValue != "" || foundIndex != -1 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil) } } func TestListChaining(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - chainedList := list.Select(func(index int, value interface{}) bool { - return value.(string) > "a" - }).Map(func(index int, value interface{}) interface{} { - return value.(string) + value.(string) + chainedList := list.Select(func(index int, value string) bool { + return value > "a" + }).Map(func(index int, value string) string { + return value + value }) if chainedList.Size() != 2 { t.Errorf("Got %v expected %v", chainedList.Size(), 2) @@ -357,7 +357,7 @@ func TestListChaining(t *testing.T) { } func TestListIteratorNextOnEmpty(t *testing.T) { - list := New() + list := New[string]() it := list.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty list") @@ -365,7 +365,7 @@ func TestListIteratorNextOnEmpty(t *testing.T) { } func TestListIteratorNext(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") it := list.Iterator() count := 0 @@ -396,7 +396,7 @@ func TestListIteratorNext(t *testing.T) { } func TestListIteratorPrevOnEmpty(t *testing.T) { - list := New() + list := New[string]() it := list.Iterator() for it.Prev() { t.Errorf("Shouldn't iterate on empty list") @@ -404,7 +404,7 @@ func TestListIteratorPrevOnEmpty(t *testing.T) { } func TestListIteratorPrev(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") it := list.Iterator() for it.Next() { @@ -437,7 +437,7 @@ func TestListIteratorPrev(t *testing.T) { } func TestListIteratorBegin(t *testing.T) { - list := New() + list := New[string]() it := list.Iterator() it.Begin() list.Add("a", "b", "c") @@ -451,7 +451,7 @@ func TestListIteratorBegin(t *testing.T) { } func TestListIteratorEnd(t *testing.T) { - list := New() + list := New[string]() it := list.Iterator() if index := it.Index(); index != -1 { @@ -476,7 +476,7 @@ func TestListIteratorEnd(t *testing.T) { } func TestListIteratorFirst(t *testing.T) { - list := New() + list := New[string]() it := list.Iterator() if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -491,7 +491,7 @@ func TestListIteratorFirst(t *testing.T) { } func TestListIteratorLast(t *testing.T) { - list := New() + list := New[string]() it := list.Iterator() if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -507,13 +507,13 @@ func TestListIteratorLast(t *testing.T) { func TestListIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // NextTo (empty) { - list := New() + list := New[string]() it := list.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") @@ -522,7 +522,7 @@ func TestListIteratorNextTo(t *testing.T) { // NextTo (not found) { - list := New() + list := New[string]() list.Add("xx", "yy") it := list.Iterator() for it.NextTo(seek) { @@ -532,20 +532,20 @@ func TestListIteratorNextTo(t *testing.T) { // NextTo (found) { - list := New() + list := New[string]() list.Add("aa", "bb", "cc") it := list.Iterator() it.Begin() if !it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Next() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + if index, value := it.Index(), it.Value(); index != 2 || value != "cc" { t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") } if it.Next() { @@ -556,13 +556,13 @@ func TestListIteratorNextTo(t *testing.T) { func TestListIteratorPrevTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // PrevTo (empty) { - list := New() + list := New[string]() it := list.Iterator() it.End() for it.PrevTo(seek) { @@ -572,7 +572,7 @@ func TestListIteratorPrevTo(t *testing.T) { // PrevTo (not found) { - list := New() + list := New[string]() list.Add("xx", "yy") it := list.Iterator() it.End() @@ -583,20 +583,20 @@ func TestListIteratorPrevTo(t *testing.T) { // PrevTo (found) { - list := New() + list := New[string]() list.Add("aa", "bb", "cc") it := list.Iterator() it.End() if !it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty list") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Prev() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "aa" { + if index, value := it.Index(), it.Value(); index != 0 || value != "aa" { t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") } if it.Prev() { @@ -606,12 +606,12 @@ func TestListIteratorPrevTo(t *testing.T) { } func TestListSerialization(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") var err error assert := func() { - if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abc"; actualValue != expectedValue { + if actualValue, expectedValue := list.Values(), []string{"a", "b", "c"}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } if actualValue, expectedValue := list.Size(), 3; actualValue != expectedValue { @@ -630,26 +630,27 @@ func TestListSerialization(t *testing.T) { err = list.FromJSON(bytes) assert() - bytes, err = json.Marshal([]interface{}{"a", "b", "c", list}) + bytes, err = json.Marshal([]any{"a", "b", "c", list}) if err != nil { t.Errorf("Got error %v", err) } - err = json.Unmarshal([]byte(`[1,2,3]`), &list) + err = json.Unmarshal([]byte(`["a","b","c"]`), &list) if err != nil { t.Errorf("Got error %v", err) } + assert() } func TestListString(t *testing.T) { - c := New() + c := New[int]() c.Add(1) if !strings.HasPrefix(c.String(), "ArrayList") { t.Errorf("String should start with container name") } } -func benchmarkGet(b *testing.B, list *List, size int) { +func benchmarkGet(b *testing.B, list *List[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { list.Get(n) @@ -657,7 +658,7 @@ func benchmarkGet(b *testing.B, list *List, size int) { } } -func benchmarkAdd(b *testing.B, list *List, size int) { +func benchmarkAdd(b *testing.B, list *List[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { list.Add(n) @@ -665,7 +666,7 @@ func benchmarkAdd(b *testing.B, list *List, size int) { } } -func benchmarkRemove(b *testing.B, list *List, size int) { +func benchmarkRemove(b *testing.B, list *List[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { list.Remove(n) @@ -676,7 +677,7 @@ func benchmarkRemove(b *testing.B, list *List, size int) { func BenchmarkArrayListGet100(b *testing.B) { b.StopTimer() size := 100 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -687,7 +688,7 @@ func BenchmarkArrayListGet100(b *testing.B) { func BenchmarkArrayListGet1000(b *testing.B) { b.StopTimer() size := 1000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -698,7 +699,7 @@ func BenchmarkArrayListGet1000(b *testing.B) { func BenchmarkArrayListGet10000(b *testing.B) { b.StopTimer() size := 10000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -709,7 +710,7 @@ func BenchmarkArrayListGet10000(b *testing.B) { func BenchmarkArrayListGet100000(b *testing.B) { b.StopTimer() size := 100000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -720,7 +721,7 @@ func BenchmarkArrayListGet100000(b *testing.B) { func BenchmarkArrayListAdd100(b *testing.B) { b.StopTimer() size := 100 - list := New() + list := New[int]() b.StartTimer() benchmarkAdd(b, list, size) } @@ -728,7 +729,7 @@ func BenchmarkArrayListAdd100(b *testing.B) { func BenchmarkArrayListAdd1000(b *testing.B) { b.StopTimer() size := 1000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -739,7 +740,7 @@ func BenchmarkArrayListAdd1000(b *testing.B) { func BenchmarkArrayListAdd10000(b *testing.B) { b.StopTimer() size := 10000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -750,7 +751,7 @@ func BenchmarkArrayListAdd10000(b *testing.B) { func BenchmarkArrayListAdd100000(b *testing.B) { b.StopTimer() size := 100000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -761,7 +762,7 @@ func BenchmarkArrayListAdd100000(b *testing.B) { func BenchmarkArrayListRemove100(b *testing.B) { b.StopTimer() size := 100 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -772,7 +773,7 @@ func BenchmarkArrayListRemove100(b *testing.B) { func BenchmarkArrayListRemove1000(b *testing.B) { b.StopTimer() size := 1000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -783,7 +784,7 @@ func BenchmarkArrayListRemove1000(b *testing.B) { func BenchmarkArrayListRemove10000(b *testing.B) { b.StopTimer() size := 10000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -794,7 +795,7 @@ func BenchmarkArrayListRemove10000(b *testing.B) { func BenchmarkArrayListRemove100000(b *testing.B) { b.StopTimer() size := 100000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } diff --git a/lists/arraylist/enumerable.go b/lists/arraylist/enumerable.go index 8bd60b0a..94589d72 100644 --- a/lists/arraylist/enumerable.go +++ b/lists/arraylist/enumerable.go @@ -4,13 +4,13 @@ package arraylist -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Assert Enumerable implementation -var _ containers.EnumerableWithIndex = (*List)(nil) +var _ containers.EnumerableWithIndex[int] = (*List[int])(nil) // Each calls the given function once for each element, passing that element's index and value. -func (list *List) Each(f func(index int, value interface{})) { +func (list *List[T]) Each(f func(index int, value T)) { iterator := list.Iterator() for iterator.Next() { f(iterator.Index(), iterator.Value()) @@ -19,8 +19,8 @@ func (list *List) Each(f func(index int, value interface{})) { // Map invokes the given function once for each element and returns a // container containing the values returned by the given function. -func (list *List) Map(f func(index int, value interface{}) interface{}) *List { - newList := &List{} +func (list *List[T]) Map(f func(index int, value T) T) *List[T] { + newList := &List[T]{} iterator := list.Iterator() for iterator.Next() { newList.Add(f(iterator.Index(), iterator.Value())) @@ -29,8 +29,8 @@ func (list *List) Map(f func(index int, value interface{}) interface{}) *List { } // Select returns a new container containing all elements for which the given function returns a true value. -func (list *List) Select(f func(index int, value interface{}) bool) *List { - newList := &List{} +func (list *List[T]) Select(f func(index int, value T) bool) *List[T] { + newList := &List[T]{} iterator := list.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { @@ -42,7 +42,7 @@ func (list *List) Select(f func(index int, value interface{}) bool) *List { // Any passes each element of the collection to the given function and // returns true if the function ever returns true for any element. -func (list *List) Any(f func(index int, value interface{}) bool) bool { +func (list *List[T]) Any(f func(index int, value T) bool) bool { iterator := list.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { @@ -54,7 +54,7 @@ func (list *List) Any(f func(index int, value interface{}) bool) bool { // All passes each element of the collection to the given function and // returns true if the function returns true for all elements. -func (list *List) All(f func(index int, value interface{}) bool) bool { +func (list *List[T]) All(f func(index int, value T) bool) bool { iterator := list.Iterator() for iterator.Next() { if !f(iterator.Index(), iterator.Value()) { @@ -67,12 +67,13 @@ func (list *List) All(f func(index int, value interface{}) 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. -func (list *List) Find(f func(index int, value interface{}) bool) (int, interface{}) { +func (list *List[T]) Find(f func(index int, value T) bool) (int, T) { iterator := list.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { return iterator.Index(), iterator.Value() } } - return -1, nil + var t T + return -1, t } diff --git a/lists/arraylist/iterator.go b/lists/arraylist/iterator.go index f9efe20c..5a6705ce 100644 --- a/lists/arraylist/iterator.go +++ b/lists/arraylist/iterator.go @@ -4,27 +4,27 @@ package arraylist -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Assert Iterator implementation -var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) +var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator holding the iterator's state -type Iterator struct { - list *List +type Iterator[T comparable] struct { + list *List[T] index int } // Iterator returns a stateful iterator whose values can be fetched by an index. -func (list *List) Iterator() Iterator { - return Iterator{list: list, index: -1} +func (list *List[T]) Iterator() *Iterator[T] { + return &Iterator[T]{list: list, index: -1} } // 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 { +func (iterator *Iterator[T]) Next() bool { if iterator.index < iterator.list.size { iterator.index++ } @@ -34,7 +34,7 @@ func (iterator *Iterator) Next() bool { // 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 { +func (iterator *Iterator[T]) Prev() bool { if iterator.index >= 0 { iterator.index-- } @@ -43,32 +43,32 @@ func (iterator *Iterator) Prev() bool { // Value returns the current element's value. // Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { +func (iterator *Iterator[T]) Value() T { return iterator.list.elements[iterator.index] } // Index returns the current element's index. // Does not modify the state of the iterator. -func (iterator *Iterator) Index() int { +func (iterator *Iterator[T]) Index() int { return 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() { +func (iterator *Iterator[T]) Begin() { iterator.index = -1 } // 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() { +func (iterator *Iterator[T]) End() { iterator.index = iterator.list.size } // 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 { +func (iterator *Iterator[T]) First() bool { iterator.Begin() return iterator.Next() } @@ -76,7 +76,7 @@ func (iterator *Iterator) First() bool { // 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 { +func (iterator *Iterator[T]) Last() bool { iterator.End() return iterator.Prev() } @@ -85,7 +85,7 @@ func (iterator *Iterator) Last() bool { // 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. -func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) NextTo(f func(index int, value T) bool) bool { for iterator.Next() { index, value := iterator.Index(), iterator.Value() if f(index, value) { @@ -99,7 +99,7 @@ func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool // 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. -func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) PrevTo(f func(index int, value T) bool) bool { for iterator.Prev() { index, value := iterator.Index(), iterator.Value() if f(index, value) { diff --git a/lists/arraylist/serialization.go b/lists/arraylist/serialization.go index 5e86fe96..a3aec534 100644 --- a/lists/arraylist/serialization.go +++ b/lists/arraylist/serialization.go @@ -6,20 +6,21 @@ package arraylist import ( "encoding/json" - "github.com/emirpasic/gods/containers" + + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*List)(nil) -var _ containers.JSONDeserializer = (*List)(nil) +var _ containers.JSONSerializer = (*List[int])(nil) +var _ containers.JSONDeserializer = (*List[int])(nil) // ToJSON outputs the JSON representation of list's elements. -func (list *List) ToJSON() ([]byte, error) { +func (list *List[T]) ToJSON() ([]byte, error) { return json.Marshal(list.elements[:list.size]) } // FromJSON populates list's elements from the input JSON representation. -func (list *List) FromJSON(data []byte) error { +func (list *List[T]) FromJSON(data []byte) error { err := json.Unmarshal(data, &list.elements) if err == nil { list.size = len(list.elements) @@ -28,11 +29,11 @@ func (list *List) FromJSON(data []byte) error { } // UnmarshalJSON @implements json.Unmarshaler -func (list *List) UnmarshalJSON(bytes []byte) error { +func (list *List[T]) UnmarshalJSON(bytes []byte) error { return list.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (list *List) MarshalJSON() ([]byte, error) { +func (list *List[T]) MarshalJSON() ([]byte, error) { return list.ToJSON() } diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index d0e2b3a6..6a34e9de 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -11,31 +11,32 @@ package doublylinkedlist import ( "fmt" + "slices" "strings" - "github.com/emirpasic/gods/lists" - "github.com/emirpasic/gods/utils" + "github.com/emirpasic/gods/v2/lists" + "github.com/emirpasic/gods/v2/utils" ) // Assert List implementation -var _ lists.List = (*List)(nil) +var _ lists.List[any] = (*List[any])(nil) // List holds the elements, where each element points to the next and previous element -type List struct { - first *element - last *element +type List[T comparable] struct { + first *element[T] + last *element[T] size int } -type element struct { - value interface{} - prev *element - next *element +type element[T comparable] struct { + value T + prev *element[T] + next *element[T] } // New instantiates a new list and adds the passed values, if any, to the list -func New(values ...interface{}) *List { - list := &List{} +func New[T comparable](values ...T) *List[T] { + list := &List[T]{} if len(values) > 0 { list.Add(values...) } @@ -43,9 +44,9 @@ func New(values ...interface{}) *List { } // Add appends a value (one or more) at the end of the list (same as Append()) -func (list *List) Add(values ...interface{}) { +func (list *List[T]) Add(values ...T) { for _, value := range values { - newElement := &element{value: value, prev: list.last} + newElement := &element[T]{value: value, prev: list.last} if list.size == 0 { list.first = newElement list.last = newElement @@ -58,15 +59,15 @@ func (list *List) Add(values ...interface{}) { } // Append appends a value (one or more) at the end of the list (same as Add()) -func (list *List) Append(values ...interface{}) { +func (list *List[T]) Append(values ...T) { list.Add(values...) } // Prepend prepends a values (or more) -func (list *List) Prepend(values ...interface{}) { +func (list *List[T]) Prepend(values ...T) { // in reverse to keep passed order i.e. ["c","d"] -> Prepend(["a","b"]) -> ["a","b","c",d"] for v := len(values) - 1; v >= 0; v-- { - newElement := &element{value: values[v], next: list.first} + newElement := &element[T]{value: values[v], next: list.first} if list.size == 0 { list.first = newElement list.last = newElement @@ -80,10 +81,11 @@ func (list *List) Prepend(values ...interface{}) { // Get returns the element at index. // Second return parameter is true if index is within bounds of the array and array is not empty, otherwise false. -func (list *List) Get(index int) (interface{}, bool) { +func (list *List[T]) Get(index int) (T, bool) { if !list.withinRange(index) { - return nil, false + var t T + return t, false } // determine traveral direction, last to first or first to last @@ -100,7 +102,7 @@ func (list *List) Get(index int) (interface{}, bool) { } // Remove removes the element at the given index from the list. -func (list *List) Remove(index int) { +func (list *List[T]) Remove(index int) { if !list.withinRange(index) { return @@ -111,7 +113,7 @@ func (list *List) Remove(index int) { return } - var element *element + var element *element[T] // determine traversal direction, last to first or first to last if list.size-index < index { element = list.last @@ -145,7 +147,7 @@ func (list *List) Remove(index int) { // All values have to be present in the set for the method to return true. // Performance time complexity of n^2. // Returns true if no arguments are passed at all, i.e. set is always super-set of empty set. -func (list *List) Contains(values ...interface{}) bool { +func (list *List[T]) Contains(values ...T) bool { if len(values) == 0 { return true @@ -169,8 +171,8 @@ func (list *List) Contains(values ...interface{}) bool { } // Values returns all elements in the list. -func (list *List) Values() []interface{} { - values := make([]interface{}, list.size, list.size) +func (list *List[T]) Values() []T { + values := make([]T, list.size, list.size) for e, element := 0, list.first; element != nil; e, element = e+1, element.next { values[e] = element.value } @@ -178,7 +180,7 @@ func (list *List) Values() []interface{} { } // IndexOf returns index of provided element -func (list *List) IndexOf(value interface{}) int { +func (list *List[T]) IndexOf(value T) int { if list.size == 0 { return -1 } @@ -191,31 +193,31 @@ func (list *List) IndexOf(value interface{}) int { } // Empty returns true if list does not contain any elements. -func (list *List) Empty() bool { +func (list *List[T]) Empty() bool { return list.size == 0 } // Size returns number of elements within the list. -func (list *List) Size() int { +func (list *List[T]) Size() int { return list.size } // Clear removes all elements from the list. -func (list *List) Clear() { +func (list *List[T]) Clear() { list.size = 0 list.first = nil list.last = nil } // Sort sorts values (in-place) using. -func (list *List) Sort(comparator utils.Comparator) { +func (list *List[T]) Sort(comparator utils.Comparator[T]) { if list.size < 2 { return } values := list.Values() - utils.Sort(values, comparator) + slices.SortFunc(values, comparator) list.Clear() @@ -224,9 +226,9 @@ func (list *List) Sort(comparator utils.Comparator) { } // Swap swaps values of two elements at the given indices. -func (list *List) Swap(i, j int) { +func (list *List[T]) Swap(i, j int) { if list.withinRange(i) && list.withinRange(j) && i != j { - var element1, element2 *element + var element1, element2 *element[T] for e, currentElement := 0, list.first; element1 == nil || element2 == nil; e, currentElement = e+1, currentElement.next { switch e { case i: @@ -242,7 +244,7 @@ func (list *List) Swap(i, j int) { // Insert inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right. // Does not do anything if position is negative or bigger than list's size // Note: position equal to list's size is valid, i.e. append. -func (list *List) Insert(index int, values ...interface{}) { +func (list *List[T]) Insert(index int, values ...T) { if !list.withinRange(index) { // Append @@ -252,8 +254,8 @@ func (list *List) Insert(index int, values ...interface{}) { return } - var beforeElement *element - var foundElement *element + var beforeElement *element[T] + var foundElement *element[T] // determine traversal direction, last to first or first to last if list.size-index < index { foundElement = list.last @@ -271,7 +273,7 @@ func (list *List) Insert(index int, values ...interface{}) { if foundElement == list.first { oldNextElement := list.first for i, value := range values { - newElement := &element{value: value} + newElement := &element[T]{value: value} if i == 0 { list.first = newElement } else { @@ -285,7 +287,7 @@ func (list *List) Insert(index int, values ...interface{}) { } else { oldNextElement := beforeElement.next for _, value := range values { - newElement := &element{value: value} + newElement := &element[T]{value: value} newElement.prev = beforeElement beforeElement.next = newElement beforeElement = newElement @@ -300,7 +302,7 @@ func (list *List) Insert(index int, values ...interface{}) { // Set value at specified index position // Does not do anything if position is negative or bigger than list's size // Note: position equal to list's size is valid, i.e. append. -func (list *List) Set(index int, value interface{}) { +func (list *List[T]) Set(index int, value T) { if !list.withinRange(index) { // Append @@ -310,7 +312,7 @@ func (list *List) Set(index int, value interface{}) { return } - var foundElement *element + var foundElement *element[T] // determine traversal direction, last to first or first to last if list.size-index < index { foundElement = list.last @@ -329,7 +331,7 @@ func (list *List) Set(index int, value interface{}) { } // String returns a string representation of container -func (list *List) String() string { +func (list *List[T]) String() string { str := "DoublyLinkedList\n" values := []string{} for element := list.first; element != nil; element = element.next { @@ -340,6 +342,6 @@ func (list *List) String() string { } // Check that the index is within bounds of the list -func (list *List) withinRange(index int) bool { +func (list *List[T]) withinRange(index int) bool { return index >= 0 && index < list.size } diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 312d5ff2..4a4afdc7 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -5,22 +5,21 @@ package doublylinkedlist import ( + "cmp" "encoding/json" - "fmt" + "slices" "strings" "testing" - - "github.com/emirpasic/gods/utils" ) func TestListNew(t *testing.T) { - list1 := New() + list1 := New[int]() if actualValue := list1.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - list2 := New(1, "b") + list2 := New[int](1, 2) if actualValue := list2.Size(); actualValue != 2 { t.Errorf("Got %v expected %v", actualValue, 2) @@ -30,17 +29,17 @@ func TestListNew(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, 1) } - if actualValue, ok := list2.Get(1); actualValue != "b" || !ok { - t.Errorf("Got %v expected %v", actualValue, "b") + if actualValue, ok := list2.Get(1); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) } - if actualValue, ok := list2.Get(2); actualValue != nil || ok { - t.Errorf("Got %v expected %v", actualValue, nil) + if actualValue, ok := list2.Get(2); actualValue != 0 || ok { + t.Errorf("Got %v expected %v", actualValue, 0) } } func TestListAdd(t *testing.T) { - list := New() + list := New[string]() list.Add("a") list.Add("b", "c") if actualValue := list.Empty(); actualValue != false { @@ -55,7 +54,7 @@ func TestListAdd(t *testing.T) { } func TestListAppendAndPrepend(t *testing.T) { - list := New() + list := New[string]() list.Add("b") list.Prepend("a") list.Append("c") @@ -77,12 +76,12 @@ func TestListAppendAndPrepend(t *testing.T) { } func TestListRemove(t *testing.T) { - list := New() + list := New[string]() list.Add("a") list.Add("b", "c") list.Remove(2) - if actualValue, ok := list.Get(2); actualValue != nil || ok { - t.Errorf("Got %v expected %v", actualValue, nil) + if actualValue, ok := list.Get(2); actualValue != "" || ok { + t.Errorf("Got %v expected %v", actualValue, "") } list.Remove(1) list.Remove(0) @@ -96,7 +95,7 @@ func TestListRemove(t *testing.T) { } func TestListGet(t *testing.T) { - list := New() + list := New[string]() list.Add("a") list.Add("b", "c") if actualValue, ok := list.Get(0); actualValue != "a" || !ok { @@ -108,8 +107,8 @@ func TestListGet(t *testing.T) { if actualValue, ok := list.Get(2); actualValue != "c" || !ok { t.Errorf("Got %v expected %v", actualValue, "c") } - if actualValue, ok := list.Get(3); actualValue != nil || ok { - t.Errorf("Got %v expected %v", actualValue, nil) + if actualValue, ok := list.Get(3); actualValue != "" || ok { + t.Errorf("Got %v expected %v", actualValue, "") } list.Remove(0) if actualValue, ok := list.Get(0); actualValue != "b" || !ok { @@ -118,31 +117,31 @@ func TestListGet(t *testing.T) { } func TestListSwap(t *testing.T) { - list := New() + list := New[string]() list.Add("a") list.Add("b", "c") list.Swap(0, 1) if actualValue, ok := list.Get(0); actualValue != "b" || !ok { - t.Errorf("Got %v expected %v", actualValue, "c") + t.Errorf("Got %v expected %v", actualValue, "b") } } func TestListSort(t *testing.T) { - list := New() - list.Sort(utils.StringComparator) + list := New[string]() + list.Sort(cmp.Compare[string]) list.Add("e", "f", "g", "a", "b", "c", "d") - list.Sort(utils.StringComparator) + list.Sort(cmp.Compare[string]) for i := 1; i < list.Size(); i++ { a, _ := list.Get(i - 1) b, _ := list.Get(i) - if a.(string) > b.(string) { + if a > b { t.Errorf("Not sorted! %s > %s", a, b) } } } func TestListClear(t *testing.T) { - list := New() + list := New[string]() list.Add("e", "f", "g", "a", "b", "c", "d") list.Clear() if actualValue := list.Empty(); actualValue != true { @@ -154,12 +153,15 @@ func TestListClear(t *testing.T) { } func TestListContains(t *testing.T) { - list := New() + list := New[string]() list.Add("a") list.Add("b", "c") if actualValue := list.Contains("a"); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } + if actualValue := list.Contains(""); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, false) + } if actualValue := list.Contains("a", "b", "c"); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } @@ -176,43 +178,16 @@ func TestListContains(t *testing.T) { } func TestListValues(t *testing.T) { - list := New() + list := New[string]() list.Add("a") list.Add("b", "c") - if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abc"; actualValue != expectedValue { + if actualValue, expectedValue := list.Values(), []string{"a", "b", "c"}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } -func TestListIndexOf(t *testing.T) { - list := New() - - expectedIndex := -1 - if index := list.IndexOf("a"); index != expectedIndex { - t.Errorf("Got %v expected %v", index, expectedIndex) - } - - list.Add("a") - list.Add("b", "c") - - expectedIndex = 0 - if index := list.IndexOf("a"); index != expectedIndex { - t.Errorf("Got %v expected %v", index, expectedIndex) - } - - expectedIndex = 1 - if index := list.IndexOf("b"); index != expectedIndex { - t.Errorf("Got %v expected %v", index, expectedIndex) - } - - expectedIndex = 2 - if index := list.IndexOf("c"); index != expectedIndex { - t.Errorf("Got %v expected %v", index, expectedIndex) - } -} - func TestListInsert(t *testing.T) { - list := New() + list := New[string]() list.Insert(0, "b", "c", "d") list.Insert(0, "a") list.Insert(10, "x") // ignore @@ -223,20 +198,20 @@ func TestListInsert(t *testing.T) { if actualValue := list.Size(); actualValue != 5 { t.Errorf("Got %v expected %v", actualValue, 5) } - if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s", list.Values()...), "abcdg"; actualValue != expectedValue { + if actualValue, expectedValue := strings.Join(list.Values(), ""), "abcdg"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } list.Insert(4, "e", "f") // last to first traversal if actualValue := list.Size(); actualValue != 7 { t.Errorf("Got %v expected %v", actualValue, 7) } - if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s", list.Values()...), "abcdefg"; actualValue != expectedValue { + if actualValue, expectedValue := strings.Join(list.Values(), ""), "abcdefg"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } func TestListSet(t *testing.T) { - list := New() + list := New[string]() list.Set(0, "a") list.Set(1, "b") if actualValue := list.Size(); actualValue != 2 { @@ -251,20 +226,15 @@ func TestListSet(t *testing.T) { if actualValue := list.Size(); actualValue != 3 { t.Errorf("Got %v expected %v", actualValue, 3) } - if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abbc"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - list.Set(2, "cc") // last to first traversal - list.Set(0, "aa") // first to last traversal - if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "aabbcc"; actualValue != expectedValue { + if actualValue, expectedValue := list.Values(), []string{"a", "bb", "c"}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } func TestListEach(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - list.Each(func(index int, value interface{}) { + list.Each(func(index int, value string) { switch index { case 0: if actualValue, expectedValue := value, "a"; actualValue != expectedValue { @@ -285,10 +255,10 @@ func TestListEach(t *testing.T) { } func TestListMap(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - mappedList := list.Map(func(index int, value interface{}) interface{} { - return "mapped: " + value.(string) + mappedList := list.Map(func(index int, value string) string { + return "mapped: " + value }) if actualValue, _ := mappedList.Get(0); actualValue != "mapped: a" { t.Errorf("Got %v expected %v", actualValue, "mapped: a") @@ -305,10 +275,10 @@ func TestListMap(t *testing.T) { } func TestListSelect(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - selectedList := list.Select(func(index int, value interface{}) bool { - return value.(string) >= "a" && value.(string) <= "b" + selectedList := list.Select(func(index int, value string) bool { + return value >= "a" && value <= "b" }) if actualValue, _ := selectedList.Get(0); actualValue != "a" { t.Errorf("Got %v expected %v", actualValue, "value: a") @@ -322,60 +292,60 @@ func TestListSelect(t *testing.T) { } func TestListAny(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - any := list.Any(func(index int, value interface{}) bool { - return value.(string) == "c" + any := list.Any(func(index int, value string) bool { + return value == "c" }) if any != true { t.Errorf("Got %v expected %v", any, true) } - any = list.Any(func(index int, value interface{}) bool { - return value.(string) == "x" + any = list.Any(func(index int, value string) bool { + return value == "x" }) if any != false { t.Errorf("Got %v expected %v", any, false) } } func TestListAll(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - all := list.All(func(index int, value interface{}) bool { - return value.(string) >= "a" && value.(string) <= "c" + all := list.All(func(index int, value string) bool { + return value >= "a" && value <= "c" }) if all != true { t.Errorf("Got %v expected %v", all, true) } - all = list.All(func(index int, value interface{}) bool { - return value.(string) >= "a" && value.(string) <= "b" + all = list.All(func(index int, value string) bool { + return value >= "a" && value <= "b" }) if all != false { t.Errorf("Got %v expected %v", all, false) } } func TestListFind(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - foundIndex, foundValue := list.Find(func(index int, value interface{}) bool { - return value.(string) == "c" + foundIndex, foundValue := list.Find(func(index int, value string) bool { + return value == "c" }) if foundValue != "c" || foundIndex != 2 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, "c", 2) } - foundIndex, foundValue = list.Find(func(index int, value interface{}) bool { - return value.(string) == "x" + foundIndex, foundValue = list.Find(func(index int, value string) bool { + return value == "x" }) - if foundValue != nil || foundIndex != -1 { + if foundValue != "" || foundIndex != -1 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil) } } func TestListChaining(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - chainedList := list.Select(func(index int, value interface{}) bool { - return value.(string) > "a" - }).Map(func(index int, value interface{}) interface{} { - return value.(string) + value.(string) + chainedList := list.Select(func(index int, value string) bool { + return value > "a" + }).Map(func(index int, value string) string { + return value + value }) if chainedList.Size() != 2 { t.Errorf("Got %v expected %v", chainedList.Size(), 2) @@ -389,7 +359,7 @@ func TestListChaining(t *testing.T) { } func TestListIteratorNextOnEmpty(t *testing.T) { - list := New() + list := New[string]() it := list.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty list") @@ -397,7 +367,7 @@ func TestListIteratorNextOnEmpty(t *testing.T) { } func TestListIteratorNext(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") it := list.Iterator() count := 0 @@ -428,7 +398,7 @@ func TestListIteratorNext(t *testing.T) { } func TestListIteratorPrevOnEmpty(t *testing.T) { - list := New() + list := New[string]() it := list.Iterator() for it.Prev() { t.Errorf("Shouldn't iterate on empty list") @@ -436,7 +406,7 @@ func TestListIteratorPrevOnEmpty(t *testing.T) { } func TestListIteratorPrev(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") it := list.Iterator() for it.Next() { @@ -469,7 +439,7 @@ func TestListIteratorPrev(t *testing.T) { } func TestListIteratorBegin(t *testing.T) { - list := New() + list := New[string]() it := list.Iterator() it.Begin() list.Add("a", "b", "c") @@ -483,7 +453,7 @@ func TestListIteratorBegin(t *testing.T) { } func TestListIteratorEnd(t *testing.T) { - list := New() + list := New[string]() it := list.Iterator() if index := it.Index(); index != -1 { @@ -508,7 +478,7 @@ func TestListIteratorEnd(t *testing.T) { } func TestListIteratorFirst(t *testing.T) { - list := New() + list := New[string]() it := list.Iterator() if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -523,7 +493,7 @@ func TestListIteratorFirst(t *testing.T) { } func TestListIteratorLast(t *testing.T) { - list := New() + list := New[string]() it := list.Iterator() if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -539,13 +509,13 @@ func TestListIteratorLast(t *testing.T) { func TestListIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // NextTo (empty) { - list := New() + list := New[string]() it := list.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") @@ -554,7 +524,7 @@ func TestListIteratorNextTo(t *testing.T) { // NextTo (not found) { - list := New() + list := New[string]() list.Add("xx", "yy") it := list.Iterator() for it.NextTo(seek) { @@ -564,20 +534,20 @@ func TestListIteratorNextTo(t *testing.T) { // NextTo (found) { - list := New() + list := New[string]() list.Add("aa", "bb", "cc") it := list.Iterator() it.Begin() if !it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Next() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + if index, value := it.Index(), it.Value(); index != 2 || value != "cc" { t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") } if it.Next() { @@ -588,13 +558,13 @@ func TestListIteratorNextTo(t *testing.T) { func TestListIteratorPrevTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // PrevTo (empty) { - list := New() + list := New[string]() it := list.Iterator() it.End() for it.PrevTo(seek) { @@ -604,7 +574,7 @@ func TestListIteratorPrevTo(t *testing.T) { // PrevTo (not found) { - list := New() + list := New[string]() list.Add("xx", "yy") it := list.Iterator() it.End() @@ -615,20 +585,20 @@ func TestListIteratorPrevTo(t *testing.T) { // PrevTo (found) { - list := New() + list := New[string]() list.Add("aa", "bb", "cc") it := list.Iterator() it.End() if !it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty list") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Prev() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "aa" { + if index, value := it.Index(), it.Value(); index != 0 || value != "aa" { t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") } if it.Prev() { @@ -638,12 +608,12 @@ func TestListIteratorPrevTo(t *testing.T) { } func TestListSerialization(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") var err error assert := func() { - if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abc"; actualValue != expectedValue { + if actualValue, expectedValue := list.Values(), []string{"a", "b", "c"}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } if actualValue, expectedValue := list.Size(), 3; actualValue != expectedValue { @@ -662,26 +632,27 @@ func TestListSerialization(t *testing.T) { err = list.FromJSON(bytes) assert() - bytes, err = json.Marshal([]interface{}{"a", "b", "c", list}) + bytes, err = json.Marshal([]any{"a", "b", "c", list}) if err != nil { t.Errorf("Got error %v", err) } - err = json.Unmarshal([]byte(`[1,2,3]`), &list) + err = json.Unmarshal([]byte(`["a","b","c"]`), &list) if err != nil { t.Errorf("Got error %v", err) } + assert() } func TestListString(t *testing.T) { - c := New() + c := New[int]() c.Add(1) if !strings.HasPrefix(c.String(), "DoublyLinkedList") { t.Errorf("String should start with container name") } } -func benchmarkGet(b *testing.B, list *List, size int) { +func benchmarkGet(b *testing.B, list *List[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { list.Get(n) @@ -689,7 +660,7 @@ func benchmarkGet(b *testing.B, list *List, size int) { } } -func benchmarkAdd(b *testing.B, list *List, size int) { +func benchmarkAdd(b *testing.B, list *List[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { list.Add(n) @@ -697,7 +668,7 @@ func benchmarkAdd(b *testing.B, list *List, size int) { } } -func benchmarkRemove(b *testing.B, list *List, size int) { +func benchmarkRemove(b *testing.B, list *List[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { list.Remove(n) @@ -708,7 +679,7 @@ func benchmarkRemove(b *testing.B, list *List, size int) { func BenchmarkDoublyLinkedListGet100(b *testing.B) { b.StopTimer() size := 100 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -719,7 +690,7 @@ func BenchmarkDoublyLinkedListGet100(b *testing.B) { func BenchmarkDoublyLinkedListGet1000(b *testing.B) { b.StopTimer() size := 1000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -730,7 +701,7 @@ func BenchmarkDoublyLinkedListGet1000(b *testing.B) { func BenchmarkDoublyLinkedListGet10000(b *testing.B) { b.StopTimer() size := 10000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -741,7 +712,7 @@ func BenchmarkDoublyLinkedListGet10000(b *testing.B) { func BenchmarkDoublyLinkedListGet100000(b *testing.B) { b.StopTimer() size := 100000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -752,7 +723,7 @@ func BenchmarkDoublyLinkedListGet100000(b *testing.B) { func BenchmarkDoublyLinkedListAdd100(b *testing.B) { b.StopTimer() size := 100 - list := New() + list := New[int]() b.StartTimer() benchmarkAdd(b, list, size) } @@ -760,7 +731,7 @@ func BenchmarkDoublyLinkedListAdd100(b *testing.B) { func BenchmarkDoublyLinkedListAdd1000(b *testing.B) { b.StopTimer() size := 1000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -771,7 +742,7 @@ func BenchmarkDoublyLinkedListAdd1000(b *testing.B) { func BenchmarkDoublyLinkedListAdd10000(b *testing.B) { b.StopTimer() size := 10000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -782,7 +753,7 @@ func BenchmarkDoublyLinkedListAdd10000(b *testing.B) { func BenchmarkDoublyLinkedListAdd100000(b *testing.B) { b.StopTimer() size := 100000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -793,7 +764,7 @@ func BenchmarkDoublyLinkedListAdd100000(b *testing.B) { func BenchmarkDoublyLinkedListRemove100(b *testing.B) { b.StopTimer() size := 100 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -804,7 +775,7 @@ func BenchmarkDoublyLinkedListRemove100(b *testing.B) { func BenchmarkDoublyLinkedListRemove1000(b *testing.B) { b.StopTimer() size := 1000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -815,7 +786,7 @@ func BenchmarkDoublyLinkedListRemove1000(b *testing.B) { func BenchmarkDoublyLinkedListRemove10000(b *testing.B) { b.StopTimer() size := 10000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -826,7 +797,7 @@ func BenchmarkDoublyLinkedListRemove10000(b *testing.B) { func BenchmarkDoublyLinkedListRemove100000(b *testing.B) { b.StopTimer() size := 100000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } diff --git a/lists/doublylinkedlist/enumerable.go b/lists/doublylinkedlist/enumerable.go index 4b14a47f..4e6e7784 100644 --- a/lists/doublylinkedlist/enumerable.go +++ b/lists/doublylinkedlist/enumerable.go @@ -4,13 +4,13 @@ package doublylinkedlist -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Assert Enumerable implementation -var _ containers.EnumerableWithIndex = (*List)(nil) +var _ containers.EnumerableWithIndex[int] = (*List[int])(nil) // Each calls the given function once for each element, passing that element's index and value. -func (list *List) Each(f func(index int, value interface{})) { +func (list *List[T]) Each(f func(index int, value T)) { iterator := list.Iterator() for iterator.Next() { f(iterator.Index(), iterator.Value()) @@ -19,8 +19,8 @@ func (list *List) Each(f func(index int, value interface{})) { // Map invokes the given function once for each element and returns a // container containing the values returned by the given function. -func (list *List) Map(f func(index int, value interface{}) interface{}) *List { - newList := &List{} +func (list *List[T]) Map(f func(index int, value T) T) *List[T] { + newList := &List[T]{} iterator := list.Iterator() for iterator.Next() { newList.Add(f(iterator.Index(), iterator.Value())) @@ -29,8 +29,8 @@ func (list *List) Map(f func(index int, value interface{}) interface{}) *List { } // Select returns a new container containing all elements for which the given function returns a true value. -func (list *List) Select(f func(index int, value interface{}) bool) *List { - newList := &List{} +func (list *List[T]) Select(f func(index int, value T) bool) *List[T] { + newList := &List[T]{} iterator := list.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { @@ -42,7 +42,7 @@ func (list *List) Select(f func(index int, value interface{}) bool) *List { // Any passes each element of the container to the given function and // returns true if the function ever returns true for any element. -func (list *List) Any(f func(index int, value interface{}) bool) bool { +func (list *List[T]) Any(f func(index int, value T) bool) bool { iterator := list.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { @@ -54,7 +54,7 @@ func (list *List) Any(f func(index int, value interface{}) bool) bool { // All passes each element of the container to the given function and // returns true if the function returns true for all elements. -func (list *List) All(f func(index int, value interface{}) bool) bool { +func (list *List[T]) All(f func(index int, value T) bool) bool { iterator := list.Iterator() for iterator.Next() { if !f(iterator.Index(), iterator.Value()) { @@ -67,12 +67,13 @@ func (list *List) All(f func(index int, value interface{}) 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. -func (list *List) Find(f func(index int, value interface{}) bool) (index int, value interface{}) { +func (list *List[T]) Find(f func(index int, value T) bool) (index int, value T) { iterator := list.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { return iterator.Index(), iterator.Value() } } - return -1, nil + var t T + return -1, t } diff --git a/lists/doublylinkedlist/iterator.go b/lists/doublylinkedlist/iterator.go index 27b34c2e..1b637073 100644 --- a/lists/doublylinkedlist/iterator.go +++ b/lists/doublylinkedlist/iterator.go @@ -4,28 +4,28 @@ package doublylinkedlist -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Assert Iterator implementation -var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) +var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator holding the iterator's state -type Iterator struct { - list *List +type Iterator[T comparable] struct { + list *List[T] index int - element *element + element *element[T] } // Iterator returns a stateful iterator whose values can be fetched by an index. -func (list *List) Iterator() Iterator { - return Iterator{list: list, index: -1, element: nil} +func (list *List[T]) Iterator() Iterator[T] { + return Iterator[T]{list: list, index: -1, element: nil} } // 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 { +func (iterator *Iterator[T]) Next() bool { if iterator.index < iterator.list.size { iterator.index++ } @@ -44,7 +44,7 @@ func (iterator *Iterator) Next() bool { // 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 { +func (iterator *Iterator[T]) Prev() bool { if iterator.index >= 0 { iterator.index-- } @@ -62,26 +62,26 @@ func (iterator *Iterator) Prev() bool { // Value returns the current element's value. // Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { +func (iterator *Iterator[T]) Value() T { return iterator.element.value } // Index returns the current element's index. // Does not modify the state of the iterator. -func (iterator *Iterator) Index() int { +func (iterator *Iterator[T]) Index() int { return 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() { +func (iterator *Iterator[T]) Begin() { iterator.index = -1 iterator.element = nil } // 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() { +func (iterator *Iterator[T]) End() { iterator.index = iterator.list.size iterator.element = iterator.list.last } @@ -89,7 +89,7 @@ func (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 { +func (iterator *Iterator[T]) First() bool { iterator.Begin() return iterator.Next() } @@ -97,7 +97,7 @@ func (iterator *Iterator) First() bool { // 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 { +func (iterator *Iterator[T]) Last() bool { iterator.End() return iterator.Prev() } @@ -106,7 +106,7 @@ func (iterator *Iterator) Last() bool { // 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. -func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) NextTo(f func(index int, value T) bool) bool { for iterator.Next() { index, value := iterator.Index(), iterator.Value() if f(index, value) { @@ -120,7 +120,7 @@ func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool // 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. -func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) PrevTo(f func(index int, value T) bool) bool { for iterator.Prev() { index, value := iterator.Index(), iterator.Value() if f(index, value) { diff --git a/lists/doublylinkedlist/serialization.go b/lists/doublylinkedlist/serialization.go index f210f9a2..38d95bf2 100644 --- a/lists/doublylinkedlist/serialization.go +++ b/lists/doublylinkedlist/serialization.go @@ -6,21 +6,22 @@ package doublylinkedlist import ( "encoding/json" - "github.com/emirpasic/gods/containers" + + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*List)(nil) -var _ containers.JSONDeserializer = (*List)(nil) +var _ containers.JSONSerializer = (*List[int])(nil) +var _ containers.JSONDeserializer = (*List[int])(nil) // ToJSON outputs the JSON representation of list's elements. -func (list *List) ToJSON() ([]byte, error) { +func (list *List[T]) ToJSON() ([]byte, error) { return json.Marshal(list.Values()) } // FromJSON populates list's elements from the input JSON representation. -func (list *List) FromJSON(data []byte) error { - elements := []interface{}{} +func (list *List[T]) FromJSON(data []byte) error { + var elements []T err := json.Unmarshal(data, &elements) if err == nil { list.Clear() @@ -30,11 +31,11 @@ func (list *List) FromJSON(data []byte) error { } // UnmarshalJSON @implements json.Unmarshaler -func (list *List) UnmarshalJSON(bytes []byte) error { +func (list *List[T]) UnmarshalJSON(bytes []byte) error { return list.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (list *List) MarshalJSON() ([]byte, error) { +func (list *List[T]) MarshalJSON() ([]byte, error) { return list.ToJSON() } diff --git a/lists/lists.go b/lists/lists.go index 55bd619e..cc310366 100644 --- a/lists/lists.go +++ b/lists/lists.go @@ -10,22 +10,22 @@ package lists import ( - "github.com/emirpasic/gods/containers" - "github.com/emirpasic/gods/utils" + "github.com/emirpasic/gods/v2/containers" + "github.com/emirpasic/gods/v2/utils" ) // List interface that all lists implement -type List interface { - Get(index int) (interface{}, bool) +type List[T comparable] interface { + Get(index int) (T, bool) Remove(index int) - Add(values ...interface{}) - Contains(values ...interface{}) bool - Sort(comparator utils.Comparator) + Add(values ...T) + Contains(values ...T) bool + Sort(comparator utils.Comparator[T]) Swap(index1, index2 int) - Insert(index int, values ...interface{}) - Set(index int, value interface{}) + Insert(index int, values ...T) + Set(index int, value T) - containers.Container + containers.Container[T] // Empty() bool // Size() int // Clear() diff --git a/lists/singlylinkedlist/enumerable.go b/lists/singlylinkedlist/enumerable.go index 6fdbcb8b..febb90d4 100644 --- a/lists/singlylinkedlist/enumerable.go +++ b/lists/singlylinkedlist/enumerable.go @@ -4,13 +4,13 @@ package singlylinkedlist -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Assert Enumerable implementation -var _ containers.EnumerableWithIndex = (*List)(nil) +var _ containers.EnumerableWithIndex[int] = (*List[int])(nil) // Each calls the given function once for each element, passing that element's index and value. -func (list *List) Each(f func(index int, value interface{})) { +func (list *List[T]) Each(f func(index int, value T)) { iterator := list.Iterator() for iterator.Next() { f(iterator.Index(), iterator.Value()) @@ -19,8 +19,8 @@ func (list *List) Each(f func(index int, value interface{})) { // Map invokes the given function once for each element and returns a // container containing the values returned by the given function. -func (list *List) Map(f func(index int, value interface{}) interface{}) *List { - newList := &List{} +func (list *List[T]) Map(f func(index int, value T) T) *List[T] { + newList := &List[T]{} iterator := list.Iterator() for iterator.Next() { newList.Add(f(iterator.Index(), iterator.Value())) @@ -29,8 +29,8 @@ func (list *List) Map(f func(index int, value interface{}) interface{}) *List { } // Select returns a new container containing all elements for which the given function returns a true value. -func (list *List) Select(f func(index int, value interface{}) bool) *List { - newList := &List{} +func (list *List[T]) Select(f func(index int, value T) bool) *List[T] { + newList := &List[T]{} iterator := list.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { @@ -42,7 +42,7 @@ func (list *List) Select(f func(index int, value interface{}) bool) *List { // Any passes each element of the container to the given function and // returns true if the function ever returns true for any element. -func (list *List) Any(f func(index int, value interface{}) bool) bool { +func (list *List[T]) Any(f func(index int, value T) bool) bool { iterator := list.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { @@ -54,7 +54,7 @@ func (list *List) Any(f func(index int, value interface{}) bool) bool { // All passes each element of the container to the given function and // returns true if the function returns true for all elements. -func (list *List) All(f func(index int, value interface{}) bool) bool { +func (list *List[T]) All(f func(index int, value T) bool) bool { iterator := list.Iterator() for iterator.Next() { if !f(iterator.Index(), iterator.Value()) { @@ -67,12 +67,12 @@ func (list *List) All(f func(index int, value interface{}) 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. -func (list *List) Find(f func(index int, value interface{}) bool) (index int, value interface{}) { +func (list *List[T]) Find(f func(index int, value T) bool) (index int, value T) { iterator := list.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { return iterator.Index(), iterator.Value() } } - return -1, nil + return -1, value } diff --git a/lists/singlylinkedlist/iterator.go b/lists/singlylinkedlist/iterator.go index 4e7f1773..dc3304a8 100644 --- a/lists/singlylinkedlist/iterator.go +++ b/lists/singlylinkedlist/iterator.go @@ -4,28 +4,28 @@ package singlylinkedlist -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Assert Iterator implementation -var _ containers.IteratorWithIndex = (*Iterator)(nil) +var _ containers.IteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator holding the iterator's state -type Iterator struct { - list *List +type Iterator[T comparable] struct { + list *List[T] index int - element *element + element *element[T] } // Iterator returns a stateful iterator whose values can be fetched by an index. -func (list *List) Iterator() Iterator { - return Iterator{list: list, index: -1, element: nil} +func (list *List[T]) Iterator() *Iterator[T] { + return &Iterator[T]{list: list, index: -1, element: nil} } // 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 { +func (iterator *Iterator[T]) Next() bool { if iterator.index < iterator.list.size { iterator.index++ } @@ -43,19 +43,19 @@ func (iterator *Iterator) Next() bool { // Value returns the current element's value. // Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { +func (iterator *Iterator[T]) Value() T { return iterator.element.value } // Index returns the current element's index. // Does not modify the state of the iterator. -func (iterator *Iterator) Index() int { +func (iterator *Iterator[T]) Index() int { return 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() { +func (iterator *Iterator[T]) Begin() { iterator.index = -1 iterator.element = nil } @@ -63,7 +63,7 @@ func (iterator *Iterator) Begin() { // 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 { +func (iterator *Iterator[T]) First() bool { iterator.Begin() return iterator.Next() } @@ -72,7 +72,7 @@ func (iterator *Iterator) First() bool { // 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. -func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) NextTo(f func(index int, value T) bool) bool { for iterator.Next() { index, value := iterator.Index(), iterator.Value() if f(index, value) { diff --git a/lists/singlylinkedlist/serialization.go b/lists/singlylinkedlist/serialization.go index 588a316c..3cc49652 100644 --- a/lists/singlylinkedlist/serialization.go +++ b/lists/singlylinkedlist/serialization.go @@ -6,21 +6,22 @@ package singlylinkedlist import ( "encoding/json" - "github.com/emirpasic/gods/containers" + + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*List)(nil) -var _ containers.JSONDeserializer = (*List)(nil) +var _ containers.JSONSerializer = (*List[int])(nil) +var _ containers.JSONDeserializer = (*List[int])(nil) // ToJSON outputs the JSON representation of list's elements. -func (list *List) ToJSON() ([]byte, error) { +func (list *List[T]) ToJSON() ([]byte, error) { return json.Marshal(list.Values()) } // FromJSON populates list's elements from the input JSON representation. -func (list *List) FromJSON(data []byte) error { - elements := []interface{}{} +func (list *List[T]) FromJSON(data []byte) error { + var elements []T err := json.Unmarshal(data, &elements) if err == nil { list.Clear() @@ -30,11 +31,11 @@ func (list *List) FromJSON(data []byte) error { } // UnmarshalJSON @implements json.Unmarshaler -func (list *List) UnmarshalJSON(bytes []byte) error { +func (list *List[T]) UnmarshalJSON(bytes []byte) error { return list.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (list *List) MarshalJSON() ([]byte, error) { +func (list *List[T]) MarshalJSON() ([]byte, error) { return list.ToJSON() } diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index c3e2c675..a4126021 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -11,30 +11,31 @@ package singlylinkedlist import ( "fmt" + "slices" "strings" - "github.com/emirpasic/gods/lists" - "github.com/emirpasic/gods/utils" + "github.com/emirpasic/gods/v2/lists" + "github.com/emirpasic/gods/v2/utils" ) // Assert List implementation -var _ lists.List = (*List)(nil) +var _ lists.List[int] = (*List[int])(nil) // List holds the elements, where each element points to the next element -type List struct { - first *element - last *element +type List[T comparable] struct { + first *element[T] + last *element[T] size int } -type element struct { - value interface{} - next *element +type element[T comparable] struct { + value T + next *element[T] } // New instantiates a new list and adds the passed values, if any, to the list -func New(values ...interface{}) *List { - list := &List{} +func New[T comparable](values ...T) *List[T] { + list := &List[T]{} if len(values) > 0 { list.Add(values...) } @@ -42,9 +43,9 @@ func New(values ...interface{}) *List { } // Add appends a value (one or more) at the end of the list (same as Append()) -func (list *List) Add(values ...interface{}) { +func (list *List[T]) Add(values ...T) { for _, value := range values { - newElement := &element{value: value} + newElement := &element[T]{value: value} if list.size == 0 { list.first = newElement list.last = newElement @@ -57,15 +58,15 @@ func (list *List) Add(values ...interface{}) { } // Append appends a value (one or more) at the end of the list (same as Add()) -func (list *List) Append(values ...interface{}) { +func (list *List[T]) Append(values ...T) { list.Add(values...) } // Prepend prepends a values (or more) -func (list *List) Prepend(values ...interface{}) { +func (list *List[T]) Prepend(values ...T) { // in reverse to keep passed order i.e. ["c","d"] -> Prepend(["a","b"]) -> ["a","b","c",d"] for v := len(values) - 1; v >= 0; v-- { - newElement := &element{value: values[v], next: list.first} + newElement := &element[T]{value: values[v], next: list.first} list.first = newElement if list.size == 0 { list.last = newElement @@ -76,10 +77,11 @@ func (list *List) Prepend(values ...interface{}) { // Get returns the element at index. // Second return parameter is true if index is within bounds of the array and array is not empty, otherwise false. -func (list *List) Get(index int) (interface{}, bool) { +func (list *List[T]) Get(index int) (T, bool) { if !list.withinRange(index) { - return nil, false + var t T + return t, false } element := list.first @@ -90,7 +92,7 @@ func (list *List) Get(index int) (interface{}, bool) { } // Remove removes the element at the given index from the list. -func (list *List) Remove(index int) { +func (list *List[T]) Remove(index int) { if !list.withinRange(index) { return @@ -101,7 +103,7 @@ func (list *List) Remove(index int) { return } - var beforeElement *element + var beforeElement *element[T] element := list.first for e := 0; e != index; e, element = e+1, element.next { beforeElement = element @@ -126,7 +128,7 @@ func (list *List) Remove(index int) { // All values have to be present in the set for the method to return true. // Performance time complexity of n^2. // Returns true if no arguments are passed at all, i.e. set is always super-set of empty set. -func (list *List) Contains(values ...interface{}) bool { +func (list *List[T]) Contains(values ...T) bool { if len(values) == 0 { return true @@ -150,16 +152,16 @@ func (list *List) Contains(values ...interface{}) bool { } // Values returns all elements in the list. -func (list *List) Values() []interface{} { - values := make([]interface{}, list.size, list.size) +func (list *List[T]) Values() []T { + values := make([]T, list.size, list.size) for e, element := 0, list.first; element != nil; e, element = e+1, element.next { values[e] = element.value } return values } -//IndexOf returns index of provided element -func (list *List) IndexOf(value interface{}) int { +// IndexOf returns index of provided element +func (list *List[T]) IndexOf(value T) int { if list.size == 0 { return -1 } @@ -172,31 +174,31 @@ func (list *List) IndexOf(value interface{}) int { } // Empty returns true if list does not contain any elements. -func (list *List) Empty() bool { +func (list *List[T]) Empty() bool { return list.size == 0 } // Size returns number of elements within the list. -func (list *List) Size() int { +func (list *List[T]) Size() int { return list.size } // Clear removes all elements from the list. -func (list *List) Clear() { +func (list *List[T]) Clear() { list.size = 0 list.first = nil list.last = nil } // Sort sort values (in-place) using. -func (list *List) Sort(comparator utils.Comparator) { +func (list *List[T]) Sort(comparator utils.Comparator[T]) { if list.size < 2 { return } values := list.Values() - utils.Sort(values, comparator) + slices.SortFunc(values, comparator) list.Clear() @@ -205,9 +207,9 @@ func (list *List) Sort(comparator utils.Comparator) { } // Swap swaps values of two elements at the given indices. -func (list *List) Swap(i, j int) { +func (list *List[T]) Swap(i, j int) { if list.withinRange(i) && list.withinRange(j) && i != j { - var element1, element2 *element + var element1, element2 *element[T] for e, currentElement := 0, list.first; element1 == nil || element2 == nil; e, currentElement = e+1, currentElement.next { switch e { case i: @@ -223,7 +225,7 @@ func (list *List) Swap(i, j int) { // Insert inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right. // Does not do anything if position is negative or bigger than list's size // Note: position equal to list's size is valid, i.e. append. -func (list *List) Insert(index int, values ...interface{}) { +func (list *List[T]) Insert(index int, values ...T) { if !list.withinRange(index) { // Append @@ -235,7 +237,7 @@ func (list *List) Insert(index int, values ...interface{}) { list.size += len(values) - var beforeElement *element + var beforeElement *element[T] foundElement := list.first for e := 0; e != index; e, foundElement = e+1, foundElement.next { beforeElement = foundElement @@ -244,7 +246,7 @@ func (list *List) Insert(index int, values ...interface{}) { if foundElement == list.first { oldNextElement := list.first for i, value := range values { - newElement := &element{value: value} + newElement := &element[T]{value: value} if i == 0 { list.first = newElement } else { @@ -256,7 +258,7 @@ func (list *List) Insert(index int, values ...interface{}) { } else { oldNextElement := beforeElement.next for _, value := range values { - newElement := &element{value: value} + newElement := &element[T]{value: value} beforeElement.next = newElement beforeElement = newElement } @@ -267,7 +269,7 @@ func (list *List) Insert(index int, values ...interface{}) { // Set value at specified index // Does not do anything if position is negative or bigger than list's size // Note: position equal to list's size is valid, i.e. append. -func (list *List) Set(index int, value interface{}) { +func (list *List[T]) Set(index int, value T) { if !list.withinRange(index) { // Append @@ -285,7 +287,7 @@ func (list *List) Set(index int, value interface{}) { } // String returns a string representation of container -func (list *List) String() string { +func (list *List[T]) String() string { str := "SinglyLinkedList\n" values := []string{} for element := list.first; element != nil; element = element.next { @@ -296,6 +298,6 @@ func (list *List) String() string { } // Check that the index is within bounds of the list -func (list *List) withinRange(index int) bool { +func (list *List[T]) withinRange(index int) bool { return index >= 0 && index < list.size } diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index 4d58b7d5..6dd1d944 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -5,22 +5,21 @@ package singlylinkedlist import ( + "cmp" "encoding/json" - "fmt" + "slices" "strings" "testing" - - "github.com/emirpasic/gods/utils" ) func TestListNew(t *testing.T) { - list1 := New() + list1 := New[int]() if actualValue := list1.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } - list2 := New(1, "b") + list2 := New[int](1, 2) if actualValue := list2.Size(); actualValue != 2 { t.Errorf("Got %v expected %v", actualValue, 2) @@ -30,17 +29,17 @@ func TestListNew(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, 1) } - if actualValue, ok := list2.Get(1); actualValue != "b" || !ok { - t.Errorf("Got %v expected %v", actualValue, "b") + if actualValue, ok := list2.Get(1); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) } - if actualValue, ok := list2.Get(2); actualValue != nil || ok { - t.Errorf("Got %v expected %v", actualValue, nil) + if actualValue, ok := list2.Get(2); actualValue != 0 || ok { + t.Errorf("Got %v expected %v", actualValue, 0) } } func TestListAdd(t *testing.T) { - list := New() + list := New[string]() list.Add("a") list.Add("b", "c") if actualValue := list.Empty(); actualValue != false { @@ -55,7 +54,7 @@ func TestListAdd(t *testing.T) { } func TestListAppendAndPrepend(t *testing.T) { - list := New() + list := New[string]() list.Add("b") list.Prepend("a") list.Append("c") @@ -77,12 +76,12 @@ func TestListAppendAndPrepend(t *testing.T) { } func TestListRemove(t *testing.T) { - list := New() + list := New[string]() list.Add("a") list.Add("b", "c") list.Remove(2) - if actualValue, ok := list.Get(2); actualValue != nil || ok { - t.Errorf("Got %v expected %v", actualValue, nil) + if actualValue, ok := list.Get(2); actualValue != "" || ok { + t.Errorf("Got %v expected %v", actualValue, "") } list.Remove(1) list.Remove(0) @@ -96,7 +95,7 @@ func TestListRemove(t *testing.T) { } func TestListGet(t *testing.T) { - list := New() + list := New[string]() list.Add("a") list.Add("b", "c") if actualValue, ok := list.Get(0); actualValue != "a" || !ok { @@ -108,8 +107,8 @@ func TestListGet(t *testing.T) { if actualValue, ok := list.Get(2); actualValue != "c" || !ok { t.Errorf("Got %v expected %v", actualValue, "c") } - if actualValue, ok := list.Get(3); actualValue != nil || ok { - t.Errorf("Got %v expected %v", actualValue, nil) + if actualValue, ok := list.Get(3); actualValue != "" || ok { + t.Errorf("Got %v expected %v", actualValue, "") } list.Remove(0) if actualValue, ok := list.Get(0); actualValue != "b" || !ok { @@ -118,31 +117,31 @@ func TestListGet(t *testing.T) { } func TestListSwap(t *testing.T) { - list := New() + list := New[string]() list.Add("a") list.Add("b", "c") list.Swap(0, 1) if actualValue, ok := list.Get(0); actualValue != "b" || !ok { - t.Errorf("Got %v expected %v", actualValue, "c") + t.Errorf("Got %v expected %v", actualValue, "b") } } func TestListSort(t *testing.T) { - list := New() - list.Sort(utils.StringComparator) + list := New[string]() + list.Sort(cmp.Compare[string]) list.Add("e", "f", "g", "a", "b", "c", "d") - list.Sort(utils.StringComparator) + list.Sort(cmp.Compare[string]) for i := 1; i < list.Size(); i++ { a, _ := list.Get(i - 1) b, _ := list.Get(i) - if a.(string) > b.(string) { + if a > b { t.Errorf("Not sorted! %s > %s", a, b) } } } func TestListClear(t *testing.T) { - list := New() + list := New[string]() list.Add("e", "f", "g", "a", "b", "c", "d") list.Clear() if actualValue := list.Empty(); actualValue != true { @@ -154,12 +153,15 @@ func TestListClear(t *testing.T) { } func TestListContains(t *testing.T) { - list := New() + list := New[string]() list.Add("a") list.Add("b", "c") if actualValue := list.Contains("a"); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } + if actualValue := list.Contains(""); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, false) + } if actualValue := list.Contains("a", "b", "c"); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } @@ -176,16 +178,16 @@ func TestListContains(t *testing.T) { } func TestListValues(t *testing.T) { - list := New() + list := New[string]() list.Add("a") list.Add("b", "c") - if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abc"; actualValue != expectedValue { + if actualValue, expectedValue := list.Values(), []string{"a", "b", "c"}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } func TestListIndexOf(t *testing.T) { - list := New() + list := New[string]() expectedIndex := -1 if index := list.IndexOf("a"); index != expectedIndex { @@ -212,7 +214,7 @@ func TestListIndexOf(t *testing.T) { } func TestListInsert(t *testing.T) { - list := New() + list := New[string]() list.Insert(0, "b", "c") list.Insert(0, "a") list.Insert(10, "x") // ignore @@ -223,13 +225,13 @@ func TestListInsert(t *testing.T) { if actualValue := list.Size(); actualValue != 4 { t.Errorf("Got %v expected %v", actualValue, 4) } - if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", list.Values()...), "abcd"; actualValue != expectedValue { + if actualValue, expectedValue := strings.Join(list.Values(), ""), "abcd"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } func TestListSet(t *testing.T) { - list := New() + list := New[string]() list.Set(0, "a") list.Set(1, "b") if actualValue := list.Size(); actualValue != 2 { @@ -244,15 +246,15 @@ func TestListSet(t *testing.T) { if actualValue := list.Size(); actualValue != 3 { t.Errorf("Got %v expected %v", actualValue, 3) } - if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abbc"; actualValue != expectedValue { + if actualValue, expectedValue := list.Values(), []string{"a", "bb", "c"}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } func TestListEach(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - list.Each(func(index int, value interface{}) { + list.Each(func(index int, value string) { switch index { case 0: if actualValue, expectedValue := value, "a"; actualValue != expectedValue { @@ -273,10 +275,10 @@ func TestListEach(t *testing.T) { } func TestListMap(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - mappedList := list.Map(func(index int, value interface{}) interface{} { - return "mapped: " + value.(string) + mappedList := list.Map(func(index int, value string) string { + return "mapped: " + value }) if actualValue, _ := mappedList.Get(0); actualValue != "mapped: a" { t.Errorf("Got %v expected %v", actualValue, "mapped: a") @@ -293,10 +295,10 @@ func TestListMap(t *testing.T) { } func TestListSelect(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - selectedList := list.Select(func(index int, value interface{}) bool { - return value.(string) >= "a" && value.(string) <= "b" + selectedList := list.Select(func(index int, value string) bool { + return value >= "a" && value <= "b" }) if actualValue, _ := selectedList.Get(0); actualValue != "a" { t.Errorf("Got %v expected %v", actualValue, "value: a") @@ -310,60 +312,60 @@ func TestListSelect(t *testing.T) { } func TestListAny(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - any := list.Any(func(index int, value interface{}) bool { - return value.(string) == "c" + any := list.Any(func(index int, value string) bool { + return value == "c" }) if any != true { t.Errorf("Got %v expected %v", any, true) } - any = list.Any(func(index int, value interface{}) bool { - return value.(string) == "x" + any = list.Any(func(index int, value string) bool { + return value == "x" }) if any != false { t.Errorf("Got %v expected %v", any, false) } } func TestListAll(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - all := list.All(func(index int, value interface{}) bool { - return value.(string) >= "a" && value.(string) <= "c" + all := list.All(func(index int, value string) bool { + return value >= "a" && value <= "c" }) if all != true { t.Errorf("Got %v expected %v", all, true) } - all = list.All(func(index int, value interface{}) bool { - return value.(string) >= "a" && value.(string) <= "b" + all = list.All(func(index int, value string) bool { + return value >= "a" && value <= "b" }) if all != false { t.Errorf("Got %v expected %v", all, false) } } func TestListFind(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - foundIndex, foundValue := list.Find(func(index int, value interface{}) bool { - return value.(string) == "c" + foundIndex, foundValue := list.Find(func(index int, value string) bool { + return value == "c" }) if foundValue != "c" || foundIndex != 2 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, "c", 2) } - foundIndex, foundValue = list.Find(func(index int, value interface{}) bool { - return value.(string) == "x" + foundIndex, foundValue = list.Find(func(index int, value string) bool { + return value == "x" }) - if foundValue != nil || foundIndex != -1 { + if foundValue != "" || foundIndex != -1 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil) } } func TestListChaining(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") - chainedList := list.Select(func(index int, value interface{}) bool { - return value.(string) > "a" - }).Map(func(index int, value interface{}) interface{} { - return value.(string) + value.(string) + chainedList := list.Select(func(index int, value string) bool { + return value > "a" + }).Map(func(index int, value string) string { + return value + value }) if chainedList.Size() != 2 { t.Errorf("Got %v expected %v", chainedList.Size(), 2) @@ -377,7 +379,7 @@ func TestListChaining(t *testing.T) { } func TestListIteratorNextOnEmpty(t *testing.T) { - list := New() + list := New[string]() it := list.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty list") @@ -385,7 +387,7 @@ func TestListIteratorNextOnEmpty(t *testing.T) { } func TestListIteratorNext(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") it := list.Iterator() count := 0 @@ -416,7 +418,7 @@ func TestListIteratorNext(t *testing.T) { } func TestListIteratorBegin(t *testing.T) { - list := New() + list := New[string]() it := list.Iterator() it.Begin() list.Add("a", "b", "c") @@ -430,7 +432,7 @@ func TestListIteratorBegin(t *testing.T) { } func TestListIteratorFirst(t *testing.T) { - list := New() + list := New[string]() it := list.Iterator() if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -446,13 +448,13 @@ func TestListIteratorFirst(t *testing.T) { func TestListIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // NextTo (empty) { - list := New() + list := New[string]() it := list.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") @@ -461,7 +463,7 @@ func TestListIteratorNextTo(t *testing.T) { // NextTo (not found) { - list := New() + list := New[string]() list.Add("xx", "yy") it := list.Iterator() for it.NextTo(seek) { @@ -471,20 +473,20 @@ func TestListIteratorNextTo(t *testing.T) { // NextTo (found) { - list := New() + list := New[string]() list.Add("aa", "bb", "cc") it := list.Iterator() it.Begin() if !it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Next() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + if index, value := it.Index(), it.Value(); index != 2 || value != "cc" { t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") } if it.Next() { @@ -494,12 +496,12 @@ func TestListIteratorNextTo(t *testing.T) { } func TestListSerialization(t *testing.T) { - list := New() + list := New[string]() list.Add("a", "b", "c") var err error assert := func() { - if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abc"; actualValue != expectedValue { + if actualValue, expectedValue := list.Values(), []string{"a", "b", "c"}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } if actualValue, expectedValue := list.Size(), 3; actualValue != expectedValue { @@ -518,26 +520,27 @@ func TestListSerialization(t *testing.T) { err = list.FromJSON(bytes) assert() - bytes, err = json.Marshal([]interface{}{"a", "b", "c", list}) + bytes, err = json.Marshal([]any{"a", "b", "c", list}) if err != nil { t.Errorf("Got error %v", err) } - err = json.Unmarshal([]byte(`[1,2,3]`), &list) + err = json.Unmarshal([]byte(`["a","b","c"]`), &list) if err != nil { t.Errorf("Got error %v", err) } + assert() } func TestListString(t *testing.T) { - c := New() + c := New[int]() c.Add(1) if !strings.HasPrefix(c.String(), "SinglyLinkedList") { t.Errorf("String should start with container name") } } -func benchmarkGet(b *testing.B, list *List, size int) { +func benchmarkGet(b *testing.B, list *List[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { list.Get(n) @@ -545,7 +548,7 @@ func benchmarkGet(b *testing.B, list *List, size int) { } } -func benchmarkAdd(b *testing.B, list *List, size int) { +func benchmarkAdd(b *testing.B, list *List[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { list.Add(n) @@ -553,7 +556,7 @@ func benchmarkAdd(b *testing.B, list *List, size int) { } } -func benchmarkRemove(b *testing.B, list *List, size int) { +func benchmarkRemove(b *testing.B, list *List[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { list.Remove(n) @@ -564,7 +567,7 @@ func benchmarkRemove(b *testing.B, list *List, size int) { func BenchmarkSinglyLinkedListGet100(b *testing.B) { b.StopTimer() size := 100 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -575,7 +578,7 @@ func BenchmarkSinglyLinkedListGet100(b *testing.B) { func BenchmarkSinglyLinkedListGet1000(b *testing.B) { b.StopTimer() size := 1000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -586,7 +589,7 @@ func BenchmarkSinglyLinkedListGet1000(b *testing.B) { func BenchmarkSinglyLinkedListGet10000(b *testing.B) { b.StopTimer() size := 10000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -597,7 +600,7 @@ func BenchmarkSinglyLinkedListGet10000(b *testing.B) { func BenchmarkSinglyLinkedListGet100000(b *testing.B) { b.StopTimer() size := 100000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -608,7 +611,7 @@ func BenchmarkSinglyLinkedListGet100000(b *testing.B) { func BenchmarkSinglyLinkedListAdd100(b *testing.B) { b.StopTimer() size := 100 - list := New() + list := New[int]() b.StartTimer() benchmarkAdd(b, list, size) } @@ -616,7 +619,7 @@ func BenchmarkSinglyLinkedListAdd100(b *testing.B) { func BenchmarkSinglyLinkedListAdd1000(b *testing.B) { b.StopTimer() size := 1000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -627,7 +630,7 @@ func BenchmarkSinglyLinkedListAdd1000(b *testing.B) { func BenchmarkSinglyLinkedListAdd10000(b *testing.B) { b.StopTimer() size := 10000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -638,7 +641,7 @@ func BenchmarkSinglyLinkedListAdd10000(b *testing.B) { func BenchmarkSinglyLinkedListAdd100000(b *testing.B) { b.StopTimer() size := 100000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -649,7 +652,7 @@ func BenchmarkSinglyLinkedListAdd100000(b *testing.B) { func BenchmarkSinglyLinkedListRemove100(b *testing.B) { b.StopTimer() size := 100 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -660,7 +663,7 @@ func BenchmarkSinglyLinkedListRemove100(b *testing.B) { func BenchmarkSinglyLinkedListRemove1000(b *testing.B) { b.StopTimer() size := 1000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -671,7 +674,7 @@ func BenchmarkSinglyLinkedListRemove1000(b *testing.B) { func BenchmarkSinglyLinkedListRemove10000(b *testing.B) { b.StopTimer() size := 10000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } @@ -682,7 +685,7 @@ func BenchmarkSinglyLinkedListRemove10000(b *testing.B) { func BenchmarkSinglyLinkedListRemove100000(b *testing.B) { b.StopTimer() size := 100000 - list := New() + list := New[int]() for n := 0; n < size; n++ { list.Add(n) } diff --git a/maps/hashbidimap/hashbidimap.go b/maps/hashbidimap/hashbidimap.go index 5a386ec7..cf947a82 100644 --- a/maps/hashbidimap/hashbidimap.go +++ b/maps/hashbidimap/hashbidimap.go @@ -17,26 +17,27 @@ package hashbidimap import ( "fmt" - "github.com/emirpasic/gods/maps" - "github.com/emirpasic/gods/maps/hashmap" + + "github.com/emirpasic/gods/v2/maps" + "github.com/emirpasic/gods/v2/maps/hashmap" ) // Assert Map implementation -var _ maps.BidiMap = (*Map)(nil) +var _ maps.BidiMap[string, int] = (*Map[string, int])(nil) // Map holds the elements in two hashmaps. -type Map struct { - forwardMap hashmap.Map - inverseMap hashmap.Map +type Map[K, V comparable] struct { + forwardMap hashmap.Map[K, V] + inverseMap hashmap.Map[V, K] } // New instantiates a bidirectional map. -func New() *Map { - return &Map{*hashmap.New(), *hashmap.New()} +func New[K, V comparable]() *Map[K, V] { + return &Map[K, V]{*hashmap.New[K, V](), *hashmap.New[V, K]()} } // Put inserts element into the map. -func (m *Map) Put(key interface{}, value interface{}) { +func (m *Map[K, V]) Put(key K, value V) { if valueByKey, ok := m.forwardMap.Get(key); ok { m.inverseMap.Remove(valueByKey) } @@ -49,18 +50,18 @@ func (m *Map) Put(key interface{}, value interface{}) { // Get searches the element in the map by key and returns its value or nil if key is not found in map. // Second return parameter is true if key was found, otherwise false. -func (m *Map) Get(key interface{}) (value interface{}, found bool) { +func (m *Map[K, V]) Get(key K) (value V, found bool) { return m.forwardMap.Get(key) } // GetKey searches the element in the map by value and returns its key or nil if value is not found in map. // Second return parameter is true if value was found, otherwise false. -func (m *Map) GetKey(value interface{}) (key interface{}, found bool) { +func (m *Map[K, V]) GetKey(value V) (key K, found bool) { return m.inverseMap.Get(value) } // Remove removes the element from the map by key. -func (m *Map) Remove(key interface{}) { +func (m *Map[K, V]) Remove(key K) { if value, found := m.forwardMap.Get(key); found { m.forwardMap.Remove(key) m.inverseMap.Remove(value) @@ -68,33 +69,33 @@ func (m *Map) Remove(key interface{}) { } // Empty returns true if map does not contain any elements -func (m *Map) Empty() bool { +func (m *Map[K, V]) Empty() bool { return m.Size() == 0 } // Size returns number of elements in the map. -func (m *Map) Size() int { +func (m *Map[K, V]) Size() int { return m.forwardMap.Size() } // Keys returns all keys (random order). -func (m *Map) Keys() []interface{} { +func (m *Map[K, V]) Keys() []K { return m.forwardMap.Keys() } // Values returns all values (random order). -func (m *Map) Values() []interface{} { +func (m *Map[K, V]) Values() []V { return m.inverseMap.Keys() } // Clear removes all elements from the map. -func (m *Map) Clear() { +func (m *Map[K, V]) Clear() { m.forwardMap.Clear() m.inverseMap.Clear() } // String returns a string representation of container -func (m *Map) String() string { +func (m *Map[K, V]) String() string { str := "HashBidiMap\n" str += fmt.Sprintf("%v", m.forwardMap) return str diff --git a/maps/hashbidimap/hashbidimap_test.go b/maps/hashbidimap/hashbidimap_test.go index dd911165..64fae28f 100644 --- a/maps/hashbidimap/hashbidimap_test.go +++ b/maps/hashbidimap/hashbidimap_test.go @@ -6,13 +6,14 @@ package hashbidimap import ( "encoding/json" - "fmt" "strings" "testing" + + "github.com/emirpasic/gods/v2/testutils" ) func TestMapPut(t *testing.T) { - m := New() + m := New[int, string]() m.Put(5, "e") m.Put(6, "f") m.Put(7, "g") @@ -25,12 +26,8 @@ func TestMapPut(t *testing.T) { if actualValue := m.Size(); actualValue != 7 { t.Errorf("Got %v expected %v", actualValue, 7) } - if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "e", "f", "g"}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4, 5, 6, 7}) + testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d", "e", "f", "g"}) // key,expectedValue,expectedFound tests1 := [][]interface{}{ @@ -41,12 +38,12 @@ func TestMapPut(t *testing.T) { {5, "e", true}, {6, "f", true}, {7, "g", true}, - {8, nil, false}, + {8, "", false}, } for _, test := range tests1 { // retrievals - actualValue, actualFound := m.Get(test[0]) + actualValue, actualFound := m.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } @@ -54,7 +51,7 @@ func TestMapPut(t *testing.T) { } func TestMapRemove(t *testing.T) { - m := New() + m := New[int, string]() m.Put(5, "e") m.Put(6, "f") m.Put(7, "g") @@ -70,13 +67,9 @@ func TestMapRemove(t *testing.T) { m.Remove(8) m.Remove(5) - if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4}) + testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d"}) - if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d"}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } if actualValue := m.Size(); actualValue != 4 { t.Errorf("Got %v expected %v", actualValue, 4) } @@ -86,14 +79,14 @@ func TestMapRemove(t *testing.T) { {2, "b", true}, {3, "c", true}, {4, "d", true}, - {5, nil, false}, - {6, nil, false}, - {7, nil, false}, - {8, nil, false}, + {5, "", false}, + {6, "", false}, + {7, "", false}, + {8, "", false}, } for _, test := range tests2 { - actualValue, actualFound := m.Get(test[0]) + actualValue, actualFound := m.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } @@ -106,12 +99,8 @@ func TestMapRemove(t *testing.T) { m.Remove(2) m.Remove(2) - if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, m.Keys(), nil) + testutils.SameElements(t, m.Values(), nil) if actualValue := m.Size(); actualValue != 0 { t.Errorf("Got %v expected %v", actualValue, 0) } @@ -121,7 +110,7 @@ func TestMapRemove(t *testing.T) { } func TestMapGetKey(t *testing.T) { - m := New() + m := New[int, string]() m.Put(5, "e") m.Put(6, "f") m.Put(7, "g") @@ -140,12 +129,12 @@ func TestMapGetKey(t *testing.T) { {5, "e", true}, {6, "f", true}, {7, "g", true}, - {nil, "x", false}, + {0, "x", false}, } for _, test := range tests1 { // retrievals - actualValue, actualFound := m.GetKey(test[1]) + actualValue, actualFound := m.GetKey(test[1].(string)) if actualValue != test[0] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[0]) } @@ -153,19 +142,15 @@ func TestMapGetKey(t *testing.T) { } func TestMapSerialization(t *testing.T) { - m := New() + m := New[string, float64]() m.Put("a", 1.0) m.Put("b", 2.0) m.Put("c", 3.0) var err error assert := func() { - if actualValue, expectedValue := m.Keys(), []interface{}{"a", "b", "c"}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := m.Values(), []interface{}{1.0, 2.0, 3.0}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, m.Keys(), []string{"a", "b", "c"}) + testutils.SameElements(t, m.Values(), []float64{1.0, 2.0, 3.0}) if actualValue, expectedValue := m.Size(), 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } @@ -194,33 +179,14 @@ func TestMapSerialization(t *testing.T) { } func TestMapString(t *testing.T) { - c := New() + c := New[string, int]() c.Put("a", 1) if !strings.HasPrefix(c.String(), "HashBidiMap") { t.Errorf("String should start with container name") } } -func sameElements(a []interface{}, b []interface{}) bool { - if len(a) != len(b) { - return false - } - for _, av := range a { - found := false - for _, bv := range b { - if av == bv { - found = true - break - } - } - if !found { - return false - } - } - return true -} - -func benchmarkGet(b *testing.B, m *Map, size int) { +func benchmarkGet(b *testing.B, m *Map[int, int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { m.Get(n) @@ -228,7 +194,7 @@ func benchmarkGet(b *testing.B, m *Map, size int) { } } -func benchmarkPut(b *testing.B, m *Map, size int) { +func benchmarkPut(b *testing.B, m *Map[int, int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { m.Put(n, n) @@ -236,7 +202,7 @@ func benchmarkPut(b *testing.B, m *Map, size int) { } } -func benchmarkRemove(b *testing.B, m *Map, size int) { +func benchmarkRemove(b *testing.B, m *Map[int, int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { m.Remove(n) @@ -247,7 +213,7 @@ func benchmarkRemove(b *testing.B, m *Map, size int) { func BenchmarkHashBidiMapGet100(b *testing.B) { b.StopTimer() size := 100 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -258,7 +224,7 @@ func BenchmarkHashBidiMapGet100(b *testing.B) { func BenchmarkHashBidiMapGet1000(b *testing.B) { b.StopTimer() size := 1000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -269,7 +235,7 @@ func BenchmarkHashBidiMapGet1000(b *testing.B) { func BenchmarkHashBidiMapGet10000(b *testing.B) { b.StopTimer() size := 10000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -280,7 +246,7 @@ func BenchmarkHashBidiMapGet10000(b *testing.B) { func BenchmarkHashBidiMapGet100000(b *testing.B) { b.StopTimer() size := 100000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -291,7 +257,7 @@ func BenchmarkHashBidiMapGet100000(b *testing.B) { func BenchmarkHashBidiMapPut100(b *testing.B) { b.StopTimer() size := 100 - m := New() + m := New[int, int]() b.StartTimer() benchmarkPut(b, m, size) } @@ -299,7 +265,7 @@ func BenchmarkHashBidiMapPut100(b *testing.B) { func BenchmarkHashBidiMapPut1000(b *testing.B) { b.StopTimer() size := 1000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -310,7 +276,7 @@ func BenchmarkHashBidiMapPut1000(b *testing.B) { func BenchmarkHashBidiMapPut10000(b *testing.B) { b.StopTimer() size := 10000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -321,7 +287,7 @@ func BenchmarkHashBidiMapPut10000(b *testing.B) { func BenchmarkHashBidiMapPut100000(b *testing.B) { b.StopTimer() size := 100000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -332,7 +298,7 @@ func BenchmarkHashBidiMapPut100000(b *testing.B) { func BenchmarkHashBidiMapRemove100(b *testing.B) { b.StopTimer() size := 100 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -343,7 +309,7 @@ func BenchmarkHashBidiMapRemove100(b *testing.B) { func BenchmarkHashBidiMapRemove1000(b *testing.B) { b.StopTimer() size := 1000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -354,7 +320,7 @@ func BenchmarkHashBidiMapRemove1000(b *testing.B) { func BenchmarkHashBidiMapRemove10000(b *testing.B) { b.StopTimer() size := 10000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -365,7 +331,7 @@ func BenchmarkHashBidiMapRemove10000(b *testing.B) { func BenchmarkHashBidiMapRemove100000(b *testing.B) { b.StopTimer() size := 100000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } diff --git a/maps/hashbidimap/serialization.go b/maps/hashbidimap/serialization.go index dfae0430..9decc35a 100644 --- a/maps/hashbidimap/serialization.go +++ b/maps/hashbidimap/serialization.go @@ -6,37 +6,41 @@ package hashbidimap import ( "encoding/json" - "github.com/emirpasic/gods/containers" + + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*Map)(nil) -var _ containers.JSONDeserializer = (*Map)(nil) +var _ containers.JSONSerializer = (*Map[string, int])(nil) +var _ containers.JSONDeserializer = (*Map[string, int])(nil) // ToJSON outputs the JSON representation of the map. -func (m *Map) ToJSON() ([]byte, error) { +func (m *Map[K, V]) ToJSON() ([]byte, error) { return m.forwardMap.ToJSON() } // FromJSON populates the map from the input JSON representation. -func (m *Map) FromJSON(data []byte) error { - elements := make(map[string]interface{}) +func (m *Map[K, V]) FromJSON(data []byte) error { + var elements map[K]V err := json.Unmarshal(data, &elements) - if err == nil { - m.Clear() - for key, value := range elements { - m.Put(key, value) - } + if err != nil { + return err + } + + m.Clear() + for k, v := range elements { + m.Put(k, v) } - return err + + return nil } // UnmarshalJSON @implements json.Unmarshaler -func (m *Map) UnmarshalJSON(bytes []byte) error { +func (m *Map[K, V]) UnmarshalJSON(bytes []byte) error { return m.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (m *Map) MarshalJSON() ([]byte, error) { +func (m *Map[K, V]) MarshalJSON() ([]byte, error) { return m.ToJSON() } diff --git a/maps/hashmap/hashmap.go b/maps/hashmap/hashmap.go index e945c39f..e2bbbf52 100644 --- a/maps/hashmap/hashmap.go +++ b/maps/hashmap/hashmap.go @@ -13,52 +13,53 @@ package hashmap import ( "fmt" - "github.com/emirpasic/gods/maps" + + "github.com/emirpasic/gods/v2/maps" ) // Assert Map implementation -var _ maps.Map = (*Map)(nil) +var _ maps.Map[string, int] = (*Map[string, int])(nil) // Map holds the elements in go's native map -type Map struct { - m map[interface{}]interface{} +type Map[K comparable, V any] struct { + m map[K]V } // New instantiates a hash map. -func New() *Map { - return &Map{m: make(map[interface{}]interface{})} +func New[K comparable, V any]() *Map[K, V] { + return &Map[K, V]{m: make(map[K]V)} } // Put inserts element into the map. -func (m *Map) Put(key interface{}, value interface{}) { +func (m *Map[K, V]) Put(key K, value V) { m.m[key] = value } // Get searches the element in the map by key and returns its value or nil if key is not found in map. // Second return parameter is true if key was found, otherwise false. -func (m *Map) Get(key interface{}) (value interface{}, found bool) { +func (m *Map[K, V]) Get(key K) (value V, found bool) { value, found = m.m[key] return } // Remove removes the element from the map by key. -func (m *Map) Remove(key interface{}) { +func (m *Map[K, V]) Remove(key K) { delete(m.m, key) } // Empty returns true if map does not contain any elements -func (m *Map) Empty() bool { +func (m *Map[K, V]) Empty() bool { return m.Size() == 0 } // Size returns number of elements in the map. -func (m *Map) Size() int { +func (m *Map[K, V]) Size() int { return len(m.m) } // Keys returns all keys (random order). -func (m *Map) Keys() []interface{} { - keys := make([]interface{}, m.Size()) +func (m *Map[K, V]) Keys() []K { + keys := make([]K, m.Size()) count := 0 for key := range m.m { keys[count] = key @@ -68,8 +69,8 @@ func (m *Map) Keys() []interface{} { } // Values returns all values (random order). -func (m *Map) Values() []interface{} { - values := make([]interface{}, m.Size()) +func (m *Map[K, V]) Values() []V { + values := make([]V, m.Size()) count := 0 for _, value := range m.m { values[count] = value @@ -79,12 +80,12 @@ func (m *Map) Values() []interface{} { } // Clear removes all elements from the map. -func (m *Map) Clear() { - m.m = make(map[interface{}]interface{}) +func (m *Map[K, V]) Clear() { + clear(m.m) } // String returns a string representation of container -func (m *Map) String() string { +func (m *Map[K, V]) String() string { str := "HashMap\n" str += fmt.Sprintf("%v", m.m) return str diff --git a/maps/hashmap/hashmap_test.go b/maps/hashmap/hashmap_test.go index 91acca8d..5e650682 100644 --- a/maps/hashmap/hashmap_test.go +++ b/maps/hashmap/hashmap_test.go @@ -6,13 +6,14 @@ package hashmap import ( "encoding/json" - "fmt" "strings" "testing" + + "github.com/emirpasic/gods/v2/testutils" ) func TestMapPut(t *testing.T) { - m := New() + m := New[int, string]() m.Put(5, "e") m.Put(6, "f") m.Put(7, "g") @@ -25,12 +26,8 @@ func TestMapPut(t *testing.T) { if actualValue := m.Size(); actualValue != 7 { t.Errorf("Got %v expected %v", actualValue, 7) } - if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "e", "f", "g"}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4, 5, 6, 7}) + testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d", "e", "f", "g"}) // key,expectedValue,expectedFound tests1 := [][]interface{}{ @@ -41,12 +38,12 @@ func TestMapPut(t *testing.T) { {5, "e", true}, {6, "f", true}, {7, "g", true}, - {8, nil, false}, + {8, "", false}, } for _, test := range tests1 { // retrievals - actualValue, actualFound := m.Get(test[0]) + actualValue, actualFound := m.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } @@ -54,7 +51,7 @@ func TestMapPut(t *testing.T) { } func TestMapRemove(t *testing.T) { - m := New() + m := New[int, string]() m.Put(5, "e") m.Put(6, "f") m.Put(7, "g") @@ -70,13 +67,9 @@ func TestMapRemove(t *testing.T) { m.Remove(8) m.Remove(5) - if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4}) + testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d"}) - if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d"}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } if actualValue := m.Size(); actualValue != 4 { t.Errorf("Got %v expected %v", actualValue, 4) } @@ -86,14 +79,14 @@ func TestMapRemove(t *testing.T) { {2, "b", true}, {3, "c", true}, {4, "d", true}, - {5, nil, false}, - {6, nil, false}, - {7, nil, false}, - {8, nil, false}, + {5, "", false}, + {6, "", false}, + {7, "", false}, + {8, "", false}, } for _, test := range tests2 { - actualValue, actualFound := m.Get(test[0]) + actualValue, actualFound := m.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } @@ -106,12 +99,8 @@ func TestMapRemove(t *testing.T) { m.Remove(2) m.Remove(2) - if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, m.Keys(), nil) + testutils.SameElements(t, m.Values(), nil) if actualValue := m.Size(); actualValue != 0 { t.Errorf("Got %v expected %v", actualValue, 0) } @@ -121,19 +110,15 @@ func TestMapRemove(t *testing.T) { } func TestMapSerialization(t *testing.T) { - m := New() + m := New[string, float64]() m.Put("a", 1.0) m.Put("b", 2.0) m.Put("c", 3.0) var err error assert := func() { - if actualValue, expectedValue := m.Keys(), []interface{}{"a", "b", "c"}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := m.Values(), []interface{}{1.0, 2.0, 3.0}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, m.Keys(), []string{"a", "b", "c"}) + testutils.SameElements(t, m.Values(), []float64{1.0, 2.0, 3.0}) if actualValue, expectedValue := m.Size(), 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } @@ -162,33 +147,14 @@ func TestMapSerialization(t *testing.T) { } func TestMapString(t *testing.T) { - c := New() + c := New[string, int]() c.Put("a", 1) if !strings.HasPrefix(c.String(), "HashMap") { t.Errorf("String should start with container name") } } -func sameElements(a []interface{}, b []interface{}) bool { - if len(a) != len(b) { - return false - } - for _, av := range a { - found := false - for _, bv := range b { - if av == bv { - found = true - break - } - } - if !found { - return false - } - } - return true -} - -func benchmarkGet(b *testing.B, m *Map, size int) { +func benchmarkGet(b *testing.B, m *Map[int, int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { m.Get(n) @@ -196,15 +162,15 @@ func benchmarkGet(b *testing.B, m *Map, size int) { } } -func benchmarkPut(b *testing.B, m *Map, size int) { +func benchmarkPut(b *testing.B, m *Map[int, int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } } } -func benchmarkRemove(b *testing.B, m *Map, size int) { +func benchmarkRemove(b *testing.B, m *Map[int, int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { m.Remove(n) @@ -215,9 +181,9 @@ func benchmarkRemove(b *testing.B, m *Map, size int) { func BenchmarkHashMapGet100(b *testing.B) { b.StopTimer() size := 100 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkGet(b, m, size) @@ -226,9 +192,9 @@ func BenchmarkHashMapGet100(b *testing.B) { func BenchmarkHashMapGet1000(b *testing.B) { b.StopTimer() size := 1000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkGet(b, m, size) @@ -237,9 +203,9 @@ func BenchmarkHashMapGet1000(b *testing.B) { func BenchmarkHashMapGet10000(b *testing.B) { b.StopTimer() size := 10000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkGet(b, m, size) @@ -248,9 +214,9 @@ func BenchmarkHashMapGet10000(b *testing.B) { func BenchmarkHashMapGet100000(b *testing.B) { b.StopTimer() size := 100000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkGet(b, m, size) @@ -259,7 +225,7 @@ func BenchmarkHashMapGet100000(b *testing.B) { func BenchmarkHashMapPut100(b *testing.B) { b.StopTimer() size := 100 - m := New() + m := New[int, int]() b.StartTimer() benchmarkPut(b, m, size) } @@ -267,9 +233,9 @@ func BenchmarkHashMapPut100(b *testing.B) { func BenchmarkHashMapPut1000(b *testing.B) { b.StopTimer() size := 1000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkPut(b, m, size) @@ -278,9 +244,9 @@ func BenchmarkHashMapPut1000(b *testing.B) { func BenchmarkHashMapPut10000(b *testing.B) { b.StopTimer() size := 10000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkPut(b, m, size) @@ -289,9 +255,9 @@ func BenchmarkHashMapPut10000(b *testing.B) { func BenchmarkHashMapPut100000(b *testing.B) { b.StopTimer() size := 100000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkPut(b, m, size) @@ -300,9 +266,9 @@ func BenchmarkHashMapPut100000(b *testing.B) { func BenchmarkHashMapRemove100(b *testing.B) { b.StopTimer() size := 100 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkRemove(b, m, size) @@ -311,9 +277,9 @@ func BenchmarkHashMapRemove100(b *testing.B) { func BenchmarkHashMapRemove1000(b *testing.B) { b.StopTimer() size := 1000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkRemove(b, m, size) @@ -322,9 +288,9 @@ func BenchmarkHashMapRemove1000(b *testing.B) { func BenchmarkHashMapRemove10000(b *testing.B) { b.StopTimer() size := 10000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkRemove(b, m, size) @@ -333,9 +299,9 @@ func BenchmarkHashMapRemove10000(b *testing.B) { func BenchmarkHashMapRemove100000(b *testing.B) { b.StopTimer() size := 100000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkRemove(b, m, size) diff --git a/maps/hashmap/serialization.go b/maps/hashmap/serialization.go index a86fd864..f1624998 100644 --- a/maps/hashmap/serialization.go +++ b/maps/hashmap/serialization.go @@ -6,42 +6,30 @@ package hashmap import ( "encoding/json" - "github.com/emirpasic/gods/containers" - "github.com/emirpasic/gods/utils" + + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*Map)(nil) -var _ containers.JSONDeserializer = (*Map)(nil) +var _ containers.JSONSerializer = (*Map[string, int])(nil) +var _ containers.JSONDeserializer = (*Map[string, int])(nil) // ToJSON outputs the JSON representation of the map. -func (m *Map) ToJSON() ([]byte, error) { - elements := make(map[string]interface{}) - for key, value := range m.m { - elements[utils.ToString(key)] = value - } - return json.Marshal(&elements) +func (m *Map[K, V]) ToJSON() ([]byte, error) { + return json.Marshal(m.m) } // FromJSON populates the map from the input JSON representation. -func (m *Map) FromJSON(data []byte) error { - elements := make(map[string]interface{}) - err := json.Unmarshal(data, &elements) - if err == nil { - m.Clear() - for key, value := range elements { - m.m[key] = value - } - } - return err +func (m *Map[K, V]) FromJSON(data []byte) error { + return json.Unmarshal(data, &m.m) } // UnmarshalJSON @implements json.Unmarshaler -func (m *Map) UnmarshalJSON(bytes []byte) error { +func (m *Map[K, V]) UnmarshalJSON(bytes []byte) error { return m.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (m *Map) MarshalJSON() ([]byte, error) { +func (m *Map[K, V]) MarshalJSON() ([]byte, error) { return m.ToJSON() } diff --git a/maps/linkedhashmap/enumerable.go b/maps/linkedhashmap/enumerable.go index eafcaa5d..fc496e72 100644 --- a/maps/linkedhashmap/enumerable.go +++ b/maps/linkedhashmap/enumerable.go @@ -4,13 +4,13 @@ package linkedhashmap -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Assert Enumerable implementation -var _ containers.EnumerableWithKey = (*Map)(nil) +var _ containers.EnumerableWithKey[string, int] = (*Map[string, int])(nil) // Each calls the given function once for each element, passing that element's key and value. -func (m *Map) Each(f func(key interface{}, value interface{})) { +func (m *Map[K, V]) Each(f func(key K, value V)) { iterator := m.Iterator() for iterator.Next() { f(iterator.Key(), iterator.Value()) @@ -19,8 +19,8 @@ func (m *Map) Each(f func(key interface{}, value interface{})) { // 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. -func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) *Map { - newMap := New() +func (m *Map[K, V]) Map(f func(key1 K, value1 V) (K, V)) *Map[K, V] { + newMap := New[K, V]() iterator := m.Iterator() for iterator.Next() { key2, value2 := f(iterator.Key(), iterator.Value()) @@ -30,8 +30,8 @@ func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, int } // Select returns a new container containing all elements for which the given function returns a true value. -func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map { - newMap := New() +func (m *Map[K, V]) Select(f func(key K, value V) bool) *Map[K, V] { + newMap := New[K, V]() iterator := m.Iterator() for iterator.Next() { if f(iterator.Key(), iterator.Value()) { @@ -43,7 +43,7 @@ func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map { // Any passes each element of the container to the given function and // returns true if the function ever returns true for any element. -func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool { +func (m *Map[K, V]) Any(f func(key K, value V) bool) bool { iterator := m.Iterator() for iterator.Next() { if f(iterator.Key(), iterator.Value()) { @@ -55,7 +55,7 @@ func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool { // All passes each element of the container to the given function and // returns true if the function returns true for all elements. -func (m *Map) All(f func(key interface{}, value interface{}) bool) bool { +func (m *Map[K, V]) All(f func(key K, value V) bool) bool { iterator := m.Iterator() for iterator.Next() { if !f(iterator.Key(), iterator.Value()) { @@ -68,12 +68,12 @@ func (m *Map) All(f func(key interface{}, value interface{}) 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. -func (m *Map) Find(f func(key interface{}, value interface{}) bool) (interface{}, interface{}) { +func (m *Map[K, V]) Find(f func(key K, value V) bool) (k K, v V) { iterator := m.Iterator() for iterator.Next() { if f(iterator.Key(), iterator.Value()) { return iterator.Key(), iterator.Value() } } - return nil, nil + return k, v } diff --git a/maps/linkedhashmap/iterator.go b/maps/linkedhashmap/iterator.go index 4c141780..9ac39318 100644 --- a/maps/linkedhashmap/iterator.go +++ b/maps/linkedhashmap/iterator.go @@ -5,77 +5,78 @@ package linkedhashmap import ( - "github.com/emirpasic/gods/containers" - "github.com/emirpasic/gods/lists/doublylinkedlist" + "github.com/emirpasic/gods/v2/containers" + "github.com/emirpasic/gods/v2/lists/doublylinkedlist" ) // Assert Iterator implementation -var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) +var _ containers.ReverseIteratorWithKey[string, int] = (*Iterator[string, int])(nil) // Iterator holding the iterator's state -type Iterator struct { - iterator doublylinkedlist.Iterator - table map[interface{}]interface{} +type Iterator[K comparable, V any] struct { + iterator doublylinkedlist.Iterator[K] + table map[K]V } // Iterator returns a stateful iterator whose elements are key/value pairs. -func (m *Map) Iterator() Iterator { - return Iterator{ +func (m *Map[K, V]) Iterator() *Iterator[K, V] { + return &Iterator[K, V]{ iterator: m.ordering.Iterator(), - table: m.table} + table: m.table, + } } // 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. // Modifies the state of the iterator. -func (iterator *Iterator) Next() bool { +func (iterator *Iterator[K, V]) 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. -func (iterator *Iterator) Prev() bool { +func (iterator *Iterator[K, V]) 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{} { +func (iterator *Iterator[K, V]) Value() V { key := iterator.iterator.Value() return iterator.table[key] } // Key returns the current element's key. // Does not modify the state of the iterator. -func (iterator *Iterator) Key() interface{} { +func (iterator *Iterator[K, V]) Key() K { return iterator.iterator.Value() } // Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. -func (iterator *Iterator) Begin() { +func (iterator *Iterator[K, V]) 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() { +func (iterator *Iterator[K, V]) 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator -func (iterator *Iterator) First() bool { +func (iterator *Iterator[K, V]) 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. -func (iterator *Iterator) Last() bool { +func (iterator *Iterator[K, V]) Last() bool { return iterator.iterator.Last() } @@ -83,7 +84,7 @@ func (iterator *Iterator) Last() bool { // 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. -func (iterator *Iterator) NextTo(f func(key interface{}, value interface{}) bool) bool { +func (iterator *Iterator[K, V]) NextTo(f func(key K, value V) bool) bool { for iterator.Next() { key, value := iterator.Key(), iterator.Value() if f(key, value) { @@ -97,7 +98,7 @@ func (iterator *Iterator) NextTo(f func(key interface{}, value interface{}) bool // 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. -func (iterator *Iterator) PrevTo(f func(key interface{}, value interface{}) bool) bool { +func (iterator *Iterator[K, V]) PrevTo(f func(key K, value V) bool) bool { for iterator.Prev() { key, value := iterator.Key(), iterator.Value() if f(key, value) { diff --git a/maps/linkedhashmap/linkedhashmap.go b/maps/linkedhashmap/linkedhashmap.go index d625b3d7..bf5ef4c3 100644 --- a/maps/linkedhashmap/linkedhashmap.go +++ b/maps/linkedhashmap/linkedhashmap.go @@ -13,31 +13,32 @@ package linkedhashmap import ( "fmt" - "github.com/emirpasic/gods/lists/doublylinkedlist" - "github.com/emirpasic/gods/maps" "strings" + + "github.com/emirpasic/gods/v2/lists/doublylinkedlist" + "github.com/emirpasic/gods/v2/maps" ) // Assert Map implementation -var _ maps.Map = (*Map)(nil) +var _ maps.Map[string, int] = (*Map[string, int])(nil) // Map holds the elements in a regular hash table, and uses doubly-linked list to store key ordering. -type Map struct { - table map[interface{}]interface{} - ordering *doublylinkedlist.List +type Map[K comparable, V any] struct { + table map[K]V + ordering *doublylinkedlist.List[K] } // New instantiates a linked-hash-map. -func New() *Map { - return &Map{ - table: make(map[interface{}]interface{}), - ordering: doublylinkedlist.New(), +func New[K comparable, V any]() *Map[K, V] { + return &Map[K, V]{ + table: make(map[K]V), + ordering: doublylinkedlist.New[K](), } } // Put inserts key-value pair into the map. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (m *Map) Put(key interface{}, value interface{}) { +func (m *Map[K, V]) Put(key K, value V) { if _, contains := m.table[key]; !contains { m.ordering.Append(key) } @@ -47,15 +48,14 @@ func (m *Map) Put(key interface{}, value interface{}) { // Get searches the element in the map by key and returns its value or nil if key is not found in tree. // Second return parameter is true if key was found, otherwise false. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (m *Map) Get(key interface{}) (value interface{}, found bool) { - value = m.table[key] - found = value != nil - return +func (m *Map[K, V]) Get(key K) (value V, found bool) { + value, found = m.table[key] + return value, found } // Remove removes the element from the map by key. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (m *Map) Remove(key interface{}) { +func (m *Map[K, V]) Remove(key K) { if _, contains := m.table[key]; contains { delete(m.table, key) index := m.ordering.IndexOf(key) @@ -64,23 +64,23 @@ func (m *Map) Remove(key interface{}) { } // Empty returns true if map does not contain any elements -func (m *Map) Empty() bool { +func (m *Map[K, V]) Empty() bool { return m.Size() == 0 } // Size returns number of elements in the map. -func (m *Map) Size() int { +func (m *Map[K, V]) Size() int { return m.ordering.Size() } // Keys returns all keys in-order -func (m *Map) Keys() []interface{} { +func (m *Map[K, V]) Keys() []K { return m.ordering.Values() } // Values returns all values in-order based on the key. -func (m *Map) Values() []interface{} { - values := make([]interface{}, m.Size()) +func (m *Map[K, V]) Values() []V { + values := make([]V, m.Size()) count := 0 it := m.Iterator() for it.Next() { @@ -91,13 +91,13 @@ func (m *Map) Values() []interface{} { } // Clear removes all elements from the map. -func (m *Map) Clear() { - m.table = make(map[interface{}]interface{}) +func (m *Map[K, V]) Clear() { + clear(m.table) m.ordering.Clear() } // String returns a string representation of container -func (m *Map) String() string { +func (m *Map[K, V]) String() string { str := "LinkedHashMap\nmap[" it := m.Iterator() for it.Next() { diff --git a/maps/linkedhashmap/linkedhashmap_test.go b/maps/linkedhashmap/linkedhashmap_test.go index ca44792c..a8d597e8 100644 --- a/maps/linkedhashmap/linkedhashmap_test.go +++ b/maps/linkedhashmap/linkedhashmap_test.go @@ -6,13 +6,14 @@ package linkedhashmap import ( "encoding/json" - "fmt" "strings" "testing" + + "github.com/emirpasic/gods/v2/testutils" ) func TestMapPut(t *testing.T) { - m := New() + m := New[int, string]() m.Put(5, "e") m.Put(6, "f") m.Put(7, "g") @@ -25,12 +26,8 @@ func TestMapPut(t *testing.T) { if actualValue := m.Size(); actualValue != 7 { t.Errorf("Got %v expected %v", actualValue, 7) } - if actualValue, expectedValue := m.Keys(), []interface{}{5, 6, 7, 3, 4, 1, 2}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := m.Values(), []interface{}{"e", "f", "g", "c", "d", "a", "b"}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4, 5, 6, 7}) + testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d", "e", "f", "g"}) // key,expectedValue,expectedFound tests1 := [][]interface{}{ @@ -41,12 +38,12 @@ func TestMapPut(t *testing.T) { {5, "e", true}, {6, "f", true}, {7, "g", true}, - {8, nil, false}, + {8, "", false}, } for _, test := range tests1 { // retrievals - actualValue, actualFound := m.Get(test[0]) + actualValue, actualFound := m.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } @@ -54,7 +51,7 @@ func TestMapPut(t *testing.T) { } func TestMapRemove(t *testing.T) { - m := New() + m := New[int, string]() m.Put(5, "e") m.Put(6, "f") m.Put(7, "g") @@ -70,13 +67,9 @@ func TestMapRemove(t *testing.T) { m.Remove(8) m.Remove(5) - if actualValue, expectedValue := m.Keys(), []interface{}{3, 4, 1, 2}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4}) + testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d"}) - if actualValue, expectedValue := m.Values(), []interface{}{"c", "d", "a", "b"}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } if actualValue := m.Size(); actualValue != 4 { t.Errorf("Got %v expected %v", actualValue, 4) } @@ -86,14 +79,14 @@ func TestMapRemove(t *testing.T) { {2, "b", true}, {3, "c", true}, {4, "d", true}, - {5, nil, false}, - {6, nil, false}, - {7, nil, false}, - {8, nil, false}, + {5, "", false}, + {6, "", false}, + {7, "", false}, + {8, "", false}, } for _, test := range tests2 { - actualValue, actualFound := m.Get(test[0]) + actualValue, actualFound := m.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } @@ -106,12 +99,8 @@ func TestMapRemove(t *testing.T) { m.Remove(2) m.Remove(2) - if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, m.Keys(), nil) + testutils.SameElements(t, m.Values(), nil) if actualValue := m.Size(); actualValue != 0 { t.Errorf("Got %v expected %v", actualValue, 0) } @@ -120,32 +109,13 @@ func TestMapRemove(t *testing.T) { } } -func sameElements(a []interface{}, b []interface{}) bool { - // If one is nil, the other must also be nil. - if (a == nil) != (b == nil) { - return false - } - - if len(a) != len(b) { - return false - } - - for i := range a { - if a[i] != b[i] { - return false - } - } - - return true -} - func TestMapEach(t *testing.T) { - m := New() + m := New[string, int]() m.Put("c", 1) m.Put("a", 2) m.Put("b", 3) count := 0 - m.Each(func(key interface{}, value interface{}) { + m.Each(func(key string, value int) { count++ if actualValue, expectedValue := count, value; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -170,12 +140,12 @@ func TestMapEach(t *testing.T) { } func TestMapMap(t *testing.T) { - m := New() + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) - mappedMap := m.Map(func(key1 interface{}, value1 interface{}) (key2 interface{}, value2 interface{}) { - return key1, value1.(int) * value1.(int) + mappedMap := m.Map(func(key1 string, value1 int) (key2 string, value2 int) { + return key1, value1 * value1 }) if actualValue, _ := mappedMap.Get("c"); actualValue != 9 { t.Errorf("Got %v expected %v", actualValue, "mapped: c") @@ -192,12 +162,12 @@ func TestMapMap(t *testing.T) { } func TestMapSelect(t *testing.T) { - m := New() + m := New[string, int]() m.Put("c", 3) m.Put("b", 1) m.Put("a", 2) - selectedMap := m.Select(func(key interface{}, value interface{}) bool { - return key.(string) >= "a" && key.(string) <= "b" + selectedMap := m.Select(func(key string, value int) bool { + return key >= "a" && key <= "b" }) if actualValue, _ := selectedMap.Get("b"); actualValue != 1 { t.Errorf("Got %v expected %v", actualValue, "value: a") @@ -211,18 +181,18 @@ func TestMapSelect(t *testing.T) { } func TestMapAny(t *testing.T) { - m := New() + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) - any := m.Any(func(key interface{}, value interface{}) bool { - return value.(int) == 3 + any := m.Any(func(key string, value int) bool { + return value == 3 }) if any != true { t.Errorf("Got %v expected %v", any, true) } - any = m.Any(func(key interface{}, value interface{}) bool { - return value.(int) == 4 + any = m.Any(func(key string, value int) bool { + return value == 4 }) if any != false { t.Errorf("Got %v expected %v", any, false) @@ -230,18 +200,18 @@ func TestMapAny(t *testing.T) { } func TestMapAll(t *testing.T) { - m := New() + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) - all := m.All(func(key interface{}, value interface{}) bool { - return key.(string) >= "a" && key.(string) <= "c" + all := m.All(func(key string, value int) bool { + return key >= "a" && key <= "c" }) if all != true { t.Errorf("Got %v expected %v", all, true) } - all = m.All(func(key interface{}, value interface{}) bool { - return key.(string) >= "a" && key.(string) <= "b" + all = m.All(func(key string, value int) bool { + return key >= "a" && key <= "b" }) if all != false { t.Errorf("Got %v expected %v", all, false) @@ -249,38 +219,38 @@ func TestMapAll(t *testing.T) { } func TestMapFind(t *testing.T) { - m := New() + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) - foundKey, foundValue := m.Find(func(key interface{}, value interface{}) bool { - return key.(string) == "c" + foundKey, foundValue := m.Find(func(key string, value int) bool { + return key == "c" }) if foundKey != "c" || foundValue != 3 { t.Errorf("Got %v -> %v expected %v -> %v", foundKey, foundValue, "c", 3) } - foundKey, foundValue = m.Find(func(key interface{}, value interface{}) bool { - return key.(string) == "x" + foundKey, foundValue = m.Find(func(key string, value int) bool { + return key == "x" }) - if foundKey != nil || foundValue != nil { - t.Errorf("Got %v at %v expected %v at %v", foundValue, foundKey, nil, nil) + if foundKey != "" || foundValue != 0 { + t.Errorf("Got %v at %v expected %v at %v", foundValue, foundKey, "", 0) } } func TestMapChaining(t *testing.T) { - m := New() + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) - chainedMap := m.Select(func(key interface{}, value interface{}) bool { - return value.(int) > 1 - }).Map(func(key interface{}, value interface{}) (interface{}, interface{}) { - return key.(string) + key.(string), value.(int) * value.(int) + chainedMap := m.Select(func(key string, value int) bool { + return value > 1 + }).Map(func(key string, value int) (string, int) { + return key + key, value * value }) if actualValue := chainedMap.Size(); actualValue != 2 { t.Errorf("Got %v expected %v", actualValue, 2) } - if actualValue, found := chainedMap.Get("aa"); actualValue != nil || found { + if actualValue, found := chainedMap.Get("aa"); actualValue != 0 || found { t.Errorf("Got %v expected %v", actualValue, nil) } if actualValue, found := chainedMap.Get("bb"); actualValue != 4 || !found { @@ -292,7 +262,7 @@ func TestMapChaining(t *testing.T) { } func TestMapIteratorNextOnEmpty(t *testing.T) { - m := New() + m := New[string, int]() it := m.Iterator() it = m.Iterator() for it.Next() { @@ -301,7 +271,7 @@ func TestMapIteratorNextOnEmpty(t *testing.T) { } func TestMapIteratorPrevOnEmpty(t *testing.T) { - m := New() + m := New[string, int]() it := m.Iterator() it = m.Iterator() for it.Prev() { @@ -310,7 +280,7 @@ func TestMapIteratorPrevOnEmpty(t *testing.T) { } func TestMapIteratorNext(t *testing.T) { - m := New() + m := New[string, int]() m.Put("c", 1) m.Put("a", 2) m.Put("b", 3) @@ -347,7 +317,7 @@ func TestMapIteratorNext(t *testing.T) { } func TestMapIteratorPrev(t *testing.T) { - m := New() + m := New[string, int]() m.Put("c", 1) m.Put("a", 2) m.Put("b", 3) @@ -386,7 +356,7 @@ func TestMapIteratorPrev(t *testing.T) { } func TestMapIteratorBegin(t *testing.T) { - m := New() + m := New[int, string]() it := m.Iterator() it.Begin() m.Put(3, "c") @@ -402,7 +372,7 @@ func TestMapIteratorBegin(t *testing.T) { } func TestMapIteratorEnd(t *testing.T) { - m := New() + m := New[int, string]() it := m.Iterator() m.Put(3, "c") m.Put(1, "a") @@ -415,7 +385,7 @@ func TestMapIteratorEnd(t *testing.T) { } func TestMapIteratorFirst(t *testing.T) { - m := New() + m := New[int, string]() m.Put(3, "c") m.Put(1, "a") m.Put(2, "b") @@ -429,7 +399,7 @@ func TestMapIteratorFirst(t *testing.T) { } func TestMapIteratorLast(t *testing.T) { - m := New() + m := New[int, string]() m.Put(3, "c") m.Put(1, "a") m.Put(2, "b") @@ -444,13 +414,13 @@ func TestMapIteratorLast(t *testing.T) { func TestMapIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index interface{}, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // NextTo (empty) { - m := New() + m := New[int, string]() it := m.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty map") @@ -459,7 +429,7 @@ func TestMapIteratorNextTo(t *testing.T) { // NextTo (not found) { - m := New() + m := New[int, string]() m.Put(0, "xx") m.Put(1, "yy") it := m.Iterator() @@ -470,7 +440,7 @@ func TestMapIteratorNextTo(t *testing.T) { // NextTo (found) { - m := New() + m := New[int, string]() m.Put(0, "aa") m.Put(1, "bb") m.Put(2, "cc") @@ -479,13 +449,13 @@ func TestMapIteratorNextTo(t *testing.T) { if !it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty map") } - if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Key(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Next() { t.Errorf("Should go to first element") } - if index, value := it.Key(), it.Value(); index != 2 || value.(string) != "cc" { + if index, value := it.Key(), it.Value(); index != 2 || value != "cc" { t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") } if it.Next() { @@ -496,13 +466,13 @@ func TestMapIteratorNextTo(t *testing.T) { func TestMapIteratorPrevTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index interface{}, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // PrevTo (empty) { - m := New() + m := New[int, string]() it := m.Iterator() it.End() for it.PrevTo(seek) { @@ -512,7 +482,7 @@ func TestMapIteratorPrevTo(t *testing.T) { // PrevTo (not found) { - m := New() + m := New[int, string]() m.Put(0, "xx") m.Put(1, "yy") it := m.Iterator() @@ -524,7 +494,7 @@ func TestMapIteratorPrevTo(t *testing.T) { // PrevTo (found) { - m := New() + m := New[int, string]() m.Put(0, "aa") m.Put(1, "bb") m.Put(2, "cc") @@ -533,13 +503,13 @@ func TestMapIteratorPrevTo(t *testing.T) { if !it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty map") } - if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Key(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Prev() { t.Errorf("Should go to first element") } - if index, value := it.Key(), it.Value(); index != 0 || value.(string) != "aa" { + if index, value := it.Key(), it.Value(); index != 0 || value != "aa" { t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") } if it.Prev() { @@ -550,30 +520,36 @@ func TestMapIteratorPrevTo(t *testing.T) { func TestMapSerialization(t *testing.T) { for i := 0; i < 10; i++ { - original := New() + original := New[string, string]() original.Put("d", "4") original.Put("e", "5") original.Put("c", "3") original.Put("b", "2") original.Put("a", "1") - assertSerialization(original, "A", t) - serialized, err := original.ToJSON() if err != nil { t.Errorf("Got error %v", err) } - assertSerialization(original, "B", t) - deserialized := New() + deserialized := New[string, string]() err = deserialized.FromJSON(serialized) if err != nil { t.Errorf("Got error %v", err) } - assertSerialization(deserialized, "C", t) + + if original.Size() != deserialized.Size() { + t.Errorf("Got map of size %d, expected %d", original.Size(), deserialized.Size()) + } + original.Each(func(key string, expected string) { + actual, ok := deserialized.Get(key) + if !ok || actual != expected { + t.Errorf("Did not find expected value %v for key %v in deserialied map (got %v)", expected, key, actual) + } + }) } - m := New() + m := New[string, float64]() m.Put("a", 1.0) m.Put("b", 2.0) m.Put("c", 3.0) @@ -590,37 +566,14 @@ func TestMapSerialization(t *testing.T) { } func TestMapString(t *testing.T) { - c := New() + c := New[string, int]() c.Put("a", 1) if !strings.HasPrefix(c.String(), "LinkedHashMap") { t.Errorf("String should start with container name") } } -//noinspection GoBoolExpressions -func assertSerialization(m *Map, txt string, t *testing.T) { - if actualValue := m.Keys(); false || - actualValue[0].(string) != "d" || - actualValue[1].(string) != "e" || - actualValue[2].(string) != "c" || - actualValue[3].(string) != "b" || - actualValue[4].(string) != "a" { - t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[d,e,c,b,a]") - } - if actualValue := m.Values(); false || - actualValue[0].(string) != "4" || - actualValue[1].(string) != "5" || - actualValue[2].(string) != "3" || - actualValue[3].(string) != "2" || - actualValue[4].(string) != "1" { - t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[4,5,3,2,1]") - } - if actualValue, expectedValue := m.Size(), 5; actualValue != expectedValue { - t.Errorf("[%s] Got %v expected %v", txt, actualValue, expectedValue) - } -} - -func benchmarkGet(b *testing.B, m *Map, size int) { +func benchmarkGet(b *testing.B, m *Map[int, int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { m.Get(n) @@ -628,15 +581,15 @@ func benchmarkGet(b *testing.B, m *Map, size int) { } } -func benchmarkPut(b *testing.B, m *Map, size int) { +func benchmarkPut(b *testing.B, m *Map[int, int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } } } -func benchmarkRemove(b *testing.B, m *Map, size int) { +func benchmarkRemove(b *testing.B, m *Map[int, int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { m.Remove(n) @@ -647,9 +600,9 @@ func benchmarkRemove(b *testing.B, m *Map, size int) { func BenchmarkTreeMapGet100(b *testing.B) { b.StopTimer() size := 100 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkGet(b, m, size) @@ -658,9 +611,9 @@ func BenchmarkTreeMapGet100(b *testing.B) { func BenchmarkTreeMapGet1000(b *testing.B) { b.StopTimer() size := 1000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkGet(b, m, size) @@ -669,9 +622,9 @@ func BenchmarkTreeMapGet1000(b *testing.B) { func BenchmarkTreeMapGet10000(b *testing.B) { b.StopTimer() size := 10000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkGet(b, m, size) @@ -680,9 +633,9 @@ func BenchmarkTreeMapGet10000(b *testing.B) { func BenchmarkTreeMapGet100000(b *testing.B) { b.StopTimer() size := 100000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkGet(b, m, size) @@ -691,7 +644,7 @@ func BenchmarkTreeMapGet100000(b *testing.B) { func BenchmarkTreeMapPut100(b *testing.B) { b.StopTimer() size := 100 - m := New() + m := New[int, int]() b.StartTimer() benchmarkPut(b, m, size) } @@ -699,9 +652,9 @@ func BenchmarkTreeMapPut100(b *testing.B) { func BenchmarkTreeMapPut1000(b *testing.B) { b.StopTimer() size := 1000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkPut(b, m, size) @@ -710,9 +663,9 @@ func BenchmarkTreeMapPut1000(b *testing.B) { func BenchmarkTreeMapPut10000(b *testing.B) { b.StopTimer() size := 10000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkPut(b, m, size) @@ -721,9 +674,9 @@ func BenchmarkTreeMapPut10000(b *testing.B) { func BenchmarkTreeMapPut100000(b *testing.B) { b.StopTimer() size := 100000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkPut(b, m, size) @@ -732,9 +685,9 @@ func BenchmarkTreeMapPut100000(b *testing.B) { func BenchmarkTreeMapRemove100(b *testing.B) { b.StopTimer() size := 100 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkRemove(b, m, size) @@ -743,9 +696,9 @@ func BenchmarkTreeMapRemove100(b *testing.B) { func BenchmarkTreeMapRemove1000(b *testing.B) { b.StopTimer() size := 1000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkRemove(b, m, size) @@ -754,9 +707,9 @@ func BenchmarkTreeMapRemove1000(b *testing.B) { func BenchmarkTreeMapRemove10000(b *testing.B) { b.StopTimer() size := 10000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkRemove(b, m, size) @@ -765,9 +718,9 @@ func BenchmarkTreeMapRemove10000(b *testing.B) { func BenchmarkTreeMapRemove100000(b *testing.B) { b.StopTimer() size := 100000 - m := New() + m := New[int, int]() for n := 0; n < size; n++ { - m.Put(n, struct{}{}) + m.Put(n, n) } b.StartTimer() benchmarkRemove(b, m, size) diff --git a/maps/linkedhashmap/serialization.go b/maps/linkedhashmap/serialization.go index 9265f1db..6a83df95 100644 --- a/maps/linkedhashmap/serialization.go +++ b/maps/linkedhashmap/serialization.go @@ -6,17 +6,19 @@ package linkedhashmap import ( "bytes" + "cmp" "encoding/json" - "github.com/emirpasic/gods/containers" - "github.com/emirpasic/gods/utils" + "slices" + + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*Map)(nil) -var _ containers.JSONDeserializer = (*Map)(nil) +var _ containers.JSONSerializer = (*Map[string, int])(nil) +var _ containers.JSONDeserializer = (*Map[string, int])(nil) // ToJSON outputs the JSON representation of map. -func (m *Map) ToJSON() ([]byte, error) { +func (m *Map[K, V]) ToJSON() ([]byte, error) { var b []byte buf := bytes.NewBuffer(b) @@ -54,7 +56,7 @@ func (m *Map) ToJSON() ([]byte, error) { } // FromJSON populates map from the input JSON representation. -//func (m *Map) FromJSON(data []byte) error { +//func (m *Map[K, V]) FromJSON(data []byte) error { // elements := make(map[string]interface{}) // err := json.Unmarshal(data, &elements) // if err == nil { @@ -67,46 +69,42 @@ func (m *Map) ToJSON() ([]byte, error) { //} // FromJSON populates map from the input JSON representation. -func (m *Map) FromJSON(data []byte) error { - elements := make(map[string]interface{}) +func (m *Map[K, V]) FromJSON(data []byte) error { + elements := make(map[K]V) err := json.Unmarshal(data, &elements) if err != nil { return err } - index := make(map[string]int) - var keys []interface{} + index := make(map[K]int) + var keys []K for key := range elements { keys = append(keys, key) esc, _ := json.Marshal(key) index[key] = bytes.Index(data, esc) } - byIndex := func(a, b interface{}) int { - key1 := a.(string) - key2 := b.(string) - index1 := index[key1] - index2 := index[key2] - return index1 - index2 + byIndex := func(key1, key2 K) int { + return cmp.Compare(index[key1], index[key2]) } - utils.Sort(keys, byIndex) + slices.SortFunc(keys, byIndex) m.Clear() for _, key := range keys { - m.Put(key, elements[key.(string)]) + m.Put(key, elements[key]) } return nil } // UnmarshalJSON @implements json.Unmarshaler -func (m *Map) UnmarshalJSON(bytes []byte) error { +func (m *Map[K, V]) UnmarshalJSON(bytes []byte) error { return m.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (m *Map) MarshalJSON() ([]byte, error) { +func (m *Map[K, V]) MarshalJSON() ([]byte, error) { return m.ToJSON() } diff --git a/maps/maps.go b/maps/maps.go index cdce9f7b..b54f7dc5 100644 --- a/maps/maps.go +++ b/maps/maps.go @@ -15,16 +15,16 @@ // Reference: https://en.wikipedia.org/wiki/Associative_array package maps -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Map interface that all maps implement -type Map interface { - Put(key interface{}, value interface{}) - Get(key interface{}) (value interface{}, found bool) - Remove(key interface{}) - Keys() []interface{} +type Map[K comparable, V any] interface { + Put(key K, value V) + Get(key K) (value V, found bool) + Remove(key K) + Keys() []K - containers.Container + containers.Container[V] // Empty() bool // Size() int // Clear() @@ -33,8 +33,8 @@ type Map interface { } // BidiMap interface that all bidirectional maps implement (extends the Map interface) -type BidiMap interface { - GetKey(value interface{}) (key interface{}, found bool) +type BidiMap[K comparable, V comparable] interface { + GetKey(value V) (key K, found bool) - Map + Map[K, V] } diff --git a/maps/treebidimap/enumerable.go b/maps/treebidimap/enumerable.go index 8daef722..febeff46 100644 --- a/maps/treebidimap/enumerable.go +++ b/maps/treebidimap/enumerable.go @@ -4,13 +4,13 @@ package treebidimap -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Assert Enumerable implementation -var _ containers.EnumerableWithKey = (*Map)(nil) +var _ containers.EnumerableWithKey[string, int] = (*Map[string, int])(nil) // Each calls the given function once for each element, passing that element's key and value. -func (m *Map) Each(f func(key interface{}, value interface{})) { +func (m *Map[K, V]) Each(f func(key K, value V)) { iterator := m.Iterator() for iterator.Next() { f(iterator.Key(), iterator.Value()) @@ -19,8 +19,8 @@ func (m *Map) Each(f func(key interface{}, value interface{})) { // 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. -func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) *Map { - newMap := NewWith(m.keyComparator, m.valueComparator) +func (m *Map[K, V]) Map(f func(key1 K, value1 V) (K, V)) *Map[K, V] { + newMap := NewWith[K, V](m.forwardMap.Comparator, m.inverseMap.Comparator) iterator := m.Iterator() for iterator.Next() { key2, value2 := f(iterator.Key(), iterator.Value()) @@ -30,8 +30,8 @@ func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, int } // Select returns a new container containing all elements for which the given function returns a true value. -func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map { - newMap := NewWith(m.keyComparator, m.valueComparator) +func (m *Map[K, V]) Select(f func(key K, value V) bool) *Map[K, V] { + newMap := NewWith[K, V](m.forwardMap.Comparator, m.inverseMap.Comparator) iterator := m.Iterator() for iterator.Next() { if f(iterator.Key(), iterator.Value()) { @@ -43,7 +43,7 @@ func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map { // Any passes each element of the container to the given function and // returns true if the function ever returns true for any element. -func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool { +func (m *Map[K, V]) Any(f func(key K, value V) bool) bool { iterator := m.Iterator() for iterator.Next() { if f(iterator.Key(), iterator.Value()) { @@ -55,7 +55,7 @@ func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool { // All passes each element of the container to the given function and // returns true if the function returns true for all elements. -func (m *Map) All(f func(key interface{}, value interface{}) bool) bool { +func (m *Map[K, V]) All(f func(key K, value V) bool) bool { iterator := m.Iterator() for iterator.Next() { if !f(iterator.Key(), iterator.Value()) { @@ -68,12 +68,12 @@ func (m *Map) All(f func(key interface{}, value interface{}) 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. -func (m *Map) Find(f func(key interface{}, value interface{}) bool) (interface{}, interface{}) { +func (m *Map[K, V]) Find(f func(key K, value V) bool) (k K, v V) { iterator := m.Iterator() for iterator.Next() { if f(iterator.Key(), iterator.Value()) { return iterator.Key(), iterator.Value() } } - return nil, nil + return k, v } diff --git a/maps/treebidimap/iterator.go b/maps/treebidimap/iterator.go index 9961a110..bf86ea71 100644 --- a/maps/treebidimap/iterator.go +++ b/maps/treebidimap/iterator.go @@ -5,73 +5,73 @@ package treebidimap import ( - "github.com/emirpasic/gods/containers" - rbt "github.com/emirpasic/gods/trees/redblacktree" + "github.com/emirpasic/gods/v2/containers" + rbt "github.com/emirpasic/gods/v2/trees/redblacktree" ) // Assert Iterator implementation -var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) +var _ containers.ReverseIteratorWithKey[string, int] = (*Iterator[string, int])(nil) // Iterator holding the iterator's state -type Iterator struct { - iterator rbt.Iterator +type Iterator[K comparable, V any] struct { + iterator *rbt.Iterator[K, V] } // Iterator returns a stateful iterator whose elements are key/value pairs. -func (m *Map) Iterator() Iterator { - return Iterator{iterator: m.forwardMap.Iterator()} +func (m *Map[K, V]) Iterator() *Iterator[K, V] { + return &Iterator[K, V]{iterator: m.forwardMap.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 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. // Modifies the state of the iterator. -func (iterator *Iterator) Next() bool { +func (iterator *Iterator[K, V]) 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. -func (iterator *Iterator) Prev() bool { +func (iterator *Iterator[K, V]) 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().(*data).value +func (iterator *Iterator[K, V]) Value() V { + return iterator.iterator.Value() } // Key returns the current element's key. // Does not modify the state of the iterator. -func (iterator *Iterator) Key() interface{} { +func (iterator *Iterator[K, V]) Key() K { return iterator.iterator.Key() } // Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. -func (iterator *Iterator) Begin() { +func (iterator *Iterator[K, V]) 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() { +func (iterator *Iterator[K, V]) 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator -func (iterator *Iterator) First() bool { +func (iterator *Iterator[K, V]) 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. -func (iterator *Iterator) Last() bool { +func (iterator *Iterator[K, V]) Last() bool { return iterator.iterator.Last() } @@ -79,7 +79,7 @@ func (iterator *Iterator) Last() bool { // 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. -func (iterator *Iterator) NextTo(f func(key interface{}, value interface{}) bool) bool { +func (iterator *Iterator[K, V]) NextTo(f func(key K, value V) bool) bool { for iterator.Next() { key, value := iterator.Key(), iterator.Value() if f(key, value) { @@ -93,7 +93,7 @@ func (iterator *Iterator) NextTo(f func(key interface{}, value interface{}) bool // 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. -func (iterator *Iterator) PrevTo(f func(key interface{}, value interface{}) bool) bool { +func (iterator *Iterator[K, V]) PrevTo(f func(key K, value V) bool) bool { for iterator.Prev() { key, value := iterator.Key(), iterator.Value() if f(key, value) { diff --git a/maps/treebidimap/serialization.go b/maps/treebidimap/serialization.go index 2cccce64..b72907b9 100644 --- a/maps/treebidimap/serialization.go +++ b/maps/treebidimap/serialization.go @@ -6,43 +6,41 @@ package treebidimap import ( "encoding/json" - "github.com/emirpasic/gods/containers" - "github.com/emirpasic/gods/utils" + + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*Map)(nil) -var _ containers.JSONDeserializer = (*Map)(nil) +var _ containers.JSONSerializer = (*Map[string, int])(nil) +var _ containers.JSONDeserializer = (*Map[string, int])(nil) // ToJSON outputs the JSON representation of the map. -func (m *Map) ToJSON() ([]byte, error) { - elements := make(map[string]interface{}) - it := m.Iterator() - for it.Next() { - elements[utils.ToString(it.Key())] = it.Value() - } - return json.Marshal(&elements) +func (m *Map[K, V]) ToJSON() ([]byte, error) { + return m.forwardMap.ToJSON() } // FromJSON populates the map from the input JSON representation. -func (m *Map) FromJSON(data []byte) error { - elements := make(map[string]interface{}) +func (m *Map[K, V]) FromJSON(data []byte) error { + var elements map[K]V err := json.Unmarshal(data, &elements) - if err == nil { - m.Clear() - for key, value := range elements { - m.Put(key, value) - } + if err != nil { + return err } - return err + + m.Clear() + for key, value := range elements { + m.Put(key, value) + } + + return nil } // UnmarshalJSON @implements json.Unmarshaler -func (m *Map) UnmarshalJSON(bytes []byte) error { +func (m *Map[K, V]) UnmarshalJSON(bytes []byte) error { return m.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (m *Map) MarshalJSON() ([]byte, error) { +func (m *Map[K, V]) MarshalJSON() ([]byte, error) { return m.ToJSON() } diff --git a/maps/treebidimap/treebidimap.go b/maps/treebidimap/treebidimap.go index 37af07e0..27d6c9ef 100644 --- a/maps/treebidimap/treebidimap.go +++ b/maps/treebidimap/treebidimap.go @@ -18,116 +18,101 @@ package treebidimap import ( + "cmp" "fmt" - "github.com/emirpasic/gods/maps" - "github.com/emirpasic/gods/trees/redblacktree" - "github.com/emirpasic/gods/utils" + "strings" + + "github.com/emirpasic/gods/v2/maps" + "github.com/emirpasic/gods/v2/trees/redblacktree" + "github.com/emirpasic/gods/v2/utils" ) // Assert Map implementation -var _ maps.BidiMap = (*Map)(nil) +var _ maps.BidiMap[string, int] = (*Map[string, int])(nil) // Map holds the elements in two red-black trees. -type Map struct { - forwardMap redblacktree.Tree - inverseMap redblacktree.Tree - keyComparator utils.Comparator - valueComparator utils.Comparator +type Map[K, V comparable] struct { + forwardMap redblacktree.Tree[K, V] + inverseMap redblacktree.Tree[V, K] } -type data struct { - key interface{} - value interface{} +// New instantiates a bidirectional map. +func New[K, V cmp.Ordered]() *Map[K, V] { + return &Map[K, V]{ + forwardMap: *redblacktree.New[K, V](), + inverseMap: *redblacktree.New[V, K](), + } } // NewWith instantiates a bidirectional map. -func NewWith(keyComparator utils.Comparator, valueComparator utils.Comparator) *Map { - return &Map{ - forwardMap: *redblacktree.NewWith(keyComparator), - inverseMap: *redblacktree.NewWith(valueComparator), - keyComparator: keyComparator, - valueComparator: valueComparator, +func NewWith[K, V comparable](keyComparator utils.Comparator[K], valueComparator utils.Comparator[V]) *Map[K, V] { + return &Map[K, V]{ + forwardMap: *redblacktree.NewWith[K, V](keyComparator), + inverseMap: *redblacktree.NewWith[V, K](valueComparator), } } -// NewWithIntComparators instantiates a bidirectional map with the IntComparator for key and value, i.e. keys and values are of type int. -func NewWithIntComparators() *Map { - return NewWith(utils.IntComparator, utils.IntComparator) -} - -// NewWithStringComparators instantiates a bidirectional map with the StringComparator for key and value, i.e. keys and values are of type string. -func NewWithStringComparators() *Map { - return NewWith(utils.StringComparator, utils.StringComparator) -} - // Put inserts element into the map. -func (m *Map) Put(key interface{}, value interface{}) { - if d, ok := m.forwardMap.Get(key); ok { - m.inverseMap.Remove(d.(*data).value) +func (m *Map[K, V]) Put(key K, value V) { + if v, ok := m.forwardMap.Get(key); ok { + m.inverseMap.Remove(v) } - if d, ok := m.inverseMap.Get(value); ok { - m.forwardMap.Remove(d.(*data).key) + if k, ok := m.inverseMap.Get(value); ok { + m.forwardMap.Remove(k) } - d := &data{key: key, value: value} - m.forwardMap.Put(key, d) - m.inverseMap.Put(value, d) + m.forwardMap.Put(key, value) + m.inverseMap.Put(value, key) } // Get searches the element in the map by key and returns its value or nil if key is not found in map. // Second return parameter is true if key was found, otherwise false. -func (m *Map) Get(key interface{}) (value interface{}, found bool) { - if d, ok := m.forwardMap.Get(key); ok { - return d.(*data).value, true - } - return nil, false +func (m *Map[K, V]) Get(key K) (value V, found bool) { + return m.forwardMap.Get(key) } // GetKey searches the element in the map by value and returns its key or nil if value is not found in map. // Second return parameter is true if value was found, otherwise false. -func (m *Map) GetKey(value interface{}) (key interface{}, found bool) { - if d, ok := m.inverseMap.Get(value); ok { - return d.(*data).key, true - } - return nil, false +func (m *Map[K, V]) GetKey(value V) (key K, found bool) { + return m.inverseMap.Get(value) } // Remove removes the element from the map by key. -func (m *Map) Remove(key interface{}) { - if d, found := m.forwardMap.Get(key); found { +func (m *Map[K, V]) Remove(key K) { + if v, found := m.forwardMap.Get(key); found { m.forwardMap.Remove(key) - m.inverseMap.Remove(d.(*data).value) + m.inverseMap.Remove(v) } } // Empty returns true if map does not contain any elements -func (m *Map) Empty() bool { +func (m *Map[K, V]) Empty() bool { return m.Size() == 0 } // Size returns number of elements in the map. -func (m *Map) Size() int { +func (m *Map[K, V]) Size() int { return m.forwardMap.Size() } // Keys returns all keys (ordered). -func (m *Map) Keys() []interface{} { +func (m *Map[K, V]) Keys() []K { return m.forwardMap.Keys() } // Values returns all values (ordered). -func (m *Map) Values() []interface{} { +func (m *Map[K, V]) Values() []V { return m.inverseMap.Keys() } // Clear removes all elements from the map. -func (m *Map) Clear() { +func (m *Map[K, V]) Clear() { m.forwardMap.Clear() m.inverseMap.Clear() } // String returns a string representation of container -func (m *Map) String() string { +func (m *Map[K, V]) String() string { str := "TreeBidiMap\nmap[" it := m.Iterator() for it.Next() { diff --git a/maps/treebidimap/treebidimap_test.go b/maps/treebidimap/treebidimap_test.go index 75296e80..8c579ca6 100644 --- a/maps/treebidimap/treebidimap_test.go +++ b/maps/treebidimap/treebidimap_test.go @@ -6,14 +6,14 @@ package treebidimap import ( "encoding/json" - "fmt" - "github.com/emirpasic/gods/utils" "strings" "testing" + + "github.com/emirpasic/gods/v2/testutils" ) func TestMapPut(t *testing.T) { - m := NewWith(utils.IntComparator, utils.StringComparator) + m := New[int, string]() m.Put(5, "e") m.Put(6, "f") m.Put(7, "g") @@ -26,12 +26,8 @@ func TestMapPut(t *testing.T) { if actualValue := m.Size(); actualValue != 7 { t.Errorf("Got %v expected %v", actualValue, 7) } - if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "e", "f", "g"}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4, 5, 6, 7}) + testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d", "e", "f", "g"}) // key,expectedValue,expectedFound tests1 := [][]interface{}{ @@ -42,12 +38,12 @@ func TestMapPut(t *testing.T) { {5, "e", true}, {6, "f", true}, {7, "g", true}, - {8, nil, false}, + {8, "", false}, } for _, test := range tests1 { // retrievals - actualValue, actualFound := m.Get(test[0]) + actualValue, actualFound := m.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } @@ -55,7 +51,7 @@ func TestMapPut(t *testing.T) { } func TestMapRemove(t *testing.T) { - m := NewWith(utils.IntComparator, utils.StringComparator) + m := New[int, string]() m.Put(5, "e") m.Put(6, "f") m.Put(7, "g") @@ -71,13 +67,9 @@ func TestMapRemove(t *testing.T) { m.Remove(8) m.Remove(5) - if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4}) + testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d"}) - if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d"}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } if actualValue := m.Size(); actualValue != 4 { t.Errorf("Got %v expected %v", actualValue, 4) } @@ -87,14 +79,14 @@ func TestMapRemove(t *testing.T) { {2, "b", true}, {3, "c", true}, {4, "d", true}, - {5, nil, false}, - {6, nil, false}, - {7, nil, false}, - {8, nil, false}, + {5, "", false}, + {6, "", false}, + {7, "", false}, + {8, "", false}, } for _, test := range tests2 { - actualValue, actualFound := m.Get(test[0]) + actualValue, actualFound := m.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } @@ -107,12 +99,8 @@ func TestMapRemove(t *testing.T) { m.Remove(2) m.Remove(2) - if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, m.Keys(), nil) + testutils.SameElements(t, m.Values(), nil) if actualValue := m.Size(); actualValue != 0 { t.Errorf("Got %v expected %v", actualValue, 0) } @@ -122,7 +110,7 @@ func TestMapRemove(t *testing.T) { } func TestMapGetKey(t *testing.T) { - m := NewWith(utils.IntComparator, utils.StringComparator) + m := New[int, string]() m.Put(5, "e") m.Put(6, "f") m.Put(7, "g") @@ -141,12 +129,12 @@ func TestMapGetKey(t *testing.T) { {5, "e", true}, {6, "f", true}, {7, "g", true}, - {nil, "x", false}, + {0, "x", false}, } for _, test := range tests1 { // retrievals - actualValue, actualFound := m.GetKey(test[1]) + actualValue, actualFound := m.GetKey(test[1].(string)) if actualValue != test[0] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[0]) } @@ -173,12 +161,12 @@ func sameElements(a []interface{}, b []interface{}) bool { } func TestMapEach(t *testing.T) { - m := NewWith(utils.StringComparator, utils.IntComparator) + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) count := 0 - m.Each(func(key interface{}, value interface{}) { + m.Each(func(key string, value int) { count++ if actualValue, expectedValue := count, value; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -203,12 +191,12 @@ func TestMapEach(t *testing.T) { } func TestMapMap(t *testing.T) { - m := NewWith(utils.StringComparator, utils.IntComparator) + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) - mappedMap := m.Map(func(key1 interface{}, value1 interface{}) (key2 interface{}, value2 interface{}) { - return key1, value1.(int) * value1.(int) + mappedMap := m.Map(func(key1 string, value1 int) (key2 string, value2 int) { + return key1, value1 * value1 }) if actualValue, _ := mappedMap.Get("a"); actualValue != 1 { t.Errorf("Got %v expected %v", actualValue, "mapped: a") @@ -225,12 +213,12 @@ func TestMapMap(t *testing.T) { } func TestMapSelect(t *testing.T) { - m := NewWith(utils.StringComparator, utils.IntComparator) + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) - selectedMap := m.Select(func(key interface{}, value interface{}) bool { - return key.(string) >= "a" && key.(string) <= "b" + selectedMap := m.Select(func(key string, value int) bool { + return key >= "a" && key <= "b" }) if actualValue, _ := selectedMap.Get("a"); actualValue != 1 { t.Errorf("Got %v expected %v", actualValue, "value: a") @@ -244,18 +232,18 @@ func TestMapSelect(t *testing.T) { } func TestMapAny(t *testing.T) { - m := NewWith(utils.StringComparator, utils.IntComparator) + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) - any := m.Any(func(key interface{}, value interface{}) bool { - return value.(int) == 3 + any := m.Any(func(key string, value int) bool { + return value == 3 }) if any != true { t.Errorf("Got %v expected %v", any, true) } - any = m.Any(func(key interface{}, value interface{}) bool { - return value.(int) == 4 + any = m.Any(func(key string, value int) bool { + return value == 4 }) if any != false { t.Errorf("Got %v expected %v", any, false) @@ -263,18 +251,18 @@ func TestMapAny(t *testing.T) { } func TestMapAll(t *testing.T) { - m := NewWith(utils.StringComparator, utils.IntComparator) + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) - all := m.All(func(key interface{}, value interface{}) bool { - return key.(string) >= "a" && key.(string) <= "c" + all := m.All(func(key string, value int) bool { + return key >= "a" && key <= "c" }) if all != true { t.Errorf("Got %v expected %v", all, true) } - all = m.All(func(key interface{}, value interface{}) bool { - return key.(string) >= "a" && key.(string) <= "b" + all = m.All(func(key string, value int) bool { + return key >= "a" && key <= "b" }) if all != false { t.Errorf("Got %v expected %v", all, false) @@ -282,38 +270,38 @@ func TestMapAll(t *testing.T) { } func TestMapFind(t *testing.T) { - m := NewWith(utils.StringComparator, utils.IntComparator) + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) - foundKey, foundValue := m.Find(func(key interface{}, value interface{}) bool { - return key.(string) == "c" + foundKey, foundValue := m.Find(func(key string, value int) bool { + return key == "c" }) if foundKey != "c" || foundValue != 3 { t.Errorf("Got %v -> %v expected %v -> %v", foundKey, foundValue, "c", 3) } - foundKey, foundValue = m.Find(func(key interface{}, value interface{}) bool { - return key.(string) == "x" + foundKey, foundValue = m.Find(func(key string, value int) bool { + return key == "x" }) - if foundKey != nil || foundValue != nil { + if foundKey != "" || foundValue != 0 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundKey, nil, nil) } } func TestMapChaining(t *testing.T) { - m := NewWith(utils.StringComparator, utils.IntComparator) + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) - chainedMap := m.Select(func(key interface{}, value interface{}) bool { - return value.(int) > 1 - }).Map(func(key interface{}, value interface{}) (interface{}, interface{}) { - return key.(string) + key.(string), value.(int) * value.(int) + chainedMap := m.Select(func(key string, value int) bool { + return value > 1 + }).Map(func(key string, value int) (string, int) { + return key + key, value * value }) if actualValue := chainedMap.Size(); actualValue != 2 { t.Errorf("Got %v expected %v", actualValue, 2) } - if actualValue, found := chainedMap.Get("aa"); actualValue != nil || found { + if actualValue, found := chainedMap.Get("aa"); actualValue != 0 || found { t.Errorf("Got %v expected %v", actualValue, nil) } if actualValue, found := chainedMap.Get("bb"); actualValue != 4 || !found { @@ -325,7 +313,7 @@ func TestMapChaining(t *testing.T) { } func TestMapIteratorNextOnEmpty(t *testing.T) { - m := NewWithStringComparators() + m := New[string, string]() it := m.Iterator() it = m.Iterator() for it.Next() { @@ -334,7 +322,7 @@ func TestMapIteratorNextOnEmpty(t *testing.T) { } func TestMapIteratorPrevOnEmpty(t *testing.T) { - m := NewWithStringComparators() + m := New[string, string]() it := m.Iterator() it = m.Iterator() for it.Prev() { @@ -343,7 +331,7 @@ func TestMapIteratorPrevOnEmpty(t *testing.T) { } func TestMapIteratorNext(t *testing.T) { - m := NewWith(utils.StringComparator, utils.IntComparator) + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) @@ -380,7 +368,7 @@ func TestMapIteratorNext(t *testing.T) { } func TestMapIteratorPrev(t *testing.T) { - m := NewWith(utils.StringComparator, utils.IntComparator) + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) @@ -419,7 +407,7 @@ func TestMapIteratorPrev(t *testing.T) { } func TestMapIteratorBegin(t *testing.T) { - m := NewWith(utils.IntComparator, utils.StringComparator) + m := New[int, string]() it := m.Iterator() it.Begin() m.Put(3, "c") @@ -435,7 +423,7 @@ func TestMapIteratorBegin(t *testing.T) { } func TestMapIteratorEnd(t *testing.T) { - m := NewWith(utils.IntComparator, utils.StringComparator) + m := New[int, string]() it := m.Iterator() m.Put(3, "c") m.Put(1, "a") @@ -448,7 +436,7 @@ func TestMapIteratorEnd(t *testing.T) { } func TestMapIteratorFirst(t *testing.T) { - m := NewWith(utils.IntComparator, utils.StringComparator) + m := New[int, string]() m.Put(3, "c") m.Put(1, "a") m.Put(2, "b") @@ -462,7 +450,7 @@ func TestMapIteratorFirst(t *testing.T) { } func TestMapIteratorLast(t *testing.T) { - m := NewWith(utils.IntComparator, utils.StringComparator) + m := New[int, string]() m.Put(3, "c") m.Put(1, "a") m.Put(2, "b") @@ -477,13 +465,13 @@ func TestMapIteratorLast(t *testing.T) { func TestMapIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index interface{}, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // NextTo (empty) { - m := NewWith(utils.IntComparator, utils.StringComparator) + m := New[int, string]() it := m.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty map") @@ -492,7 +480,7 @@ func TestMapIteratorNextTo(t *testing.T) { // NextTo (not found) { - m := NewWith(utils.IntComparator, utils.StringComparator) + m := New[int, string]() m.Put(0, "xx") m.Put(1, "yy") it := m.Iterator() @@ -503,7 +491,7 @@ func TestMapIteratorNextTo(t *testing.T) { // NextTo (found) { - m := NewWith(utils.IntComparator, utils.StringComparator) + m := New[int, string]() m.Put(0, "aa") m.Put(1, "bb") m.Put(2, "cc") @@ -512,13 +500,13 @@ func TestMapIteratorNextTo(t *testing.T) { if !it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty map") } - if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Key(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Next() { t.Errorf("Should go to first element") } - if index, value := it.Key(), it.Value(); index != 2 || value.(string) != "cc" { + if index, value := it.Key(), it.Value(); index != 2 || value != "cc" { t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") } if it.Next() { @@ -529,13 +517,13 @@ func TestMapIteratorNextTo(t *testing.T) { func TestMapIteratorPrevTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index interface{}, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // PrevTo (empty) { - m := NewWith(utils.IntComparator, utils.StringComparator) + m := New[int, string]() it := m.Iterator() it.End() for it.PrevTo(seek) { @@ -545,7 +533,7 @@ func TestMapIteratorPrevTo(t *testing.T) { // PrevTo (not found) { - m := NewWith(utils.IntComparator, utils.StringComparator) + m := New[int, string]() m.Put(0, "xx") m.Put(1, "yy") it := m.Iterator() @@ -557,7 +545,7 @@ func TestMapIteratorPrevTo(t *testing.T) { // PrevTo (found) { - m := NewWith(utils.IntComparator, utils.StringComparator) + m := New[int, string]() m.Put(0, "aa") m.Put(1, "bb") m.Put(2, "cc") @@ -566,13 +554,13 @@ func TestMapIteratorPrevTo(t *testing.T) { if !it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty map") } - if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Key(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Prev() { t.Errorf("Should go to first element") } - if index, value := it.Key(), it.Value(); index != 0 || value.(string) != "aa" { + if index, value := it.Key(), it.Value(); index != 0 || value != "aa" { t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") } if it.Prev() { @@ -583,30 +571,36 @@ func TestMapIteratorPrevTo(t *testing.T) { func TestMapSerialization(t *testing.T) { for i := 0; i < 10; i++ { - original := NewWith(utils.StringComparator, utils.StringComparator) + original := New[string, string]() original.Put("d", "4") original.Put("e", "5") original.Put("c", "3") original.Put("b", "2") original.Put("a", "1") - assertSerialization(original, "A", t) - serialized, err := original.ToJSON() if err != nil { t.Errorf("Got error %v", err) } - assertSerialization(original, "B", t) - deserialized := NewWith(utils.StringComparator, utils.StringComparator) + deserialized := New[string, string]() err = deserialized.FromJSON(serialized) if err != nil { t.Errorf("Got error %v", err) } - assertSerialization(deserialized, "C", t) + + if original.Size() != deserialized.Size() { + t.Errorf("Got map of size %d, expected %d", original.Size(), deserialized.Size()) + } + original.Each(func(key string, expected string) { + actual, ok := deserialized.Get(key) + if !ok || actual != expected { + t.Errorf("Did not find expected value %v for key %v in deserialied map (got %q)", expected, key, actual) + } + }) } - m := NewWith(utils.StringComparator, utils.Float64Comparator) + m := New[string, float64]() m.Put("a", 1.0) m.Put("b", 2.0) m.Put("c", 3.0) @@ -623,37 +617,14 @@ func TestMapSerialization(t *testing.T) { } func TestMapString(t *testing.T) { - c := NewWithStringComparators() + c := New[string, string]() c.Put("a", "a") if !strings.HasPrefix(c.String(), "TreeBidiMap") { t.Errorf("String should start with container name") } } -//noinspection GoBoolExpressions -func assertSerialization(m *Map, txt string, t *testing.T) { - if actualValue := m.Keys(); false || - actualValue[0].(string) != "a" || - actualValue[1].(string) != "b" || - actualValue[2].(string) != "c" || - actualValue[3].(string) != "d" || - actualValue[4].(string) != "e" { - t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[a,b,c,d,e]") - } - if actualValue := m.Values(); false || - actualValue[0].(string) != "1" || - actualValue[1].(string) != "2" || - actualValue[2].(string) != "3" || - actualValue[3].(string) != "4" || - actualValue[4].(string) != "5" { - t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[1,2,3,4,5]") - } - if actualValue, expectedValue := m.Size(), 5; actualValue != expectedValue { - t.Errorf("[%s] Got %v expected %v", txt, actualValue, expectedValue) - } -} - -func benchmarkGet(b *testing.B, m *Map, size int) { +func benchmarkGet(b *testing.B, m *Map[int, int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { m.Get(n) @@ -661,7 +632,7 @@ func benchmarkGet(b *testing.B, m *Map, size int) { } } -func benchmarkPut(b *testing.B, m *Map, size int) { +func benchmarkPut(b *testing.B, m *Map[int, int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { m.Put(n, n) @@ -669,7 +640,7 @@ func benchmarkPut(b *testing.B, m *Map, size int) { } } -func benchmarkRemove(b *testing.B, m *Map, size int) { +func benchmarkRemove(b *testing.B, m *Map[int, int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { m.Remove(n) @@ -680,7 +651,7 @@ func benchmarkRemove(b *testing.B, m *Map, size int) { func BenchmarkTreeBidiMapGet100(b *testing.B) { b.StopTimer() size := 100 - m := NewWithIntComparators() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -691,7 +662,7 @@ func BenchmarkTreeBidiMapGet100(b *testing.B) { func BenchmarkTreeBidiMapGet1000(b *testing.B) { b.StopTimer() size := 1000 - m := NewWithIntComparators() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -702,7 +673,7 @@ func BenchmarkTreeBidiMapGet1000(b *testing.B) { func BenchmarkTreeBidiMapGet10000(b *testing.B) { b.StopTimer() size := 10000 - m := NewWithIntComparators() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -713,7 +684,7 @@ func BenchmarkTreeBidiMapGet10000(b *testing.B) { func BenchmarkTreeBidiMapGet100000(b *testing.B) { b.StopTimer() size := 100000 - m := NewWithIntComparators() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -724,7 +695,7 @@ func BenchmarkTreeBidiMapGet100000(b *testing.B) { func BenchmarkTreeBidiMapPut100(b *testing.B) { b.StopTimer() size := 100 - m := NewWithIntComparators() + m := New[int, int]() b.StartTimer() benchmarkPut(b, m, size) } @@ -732,7 +703,7 @@ func BenchmarkTreeBidiMapPut100(b *testing.B) { func BenchmarkTreeBidiMapPut1000(b *testing.B) { b.StopTimer() size := 1000 - m := NewWithIntComparators() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -743,7 +714,7 @@ func BenchmarkTreeBidiMapPut1000(b *testing.B) { func BenchmarkTreeBidiMapPut10000(b *testing.B) { b.StopTimer() size := 10000 - m := NewWithIntComparators() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -754,7 +725,7 @@ func BenchmarkTreeBidiMapPut10000(b *testing.B) { func BenchmarkTreeBidiMapPut100000(b *testing.B) { b.StopTimer() size := 100000 - m := NewWithIntComparators() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -765,7 +736,7 @@ func BenchmarkTreeBidiMapPut100000(b *testing.B) { func BenchmarkTreeBidiMapRemove100(b *testing.B) { b.StopTimer() size := 100 - m := NewWithIntComparators() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -776,7 +747,7 @@ func BenchmarkTreeBidiMapRemove100(b *testing.B) { func BenchmarkTreeBidiMapRemove1000(b *testing.B) { b.StopTimer() size := 1000 - m := NewWithIntComparators() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -787,7 +758,7 @@ func BenchmarkTreeBidiMapRemove1000(b *testing.B) { func BenchmarkTreeBidiMapRemove10000(b *testing.B) { b.StopTimer() size := 10000 - m := NewWithIntComparators() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } @@ -798,7 +769,7 @@ func BenchmarkTreeBidiMapRemove10000(b *testing.B) { func BenchmarkTreeBidiMapRemove100000(b *testing.B) { b.StopTimer() size := 100000 - m := NewWithIntComparators() + m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } diff --git a/maps/treemap/enumerable.go b/maps/treemap/enumerable.go index 34b3704d..7b0df161 100644 --- a/maps/treemap/enumerable.go +++ b/maps/treemap/enumerable.go @@ -5,15 +5,15 @@ package treemap import ( - "github.com/emirpasic/gods/containers" - rbt "github.com/emirpasic/gods/trees/redblacktree" + "github.com/emirpasic/gods/v2/containers" + rbt "github.com/emirpasic/gods/v2/trees/redblacktree" ) // Assert Enumerable implementation -var _ containers.EnumerableWithKey = (*Map)(nil) +var _ containers.EnumerableWithKey[string, int] = (*Map[string, int])(nil) // Each calls the given function once for each element, passing that element's key and value. -func (m *Map) Each(f func(key interface{}, value interface{})) { +func (m *Map[K, V]) Each(f func(key K, value V)) { iterator := m.Iterator() for iterator.Next() { f(iterator.Key(), iterator.Value()) @@ -22,8 +22,8 @@ func (m *Map) Each(f func(key interface{}, value interface{})) { // 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. -func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) *Map { - newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)} +func (m *Map[K, V]) Map(f func(key1 K, value1 V) (K, V)) *Map[K, V] { + newMap := &Map[K, V]{tree: rbt.NewWith[K, V](m.tree.Comparator)} iterator := m.Iterator() for iterator.Next() { key2, value2 := f(iterator.Key(), iterator.Value()) @@ -33,8 +33,8 @@ func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, int } // Select returns a new container containing all elements for which the given function returns a true value. -func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map { - newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)} +func (m *Map[K, V]) Select(f func(key K, value V) bool) *Map[K, V] { + newMap := &Map[K, V]{tree: rbt.NewWith[K, V](m.tree.Comparator)} iterator := m.Iterator() for iterator.Next() { if f(iterator.Key(), iterator.Value()) { @@ -46,7 +46,7 @@ func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map { // Any passes each element of the container to the given function and // returns true if the function ever returns true for any element. -func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool { +func (m *Map[K, V]) Any(f func(key K, value V) bool) bool { iterator := m.Iterator() for iterator.Next() { if f(iterator.Key(), iterator.Value()) { @@ -58,7 +58,7 @@ func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool { // All passes each element of the container to the given function and // returns true if the function returns true for all elements. -func (m *Map) All(f func(key interface{}, value interface{}) bool) bool { +func (m *Map[K, V]) All(f func(key K, value V) bool) bool { iterator := m.Iterator() for iterator.Next() { if !f(iterator.Key(), iterator.Value()) { @@ -71,12 +71,12 @@ func (m *Map) All(f func(key interface{}, value interface{}) 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. -func (m *Map) Find(f func(key interface{}, value interface{}) bool) (interface{}, interface{}) { +func (m *Map[K, V]) Find(f func(key K, value V) bool) (k K, v V) { iterator := m.Iterator() for iterator.Next() { if f(iterator.Key(), iterator.Value()) { return iterator.Key(), iterator.Value() } } - return nil, nil + return k, v } diff --git a/maps/treemap/iterator.go b/maps/treemap/iterator.go index becb56db..9bdf91b5 100644 --- a/maps/treemap/iterator.go +++ b/maps/treemap/iterator.go @@ -5,73 +5,73 @@ package treemap import ( - "github.com/emirpasic/gods/containers" - rbt "github.com/emirpasic/gods/trees/redblacktree" + "github.com/emirpasic/gods/v2/containers" + rbt "github.com/emirpasic/gods/v2/trees/redblacktree" ) // Assert Iterator implementation -var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) +var _ containers.ReverseIteratorWithKey[string, int] = (*Iterator[string, int])(nil) // Iterator holding the iterator's state -type Iterator struct { - iterator rbt.Iterator +type Iterator[K comparable, V any] struct { + iterator *rbt.Iterator[K, V] } // Iterator returns a stateful iterator whose elements are key/value pairs. -func (m *Map) Iterator() Iterator { - return Iterator{iterator: m.tree.Iterator()} +func (m *Map[K, V]) Iterator() *Iterator[K, V] { + return &Iterator[K, V]{iterator: m.tree.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 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. // Modifies the state of the iterator. -func (iterator *Iterator) Next() bool { +func (iterator *Iterator[K, V]) 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. -func (iterator *Iterator) Prev() bool { +func (iterator *Iterator[K, V]) 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{} { +func (iterator *Iterator[K, V]) Value() V { return iterator.iterator.Value() } // Key returns the current element's key. // Does not modify the state of the iterator. -func (iterator *Iterator) Key() interface{} { +func (iterator *Iterator[K, V]) Key() K { return iterator.iterator.Key() } // Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. -func (iterator *Iterator) Begin() { +func (iterator *Iterator[K, V]) 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() { +func (iterator *Iterator[K, V]) 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator -func (iterator *Iterator) First() bool { +func (iterator *Iterator[K, V]) 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. -func (iterator *Iterator) Last() bool { +func (iterator *Iterator[K, V]) Last() bool { return iterator.iterator.Last() } @@ -79,7 +79,7 @@ func (iterator *Iterator) Last() bool { // 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. -func (iterator *Iterator) NextTo(f func(key interface{}, value interface{}) bool) bool { +func (iterator *Iterator[K, V]) NextTo(f func(key K, value V) bool) bool { for iterator.Next() { key, value := iterator.Key(), iterator.Value() if f(key, value) { @@ -93,7 +93,7 @@ func (iterator *Iterator) NextTo(f func(key interface{}, value interface{}) bool // 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. -func (iterator *Iterator) PrevTo(f func(key interface{}, value interface{}) bool) bool { +func (iterator *Iterator[K, V]) PrevTo(f func(key K, value V) bool) bool { for iterator.Prev() { key, value := iterator.Key(), iterator.Value() if f(key, value) { diff --git a/maps/treemap/serialization.go b/maps/treemap/serialization.go index 415a77dd..c63c4972 100644 --- a/maps/treemap/serialization.go +++ b/maps/treemap/serialization.go @@ -5,29 +5,29 @@ package treemap import ( - "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*Map)(nil) -var _ containers.JSONDeserializer = (*Map)(nil) +var _ containers.JSONSerializer = (*Map[string, int])(nil) +var _ containers.JSONDeserializer = (*Map[string, int])(nil) // ToJSON outputs the JSON representation of the map. -func (m *Map) ToJSON() ([]byte, error) { +func (m *Map[K, V]) ToJSON() ([]byte, error) { return m.tree.ToJSON() } // FromJSON populates the map from the input JSON representation. -func (m *Map) FromJSON(data []byte) error { +func (m *Map[K, V]) FromJSON(data []byte) error { return m.tree.FromJSON(data) } // UnmarshalJSON @implements json.Unmarshaler -func (m *Map) UnmarshalJSON(bytes []byte) error { +func (m *Map[K, V]) UnmarshalJSON(bytes []byte) error { return m.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (m *Map) MarshalJSON() ([]byte, error) { +func (m *Map[K, V]) MarshalJSON() ([]byte, error) { return m.ToJSON() } diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index a77d16d8..f3766622 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -12,96 +12,93 @@ package treemap import ( + "cmp" "fmt" - "github.com/emirpasic/gods/maps" - rbt "github.com/emirpasic/gods/trees/redblacktree" - "github.com/emirpasic/gods/utils" "strings" + + "github.com/emirpasic/gods/v2/maps" + rbt "github.com/emirpasic/gods/v2/trees/redblacktree" + "github.com/emirpasic/gods/v2/utils" ) // Assert Map implementation -var _ maps.Map = (*Map)(nil) +var _ maps.Map[string, int] = (*Map[string, int])(nil) // Map holds the elements in a red-black tree -type Map struct { - tree *rbt.Tree +type Map[K comparable, V any] struct { + tree *rbt.Tree[K, V] } -// NewWith instantiates a tree map with the custom comparator. -func NewWith(comparator utils.Comparator) *Map { - return &Map{tree: rbt.NewWith(comparator)} +// New instantiates a tree map with the built-in comparator for K +func New[K cmp.Ordered, V any]() *Map[K, V] { + return &Map[K, V]{tree: rbt.New[K, V]()} } -// NewWithIntComparator instantiates a tree map with the IntComparator, i.e. keys are of type int. -func NewWithIntComparator() *Map { - return &Map{tree: rbt.NewWithIntComparator()} -} - -// NewWithStringComparator instantiates a tree map with the StringComparator, i.e. keys are of type string. -func NewWithStringComparator() *Map { - return &Map{tree: rbt.NewWithStringComparator()} +// NewWith instantiates a tree map with the custom comparator. +func NewWith[K comparable, V any](comparator utils.Comparator[K]) *Map[K, V] { + return &Map[K, V]{tree: rbt.NewWith[K, V](comparator)} } // Put inserts key-value pair into the map. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (m *Map) Put(key interface{}, value interface{}) { +func (m *Map[K, V]) Put(key K, value V) { m.tree.Put(key, value) } // Get searches the element in the map by key and returns its value or nil if key is not found in tree. // Second return parameter is true if key was found, otherwise false. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (m *Map) Get(key interface{}) (value interface{}, found bool) { +func (m *Map[K, V]) Get(key K) (value V, found bool) { return m.tree.Get(key) } // Remove removes the element from the map by key. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (m *Map) Remove(key interface{}) { +func (m *Map[K, V]) Remove(key K) { m.tree.Remove(key) } // Empty returns true if map does not contain any elements -func (m *Map) Empty() bool { +func (m *Map[K, V]) Empty() bool { return m.tree.Empty() } // Size returns number of elements in the map. -func (m *Map) Size() int { +func (m *Map[K, V]) Size() int { return m.tree.Size() } // Keys returns all keys in-order -func (m *Map) Keys() []interface{} { +func (m *Map[K, V]) Keys() []K { return m.tree.Keys() } // Values returns all values in-order based on the key. -func (m *Map) Values() []interface{} { +func (m *Map[K, V]) Values() []V { return m.tree.Values() } // Clear removes all elements from the map. -func (m *Map) Clear() { +func (m *Map[K, V]) Clear() { m.tree.Clear() } // Min returns the minimum key and its value from the tree map. -// Returns nil, nil if map is empty. -func (m *Map) Min() (key interface{}, value interface{}) { +// Returns 0-value, 0-value, false if map is empty. +func (m *Map[K, V]) Min() (key K, value V, ok bool) { if node := m.tree.Left(); node != nil { - return node.Key, node.Value + return node.Key, node.Value, true } - return nil, nil + return key, value, false } // Max returns the maximum key and its value from the tree map. -// Returns nil, nil if map is empty. -func (m *Map) Max() (key interface{}, value interface{}) { +// Returns 0-value, 0-value, false if map is empty. +func (m *Map[K, V]) Max() (key K, value V, ok bool) { if node := m.tree.Right(); node != nil { - return node.Key, node.Value + return node.Key, node.Value, true } - return nil, nil + return key, value, false } // Floor finds the floor key-value pair for the input key. @@ -113,12 +110,12 @@ func (m *Map) Max() (key interface{}, value interface{}) { // all keys in the map are larger than the given key. // // Key should adhere to the comparator's type assertion, otherwise method panics. -func (m *Map) Floor(key interface{}) (foundKey interface{}, foundValue interface{}) { +func (m *Map[K, V]) Floor(key K) (foundKey K, foundValue V, ok bool) { node, found := m.tree.Floor(key) if found { - return node.Key, node.Value + return node.Key, node.Value, true } - return nil, nil + return foundKey, foundValue, false } // Ceiling finds the ceiling key-value pair for the input key. @@ -130,16 +127,16 @@ func (m *Map) Floor(key interface{}) (foundKey interface{}, foundValue interface // all keys in the map are smaller than the given key. // // Key should adhere to the comparator's type assertion, otherwise method panics. -func (m *Map) Ceiling(key interface{}) (foundKey interface{}, foundValue interface{}) { +func (m *Map[K, V]) Ceiling(key K) (foundKey K, foundValue V, ok bool) { node, found := m.tree.Ceiling(key) if found { - return node.Key, node.Value + return node.Key, node.Value, true } - return nil, nil + return foundKey, foundValue, false } // String returns a string representation of container -func (m *Map) String() string { +func (m *Map[K, V]) String() string { str := "TreeMap\nmap[" it := m.Iterator() for it.Next() { diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index f0c96baa..e608f0e6 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -6,14 +6,14 @@ package treemap import ( "encoding/json" - "fmt" - "github.com/emirpasic/gods/utils" "strings" "testing" + + "github.com/emirpasic/gods/v2/testutils" ) func TestMapPut(t *testing.T) { - m := NewWith(utils.IntComparator) + m := New[int, string]() m.Put(5, "e") m.Put(6, "f") m.Put(7, "g") @@ -26,12 +26,8 @@ func TestMapPut(t *testing.T) { if actualValue := m.Size(); actualValue != 7 { t.Errorf("Got %v expected %v", actualValue, 7) } - if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "e", "f", "g"}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4, 5, 6, 7}) + testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d", "e", "f", "g"}) // key,expectedValue,expectedFound tests1 := [][]interface{}{ @@ -42,12 +38,12 @@ func TestMapPut(t *testing.T) { {5, "e", true}, {6, "f", true}, {7, "g", true}, - {8, nil, false}, + {8, "", false}, } for _, test := range tests1 { // retrievals - actualValue, actualFound := m.Get(test[0]) + actualValue, actualFound := m.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } @@ -55,10 +51,10 @@ func TestMapPut(t *testing.T) { } func TestMapMin(t *testing.T) { - m := NewWithIntComparator() + m := New[int, string]() - if k, v := m.Min(); k != nil || v != nil { - t.Errorf("Got %v->%v expected %v->%v", k, v, nil, nil) + if k, v, ok := m.Min(); k != 0 || v != "" || ok { + t.Errorf("Got %v->%v->%v expected %v->%v-%v", k, v, ok, 0, "", false) } m.Put(5, "e") @@ -70,21 +66,24 @@ func TestMapMin(t *testing.T) { m.Put(2, "b") m.Put(1, "a") //overwrite - actualKey, actualValue := m.Min() - expectedKey, expectedValue := 1, "a" + actualKey, actualValue, actualOk := m.Min() + expectedKey, expectedValue, expectedOk := 1, "a", true if actualKey != expectedKey { t.Errorf("Got %v expected %v", actualKey, expectedKey) } if actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } + if actualOk != expectedOk { + t.Errorf("Got %v expected %v", actualOk, expectedOk) + } } func TestMapMax(t *testing.T) { - m := NewWithIntComparator() + m := New[int, string]() - if k, v := m.Max(); k != nil || v != nil { - t.Errorf("Got %v->%v expected %v->%v", k, v, nil, nil) + if k, v, ok := m.Max(); k != 0 || v != "" || ok { + t.Errorf("Got %v->%v->%v expected %v->%v-%v", k, v, ok, 0, "", false) } m.Put(5, "e") @@ -96,18 +95,21 @@ func TestMapMax(t *testing.T) { m.Put(2, "b") m.Put(1, "a") //overwrite - actualKey, actualValue := m.Max() - expectedKey, expectedValue := 7, "g" + actualKey, actualValue, actualOk := m.Max() + expectedKey, expectedValue, expectedOk := 7, "g", true if actualKey != expectedKey { t.Errorf("Got %v expected %v", actualKey, expectedKey) } if actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } + if actualOk != expectedOk { + t.Errorf("Got %v expected %v", actualOk, expectedOk) + } } func TestMapClear(t *testing.T) { - m := NewWithIntComparator() + m := New[int, string]() m.Put(5, "e") m.Put(6, "f") m.Put(7, "g") @@ -122,7 +124,7 @@ func TestMapClear(t *testing.T) { } func TestMapRemove(t *testing.T) { - m := NewWithIntComparator() + m := New[int, string]() m.Put(5, "e") m.Put(6, "f") m.Put(7, "g") @@ -138,13 +140,9 @@ func TestMapRemove(t *testing.T) { m.Remove(8) m.Remove(5) - if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4}) + testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d"}) - if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d"}; !sameElements(actualValue, expectedValue) { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } if actualValue := m.Size(); actualValue != 4 { t.Errorf("Got %v expected %v", actualValue, 4) } @@ -154,14 +152,14 @@ func TestMapRemove(t *testing.T) { {2, "b", true}, {3, "c", true}, {4, "d", true}, - {5, nil, false}, - {6, nil, false}, - {7, nil, false}, - {8, nil, false}, + {5, "", false}, + {6, "", false}, + {7, "", false}, + {8, "", false}, } for _, test := range tests2 { - actualValue, actualFound := m.Get(test[0]) + actualValue, actualFound := m.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } @@ -174,12 +172,8 @@ func TestMapRemove(t *testing.T) { m.Remove(2) m.Remove(2) - if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, m.Keys(), nil) + testutils.SameElements(t, m.Values(), nil) if actualValue := m.Size(); actualValue != 0 { t.Errorf("Got %v expected %v", actualValue, 0) } @@ -189,15 +183,15 @@ func TestMapRemove(t *testing.T) { } func TestMapFloor(t *testing.T) { - m := NewWithIntComparator() + m := New[int, string]() m.Put(7, "g") m.Put(3, "c") m.Put(1, "a") // key,expectedKey,expectedValue,expectedFound tests1 := [][]interface{}{ - {-1, nil, nil, false}, - {0, nil, nil, false}, + {-1, 0, "", false}, + {0, 0, "", false}, {1, 1, "a", true}, {2, 1, "a", true}, {3, 3, "c", true}, @@ -208,16 +202,15 @@ func TestMapFloor(t *testing.T) { for _, test := range tests1 { // retrievals - actualKey, actualValue := m.Floor(test[0]) - actualFound := actualKey != nil && actualValue != nil - if actualKey != test[1] || actualValue != test[2] || actualFound != test[3] { - t.Errorf("Got %v, %v, %v, expected %v, %v, %v", actualKey, actualValue, actualFound, test[1], test[2], test[3]) + actualKey, actualValue, actualOk := m.Floor(test[0].(int)) + if actualKey != test[1] || actualValue != test[2] || actualOk != test[3] { + t.Errorf("Got %v, %v, %v, expected %v, %v, %v", actualKey, actualValue, actualOk, test[1], test[2], test[3]) } } } func TestMapCeiling(t *testing.T) { - m := NewWithIntComparator() + m := New[int, string]() m.Put(7, "g") m.Put(3, "c") m.Put(1, "a") @@ -231,45 +224,25 @@ func TestMapCeiling(t *testing.T) { {3, 3, "c", true}, {4, 7, "g", true}, {7, 7, "g", true}, - {8, nil, nil, false}, + {8, 0, "", false}, } for _, test := range tests1 { // retrievals - actualKey, actualValue := m.Ceiling(test[0]) - actualFound := actualKey != nil && actualValue != nil - if actualKey != test[1] || actualValue != test[2] || actualFound != test[3] { - t.Errorf("Got %v, %v, %v, expected %v, %v, %v", actualKey, actualValue, actualFound, test[1], test[2], test[3]) - } - } -} - -func sameElements(a []interface{}, b []interface{}) bool { - if len(a) != len(b) { - return false - } - for _, av := range a { - found := false - for _, bv := range b { - if av == bv { - found = true - break - } - } - if !found { - return false + actualKey, actualValue, actualOk := m.Ceiling(test[0].(int)) + if actualKey != test[1] || actualValue != test[2] || actualOk != test[3] { + t.Errorf("Got %v, %v, %v, expected %v, %v, %v", actualKey, actualValue, actualOk, test[1], test[2], test[3]) } } - return true } func TestMapEach(t *testing.T) { - m := NewWithStringComparator() + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) count := 0 - m.Each(func(key interface{}, value interface{}) { + m.Each(func(key string, value int) { count++ if actualValue, expectedValue := count, value; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -294,12 +267,12 @@ func TestMapEach(t *testing.T) { } func TestMapMap(t *testing.T) { - m := NewWithStringComparator() + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) - mappedMap := m.Map(func(key1 interface{}, value1 interface{}) (key2 interface{}, value2 interface{}) { - return key1, value1.(int) * value1.(int) + mappedMap := m.Map(func(key1 string, value1 int) (key2 string, value2 int) { + return key1, value1 * value1 }) if actualValue, _ := mappedMap.Get("a"); actualValue != 1 { t.Errorf("Got %v expected %v", actualValue, "mapped: a") @@ -316,12 +289,12 @@ func TestMapMap(t *testing.T) { } func TestMapSelect(t *testing.T) { - m := NewWithStringComparator() + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) - selectedMap := m.Select(func(key interface{}, value interface{}) bool { - return key.(string) >= "a" && key.(string) <= "b" + selectedMap := m.Select(func(key string, value int) bool { + return key >= "a" && key <= "b" }) if actualValue, _ := selectedMap.Get("a"); actualValue != 1 { t.Errorf("Got %v expected %v", actualValue, "value: a") @@ -335,18 +308,18 @@ func TestMapSelect(t *testing.T) { } func TestMapAny(t *testing.T) { - m := NewWithStringComparator() + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) - any := m.Any(func(key interface{}, value interface{}) bool { - return value.(int) == 3 + any := m.Any(func(key string, value int) bool { + return value == 3 }) if any != true { t.Errorf("Got %v expected %v", any, true) } - any = m.Any(func(key interface{}, value interface{}) bool { - return value.(int) == 4 + any = m.Any(func(key string, value int) bool { + return value == 4 }) if any != false { t.Errorf("Got %v expected %v", any, false) @@ -354,18 +327,18 @@ func TestMapAny(t *testing.T) { } func TestMapAll(t *testing.T) { - m := NewWithStringComparator() + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) - all := m.All(func(key interface{}, value interface{}) bool { - return key.(string) >= "a" && key.(string) <= "c" + all := m.All(func(key string, value int) bool { + return key >= "a" && key <= "c" }) if all != true { t.Errorf("Got %v expected %v", all, true) } - all = m.All(func(key interface{}, value interface{}) bool { - return key.(string) >= "a" && key.(string) <= "b" + all = m.All(func(key string, value int) bool { + return key >= "a" && key <= "b" }) if all != false { t.Errorf("Got %v expected %v", all, false) @@ -373,38 +346,38 @@ func TestMapAll(t *testing.T) { } func TestMapFind(t *testing.T) { - m := NewWithStringComparator() + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) - foundKey, foundValue := m.Find(func(key interface{}, value interface{}) bool { - return key.(string) == "c" + foundKey, foundValue := m.Find(func(key string, value int) bool { + return key == "c" }) if foundKey != "c" || foundValue != 3 { t.Errorf("Got %v -> %v expected %v -> %v", foundKey, foundValue, "c", 3) } - foundKey, foundValue = m.Find(func(key interface{}, value interface{}) bool { - return key.(string) == "x" + foundKey, foundValue = m.Find(func(key string, value int) bool { + return key == "x" }) - if foundKey != nil || foundValue != nil { + if foundKey != "" || foundValue != 0 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundKey, nil, nil) } } func TestMapChaining(t *testing.T) { - m := NewWithStringComparator() + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) - chainedMap := m.Select(func(key interface{}, value interface{}) bool { - return value.(int) > 1 - }).Map(func(key interface{}, value interface{}) (interface{}, interface{}) { - return key.(string) + key.(string), value.(int) * value.(int) + chainedMap := m.Select(func(key string, value int) bool { + return value > 1 + }).Map(func(key string, value int) (string, int) { + return key + key, value * value }) if actualValue := chainedMap.Size(); actualValue != 2 { t.Errorf("Got %v expected %v", actualValue, 2) } - if actualValue, found := chainedMap.Get("aa"); actualValue != nil || found { + if actualValue, found := chainedMap.Get("aa"); actualValue != 0 || found { t.Errorf("Got %v expected %v", actualValue, nil) } if actualValue, found := chainedMap.Get("bb"); actualValue != 4 || !found { @@ -416,7 +389,7 @@ func TestMapChaining(t *testing.T) { } func TestMapIteratorNextOnEmpty(t *testing.T) { - m := NewWithStringComparator() + m := New[string, int]() it := m.Iterator() it = m.Iterator() for it.Next() { @@ -425,7 +398,7 @@ func TestMapIteratorNextOnEmpty(t *testing.T) { } func TestMapIteratorPrevOnEmpty(t *testing.T) { - m := NewWithStringComparator() + m := New[string, int]() it := m.Iterator() it = m.Iterator() for it.Prev() { @@ -434,7 +407,7 @@ func TestMapIteratorPrevOnEmpty(t *testing.T) { } func TestMapIteratorNext(t *testing.T) { - m := NewWithStringComparator() + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) @@ -471,7 +444,7 @@ func TestMapIteratorNext(t *testing.T) { } func TestMapIteratorPrev(t *testing.T) { - m := NewWithStringComparator() + m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) @@ -510,7 +483,7 @@ func TestMapIteratorPrev(t *testing.T) { } func TestMapIteratorBegin(t *testing.T) { - m := NewWithIntComparator() + m := New[int, string]() it := m.Iterator() it.Begin() m.Put(3, "c") @@ -526,7 +499,7 @@ func TestMapIteratorBegin(t *testing.T) { } func TestMapIteratorEnd(t *testing.T) { - m := NewWithIntComparator() + m := New[int, string]() it := m.Iterator() m.Put(3, "c") m.Put(1, "a") @@ -539,7 +512,7 @@ func TestMapIteratorEnd(t *testing.T) { } func TestMapIteratorFirst(t *testing.T) { - m := NewWithIntComparator() + m := New[int, string]() m.Put(3, "c") m.Put(1, "a") m.Put(2, "b") @@ -553,7 +526,7 @@ func TestMapIteratorFirst(t *testing.T) { } func TestMapIteratorLast(t *testing.T) { - m := NewWithIntComparator() + m := New[int, string]() m.Put(3, "c") m.Put(1, "a") m.Put(2, "b") @@ -568,13 +541,13 @@ func TestMapIteratorLast(t *testing.T) { func TestMapIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index interface{}, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // NextTo (empty) { - m := NewWithIntComparator() + m := New[int, string]() it := m.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty map") @@ -583,7 +556,7 @@ func TestMapIteratorNextTo(t *testing.T) { // NextTo (not found) { - m := NewWithIntComparator() + m := New[int, string]() m.Put(0, "xx") m.Put(1, "yy") it := m.Iterator() @@ -594,7 +567,7 @@ func TestMapIteratorNextTo(t *testing.T) { // NextTo (found) { - m := NewWithIntComparator() + m := New[int, string]() m.Put(0, "aa") m.Put(1, "bb") m.Put(2, "cc") @@ -603,13 +576,13 @@ func TestMapIteratorNextTo(t *testing.T) { if !it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty map") } - if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Key(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Next() { t.Errorf("Should go to first element") } - if index, value := it.Key(), it.Value(); index != 2 || value.(string) != "cc" { + if index, value := it.Key(), it.Value(); index != 2 || value != "cc" { t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") } if it.Next() { @@ -620,13 +593,13 @@ func TestMapIteratorNextTo(t *testing.T) { func TestMapIteratorPrevTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index interface{}, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // PrevTo (empty) { - m := NewWithIntComparator() + m := New[int, string]() it := m.Iterator() it.End() for it.PrevTo(seek) { @@ -636,7 +609,7 @@ func TestMapIteratorPrevTo(t *testing.T) { // PrevTo (not found) { - m := NewWithIntComparator() + m := New[int, string]() m.Put(0, "xx") m.Put(1, "yy") it := m.Iterator() @@ -648,7 +621,7 @@ func TestMapIteratorPrevTo(t *testing.T) { // PrevTo (found) { - m := NewWithIntComparator() + m := New[int, string]() m.Put(0, "aa") m.Put(1, "bb") m.Put(2, "cc") @@ -657,13 +630,13 @@ func TestMapIteratorPrevTo(t *testing.T) { if !it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty map") } - if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Key(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Prev() { t.Errorf("Should go to first element") } - if index, value := it.Key(), it.Value(); index != 0 || value.(string) != "aa" { + if index, value := it.Key(), it.Value(); index != 0 || value != "aa" { t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") } if it.Prev() { @@ -674,7 +647,7 @@ func TestMapIteratorPrevTo(t *testing.T) { func TestMapSerialization(t *testing.T) { for i := 0; i < 10; i++ { - original := NewWithStringComparator() + original := New[string, string]() original.Put("d", "4") original.Put("e", "5") original.Put("c", "3") @@ -689,7 +662,7 @@ func TestMapSerialization(t *testing.T) { } assertSerialization(original, "B", t) - deserialized := NewWithStringComparator() + deserialized := New[string, string]() err = deserialized.FromJSON(serialized) if err != nil { t.Errorf("Got error %v", err) @@ -697,7 +670,7 @@ func TestMapSerialization(t *testing.T) { assertSerialization(deserialized, "C", t) } - m := NewWithStringComparator() + m := New[string, float64]() m.Put("a", 1.0) m.Put("b", 2.0) m.Put("c", 3.0) @@ -714,29 +687,29 @@ func TestMapSerialization(t *testing.T) { } func TestMapString(t *testing.T) { - c := NewWithStringComparator() + c := New[string, int]() c.Put("a", 1) if !strings.HasPrefix(c.String(), "TreeMap") { t.Errorf("String should start with container name") } } -//noinspection GoBoolExpressions -func assertSerialization(m *Map, txt string, t *testing.T) { +// noinspection GoBoolExpressions +func assertSerialization(m *Map[string, string], txt string, t *testing.T) { if actualValue := m.Keys(); false || - actualValue[0].(string) != "a" || - actualValue[1].(string) != "b" || - actualValue[2].(string) != "c" || - actualValue[3].(string) != "d" || - actualValue[4].(string) != "e" { + actualValue[0] != "a" || + actualValue[1] != "b" || + actualValue[2] != "c" || + actualValue[3] != "d" || + actualValue[4] != "e" { t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[a,b,c,d,e]") } if actualValue := m.Values(); false || - actualValue[0].(string) != "1" || - actualValue[1].(string) != "2" || - actualValue[2].(string) != "3" || - actualValue[3].(string) != "4" || - actualValue[4].(string) != "5" { + actualValue[0] != "1" || + actualValue[1] != "2" || + actualValue[2] != "3" || + actualValue[3] != "4" || + actualValue[4] != "5" { t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[1,2,3,4,5]") } if actualValue, expectedValue := m.Size(), 5; actualValue != expectedValue { @@ -744,7 +717,7 @@ func assertSerialization(m *Map, txt string, t *testing.T) { } } -func benchmarkGet(b *testing.B, m *Map, size int) { +func benchmarkGet(b *testing.B, m *Map[int, struct{}], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { m.Get(n) @@ -752,7 +725,7 @@ func benchmarkGet(b *testing.B, m *Map, size int) { } } -func benchmarkPut(b *testing.B, m *Map, size int) { +func benchmarkPut(b *testing.B, m *Map[int, struct{}], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { m.Put(n, struct{}{}) @@ -760,7 +733,7 @@ func benchmarkPut(b *testing.B, m *Map, size int) { } } -func benchmarkRemove(b *testing.B, m *Map, size int) { +func benchmarkRemove(b *testing.B, m *Map[int, struct{}], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { m.Remove(n) @@ -771,7 +744,7 @@ func benchmarkRemove(b *testing.B, m *Map, size int) { func BenchmarkTreeMapGet100(b *testing.B) { b.StopTimer() size := 100 - m := NewWithIntComparator() + m := New[int, struct{}]() for n := 0; n < size; n++ { m.Put(n, struct{}{}) } @@ -782,7 +755,7 @@ func BenchmarkTreeMapGet100(b *testing.B) { func BenchmarkTreeMapGet1000(b *testing.B) { b.StopTimer() size := 1000 - m := NewWithIntComparator() + m := New[int, struct{}]() for n := 0; n < size; n++ { m.Put(n, struct{}{}) } @@ -793,7 +766,7 @@ func BenchmarkTreeMapGet1000(b *testing.B) { func BenchmarkTreeMapGet10000(b *testing.B) { b.StopTimer() size := 10000 - m := NewWithIntComparator() + m := New[int, struct{}]() for n := 0; n < size; n++ { m.Put(n, struct{}{}) } @@ -804,7 +777,7 @@ func BenchmarkTreeMapGet10000(b *testing.B) { func BenchmarkTreeMapGet100000(b *testing.B) { b.StopTimer() size := 100000 - m := NewWithIntComparator() + m := New[int, struct{}]() for n := 0; n < size; n++ { m.Put(n, struct{}{}) } @@ -815,7 +788,7 @@ func BenchmarkTreeMapGet100000(b *testing.B) { func BenchmarkTreeMapPut100(b *testing.B) { b.StopTimer() size := 100 - m := NewWithIntComparator() + m := New[int, struct{}]() b.StartTimer() benchmarkPut(b, m, size) } @@ -823,7 +796,7 @@ func BenchmarkTreeMapPut100(b *testing.B) { func BenchmarkTreeMapPut1000(b *testing.B) { b.StopTimer() size := 1000 - m := NewWithIntComparator() + m := New[int, struct{}]() for n := 0; n < size; n++ { m.Put(n, struct{}{}) } @@ -834,7 +807,7 @@ func BenchmarkTreeMapPut1000(b *testing.B) { func BenchmarkTreeMapPut10000(b *testing.B) { b.StopTimer() size := 10000 - m := NewWithIntComparator() + m := New[int, struct{}]() for n := 0; n < size; n++ { m.Put(n, struct{}{}) } @@ -845,7 +818,7 @@ func BenchmarkTreeMapPut10000(b *testing.B) { func BenchmarkTreeMapPut100000(b *testing.B) { b.StopTimer() size := 100000 - m := NewWithIntComparator() + m := New[int, struct{}]() for n := 0; n < size; n++ { m.Put(n, struct{}{}) } @@ -856,7 +829,7 @@ func BenchmarkTreeMapPut100000(b *testing.B) { func BenchmarkTreeMapRemove100(b *testing.B) { b.StopTimer() size := 100 - m := NewWithIntComparator() + m := New[int, struct{}]() for n := 0; n < size; n++ { m.Put(n, struct{}{}) } @@ -867,7 +840,7 @@ func BenchmarkTreeMapRemove100(b *testing.B) { func BenchmarkTreeMapRemove1000(b *testing.B) { b.StopTimer() size := 1000 - m := NewWithIntComparator() + m := New[int, struct{}]() for n := 0; n < size; n++ { m.Put(n, struct{}{}) } @@ -878,7 +851,7 @@ func BenchmarkTreeMapRemove1000(b *testing.B) { func BenchmarkTreeMapRemove10000(b *testing.B) { b.StopTimer() size := 10000 - m := NewWithIntComparator() + m := New[int, struct{}]() for n := 0; n < size; n++ { m.Put(n, struct{}{}) } @@ -889,7 +862,7 @@ func BenchmarkTreeMapRemove10000(b *testing.B) { func BenchmarkTreeMapRemove100000(b *testing.B) { b.StopTimer() size := 100000 - m := NewWithIntComparator() + m := New[int, struct{}]() for n := 0; n < size; n++ { m.Put(n, struct{}{}) } diff --git a/queues/arrayqueue/arrayqueue.go b/queues/arrayqueue/arrayqueue.go index 8d480e90..6c57c722 100644 --- a/queues/arrayqueue/arrayqueue.go +++ b/queues/arrayqueue/arrayqueue.go @@ -13,31 +13,31 @@ import ( "fmt" "strings" - "github.com/emirpasic/gods/lists/arraylist" - "github.com/emirpasic/gods/queues" + "github.com/emirpasic/gods/v2/lists/arraylist" + "github.com/emirpasic/gods/v2/queues" ) // Assert Queue implementation -var _ queues.Queue = (*Queue)(nil) +var _ queues.Queue[int] = (*Queue[int])(nil) // Queue holds elements in an array-list -type Queue struct { - list *arraylist.List +type Queue[T comparable] struct { + list *arraylist.List[T] } // New instantiates a new empty queue -func New() *Queue { - return &Queue{list: arraylist.New()} +func New[T comparable]() *Queue[T] { + return &Queue[T]{list: arraylist.New[T]()} } // Enqueue adds a value to the end of the queue -func (queue *Queue) Enqueue(value interface{}) { +func (queue *Queue[T]) Enqueue(value T) { queue.list.Add(value) } // Dequeue removes first element of the queue and returns it, or nil if queue is empty. // Second return parameter is true, unless the queue was empty and there was nothing to dequeue. -func (queue *Queue) Dequeue() (value interface{}, ok bool) { +func (queue *Queue[T]) Dequeue() (value T, ok bool) { value, ok = queue.list.Get(0) if ok { queue.list.Remove(0) @@ -47,32 +47,32 @@ func (queue *Queue) Dequeue() (value interface{}, ok bool) { // Peek returns first element of the queue without removing it, or nil if queue is empty. // Second return parameter is true, unless the queue was empty and there was nothing to peek. -func (queue *Queue) Peek() (value interface{}, ok bool) { +func (queue *Queue[T]) Peek() (value T, ok bool) { return queue.list.Get(0) } // Empty returns true if queue does not contain any elements. -func (queue *Queue) Empty() bool { +func (queue *Queue[T]) Empty() bool { return queue.list.Empty() } // Size returns number of elements within the queue. -func (queue *Queue) Size() int { +func (queue *Queue[T]) Size() int { return queue.list.Size() } // Clear removes all elements from the queue. -func (queue *Queue) Clear() { +func (queue *Queue[T]) Clear() { queue.list.Clear() } // Values returns all elements in the queue (FIFO order). -func (queue *Queue) Values() []interface{} { +func (queue *Queue[T]) Values() []T { return queue.list.Values() } // String returns a string representation of container -func (queue *Queue) String() string { +func (queue *Queue[T]) String() string { str := "ArrayQueue\n" values := []string{} for _, value := range queue.list.Values() { @@ -83,6 +83,6 @@ func (queue *Queue) String() string { } // Check that the index is within bounds of the list -func (queue *Queue) withinRange(index int) bool { +func (queue *Queue[T]) withinRange(index int) bool { return index >= 0 && index < queue.list.Size() } diff --git a/queues/arrayqueue/arrayqueue_test.go b/queues/arrayqueue/arrayqueue_test.go index b704dbf5..8c295da5 100644 --- a/queues/arrayqueue/arrayqueue_test.go +++ b/queues/arrayqueue/arrayqueue_test.go @@ -6,13 +6,14 @@ package arrayqueue import ( "encoding/json" - "fmt" "strings" "testing" + + "github.com/emirpasic/gods/v2/testutils" ) func TestQueueEnqueue(t *testing.T) { - queue := New() + queue := New[int]() if actualValue := queue.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } @@ -20,7 +21,7 @@ func TestQueueEnqueue(t *testing.T) { queue.Enqueue(2) queue.Enqueue(3) - if actualValue := queue.Values(); actualValue[0].(int) != 1 || actualValue[1].(int) != 2 || actualValue[2].(int) != 3 { + if actualValue := queue.Values(); actualValue[0] != 1 || actualValue[1] != 2 || actualValue[2] != 3 { t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") } if actualValue := queue.Empty(); actualValue != false { @@ -35,8 +36,8 @@ func TestQueueEnqueue(t *testing.T) { } func TestQueuePeek(t *testing.T) { - queue := New() - if actualValue, ok := queue.Peek(); actualValue != nil || ok { + queue := New[int]() + if actualValue, ok := queue.Peek(); actualValue != 0 || ok { t.Errorf("Got %v expected %v", actualValue, nil) } queue.Enqueue(1) @@ -48,7 +49,7 @@ func TestQueuePeek(t *testing.T) { } func TestQueueDequeue(t *testing.T) { - queue := New() + queue := New[int]() queue.Enqueue(1) queue.Enqueue(2) queue.Enqueue(3) @@ -62,7 +63,7 @@ func TestQueueDequeue(t *testing.T) { if actualValue, ok := queue.Dequeue(); actualValue != 3 || !ok { t.Errorf("Got %v expected %v", actualValue, 3) } - if actualValue, ok := queue.Dequeue(); actualValue != nil || ok { + if actualValue, ok := queue.Dequeue(); actualValue != 0 || ok { t.Errorf("Got %v expected %v", actualValue, nil) } if actualValue := queue.Empty(); actualValue != true { @@ -74,7 +75,7 @@ func TestQueueDequeue(t *testing.T) { } func TestQueueIteratorOnEmpty(t *testing.T) { - queue := New() + queue := New[int]() it := queue.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty queue") @@ -82,7 +83,7 @@ func TestQueueIteratorOnEmpty(t *testing.T) { } func TestQueueIteratorNext(t *testing.T) { - queue := New() + queue := New[string]() queue.Enqueue("a") queue.Enqueue("b") queue.Enqueue("c") @@ -125,7 +126,7 @@ func TestQueueIteratorNext(t *testing.T) { } func TestQueueIteratorPrev(t *testing.T) { - queue := New() + queue := New[string]() queue.Enqueue("a") queue.Enqueue("b") queue.Enqueue("c") @@ -164,7 +165,7 @@ func TestQueueIteratorPrev(t *testing.T) { } func TestQueueIteratorBegin(t *testing.T) { - queue := New() + queue := New[string]() it := queue.Iterator() it.Begin() queue.Enqueue("a") @@ -180,7 +181,7 @@ func TestQueueIteratorBegin(t *testing.T) { } func TestQueueIteratorEnd(t *testing.T) { - queue := New() + queue := New[string]() it := queue.Iterator() if index := it.Index(); index != -1 { @@ -207,7 +208,7 @@ func TestQueueIteratorEnd(t *testing.T) { } func TestQueueIteratorFirst(t *testing.T) { - queue := New() + queue := New[string]() it := queue.Iterator() if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -224,7 +225,7 @@ func TestQueueIteratorFirst(t *testing.T) { } func TestQueueIteratorLast(t *testing.T) { - queue := New() + queue := New[string]() it := queue.Iterator() if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -242,13 +243,13 @@ func TestQueueIteratorLast(t *testing.T) { func TestQueueIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // NextTo (empty) { - queue := New() + queue := New[string]() it := queue.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty queue") @@ -257,7 +258,7 @@ func TestQueueIteratorNextTo(t *testing.T) { // NextTo (not found) { - queue := New() + queue := New[string]() queue.Enqueue("xx") queue.Enqueue("yy") it := queue.Iterator() @@ -268,7 +269,7 @@ func TestQueueIteratorNextTo(t *testing.T) { // NextTo (found) { - queue := New() + queue := New[string]() queue.Enqueue("aa") queue.Enqueue("bb") queue.Enqueue("cc") @@ -277,13 +278,13 @@ func TestQueueIteratorNextTo(t *testing.T) { if !it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty queue") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Next() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + if index, value := it.Index(), it.Value(); index != 2 || value != "cc" { t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") } if it.Next() { @@ -294,13 +295,13 @@ func TestQueueIteratorNextTo(t *testing.T) { func TestQueueIteratorPrevTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // PrevTo (empty) { - queue := New() + queue := New[string]() it := queue.Iterator() it.End() for it.PrevTo(seek) { @@ -310,7 +311,7 @@ func TestQueueIteratorPrevTo(t *testing.T) { // PrevTo (not found) { - queue := New() + queue := New[string]() queue.Enqueue("xx") queue.Enqueue("yy") it := queue.Iterator() @@ -322,7 +323,7 @@ func TestQueueIteratorPrevTo(t *testing.T) { // PrevTo (found) { - queue := New() + queue := New[string]() queue.Enqueue("aa") queue.Enqueue("bb") queue.Enqueue("cc") @@ -331,13 +332,13 @@ func TestQueueIteratorPrevTo(t *testing.T) { if !it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty queue") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Prev() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "aa" { + if index, value := it.Index(), it.Value(); index != 0 || value != "aa" { t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") } if it.Prev() { @@ -347,16 +348,14 @@ func TestQueueIteratorPrevTo(t *testing.T) { } func TestQueueSerialization(t *testing.T) { - queue := New() + queue := New[string]() queue.Enqueue("a") queue.Enqueue("b") queue.Enqueue("c") var err error assert := func() { - if actualValue, expectedValue := fmt.Sprintf("%s%s%s", queue.Values()...), "abc"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, queue.Values(), []string{"a", "b", "c"}) if actualValue, expectedValue := queue.Size(), 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } @@ -378,21 +377,22 @@ func TestQueueSerialization(t *testing.T) { t.Errorf("Got error %v", err) } - err = json.Unmarshal([]byte(`[1,2,3]`), &queue) + err = json.Unmarshal([]byte(`["a","b","c"]`), &queue) if err != nil { t.Errorf("Got error %v", err) } + assert() } func TestQueueString(t *testing.T) { - c := New() + c := New[int]() c.Enqueue(1) if !strings.HasPrefix(c.String(), "ArrayQueue") { t.Errorf("String should start with container name") } } -func benchmarkEnqueue(b *testing.B, queue *Queue, size int) { +func benchmarkEnqueue(b *testing.B, queue *Queue[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { queue.Enqueue(n) @@ -400,7 +400,7 @@ func benchmarkEnqueue(b *testing.B, queue *Queue, size int) { } } -func benchmarkDequeue(b *testing.B, queue *Queue, size int) { +func benchmarkDequeue(b *testing.B, queue *Queue[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { queue.Dequeue() @@ -411,7 +411,7 @@ func benchmarkDequeue(b *testing.B, queue *Queue, size int) { func BenchmarkArrayQueueDequeue100(b *testing.B) { b.StopTimer() size := 100 - queue := New() + queue := New[int]() for n := 0; n < size; n++ { queue.Enqueue(n) } @@ -422,7 +422,7 @@ func BenchmarkArrayQueueDequeue100(b *testing.B) { func BenchmarkArrayQueueDequeue1000(b *testing.B) { b.StopTimer() size := 1000 - queue := New() + queue := New[int]() for n := 0; n < size; n++ { queue.Enqueue(n) } @@ -433,7 +433,7 @@ func BenchmarkArrayQueueDequeue1000(b *testing.B) { func BenchmarkArrayQueueDequeue10000(b *testing.B) { b.StopTimer() size := 10000 - queue := New() + queue := New[int]() for n := 0; n < size; n++ { queue.Enqueue(n) } @@ -444,7 +444,7 @@ func BenchmarkArrayQueueDequeue10000(b *testing.B) { func BenchmarkArrayQueueDequeue100000(b *testing.B) { b.StopTimer() size := 100000 - queue := New() + queue := New[int]() for n := 0; n < size; n++ { queue.Enqueue(n) } @@ -455,7 +455,7 @@ func BenchmarkArrayQueueDequeue100000(b *testing.B) { func BenchmarkArrayQueueEnqueue100(b *testing.B) { b.StopTimer() size := 100 - queue := New() + queue := New[int]() b.StartTimer() benchmarkEnqueue(b, queue, size) } @@ -463,7 +463,7 @@ func BenchmarkArrayQueueEnqueue100(b *testing.B) { func BenchmarkArrayQueueEnqueue1000(b *testing.B) { b.StopTimer() size := 1000 - queue := New() + queue := New[int]() for n := 0; n < size; n++ { queue.Enqueue(n) } @@ -474,7 +474,7 @@ func BenchmarkArrayQueueEnqueue1000(b *testing.B) { func BenchmarkArrayQueueEnqueue10000(b *testing.B) { b.StopTimer() size := 10000 - queue := New() + queue := New[int]() for n := 0; n < size; n++ { queue.Enqueue(n) } @@ -485,7 +485,7 @@ func BenchmarkArrayQueueEnqueue10000(b *testing.B) { func BenchmarkArrayQueueEnqueue100000(b *testing.B) { b.StopTimer() size := 100000 - queue := New() + queue := New[int]() for n := 0; n < size; n++ { queue.Enqueue(n) } diff --git a/queues/arrayqueue/iterator.go b/queues/arrayqueue/iterator.go index 51a30f9a..bc684685 100644 --- a/queues/arrayqueue/iterator.go +++ b/queues/arrayqueue/iterator.go @@ -4,27 +4,27 @@ package arrayqueue -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Assert Iterator implementation -var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) +var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. -type Iterator struct { - queue *Queue +type Iterator[T comparable] struct { + queue *Queue[T] index int } // Iterator returns a stateful iterator whose values can be fetched by an index. -func (queue *Queue) Iterator() Iterator { - return Iterator{queue: queue, index: -1} +func (queue *Queue[T]) Iterator() *Iterator[T] { + return &Iterator[T]{queue: queue, index: -1} } // 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 { +func (iterator *Iterator[T]) Next() bool { if iterator.index < iterator.queue.Size() { iterator.index++ } @@ -34,7 +34,7 @@ func (iterator *Iterator) Next() bool { // 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 { +func (iterator *Iterator[T]) Prev() bool { if iterator.index >= 0 { iterator.index-- } @@ -43,33 +43,33 @@ func (iterator *Iterator) Prev() bool { // Value returns the current element's value. // Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { +func (iterator *Iterator[T]) Value() T { value, _ := iterator.queue.list.Get(iterator.index) return value } // Index returns the current element's index. // Does not modify the state of the iterator. -func (iterator *Iterator) Index() int { +func (iterator *Iterator[T]) Index() int { return 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() { +func (iterator *Iterator[T]) Begin() { iterator.index = -1 } // 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() { +func (iterator *Iterator[T]) End() { iterator.index = iterator.queue.Size() } // 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 { +func (iterator *Iterator[T]) First() bool { iterator.Begin() return iterator.Next() } @@ -77,7 +77,7 @@ func (iterator *Iterator) First() bool { // 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 { +func (iterator *Iterator[T]) Last() bool { iterator.End() return iterator.Prev() } @@ -86,7 +86,7 @@ func (iterator *Iterator) Last() bool { // 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. -func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) NextTo(f func(index int, value T) bool) bool { for iterator.Next() { index, value := iterator.Index(), iterator.Value() if f(index, value) { @@ -100,7 +100,7 @@ func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool // 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. -func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) PrevTo(f func(index int, value T) bool) bool { for iterator.Prev() { index, value := iterator.Index(), iterator.Value() if f(index, value) { diff --git a/queues/arrayqueue/serialization.go b/queues/arrayqueue/serialization.go index a33a82f9..49abb16f 100644 --- a/queues/arrayqueue/serialization.go +++ b/queues/arrayqueue/serialization.go @@ -5,29 +5,29 @@ package arrayqueue import ( - "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*Queue)(nil) -var _ containers.JSONDeserializer = (*Queue)(nil) +var _ containers.JSONSerializer = (*Queue[int])(nil) +var _ containers.JSONDeserializer = (*Queue[int])(nil) // ToJSON outputs the JSON representation of the queue. -func (queue *Queue) ToJSON() ([]byte, error) { +func (queue *Queue[T]) ToJSON() ([]byte, error) { return queue.list.ToJSON() } // FromJSON populates the queue from the input JSON representation. -func (queue *Queue) FromJSON(data []byte) error { +func (queue *Queue[T]) FromJSON(data []byte) error { return queue.list.FromJSON(data) } // UnmarshalJSON @implements json.Unmarshaler -func (queue *Queue) UnmarshalJSON(bytes []byte) error { +func (queue *Queue[T]) UnmarshalJSON(bytes []byte) error { return queue.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (queue *Queue) MarshalJSON() ([]byte, error) { +func (queue *Queue[T]) MarshalJSON() ([]byte, error) { return queue.ToJSON() } diff --git a/queues/circularbuffer/circularbuffer.go b/queues/circularbuffer/circularbuffer.go index f74a55b1..ef71fdd4 100644 --- a/queues/circularbuffer/circularbuffer.go +++ b/queues/circularbuffer/circularbuffer.go @@ -15,15 +15,15 @@ import ( "fmt" "strings" - "github.com/emirpasic/gods/queues" + "github.com/emirpasic/gods/v2/queues" ) // Assert Queue implementation -var _ queues.Queue = (*Queue)(nil) +var _ queues.Queue[int] = (*Queue[int])(nil) // Queue holds values in a slice. -type Queue struct { - values []interface{} +type Queue[T comparable] struct { + values []T start int end int full bool @@ -33,17 +33,17 @@ type Queue struct { // New instantiates a new empty queue with the specified size of maximum number of elements that it can hold. // This max size of the buffer cannot be changed. -func New(maxSize int) *Queue { +func New[T comparable](maxSize int) *Queue[T] { if maxSize < 1 { panic("Invalid maxSize, should be at least 1") } - queue := &Queue{maxSize: maxSize} + queue := &Queue[T]{maxSize: maxSize} queue.Clear() return queue } // Enqueue adds a value to the end of the queue -func (queue *Queue) Enqueue(value interface{}) { +func (queue *Queue[T]) Enqueue(value T) { if queue.Full() { queue.Dequeue() } @@ -59,24 +59,19 @@ func (queue *Queue) Enqueue(value interface{}) { queue.size = queue.calculateSize() } -// Dequeue removes first element of the queue and returns it, or nil if queue is empty. +// Dequeue removes first element of the queue and returns it, or the 0-value if queue is empty. // Second return parameter is true, unless the queue was empty and there was nothing to dequeue. -func (queue *Queue) Dequeue() (value interface{}, ok bool) { +func (queue *Queue[T]) Dequeue() (value T, ok bool) { if queue.Empty() { - return nil, false + return value, false } value, ok = queue.values[queue.start], true - - if value != nil { - queue.values[queue.start] = nil - queue.start = queue.start + 1 - if queue.start >= queue.maxSize { - queue.start = 0 - } - queue.full = false + queue.start = queue.start + 1 + if queue.start >= queue.maxSize { + queue.start = 0 } - + queue.full = false queue.size = queue.size - 1 return @@ -84,31 +79,31 @@ func (queue *Queue) Dequeue() (value interface{}, ok bool) { // Peek returns first element of the queue without removing it, or nil if queue is empty. // Second return parameter is true, unless the queue was empty and there was nothing to peek. -func (queue *Queue) Peek() (value interface{}, ok bool) { +func (queue *Queue[T]) Peek() (value T, ok bool) { if queue.Empty() { - return nil, false + return value, false } return queue.values[queue.start], true } // Empty returns true if queue does not contain any elements. -func (queue *Queue) Empty() bool { +func (queue *Queue[T]) Empty() bool { return queue.Size() == 0 } // Full returns true if the queue is full, i.e. has reached the maximum number of elements that it can hold. -func (queue *Queue) Full() bool { +func (queue *Queue[T]) Full() bool { return queue.Size() == queue.maxSize } // Size returns number of elements within the queue. -func (queue *Queue) Size() int { +func (queue *Queue[T]) Size() int { return queue.size } // Clear removes all elements from the queue. -func (queue *Queue) Clear() { - queue.values = make([]interface{}, queue.maxSize, queue.maxSize) +func (queue *Queue[T]) Clear() { + queue.values = make([]T, queue.maxSize, queue.maxSize) queue.start = 0 queue.end = 0 queue.full = false @@ -116,8 +111,8 @@ func (queue *Queue) Clear() { } // Values returns all elements in the queue (FIFO order). -func (queue *Queue) Values() []interface{} { - values := make([]interface{}, queue.Size(), queue.Size()) +func (queue *Queue[T]) Values() []T { + values := make([]T, queue.Size(), queue.Size()) for i := 0; i < queue.Size(); i++ { values[i] = queue.values[(queue.start+i)%queue.maxSize] } @@ -125,7 +120,7 @@ func (queue *Queue) Values() []interface{} { } // String returns a string representation of container -func (queue *Queue) String() string { +func (queue *Queue[T]) String() string { str := "CircularBuffer\n" var values []string for _, value := range queue.Values() { @@ -136,11 +131,11 @@ func (queue *Queue) String() string { } // Check that the index is within bounds of the list -func (queue *Queue) withinRange(index int) bool { +func (queue *Queue[T]) withinRange(index int) bool { return index >= 0 && index < queue.size } -func (queue *Queue) calculateSize() int { +func (queue *Queue[T]) calculateSize() int { if queue.end < queue.start { return queue.maxSize - queue.start + queue.end } else if queue.end == queue.start { diff --git a/queues/circularbuffer/circularbuffer_test.go b/queues/circularbuffer/circularbuffer_test.go index 676ea7eb..d48bb3ae 100644 --- a/queues/circularbuffer/circularbuffer_test.go +++ b/queues/circularbuffer/circularbuffer_test.go @@ -6,13 +6,14 @@ package circularbuffer import ( "encoding/json" - "fmt" "strings" "testing" + + "github.com/emirpasic/gods/v2/testutils" ) func TestQueueEnqueue(t *testing.T) { - queue := New(3) + queue := New[int](3) if actualValue := queue.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } @@ -20,7 +21,7 @@ func TestQueueEnqueue(t *testing.T) { queue.Enqueue(2) queue.Enqueue(3) - if actualValue := queue.Values(); actualValue[0].(int) != 1 || actualValue[1].(int) != 2 || actualValue[2].(int) != 3 { + if actualValue := queue.Values(); actualValue[0] != 1 || actualValue[1] != 2 || actualValue[2] != 3 { t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") } if actualValue := queue.Empty(); actualValue != false { @@ -35,8 +36,8 @@ func TestQueueEnqueue(t *testing.T) { } func TestQueuePeek(t *testing.T) { - queue := New(3) - if actualValue, ok := queue.Peek(); actualValue != nil || ok { + queue := New[int](3) + if actualValue, ok := queue.Peek(); actualValue != 0 || ok { t.Errorf("Got %v expected %v", actualValue, nil) } queue.Enqueue(1) @@ -54,7 +55,7 @@ func TestQueueDequeue(t *testing.T) { } } - queue := New(3) + queue := New[int](3) assert(queue.Empty(), true) assert(queue.Empty(), true) assert(queue.Full(), false) @@ -89,7 +90,7 @@ func TestQueueDequeue(t *testing.T) { assert(queue.Empty(), true) assert(queue.Full(), false) - if actualValue, ok := queue.Dequeue(); actualValue != nil || ok { + if actualValue, ok := queue.Dequeue(); actualValue != 0 || ok { t.Errorf("Got %v expected %v", actualValue, nil) } assert(queue.Size(), 0) @@ -106,7 +107,7 @@ func TestQueueDequeueFull(t *testing.T) { } } - queue := New(2) + queue := New[int](2) assert(queue.Empty(), true) assert(queue.Full(), false) assert(queue.Size(), 0) @@ -142,7 +143,7 @@ func TestQueueDequeueFull(t *testing.T) { } assert(queue.Size(), 0) - if actualValue, ok := queue.Dequeue(); actualValue != nil || ok { + if actualValue, ok := queue.Dequeue(); actualValue != 0 || ok { t.Errorf("Got %v expected %v", actualValue, nil) } assert(queue.Empty(), true) @@ -151,7 +152,7 @@ func TestQueueDequeueFull(t *testing.T) { } func TestQueueIteratorOnEmpty(t *testing.T) { - queue := New(3) + queue := New[int](3) it := queue.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty queue") @@ -159,7 +160,7 @@ func TestQueueIteratorOnEmpty(t *testing.T) { } func TestQueueIteratorNext(t *testing.T) { - queue := New(3) + queue := New[string](3) queue.Enqueue("a") queue.Enqueue("b") queue.Enqueue("c") @@ -202,7 +203,7 @@ func TestQueueIteratorNext(t *testing.T) { } func TestQueueIteratorPrev(t *testing.T) { - queue := New(3) + queue := New[string](3) queue.Enqueue("a") queue.Enqueue("b") queue.Enqueue("c") @@ -241,7 +242,7 @@ func TestQueueIteratorPrev(t *testing.T) { } func TestQueueIteratorBegin(t *testing.T) { - queue := New(3) + queue := New[string](3) it := queue.Iterator() it.Begin() queue.Enqueue("a") @@ -257,7 +258,7 @@ func TestQueueIteratorBegin(t *testing.T) { } func TestQueueIteratorEnd(t *testing.T) { - queue := New(3) + queue := New[string](3) it := queue.Iterator() if index := it.Index(); index != -1 { @@ -284,7 +285,7 @@ func TestQueueIteratorEnd(t *testing.T) { } func TestQueueIteratorFirst(t *testing.T) { - queue := New(3) + queue := New[string](3) it := queue.Iterator() if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -301,7 +302,7 @@ func TestQueueIteratorFirst(t *testing.T) { } func TestQueueIteratorLast(t *testing.T) { - queue := New(3) + queue := New[string](3) it := queue.Iterator() if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -319,13 +320,13 @@ func TestQueueIteratorLast(t *testing.T) { func TestQueueIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // NextTo (empty) { - queue := New(3) + queue := New[string](3) it := queue.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty queue") @@ -334,7 +335,7 @@ func TestQueueIteratorNextTo(t *testing.T) { // NextTo (not found) { - queue := New(3) + queue := New[string](3) queue.Enqueue("xx") queue.Enqueue("yy") it := queue.Iterator() @@ -345,7 +346,7 @@ func TestQueueIteratorNextTo(t *testing.T) { // NextTo (found) { - queue := New(3) + queue := New[string](3) queue.Enqueue("aa") queue.Enqueue("bb") queue.Enqueue("cc") @@ -354,13 +355,13 @@ func TestQueueIteratorNextTo(t *testing.T) { if !it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty queue") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Next() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + if index, value := it.Index(), it.Value(); index != 2 || value != "cc" { t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") } if it.Next() { @@ -371,13 +372,13 @@ func TestQueueIteratorNextTo(t *testing.T) { func TestQueueIteratorPrevTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // PrevTo (empty) { - queue := New(3) + queue := New[string](3) it := queue.Iterator() it.End() for it.PrevTo(seek) { @@ -387,7 +388,7 @@ func TestQueueIteratorPrevTo(t *testing.T) { // PrevTo (not found) { - queue := New(3) + queue := New[string](3) queue.Enqueue("xx") queue.Enqueue("yy") it := queue.Iterator() @@ -399,7 +400,7 @@ func TestQueueIteratorPrevTo(t *testing.T) { // PrevTo (found) { - queue := New(3) + queue := New[string](3) queue.Enqueue("aa") queue.Enqueue("bb") queue.Enqueue("cc") @@ -408,13 +409,13 @@ func TestQueueIteratorPrevTo(t *testing.T) { if !it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty queue") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Prev() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "aa" { + if index, value := it.Index(), it.Value(); index != 0 || value != "aa" { t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") } if it.Prev() { @@ -430,7 +431,7 @@ func TestQueueIterator(t *testing.T) { } } - queue := New(2) + queue := New[string](2) queue.Enqueue("a") queue.Enqueue("b") @@ -482,16 +483,14 @@ func TestQueueIterator(t *testing.T) { } func TestQueueSerialization(t *testing.T) { - queue := New(3) + queue := New[string](3) queue.Enqueue("a") queue.Enqueue("b") queue.Enqueue("c") var err error assert := func() { - if actualValue, expectedValue := fmt.Sprintf("%s%s%s", queue.Values()...), "abc"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, queue.Values(), []string{"a", "b", "c"}) if actualValue, expectedValue := queue.Size(), 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } @@ -513,21 +512,22 @@ func TestQueueSerialization(t *testing.T) { t.Errorf("Got error %v", err) } - err = json.Unmarshal([]byte(`[1,2,3]`), &queue) + err = json.Unmarshal([]byte(`["a","b","c"]`), &queue) if err != nil { t.Errorf("Got error %v", err) } + assert() } func TestQueueString(t *testing.T) { - c := New(3) + c := New[int](3) c.Enqueue(1) if !strings.HasPrefix(c.String(), "CircularBuffer") { t.Errorf("String should start with container name") } } -func benchmarkEnqueue(b *testing.B, queue *Queue, size int) { +func benchmarkEnqueue(b *testing.B, queue *Queue[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { queue.Enqueue(n) @@ -535,7 +535,7 @@ func benchmarkEnqueue(b *testing.B, queue *Queue, size int) { } } -func benchmarkDequeue(b *testing.B, queue *Queue, size int) { +func benchmarkDequeue(b *testing.B, queue *Queue[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { queue.Dequeue() @@ -546,7 +546,7 @@ func benchmarkDequeue(b *testing.B, queue *Queue, size int) { func BenchmarkArrayQueueDequeue100(b *testing.B) { b.StopTimer() size := 100 - queue := New(3) + queue := New[int](3) for n := 0; n < size; n++ { queue.Enqueue(n) } @@ -557,7 +557,7 @@ func BenchmarkArrayQueueDequeue100(b *testing.B) { func BenchmarkArrayQueueDequeue1000(b *testing.B) { b.StopTimer() size := 1000 - queue := New(3) + queue := New[int](3) for n := 0; n < size; n++ { queue.Enqueue(n) } @@ -568,7 +568,7 @@ func BenchmarkArrayQueueDequeue1000(b *testing.B) { func BenchmarkArrayQueueDequeue10000(b *testing.B) { b.StopTimer() size := 10000 - queue := New(3) + queue := New[int](3) for n := 0; n < size; n++ { queue.Enqueue(n) } @@ -579,7 +579,7 @@ func BenchmarkArrayQueueDequeue10000(b *testing.B) { func BenchmarkArrayQueueDequeue100000(b *testing.B) { b.StopTimer() size := 100000 - queue := New(3) + queue := New[int](3) for n := 0; n < size; n++ { queue.Enqueue(n) } @@ -590,7 +590,7 @@ func BenchmarkArrayQueueDequeue100000(b *testing.B) { func BenchmarkArrayQueueEnqueue100(b *testing.B) { b.StopTimer() size := 100 - queue := New(3) + queue := New[int](3) b.StartTimer() benchmarkEnqueue(b, queue, size) } @@ -598,7 +598,7 @@ func BenchmarkArrayQueueEnqueue100(b *testing.B) { func BenchmarkArrayQueueEnqueue1000(b *testing.B) { b.StopTimer() size := 1000 - queue := New(3) + queue := New[int](3) for n := 0; n < size; n++ { queue.Enqueue(n) } @@ -609,7 +609,7 @@ func BenchmarkArrayQueueEnqueue1000(b *testing.B) { func BenchmarkArrayQueueEnqueue10000(b *testing.B) { b.StopTimer() size := 10000 - queue := New(3) + queue := New[int](3) for n := 0; n < size; n++ { queue.Enqueue(n) } @@ -620,7 +620,7 @@ func BenchmarkArrayQueueEnqueue10000(b *testing.B) { func BenchmarkArrayQueueEnqueue100000(b *testing.B) { b.StopTimer() size := 100000 - queue := New(3) + queue := New[int](3) for n := 0; n < size; n++ { queue.Enqueue(n) } diff --git a/queues/circularbuffer/iterator.go b/queues/circularbuffer/iterator.go index dae30ce4..be6af87d 100644 --- a/queues/circularbuffer/iterator.go +++ b/queues/circularbuffer/iterator.go @@ -4,27 +4,27 @@ package circularbuffer -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Assert Iterator implementation -var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) +var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. -type Iterator struct { - queue *Queue +type Iterator[T comparable] struct { + queue *Queue[T] index int } // Iterator returns a stateful iterator whose values can be fetched by an index. -func (queue *Queue) Iterator() Iterator { - return Iterator{queue: queue, index: -1} +func (queue *Queue[T]) Iterator() *Iterator[T] { + return &Iterator[T]{queue: queue, index: -1} } // 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 { +func (iterator *Iterator[T]) Next() bool { if iterator.index < iterator.queue.size { iterator.index++ } @@ -34,7 +34,7 @@ func (iterator *Iterator) Next() bool { // 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 { +func (iterator *Iterator[T]) Prev() bool { if iterator.index >= 0 { iterator.index-- } @@ -43,7 +43,7 @@ func (iterator *Iterator) Prev() bool { // Value returns the current element's value. // Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { +func (iterator *Iterator[T]) Value() T { index := (iterator.index + iterator.queue.start) % iterator.queue.maxSize value := iterator.queue.values[index] return value @@ -51,26 +51,26 @@ func (iterator *Iterator) Value() interface{} { // Index returns the current element's index. // Does not modify the state of the iterator. -func (iterator *Iterator) Index() int { +func (iterator *Iterator[T]) Index() int { return 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() { +func (iterator *Iterator[T]) Begin() { iterator.index = -1 } // 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() { +func (iterator *Iterator[T]) End() { iterator.index = iterator.queue.size } // 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 { +func (iterator *Iterator[T]) First() bool { iterator.Begin() return iterator.Next() } @@ -78,7 +78,7 @@ func (iterator *Iterator) First() bool { // 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 { +func (iterator *Iterator[T]) Last() bool { iterator.End() return iterator.Prev() } @@ -87,7 +87,7 @@ func (iterator *Iterator) Last() bool { // 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. -func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) NextTo(f func(index int, value T) bool) bool { for iterator.Next() { index, value := iterator.Index(), iterator.Value() if f(index, value) { @@ -101,7 +101,7 @@ func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool // 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. -func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) PrevTo(f func(index int, value T) bool) bool { for iterator.Prev() { index, value := iterator.Index(), iterator.Value() if f(index, value) { diff --git a/queues/circularbuffer/serialization.go b/queues/circularbuffer/serialization.go index da2543d0..a020bac0 100644 --- a/queues/circularbuffer/serialization.go +++ b/queues/circularbuffer/serialization.go @@ -6,21 +6,22 @@ package circularbuffer import ( "encoding/json" - "github.com/emirpasic/gods/containers" + + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*Queue)(nil) -var _ containers.JSONDeserializer = (*Queue)(nil) +var _ containers.JSONSerializer = (*Queue[int])(nil) +var _ containers.JSONDeserializer = (*Queue[int])(nil) // ToJSON outputs the JSON representation of queue's elements. -func (queue *Queue) ToJSON() ([]byte, error) { +func (queue *Queue[T]) ToJSON() ([]byte, error) { return json.Marshal(queue.values[:queue.maxSize]) } // FromJSON populates list's elements from the input JSON representation. -func (queue *Queue) FromJSON(data []byte) error { - var values []interface{} +func (queue *Queue[T]) FromJSON(data []byte) error { + var values []T err := json.Unmarshal(data, &values) if err == nil { for _, value := range values { @@ -31,11 +32,11 @@ func (queue *Queue) FromJSON(data []byte) error { } // UnmarshalJSON @implements json.Unmarshaler -func (queue *Queue) UnmarshalJSON(bytes []byte) error { +func (queue *Queue[T]) UnmarshalJSON(bytes []byte) error { return queue.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (queue *Queue) MarshalJSON() ([]byte, error) { +func (queue *Queue[T]) MarshalJSON() ([]byte, error) { return queue.ToJSON() } diff --git a/queues/linkedlistqueue/iterator.go b/queues/linkedlistqueue/iterator.go index cf47b191..29bfffda 100644 --- a/queues/linkedlistqueue/iterator.go +++ b/queues/linkedlistqueue/iterator.go @@ -4,27 +4,27 @@ package linkedlistqueue -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Assert Iterator implementation -var _ containers.IteratorWithIndex = (*Iterator)(nil) +var _ containers.IteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. -type Iterator struct { - queue *Queue +type Iterator[T comparable] struct { + queue *Queue[T] index int } // Iterator returns a stateful iterator whose values can be fetched by an index. -func (queue *Queue) Iterator() Iterator { - return Iterator{queue: queue, index: -1} +func (queue *Queue[T]) Iterator() *Iterator[T] { + return &Iterator[T]{queue: queue, index: -1} } // 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 { +func (iterator *Iterator[T]) Next() bool { if iterator.index < iterator.queue.Size() { iterator.index++ } @@ -33,27 +33,27 @@ func (iterator *Iterator) Next() bool { // Value returns the current element's value. // Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { +func (iterator *Iterator[T]) Value() T { value, _ := iterator.queue.list.Get(iterator.index) return value } // Index returns the current element's index. // Does not modify the state of the iterator. -func (iterator *Iterator) Index() int { +func (iterator *Iterator[T]) Index() int { return 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() { +func (iterator *Iterator[T]) Begin() { iterator.index = -1 } // 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 { +func (iterator *Iterator[T]) First() bool { iterator.Begin() return iterator.Next() } @@ -62,7 +62,7 @@ func (iterator *Iterator) First() bool { // 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. -func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) NextTo(f func(index int, value T) bool) bool { for iterator.Next() { index, value := iterator.Index(), iterator.Value() if f(index, value) { diff --git a/queues/linkedlistqueue/linkedlistqueue.go b/queues/linkedlistqueue/linkedlistqueue.go index fdb94636..32ad9f32 100644 --- a/queues/linkedlistqueue/linkedlistqueue.go +++ b/queues/linkedlistqueue/linkedlistqueue.go @@ -13,31 +13,31 @@ import ( "fmt" "strings" - "github.com/emirpasic/gods/lists/singlylinkedlist" - "github.com/emirpasic/gods/queues" + "github.com/emirpasic/gods/v2/lists/singlylinkedlist" + "github.com/emirpasic/gods/v2/queues" ) // Assert Queue implementation -var _ queues.Queue = (*Queue)(nil) +var _ queues.Queue[int] = (*Queue[int])(nil) // Queue holds elements in a singly-linked-list -type Queue struct { - list *singlylinkedlist.List +type Queue[T comparable] struct { + list *singlylinkedlist.List[T] } // New instantiates a new empty queue -func New() *Queue { - return &Queue{list: &singlylinkedlist.List{}} +func New[T comparable]() *Queue[T] { + return &Queue[T]{list: singlylinkedlist.New[T]()} } // Enqueue adds a value to the end of the queue -func (queue *Queue) Enqueue(value interface{}) { +func (queue *Queue[T]) Enqueue(value T) { queue.list.Add(value) } // Dequeue removes first element of the queue and returns it, or nil if queue is empty. // Second return parameter is true, unless the queue was empty and there was nothing to dequeue. -func (queue *Queue) Dequeue() (value interface{}, ok bool) { +func (queue *Queue[T]) Dequeue() (value T, ok bool) { value, ok = queue.list.Get(0) if ok { queue.list.Remove(0) @@ -47,32 +47,32 @@ func (queue *Queue) Dequeue() (value interface{}, ok bool) { // Peek returns first element of the queue without removing it, or nil if queue is empty. // Second return parameter is true, unless the queue was empty and there was nothing to peek. -func (queue *Queue) Peek() (value interface{}, ok bool) { +func (queue *Queue[T]) Peek() (value T, ok bool) { return queue.list.Get(0) } // Empty returns true if queue does not contain any elements. -func (queue *Queue) Empty() bool { +func (queue *Queue[T]) Empty() bool { return queue.list.Empty() } // Size returns number of elements within the queue. -func (queue *Queue) Size() int { +func (queue *Queue[T]) Size() int { return queue.list.Size() } // Clear removes all elements from the queue. -func (queue *Queue) Clear() { +func (queue *Queue[T]) Clear() { queue.list.Clear() } // Values returns all elements in the queue (FIFO order). -func (queue *Queue) Values() []interface{} { +func (queue *Queue[T]) Values() []T { return queue.list.Values() } // String returns a string representation of container -func (queue *Queue) String() string { +func (queue *Queue[T]) String() string { str := "LinkedListQueue\n" values := []string{} for _, value := range queue.list.Values() { @@ -83,6 +83,6 @@ func (queue *Queue) String() string { } // Check that the index is within bounds of the list -func (queue *Queue) withinRange(index int) bool { +func (queue *Queue[T]) withinRange(index int) bool { return index >= 0 && index < queue.list.Size() } diff --git a/queues/linkedlistqueue/linkedlistqueue_test.go b/queues/linkedlistqueue/linkedlistqueue_test.go index e8e7c749..60ae2f75 100644 --- a/queues/linkedlistqueue/linkedlistqueue_test.go +++ b/queues/linkedlistqueue/linkedlistqueue_test.go @@ -6,13 +6,14 @@ package linkedlistqueue import ( "encoding/json" - "fmt" "strings" "testing" + + "github.com/emirpasic/gods/v2/testutils" ) func TestQueueEnqueue(t *testing.T) { - queue := New() + queue := New[int]() if actualValue := queue.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } @@ -20,7 +21,7 @@ func TestQueueEnqueue(t *testing.T) { queue.Enqueue(2) queue.Enqueue(3) - if actualValue := queue.Values(); actualValue[0].(int) != 1 || actualValue[1].(int) != 2 || actualValue[2].(int) != 3 { + if actualValue := queue.Values(); actualValue[0] != 1 || actualValue[1] != 2 || actualValue[2] != 3 { t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") } if actualValue := queue.Empty(); actualValue != false { @@ -35,8 +36,8 @@ func TestQueueEnqueue(t *testing.T) { } func TestQueuePeek(t *testing.T) { - queue := New() - if actualValue, ok := queue.Peek(); actualValue != nil || ok { + queue := New[int]() + if actualValue, ok := queue.Peek(); actualValue != 0 || ok { t.Errorf("Got %v expected %v", actualValue, nil) } queue.Enqueue(1) @@ -48,7 +49,7 @@ func TestQueuePeek(t *testing.T) { } func TestQueueDequeue(t *testing.T) { - queue := New() + queue := New[int]() queue.Enqueue(1) queue.Enqueue(2) queue.Enqueue(3) @@ -62,7 +63,7 @@ func TestQueueDequeue(t *testing.T) { if actualValue, ok := queue.Dequeue(); actualValue != 3 || !ok { t.Errorf("Got %v expected %v", actualValue, 3) } - if actualValue, ok := queue.Dequeue(); actualValue != nil || ok { + if actualValue, ok := queue.Dequeue(); actualValue != 0 || ok { t.Errorf("Got %v expected %v", actualValue, nil) } if actualValue := queue.Empty(); actualValue != true { @@ -74,7 +75,7 @@ func TestQueueDequeue(t *testing.T) { } func TestQueueIteratorOnEmpty(t *testing.T) { - queue := New() + queue := New[int]() it := queue.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty queue") @@ -82,7 +83,7 @@ func TestQueueIteratorOnEmpty(t *testing.T) { } func TestQueueIteratorNext(t *testing.T) { - queue := New() + queue := New[string]() queue.Enqueue("a") queue.Enqueue("b") queue.Enqueue("c") @@ -125,7 +126,7 @@ func TestQueueIteratorNext(t *testing.T) { } func TestQueueIteratorBegin(t *testing.T) { - queue := New() + queue := New[string]() it := queue.Iterator() it.Begin() queue.Enqueue("a") @@ -141,7 +142,7 @@ func TestQueueIteratorBegin(t *testing.T) { } func TestQueueIteratorFirst(t *testing.T) { - queue := New() + queue := New[string]() it := queue.Iterator() if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -159,13 +160,13 @@ func TestQueueIteratorFirst(t *testing.T) { func TestQueueIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // NextTo (empty) { - queue := New() + queue := New[string]() it := queue.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty queue") @@ -174,7 +175,7 @@ func TestQueueIteratorNextTo(t *testing.T) { // NextTo (not found) { - queue := New() + queue := New[string]() queue.Enqueue("xx") queue.Enqueue("yy") it := queue.Iterator() @@ -185,7 +186,7 @@ func TestQueueIteratorNextTo(t *testing.T) { // NextTo (found) { - queue := New() + queue := New[string]() queue.Enqueue("aa") queue.Enqueue("bb") queue.Enqueue("cc") @@ -194,13 +195,13 @@ func TestQueueIteratorNextTo(t *testing.T) { if !it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty queue") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Next() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + if index, value := it.Index(), it.Value(); index != 2 || value != "cc" { t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") } if it.Next() { @@ -210,16 +211,14 @@ func TestQueueIteratorNextTo(t *testing.T) { } func TestQueueSerialization(t *testing.T) { - queue := New() + queue := New[string]() queue.Enqueue("a") queue.Enqueue("b") queue.Enqueue("c") var err error assert := func() { - if actualValue, expectedValue := fmt.Sprintf("%s%s%s", queue.Values()...), "abc"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, queue.Values(), []string{"a", "b", "c"}) if actualValue, expectedValue := queue.Size(), 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } @@ -241,21 +240,22 @@ func TestQueueSerialization(t *testing.T) { t.Errorf("Got error %v", err) } - err = json.Unmarshal([]byte(`[1,2,3]`), &queue) + err = json.Unmarshal([]byte(`["a","b","c"]`), &queue) if err != nil { t.Errorf("Got error %v", err) } + assert() } func TestQueueString(t *testing.T) { - c := New() + c := New[int]() c.Enqueue(1) if !strings.HasPrefix(c.String(), "LinkedListQueue") { t.Errorf("String should start with container name") } } -func benchmarkEnqueue(b *testing.B, queue *Queue, size int) { +func benchmarkEnqueue(b *testing.B, queue *Queue[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { queue.Enqueue(n) @@ -263,7 +263,7 @@ func benchmarkEnqueue(b *testing.B, queue *Queue, size int) { } } -func benchmarkDequeue(b *testing.B, queue *Queue, size int) { +func benchmarkDequeue(b *testing.B, queue *Queue[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { queue.Dequeue() @@ -274,7 +274,7 @@ func benchmarkDequeue(b *testing.B, queue *Queue, size int) { func BenchmarkArrayQueueDequeue100(b *testing.B) { b.StopTimer() size := 100 - queue := New() + queue := New[int]() for n := 0; n < size; n++ { queue.Enqueue(n) } @@ -285,7 +285,7 @@ func BenchmarkArrayQueueDequeue100(b *testing.B) { func BenchmarkArrayQueueDequeue1000(b *testing.B) { b.StopTimer() size := 1000 - queue := New() + queue := New[int]() for n := 0; n < size; n++ { queue.Enqueue(n) } @@ -296,7 +296,7 @@ func BenchmarkArrayQueueDequeue1000(b *testing.B) { func BenchmarkArrayQueueDequeue10000(b *testing.B) { b.StopTimer() size := 10000 - queue := New() + queue := New[int]() for n := 0; n < size; n++ { queue.Enqueue(n) } @@ -307,7 +307,7 @@ func BenchmarkArrayQueueDequeue10000(b *testing.B) { func BenchmarkArrayQueueDequeue100000(b *testing.B) { b.StopTimer() size := 100000 - queue := New() + queue := New[int]() for n := 0; n < size; n++ { queue.Enqueue(n) } @@ -318,7 +318,7 @@ func BenchmarkArrayQueueDequeue100000(b *testing.B) { func BenchmarkArrayQueueEnqueue100(b *testing.B) { b.StopTimer() size := 100 - queue := New() + queue := New[int]() b.StartTimer() benchmarkEnqueue(b, queue, size) } @@ -326,7 +326,7 @@ func BenchmarkArrayQueueEnqueue100(b *testing.B) { func BenchmarkArrayQueueEnqueue1000(b *testing.B) { b.StopTimer() size := 1000 - queue := New() + queue := New[int]() for n := 0; n < size; n++ { queue.Enqueue(n) } @@ -337,7 +337,7 @@ func BenchmarkArrayQueueEnqueue1000(b *testing.B) { func BenchmarkArrayQueueEnqueue10000(b *testing.B) { b.StopTimer() size := 10000 - queue := New() + queue := New[int]() for n := 0; n < size; n++ { queue.Enqueue(n) } @@ -348,7 +348,7 @@ func BenchmarkArrayQueueEnqueue10000(b *testing.B) { func BenchmarkArrayQueueEnqueue100000(b *testing.B) { b.StopTimer() size := 100000 - queue := New() + queue := New[int]() for n := 0; n < size; n++ { queue.Enqueue(n) } diff --git a/queues/linkedlistqueue/serialization.go b/queues/linkedlistqueue/serialization.go index 2b34c8e4..8e9c157d 100644 --- a/queues/linkedlistqueue/serialization.go +++ b/queues/linkedlistqueue/serialization.go @@ -5,29 +5,29 @@ package linkedlistqueue import ( - "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*Queue)(nil) -var _ containers.JSONDeserializer = (*Queue)(nil) +var _ containers.JSONSerializer = (*Queue[int])(nil) +var _ containers.JSONDeserializer = (*Queue[int])(nil) // ToJSON outputs the JSON representation of the queue. -func (queue *Queue) ToJSON() ([]byte, error) { +func (queue *Queue[T]) ToJSON() ([]byte, error) { return queue.list.ToJSON() } // FromJSON populates the queue from the input JSON representation. -func (queue *Queue) FromJSON(data []byte) error { +func (queue *Queue[T]) FromJSON(data []byte) error { return queue.list.FromJSON(data) } // UnmarshalJSON @implements json.Unmarshaler -func (queue *Queue) UnmarshalJSON(bytes []byte) error { +func (queue *Queue[T]) UnmarshalJSON(bytes []byte) error { return queue.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (queue *Queue) MarshalJSON() ([]byte, error) { +func (queue *Queue[T]) MarshalJSON() ([]byte, error) { return queue.ToJSON() } diff --git a/queues/priorityqueue/iterator.go b/queues/priorityqueue/iterator.go index ea6181a2..1a55e07f 100644 --- a/queues/priorityqueue/iterator.go +++ b/queues/priorityqueue/iterator.go @@ -5,73 +5,73 @@ package priorityqueue import ( - "github.com/emirpasic/gods/containers" - "github.com/emirpasic/gods/trees/binaryheap" + "github.com/emirpasic/gods/v2/containers" + "github.com/emirpasic/gods/v2/trees/binaryheap" ) // Assert Iterator implementation -var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) +var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. -type Iterator struct { - iterator binaryheap.Iterator +type Iterator[T comparable] struct { + iterator *binaryheap.Iterator[T] } // Iterator returns a stateful iterator whose values can be fetched by an index. -func (queue *Queue) Iterator() Iterator { - return Iterator{iterator: queue.heap.Iterator()} +func (queue *Queue[T]) Iterator() *Iterator[T] { + return &Iterator[T]{iterator: queue.heap.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 { +func (iterator *Iterator[T]) 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 { +func (iterator *Iterator[T]) 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{} { +func (iterator *Iterator[T]) Value() T { return iterator.iterator.Value() } // Index returns the current element's index. // Does not modify the state of the iterator. -func (iterator *Iterator) Index() int { +func (iterator *Iterator[T]) 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() { +func (iterator *Iterator[T]) 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() { +func (iterator *Iterator[T]) 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 { +func (iterator *Iterator[T]) 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 { +func (iterator *Iterator[T]) Last() bool { return iterator.iterator.Last() } @@ -79,7 +79,7 @@ func (iterator *Iterator) Last() bool { // 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. -func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) NextTo(f func(index int, value T) bool) bool { return iterator.iterator.NextTo(f) } @@ -87,6 +87,6 @@ func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool // 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. -func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) PrevTo(f func(index int, value T) bool) bool { return iterator.iterator.PrevTo(f) } diff --git a/queues/priorityqueue/priorityqueue.go b/queues/priorityqueue/priorityqueue.go index 3a7e6f22..4427f75e 100644 --- a/queues/priorityqueue/priorityqueue.go +++ b/queues/priorityqueue/priorityqueue.go @@ -16,66 +16,72 @@ package priorityqueue import ( + "cmp" "fmt" - "github.com/emirpasic/gods/queues" - "github.com/emirpasic/gods/trees/binaryheap" - "github.com/emirpasic/gods/utils" "strings" + + "github.com/emirpasic/gods/v2/queues" + "github.com/emirpasic/gods/v2/trees/binaryheap" + "github.com/emirpasic/gods/v2/utils" ) // Assert Queue implementation -var _ queues.Queue = (*Queue)(nil) +var _ queues.Queue[int] = (*Queue[int])(nil) // Queue holds elements in an array-list -type Queue struct { - heap *binaryheap.Heap - Comparator utils.Comparator +type Queue[T comparable] struct { + heap *binaryheap.Heap[T] + Comparator utils.Comparator[T] +} + +func New[T cmp.Ordered]() *Queue[T] { + return NewWith[T](cmp.Compare[T]) } // NewWith instantiates a new empty queue with the custom comparator. -func NewWith(comparator utils.Comparator) *Queue { - return &Queue{heap: binaryheap.NewWith(comparator), Comparator: comparator} +func NewWith[T comparable](comparator utils.Comparator[T]) *Queue[T] { + return &Queue[T]{heap: binaryheap.NewWith(comparator), Comparator: comparator} } // Enqueue adds a value to the end of the queue -func (queue *Queue) Enqueue(value interface{}) { +func (queue *Queue[T]) Enqueue(value T) { queue.heap.Push(value) } // Dequeue removes first element of the queue and returns it, or nil if queue is empty. // Second return parameter is true, unless the queue was empty and there was nothing to dequeue. -func (queue *Queue) Dequeue() (value interface{}, ok bool) { +func (queue *Queue[T]) Dequeue() (value T, ok bool) { return queue.heap.Pop() } // Peek returns top element on the queue without removing it, or nil if queue is empty. // Second return parameter is true, unless the queue was empty and there was nothing to peek. -func (queue *Queue) Peek() (value interface{}, ok bool) { +func (queue *Queue[T]) Peek() (value T, ok bool) { return queue.heap.Peek() } // Empty returns true if queue does not contain any elements. -func (queue *Queue) Empty() bool { +func (queue *Queue[T]) Empty() bool { return queue.heap.Empty() } // Size returns number of elements within the queue. -func (queue *Queue) Size() int { +func (queue *Queue[T]) Size() int { return queue.heap.Size() } // Clear removes all elements from the queue. -func (queue *Queue) Clear() { +func (queue *Queue[T]) Clear() { queue.heap.Clear() } // Values returns all elements in the queue. -func (queue *Queue) Values() []interface{} { +func (queue *Queue[T]) Values() []T { return queue.heap.Values() } // String returns a string representation of container -func (queue *Queue) String() string { +func (queue *Queue[T]) String() string { str := "PriorityQueue\n" values := make([]string, queue.heap.Size(), queue.heap.Size()) for index, value := range queue.heap.Values() { diff --git a/queues/priorityqueue/priorityqueue_test.go b/queues/priorityqueue/priorityqueue_test.go index 6c0db896..1a21e571 100644 --- a/queues/priorityqueue/priorityqueue_test.go +++ b/queues/priorityqueue/priorityqueue_test.go @@ -5,9 +5,9 @@ package priorityqueue import ( + "cmp" "encoding/json" "fmt" - "github.com/emirpasic/gods/utils" "math/rand" "strings" "testing" @@ -23,15 +23,12 @@ func (element Element) String() string { } // Comparator function (sort by priority value in descending order) -func byPriority(a, b interface{}) int { - return -utils.IntComparator( // Note "-" for descending order - a.(Element).priority, - b.(Element).priority, - ) +func byPriority(a, b Element) int { + return -cmp.Compare(a.priority, b.priority) // Note "-" for descending order } func TestBinaryQueueEnqueue(t *testing.T) { - queue := NewWith(byPriority) + queue := NewWith[Element](byPriority) if actualValue := queue.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) @@ -53,15 +50,15 @@ func TestBinaryQueueEnqueue(t *testing.T) { value := it.Value() switch index { case 0: - if actualValue, expectedValue := value.(Element).name, "c"; actualValue != expectedValue { + if actualValue, expectedValue := value.name, "c"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } case 1: - if actualValue, expectedValue := value.(Element).name, "b"; actualValue != expectedValue { + if actualValue, expectedValue := value.name, "b"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } case 2: - if actualValue, expectedValue := value.(Element).name, "a"; actualValue != expectedValue { + if actualValue, expectedValue := value.name, "a"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } default: @@ -72,13 +69,13 @@ func TestBinaryQueueEnqueue(t *testing.T) { } } - if actualValue := queue.Values(); actualValue[0].(Element).name != "c" || actualValue[1].(Element).name != "b" || actualValue[2].(Element).name != "a" { + if actualValue := queue.Values(); actualValue[0].name != "c" || actualValue[1].name != "b" || actualValue[2].name != "a" { t.Errorf("Got %v expected %v", actualValue, `[{3 c} {2 b} {1 a}]`) } } func TestBinaryQueueEnqueueBulk(t *testing.T) { - queue := NewWith(utils.IntComparator) + queue := New[int]() queue.Enqueue(15) queue.Enqueue(20) @@ -109,7 +106,7 @@ func TestBinaryQueueEnqueueBulk(t *testing.T) { } func TestBinaryQueueDequeue(t *testing.T) { - queue := NewWith(utils.IntComparator) + queue := New[int]() if actualValue := queue.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) @@ -126,7 +123,7 @@ func TestBinaryQueueDequeue(t *testing.T) { if actualValue, ok := queue.Dequeue(); actualValue != 3 || !ok { t.Errorf("Got %v expected %v", actualValue, 3) } - if actualValue, ok := queue.Dequeue(); actualValue != nil || ok { + if actualValue, ok := queue.Dequeue(); actualValue != 0 || ok { t.Errorf("Got %v expected %v", actualValue, nil) } if actualValue := queue.Empty(); actualValue != true { @@ -138,7 +135,7 @@ func TestBinaryQueueDequeue(t *testing.T) { } func TestBinaryQueueRandom(t *testing.T) { - queue := NewWith(utils.IntComparator) + queue := New[int]() rand.Seed(3) for i := 0; i < 10000; i++ { @@ -149,7 +146,7 @@ func TestBinaryQueueRandom(t *testing.T) { prev, _ := queue.Dequeue() for !queue.Empty() { curr, _ := queue.Dequeue() - if prev.(int) > curr.(int) { + if prev > curr { t.Errorf("Queue property invalidated. prev: %v current: %v", prev, curr) } prev = curr @@ -157,7 +154,7 @@ func TestBinaryQueueRandom(t *testing.T) { } func TestBinaryQueueIteratorOnEmpty(t *testing.T) { - queue := NewWith(utils.IntComparator) + queue := New[int]() it := queue.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty queue") @@ -165,7 +162,7 @@ func TestBinaryQueueIteratorOnEmpty(t *testing.T) { } func TestBinaryQueueIteratorNext(t *testing.T) { - queue := NewWith(utils.IntComparator) + queue := New[int]() queue.Enqueue(3) queue.Enqueue(2) queue.Enqueue(1) @@ -202,7 +199,7 @@ func TestBinaryQueueIteratorNext(t *testing.T) { } func TestBinaryQueueIteratorPrev(t *testing.T) { - queue := NewWith(utils.IntComparator) + queue := New[int]() queue.Enqueue(3) queue.Enqueue(2) queue.Enqueue(1) @@ -241,7 +238,7 @@ func TestBinaryQueueIteratorPrev(t *testing.T) { } func TestBinaryQueueIteratorBegin(t *testing.T) { - queue := NewWith(utils.IntComparator) + queue := New[int]() it := queue.Iterator() it.Begin() queue.Enqueue(2) @@ -257,7 +254,7 @@ func TestBinaryQueueIteratorBegin(t *testing.T) { } func TestBinaryQueueIteratorEnd(t *testing.T) { - queue := NewWith(utils.IntComparator) + queue := New[int]() it := queue.Iterator() if index := it.Index(); index != -1 { @@ -284,7 +281,7 @@ func TestBinaryQueueIteratorEnd(t *testing.T) { } func TestBinaryQueueIteratorFirst(t *testing.T) { - queue := NewWith(utils.IntComparator) + queue := New[int]() it := queue.Iterator() if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -301,7 +298,7 @@ func TestBinaryQueueIteratorFirst(t *testing.T) { } func TestBinaryQueueIteratorLast(t *testing.T) { - tree := NewWith(utils.IntComparator) + tree := New[int]() it := tree.Iterator() if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -319,13 +316,13 @@ func TestBinaryQueueIteratorLast(t *testing.T) { func TestBinaryQueueIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // NextTo (empty) { - tree := NewWith(utils.StringComparator) + tree := New[string]() it := tree.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") @@ -334,7 +331,7 @@ func TestBinaryQueueIteratorNextTo(t *testing.T) { // NextTo (not found) { - tree := NewWith(utils.StringComparator) + tree := New[string]() tree.Enqueue("xx") tree.Enqueue("yy") it := tree.Iterator() @@ -345,7 +342,7 @@ func TestBinaryQueueIteratorNextTo(t *testing.T) { // NextTo (found) { - tree := NewWith(utils.StringComparator) + tree := New[string]() tree.Enqueue("aa") tree.Enqueue("bb") tree.Enqueue("cc") @@ -354,13 +351,13 @@ func TestBinaryQueueIteratorNextTo(t *testing.T) { if !it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Next() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + if index, value := it.Index(), it.Value(); index != 2 || value != "cc" { t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") } if it.Next() { @@ -371,13 +368,13 @@ func TestBinaryQueueIteratorNextTo(t *testing.T) { func TestBinaryQueueIteratorPrevTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // PrevTo (empty) { - tree := NewWith(utils.StringComparator) + tree := New[string]() it := tree.Iterator() it.End() for it.PrevTo(seek) { @@ -387,7 +384,7 @@ func TestBinaryQueueIteratorPrevTo(t *testing.T) { // PrevTo (not found) { - tree := NewWith(utils.StringComparator) + tree := New[string]() tree.Enqueue("xx") tree.Enqueue("yy") it := tree.Iterator() @@ -399,7 +396,7 @@ func TestBinaryQueueIteratorPrevTo(t *testing.T) { // PrevTo (found) { - tree := NewWith(utils.StringComparator) + tree := New[string]() tree.Enqueue("aa") tree.Enqueue("bb") tree.Enqueue("cc") @@ -408,13 +405,13 @@ func TestBinaryQueueIteratorPrevTo(t *testing.T) { if !it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty list") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Prev() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "aa" { + if index, value := it.Index(), it.Value(); index != 0 || value != "aa" { t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") } if it.Prev() { @@ -424,7 +421,7 @@ func TestBinaryQueueIteratorPrevTo(t *testing.T) { } func TestBinaryQueueSerialization(t *testing.T) { - queue := NewWith(utils.StringComparator) + queue := New[string]() queue.Enqueue("c") queue.Enqueue("b") @@ -432,7 +429,7 @@ func TestBinaryQueueSerialization(t *testing.T) { var err error assert := func() { - if actualValue := queue.Values(); actualValue[0].(string) != "a" || actualValue[1].(string) != "b" || actualValue[2].(string) != "c" { + if actualValue := queue.Values(); actualValue[0] != "a" || actualValue[1] != "b" || actualValue[2] != "c" { t.Errorf("Got %v expected %v", actualValue, "[1,3,2]") } if actualValue := queue.Size(); actualValue != 3 { @@ -459,21 +456,22 @@ func TestBinaryQueueSerialization(t *testing.T) { t.Errorf("Got error %v", err) } - err = json.Unmarshal([]byte(`[1,2,3]`), &queue) + err = json.Unmarshal([]byte(`["a","b","c"]`), &queue) if err != nil { t.Errorf("Got error %v", err) } + assert() } func TestBTreeString(t *testing.T) { - c := NewWith(byPriority) + c := New[int]() c.Enqueue(1) if !strings.HasPrefix(c.String(), "PriorityQueue") { t.Errorf("String should start with container name") } } -func benchmarkEnqueue(b *testing.B, queue *Queue, size int) { +func benchmarkEnqueue(b *testing.B, queue *Queue[Element], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { queue.Enqueue(Element{}) @@ -481,7 +479,7 @@ func benchmarkEnqueue(b *testing.B, queue *Queue, size int) { } } -func benchmarkDequeue(b *testing.B, queue *Queue, size int) { +func benchmarkDequeue(b *testing.B, queue *Queue[Element], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { queue.Dequeue() @@ -492,7 +490,7 @@ func benchmarkDequeue(b *testing.B, queue *Queue, size int) { func BenchmarkBinaryQueueDequeue100(b *testing.B) { b.StopTimer() size := 100 - queue := NewWith(byPriority) + queue := NewWith[Element](byPriority) for n := 0; n < size; n++ { queue.Enqueue(Element{}) } @@ -503,7 +501,7 @@ func BenchmarkBinaryQueueDequeue100(b *testing.B) { func BenchmarkBinaryQueueDequeue1000(b *testing.B) { b.StopTimer() size := 1000 - queue := NewWith(byPriority) + queue := NewWith[Element](byPriority) for n := 0; n < size; n++ { queue.Enqueue(Element{}) } @@ -514,7 +512,7 @@ func BenchmarkBinaryQueueDequeue1000(b *testing.B) { func BenchmarkBinaryQueueDequeue10000(b *testing.B) { b.StopTimer() size := 10000 - queue := NewWith(byPriority) + queue := NewWith[Element](byPriority) for n := 0; n < size; n++ { queue.Enqueue(Element{}) } @@ -525,7 +523,7 @@ func BenchmarkBinaryQueueDequeue10000(b *testing.B) { func BenchmarkBinaryQueueDequeue100000(b *testing.B) { b.StopTimer() size := 100000 - queue := NewWith(byPriority) + queue := NewWith[Element](byPriority) for n := 0; n < size; n++ { queue.Enqueue(Element{}) } @@ -544,7 +542,7 @@ func BenchmarkBinaryQueueEnqueue100(b *testing.B) { func BenchmarkBinaryQueueEnqueue1000(b *testing.B) { b.StopTimer() size := 1000 - queue := NewWith(byPriority) + queue := NewWith[Element](byPriority) for n := 0; n < size; n++ { queue.Enqueue(Element{}) } @@ -555,7 +553,7 @@ func BenchmarkBinaryQueueEnqueue1000(b *testing.B) { func BenchmarkBinaryQueueEnqueue10000(b *testing.B) { b.StopTimer() size := 10000 - queue := NewWith(byPriority) + queue := NewWith[Element](byPriority) for n := 0; n < size; n++ { queue.Enqueue(Element{}) } @@ -566,7 +564,7 @@ func BenchmarkBinaryQueueEnqueue10000(b *testing.B) { func BenchmarkBinaryQueueEnqueue100000(b *testing.B) { b.StopTimer() size := 100000 - queue := NewWith(byPriority) + queue := NewWith[Element](byPriority) for n := 0; n < size; n++ { queue.Enqueue(Element{}) } diff --git a/queues/priorityqueue/serialization.go b/queues/priorityqueue/serialization.go index 6072a168..f22548df 100644 --- a/queues/priorityqueue/serialization.go +++ b/queues/priorityqueue/serialization.go @@ -5,29 +5,29 @@ package priorityqueue import ( - "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*Queue)(nil) -var _ containers.JSONDeserializer = (*Queue)(nil) +var _ containers.JSONSerializer = (*Queue[int])(nil) +var _ containers.JSONDeserializer = (*Queue[int])(nil) // ToJSON outputs the JSON representation of the queue. -func (queue *Queue) ToJSON() ([]byte, error) { +func (queue *Queue[T]) ToJSON() ([]byte, error) { return queue.heap.ToJSON() } // FromJSON populates the queue from the input JSON representation. -func (queue *Queue) FromJSON(data []byte) error { +func (queue *Queue[T]) FromJSON(data []byte) error { return queue.heap.FromJSON(data) } // UnmarshalJSON @implements json.Unmarshaler -func (queue *Queue) UnmarshalJSON(bytes []byte) error { +func (queue *Queue[T]) UnmarshalJSON(bytes []byte) error { return queue.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (queue *Queue) MarshalJSON() ([]byte, error) { +func (queue *Queue[T]) MarshalJSON() ([]byte, error) { return queue.ToJSON() } diff --git a/queues/queues.go b/queues/queues.go index 80239d48..6f2deb43 100644 --- a/queues/queues.go +++ b/queues/queues.go @@ -10,15 +10,15 @@ // Reference: https://en.wikipedia.org/wiki/Queue_(abstract_data_type) package queues -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Queue interface that all queues implement -type Queue interface { - Enqueue(value interface{}) - Dequeue() (value interface{}, ok bool) - Peek() (value interface{}, ok bool) +type Queue[T comparable] interface { + Enqueue(value T) + Dequeue() (value T, ok bool) + Peek() (value T, ok bool) - containers.Container + containers.Container[T] // Empty() bool // Size() int // Clear() diff --git a/sets/hashset/hashset.go b/sets/hashset/hashset.go index 94399288..32523abf 100644 --- a/sets/hashset/hashset.go +++ b/sets/hashset/hashset.go @@ -11,23 +11,24 @@ package hashset import ( "fmt" - "github.com/emirpasic/gods/sets" "strings" + + "github.com/emirpasic/gods/v2/sets" ) // Assert Set implementation -var _ sets.Set = (*Set)(nil) +var _ sets.Set[int] = (*Set[int])(nil) // Set holds elements in go's native map -type Set struct { - items map[interface{}]struct{} +type Set[T comparable] struct { + items map[T]struct{} } var itemExists = struct{}{} // New instantiates a new empty set and adds the passed values, if any, to the set -func New(values ...interface{}) *Set { - set := &Set{items: make(map[interface{}]struct{})} +func New[T comparable](values ...T) *Set[T] { + set := &Set[T]{items: make(map[T]struct{})} if len(values) > 0 { set.Add(values...) } @@ -35,14 +36,14 @@ func New(values ...interface{}) *Set { } // Add adds the items (one or more) to the set. -func (set *Set) Add(items ...interface{}) { +func (set *Set[T]) Add(items ...T) { for _, item := range items { set.items[item] = itemExists } } // Remove removes the items (one or more) from the set. -func (set *Set) Remove(items ...interface{}) { +func (set *Set[T]) Remove(items ...T) { for _, item := range items { delete(set.items, item) } @@ -51,7 +52,7 @@ func (set *Set) Remove(items ...interface{}) { // 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 { +func (set *Set[T]) Contains(items ...T) bool { for _, item := range items { if _, contains := set.items[item]; !contains { return false @@ -61,23 +62,23 @@ func (set *Set) Contains(items ...interface{}) bool { } // Empty returns true if set does not contain any elements. -func (set *Set) Empty() bool { +func (set *Set[T]) Empty() bool { return set.Size() == 0 } // Size returns number of elements within the set. -func (set *Set) Size() int { +func (set *Set[T]) Size() int { return len(set.items) } // Clear clears all values in the set. -func (set *Set) Clear() { - set.items = make(map[interface{}]struct{}) +func (set *Set[T]) Clear() { + set.items = make(map[T]struct{}) } // Values returns all items in the set. -func (set *Set) Values() []interface{} { - values := make([]interface{}, set.Size()) +func (set *Set[T]) Values() []T { + values := make([]T, set.Size()) count := 0 for item := range set.items { values[count] = item @@ -87,7 +88,7 @@ func (set *Set) Values() []interface{} { } // String returns a string representation of container -func (set *Set) String() string { +func (set *Set[T]) String() string { str := "HashSet\n" items := []string{} for k := range set.items { @@ -100,8 +101,8 @@ func (set *Set) String() string { // Intersection returns the intersection between two sets. // The new set consists of all elements that are both in "set" and "another". // Ref: https://en.wikipedia.org/wiki/Intersection_(set_theory) -func (set *Set) Intersection(another *Set) *Set { - result := New() +func (set *Set[T]) Intersection(another *Set[T]) *Set[T] { + result := New[T]() // Iterate over smaller set (optimization) if set.Size() <= another.Size() { @@ -124,8 +125,8 @@ func (set *Set) Intersection(another *Set) *Set { // Union returns the union of two sets. // The new set consists of all elements that are in "set" or "another" (possibly both). // Ref: https://en.wikipedia.org/wiki/Union_(set_theory) -func (set *Set) Union(another *Set) *Set { - result := New() +func (set *Set[T]) Union(another *Set[T]) *Set[T] { + result := New[T]() for item := range set.items { result.Add(item) @@ -140,8 +141,8 @@ func (set *Set) Union(another *Set) *Set { // Difference returns the difference between two sets. // The new set consists of all elements that are in "set" but not in "another". // Ref: https://proofwiki.org/wiki/Definition:Set_Difference -func (set *Set) Difference(another *Set) *Set { - result := New() +func (set *Set[T]) Difference(another *Set[T]) *Set[T] { + result := New[T]() for item := range set.items { if _, contains := another.items[item]; !contains { diff --git a/sets/hashset/hashset_test.go b/sets/hashset/hashset_test.go index fe516b79..21d84297 100644 --- a/sets/hashset/hashset_test.go +++ b/sets/hashset/hashset_test.go @@ -28,7 +28,7 @@ func TestSetNew(t *testing.T) { } func TestSetAdd(t *testing.T) { - set := New() + set := New[int]() set.Add() set.Add(1) set.Add(2) @@ -43,7 +43,7 @@ func TestSetAdd(t *testing.T) { } func TestSetContains(t *testing.T) { - set := New() + set := New[int]() set.Add(3, 1, 2) set.Add(2, 3) set.Add() @@ -62,7 +62,7 @@ func TestSetContains(t *testing.T) { } func TestSetRemove(t *testing.T) { - set := New() + set := New[int]() set.Add(3, 1, 2) set.Remove() if actualValue := set.Size(); actualValue != 3 { @@ -82,7 +82,7 @@ func TestSetRemove(t *testing.T) { } func TestSetSerialization(t *testing.T) { - set := New() + set := New[string]() set.Add("a", "b", "c") var err error @@ -111,14 +111,15 @@ func TestSetSerialization(t *testing.T) { t.Errorf("Got error %v", err) } - err = json.Unmarshal([]byte(`[1,2,3]`), &set) + err = json.Unmarshal([]byte(`["a","b","c"]`), &set) if err != nil { t.Errorf("Got error %v", err) } + assert() } func TestSetString(t *testing.T) { - c := New() + c := New[int]() c.Add(1) if !strings.HasPrefix(c.String(), "HashSet") { t.Errorf("String should start with container name") @@ -126,8 +127,8 @@ func TestSetString(t *testing.T) { } func TestSetIntersection(t *testing.T) { - set := New() - another := New() + set := New[string]() + another := New[string]() intersection := set.Intersection(another) if actualValue, expectedValue := intersection.Size(), 0; actualValue != expectedValue { @@ -148,8 +149,8 @@ func TestSetIntersection(t *testing.T) { } func TestSetUnion(t *testing.T) { - set := New() - another := New() + set := New[string]() + another := New[string]() union := set.Union(another) if actualValue, expectedValue := union.Size(), 0; actualValue != expectedValue { @@ -170,8 +171,8 @@ func TestSetUnion(t *testing.T) { } func TestSetDifference(t *testing.T) { - set := New() - another := New() + set := New[string]() + another := New[string]() difference := set.Difference(another) if actualValue, expectedValue := difference.Size(), 0; actualValue != expectedValue { @@ -191,7 +192,7 @@ func TestSetDifference(t *testing.T) { } } -func benchmarkContains(b *testing.B, set *Set, size int) { +func benchmarkContains(b *testing.B, set *Set[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { set.Contains(n) @@ -199,7 +200,7 @@ func benchmarkContains(b *testing.B, set *Set, size int) { } } -func benchmarkAdd(b *testing.B, set *Set, size int) { +func benchmarkAdd(b *testing.B, set *Set[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { set.Add(n) @@ -207,7 +208,7 @@ func benchmarkAdd(b *testing.B, set *Set, size int) { } } -func benchmarkRemove(b *testing.B, set *Set, size int) { +func benchmarkRemove(b *testing.B, set *Set[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { set.Remove(n) @@ -218,7 +219,7 @@ func benchmarkRemove(b *testing.B, set *Set, size int) { func BenchmarkHashSetContains100(b *testing.B) { b.StopTimer() size := 100 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -229,7 +230,7 @@ func BenchmarkHashSetContains100(b *testing.B) { func BenchmarkHashSetContains1000(b *testing.B) { b.StopTimer() size := 1000 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -240,7 +241,7 @@ func BenchmarkHashSetContains1000(b *testing.B) { func BenchmarkHashSetContains10000(b *testing.B) { b.StopTimer() size := 10000 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -251,7 +252,7 @@ func BenchmarkHashSetContains10000(b *testing.B) { func BenchmarkHashSetContains100000(b *testing.B) { b.StopTimer() size := 100000 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -262,7 +263,7 @@ func BenchmarkHashSetContains100000(b *testing.B) { func BenchmarkHashSetAdd100(b *testing.B) { b.StopTimer() size := 100 - set := New() + set := New[int]() b.StartTimer() benchmarkAdd(b, set, size) } @@ -270,7 +271,7 @@ func BenchmarkHashSetAdd100(b *testing.B) { func BenchmarkHashSetAdd1000(b *testing.B) { b.StopTimer() size := 1000 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -281,7 +282,7 @@ func BenchmarkHashSetAdd1000(b *testing.B) { func BenchmarkHashSetAdd10000(b *testing.B) { b.StopTimer() size := 10000 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -292,7 +293,7 @@ func BenchmarkHashSetAdd10000(b *testing.B) { func BenchmarkHashSetAdd100000(b *testing.B) { b.StopTimer() size := 100000 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -303,7 +304,7 @@ func BenchmarkHashSetAdd100000(b *testing.B) { func BenchmarkHashSetRemove100(b *testing.B) { b.StopTimer() size := 100 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -314,7 +315,7 @@ func BenchmarkHashSetRemove100(b *testing.B) { func BenchmarkHashSetRemove1000(b *testing.B) { b.StopTimer() size := 1000 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -325,7 +326,7 @@ func BenchmarkHashSetRemove1000(b *testing.B) { func BenchmarkHashSetRemove10000(b *testing.B) { b.StopTimer() size := 10000 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -336,7 +337,7 @@ func BenchmarkHashSetRemove10000(b *testing.B) { func BenchmarkHashSetRemove100000(b *testing.B) { b.StopTimer() size := 100000 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } diff --git a/sets/hashset/serialization.go b/sets/hashset/serialization.go index 583d129d..4b81ce2f 100644 --- a/sets/hashset/serialization.go +++ b/sets/hashset/serialization.go @@ -6,21 +6,22 @@ package hashset import ( "encoding/json" - "github.com/emirpasic/gods/containers" + + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*Set)(nil) -var _ containers.JSONDeserializer = (*Set)(nil) +var _ containers.JSONSerializer = (*Set[int])(nil) +var _ containers.JSONDeserializer = (*Set[int])(nil) // ToJSON outputs the JSON representation of the set. -func (set *Set) ToJSON() ([]byte, error) { +func (set *Set[T]) ToJSON() ([]byte, error) { return json.Marshal(set.Values()) } // FromJSON populates the set from the input JSON representation. -func (set *Set) FromJSON(data []byte) error { - elements := []interface{}{} +func (set *Set[T]) FromJSON(data []byte) error { + var elements []T err := json.Unmarshal(data, &elements) if err == nil { set.Clear() @@ -30,11 +31,11 @@ func (set *Set) FromJSON(data []byte) error { } // UnmarshalJSON @implements json.Unmarshaler -func (set *Set) UnmarshalJSON(bytes []byte) error { +func (set *Set[T]) UnmarshalJSON(bytes []byte) error { return set.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (set *Set) MarshalJSON() ([]byte, error) { +func (set *Set[T]) MarshalJSON() ([]byte, error) { return set.ToJSON() } diff --git a/sets/linkedhashset/enumerable.go b/sets/linkedhashset/enumerable.go index fc855722..2e51edfe 100644 --- a/sets/linkedhashset/enumerable.go +++ b/sets/linkedhashset/enumerable.go @@ -4,13 +4,13 @@ package linkedhashset -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Assert Enumerable implementation -var _ containers.EnumerableWithIndex = (*Set)(nil) +var _ containers.EnumerableWithIndex[int] = (*Set[int])(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{})) { +func (set *Set[T]) Each(f func(index int, value T)) { iterator := set.Iterator() for iterator.Next() { f(iterator.Index(), iterator.Value()) @@ -19,8 +19,8 @@ func (set *Set) Each(f func(index int, value interface{})) { // 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() +func (set *Set[T]) Map(f func(index int, value T) T) *Set[T] { + newSet := New[T]() iterator := set.Iterator() for iterator.Next() { newSet.Add(f(iterator.Index(), iterator.Value())) @@ -29,8 +29,8 @@ func (set *Set) Map(f func(index int, value interface{}) interface{}) *Set { } // 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() +func (set *Set[T]) Select(f func(index int, value T) bool) *Set[T] { + newSet := New[T]() iterator := set.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { @@ -42,7 +42,7 @@ func (set *Set) Select(f func(index int, value interface{}) bool) *Set { // 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 { +func (set *Set[T]) Any(f func(index int, value T) bool) bool { iterator := set.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { @@ -54,7 +54,7 @@ func (set *Set) Any(f func(index int, value interface{}) bool) bool { // 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 { +func (set *Set[T]) All(f func(index int, value T) bool) bool { iterator := set.Iterator() for iterator.Next() { if !f(iterator.Index(), iterator.Value()) { @@ -67,12 +67,13 @@ func (set *Set) All(f func(index int, value interface{}) 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. -func (set *Set) Find(f func(index int, value interface{}) bool) (int, interface{}) { +func (set *Set[T]) Find(f func(index int, value T) bool) (int, T) { iterator := set.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { return iterator.Index(), iterator.Value() } } - return -1, nil + var t T + return -1, t } diff --git a/sets/linkedhashset/iterator.go b/sets/linkedhashset/iterator.go index aa793841..378ec853 100644 --- a/sets/linkedhashset/iterator.go +++ b/sets/linkedhashset/iterator.go @@ -5,73 +5,73 @@ package linkedhashset import ( - "github.com/emirpasic/gods/containers" - "github.com/emirpasic/gods/lists/doublylinkedlist" + "github.com/emirpasic/gods/v2/containers" + "github.com/emirpasic/gods/v2/lists/doublylinkedlist" ) // Assert Iterator implementation -var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) +var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator holding the iterator's state -type Iterator struct { - iterator doublylinkedlist.Iterator +type Iterator[T comparable] struct { + iterator doublylinkedlist.Iterator[T] } // Iterator returns a stateful iterator whose values can be fetched by an index. -func (set *Set) Iterator() Iterator { - return Iterator{iterator: set.ordering.Iterator()} +func (set *Set[T]) Iterator() Iterator[T] { + return Iterator[T]{iterator: set.ordering.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 { +func (iterator *Iterator[T]) 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 { +func (iterator *Iterator[T]) 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{} { +func (iterator *Iterator[T]) Value() T { return iterator.iterator.Value() } // Index returns the current element's index. // Does not modify the state of the iterator. -func (iterator *Iterator) Index() int { +func (iterator *Iterator[T]) 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() { +func (iterator *Iterator[T]) 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() { +func (iterator *Iterator[T]) 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 { +func (iterator *Iterator[T]) 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 { +func (iterator *Iterator[T]) Last() bool { return iterator.iterator.Last() } @@ -79,7 +79,7 @@ func (iterator *Iterator) Last() bool { // 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. -func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) NextTo(f func(index int, value T) bool) bool { for iterator.Next() { index, value := iterator.Index(), iterator.Value() if f(index, value) { @@ -93,7 +93,7 @@ func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool // 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. -func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) PrevTo(f func(index int, value T) bool) bool { for iterator.Prev() { index, value := iterator.Index(), iterator.Value() if f(index, value) { diff --git a/sets/linkedhashset/linkedhashset.go b/sets/linkedhashset/linkedhashset.go index 3bf4e5fe..ea681a9f 100644 --- a/sets/linkedhashset/linkedhashset.go +++ b/sets/linkedhashset/linkedhashset.go @@ -15,27 +15,28 @@ package linkedhashset import ( "fmt" - "github.com/emirpasic/gods/lists/doublylinkedlist" - "github.com/emirpasic/gods/sets" "strings" + + "github.com/emirpasic/gods/v2/lists/doublylinkedlist" + "github.com/emirpasic/gods/v2/sets" ) // Assert Set implementation -var _ sets.Set = (*Set)(nil) +var _ sets.Set[int] = (*Set[int])(nil) // Set holds elements in go's native map -type Set struct { - table map[interface{}]struct{} - ordering *doublylinkedlist.List +type Set[T comparable] struct { + table map[T]struct{} + ordering *doublylinkedlist.List[T] } var itemExists = struct{}{} // New instantiates a new empty set and adds the passed values, if any, to the set -func New(values ...interface{}) *Set { - set := &Set{ - table: make(map[interface{}]struct{}), - ordering: doublylinkedlist.New(), +func New[T comparable](values ...T) *Set[T] { + set := &Set[T]{ + table: make(map[T]struct{}), + ordering: doublylinkedlist.New[T](), } if len(values) > 0 { set.Add(values...) @@ -45,7 +46,7 @@ func New(values ...interface{}) *Set { // 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{}) { +func (set *Set[T]) Add(items ...T) { for _, item := range items { if _, contains := set.table[item]; !contains { set.table[item] = itemExists @@ -56,7 +57,7 @@ func (set *Set) Add(items ...interface{}) { // Remove removes the items (one or more) from the set. // Slow operation, worst-case O(n^2). -func (set *Set) Remove(items ...interface{}) { +func (set *Set[T]) Remove(items ...T) { for _, item := range items { if _, contains := set.table[item]; contains { delete(set.table, item) @@ -69,7 +70,7 @@ func (set *Set) Remove(items ...interface{}) { // 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 { +func (set *Set[T]) Contains(items ...T) bool { for _, item := range items { if _, contains := set.table[item]; !contains { return false @@ -79,24 +80,24 @@ func (set *Set) Contains(items ...interface{}) bool { } // Empty returns true if set does not contain any elements. -func (set *Set) Empty() bool { +func (set *Set[T]) Empty() bool { return set.Size() == 0 } // Size returns number of elements within the set. -func (set *Set) Size() int { +func (set *Set[T]) Size() int { return set.ordering.Size() } // Clear clears all values in the set. -func (set *Set) Clear() { - set.table = make(map[interface{}]struct{}) +func (set *Set[T]) Clear() { + set.table = make(map[T]struct{}) set.ordering.Clear() } // Values returns all items in the set. -func (set *Set) Values() []interface{} { - values := make([]interface{}, set.Size()) +func (set *Set[T]) Values() []T { + values := make([]T, set.Size()) it := set.Iterator() for it.Next() { values[it.Index()] = it.Value() @@ -105,7 +106,7 @@ func (set *Set) Values() []interface{} { } // String returns a string representation of container -func (set *Set) String() string { +func (set *Set[T]) String() string { str := "LinkedHashSet\n" items := []string{} it := set.Iterator() @@ -119,8 +120,8 @@ func (set *Set) String() string { // Intersection returns the intersection between two sets. // The new set consists of all elements that are both in "set" and "another". // Ref: https://en.wikipedia.org/wiki/Intersection_(set_theory) -func (set *Set) Intersection(another *Set) *Set { - result := New() +func (set *Set[T]) Intersection(another *Set[T]) *Set[T] { + result := New[T]() // Iterate over smaller set (optimization) if set.Size() <= another.Size() { @@ -143,8 +144,8 @@ func (set *Set) Intersection(another *Set) *Set { // Union returns the union of two sets. // The new set consists of all elements that are in "set" or "another" (possibly both). // Ref: https://en.wikipedia.org/wiki/Union_(set_theory) -func (set *Set) Union(another *Set) *Set { - result := New() +func (set *Set[T]) Union(another *Set[T]) *Set[T] { + result := New[T]() for item := range set.table { result.Add(item) @@ -159,8 +160,8 @@ func (set *Set) Union(another *Set) *Set { // Difference returns the difference between two sets. // The new set consists of all elements that are in "set" but not in "another". // Ref: https://proofwiki.org/wiki/Definition:Set_Difference -func (set *Set) Difference(another *Set) *Set { - result := New() +func (set *Set[T]) Difference(another *Set[T]) *Set[T] { + result := New[T]() for item := range set.table { if _, contains := another.table[item]; !contains { diff --git a/sets/linkedhashset/linkedhashset_test.go b/sets/linkedhashset/linkedhashset_test.go index 3f857ea9..a3a8fac4 100644 --- a/sets/linkedhashset/linkedhashset_test.go +++ b/sets/linkedhashset/linkedhashset_test.go @@ -13,20 +13,23 @@ import ( func TestSetNew(t *testing.T) { set := New(2, 1) + if actualValue := set.Size(); actualValue != 2 { t.Errorf("Got %v expected %v", actualValue, 2) } - values := set.Values() - if actualValue := values[0]; actualValue != 2 { - t.Errorf("Got %v expected %v", actualValue, 2) + if actualValue := set.Contains(1); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) } - if actualValue := values[1]; actualValue != 1 { - t.Errorf("Got %v expected %v", actualValue, 1) + if actualValue := set.Contains(2); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + if actualValue := set.Contains(3); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, true) } } func TestSetAdd(t *testing.T) { - set := New() + set := New[int]() set.Add() set.Add(1) set.Add(2) @@ -41,7 +44,7 @@ func TestSetAdd(t *testing.T) { } func TestSetContains(t *testing.T) { - set := New() + set := New[int]() set.Add(3, 1, 2) set.Add(2, 3) set.Add() @@ -60,7 +63,7 @@ func TestSetContains(t *testing.T) { } func TestSetRemove(t *testing.T) { - set := New() + set := New[int]() set.Add(3, 1, 2) set.Remove() if actualValue := set.Size(); actualValue != 3 { @@ -80,9 +83,9 @@ func TestSetRemove(t *testing.T) { } func TestSetEach(t *testing.T) { - set := New() + set := New[string]() set.Add("c", "a", "b") - set.Each(func(index int, value interface{}) { + set.Each(func(index int, value string) { switch index { case 0: if actualValue, expectedValue := value, "c"; actualValue != expectedValue { @@ -103,10 +106,10 @@ func TestSetEach(t *testing.T) { } func TestSetMap(t *testing.T) { - set := New() + set := New[string]() set.Add("c", "a", "b") - mappedSet := set.Map(func(index int, value interface{}) interface{} { - return "mapped: " + value.(string) + mappedSet := set.Map(func(index int, value string) string { + return "mapped: " + value }) if actualValue, expectedValue := mappedSet.Contains("mapped: c", "mapped: b", "mapped: a"), true; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -120,10 +123,10 @@ func TestSetMap(t *testing.T) { } func TestSetSelect(t *testing.T) { - set := New() + set := New[string]() set.Add("c", "a", "b") - selectedSet := set.Select(func(index int, value interface{}) bool { - return value.(string) >= "a" && value.(string) <= "b" + selectedSet := set.Select(func(index int, value string) bool { + return value >= "a" && value <= "b" }) if actualValue, expectedValue := selectedSet.Contains("a", "b"), true; actualValue != expectedValue { fmt.Println("A: ", selectedSet.Contains("b")) @@ -138,16 +141,16 @@ func TestSetSelect(t *testing.T) { } func TestSetAny(t *testing.T) { - set := New() + set := New[string]() set.Add("c", "a", "b") - any := set.Any(func(index int, value interface{}) bool { - return value.(string) == "c" + any := set.Any(func(index int, value string) bool { + return value == "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" + any = set.Any(func(index int, value string) bool { + return value == "x" }) if any != false { t.Errorf("Got %v expected %v", any, false) @@ -155,16 +158,16 @@ func TestSetAny(t *testing.T) { } func TestSetAll(t *testing.T) { - set := New() + set := New[string]() set.Add("c", "a", "b") - all := set.All(func(index int, value interface{}) bool { - return value.(string) >= "a" && value.(string) <= "c" + all := set.All(func(index int, value string) bool { + return value >= "a" && value <= "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" + all = set.All(func(index int, value string) bool { + return value >= "a" && value <= "b" }) if all != false { t.Errorf("Got %v expected %v", all, false) @@ -172,29 +175,29 @@ func TestSetAll(t *testing.T) { } func TestSetFind(t *testing.T) { - set := New() + set := New[string]() set.Add("c", "a", "b") - foundIndex, foundValue := set.Find(func(index int, value interface{}) bool { - return value.(string) == "c" + foundIndex, foundValue := set.Find(func(index int, value string) bool { + return value == "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" + foundIndex, foundValue = set.Find(func(index int, value string) bool { + return value == "x" }) - if foundValue != nil || foundIndex != -1 { + if foundValue != "" || foundIndex != -1 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil) } } func TestSetChaining(t *testing.T) { - set := New() + set := New[string]() set.Add("c", "a", "b") } func TestSetIteratorPrevOnEmpty(t *testing.T) { - set := New() + set := New[string]() it := set.Iterator() for it.Prev() { t.Errorf("Shouldn't iterate on empty set") @@ -202,7 +205,7 @@ func TestSetIteratorPrevOnEmpty(t *testing.T) { } func TestSetIteratorNext(t *testing.T) { - set := New() + set := New[string]() set.Add("c", "a", "b") it := set.Iterator() count := 0 @@ -236,7 +239,7 @@ func TestSetIteratorNext(t *testing.T) { } func TestSetIteratorPrev(t *testing.T) { - set := New() + set := New[string]() set.Add("c", "a", "b") it := set.Iterator() for it.Prev() { @@ -272,7 +275,7 @@ func TestSetIteratorPrev(t *testing.T) { } func TestSetIteratorBegin(t *testing.T) { - set := New() + set := New[string]() it := set.Iterator() it.Begin() set.Add("a", "b", "c") @@ -286,7 +289,7 @@ func TestSetIteratorBegin(t *testing.T) { } func TestSetIteratorEnd(t *testing.T) { - set := New() + set := New[string]() it := set.Iterator() if index := it.Index(); index != -1 { @@ -311,7 +314,7 @@ func TestSetIteratorEnd(t *testing.T) { } func TestSetIteratorFirst(t *testing.T) { - set := New() + set := New[string]() set.Add("a", "b", "c") it := set.Iterator() if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { @@ -323,7 +326,7 @@ func TestSetIteratorFirst(t *testing.T) { } func TestSetIteratorLast(t *testing.T) { - set := New() + set := New[string]() set.Add("a", "b", "c") it := set.Iterator() if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue { @@ -336,13 +339,13 @@ func TestSetIteratorLast(t *testing.T) { func TestSetIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // NextTo (empty) { - set := New() + set := New[string]() it := set.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty set") @@ -351,7 +354,7 @@ func TestSetIteratorNextTo(t *testing.T) { // NextTo (not found) { - set := New() + set := New[string]() set.Add("xx", "yy") it := set.Iterator() for it.NextTo(seek) { @@ -361,20 +364,20 @@ func TestSetIteratorNextTo(t *testing.T) { // NextTo (found) { - set := New() + set := New[string]() set.Add("aa", "bb", "cc") it := set.Iterator() it.Begin() if !it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty set") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Next() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + if index, value := it.Index(), it.Value(); index != 2 || value != "cc" { t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") } if it.Next() { @@ -385,13 +388,13 @@ func TestSetIteratorNextTo(t *testing.T) { func TestSetIteratorPrevTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // PrevTo (empty) { - set := New() + set := New[string]() it := set.Iterator() it.End() for it.PrevTo(seek) { @@ -401,7 +404,7 @@ func TestSetIteratorPrevTo(t *testing.T) { // PrevTo (not found) { - set := New() + set := New[string]() set.Add("xx", "yy") it := set.Iterator() it.End() @@ -412,20 +415,20 @@ func TestSetIteratorPrevTo(t *testing.T) { // PrevTo (found) { - set := New() + set := New[string]() set.Add("aa", "bb", "cc") it := set.Iterator() it.End() if !it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty set") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Prev() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "aa" { + if index, value := it.Index(), it.Value(); index != 0 || value != "aa" { t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") } if it.Prev() { @@ -435,7 +438,7 @@ func TestSetIteratorPrevTo(t *testing.T) { } func TestSetSerialization(t *testing.T) { - set := New() + set := New[string]() set.Add("a", "b", "c") var err error @@ -464,14 +467,15 @@ func TestSetSerialization(t *testing.T) { t.Errorf("Got error %v", err) } - err = json.Unmarshal([]byte(`[1,2,3]`), &set) + err = json.Unmarshal([]byte(`["a","b","c"]`), &set) if err != nil { t.Errorf("Got error %v", err) } + assert() } func TestSetString(t *testing.T) { - c := New() + c := New[int]() c.Add(1) if !strings.HasPrefix(c.String(), "LinkedHashSet") { t.Errorf("String should start with container name") @@ -479,8 +483,8 @@ func TestSetString(t *testing.T) { } func TestSetIntersection(t *testing.T) { - set := New() - another := New() + set := New[string]() + another := New[string]() intersection := set.Intersection(another) if actualValue, expectedValue := intersection.Size(), 0; actualValue != expectedValue { @@ -501,8 +505,8 @@ func TestSetIntersection(t *testing.T) { } func TestSetUnion(t *testing.T) { - set := New() - another := New() + set := New[string]() + another := New[string]() union := set.Union(another) if actualValue, expectedValue := union.Size(), 0; actualValue != expectedValue { @@ -523,8 +527,8 @@ func TestSetUnion(t *testing.T) { } func TestSetDifference(t *testing.T) { - set := New() - another := New() + set := New[string]() + another := New[string]() difference := set.Difference(another) if actualValue, expectedValue := difference.Size(), 0; actualValue != expectedValue { @@ -544,7 +548,7 @@ func TestSetDifference(t *testing.T) { } } -func benchmarkContains(b *testing.B, set *Set, size int) { +func benchmarkContains(b *testing.B, set *Set[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { set.Contains(n) @@ -552,7 +556,7 @@ func benchmarkContains(b *testing.B, set *Set, size int) { } } -func benchmarkAdd(b *testing.B, set *Set, size int) { +func benchmarkAdd(b *testing.B, set *Set[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { set.Add(n) @@ -560,7 +564,7 @@ func benchmarkAdd(b *testing.B, set *Set, size int) { } } -func benchmarkRemove(b *testing.B, set *Set, size int) { +func benchmarkRemove(b *testing.B, set *Set[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { set.Remove(n) @@ -571,7 +575,7 @@ func benchmarkRemove(b *testing.B, set *Set, size int) { func BenchmarkHashSetContains100(b *testing.B) { b.StopTimer() size := 100 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -582,7 +586,7 @@ func BenchmarkHashSetContains100(b *testing.B) { func BenchmarkHashSetContains1000(b *testing.B) { b.StopTimer() size := 1000 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -593,7 +597,7 @@ func BenchmarkHashSetContains1000(b *testing.B) { func BenchmarkHashSetContains10000(b *testing.B) { b.StopTimer() size := 10000 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -604,7 +608,7 @@ func BenchmarkHashSetContains10000(b *testing.B) { func BenchmarkHashSetContains100000(b *testing.B) { b.StopTimer() size := 100000 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -615,7 +619,7 @@ func BenchmarkHashSetContains100000(b *testing.B) { func BenchmarkHashSetAdd100(b *testing.B) { b.StopTimer() size := 100 - set := New() + set := New[int]() b.StartTimer() benchmarkAdd(b, set, size) } @@ -623,7 +627,7 @@ func BenchmarkHashSetAdd100(b *testing.B) { func BenchmarkHashSetAdd1000(b *testing.B) { b.StopTimer() size := 1000 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -634,7 +638,7 @@ func BenchmarkHashSetAdd1000(b *testing.B) { func BenchmarkHashSetAdd10000(b *testing.B) { b.StopTimer() size := 10000 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -645,7 +649,7 @@ func BenchmarkHashSetAdd10000(b *testing.B) { func BenchmarkHashSetAdd100000(b *testing.B) { b.StopTimer() size := 100000 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -656,7 +660,7 @@ func BenchmarkHashSetAdd100000(b *testing.B) { func BenchmarkHashSetRemove100(b *testing.B) { b.StopTimer() size := 100 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -667,7 +671,7 @@ func BenchmarkHashSetRemove100(b *testing.B) { func BenchmarkHashSetRemove1000(b *testing.B) { b.StopTimer() size := 1000 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -678,7 +682,7 @@ func BenchmarkHashSetRemove1000(b *testing.B) { func BenchmarkHashSetRemove10000(b *testing.B) { b.StopTimer() size := 10000 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -689,7 +693,7 @@ func BenchmarkHashSetRemove10000(b *testing.B) { func BenchmarkHashSetRemove100000(b *testing.B) { b.StopTimer() size := 100000 - set := New() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } diff --git a/sets/linkedhashset/serialization.go b/sets/linkedhashset/serialization.go index ab2f3b4d..c29e1cbd 100644 --- a/sets/linkedhashset/serialization.go +++ b/sets/linkedhashset/serialization.go @@ -6,21 +6,22 @@ package linkedhashset import ( "encoding/json" - "github.com/emirpasic/gods/containers" + + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*Set)(nil) -var _ containers.JSONDeserializer = (*Set)(nil) +var _ containers.JSONSerializer = (*Set[int])(nil) +var _ containers.JSONDeserializer = (*Set[int])(nil) // ToJSON outputs the JSON representation of the set. -func (set *Set) ToJSON() ([]byte, error) { +func (set *Set[T]) ToJSON() ([]byte, error) { return json.Marshal(set.Values()) } // FromJSON populates the set from the input JSON representation. -func (set *Set) FromJSON(data []byte) error { - elements := []interface{}{} +func (set *Set[T]) FromJSON(data []byte) error { + var elements []T err := json.Unmarshal(data, &elements) if err == nil { set.Clear() @@ -30,11 +31,11 @@ func (set *Set) FromJSON(data []byte) error { } // UnmarshalJSON @implements json.Unmarshaler -func (set *Set) UnmarshalJSON(bytes []byte) error { +func (set *Set[T]) UnmarshalJSON(bytes []byte) error { return set.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (set *Set) MarshalJSON() ([]byte, error) { +func (set *Set[T]) MarshalJSON() ([]byte, error) { return set.ToJSON() } diff --git a/sets/sets.go b/sets/sets.go index 9641951a..e63bb5fe 100644 --- a/sets/sets.go +++ b/sets/sets.go @@ -9,18 +9,17 @@ // Reference: https://en.wikipedia.org/wiki/Set_%28abstract_data_type%29 package sets -import "github.com/emirpasic/gods/containers" +import ( + "github.com/emirpasic/gods/v2/containers" +) // Set interface that all sets implement -type Set interface { - Add(elements ...interface{}) - Remove(elements ...interface{}) - Contains(elements ...interface{}) bool - // Intersection(another *Set) *Set - // Union(another *Set) *Set - // Difference(another *Set) *Set +type Set[T comparable] interface { + Add(elements ...T) + Remove(elements ...T) + Contains(elements ...T) bool - containers.Container + containers.Container[T] // Empty() bool // Size() int // Clear() diff --git a/sets/treeset/enumerable.go b/sets/treeset/enumerable.go index c774834a..b41a495a 100644 --- a/sets/treeset/enumerable.go +++ b/sets/treeset/enumerable.go @@ -5,15 +5,15 @@ package treeset import ( - "github.com/emirpasic/gods/containers" - rbt "github.com/emirpasic/gods/trees/redblacktree" + "github.com/emirpasic/gods/v2/containers" + rbt "github.com/emirpasic/gods/v2/trees/redblacktree" ) // Assert Enumerable implementation -var _ containers.EnumerableWithIndex = (*Set)(nil) +var _ containers.EnumerableWithIndex[int] = (*Set[int])(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{})) { +func (set *Set[T]) Each(f func(index int, value T)) { iterator := set.Iterator() for iterator.Next() { f(iterator.Index(), iterator.Value()) @@ -22,8 +22,8 @@ func (set *Set) Each(f func(index int, value interface{})) { // 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 := &Set{tree: rbt.NewWith(set.tree.Comparator)} +func (set *Set[T]) Map(f func(index int, value T) T) *Set[T] { + newSet := &Set[T]{tree: rbt.NewWith[T, struct{}](set.tree.Comparator)} iterator := set.Iterator() for iterator.Next() { newSet.Add(f(iterator.Index(), iterator.Value())) @@ -32,8 +32,8 @@ func (set *Set) Map(f func(index int, value interface{}) interface{}) *Set { } // 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 := &Set{tree: rbt.NewWith(set.tree.Comparator)} +func (set *Set[T]) Select(f func(index int, value T) bool) *Set[T] { + newSet := &Set[T]{tree: rbt.NewWith[T, struct{}](set.tree.Comparator)} iterator := set.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { @@ -45,7 +45,7 @@ func (set *Set) Select(f func(index int, value interface{}) bool) *Set { // 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 { +func (set *Set[T]) Any(f func(index int, value T) bool) bool { iterator := set.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { @@ -57,7 +57,7 @@ func (set *Set) Any(f func(index int, value interface{}) bool) bool { // 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 { +func (set *Set[T]) All(f func(index int, value T) bool) bool { iterator := set.Iterator() for iterator.Next() { if !f(iterator.Index(), iterator.Value()) { @@ -70,12 +70,13 @@ func (set *Set) All(f func(index int, value interface{}) 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. -func (set *Set) Find(f func(index int, value interface{}) bool) (int, interface{}) { +func (set *Set[T]) Find(f func(index int, value T) bool) (int, T) { iterator := set.Iterator() for iterator.Next() { if f(iterator.Index(), iterator.Value()) { return iterator.Index(), iterator.Value() } } - return -1, nil + var t T + return -1, t } diff --git a/sets/treeset/iterator.go b/sets/treeset/iterator.go index 88a0bea7..435b46b0 100644 --- a/sets/treeset/iterator.go +++ b/sets/treeset/iterator.go @@ -5,30 +5,30 @@ package treeset import ( - "github.com/emirpasic/gods/containers" - rbt "github.com/emirpasic/gods/trees/redblacktree" + "github.com/emirpasic/gods/v2/containers" + rbt "github.com/emirpasic/gods/v2/trees/redblacktree" ) // Assert Iterator implementation -var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) +var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. -type Iterator struct { +type Iterator[T comparable] struct { index int - iterator rbt.Iterator - tree *rbt.Tree + iterator *rbt.Iterator[T, struct{}] + tree *rbt.Tree[T, struct{}] } // Iterator holding the iterator's state -func (set *Set) Iterator() Iterator { - return Iterator{index: -1, iterator: set.tree.Iterator(), tree: set.tree} +func (set *Set[T]) Iterator() Iterator[T] { + return Iterator[T]{index: -1, iterator: set.tree.Iterator(), tree: set.tree} } // 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 { +func (iterator *Iterator[T]) Next() bool { if iterator.index < iterator.tree.Size() { iterator.index++ } @@ -38,7 +38,7 @@ func (iterator *Iterator) Next() bool { // 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 { +func (iterator *Iterator[T]) Prev() bool { if iterator.index >= 0 { iterator.index-- } @@ -47,26 +47,26 @@ func (iterator *Iterator) Prev() bool { // Value returns the current element's value. // Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { +func (iterator *Iterator[T]) Value() T { return iterator.iterator.Key() } // Index returns the current element's index. // Does not modify the state of the iterator. -func (iterator *Iterator) Index() int { +func (iterator *Iterator[T]) Index() int { return 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() { +func (iterator *Iterator[T]) Begin() { iterator.index = -1 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() { +func (iterator *Iterator[T]) End() { iterator.index = iterator.tree.Size() iterator.iterator.End() } @@ -74,7 +74,7 @@ func (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 { +func (iterator *Iterator[T]) First() bool { iterator.Begin() return iterator.Next() } @@ -82,7 +82,7 @@ func (iterator *Iterator) First() bool { // 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 { +func (iterator *Iterator[T]) Last() bool { iterator.End() return iterator.Prev() } @@ -91,7 +91,7 @@ func (iterator *Iterator) Last() bool { // 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. -func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) NextTo(f func(index int, value T) bool) bool { for iterator.Next() { index, value := iterator.Index(), iterator.Value() if f(index, value) { @@ -105,7 +105,7 @@ func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool // 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. -func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) PrevTo(f func(index int, value T) bool) bool { for iterator.Prev() { index, value := iterator.Index(), iterator.Value() if f(index, value) { diff --git a/sets/treeset/serialization.go b/sets/treeset/serialization.go index 76d049dd..5543fd36 100644 --- a/sets/treeset/serialization.go +++ b/sets/treeset/serialization.go @@ -6,21 +6,22 @@ package treeset import ( "encoding/json" - "github.com/emirpasic/gods/containers" + + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*Set)(nil) -var _ containers.JSONDeserializer = (*Set)(nil) +var _ containers.JSONSerializer = (*Set[int])(nil) +var _ containers.JSONDeserializer = (*Set[int])(nil) // ToJSON outputs the JSON representation of the set. -func (set *Set) ToJSON() ([]byte, error) { +func (set *Set[T]) ToJSON() ([]byte, error) { return json.Marshal(set.Values()) } // FromJSON populates the set from the input JSON representation. -func (set *Set) FromJSON(data []byte) error { - elements := []interface{}{} +func (set *Set[T]) FromJSON(data []byte) error { + var elements []T err := json.Unmarshal(data, &elements) if err == nil { set.Clear() @@ -30,11 +31,11 @@ func (set *Set) FromJSON(data []byte) error { } // UnmarshalJSON @implements json.Unmarshaler -func (set *Set) UnmarshalJSON(bytes []byte) error { +func (set *Set[T]) UnmarshalJSON(bytes []byte) error { return set.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (set *Set) MarshalJSON() ([]byte, error) { +func (set *Set[T]) MarshalJSON() ([]byte, error) { return set.ToJSON() } diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 3507cc90..6b63a7e1 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -10,45 +10,33 @@ package treeset import ( + "cmp" "fmt" - "github.com/emirpasic/gods/sets" - rbt "github.com/emirpasic/gods/trees/redblacktree" - "github.com/emirpasic/gods/utils" "reflect" "strings" + + "github.com/emirpasic/gods/v2/sets" + rbt "github.com/emirpasic/gods/v2/trees/redblacktree" + "github.com/emirpasic/gods/v2/utils" ) // Assert Set implementation -var _ sets.Set = (*Set)(nil) +var _ sets.Set[int] = (*Set[int])(nil) // Set holds elements in a red-black tree -type Set struct { - tree *rbt.Tree +type Set[T comparable] struct { + tree *rbt.Tree[T, struct{}] } var itemExists = struct{}{} -// NewWith instantiates a new empty set with the custom comparator. -func NewWith(comparator utils.Comparator, values ...interface{}) *Set { - set := &Set{tree: rbt.NewWith(comparator)} - if len(values) > 0 { - set.Add(values...) - } - return set +func New[T cmp.Ordered](values ...T) *Set[T] { + return NewWith[T](cmp.Compare[T], values...) } -// NewWithIntComparator instantiates a new empty set with the IntComparator, i.e. keys are of type int. -func NewWithIntComparator(values ...interface{}) *Set { - set := &Set{tree: rbt.NewWithIntComparator()} - if len(values) > 0 { - set.Add(values...) - } - return set -} - -// NewWithStringComparator instantiates a new empty set with the StringComparator, i.e. keys are of type string. -func NewWithStringComparator(values ...interface{}) *Set { - set := &Set{tree: rbt.NewWithStringComparator()} +// NewWith instantiates a new empty set with the custom comparator. +func NewWith[T comparable](comparator utils.Comparator[T], values ...T) *Set[T] { + set := &Set[T]{tree: rbt.NewWith[T, struct{}](comparator)} if len(values) > 0 { set.Add(values...) } @@ -56,14 +44,14 @@ func NewWithStringComparator(values ...interface{}) *Set { } // Add adds the items (one or more) to the set. -func (set *Set) Add(items ...interface{}) { +func (set *Set[T]) Add(items ...T) { for _, item := range items { set.tree.Put(item, itemExists) } } // Remove removes the items (one or more) from the set. -func (set *Set) Remove(items ...interface{}) { +func (set *Set[T]) Remove(items ...T) { for _, item := range items { set.tree.Remove(item) } @@ -72,7 +60,7 @@ func (set *Set) Remove(items ...interface{}) { // Contains checks weather 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 { +func (set *Set[T]) Contains(items ...T) bool { for _, item := range items { if _, contains := set.tree.Get(item); !contains { return false @@ -82,27 +70,27 @@ func (set *Set) Contains(items ...interface{}) bool { } // Empty returns true if set does not contain any elements. -func (set *Set) Empty() bool { +func (set *Set[T]) Empty() bool { return set.tree.Size() == 0 } // Size returns number of elements within the set. -func (set *Set) Size() int { +func (set *Set[T]) Size() int { return set.tree.Size() } // Clear clears all values in the set. -func (set *Set) Clear() { +func (set *Set[T]) Clear() { set.tree.Clear() } // Values returns all items in the set. -func (set *Set) Values() []interface{} { +func (set *Set[T]) Values() []T { return set.tree.Keys() } // String returns a string representation of container -func (set *Set) String() string { +func (set *Set[T]) String() string { str := "TreeSet\n" items := []string{} for _, v := range set.tree.Keys() { @@ -116,7 +104,7 @@ func (set *Set) String() string { // The new set consists of all elements that are both in "set" and "another". // The two sets should have the same comparators, otherwise the result is empty set. // Ref: https://en.wikipedia.org/wiki/Intersection_(set_theory) -func (set *Set) Intersection(another *Set) *Set { +func (set *Set[T]) Intersection(another *Set[T]) *Set[T] { result := NewWith(set.tree.Comparator) setComparator := reflect.ValueOf(set.tree.Comparator) @@ -147,7 +135,7 @@ func (set *Set) Intersection(another *Set) *Set { // The new set consists of all elements that are in "set" or "another" (possibly both). // The two sets should have the same comparators, otherwise the result is empty set. // Ref: https://en.wikipedia.org/wiki/Union_(set_theory) -func (set *Set) Union(another *Set) *Set { +func (set *Set[T]) Union(another *Set[T]) *Set[T] { result := NewWith(set.tree.Comparator) setComparator := reflect.ValueOf(set.tree.Comparator) @@ -170,7 +158,7 @@ func (set *Set) Union(another *Set) *Set { // The two sets should have the same comparators, otherwise the result is empty set. // The new set consists of all elements that are in "set" but not in "another". // Ref: https://proofwiki.org/wiki/Definition:Set_Difference -func (set *Set) Difference(another *Set) *Set { +func (set *Set[T]) Difference(another *Set[T]) *Set[T] { result := NewWith(set.tree.Comparator) setComparator := reflect.ValueOf(set.tree.Comparator) diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index 9e7c6707..709ed84d 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -9,10 +9,12 @@ import ( "fmt" "strings" "testing" + + "github.com/emirpasic/gods/v2/testutils" ) func TestSetNew(t *testing.T) { - set := NewWithIntComparator(2, 1) + set := New[int](2, 1) if actualValue := set.Size(); actualValue != 2 { t.Errorf("Got %v expected %v", actualValue, 2) } @@ -26,7 +28,7 @@ func TestSetNew(t *testing.T) { } func TestSetAdd(t *testing.T) { - set := NewWithIntComparator() + set := New[int]() set.Add() set.Add(1) set.Add(2) @@ -38,13 +40,11 @@ func TestSetAdd(t *testing.T) { if actualValue := set.Size(); actualValue != 3 { t.Errorf("Got %v expected %v", actualValue, 3) } - if actualValue, expectedValue := fmt.Sprintf("%d%d%d", set.Values()...), "123"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, set.Values(), []int{1, 2, 3}) } func TestSetContains(t *testing.T) { - set := NewWithIntComparator() + set := New[int]() set.Add(3, 1, 2) if actualValue := set.Contains(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) @@ -61,7 +61,7 @@ func TestSetContains(t *testing.T) { } func TestSetRemove(t *testing.T) { - set := NewWithIntComparator() + set := New[int]() set.Add(3, 1, 2) set.Remove() if actualValue := set.Size(); actualValue != 3 { @@ -81,9 +81,9 @@ func TestSetRemove(t *testing.T) { } func TestSetEach(t *testing.T) { - set := NewWithStringComparator() + set := New[string]() set.Add("c", "a", "b") - set.Each(func(index int, value interface{}) { + set.Each(func(index int, value string) { switch index { case 0: if actualValue, expectedValue := value, "a"; actualValue != expectedValue { @@ -104,10 +104,10 @@ func TestSetEach(t *testing.T) { } func TestSetMap(t *testing.T) { - set := NewWithStringComparator() + set := New[string]() set.Add("c", "a", "b") - mappedSet := set.Map(func(index int, value interface{}) interface{} { - return "mapped: " + value.(string) + mappedSet := set.Map(func(index int, value string) string { + return "mapped: " + value }) if actualValue, expectedValue := mappedSet.Contains("mapped: a", "mapped: b", "mapped: c"), true; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -121,10 +121,10 @@ func TestSetMap(t *testing.T) { } func TestSetSelect(t *testing.T) { - set := NewWithStringComparator() + set := New[string]() set.Add("c", "a", "b") - selectedSet := set.Select(func(index int, value interface{}) bool { - return value.(string) >= "a" && value.(string) <= "b" + selectedSet := set.Select(func(index int, value string) bool { + return value >= "a" && value <= "b" }) if actualValue, expectedValue := selectedSet.Contains("a", "b"), true; actualValue != expectedValue { fmt.Println("A: ", selectedSet.Contains("b")) @@ -139,16 +139,16 @@ func TestSetSelect(t *testing.T) { } func TestSetAny(t *testing.T) { - set := NewWithStringComparator() + set := New[string]() set.Add("c", "a", "b") - any := set.Any(func(index int, value interface{}) bool { - return value.(string) == "c" + any := set.Any(func(index int, value string) bool { + return value == "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" + any = set.Any(func(index int, value string) bool { + return value == "x" }) if any != false { t.Errorf("Got %v expected %v", any, false) @@ -156,16 +156,16 @@ func TestSetAny(t *testing.T) { } func TestSetAll(t *testing.T) { - set := NewWithStringComparator() + set := New[string]() set.Add("c", "a", "b") - all := set.All(func(index int, value interface{}) bool { - return value.(string) >= "a" && value.(string) <= "c" + all := set.All(func(index int, value string) bool { + return value >= "a" && value <= "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" + all = set.All(func(index int, value string) bool { + return value >= "a" && value <= "b" }) if all != false { t.Errorf("Got %v expected %v", all, false) @@ -173,29 +173,29 @@ func TestSetAll(t *testing.T) { } func TestSetFind(t *testing.T) { - set := NewWithStringComparator() + set := New[string]() set.Add("c", "a", "b") - foundIndex, foundValue := set.Find(func(index int, value interface{}) bool { - return value.(string) == "c" + foundIndex, foundValue := set.Find(func(index int, value string) bool { + return value == "c" }) if foundValue != "c" || foundIndex != 2 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, "c", 2) } - foundIndex, foundValue = set.Find(func(index int, value interface{}) bool { - return value.(string) == "x" + foundIndex, foundValue = set.Find(func(index int, value string) bool { + return value == "x" }) - if foundValue != nil || foundIndex != -1 { + if foundValue != "" || foundIndex != -1 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil) } } func TestSetChaining(t *testing.T) { - set := NewWithStringComparator() + set := New[string]() set.Add("c", "a", "b") } func TestSetIteratorNextOnEmpty(t *testing.T) { - set := NewWithStringComparator() + set := New[string]() it := set.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty set") @@ -203,7 +203,7 @@ func TestSetIteratorNextOnEmpty(t *testing.T) { } func TestSetIteratorPrevOnEmpty(t *testing.T) { - set := NewWithStringComparator() + set := New[string]() it := set.Iterator() for it.Prev() { t.Errorf("Shouldn't iterate on empty set") @@ -211,7 +211,7 @@ func TestSetIteratorPrevOnEmpty(t *testing.T) { } func TestSetIteratorNext(t *testing.T) { - set := NewWithStringComparator() + set := New[string]() set.Add("c", "a", "b") it := set.Iterator() count := 0 @@ -245,7 +245,7 @@ func TestSetIteratorNext(t *testing.T) { } func TestSetIteratorPrev(t *testing.T) { - set := NewWithStringComparator() + set := New[string]() set.Add("c", "a", "b") it := set.Iterator() for it.Prev() { @@ -281,7 +281,7 @@ func TestSetIteratorPrev(t *testing.T) { } func TestSetIteratorBegin(t *testing.T) { - set := NewWithStringComparator() + set := New[string]() it := set.Iterator() it.Begin() set.Add("a", "b", "c") @@ -295,7 +295,7 @@ func TestSetIteratorBegin(t *testing.T) { } func TestSetIteratorEnd(t *testing.T) { - set := NewWithStringComparator() + set := New[string]() it := set.Iterator() if index := it.Index(); index != -1 { @@ -320,7 +320,7 @@ func TestSetIteratorEnd(t *testing.T) { } func TestSetIteratorFirst(t *testing.T) { - set := NewWithStringComparator() + set := New[string]() set.Add("a", "b", "c") it := set.Iterator() if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { @@ -332,7 +332,7 @@ func TestSetIteratorFirst(t *testing.T) { } func TestSetIteratorLast(t *testing.T) { - set := NewWithStringComparator() + set := New[string]() set.Add("a", "b", "c") it := set.Iterator() if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue { @@ -345,13 +345,13 @@ func TestSetIteratorLast(t *testing.T) { func TestSetIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // NextTo (empty) { - set := NewWithStringComparator() + set := New[string]() it := set.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty set") @@ -360,7 +360,7 @@ func TestSetIteratorNextTo(t *testing.T) { // NextTo (not found) { - set := NewWithStringComparator() + set := New[string]() set.Add("xx", "yy") it := set.Iterator() for it.NextTo(seek) { @@ -370,20 +370,20 @@ func TestSetIteratorNextTo(t *testing.T) { // NextTo (found) { - set := NewWithStringComparator() + set := New[string]() set.Add("aa", "bb", "cc") it := set.Iterator() it.Begin() if !it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty set") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Next() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + if index, value := it.Index(), it.Value(); index != 2 || value != "cc" { t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") } if it.Next() { @@ -394,13 +394,13 @@ func TestSetIteratorNextTo(t *testing.T) { func TestSetIteratorPrevTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // PrevTo (empty) { - set := NewWithStringComparator() + set := New[string]() it := set.Iterator() it.End() for it.PrevTo(seek) { @@ -410,7 +410,7 @@ func TestSetIteratorPrevTo(t *testing.T) { // PrevTo (not found) { - set := NewWithStringComparator() + set := New[string]() set.Add("xx", "yy") it := set.Iterator() it.End() @@ -421,20 +421,20 @@ func TestSetIteratorPrevTo(t *testing.T) { // PrevTo (found) { - set := NewWithStringComparator() + set := New[string]() set.Add("aa", "bb", "cc") it := set.Iterator() it.End() if !it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty set") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Prev() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "aa" { + if index, value := it.Index(), it.Value(); index != 0 || value != "aa" { t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") } if it.Prev() { @@ -444,7 +444,7 @@ func TestSetIteratorPrevTo(t *testing.T) { } func TestSetSerialization(t *testing.T) { - set := NewWithStringComparator() + set := New[string]() set.Add("a", "b", "c") var err error @@ -480,7 +480,7 @@ func TestSetSerialization(t *testing.T) { } func TestSetString(t *testing.T) { - c := NewWithIntComparator() + c := New[int]() c.Add(1) if !strings.HasPrefix(c.String(), "TreeSet") { t.Errorf("String should start with container name") @@ -488,19 +488,8 @@ func TestSetString(t *testing.T) { } func TestSetIntersection(t *testing.T) { - { - set := NewWithStringComparator() - another := NewWithIntComparator() - set.Add("a", "b", "c", "d") - another.Add(1, 2, 3, 4) - difference := set.Difference(another) - if actualValue, expectedValue := difference.Size(), 0; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - } - - set := NewWithStringComparator() - another := NewWithStringComparator() + set := New[string]() + another := New[string]() intersection := set.Intersection(another) if actualValue, expectedValue := intersection.Size(), 0; actualValue != expectedValue { @@ -521,19 +510,8 @@ func TestSetIntersection(t *testing.T) { } func TestSetUnion(t *testing.T) { - { - set := NewWithStringComparator() - another := NewWithIntComparator() - set.Add("a", "b", "c", "d") - another.Add(1, 2, 3, 4) - difference := set.Difference(another) - if actualValue, expectedValue := difference.Size(), 0; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - } - - set := NewWithStringComparator() - another := NewWithStringComparator() + set := New[string]() + another := New[string]() union := set.Union(another) if actualValue, expectedValue := union.Size(), 0; actualValue != expectedValue { @@ -554,19 +532,8 @@ func TestSetUnion(t *testing.T) { } func TestSetDifference(t *testing.T) { - { - set := NewWithStringComparator() - another := NewWithIntComparator() - set.Add("a", "b", "c", "d") - another.Add(1, 2, 3, 4) - difference := set.Difference(another) - if actualValue, expectedValue := difference.Size(), 0; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - } - - set := NewWithStringComparator() - another := NewWithStringComparator() + set := New[string]() + another := New[string]() difference := set.Difference(another) if actualValue, expectedValue := difference.Size(), 0; actualValue != expectedValue { @@ -586,7 +553,7 @@ func TestSetDifference(t *testing.T) { } } -func benchmarkContains(b *testing.B, set *Set, size int) { +func benchmarkContains(b *testing.B, set *Set[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { set.Contains(n) @@ -594,7 +561,7 @@ func benchmarkContains(b *testing.B, set *Set, size int) { } } -func benchmarkAdd(b *testing.B, set *Set, size int) { +func benchmarkAdd(b *testing.B, set *Set[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { set.Add(n) @@ -602,7 +569,7 @@ func benchmarkAdd(b *testing.B, set *Set, size int) { } } -func benchmarkRemove(b *testing.B, set *Set, size int) { +func benchmarkRemove(b *testing.B, set *Set[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { set.Remove(n) @@ -613,7 +580,7 @@ func benchmarkRemove(b *testing.B, set *Set, size int) { func BenchmarkTreeSetContains100(b *testing.B) { b.StopTimer() size := 100 - set := NewWithIntComparator() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -624,7 +591,7 @@ func BenchmarkTreeSetContains100(b *testing.B) { func BenchmarkTreeSetContains1000(b *testing.B) { b.StopTimer() size := 1000 - set := NewWithIntComparator() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -635,7 +602,7 @@ func BenchmarkTreeSetContains1000(b *testing.B) { func BenchmarkTreeSetContains10000(b *testing.B) { b.StopTimer() size := 10000 - set := NewWithIntComparator() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -646,7 +613,7 @@ func BenchmarkTreeSetContains10000(b *testing.B) { func BenchmarkTreeSetContains100000(b *testing.B) { b.StopTimer() size := 100000 - set := NewWithIntComparator() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -657,7 +624,7 @@ func BenchmarkTreeSetContains100000(b *testing.B) { func BenchmarkTreeSetAdd100(b *testing.B) { b.StopTimer() size := 100 - set := NewWithIntComparator() + set := New[int]() b.StartTimer() benchmarkAdd(b, set, size) } @@ -665,7 +632,7 @@ func BenchmarkTreeSetAdd100(b *testing.B) { func BenchmarkTreeSetAdd1000(b *testing.B) { b.StopTimer() size := 1000 - set := NewWithIntComparator() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -676,7 +643,7 @@ func BenchmarkTreeSetAdd1000(b *testing.B) { func BenchmarkTreeSetAdd10000(b *testing.B) { b.StopTimer() size := 10000 - set := NewWithIntComparator() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -687,7 +654,7 @@ func BenchmarkTreeSetAdd10000(b *testing.B) { func BenchmarkTreeSetAdd100000(b *testing.B) { b.StopTimer() size := 100000 - set := NewWithIntComparator() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -698,7 +665,7 @@ func BenchmarkTreeSetAdd100000(b *testing.B) { func BenchmarkTreeSetRemove100(b *testing.B) { b.StopTimer() size := 100 - set := NewWithIntComparator() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -709,7 +676,7 @@ func BenchmarkTreeSetRemove100(b *testing.B) { func BenchmarkTreeSetRemove1000(b *testing.B) { b.StopTimer() size := 1000 - set := NewWithIntComparator() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -720,7 +687,7 @@ func BenchmarkTreeSetRemove1000(b *testing.B) { func BenchmarkTreeSetRemove10000(b *testing.B) { b.StopTimer() size := 10000 - set := NewWithIntComparator() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } @@ -731,7 +698,7 @@ func BenchmarkTreeSetRemove10000(b *testing.B) { func BenchmarkTreeSetRemove100000(b *testing.B) { b.StopTimer() size := 100000 - set := NewWithIntComparator() + set := New[int]() for n := 0; n < size; n++ { set.Add(n) } diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index 78c3dda3..ec80cb20 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -11,32 +11,33 @@ package arraystack import ( "fmt" - "github.com/emirpasic/gods/lists/arraylist" - "github.com/emirpasic/gods/stacks" "strings" + + "github.com/emirpasic/gods/v2/lists/arraylist" + "github.com/emirpasic/gods/v2/stacks" ) // Assert Stack implementation -var _ stacks.Stack = (*Stack)(nil) +var _ stacks.Stack[int] = (*Stack[int])(nil) // Stack holds elements in an array-list -type Stack struct { - list *arraylist.List +type Stack[T comparable] struct { + list *arraylist.List[T] } // New instantiates a new empty stack -func New() *Stack { - return &Stack{list: arraylist.New()} +func New[T comparable]() *Stack[T] { + return &Stack[T]{list: arraylist.New[T]()} } // Push adds a value onto the top of the stack -func (stack *Stack) Push(value interface{}) { +func (stack *Stack[T]) Push(value T) { stack.list.Add(value) } // Pop removes top element on stack and returns it, or nil if stack is empty. // Second return parameter is true, unless the stack was empty and there was nothing to pop. -func (stack *Stack) Pop() (value interface{}, ok bool) { +func (stack *Stack[T]) Pop() (value T, ok bool) { value, ok = stack.list.Get(stack.list.Size() - 1) stack.list.Remove(stack.list.Size() - 1) return @@ -44,29 +45,29 @@ func (stack *Stack) Pop() (value interface{}, ok bool) { // Peek returns top element on the stack without removing it, or nil if stack is empty. // Second return parameter is true, unless the stack was empty and there was nothing to peek. -func (stack *Stack) Peek() (value interface{}, ok bool) { +func (stack *Stack[T]) Peek() (value T, ok bool) { return stack.list.Get(stack.list.Size() - 1) } // Empty returns true if stack does not contain any elements. -func (stack *Stack) Empty() bool { +func (stack *Stack[T]) Empty() bool { return stack.list.Empty() } // Size returns number of elements within the stack. -func (stack *Stack) Size() int { +func (stack *Stack[T]) Size() int { return stack.list.Size() } // Clear removes all elements from the stack. -func (stack *Stack) Clear() { +func (stack *Stack[T]) Clear() { stack.list.Clear() } // Values returns all elements in the stack (LIFO order). -func (stack *Stack) Values() []interface{} { +func (stack *Stack[T]) Values() []T { size := stack.list.Size() - elements := make([]interface{}, size, size) + elements := make([]T, size, size) for i := 1; i <= size; i++ { elements[size-i], _ = stack.list.Get(i - 1) // in reverse (LIFO) } @@ -74,7 +75,7 @@ func (stack *Stack) Values() []interface{} { } // String returns a string representation of container -func (stack *Stack) String() string { +func (stack *Stack[T]) String() string { str := "ArrayStack\n" values := []string{} for _, value := range stack.list.Values() { @@ -85,6 +86,6 @@ func (stack *Stack) String() string { } // Check that the index is within bounds of the list -func (stack *Stack) withinRange(index int) bool { +func (stack *Stack[T]) withinRange(index int) bool { return index >= 0 && index < stack.list.Size() } diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index eba42870..4e754608 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -6,13 +6,14 @@ package arraystack import ( "encoding/json" - "fmt" "strings" "testing" + + "github.com/emirpasic/gods/v2/testutils" ) func TestStackPush(t *testing.T) { - stack := New() + stack := New[int]() if actualValue := stack.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } @@ -20,7 +21,7 @@ func TestStackPush(t *testing.T) { stack.Push(2) stack.Push(3) - if actualValue := stack.Values(); actualValue[0].(int) != 3 || actualValue[1].(int) != 2 || actualValue[2].(int) != 1 { + if actualValue := stack.Values(); actualValue[0] != 3 || actualValue[1] != 2 || actualValue[2] != 1 { t.Errorf("Got %v expected %v", actualValue, "[3,2,1]") } if actualValue := stack.Empty(); actualValue != false { @@ -35,8 +36,8 @@ func TestStackPush(t *testing.T) { } func TestStackPeek(t *testing.T) { - stack := New() - if actualValue, ok := stack.Peek(); actualValue != nil || ok { + stack := New[int]() + if actualValue, ok := stack.Peek(); actualValue != 0 || ok { t.Errorf("Got %v expected %v", actualValue, nil) } stack.Push(1) @@ -48,7 +49,7 @@ func TestStackPeek(t *testing.T) { } func TestStackPop(t *testing.T) { - stack := New() + stack := New[int]() stack.Push(1) stack.Push(2) stack.Push(3) @@ -62,7 +63,7 @@ func TestStackPop(t *testing.T) { if actualValue, ok := stack.Pop(); actualValue != 1 || !ok { t.Errorf("Got %v expected %v", actualValue, 1) } - if actualValue, ok := stack.Pop(); actualValue != nil || ok { + if actualValue, ok := stack.Pop(); actualValue != 0 || ok { t.Errorf("Got %v expected %v", actualValue, nil) } if actualValue := stack.Empty(); actualValue != true { @@ -74,7 +75,7 @@ func TestStackPop(t *testing.T) { } func TestStackIteratorOnEmpty(t *testing.T) { - stack := New() + stack := New[string]() it := stack.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty stack") @@ -82,7 +83,7 @@ func TestStackIteratorOnEmpty(t *testing.T) { } func TestStackIteratorNext(t *testing.T) { - stack := New() + stack := New[string]() stack.Push("a") stack.Push("b") stack.Push("c") @@ -125,7 +126,7 @@ func TestStackIteratorNext(t *testing.T) { } func TestStackIteratorPrev(t *testing.T) { - stack := New() + stack := New[string]() stack.Push("a") stack.Push("b") stack.Push("c") @@ -164,7 +165,7 @@ func TestStackIteratorPrev(t *testing.T) { } func TestStackIteratorBegin(t *testing.T) { - stack := New() + stack := New[string]() it := stack.Iterator() it.Begin() stack.Push("a") @@ -180,7 +181,7 @@ func TestStackIteratorBegin(t *testing.T) { } func TestStackIteratorEnd(t *testing.T) { - stack := New() + stack := New[string]() it := stack.Iterator() if index := it.Index(); index != -1 { @@ -207,7 +208,7 @@ func TestStackIteratorEnd(t *testing.T) { } func TestStackIteratorFirst(t *testing.T) { - stack := New() + stack := New[string]() it := stack.Iterator() if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -224,7 +225,7 @@ func TestStackIteratorFirst(t *testing.T) { } func TestStackIteratorLast(t *testing.T) { - stack := New() + stack := New[string]() it := stack.Iterator() if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -242,13 +243,13 @@ func TestStackIteratorLast(t *testing.T) { func TestStackIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // NextTo (empty) { - stack := New() + stack := New[string]() it := stack.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty stack") @@ -257,7 +258,7 @@ func TestStackIteratorNextTo(t *testing.T) { // NextTo (not found) { - stack := New() + stack := New[string]() stack.Push("xx") stack.Push("yy") it := stack.Iterator() @@ -268,7 +269,7 @@ func TestStackIteratorNextTo(t *testing.T) { // NextTo (found) { - stack := New() + stack := New[string]() stack.Push("aa") stack.Push("bb") stack.Push("cc") @@ -277,13 +278,13 @@ func TestStackIteratorNextTo(t *testing.T) { if !it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty stack") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Next() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "aa" { + if index, value := it.Index(), it.Value(); index != 2 || value != "aa" { t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "aa") } if it.Next() { @@ -294,13 +295,13 @@ func TestStackIteratorNextTo(t *testing.T) { func TestStackIteratorPrevTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // PrevTo (empty) { - stack := New() + stack := New[string]() it := stack.Iterator() it.End() for it.PrevTo(seek) { @@ -310,7 +311,7 @@ func TestStackIteratorPrevTo(t *testing.T) { // PrevTo (not found) { - stack := New() + stack := New[string]() stack.Push("xx") stack.Push("yy") it := stack.Iterator() @@ -322,7 +323,7 @@ func TestStackIteratorPrevTo(t *testing.T) { // PrevTo (found) { - stack := New() + stack := New[string]() stack.Push("aa") stack.Push("bb") stack.Push("cc") @@ -331,13 +332,13 @@ func TestStackIteratorPrevTo(t *testing.T) { if !it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty stack") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Prev() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "cc" { + if index, value := it.Index(), it.Value(); index != 0 || value != "cc" { t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "cc") } if it.Prev() { @@ -347,16 +348,14 @@ func TestStackIteratorPrevTo(t *testing.T) { } func TestStackSerialization(t *testing.T) { - stack := New() + stack := New[string]() stack.Push("a") stack.Push("b") stack.Push("c") var err error assert := func() { - if actualValue, expectedValue := fmt.Sprintf("%s%s%s", stack.Values()...), "cba"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, stack.Values(), []string{"c", "b", "a"}) if actualValue, expectedValue := stack.Size(), 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } @@ -378,21 +377,22 @@ func TestStackSerialization(t *testing.T) { t.Errorf("Got error %v", err) } - err = json.Unmarshal([]byte(`[1,2,3]`), &stack) + err = json.Unmarshal([]byte(`["a","b","c"]`), &stack) if err != nil { t.Errorf("Got error %v", err) } + assert() } func TestStackString(t *testing.T) { - c := New() + c := New[int]() c.Push(1) if !strings.HasPrefix(c.String(), "ArrayStack") { t.Errorf("String should start with container name") } } -func benchmarkPush(b *testing.B, stack *Stack, size int) { +func benchmarkPush(b *testing.B, stack *Stack[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { stack.Push(n) @@ -400,7 +400,7 @@ func benchmarkPush(b *testing.B, stack *Stack, size int) { } } -func benchmarkPop(b *testing.B, stack *Stack, size int) { +func benchmarkPop(b *testing.B, stack *Stack[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { stack.Pop() @@ -411,7 +411,7 @@ func benchmarkPop(b *testing.B, stack *Stack, size int) { func BenchmarkArrayStackPop100(b *testing.B) { b.StopTimer() size := 100 - stack := New() + stack := New[int]() for n := 0; n < size; n++ { stack.Push(n) } @@ -422,7 +422,7 @@ func BenchmarkArrayStackPop100(b *testing.B) { func BenchmarkArrayStackPop1000(b *testing.B) { b.StopTimer() size := 1000 - stack := New() + stack := New[int]() for n := 0; n < size; n++ { stack.Push(n) } @@ -433,7 +433,7 @@ func BenchmarkArrayStackPop1000(b *testing.B) { func BenchmarkArrayStackPop10000(b *testing.B) { b.StopTimer() size := 10000 - stack := New() + stack := New[int]() for n := 0; n < size; n++ { stack.Push(n) } @@ -444,7 +444,7 @@ func BenchmarkArrayStackPop10000(b *testing.B) { func BenchmarkArrayStackPop100000(b *testing.B) { b.StopTimer() size := 100000 - stack := New() + stack := New[int]() for n := 0; n < size; n++ { stack.Push(n) } @@ -455,7 +455,7 @@ func BenchmarkArrayStackPop100000(b *testing.B) { func BenchmarkArrayStackPush100(b *testing.B) { b.StopTimer() size := 100 - stack := New() + stack := New[int]() b.StartTimer() benchmarkPush(b, stack, size) } @@ -463,7 +463,7 @@ func BenchmarkArrayStackPush100(b *testing.B) { func BenchmarkArrayStackPush1000(b *testing.B) { b.StopTimer() size := 1000 - stack := New() + stack := New[int]() for n := 0; n < size; n++ { stack.Push(n) } @@ -474,7 +474,7 @@ func BenchmarkArrayStackPush1000(b *testing.B) { func BenchmarkArrayStackPush10000(b *testing.B) { b.StopTimer() size := 10000 - stack := New() + stack := New[int]() for n := 0; n < size; n++ { stack.Push(n) } @@ -485,7 +485,7 @@ func BenchmarkArrayStackPush10000(b *testing.B) { func BenchmarkArrayStackPush100000(b *testing.B) { b.StopTimer() size := 100000 - stack := New() + stack := New[int]() for n := 0; n < size; n++ { stack.Push(n) } diff --git a/stacks/arraystack/iterator.go b/stacks/arraystack/iterator.go index c01d7c8b..651e41a0 100644 --- a/stacks/arraystack/iterator.go +++ b/stacks/arraystack/iterator.go @@ -4,27 +4,27 @@ package arraystack -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Assert Iterator implementation -var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) +var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. -type Iterator struct { - stack *Stack +type Iterator[T comparable] struct { + stack *Stack[T] index int } // Iterator returns a stateful iterator whose values can be fetched by an index. -func (stack *Stack) Iterator() Iterator { - return Iterator{stack: stack, index: -1} +func (stack *Stack[T]) Iterator() *Iterator[T] { + return &Iterator[T]{stack: stack, index: -1} } // 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 { +func (iterator *Iterator[T]) Next() bool { if iterator.index < iterator.stack.Size() { iterator.index++ } @@ -34,7 +34,7 @@ func (iterator *Iterator) Next() bool { // 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 { +func (iterator *Iterator[T]) Prev() bool { if iterator.index >= 0 { iterator.index-- } @@ -43,33 +43,33 @@ func (iterator *Iterator) Prev() bool { // Value returns the current element's value. // Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { +func (iterator *Iterator[T]) Value() T { value, _ := iterator.stack.list.Get(iterator.stack.list.Size() - iterator.index - 1) // in reverse (LIFO) return value } // Index returns the current element's index. // Does not modify the state of the iterator. -func (iterator *Iterator) Index() int { +func (iterator *Iterator[T]) Index() int { return 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() { +func (iterator *Iterator[T]) Begin() { iterator.index = -1 } // 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() { +func (iterator *Iterator[T]) End() { iterator.index = iterator.stack.Size() } // 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 { +func (iterator *Iterator[T]) First() bool { iterator.Begin() return iterator.Next() } @@ -77,7 +77,7 @@ func (iterator *Iterator) First() bool { // 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 { +func (iterator *Iterator[T]) Last() bool { iterator.End() return iterator.Prev() } @@ -86,7 +86,7 @@ func (iterator *Iterator) Last() bool { // 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. -func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) NextTo(f func(index int, value T) bool) bool { for iterator.Next() { index, value := iterator.Index(), iterator.Value() if f(index, value) { @@ -100,7 +100,7 @@ func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool // 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. -func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) PrevTo(f func(index int, value T) bool) bool { for iterator.Prev() { index, value := iterator.Index(), iterator.Value() if f(index, value) { diff --git a/stacks/arraystack/serialization.go b/stacks/arraystack/serialization.go index e65889fb..ff0c6385 100644 --- a/stacks/arraystack/serialization.go +++ b/stacks/arraystack/serialization.go @@ -5,29 +5,29 @@ package arraystack import ( - "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*Stack)(nil) -var _ containers.JSONDeserializer = (*Stack)(nil) +var _ containers.JSONSerializer = (*Stack[int])(nil) +var _ containers.JSONDeserializer = (*Stack[int])(nil) // ToJSON outputs the JSON representation of the stack. -func (stack *Stack) ToJSON() ([]byte, error) { +func (stack *Stack[T]) ToJSON() ([]byte, error) { return stack.list.ToJSON() } // FromJSON populates the stack from the input JSON representation. -func (stack *Stack) FromJSON(data []byte) error { +func (stack *Stack[T]) FromJSON(data []byte) error { return stack.list.FromJSON(data) } // UnmarshalJSON @implements json.Unmarshaler -func (stack *Stack) UnmarshalJSON(bytes []byte) error { +func (stack *Stack[T]) UnmarshalJSON(bytes []byte) error { return stack.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (stack *Stack) MarshalJSON() ([]byte, error) { +func (stack *Stack[T]) MarshalJSON() ([]byte, error) { return stack.ToJSON() } diff --git a/stacks/linkedliststack/iterator.go b/stacks/linkedliststack/iterator.go index dea086b1..5350e330 100644 --- a/stacks/linkedliststack/iterator.go +++ b/stacks/linkedliststack/iterator.go @@ -4,27 +4,27 @@ package linkedliststack -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Assert Iterator implementation -var _ containers.IteratorWithIndex = (*Iterator)(nil) +var _ containers.IteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. -type Iterator struct { - stack *Stack +type Iterator[T comparable] struct { + stack *Stack[T] index int } // Iterator returns a stateful iterator whose values can be fetched by an index. -func (stack *Stack) Iterator() Iterator { - return Iterator{stack: stack, index: -1} +func (stack *Stack[T]) Iterator() *Iterator[T] { + return &Iterator[T]{stack: stack, index: -1} } // 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 { +func (iterator *Iterator[T]) Next() bool { if iterator.index < iterator.stack.Size() { iterator.index++ } @@ -33,27 +33,27 @@ func (iterator *Iterator) Next() bool { // Value returns the current element's value. // Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { +func (iterator *Iterator[T]) Value() T { value, _ := iterator.stack.list.Get(iterator.index) // in reverse (LIFO) return value } // Index returns the current element's index. // Does not modify the state of the iterator. -func (iterator *Iterator) Index() int { +func (iterator *Iterator[T]) Index() int { return 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() { +func (iterator *Iterator[T]) Begin() { iterator.index = -1 } // 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 { +func (iterator *Iterator[T]) First() bool { iterator.Begin() return iterator.Next() } @@ -62,7 +62,7 @@ func (iterator *Iterator) First() bool { // 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. -func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) NextTo(f func(index int, value T) bool) bool { for iterator.Next() { index, value := iterator.Index(), iterator.Value() if f(index, value) { diff --git a/stacks/linkedliststack/linkedliststack.go b/stacks/linkedliststack/linkedliststack.go index ce69b212..ec373dd5 100644 --- a/stacks/linkedliststack/linkedliststack.go +++ b/stacks/linkedliststack/linkedliststack.go @@ -11,32 +11,33 @@ package linkedliststack import ( "fmt" - "github.com/emirpasic/gods/lists/singlylinkedlist" - "github.com/emirpasic/gods/stacks" "strings" + + "github.com/emirpasic/gods/v2/lists/singlylinkedlist" + "github.com/emirpasic/gods/v2/stacks" ) // Assert Stack implementation -var _ stacks.Stack = (*Stack)(nil) +var _ stacks.Stack[int] = (*Stack[int])(nil) // Stack holds elements in a singly-linked-list -type Stack struct { - list *singlylinkedlist.List +type Stack[T comparable] struct { + list *singlylinkedlist.List[T] } // New nnstantiates a new empty stack -func New() *Stack { - return &Stack{list: &singlylinkedlist.List{}} +func New[T comparable]() *Stack[T] { + return &Stack[T]{list: singlylinkedlist.New[T]()} } // Push adds a value onto the top of the stack -func (stack *Stack) Push(value interface{}) { +func (stack *Stack[T]) Push(value T) { stack.list.Prepend(value) } // Pop removes top element on stack and returns it, or nil if stack is empty. // Second return parameter is true, unless the stack was empty and there was nothing to pop. -func (stack *Stack) Pop() (value interface{}, ok bool) { +func (stack *Stack[T]) Pop() (value T, ok bool) { value, ok = stack.list.Get(0) stack.list.Remove(0) return @@ -44,32 +45,32 @@ func (stack *Stack) Pop() (value interface{}, ok bool) { // Peek returns top element on the stack without removing it, or nil if stack is empty. // Second return parameter is true, unless the stack was empty and there was nothing to peek. -func (stack *Stack) Peek() (value interface{}, ok bool) { +func (stack *Stack[T]) Peek() (value T, ok bool) { return stack.list.Get(0) } // Empty returns true if stack does not contain any elements. -func (stack *Stack) Empty() bool { +func (stack *Stack[T]) Empty() bool { return stack.list.Empty() } // Size returns number of elements within the stack. -func (stack *Stack) Size() int { +func (stack *Stack[T]) Size() int { return stack.list.Size() } // Clear removes all elements from the stack. -func (stack *Stack) Clear() { +func (stack *Stack[T]) Clear() { stack.list.Clear() } // Values returns all elements in the stack (LIFO order). -func (stack *Stack) Values() []interface{} { +func (stack *Stack[T]) Values() []T { return stack.list.Values() } // String returns a string representation of container -func (stack *Stack) String() string { +func (stack *Stack[T]) String() string { str := "LinkedListStack\n" values := []string{} for _, value := range stack.list.Values() { @@ -80,6 +81,6 @@ func (stack *Stack) String() string { } // Check that the index is within bounds of the list -func (stack *Stack) withinRange(index int) bool { +func (stack *Stack[T]) withinRange(index int) bool { return index >= 0 && index < stack.list.Size() } diff --git a/stacks/linkedliststack/linkedliststack_test.go b/stacks/linkedliststack/linkedliststack_test.go index f491fd3a..f215ba37 100644 --- a/stacks/linkedliststack/linkedliststack_test.go +++ b/stacks/linkedliststack/linkedliststack_test.go @@ -6,13 +6,14 @@ package linkedliststack import ( "encoding/json" - "fmt" "strings" "testing" + + "github.com/emirpasic/gods/v2/testutils" ) func TestStackPush(t *testing.T) { - stack := New() + stack := New[int]() if actualValue := stack.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } @@ -20,7 +21,7 @@ func TestStackPush(t *testing.T) { stack.Push(2) stack.Push(3) - if actualValue := stack.Values(); actualValue[0].(int) != 3 || actualValue[1].(int) != 2 || actualValue[2].(int) != 1 { + if actualValue := stack.Values(); actualValue[0] != 3 || actualValue[1] != 2 || actualValue[2] != 1 { t.Errorf("Got %v expected %v", actualValue, "[3,2,1]") } if actualValue := stack.Empty(); actualValue != false { @@ -35,8 +36,8 @@ func TestStackPush(t *testing.T) { } func TestStackPeek(t *testing.T) { - stack := New() - if actualValue, ok := stack.Peek(); actualValue != nil || ok { + stack := New[int]() + if actualValue, ok := stack.Peek(); actualValue != 0 || ok { t.Errorf("Got %v expected %v", actualValue, nil) } stack.Push(1) @@ -48,7 +49,7 @@ func TestStackPeek(t *testing.T) { } func TestStackPop(t *testing.T) { - stack := New() + stack := New[int]() stack.Push(1) stack.Push(2) stack.Push(3) @@ -62,7 +63,7 @@ func TestStackPop(t *testing.T) { if actualValue, ok := stack.Pop(); actualValue != 1 || !ok { t.Errorf("Got %v expected %v", actualValue, 1) } - if actualValue, ok := stack.Pop(); actualValue != nil || ok { + if actualValue, ok := stack.Pop(); actualValue != 0 || ok { t.Errorf("Got %v expected %v", actualValue, nil) } if actualValue := stack.Empty(); actualValue != true { @@ -74,7 +75,7 @@ func TestStackPop(t *testing.T) { } func TestStackIterator(t *testing.T) { - stack := New() + stack := New[string]() stack.Push("a") stack.Push("b") stack.Push("c") @@ -118,7 +119,7 @@ func TestStackIterator(t *testing.T) { } func TestStackIteratorBegin(t *testing.T) { - stack := New() + stack := New[string]() it := stack.Iterator() it.Begin() stack.Push("a") @@ -134,7 +135,7 @@ func TestStackIteratorBegin(t *testing.T) { } func TestStackIteratorFirst(t *testing.T) { - stack := New() + stack := New[string]() it := stack.Iterator() if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -152,13 +153,13 @@ func TestStackIteratorFirst(t *testing.T) { func TestStackIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // NextTo (empty) { - stack := New() + stack := New[string]() it := stack.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty stack") @@ -167,7 +168,7 @@ func TestStackIteratorNextTo(t *testing.T) { // NextTo (not found) { - stack := New() + stack := New[string]() stack.Push("xx") stack.Push("yy") it := stack.Iterator() @@ -178,7 +179,7 @@ func TestStackIteratorNextTo(t *testing.T) { // NextTo (found) { - stack := New() + stack := New[string]() stack.Push("aa") stack.Push("bb") stack.Push("cc") @@ -187,13 +188,13 @@ func TestStackIteratorNextTo(t *testing.T) { if !it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty stack") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Next() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "aa" { + if index, value := it.Index(), it.Value(); index != 2 || value != "aa" { t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "aa") } if it.Next() { @@ -203,16 +204,14 @@ func TestStackIteratorNextTo(t *testing.T) { } func TestStackSerialization(t *testing.T) { - stack := New() + stack := New[string]() stack.Push("a") stack.Push("b") stack.Push("c") var err error assert := func() { - if actualValue, expectedValue := fmt.Sprintf("%s%s%s", stack.Values()...), "cba"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } + testutils.SameElements(t, stack.Values(), []string{"c", "b", "a"}) if actualValue, expectedValue := stack.Size(), 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } @@ -234,21 +233,22 @@ func TestStackSerialization(t *testing.T) { t.Errorf("Got error %v", err) } - err = json.Unmarshal([]byte(`[1,2,3]`), &stack) + err = json.Unmarshal([]byte(`["a","b","c"]`), &stack) if err != nil { t.Errorf("Got error %v", err) } + assert() } func TestStackString(t *testing.T) { - c := New() + c := New[int]() c.Push(1) if !strings.HasPrefix(c.String(), "LinkedListStack") { t.Errorf("String should start with container name") } } -func benchmarkPush(b *testing.B, stack *Stack, size int) { +func benchmarkPush(b *testing.B, stack *Stack[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { stack.Push(n) @@ -256,7 +256,7 @@ func benchmarkPush(b *testing.B, stack *Stack, size int) { } } -func benchmarkPop(b *testing.B, stack *Stack, size int) { +func benchmarkPop(b *testing.B, stack *Stack[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { stack.Pop() @@ -267,7 +267,7 @@ func benchmarkPop(b *testing.B, stack *Stack, size int) { func BenchmarkLinkedListStackPop100(b *testing.B) { b.StopTimer() size := 100 - stack := New() + stack := New[int]() for n := 0; n < size; n++ { stack.Push(n) } @@ -278,7 +278,7 @@ func BenchmarkLinkedListStackPop100(b *testing.B) { func BenchmarkLinkedListStackPop1000(b *testing.B) { b.StopTimer() size := 1000 - stack := New() + stack := New[int]() for n := 0; n < size; n++ { stack.Push(n) } @@ -289,7 +289,7 @@ func BenchmarkLinkedListStackPop1000(b *testing.B) { func BenchmarkLinkedListStackPop10000(b *testing.B) { b.StopTimer() size := 10000 - stack := New() + stack := New[int]() for n := 0; n < size; n++ { stack.Push(n) } @@ -300,7 +300,7 @@ func BenchmarkLinkedListStackPop10000(b *testing.B) { func BenchmarkLinkedListStackPop100000(b *testing.B) { b.StopTimer() size := 100000 - stack := New() + stack := New[int]() for n := 0; n < size; n++ { stack.Push(n) } @@ -311,7 +311,7 @@ func BenchmarkLinkedListStackPop100000(b *testing.B) { func BenchmarkLinkedListStackPush100(b *testing.B) { b.StopTimer() size := 100 - stack := New() + stack := New[int]() b.StartTimer() benchmarkPush(b, stack, size) } @@ -319,7 +319,7 @@ func BenchmarkLinkedListStackPush100(b *testing.B) { func BenchmarkLinkedListStackPush1000(b *testing.B) { b.StopTimer() size := 1000 - stack := New() + stack := New[int]() for n := 0; n < size; n++ { stack.Push(n) } @@ -330,7 +330,7 @@ func BenchmarkLinkedListStackPush1000(b *testing.B) { func BenchmarkLinkedListStackPush10000(b *testing.B) { b.StopTimer() size := 10000 - stack := New() + stack := New[int]() for n := 0; n < size; n++ { stack.Push(n) } @@ -341,7 +341,7 @@ func BenchmarkLinkedListStackPush10000(b *testing.B) { func BenchmarkLinkedListStackPush100000(b *testing.B) { b.StopTimer() size := 100000 - stack := New() + stack := New[int]() for n := 0; n < size; n++ { stack.Push(n) } diff --git a/stacks/linkedliststack/serialization.go b/stacks/linkedliststack/serialization.go index a82b768c..3a8ca044 100644 --- a/stacks/linkedliststack/serialization.go +++ b/stacks/linkedliststack/serialization.go @@ -5,29 +5,29 @@ package linkedliststack import ( - "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*Stack)(nil) -var _ containers.JSONDeserializer = (*Stack)(nil) +var _ containers.JSONSerializer = (*Stack[int])(nil) +var _ containers.JSONDeserializer = (*Stack[int])(nil) // ToJSON outputs the JSON representation of the stack. -func (stack *Stack) ToJSON() ([]byte, error) { +func (stack *Stack[T]) ToJSON() ([]byte, error) { return stack.list.ToJSON() } // FromJSON populates the stack from the input JSON representation. -func (stack *Stack) FromJSON(data []byte) error { +func (stack *Stack[T]) FromJSON(data []byte) error { return stack.list.FromJSON(data) } // UnmarshalJSON @implements json.Unmarshaler -func (stack *Stack) UnmarshalJSON(bytes []byte) error { +func (stack *Stack[T]) UnmarshalJSON(bytes []byte) error { return stack.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (stack *Stack) MarshalJSON() ([]byte, error) { +func (stack *Stack[T]) MarshalJSON() ([]byte, error) { return stack.ToJSON() } diff --git a/stacks/stacks.go b/stacks/stacks.go index e9ae56e1..4acd0116 100644 --- a/stacks/stacks.go +++ b/stacks/stacks.go @@ -9,15 +9,15 @@ // Reference: https://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29 package stacks -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Stack interface that all stacks implement -type Stack interface { - Push(value interface{}) - Pop() (value interface{}, ok bool) - Peek() (value interface{}, ok bool) +type Stack[T any] interface { + Push(value T) + Pop() (value T, ok bool) + Peek() (value T, ok bool) - containers.Container + containers.Container[T] // Empty() bool // Size() int // Clear() diff --git a/testutils/testutils.go b/testutils/testutils.go new file mode 100644 index 00000000..b97d6385 --- /dev/null +++ b/testutils/testutils.go @@ -0,0 +1,18 @@ +package testutils + +import "testing" + +func SameElements[T comparable](t *testing.T, actual, expected []T) { + if len(actual) != len(expected) { + t.Errorf("Got %d expected %d", len(actual), len(expected)) + } +outer: + for _, e := range expected { + for _, a := range actual { + if e == a { + continue outer + } + } + t.Errorf("Did not find expected element %v in %v", e, actual) + } +} diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index ec2765cd..81b9f3f8 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -10,68 +10,65 @@ package avltree import ( + "cmp" "fmt" - "github.com/emirpasic/gods/trees" - "github.com/emirpasic/gods/utils" + + "github.com/emirpasic/gods/v2/trees" + "github.com/emirpasic/gods/v2/utils" ) // Assert Tree implementation -var _ trees.Tree = new(Tree) +var _ trees.Tree[int] = (*Tree[string, int])(nil) // Tree holds elements of the AVL tree. -type Tree struct { - Root *Node // Root node - Comparator utils.Comparator // Key comparator - size int // Total number of keys in the tree +type Tree[K comparable, V any] struct { + Root *Node[K, V] // Root node + Comparator utils.Comparator[K] // Key comparator + size int // Total number of keys in the tree } // Node is a single element within the tree -type Node struct { - Key interface{} - Value interface{} - Parent *Node // Parent node - Children [2]*Node // Children nodes +type Node[K comparable, V any] struct { + Key K + Value V + Parent *Node[K, V] // Parent node + Children [2]*Node[K, V] // Children nodes b int8 } -// NewWith instantiates an AVL tree with the custom comparator. -func NewWith(comparator utils.Comparator) *Tree { - return &Tree{Comparator: comparator} -} - -// NewWithIntComparator instantiates an AVL tree with the IntComparator, i.e. keys are of type int. -func NewWithIntComparator() *Tree { - return &Tree{Comparator: utils.IntComparator} +// New instantiates an AVL tree with the built-in comparator for K +func New[K cmp.Ordered, V any]() *Tree[K, V] { + return &Tree[K, V]{Comparator: cmp.Compare[K]} } -// NewWithStringComparator instantiates an AVL tree with the StringComparator, i.e. keys are of type string. -func NewWithStringComparator() *Tree { - return &Tree{Comparator: utils.StringComparator} +// NewWith instantiates an AVL tree with the custom comparator. +func NewWith[K comparable, V any](comparator utils.Comparator[K]) *Tree[K, V] { + return &Tree[K, V]{Comparator: comparator} } // Put inserts node into the tree. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (t *Tree) Put(key interface{}, value interface{}) { - t.put(key, value, nil, &t.Root) +func (tree *Tree[K, V]) Put(key K, value V) { + tree.put(key, value, nil, &tree.Root) } // Get searches the node in the tree by key and returns its value or nil if key is not found in tree. // Second return parameter is true if key was found, otherwise false. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (t *Tree) Get(key interface{}) (value interface{}, found bool) { - n := t.GetNode(key) +func (tree *Tree[K, V]) Get(key K) (value V, found bool) { + n := tree.GetNode(key) if n != nil { return n.Value, true } - return nil, false + return value, false } // GetNode searches the node in the tree by key and returns its node or nil if key is not found in tree. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (t *Tree) GetNode(key interface{}) *Node { - n := t.Root +func (tree *Tree[K, V]) GetNode(key K) *Node[K, V] { + n := tree.Root for n != nil { - cmp := t.Comparator(key, n.Key) + cmp := tree.Comparator(key, n.Key) switch { case cmp == 0: return n @@ -86,23 +83,23 @@ func (t *Tree) GetNode(key interface{}) *Node { // Remove remove the node from the tree by key. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (t *Tree) Remove(key interface{}) { - t.remove(key, &t.Root) +func (tree *Tree[K, V]) Remove(key K) { + tree.remove(key, &tree.Root) } // Empty returns true if tree does not contain any nodes. -func (t *Tree) Empty() bool { - return t.size == 0 +func (tree *Tree[K, V]) Empty() bool { + return tree.size == 0 } // Size returns the number of elements stored in the tree. -func (t *Tree) Size() int { - return t.size +func (tree *Tree[K, V]) Size() int { + return tree.size } // Size returns the number of elements stored in the subtree. // Computed dynamically on each call, i.e. the subtree is traversed to count the number of the nodes. -func (n *Node) Size() int { +func (n *Node[K, V]) Size() int { if n == nil { return 0 } @@ -117,9 +114,9 @@ func (n *Node) Size() int { } // Keys returns all keys in-order -func (t *Tree) Keys() []interface{} { - keys := make([]interface{}, t.size) - it := t.Iterator() +func (tree *Tree[K, V]) Keys() []K { + keys := make([]K, tree.size) + it := tree.Iterator() for i := 0; it.Next(); i++ { keys[i] = it.Key() } @@ -127,9 +124,9 @@ func (t *Tree) Keys() []interface{} { } // Values returns all values in-order based on the key. -func (t *Tree) Values() []interface{} { - values := make([]interface{}, t.size) - it := t.Iterator() +func (tree *Tree[K, V]) Values() []V { + values := make([]V, tree.size) + it := tree.Iterator() for i := 0; it.Next(); i++ { values[i] = it.Value() } @@ -138,14 +135,14 @@ func (t *Tree) Values() []interface{} { // Left returns the minimum element of the AVL tree // or nil if the tree is empty. -func (t *Tree) Left() *Node { - return t.bottom(0) +func (tree *Tree[K, V]) Left() *Node[K, V] { + return tree.bottom(0) } // Right returns the maximum element of the AVL tree // or nil if the tree is empty. -func (t *Tree) Right() *Node { - return t.bottom(1) +func (tree *Tree[K, V]) Right() *Node[K, V] { + return tree.bottom(1) } // Floor Finds floor node of the input key, return the floor node or nil if no floor is found. @@ -156,11 +153,11 @@ func (t *Tree) Right() *Node { // all nodes in the tree is larger than the given node. // // Key should adhere to the comparator's type assertion, otherwise method panics. -func (t *Tree) Floor(key interface{}) (floor *Node, found bool) { +func (tree *Tree[K, V]) Floor(key K) (floor *Node[K, V], found bool) { found = false - n := t.Root + n := tree.Root for n != nil { - c := t.Comparator(key, n.Key) + c := tree.Comparator(key, n.Key) switch { case c == 0: return n, true @@ -185,11 +182,11 @@ func (t *Tree) Floor(key interface{}) (floor *Node, found bool) { // all nodes in the tree is smaller than the given node. // // Key should adhere to the comparator's type assertion, otherwise method panics. -func (t *Tree) Ceiling(key interface{}) (floor *Node, found bool) { +func (tree *Tree[K, V]) Ceiling(key K) (floor *Node[K, V], found bool) { found = false - n := t.Root + n := tree.Root for n != nil { - c := t.Comparator(key, n.Key) + c := tree.Comparator(key, n.Key) switch { case c == 0: return n, true @@ -207,33 +204,33 @@ func (t *Tree) Ceiling(key interface{}) (floor *Node, found bool) { } // Clear removes all nodes from the tree. -func (t *Tree) Clear() { - t.Root = nil - t.size = 0 +func (tree *Tree[K, V]) Clear() { + tree.Root = nil + tree.size = 0 } // String returns a string representation of container -func (t *Tree) String() string { +func (tree *Tree[K, V]) String() string { str := "AVLTree\n" - if !t.Empty() { - output(t.Root, "", true, &str) + if !tree.Empty() { + output(tree.Root, "", true, &str) } return str } -func (n *Node) String() string { +func (n *Node[K, V]) String() string { return fmt.Sprintf("%v", n.Key) } -func (t *Tree) put(key interface{}, value interface{}, p *Node, qp **Node) bool { +func (tree *Tree[K, V]) put(key K, value V, p *Node[K, V], qp **Node[K, V]) bool { q := *qp if q == nil { - t.size++ - *qp = &Node{Key: key, Value: value, Parent: p} + tree.size++ + *qp = &Node[K, V]{Key: key, Value: value, Parent: p} return true } - c := t.Comparator(key, q.Key) + c := tree.Comparator(key, q.Key) if c == 0 { q.Key = key q.Value = value @@ -247,22 +244,22 @@ func (t *Tree) put(key interface{}, value interface{}, p *Node, qp **Node) bool } a := (c + 1) / 2 var fix bool - fix = t.put(key, value, q, &q.Children[a]) + fix = tree.put(key, value, q, &q.Children[a]) if fix { return putFix(int8(c), qp) } return false } -func (t *Tree) remove(key interface{}, qp **Node) bool { +func (tree *Tree[K, V]) remove(key K, qp **Node[K, V]) bool { q := *qp if q == nil { return false } - c := t.Comparator(key, q.Key) + c := tree.Comparator(key, q.Key) if c == 0 { - t.size-- + tree.size-- if q.Children[1] == nil { if q.Children[0] != nil { q.Children[0].Parent = q.Parent @@ -283,14 +280,14 @@ func (t *Tree) remove(key interface{}, qp **Node) bool { c = 1 } a := (c + 1) / 2 - fix := t.remove(key, &q.Children[a]) + fix := tree.remove(key, &q.Children[a]) if fix { return removeFix(int8(-c), qp) } return false } -func removeMin(qp **Node, minKey *interface{}, minVal *interface{}) bool { +func removeMin[K comparable, V any](qp **Node[K, V], minKey *K, minVal *V) bool { q := *qp if q.Children[0] == nil { *minKey = q.Key @@ -308,7 +305,7 @@ func removeMin(qp **Node, minKey *interface{}, minVal *interface{}) bool { return false } -func putFix(c int8, t **Node) bool { +func putFix[K comparable, V any](c int8, t **Node[K, V]) bool { s := *t if s.b == 0 { s.b = c @@ -329,7 +326,7 @@ func putFix(c int8, t **Node) bool { return false } -func removeFix(c int8, t **Node) bool { +func removeFix[K comparable, V any](c int8, t **Node[K, V]) bool { s := *t if s.b == 0 { s.b = c @@ -358,14 +355,14 @@ func removeFix(c int8, t **Node) bool { return true } -func singlerot(c int8, s *Node) *Node { +func singlerot[K comparable, V any](c int8, s *Node[K, V]) *Node[K, V] { s.b = 0 s = rotate(c, s) s.b = 0 return s } -func doublerot(c int8, s *Node) *Node { +func doublerot[K comparable, V any](c int8, s *Node[K, V]) *Node[K, V] { a := (c + 1) / 2 r := s.Children[a] s.Children[a] = rotate(-c, s.Children[a]) @@ -387,7 +384,7 @@ func doublerot(c int8, s *Node) *Node { return p } -func rotate(c int8, s *Node) *Node { +func rotate[K comparable, V any](c int8, s *Node[K, V]) *Node[K, V] { a := (c + 1) / 2 r := s.Children[a] s.Children[a] = r.Children[a^1] @@ -400,8 +397,8 @@ func rotate(c int8, s *Node) *Node { return r } -func (t *Tree) bottom(d int) *Node { - n := t.Root +func (tree *Tree[K, V]) bottom(d int) *Node[K, V] { + n := tree.Root if n == nil { return nil } @@ -414,17 +411,17 @@ func (t *Tree) bottom(d int) *Node { // Prev returns the previous element in an inorder // walk of the AVL tree. -func (n *Node) Prev() *Node { +func (n *Node[K, V]) Prev() *Node[K, V] { return n.walk1(0) } // Next returns the next element in an inorder // walk of the AVL tree. -func (n *Node) Next() *Node { +func (n *Node[K, V]) Next() *Node[K, V] { return n.walk1(1) } -func (n *Node) walk1(a int) *Node { +func (n *Node[K, V]) walk1(a int) *Node[K, V] { if n == nil { return nil } @@ -445,7 +442,7 @@ func (n *Node) walk1(a int) *Node { return p } -func output(node *Node, prefix string, isTail bool, str *string) { +func output[K comparable, V any](node *Node[K, V], prefix string, isTail bool, str *string) { if node.Children[1] != nil { newPrefix := prefix if isTail { diff --git a/trees/avltree/avltree_test.go b/trees/avltree/avltree_test.go index 114b5a5e..346fc479 100644 --- a/trees/avltree/avltree_test.go +++ b/trees/avltree/avltree_test.go @@ -5,14 +5,13 @@ package avltree import ( "encoding/json" - "fmt" - "github.com/emirpasic/gods/utils" + "slices" "strings" "testing" ) func TestAVLTreeGet(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() if actualValue := tree.Size(); actualValue != 0 { t.Errorf("Got %v expected %v", actualValue, 0) @@ -56,7 +55,7 @@ func TestAVLTreeGet(t *testing.T) { } func TestAVLTreePut(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(5, "e") tree.Put(6, "f") tree.Put(7, "g") @@ -69,10 +68,10 @@ func TestAVLTreePut(t *testing.T) { if actualValue := tree.Size(); actualValue != 7 { t.Errorf("Got %v expected %v", actualValue, 7) } - if actualValue, expectedValue := fmt.Sprintf("%d%d%d%d%d%d%d", tree.Keys()...), "1234567"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Keys(), []int{1, 2, 3, 4, 5, 6, 7}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s", tree.Values()...), "abcdefg"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Values(), []string{"a", "b", "c", "d", "e", "f", "g"}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } @@ -84,12 +83,12 @@ func TestAVLTreePut(t *testing.T) { {5, "e", true}, {6, "f", true}, {7, "g", true}, - {8, nil, false}, + {8, "", false}, } for _, test := range tests1 { // retrievals - actualValue, actualFound := tree.Get(test[0]) + actualValue, actualFound := tree.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } @@ -97,7 +96,7 @@ func TestAVLTreePut(t *testing.T) { } func TestAVLTreeRemove(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(5, "e") tree.Put(6, "f") tree.Put(7, "g") @@ -113,13 +112,10 @@ func TestAVLTreeRemove(t *testing.T) { tree.Remove(8) tree.Remove(5) - if actualValue, expectedValue := fmt.Sprintf("%d%d%d%d", tree.Keys()...), "1234"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Keys(), []int{1, 2, 3, 4}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", tree.Values()...), "abcd"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", tree.Values()...), "abcd"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Values(), []string{"a", "b", "c", "d"}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } if actualValue := tree.Size(); actualValue != 4 { @@ -131,14 +127,14 @@ func TestAVLTreeRemove(t *testing.T) { {2, "b", true}, {3, "c", true}, {4, "d", true}, - {5, nil, false}, - {6, nil, false}, - {7, nil, false}, - {8, nil, false}, + {5, "", false}, + {6, "", false}, + {7, "", false}, + {8, "", false}, } for _, test := range tests2 { - actualValue, actualFound := tree.Get(test[0]) + actualValue, actualFound := tree.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } @@ -151,10 +147,10 @@ func TestAVLTreeRemove(t *testing.T) { tree.Remove(2) tree.Remove(2) - if actualValue, expectedValue := fmt.Sprintf("%s", tree.Keys()), "[]"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Keys(), []int{}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if actualValue, expectedValue := fmt.Sprintf("%s", tree.Values()), "[]"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Values(), []string{}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } if empty, size := tree.Empty(), tree.Size(); empty != true || size != -0 { @@ -164,7 +160,7 @@ func TestAVLTreeRemove(t *testing.T) { } func TestAVLTreeLeftAndRight(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() if actualValue := tree.Left(); actualValue != nil { t.Errorf("Got %v expected %v", actualValue, nil) @@ -182,23 +178,23 @@ func TestAVLTreeLeftAndRight(t *testing.T) { tree.Put(1, "x") // overwrite tree.Put(2, "b") - if actualValue, expectedValue := fmt.Sprintf("%d", tree.Left().Key), "1"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Left().Key, 1; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if actualValue, expectedValue := fmt.Sprintf("%s", tree.Left().Value), "x"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Left().Value, "x"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if actualValue, expectedValue := fmt.Sprintf("%d", tree.Right().Key), "7"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Right().Key, 7; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if actualValue, expectedValue := fmt.Sprintf("%s", tree.Right().Value), "g"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Right().Value, "g"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } func TestAVLTreeCeilingAndFloor(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() if node, found := tree.Floor(0); node != nil || found { t.Errorf("Got %v expected %v", node, "") @@ -231,7 +227,7 @@ func TestAVLTreeCeilingAndFloor(t *testing.T) { } func TestAVLTreeIteratorNextOnEmpty(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() it := tree.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty tree") @@ -239,7 +235,7 @@ func TestAVLTreeIteratorNextOnEmpty(t *testing.T) { } func TestAVLTreeIteratorPrevOnEmpty(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() it := tree.Iterator() for it.Prev() { t.Errorf("Shouldn't iterate on empty tree") @@ -247,7 +243,7 @@ func TestAVLTreeIteratorPrevOnEmpty(t *testing.T) { } func TestAVLTreeIterator1Next(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(5, "e") tree.Put(6, "f") tree.Put(7, "g") @@ -279,7 +275,7 @@ func TestAVLTreeIterator1Next(t *testing.T) { } func TestAVLTreeIterator1Prev(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(5, "e") tree.Put(6, "f") tree.Put(7, "g") @@ -312,7 +308,7 @@ func TestAVLTreeIterator1Prev(t *testing.T) { } func TestAVLTreeIterator2Next(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") @@ -331,7 +327,7 @@ func TestAVLTreeIterator2Next(t *testing.T) { } func TestAVLTreeIterator2Prev(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") @@ -352,7 +348,7 @@ func TestAVLTreeIterator2Prev(t *testing.T) { } func TestAVLTreeIterator3Next(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(1, "a") it := tree.Iterator() count := 0 @@ -369,7 +365,7 @@ func TestAVLTreeIterator3Next(t *testing.T) { } func TestAVLTreeIterator3Prev(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(1, "a") it := tree.Iterator() for it.Next() { @@ -388,7 +384,7 @@ func TestAVLTreeIterator3Prev(t *testing.T) { } func TestAVLTreeIterator4Next(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, int]() tree.Put(13, 5) tree.Put(8, 3) tree.Put(17, 7) @@ -424,7 +420,7 @@ func TestAVLTreeIterator4Next(t *testing.T) { } func TestAVLTreeIterator4Prev(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, int]() tree.Put(13, 5) tree.Put(8, 3) tree.Put(17, 7) @@ -462,20 +458,20 @@ func TestAVLTreeIterator4Prev(t *testing.T) { } func TestAVLTreeIteratorBegin(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") it := tree.Iterator() - if it.Key() != nil { - t.Errorf("Got %v expected %v", it.Key(), nil) + if it.Key() != 0 { + t.Errorf("Got %v expected %v", it.Key(), 0) } it.Begin() - if it.Key() != nil { - t.Errorf("Got %v expected %v", it.Key(), nil) + if it.Key() != 0 { + t.Errorf("Got %v expected %v", it.Key(), 0) } for it.Next() { @@ -483,8 +479,8 @@ func TestAVLTreeIteratorBegin(t *testing.T) { it.Begin() - if it.Key() != nil { - t.Errorf("Got %v expected %v", it.Key(), nil) + if it.Key() != 0 { + t.Errorf("Got %v expected %v", it.Key(), 0) } it.Next() @@ -494,24 +490,24 @@ func TestAVLTreeIteratorBegin(t *testing.T) { } func TestAVLTreeIteratorEnd(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() it := tree.Iterator() - if it.Key() != nil { - t.Errorf("Got %v expected %v", it.Key(), nil) + if it.Key() != 0 { + t.Errorf("Got %v expected %v", it.Key(), 0) } it.End() - if it.Key() != nil { - t.Errorf("Got %v expected %v", it.Key(), nil) + if it.Key() != 0 { + t.Errorf("Got %v expected %v", it.Key(), 0) } tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") it.End() - if it.Key() != nil { - t.Errorf("Got %v expected %v", it.Key(), nil) + if it.Key() != 0 { + t.Errorf("Got %v expected %v", it.Key(), 0) } it.Prev() @@ -521,7 +517,7 @@ func TestAVLTreeIteratorEnd(t *testing.T) { } func TestAVLTreeIteratorFirst(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") @@ -535,7 +531,7 @@ func TestAVLTreeIteratorFirst(t *testing.T) { } func TestAVLTreeIteratorLast(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") @@ -550,13 +546,13 @@ func TestAVLTreeIteratorLast(t *testing.T) { func TestAVLTreeIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index interface{}, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // NextTo (empty) { - tree := NewWithIntComparator() + tree := New[int, string]() it := tree.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty tree") @@ -565,7 +561,7 @@ func TestAVLTreeIteratorNextTo(t *testing.T) { // NextTo (not found) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(0, "xx") tree.Put(1, "yy") it := tree.Iterator() @@ -576,7 +572,7 @@ func TestAVLTreeIteratorNextTo(t *testing.T) { // NextTo (found) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(2, "cc") tree.Put(0, "aa") tree.Put(1, "bb") @@ -585,13 +581,13 @@ func TestAVLTreeIteratorNextTo(t *testing.T) { if !it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty tree") } - if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Key(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Next() { t.Errorf("Should go to first element") } - if index, value := it.Key(), it.Value(); index != 2 || value.(string) != "cc" { + if index, value := it.Key(), it.Value(); index != 2 || value != "cc" { t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") } if it.Next() { @@ -602,13 +598,13 @@ func TestAVLTreeIteratorNextTo(t *testing.T) { func TestAVLTreeIteratorPrevTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index interface{}, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // PrevTo (empty) { - tree := NewWithIntComparator() + tree := New[int, string]() it := tree.Iterator() it.End() for it.PrevTo(seek) { @@ -618,7 +614,7 @@ func TestAVLTreeIteratorPrevTo(t *testing.T) { // PrevTo (not found) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(0, "xx") tree.Put(1, "yy") it := tree.Iterator() @@ -630,7 +626,7 @@ func TestAVLTreeIteratorPrevTo(t *testing.T) { // PrevTo (found) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(2, "cc") tree.Put(0, "aa") tree.Put(1, "bb") @@ -639,13 +635,13 @@ func TestAVLTreeIteratorPrevTo(t *testing.T) { if !it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty tree") } - if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Key(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Prev() { t.Errorf("Should go to first element") } - if index, value := it.Key(), it.Value(); index != 0 || value.(string) != "aa" { + if index, value := it.Key(), it.Value(); index != 0 || value != "aa" { t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") } if it.Prev() { @@ -655,8 +651,7 @@ func TestAVLTreeIteratorPrevTo(t *testing.T) { } func TestAVLTreeSerialization(t *testing.T) { - tree := NewWith(utils.StringComparator) - tree = NewWithStringComparator() + tree := New[string, string]() tree.Put("c", "3") tree.Put("b", "2") tree.Put("a", "1") @@ -666,11 +661,11 @@ func TestAVLTreeSerialization(t *testing.T) { if actualValue, expectedValue := tree.Size(), 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if actualValue := tree.Keys(); actualValue[0].(string) != "a" || actualValue[1].(string) != "b" || actualValue[2].(string) != "c" { - t.Errorf("Got %v expected %v", actualValue, "[a,b,c]") + if actualValue, expectedValue := tree.Keys(), []string{"a", "b", "c"}; !slices.Equal(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if actualValue := tree.Values(); actualValue[0].(string) != "1" || actualValue[1].(string) != "2" || actualValue[2].(string) != "3" { - t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + if actualValue, expectedValue := tree.Values(), []string{"1", "2", "3"}; !slices.Equal(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } if err != nil { t.Errorf("Got error %v", err) @@ -690,14 +685,24 @@ func TestAVLTreeSerialization(t *testing.T) { t.Errorf("Got error %v", err) } - err = json.Unmarshal([]byte(`{"a":1,"b":2}`), &tree) + intTree := New[string, int]() + err = json.Unmarshal([]byte(`{"a":1,"b":2}`), intTree) if err != nil { t.Errorf("Got error %v", err) } + if actualValue, expectedValue := intTree.Size(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := intTree.Keys(), []string{"a", "b"}; !slices.Equal(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := intTree.Values(), []int{1, 2}; !slices.Equal(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } } func TestAVLTreeString(t *testing.T) { - c := NewWithIntComparator() + c := New[int, int]() c.Put(1, 1) c.Put(2, 1) c.Put(3, 1) @@ -712,7 +717,7 @@ func TestAVLTreeString(t *testing.T) { } } -func benchmarkGet(b *testing.B, tree *Tree, size int) { +func benchmarkGet(b *testing.B, tree *Tree[int, struct{}], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { tree.Get(n) @@ -720,7 +725,7 @@ func benchmarkGet(b *testing.B, tree *Tree, size int) { } } -func benchmarkPut(b *testing.B, tree *Tree, size int) { +func benchmarkPut(b *testing.B, tree *Tree[int, struct{}], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { tree.Put(n, struct{}{}) @@ -728,7 +733,7 @@ func benchmarkPut(b *testing.B, tree *Tree, size int) { } } -func benchmarkRemove(b *testing.B, tree *Tree, size int) { +func benchmarkRemove(b *testing.B, tree *Tree[int, struct{}], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { tree.Remove(n) @@ -739,7 +744,7 @@ func benchmarkRemove(b *testing.B, tree *Tree, size int) { func BenchmarkAVLTreeGet100(b *testing.B) { b.StopTimer() size := 100 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -750,7 +755,7 @@ func BenchmarkAVLTreeGet100(b *testing.B) { func BenchmarkAVLTreeGet1000(b *testing.B) { b.StopTimer() size := 1000 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -761,7 +766,7 @@ func BenchmarkAVLTreeGet1000(b *testing.B) { func BenchmarkAVLTreeGet10000(b *testing.B) { b.StopTimer() size := 10000 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -772,7 +777,7 @@ func BenchmarkAVLTreeGet10000(b *testing.B) { func BenchmarkAVLTreeGet100000(b *testing.B) { b.StopTimer() size := 100000 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -783,7 +788,7 @@ func BenchmarkAVLTreeGet100000(b *testing.B) { func BenchmarkAVLTreePut100(b *testing.B) { b.StopTimer() size := 100 - tree := NewWithIntComparator() + tree := New[int, struct{}]() b.StartTimer() benchmarkPut(b, tree, size) } @@ -791,7 +796,7 @@ func BenchmarkAVLTreePut100(b *testing.B) { func BenchmarkAVLTreePut1000(b *testing.B) { b.StopTimer() size := 1000 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -802,7 +807,7 @@ func BenchmarkAVLTreePut1000(b *testing.B) { func BenchmarkAVLTreePut10000(b *testing.B) { b.StopTimer() size := 10000 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -813,7 +818,7 @@ func BenchmarkAVLTreePut10000(b *testing.B) { func BenchmarkAVLTreePut100000(b *testing.B) { b.StopTimer() size := 100000 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -824,7 +829,7 @@ func BenchmarkAVLTreePut100000(b *testing.B) { func BenchmarkAVLTreeRemove100(b *testing.B) { b.StopTimer() size := 100 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -835,7 +840,7 @@ func BenchmarkAVLTreeRemove100(b *testing.B) { func BenchmarkAVLTreeRemove1000(b *testing.B) { b.StopTimer() size := 1000 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -846,7 +851,7 @@ func BenchmarkAVLTreeRemove1000(b *testing.B) { func BenchmarkAVLTreeRemove10000(b *testing.B) { b.StopTimer() size := 10000 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -857,7 +862,7 @@ func BenchmarkAVLTreeRemove10000(b *testing.B) { func BenchmarkAVLTreeRemove100000(b *testing.B) { b.StopTimer() size := 100000 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } diff --git a/trees/avltree/iterator.go b/trees/avltree/iterator.go index 0186e40b..8541ce0a 100644 --- a/trees/avltree/iterator.go +++ b/trees/avltree/iterator.go @@ -4,15 +4,15 @@ package avltree -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Assert Iterator implementation -var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) +var _ containers.ReverseIteratorWithKey[string, int] = (*Iterator[string, int])(nil) // Iterator holding the iterator's state -type Iterator struct { - tree *Tree - node *Node +type Iterator[K comparable, V any] struct { + tree *Tree[K, V] + node *Node[K, V] position position } @@ -23,15 +23,15 @@ const ( ) // Iterator returns a stateful iterator whose elements are key/value pairs. -func (tree *Tree) Iterator() containers.ReverseIteratorWithKey { - return &Iterator{tree: tree, node: nil, position: begin} +func (tree *Tree[K, V]) Iterator() *Iterator[K, V] { + return &Iterator[K, V]{tree: tree, node: nil, position: begin} } // 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. // Modifies the state of the iterator. -func (iterator *Iterator) Next() bool { +func (iterator *Iterator[K, V]) Next() bool { switch iterator.position { case begin: iterator.position = between @@ -51,7 +51,7 @@ func (iterator *Iterator) Next() bool { // If Prev() returns true, then next element's key and value can be retrieved by Key() and Value(). // If Prev() 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) Prev() bool { +func (iterator *Iterator[K, V]) Prev() bool { switch iterator.position { case end: iterator.position = between @@ -69,38 +69,38 @@ func (iterator *Iterator) Prev() bool { // Value returns the current element's value. // Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { +func (iterator *Iterator[K, V]) Value() (v V) { if iterator.node == nil { - return nil + return v } return iterator.node.Value } // Key returns the current element's key. // Does not modify the state of the iterator. -func (iterator *Iterator) Key() interface{} { +func (iterator *Iterator[K, V]) Key() (k K) { if iterator.node == nil { - return nil + return k } return iterator.node.Key } // Node returns the current element's node. // Does not modify the state of the iterator. -func (iterator *Iterator) Node() *Node { +func (iterator *Iterator[K, V]) Node() *Node[K, V] { return iterator.node } // Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. -func (iterator *Iterator) Begin() { +func (iterator *Iterator[K, V]) Begin() { iterator.node = nil iterator.position = 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() { +func (iterator *Iterator[K, V]) End() { iterator.node = nil iterator.position = end } @@ -108,7 +108,7 @@ func (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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator -func (iterator *Iterator) First() bool { +func (iterator *Iterator[K, V]) First() bool { iterator.Begin() return iterator.Next() } @@ -116,7 +116,7 @@ func (iterator *Iterator) First() bool { // 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. -func (iterator *Iterator) Last() bool { +func (iterator *Iterator[K, V]) Last() bool { iterator.End() return iterator.Prev() } @@ -125,7 +125,7 @@ func (iterator *Iterator) Last() bool { // 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. -func (iterator *Iterator) NextTo(f func(key interface{}, value interface{}) bool) bool { +func (iterator *Iterator[K, V]) NextTo(f func(key K, value V) bool) bool { for iterator.Next() { key, value := iterator.Key(), iterator.Value() if f(key, value) { @@ -139,7 +139,7 @@ func (iterator *Iterator) NextTo(f func(key interface{}, value interface{}) bool // 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. -func (iterator *Iterator) PrevTo(f func(key interface{}, value interface{}) bool) bool { +func (iterator *Iterator[K, V]) PrevTo(f func(key K, value V) bool) bool { for iterator.Prev() { key, value := iterator.Key(), iterator.Value() if f(key, value) { diff --git a/trees/avltree/serialization.go b/trees/avltree/serialization.go index 257c4040..4b3da5d3 100644 --- a/trees/avltree/serialization.go +++ b/trees/avltree/serialization.go @@ -6,43 +6,46 @@ package avltree import ( "encoding/json" - "github.com/emirpasic/gods/containers" - "github.com/emirpasic/gods/utils" + + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*Tree)(nil) -var _ containers.JSONDeserializer = (*Tree)(nil) +var _ containers.JSONSerializer = (*Tree[string, int])(nil) +var _ containers.JSONDeserializer = (*Tree[string, int])(nil) // ToJSON outputs the JSON representation of the tree. -func (tree *Tree) ToJSON() ([]byte, error) { - elements := make(map[string]interface{}) +func (tree *Tree[K, V]) ToJSON() ([]byte, error) { + elements := make(map[K]V) it := tree.Iterator() for it.Next() { - elements[utils.ToString(it.Key())] = it.Value() + elements[it.Key()] = it.Value() } return json.Marshal(&elements) } // FromJSON populates the tree from the input JSON representation. -func (tree *Tree) FromJSON(data []byte) error { - elements := make(map[string]interface{}) +func (tree *Tree[K, V]) FromJSON(data []byte) error { + elements := make(map[K]V) err := json.Unmarshal(data, &elements) - if err == nil { - tree.Clear() - for key, value := range elements { - tree.Put(key, value) - } + if err != nil { + return err + } + + tree.Clear() + for key, value := range elements { + tree.Put(key, value) } - return err + + return nil } // UnmarshalJSON @implements json.Unmarshaler -func (tree *Tree) UnmarshalJSON(bytes []byte) error { +func (tree *Tree[K, V]) UnmarshalJSON(bytes []byte) error { return tree.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (tree *Tree) MarshalJSON() ([]byte, error) { +func (tree *Tree[K, V]) MarshalJSON() ([]byte, error) { return tree.ToJSON() } diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index e658f257..9f1605cd 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -12,39 +12,36 @@ package binaryheap import ( + "cmp" "fmt" - "github.com/emirpasic/gods/lists/arraylist" - "github.com/emirpasic/gods/trees" - "github.com/emirpasic/gods/utils" "strings" + + "github.com/emirpasic/gods/v2/lists/arraylist" + "github.com/emirpasic/gods/v2/trees" + "github.com/emirpasic/gods/v2/utils" ) // Assert Tree implementation -var _ trees.Tree = (*Heap)(nil) +var _ trees.Tree[int] = (*Heap[int])(nil) // Heap holds elements in an array-list -type Heap struct { - list *arraylist.List - Comparator utils.Comparator +type Heap[T comparable] struct { + list *arraylist.List[T] + Comparator utils.Comparator[T] } -// NewWith instantiates a new empty heap tree with the custom comparator. -func NewWith(comparator utils.Comparator) *Heap { - return &Heap{list: arraylist.New(), Comparator: comparator} +// New instantiates a new empty heap tree with the built-in comparator for T +func New[T cmp.Ordered]() *Heap[T] { + return &Heap[T]{list: arraylist.New[T](), Comparator: cmp.Compare[T]} } -// NewWithIntComparator instantiates a new empty heap with the IntComparator, i.e. elements are of type int. -func NewWithIntComparator() *Heap { - return &Heap{list: arraylist.New(), Comparator: utils.IntComparator} -} - -// NewWithStringComparator instantiates a new empty heap with the StringComparator, i.e. elements are of type string. -func NewWithStringComparator() *Heap { - return &Heap{list: arraylist.New(), Comparator: utils.StringComparator} +// NewWith instantiates a new empty heap tree with the custom comparator. +func NewWith[T comparable](comparator utils.Comparator[T]) *Heap[T] { + return &Heap[T]{list: arraylist.New[T](), Comparator: comparator} } // Push adds a value onto the heap and bubbles it up accordingly. -func (heap *Heap) Push(values ...interface{}) { +func (heap *Heap[T]) Push(values ...T) { if len(values) == 1 { heap.list.Add(values[0]) heap.bubbleUp() @@ -62,7 +59,7 @@ func (heap *Heap) Push(values ...interface{}) { // Pop removes top element on heap and returns it, or nil if heap is empty. // Second return parameter is true, unless the heap was empty and there was nothing to pop. -func (heap *Heap) Pop() (value interface{}, ok bool) { +func (heap *Heap[T]) Pop() (value T, ok bool) { value, ok = heap.list.Get(0) if !ok { return @@ -76,28 +73,28 @@ func (heap *Heap) Pop() (value interface{}, ok bool) { // Peek returns top element on the heap without removing it, or nil if heap is empty. // Second return parameter is true, unless the heap was empty and there was nothing to peek. -func (heap *Heap) Peek() (value interface{}, ok bool) { +func (heap *Heap[T]) Peek() (value T, ok bool) { return heap.list.Get(0) } // Empty returns true if heap does not contain any elements. -func (heap *Heap) Empty() bool { +func (heap *Heap[T]) Empty() bool { return heap.list.Empty() } // Size returns number of elements within the heap. -func (heap *Heap) Size() int { +func (heap *Heap[T]) Size() int { return heap.list.Size() } // Clear removes all elements from the heap. -func (heap *Heap) Clear() { +func (heap *Heap[T]) Clear() { heap.list.Clear() } // Values returns all elements in the heap. -func (heap *Heap) Values() []interface{} { - values := make([]interface{}, heap.list.Size(), heap.list.Size()) +func (heap *Heap[T]) Values() []T { + values := make([]T, heap.list.Size(), heap.list.Size()) for it := heap.Iterator(); it.Next(); { values[it.Index()] = it.Value() } @@ -105,7 +102,7 @@ func (heap *Heap) Values() []interface{} { } // String returns a string representation of container -func (heap *Heap) String() string { +func (heap *Heap[T]) String() string { str := "BinaryHeap\n" values := []string{} for it := heap.Iterator(); it.Next(); { @@ -117,13 +114,13 @@ func (heap *Heap) String() string { // Performs the "bubble down" operation. This is to place the element that is at the root // of the heap in its correct place so that the heap maintains the min/max-heap order property. -func (heap *Heap) bubbleDown() { +func (heap *Heap[T]) bubbleDown() { heap.bubbleDownIndex(0) } // Performs the "bubble down" operation. This is to place the element that is at the index // of the heap in its correct place so that the heap maintains the min/max-heap order property. -func (heap *Heap) bubbleDownIndex(index int) { +func (heap *Heap[T]) bubbleDownIndex(index int) { size := heap.list.Size() for leftIndex := index<<1 + 1; leftIndex < size; leftIndex = index<<1 + 1 { rightIndex := index<<1 + 2 @@ -147,7 +144,7 @@ func (heap *Heap) bubbleDownIndex(index int) { // Performs the "bubble up" operation. This is to place a newly inserted // element (i.e. last element in the list) in its correct place so that // the heap maintains the min/max-heap order property. -func (heap *Heap) bubbleUp() { +func (heap *Heap[T]) bubbleUp() { index := heap.list.Size() - 1 for parentIndex := (index - 1) >> 1; index > 0; parentIndex = (index - 1) >> 1 { indexValue, _ := heap.list.Get(index) @@ -161,6 +158,6 @@ func (heap *Heap) bubbleUp() { } // Check that the index is within bounds of the list -func (heap *Heap) withinRange(index int) bool { +func (heap *Heap[T]) withinRange(index int) bool { return index >= 0 && index < heap.list.Size() } diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go index bb5c42b1..5ee8df4e 100644 --- a/trees/binaryheap/binaryheap_test.go +++ b/trees/binaryheap/binaryheap_test.go @@ -7,12 +7,13 @@ package binaryheap import ( "encoding/json" "math/rand" + "slices" "strings" "testing" ) func TestBinaryHeapPush(t *testing.T) { - heap := NewWithIntComparator() + heap := New[int]() if actualValue := heap.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) @@ -22,8 +23,8 @@ func TestBinaryHeapPush(t *testing.T) { heap.Push(2) heap.Push(1) - if actualValue := heap.Values(); actualValue[0].(int) != 1 || actualValue[1].(int) != 2 || actualValue[2].(int) != 3 { - t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + if actualValue, expectedValue := heap.Values(), []int{1, 2, 3}; !slices.Equal(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } if actualValue := heap.Empty(); actualValue != false { t.Errorf("Got %v expected %v", actualValue, false) @@ -37,12 +38,12 @@ func TestBinaryHeapPush(t *testing.T) { } func TestBinaryHeapPushBulk(t *testing.T) { - heap := NewWithIntComparator() + heap := New[int]() heap.Push(15, 20, 3, 1, 2) - if actualValue := heap.Values(); actualValue[0].(int) != 1 || actualValue[1].(int) != 2 || actualValue[2].(int) != 3 { - t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + if actualValue, expectedValue := heap.Values(), []int{1, 2, 3, 15, 20}; !slices.Equal(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } if actualValue, ok := heap.Pop(); actualValue != 1 || !ok { t.Errorf("Got %v expected %v", actualValue, 1) @@ -50,7 +51,7 @@ func TestBinaryHeapPushBulk(t *testing.T) { } func TestBinaryHeapPop(t *testing.T) { - heap := NewWithIntComparator() + heap := New[int]() if actualValue := heap.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) @@ -70,7 +71,7 @@ func TestBinaryHeapPop(t *testing.T) { if actualValue, ok := heap.Pop(); actualValue != 3 || !ok { t.Errorf("Got %v expected %v", actualValue, 3) } - if actualValue, ok := heap.Pop(); actualValue != nil || ok { + if actualValue, ok := heap.Pop(); actualValue != 0 || ok { t.Errorf("Got %v expected %v", actualValue, nil) } if actualValue := heap.Empty(); actualValue != true { @@ -82,7 +83,7 @@ func TestBinaryHeapPop(t *testing.T) { } func TestBinaryHeapRandom(t *testing.T) { - heap := NewWithIntComparator() + heap := New[int]() rand.Seed(3) for i := 0; i < 10000; i++ { @@ -93,7 +94,7 @@ func TestBinaryHeapRandom(t *testing.T) { prev, _ := heap.Pop() for !heap.Empty() { curr, _ := heap.Pop() - if prev.(int) > curr.(int) { + if prev > curr { t.Errorf("Heap property invalidated. prev: %v current: %v", prev, curr) } prev = curr @@ -101,7 +102,7 @@ func TestBinaryHeapRandom(t *testing.T) { } func TestBinaryHeapIteratorOnEmpty(t *testing.T) { - heap := NewWithIntComparator() + heap := New[int]() it := heap.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty heap") @@ -109,7 +110,7 @@ func TestBinaryHeapIteratorOnEmpty(t *testing.T) { } func TestBinaryHeapIteratorNext(t *testing.T) { - heap := NewWithIntComparator() + heap := New[int]() heap.Push(3) heap.Push(2) heap.Push(1) @@ -146,7 +147,7 @@ func TestBinaryHeapIteratorNext(t *testing.T) { } func TestBinaryHeapIteratorPrev(t *testing.T) { - heap := NewWithIntComparator() + heap := New[int]() heap.Push(3) heap.Push(2) heap.Push(1) @@ -185,7 +186,7 @@ func TestBinaryHeapIteratorPrev(t *testing.T) { } func TestBinaryHeapIteratorBegin(t *testing.T) { - heap := NewWithIntComparator() + heap := New[int]() it := heap.Iterator() it.Begin() heap.Push(2) @@ -201,7 +202,7 @@ func TestBinaryHeapIteratorBegin(t *testing.T) { } func TestBinaryHeapIteratorEnd(t *testing.T) { - heap := NewWithIntComparator() + heap := New[int]() it := heap.Iterator() if index := it.Index(); index != -1 { @@ -228,7 +229,7 @@ func TestBinaryHeapIteratorEnd(t *testing.T) { } func TestBinaryHeapIteratorFirst(t *testing.T) { - heap := NewWithIntComparator() + heap := New[int]() it := heap.Iterator() if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -245,7 +246,7 @@ func TestBinaryHeapIteratorFirst(t *testing.T) { } func TestBinaryHeapIteratorLast(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int]() it := tree.Iterator() if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) @@ -263,13 +264,13 @@ func TestBinaryHeapIteratorLast(t *testing.T) { func TestBinaryHeapIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // NextTo (empty) { - tree := NewWithStringComparator() + tree := New[string]() it := tree.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") @@ -278,7 +279,7 @@ func TestBinaryHeapIteratorNextTo(t *testing.T) { // NextTo (not found) { - tree := NewWithStringComparator() + tree := New[string]() tree.Push("xx") tree.Push("yy") it := tree.Iterator() @@ -289,7 +290,7 @@ func TestBinaryHeapIteratorNextTo(t *testing.T) { // NextTo (found) { - tree := NewWithStringComparator() + tree := New[string]() tree.Push("aa") tree.Push("bb") tree.Push("cc") @@ -298,13 +299,13 @@ func TestBinaryHeapIteratorNextTo(t *testing.T) { if !it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Next() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + if index, value := it.Index(), it.Value(); index != 2 || value != "cc" { t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") } if it.Next() { @@ -315,13 +316,13 @@ func TestBinaryHeapIteratorNextTo(t *testing.T) { func TestBinaryHeapIteratorPrevTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index int, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // PrevTo (empty) { - tree := NewWithStringComparator() + tree := New[string]() it := tree.Iterator() it.End() for it.PrevTo(seek) { @@ -331,7 +332,7 @@ func TestBinaryHeapIteratorPrevTo(t *testing.T) { // PrevTo (not found) { - tree := NewWithStringComparator() + tree := New[string]() tree.Push("xx") tree.Push("yy") it := tree.Iterator() @@ -343,7 +344,7 @@ func TestBinaryHeapIteratorPrevTo(t *testing.T) { // PrevTo (found) { - tree := NewWithStringComparator() + tree := New[string]() tree.Push("aa") tree.Push("bb") tree.Push("cc") @@ -352,13 +353,13 @@ func TestBinaryHeapIteratorPrevTo(t *testing.T) { if !it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty list") } - if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Index(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Prev() { t.Errorf("Should go to first element") } - if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "aa" { + if index, value := it.Index(), it.Value(); index != 0 || value != "aa" { t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") } if it.Prev() { @@ -368,7 +369,7 @@ func TestBinaryHeapIteratorPrevTo(t *testing.T) { } func TestBinaryHeapSerialization(t *testing.T) { - heap := NewWithStringComparator() + heap := New[string]() heap.Push("c") heap.Push("b") @@ -376,8 +377,8 @@ func TestBinaryHeapSerialization(t *testing.T) { var err error assert := func() { - if actualValue := heap.Values(); actualValue[0].(string) != "a" || actualValue[1].(string) != "b" || actualValue[2].(string) != "c" { - t.Errorf("Got %v expected %v", actualValue, "[1,3,2]") + if actualValue, expectedValue := heap.Values(), []string{"a", "b", "c"}; !slices.Equal(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } if actualValue := heap.Size(); actualValue != 3 { t.Errorf("Got %v expected %v", actualValue, 3) @@ -403,21 +404,25 @@ func TestBinaryHeapSerialization(t *testing.T) { t.Errorf("Got error %v", err) } - err = json.Unmarshal([]byte(`[1,2,3]`), &heap) + intHeap := New[int]() + err = json.Unmarshal([]byte(`[1,2,3]`), &intHeap) if err != nil { t.Errorf("Got error %v", err) } + if actualValue, expectedValue := intHeap.Values(), []int{1, 2, 3}; !slices.Equal(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } } func TestBTreeString(t *testing.T) { - c := NewWithIntComparator() + c := New[int]() c.Push(1) if !strings.HasPrefix(c.String(), "BinaryHeap") { t.Errorf("String should start with container name") } } -func benchmarkPush(b *testing.B, heap *Heap, size int) { +func benchmarkPush(b *testing.B, heap *Heap[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { heap.Push(n) @@ -425,7 +430,7 @@ func benchmarkPush(b *testing.B, heap *Heap, size int) { } } -func benchmarkPop(b *testing.B, heap *Heap, size int) { +func benchmarkPop(b *testing.B, heap *Heap[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { heap.Pop() @@ -436,7 +441,7 @@ func benchmarkPop(b *testing.B, heap *Heap, size int) { func BenchmarkBinaryHeapPop100(b *testing.B) { b.StopTimer() size := 100 - heap := NewWithIntComparator() + heap := New[int]() for n := 0; n < size; n++ { heap.Push(n) } @@ -447,7 +452,7 @@ func BenchmarkBinaryHeapPop100(b *testing.B) { func BenchmarkBinaryHeapPop1000(b *testing.B) { b.StopTimer() size := 1000 - heap := NewWithIntComparator() + heap := New[int]() for n := 0; n < size; n++ { heap.Push(n) } @@ -458,7 +463,7 @@ func BenchmarkBinaryHeapPop1000(b *testing.B) { func BenchmarkBinaryHeapPop10000(b *testing.B) { b.StopTimer() size := 10000 - heap := NewWithIntComparator() + heap := New[int]() for n := 0; n < size; n++ { heap.Push(n) } @@ -469,7 +474,7 @@ func BenchmarkBinaryHeapPop10000(b *testing.B) { func BenchmarkBinaryHeapPop100000(b *testing.B) { b.StopTimer() size := 100000 - heap := NewWithIntComparator() + heap := New[int]() for n := 0; n < size; n++ { heap.Push(n) } @@ -480,7 +485,7 @@ func BenchmarkBinaryHeapPop100000(b *testing.B) { func BenchmarkBinaryHeapPush100(b *testing.B) { b.StopTimer() size := 100 - heap := NewWithIntComparator() + heap := New[int]() b.StartTimer() benchmarkPush(b, heap, size) } @@ -488,7 +493,7 @@ func BenchmarkBinaryHeapPush100(b *testing.B) { func BenchmarkBinaryHeapPush1000(b *testing.B) { b.StopTimer() size := 1000 - heap := NewWithIntComparator() + heap := New[int]() for n := 0; n < size; n++ { heap.Push(n) } @@ -499,7 +504,7 @@ func BenchmarkBinaryHeapPush1000(b *testing.B) { func BenchmarkBinaryHeapPush10000(b *testing.B) { b.StopTimer() size := 10000 - heap := NewWithIntComparator() + heap := New[int]() for n := 0; n < size; n++ { heap.Push(n) } @@ -510,7 +515,7 @@ func BenchmarkBinaryHeapPush10000(b *testing.B) { func BenchmarkBinaryHeapPush100000(b *testing.B) { b.StopTimer() size := 100000 - heap := NewWithIntComparator() + heap := New[int]() for n := 0; n < size; n++ { heap.Push(n) } diff --git a/trees/binaryheap/iterator.go b/trees/binaryheap/iterator.go index f2179633..73ff1815 100644 --- a/trees/binaryheap/iterator.go +++ b/trees/binaryheap/iterator.go @@ -5,28 +5,28 @@ package binaryheap import ( - "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/v2/containers" ) // Assert Iterator implementation -var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) +var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. -type Iterator struct { - heap *Heap +type Iterator[T comparable] struct { + heap *Heap[T] index int } // Iterator returns a stateful iterator whose values can be fetched by an index. -func (heap *Heap) Iterator() Iterator { - return Iterator{heap: heap, index: -1} +func (heap *Heap[T]) Iterator() *Iterator[T] { + return &Iterator[T]{heap: heap, index: -1} } // 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 { +func (iterator *Iterator[T]) Next() bool { if iterator.index < iterator.heap.Size() { iterator.index++ } @@ -36,7 +36,7 @@ func (iterator *Iterator) Next() bool { // 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 { +func (iterator *Iterator[T]) Prev() bool { if iterator.index >= 0 { iterator.index-- } @@ -45,7 +45,7 @@ func (iterator *Iterator) Prev() bool { // Value returns the current element's value. // Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { +func (iterator *Iterator[T]) Value() T { start, end := evaluateRange(iterator.index) if end > iterator.heap.Size() { end = iterator.heap.Size() @@ -64,26 +64,26 @@ func (iterator *Iterator) Value() interface{} { // Index returns the current element's index. // Does not modify the state of the iterator. -func (iterator *Iterator) Index() int { +func (iterator *Iterator[T]) Index() int { return 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() { +func (iterator *Iterator[T]) Begin() { iterator.index = -1 } // 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() { +func (iterator *Iterator[T]) End() { iterator.index = iterator.heap.Size() } // 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 { +func (iterator *Iterator[T]) First() bool { iterator.Begin() return iterator.Next() } @@ -91,7 +91,7 @@ func (iterator *Iterator) First() bool { // 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 { +func (iterator *Iterator[T]) Last() bool { iterator.End() return iterator.Prev() } @@ -100,7 +100,7 @@ func (iterator *Iterator) Last() bool { // 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. -func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) NextTo(f func(index int, value T) bool) bool { for iterator.Next() { index, value := iterator.Index(), iterator.Value() if f(index, value) { @@ -114,7 +114,7 @@ func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool // 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. -func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool { +func (iterator *Iterator[T]) PrevTo(f func(index int, value T) bool) bool { for iterator.Prev() { index, value := iterator.Index(), iterator.Value() if f(index, value) { diff --git a/trees/binaryheap/serialization.go b/trees/binaryheap/serialization.go index c1fce0a0..5881b05b 100644 --- a/trees/binaryheap/serialization.go +++ b/trees/binaryheap/serialization.go @@ -5,29 +5,29 @@ package binaryheap import ( - "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*Heap)(nil) -var _ containers.JSONDeserializer = (*Heap)(nil) +var _ containers.JSONSerializer = (*Heap[int])(nil) +var _ containers.JSONDeserializer = (*Heap[int])(nil) // ToJSON outputs the JSON representation of the heap. -func (heap *Heap) ToJSON() ([]byte, error) { +func (heap *Heap[T]) ToJSON() ([]byte, error) { return heap.list.ToJSON() } // FromJSON populates the heap from the input JSON representation. -func (heap *Heap) FromJSON(data []byte) error { +func (heap *Heap[T]) FromJSON(data []byte) error { return heap.list.FromJSON(data) } // UnmarshalJSON @implements json.Unmarshaler -func (heap *Heap) UnmarshalJSON(bytes []byte) error { +func (heap *Heap[T]) UnmarshalJSON(bytes []byte) error { return heap.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (heap *Heap) MarshalJSON() ([]byte, error) { +func (heap *Heap[T]) MarshalJSON() ([]byte, error) { return heap.ToJSON() } diff --git a/trees/btree/btree.go b/trees/btree/btree.go index eae4576b..75f60ad6 100644 --- a/trees/btree/btree.go +++ b/trees/btree/btree.go @@ -18,62 +18,59 @@ package btree import ( "bytes" + "cmp" "fmt" - "github.com/emirpasic/gods/trees" - "github.com/emirpasic/gods/utils" "strings" + + "github.com/emirpasic/gods/v2/trees" + "github.com/emirpasic/gods/v2/utils" ) // Assert Tree implementation -var _ trees.Tree = (*Tree)(nil) +var _ trees.Tree[int] = (*Tree[string, int])(nil) // Tree holds elements of the B-tree -type Tree struct { - Root *Node // Root node - Comparator utils.Comparator // Key comparator - size int // Total number of keys in the tree - m int // order (maximum number of children) +type Tree[K comparable, V any] struct { + Root *Node[K, V] // Root node + Comparator utils.Comparator[K] // Key comparator + size int // Total number of keys in the tree + m int // order (maximum number of children) } // Node is a single element within the tree -type Node struct { - Parent *Node - Entries []*Entry // Contained keys in node - Children []*Node // Children nodes +type Node[K comparable, V any] struct { + Parent *Node[K, V] + Entries []*Entry[K, V] // Contained keys in node + Children []*Node[K, V] // Children nodes } // Entry represents the key-value pair contained within nodes -type Entry struct { - Key interface{} - Value interface{} +type Entry[K comparable, V any] struct { + Key K + Value V +} + +// New instantiates a B-tree with the order (maximum number of children) and the built-in comparator for K +func New[K cmp.Ordered, V any](order int) *Tree[K, V] { + return NewWith[K, V](order, cmp.Compare[K]) } // NewWith instantiates a B-tree with the order (maximum number of children) and a custom key comparator. -func NewWith(order int, comparator utils.Comparator) *Tree { +func NewWith[K comparable, V any](order int, comparator utils.Comparator[K]) *Tree[K, V] { if order < 3 { panic("Invalid order, should be at least 3") } - return &Tree{m: order, Comparator: comparator} -} - -// NewWithIntComparator instantiates a B-tree with the order (maximum number of children) and the IntComparator, i.e. keys are of type int. -func NewWithIntComparator(order int) *Tree { - return NewWith(order, utils.IntComparator) -} - -// NewWithStringComparator instantiates a B-tree with the order (maximum number of children) and the StringComparator, i.e. keys are of type string. -func NewWithStringComparator(order int) *Tree { - return NewWith(order, utils.StringComparator) + return &Tree[K, V]{m: order, Comparator: comparator} } // Put inserts key-value pair node into the tree. // If key already exists, then its value is updated with the new value. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *Tree) Put(key interface{}, value interface{}) { - entry := &Entry{Key: key, Value: value} +func (tree *Tree[K, V]) Put(key K, value V) { + entry := &Entry[K, V]{Key: key, Value: value} if tree.Root == nil { - tree.Root = &Node{Entries: []*Entry{entry}, Children: []*Node{}} + tree.Root = &Node[K, V]{Entries: []*Entry[K, V]{entry}, Children: []*Node[K, V]{}} tree.size++ return } @@ -86,24 +83,24 @@ func (tree *Tree) Put(key interface{}, value interface{}) { // Get searches the node in the tree by key and returns its value or nil if key is not found in tree. // Second return parameter is true if key was found, otherwise false. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *Tree) Get(key interface{}) (value interface{}, found bool) { +func (tree *Tree[K, V]) Get(key K) (value V, found bool) { node, index, found := tree.searchRecursively(tree.Root, key) if found { return node.Entries[index].Value, true } - return nil, false + return value, false } // GetNode searches the node in the tree by key and returns its node or nil if key is not found in tree. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *Tree) GetNode(key interface{}) *Node { +func (tree *Tree[K, V]) GetNode(key K) *Node[K, V] { node, _, _ := tree.searchRecursively(tree.Root, key) return node } // Remove remove the node from the tree by key. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *Tree) Remove(key interface{}) { +func (tree *Tree[K, V]) Remove(key K) { node, index, found := tree.searchRecursively(tree.Root, key) if found { tree.delete(node, index) @@ -112,18 +109,18 @@ func (tree *Tree) Remove(key interface{}) { } // Empty returns true if tree does not contain any nodes -func (tree *Tree) Empty() bool { +func (tree *Tree[K, V]) Empty() bool { return tree.size == 0 } // Size returns number of nodes in the tree. -func (tree *Tree) Size() int { +func (tree *Tree[K, V]) Size() int { return tree.size } // Size returns the number of elements stored in the subtree. // Computed dynamically on each call, i.e. the subtree is traversed to count the number of the nodes. -func (node *Node) Size() int { +func (node *Node[K, V]) Size() int { if node == nil { return 0 } @@ -135,8 +132,8 @@ func (node *Node) Size() int { } // Keys returns all keys in-order -func (tree *Tree) Keys() []interface{} { - keys := make([]interface{}, tree.size) +func (tree *Tree[K, V]) Keys() []K { + keys := make([]K, tree.size) it := tree.Iterator() for i := 0; it.Next(); i++ { keys[i] = it.Key() @@ -145,8 +142,8 @@ func (tree *Tree) Keys() []interface{} { } // Values returns all values in-order based on the key. -func (tree *Tree) Values() []interface{} { - values := make([]interface{}, tree.size) +func (tree *Tree[K, V]) Values() []V { + values := make([]V, tree.size) it := tree.Iterator() for i := 0; it.Next(); i++ { values[i] = it.Value() @@ -155,23 +152,23 @@ func (tree *Tree) Values() []interface{} { } // Clear removes all nodes from the tree. -func (tree *Tree) Clear() { +func (tree *Tree[K, V]) Clear() { tree.Root = nil tree.size = 0 } // Height returns the height of the tree. -func (tree *Tree) Height() int { +func (tree *Tree[K, V]) Height() int { return tree.Root.height() } // Left returns the left-most (min) node or nil if tree is empty. -func (tree *Tree) Left() *Node { +func (tree *Tree[K, V]) Left() *Node[K, V] { return tree.left(tree.Root) } // LeftKey returns the left-most (min) key or nil if tree is empty. -func (tree *Tree) LeftKey() interface{} { +func (tree *Tree[K, V]) LeftKey() interface{} { if left := tree.Left(); left != nil { return left.Entries[0].Key } @@ -179,7 +176,7 @@ func (tree *Tree) LeftKey() interface{} { } // LeftValue returns the left-most value or nil if tree is empty. -func (tree *Tree) LeftValue() interface{} { +func (tree *Tree[K, V]) LeftValue() interface{} { if left := tree.Left(); left != nil { return left.Entries[0].Value } @@ -187,12 +184,12 @@ func (tree *Tree) LeftValue() interface{} { } // Right returns the right-most (max) node or nil if tree is empty. -func (tree *Tree) Right() *Node { +func (tree *Tree[K, V]) Right() *Node[K, V] { return tree.right(tree.Root) } // RightKey returns the right-most (max) key or nil if tree is empty. -func (tree *Tree) RightKey() interface{} { +func (tree *Tree[K, V]) RightKey() interface{} { if right := tree.Right(); right != nil { return right.Entries[len(right.Entries)-1].Key } @@ -200,7 +197,7 @@ func (tree *Tree) RightKey() interface{} { } // RightValue returns the right-most value or nil if tree is empty. -func (tree *Tree) RightValue() interface{} { +func (tree *Tree[K, V]) RightValue() interface{} { if right := tree.Right(); right != nil { return right.Entries[len(right.Entries)-1].Value } @@ -208,23 +205,23 @@ func (tree *Tree) RightValue() interface{} { } // String returns a string representation of container (for debugging purposes) -func (tree *Tree) String() string { +func (tree *Tree[K, V]) String() string { var buffer bytes.Buffer buffer.WriteString("BTree\n") if !tree.Empty() { - tree.output(&buffer, tree.Root, 0, true) + tree.output(&buffer, tree.Root, 0) } return buffer.String() } -func (entry *Entry) String() string { +func (entry *Entry[K, V]) String() string { return fmt.Sprintf("%v", entry.Key) } -func (tree *Tree) output(buffer *bytes.Buffer, node *Node, level int, isTail bool) { +func (tree *Tree[K, V]) output(buffer *bytes.Buffer, node *Node[K, V], level int) { for e := 0; e < len(node.Entries)+1; e++ { if e < len(node.Children) { - tree.output(buffer, node.Children[e], level+1, true) + tree.output(buffer, node.Children[e], level+1) } if e < len(node.Entries) { buffer.WriteString(strings.Repeat(" ", level)) @@ -233,7 +230,7 @@ func (tree *Tree) output(buffer *bytes.Buffer, node *Node, level int, isTail boo } } -func (node *Node) height() int { +func (node *Node[K, V]) height() int { height := 0 for ; node != nil; node = node.Children[0] { height++ @@ -244,40 +241,40 @@ func (node *Node) height() int { return height } -func (tree *Tree) isLeaf(node *Node) bool { +func (tree *Tree[K, V]) isLeaf(node *Node[K, V]) bool { return len(node.Children) == 0 } -func (tree *Tree) isFull(node *Node) bool { +func (tree *Tree[K, V]) isFull(node *Node[K, V]) bool { return len(node.Entries) == tree.maxEntries() } -func (tree *Tree) shouldSplit(node *Node) bool { +func (tree *Tree[K, V]) shouldSplit(node *Node[K, V]) bool { return len(node.Entries) > tree.maxEntries() } -func (tree *Tree) maxChildren() int { +func (tree *Tree[K, V]) maxChildren() int { return tree.m } -func (tree *Tree) minChildren() int { +func (tree *Tree[K, V]) minChildren() int { return (tree.m + 1) / 2 // ceil(m/2) } -func (tree *Tree) maxEntries() int { +func (tree *Tree[K, V]) maxEntries() int { return tree.maxChildren() - 1 } -func (tree *Tree) minEntries() int { +func (tree *Tree[K, V]) minEntries() int { return tree.minChildren() - 1 } -func (tree *Tree) middle() int { +func (tree *Tree[K, V]) middle() int { return (tree.m - 1) / 2 // "-1" to favor right nodes to have more keys when splitting } // search searches only within the single node among its entries -func (tree *Tree) search(node *Node, key interface{}) (index int, found bool) { +func (tree *Tree[K, V]) search(node *Node[K, V], key K) (index int, found bool) { low, high := 0, len(node.Entries)-1 var mid int for low <= high { @@ -296,7 +293,7 @@ func (tree *Tree) search(node *Node, key interface{}) (index int, found bool) { } // searchRecursively searches recursively down the tree starting at the startNode -func (tree *Tree) searchRecursively(startNode *Node, key interface{}) (node *Node, index int, found bool) { +func (tree *Tree[K, V]) searchRecursively(startNode *Node[K, V], key K) (node *Node[K, V], index int, found bool) { if tree.Empty() { return nil, -1, false } @@ -313,14 +310,14 @@ func (tree *Tree) searchRecursively(startNode *Node, key interface{}) (node *Nod } } -func (tree *Tree) insert(node *Node, entry *Entry) (inserted bool) { +func (tree *Tree[K, V]) insert(node *Node[K, V], entry *Entry[K, V]) (inserted bool) { if tree.isLeaf(node) { return tree.insertIntoLeaf(node, entry) } return tree.insertIntoInternal(node, entry) } -func (tree *Tree) insertIntoLeaf(node *Node, entry *Entry) (inserted bool) { +func (tree *Tree[K, V]) insertIntoLeaf(node *Node[K, V], entry *Entry[K, V]) (inserted bool) { insertPosition, found := tree.search(node, entry.Key) if found { node.Entries[insertPosition] = entry @@ -334,7 +331,7 @@ func (tree *Tree) insertIntoLeaf(node *Node, entry *Entry) (inserted bool) { return true } -func (tree *Tree) insertIntoInternal(node *Node, entry *Entry) (inserted bool) { +func (tree *Tree[K, V]) insertIntoInternal(node *Node[K, V], entry *Entry[K, V]) (inserted bool) { insertPosition, found := tree.search(node, entry.Key) if found { node.Entries[insertPosition] = entry @@ -343,7 +340,7 @@ func (tree *Tree) insertIntoInternal(node *Node, entry *Entry) (inserted bool) { return tree.insert(node.Children[insertPosition], entry) } -func (tree *Tree) split(node *Node) { +func (tree *Tree[K, V]) split(node *Node[K, V]) { if !tree.shouldSplit(node) { return } @@ -356,17 +353,17 @@ func (tree *Tree) split(node *Node) { tree.splitNonRoot(node) } -func (tree *Tree) splitNonRoot(node *Node) { +func (tree *Tree[K, V]) splitNonRoot(node *Node[K, V]) { middle := tree.middle() parent := node.Parent - left := &Node{Entries: append([]*Entry(nil), node.Entries[:middle]...), Parent: parent} - right := &Node{Entries: append([]*Entry(nil), node.Entries[middle+1:]...), Parent: parent} + left := &Node[K, V]{Entries: append([]*Entry[K, V](nil), node.Entries[:middle]...), Parent: parent} + right := &Node[K, V]{Entries: append([]*Entry[K, V](nil), node.Entries[middle+1:]...), Parent: parent} // Move children from the node to be split into left and right nodes if !tree.isLeaf(node) { - left.Children = append([]*Node(nil), node.Children[:middle+1]...) - right.Children = append([]*Node(nil), node.Children[middle+1:]...) + left.Children = append([]*Node[K, V](nil), node.Children[:middle+1]...) + right.Children = append([]*Node[K, V](nil), node.Children[middle+1:]...) setParent(left.Children, left) setParent(right.Children, right) } @@ -389,24 +386,24 @@ func (tree *Tree) splitNonRoot(node *Node) { tree.split(parent) } -func (tree *Tree) splitRoot() { +func (tree *Tree[K, V]) splitRoot() { middle := tree.middle() - left := &Node{Entries: append([]*Entry(nil), tree.Root.Entries[:middle]...)} - right := &Node{Entries: append([]*Entry(nil), tree.Root.Entries[middle+1:]...)} + left := &Node[K, V]{Entries: append([]*Entry[K, V](nil), tree.Root.Entries[:middle]...)} + right := &Node[K, V]{Entries: append([]*Entry[K, V](nil), tree.Root.Entries[middle+1:]...)} // Move children from the node to be split into left and right nodes if !tree.isLeaf(tree.Root) { - left.Children = append([]*Node(nil), tree.Root.Children[:middle+1]...) - right.Children = append([]*Node(nil), tree.Root.Children[middle+1:]...) + left.Children = append([]*Node[K, V](nil), tree.Root.Children[:middle+1]...) + right.Children = append([]*Node[K, V](nil), tree.Root.Children[middle+1:]...) setParent(left.Children, left) setParent(right.Children, right) } // Root is a node with one entry and two children (left and right) - newRoot := &Node{ - Entries: []*Entry{tree.Root.Entries[middle]}, - Children: []*Node{left, right}, + newRoot := &Node[K, V]{ + Entries: []*Entry[K, V]{tree.Root.Entries[middle]}, + Children: []*Node[K, V]{left, right}, } left.Parent = newRoot @@ -414,13 +411,13 @@ func (tree *Tree) splitRoot() { tree.Root = newRoot } -func setParent(nodes []*Node, parent *Node) { +func setParent[K comparable, V any](nodes []*Node[K, V], parent *Node[K, V]) { for _, node := range nodes { node.Parent = parent } } -func (tree *Tree) left(node *Node) *Node { +func (tree *Tree[K, V]) left(node *Node[K, V]) *Node[K, V] { if tree.Empty() { return nil } @@ -433,7 +430,7 @@ func (tree *Tree) left(node *Node) *Node { } } -func (tree *Tree) right(node *Node) *Node { +func (tree *Tree[K, V]) right(node *Node[K, V]) *Node[K, V] { if tree.Empty() { return nil } @@ -448,7 +445,7 @@ func (tree *Tree) right(node *Node) *Node { // leftSibling returns the node's left sibling and child index (in parent) if it exists, otherwise (nil,-1) // key is any of keys in node (could even be deleted). -func (tree *Tree) leftSibling(node *Node, key interface{}) (*Node, int) { +func (tree *Tree[K, V]) leftSibling(node *Node[K, V], key K) (*Node[K, V], int) { if node.Parent != nil { index, _ := tree.search(node.Parent, key) index-- @@ -461,7 +458,7 @@ func (tree *Tree) leftSibling(node *Node, key interface{}) (*Node, int) { // rightSibling returns the node's right sibling and child index (in parent) if it exists, otherwise (nil,-1) // key is any of keys in node (could even be deleted). -func (tree *Tree) rightSibling(node *Node, key interface{}) (*Node, int) { +func (tree *Tree[K, V]) rightSibling(node *Node[K, V], key K) (*Node[K, V], int) { if node.Parent != nil { index, _ := tree.search(node.Parent, key) index++ @@ -474,7 +471,7 @@ func (tree *Tree) rightSibling(node *Node, key interface{}) (*Node, int) { // delete deletes an entry in node at entries' index // ref.: https://en.wikipedia.org/wiki/B-tree#Deletion -func (tree *Tree) delete(node *Node, index int) { +func (tree *Tree[K, V]) delete(node *Node[K, V], index int) { // deleting from a leaf node if tree.isLeaf(node) { deletedKey := node.Entries[index].Key @@ -497,7 +494,7 @@ func (tree *Tree) delete(node *Node, index int) { // rebalance rebalances the tree after deletion if necessary and returns true, otherwise false. // Note that we first delete the entry and then call rebalance, thus the passed deleted key as reference. -func (tree *Tree) rebalance(node *Node, deletedKey interface{}) { +func (tree *Tree[K, V]) rebalance(node *Node[K, V], deletedKey K) { // check if rebalancing is needed if node == nil || len(node.Entries) >= tree.minEntries() { return @@ -507,13 +504,13 @@ func (tree *Tree) rebalance(node *Node, deletedKey interface{}) { leftSibling, leftSiblingIndex := tree.leftSibling(node, deletedKey) if leftSibling != nil && len(leftSibling.Entries) > tree.minEntries() { // rotate right - node.Entries = append([]*Entry{node.Parent.Entries[leftSiblingIndex]}, node.Entries...) // prepend parent's separator entry to node's entries + node.Entries = append([]*Entry[K, V]{node.Parent.Entries[leftSiblingIndex]}, node.Entries...) // prepend parent's separator entry to node's entries node.Parent.Entries[leftSiblingIndex] = leftSibling.Entries[len(leftSibling.Entries)-1] tree.deleteEntry(leftSibling, len(leftSibling.Entries)-1) if !tree.isLeaf(leftSibling) { leftSiblingRightMostChild := leftSibling.Children[len(leftSibling.Children)-1] leftSiblingRightMostChild.Parent = node - node.Children = append([]*Node{leftSiblingRightMostChild}, node.Children...) + node.Children = append([]*Node[K, V]{leftSiblingRightMostChild}, node.Children...) tree.deleteChild(leftSibling, len(leftSibling.Children)-1) } return @@ -546,7 +543,7 @@ func (tree *Tree) rebalance(node *Node, deletedKey interface{}) { tree.deleteChild(node.Parent, rightSiblingIndex) } else if leftSibling != nil { // merge with left sibling - entries := append([]*Entry(nil), leftSibling.Entries...) + entries := append([]*Entry[K, V](nil), leftSibling.Entries...) entries = append(entries, node.Parent.Entries[leftSiblingIndex]) node.Entries = append(entries, node.Entries...) deletedKey = node.Parent.Entries[leftSiblingIndex].Key @@ -566,24 +563,24 @@ func (tree *Tree) rebalance(node *Node, deletedKey interface{}) { tree.rebalance(node.Parent, deletedKey) } -func (tree *Tree) prependChildren(fromNode *Node, toNode *Node) { - children := append([]*Node(nil), fromNode.Children...) +func (tree *Tree[K, V]) prependChildren(fromNode *Node[K, V], toNode *Node[K, V]) { + children := append([]*Node[K, V](nil), fromNode.Children...) toNode.Children = append(children, toNode.Children...) setParent(fromNode.Children, toNode) } -func (tree *Tree) appendChildren(fromNode *Node, toNode *Node) { +func (tree *Tree[K, V]) appendChildren(fromNode *Node[K, V], toNode *Node[K, V]) { toNode.Children = append(toNode.Children, fromNode.Children...) setParent(fromNode.Children, toNode) } -func (tree *Tree) deleteEntry(node *Node, index int) { +func (tree *Tree[K, V]) deleteEntry(node *Node[K, V], index int) { copy(node.Entries[index:], node.Entries[index+1:]) node.Entries[len(node.Entries)-1] = nil node.Entries = node.Entries[:len(node.Entries)-1] } -func (tree *Tree) deleteChild(node *Node, index int) { +func (tree *Tree[K, V]) deleteChild(node *Node[K, V], index int) { if index >= len(node.Children) { return } diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index 8dcb2581..c6af7c0e 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -6,13 +6,13 @@ package btree import ( "encoding/json" - "fmt" + "slices" "strings" "testing" ) func TestBTreeGet1(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) tree.Put(1, "a") tree.Put(2, "b") tree.Put(3, "c") @@ -22,7 +22,7 @@ func TestBTreeGet1(t *testing.T) { tree.Put(7, "g") tests := [][]interface{}{ - {0, nil, false}, + {0, "", false}, {1, "a", true}, {2, "b", true}, {3, "c", true}, @@ -30,18 +30,18 @@ func TestBTreeGet1(t *testing.T) { {5, "e", true}, {6, "f", true}, {7, "g", true}, - {8, nil, false}, + {8, "", false}, } for _, test := range tests { - if value, found := tree.Get(test[0]); value != test[1] || found != test[2] { + if value, found := tree.Get(test[0].(int)); value != test[1] || found != test[2] { t.Errorf("Got %v,%v expected %v,%v", value, found, test[1], test[2]) } } } func TestBTreeGet2(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) tree.Put(7, "g") tree.Put(9, "i") tree.Put(10, "j") @@ -54,7 +54,7 @@ func TestBTreeGet2(t *testing.T) { tree.Put(1, "a") tests := [][]interface{}{ - {0, nil, false}, + {0, "", false}, {1, "a", true}, {2, "b", true}, {3, "c", true}, @@ -65,18 +65,18 @@ func TestBTreeGet2(t *testing.T) { {8, "h", true}, {9, "i", true}, {10, "j", true}, - {11, nil, false}, + {11, "", false}, } for _, test := range tests { - if value, found := tree.Get(test[0]); value != test[1] || found != test[2] { + if value, found := tree.Get(test[0].(int)); value != test[1] || found != test[2] { t.Errorf("Got %v,%v expected %v,%v", value, found, test[1], test[2]) } } } func TestBTreeGet3(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) if actualValue := tree.Size(); actualValue != 0 { t.Errorf("Got %v expected %v", actualValue, 0) @@ -123,7 +123,7 @@ func TestBTreeGet3(t *testing.T) { func TestBTreePut1(t *testing.T) { // https://upload.wikimedia.org/wikipedia/commons/3/33/B_tree_insertion_example.png - tree := NewWithIntComparator(3) + tree := New[int, int](3) assertValidTree(t, tree, 0) tree.Put(1, 0) @@ -172,7 +172,7 @@ func TestBTreePut1(t *testing.T) { } func TestBTreePut2(t *testing.T) { - tree := NewWithIntComparator(4) + tree := New[int, int](4) assertValidTree(t, tree, 0) tree.Put(0, 0) @@ -213,7 +213,7 @@ func TestBTreePut2(t *testing.T) { func TestBTreePut3(t *testing.T) { // http://www.geeksforgeeks.org/b-tree-set-1-insert-2/ - tree := NewWithIntComparator(6) + tree := New[int, int](6) assertValidTree(t, tree, 0) tree.Put(10, 0) @@ -263,7 +263,7 @@ func TestBTreePut3(t *testing.T) { } func TestBTreePut4(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, *struct{}](3) assertValidTree(t, tree, 0) tree.Put(6, nil) @@ -358,14 +358,14 @@ func TestBTreePut4(t *testing.T) { func TestBTreeRemove1(t *testing.T) { // empty - tree := NewWithIntComparator(3) + tree := New[int, int](3) tree.Remove(1) assertValidTree(t, tree, 0) } func TestBTreeRemove2(t *testing.T) { // leaf node (no underflow) - tree := NewWithIntComparator(3) + tree := New[int, *struct{}](3) tree.Put(1, nil) tree.Put(2, nil) @@ -380,7 +380,7 @@ func TestBTreeRemove2(t *testing.T) { func TestBTreeRemove3(t *testing.T) { // merge with right (underflow) { - tree := NewWithIntComparator(3) + tree := New[int, *struct{}](3) tree.Put(1, nil) tree.Put(2, nil) tree.Put(3, nil) @@ -391,7 +391,7 @@ func TestBTreeRemove3(t *testing.T) { } // merge with left (underflow) { - tree := NewWithIntComparator(3) + tree := New[int, *struct{}](3) tree.Put(1, nil) tree.Put(2, nil) tree.Put(3, nil) @@ -404,7 +404,7 @@ func TestBTreeRemove3(t *testing.T) { func TestBTreeRemove4(t *testing.T) { // rotate left (underflow) - tree := NewWithIntComparator(3) + tree := New[int, *struct{}](3) tree.Put(1, nil) tree.Put(2, nil) tree.Put(3, nil) @@ -424,7 +424,7 @@ func TestBTreeRemove4(t *testing.T) { func TestBTreeRemove5(t *testing.T) { // rotate right (underflow) - tree := NewWithIntComparator(3) + tree := New[int, *struct{}](3) tree.Put(1, nil) tree.Put(2, nil) tree.Put(3, nil) @@ -445,7 +445,7 @@ func TestBTreeRemove5(t *testing.T) { func TestBTreeRemove6(t *testing.T) { // root height reduction after a series of underflows on right side // use simulator: https://www.cs.usfca.edu/~galles/visualization/BTree.html - tree := NewWithIntComparator(3) + tree := New[int, *struct{}](3) tree.Put(1, nil) tree.Put(2, nil) tree.Put(3, nil) @@ -474,7 +474,7 @@ func TestBTreeRemove6(t *testing.T) { func TestBTreeRemove7(t *testing.T) { // root height reduction after a series of underflows on left side // use simulator: https://www.cs.usfca.edu/~galles/visualization/BTree.html - tree := NewWithIntComparator(3) + tree := New[int, *struct{}](3) tree.Put(1, nil) tree.Put(2, nil) tree.Put(3, nil) @@ -533,7 +533,7 @@ func TestBTreeRemove7(t *testing.T) { func TestBTreeRemove8(t *testing.T) { // use simulator: https://www.cs.usfca.edu/~galles/visualization/BTree.html - tree := NewWithIntComparator(3) + tree := New[int, *struct{}](3) tree.Put(1, nil) tree.Put(2, nil) tree.Put(3, nil) @@ -570,7 +570,7 @@ func TestBTreeRemove9(t *testing.T) { orders := []int{3, 4, 5, 6, 7, 8, 9, 10, 20, 100, 500, 1000, 5000, 10000} for _, order := range orders { - tree := NewWithIntComparator(order) + tree := New[int, int](order) { for i := 1; i <= max; i++ { @@ -611,7 +611,7 @@ func TestBTreeRemove9(t *testing.T) { } func TestBTreeHeight(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, int](3) if actualValue, expectedValue := tree.Height(), 0; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } @@ -664,7 +664,7 @@ func TestBTreeHeight(t *testing.T) { } func TestBTreeLeftAndRight(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) if actualValue := tree.Left(); actualValue != nil { t.Errorf("Got %v expected %v", actualValue, nil) @@ -698,7 +698,7 @@ func TestBTreeLeftAndRight(t *testing.T) { } func TestBTreeIteratorValuesAndKeys(t *testing.T) { - tree := NewWithIntComparator(4) + tree := New[int, string](4) tree.Put(4, "d") tree.Put(5, "e") tree.Put(6, "f") @@ -707,10 +707,10 @@ func TestBTreeIteratorValuesAndKeys(t *testing.T) { tree.Put(7, "g") tree.Put(2, "b") tree.Put(1, "x") // override - if actualValue, expectedValue := fmt.Sprintf("%d%d%d%d%d%d%d", tree.Keys()...), "1234567"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Keys(), []int{1, 2, 3, 4, 5, 6, 7}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s", tree.Values()...), "xbcdefg"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Values(), []string{"x", "b", "c", "d", "e", "f", "g"}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } if actualValue := tree.Size(); actualValue != 7 { @@ -719,7 +719,7 @@ func TestBTreeIteratorValuesAndKeys(t *testing.T) { } func TestBTreeIteratorNextOnEmpty(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) it := tree.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty tree") @@ -727,7 +727,7 @@ func TestBTreeIteratorNextOnEmpty(t *testing.T) { } func TestBTreeIteratorPrevOnEmpty(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) it := tree.Iterator() for it.Prev() { t.Errorf("Shouldn't iterate on empty tree") @@ -735,7 +735,7 @@ func TestBTreeIteratorPrevOnEmpty(t *testing.T) { } func TestBTreeIterator1Next(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) tree.Put(5, "e") tree.Put(6, "f") tree.Put(7, "g") @@ -759,7 +759,7 @@ func TestBTreeIterator1Next(t *testing.T) { } func TestBTreeIterator1Prev(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) tree.Put(5, "e") tree.Put(6, "f") tree.Put(7, "g") @@ -785,7 +785,7 @@ func TestBTreeIterator1Prev(t *testing.T) { } func TestBTreeIterator2Next(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") @@ -804,7 +804,7 @@ func TestBTreeIterator2Next(t *testing.T) { } func TestBTreeIterator2Prev(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") @@ -825,7 +825,7 @@ func TestBTreeIterator2Prev(t *testing.T) { } func TestBTreeIterator3Next(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) tree.Put(1, "a") it := tree.Iterator() count := 0 @@ -842,7 +842,7 @@ func TestBTreeIterator3Next(t *testing.T) { } func TestBTreeIterator3Prev(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) tree.Put(1, "a") it := tree.Iterator() for it.Next() { @@ -861,7 +861,7 @@ func TestBTreeIterator3Prev(t *testing.T) { } func TestBTreeIterator4Next(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, int](3) tree.Put(13, 5) tree.Put(8, 3) tree.Put(17, 7) @@ -887,7 +887,7 @@ func TestBTreeIterator4Next(t *testing.T) { } func TestBTreeIterator4Prev(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, int](3) tree.Put(13, 5) tree.Put(8, 3) tree.Put(17, 7) @@ -915,7 +915,7 @@ func TestBTreeIterator4Prev(t *testing.T) { } func TestBTreeIteratorBegin(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") @@ -947,7 +947,7 @@ func TestBTreeIteratorBegin(t *testing.T) { } func TestBTreeIteratorEnd(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) it := tree.Iterator() if it.node != nil { @@ -974,7 +974,7 @@ func TestBTreeIteratorEnd(t *testing.T) { } func TestBTreeIteratorFirst(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") @@ -988,7 +988,7 @@ func TestBTreeIteratorFirst(t *testing.T) { } func TestBTreeIteratorLast(t *testing.T) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") @@ -1003,13 +1003,13 @@ func TestBTreeIteratorLast(t *testing.T) { func TestBTreeSearch(t *testing.T) { { - tree := NewWithIntComparator(3) - tree.Root = &Node{Entries: []*Entry{}, Children: make([]*Node, 0)} + tree := New[int, int](3) + tree.Root = &Node[int, int]{Entries: []*Entry[int, int]{}, Children: make([]*Node[int, int], 0)} tests := [][]interface{}{ {0, 0, false}, } for _, test := range tests { - index, found := tree.search(tree.Root, test[0]) + index, found := tree.search(tree.Root, test[0].(int)) if actualValue, expectedValue := index, test[1]; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } @@ -1019,8 +1019,8 @@ func TestBTreeSearch(t *testing.T) { } } { - tree := NewWithIntComparator(3) - tree.Root = &Node{Entries: []*Entry{{2, 0}, {4, 1}, {6, 2}}, Children: []*Node{}} + tree := New[int, int](3) + tree.Root = &Node[int, int]{Entries: []*Entry[int, int]{{2, 0}, {4, 1}, {6, 2}}, Children: []*Node[int, int]{}} tests := [][]interface{}{ {0, 0, false}, {1, 0, false}, @@ -1032,7 +1032,7 @@ func TestBTreeSearch(t *testing.T) { {7, 3, false}, } for _, test := range tests { - index, found := tree.search(tree.Root, test[0]) + index, found := tree.search(tree.Root, test[0].(int)) if actualValue, expectedValue := index, test[1]; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } @@ -1043,13 +1043,13 @@ func TestBTreeSearch(t *testing.T) { } } -func assertValidTree(t *testing.T, tree *Tree, expectedSize int) { +func assertValidTree[K comparable, V any](t *testing.T, tree *Tree[K, V], expectedSize int) { if actualValue, expectedValue := tree.size, expectedSize; actualValue != expectedValue { t.Errorf("Got %v expected %v for tree size", actualValue, expectedValue) } } -func assertValidTreeNode(t *testing.T, node *Node, expectedEntries int, expectedChildren int, keys []int, hasParent bool) { +func assertValidTreeNode[K comparable, V any](t *testing.T, node *Node[K, V], expectedEntries int, expectedChildren int, keys []K, hasParent bool) { if actualValue, expectedValue := node.Parent != nil, hasParent; actualValue != expectedValue { t.Errorf("Got %v expected %v for hasParent", actualValue, expectedValue) } @@ -1068,13 +1068,13 @@ func assertValidTreeNode(t *testing.T, node *Node, expectedEntries int, expected func TestBTreeIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index interface{}, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // NextTo (empty) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) it := tree.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty tree") @@ -1083,7 +1083,7 @@ func TestBTreeIteratorNextTo(t *testing.T) { // NextTo (not found) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) tree.Put(0, "xx") tree.Put(1, "yy") it := tree.Iterator() @@ -1094,7 +1094,7 @@ func TestBTreeIteratorNextTo(t *testing.T) { // NextTo (found) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) tree.Put(2, "cc") tree.Put(0, "aa") tree.Put(1, "bb") @@ -1103,13 +1103,13 @@ func TestBTreeIteratorNextTo(t *testing.T) { if !it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty tree") } - if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Key(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Next() { t.Errorf("Should go to first element") } - if index, value := it.Key(), it.Value(); index != 2 || value.(string) != "cc" { + if index, value := it.Key(), it.Value(); index != 2 || value != "cc" { t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") } if it.Next() { @@ -1120,13 +1120,13 @@ func TestBTreeIteratorNextTo(t *testing.T) { func TestBTreeIteratorPrevTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index interface{}, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // PrevTo (empty) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) it := tree.Iterator() it.End() for it.PrevTo(seek) { @@ -1136,7 +1136,7 @@ func TestBTreeIteratorPrevTo(t *testing.T) { // PrevTo (not found) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) tree.Put(0, "xx") tree.Put(1, "yy") it := tree.Iterator() @@ -1148,7 +1148,7 @@ func TestBTreeIteratorPrevTo(t *testing.T) { // PrevTo (found) { - tree := NewWithIntComparator(3) + tree := New[int, string](3) tree.Put(2, "cc") tree.Put(0, "aa") tree.Put(1, "bb") @@ -1157,13 +1157,13 @@ func TestBTreeIteratorPrevTo(t *testing.T) { if !it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty tree") } - if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Key(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Prev() { t.Errorf("Should go to first element") } - if index, value := it.Key(), it.Value(); index != 0 || value.(string) != "aa" { + if index, value := it.Key(), it.Value(); index != 0 || value != "aa" { t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") } if it.Prev() { @@ -1173,7 +1173,7 @@ func TestBTreeIteratorPrevTo(t *testing.T) { } func TestBTreeSerialization(t *testing.T) { - tree := NewWithStringComparator(3) + tree := New[string, string](3) tree.Put("c", "3") tree.Put("b", "2") tree.Put("a", "1") @@ -1183,11 +1183,11 @@ func TestBTreeSerialization(t *testing.T) { if actualValue, expectedValue := tree.Size(), 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if actualValue := tree.Keys(); actualValue[0].(string) != "a" || actualValue[1].(string) != "b" || actualValue[2].(string) != "c" { - t.Errorf("Got %v expected %v", actualValue, "[a,b,c]") + if actualValue, expectedValue := tree.Keys(), []string{"a", "b", "c"}; !slices.Equal(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if actualValue := tree.Values(); actualValue[0].(string) != "1" || actualValue[1].(string) != "2" || actualValue[2].(string) != "3" { - t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + if actualValue, expectedValue := tree.Values(), []string{"1", "2", "3"}; !slices.Equal(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } if err != nil { t.Errorf("Got error %v", err) @@ -1207,21 +1207,31 @@ func TestBTreeSerialization(t *testing.T) { t.Errorf("Got error %v", err) } - err = json.Unmarshal([]byte(`{"a":1,"b":2}`), &tree) + intTree := New[string, int](3) + err = json.Unmarshal([]byte(`{"a":1,"b":2}`), intTree) if err != nil { t.Errorf("Got error %v", err) } + if actualValue, expectedValue := intTree.Size(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := intTree.Keys(), []string{"a", "b"}; !slices.Equal(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := intTree.Values(), []int{1, 2}; !slices.Equal(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } } func TestBTreeString(t *testing.T) { - c := NewWithStringComparator(3) + c := New[string, int](3) c.Put("a", 1) if !strings.HasPrefix(c.String(), "BTree") { t.Errorf("String should start with container name") } } -func benchmarkGet(b *testing.B, tree *Tree, size int) { +func benchmarkGet(b *testing.B, tree *Tree[int, struct{}], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { tree.Get(n) @@ -1229,7 +1239,7 @@ func benchmarkGet(b *testing.B, tree *Tree, size int) { } } -func benchmarkPut(b *testing.B, tree *Tree, size int) { +func benchmarkPut(b *testing.B, tree *Tree[int, struct{}], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { tree.Put(n, struct{}{}) @@ -1237,7 +1247,7 @@ func benchmarkPut(b *testing.B, tree *Tree, size int) { } } -func benchmarkRemove(b *testing.B, tree *Tree, size int) { +func benchmarkRemove(b *testing.B, tree *Tree[int, struct{}], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { tree.Remove(n) @@ -1248,7 +1258,7 @@ func benchmarkRemove(b *testing.B, tree *Tree, size int) { func BenchmarkBTreeGet100(b *testing.B) { b.StopTimer() size := 100 - tree := NewWithIntComparator(128) + tree := New[int, struct{}](128) for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -1259,7 +1269,7 @@ func BenchmarkBTreeGet100(b *testing.B) { func BenchmarkBTreeGet1000(b *testing.B) { b.StopTimer() size := 1000 - tree := NewWithIntComparator(128) + tree := New[int, struct{}](128) for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -1270,7 +1280,7 @@ func BenchmarkBTreeGet1000(b *testing.B) { func BenchmarkBTreeGet10000(b *testing.B) { b.StopTimer() size := 10000 - tree := NewWithIntComparator(128) + tree := New[int, struct{}](128) for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -1281,7 +1291,7 @@ func BenchmarkBTreeGet10000(b *testing.B) { func BenchmarkBTreeGet100000(b *testing.B) { b.StopTimer() size := 100000 - tree := NewWithIntComparator(128) + tree := New[int, struct{}](128) for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -1292,7 +1302,7 @@ func BenchmarkBTreeGet100000(b *testing.B) { func BenchmarkBTreePut100(b *testing.B) { b.StopTimer() size := 100 - tree := NewWithIntComparator(128) + tree := New[int, struct{}](128) b.StartTimer() benchmarkPut(b, tree, size) } @@ -1300,7 +1310,7 @@ func BenchmarkBTreePut100(b *testing.B) { func BenchmarkBTreePut1000(b *testing.B) { b.StopTimer() size := 1000 - tree := NewWithIntComparator(128) + tree := New[int, struct{}](128) for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -1311,7 +1321,7 @@ func BenchmarkBTreePut1000(b *testing.B) { func BenchmarkBTreePut10000(b *testing.B) { b.StopTimer() size := 10000 - tree := NewWithIntComparator(128) + tree := New[int, struct{}](128) for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -1322,7 +1332,7 @@ func BenchmarkBTreePut10000(b *testing.B) { func BenchmarkBTreePut100000(b *testing.B) { b.StopTimer() size := 100000 - tree := NewWithIntComparator(128) + tree := New[int, struct{}](128) for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -1333,7 +1343,7 @@ func BenchmarkBTreePut100000(b *testing.B) { func BenchmarkBTreeRemove100(b *testing.B) { b.StopTimer() size := 100 - tree := NewWithIntComparator(128) + tree := New[int, struct{}](128) for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -1344,7 +1354,7 @@ func BenchmarkBTreeRemove100(b *testing.B) { func BenchmarkBTreeRemove1000(b *testing.B) { b.StopTimer() size := 1000 - tree := NewWithIntComparator(128) + tree := New[int, struct{}](128) for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -1355,7 +1365,7 @@ func BenchmarkBTreeRemove1000(b *testing.B) { func BenchmarkBTreeRemove10000(b *testing.B) { b.StopTimer() size := 10000 - tree := NewWithIntComparator(128) + tree := New[int, struct{}](128) for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -1366,7 +1376,7 @@ func BenchmarkBTreeRemove10000(b *testing.B) { func BenchmarkBTreeRemove100000(b *testing.B) { b.StopTimer() size := 100000 - tree := NewWithIntComparator(128) + tree := New[int, struct{}](128) for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } diff --git a/trees/btree/iterator.go b/trees/btree/iterator.go index fb20955a..23c9387d 100644 --- a/trees/btree/iterator.go +++ b/trees/btree/iterator.go @@ -4,16 +4,16 @@ package btree -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Assert Iterator implementation -var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) +var _ containers.ReverseIteratorWithKey[string, int] = (*Iterator[string, int])(nil) // Iterator holding the iterator's state -type Iterator struct { - tree *Tree - node *Node - entry *Entry +type Iterator[K comparable, V any] struct { + tree *Tree[K, V] + node *Node[K, V] + entry *Entry[K, V] position position } @@ -24,15 +24,15 @@ const ( ) // Iterator returns a stateful iterator whose elements are key/value pairs. -func (tree *Tree) Iterator() Iterator { - return Iterator{tree: tree, node: nil, position: begin} +func (tree *Tree[K, V]) Iterator() *Iterator[K, V] { + return &Iterator[K, V]{tree: tree, node: nil, position: begin} } // 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. // Modifies the state of the iterator. -func (iterator *Iterator) Next() bool { +func (iterator *Iterator[K, V]) Next() bool { // If already at end, go to end if iterator.position == end { goto end @@ -91,7 +91,7 @@ between: // 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. -func (iterator *Iterator) Prev() bool { +func (iterator *Iterator[K, V]) Prev() bool { // If already at beginning, go to begin if iterator.position == begin { goto begin @@ -149,25 +149,25 @@ between: // Value returns the current element's value. // Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { +func (iterator *Iterator[K, V]) Value() V { return iterator.entry.Value } // Key returns the current element's key. // Does not modify the state of the iterator. -func (iterator *Iterator) Key() interface{} { +func (iterator *Iterator[K, V]) Key() K { return iterator.entry.Key } // Node returns the current element's node. // Does not modify the state of the iterator. -func (iterator *Iterator) Node() *Node { +func (iterator *Iterator[K, V]) Node() *Node[K, V] { return iterator.node } // Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. -func (iterator *Iterator) Begin() { +func (iterator *Iterator[K, V]) Begin() { iterator.node = nil iterator.position = begin iterator.entry = nil @@ -175,7 +175,7 @@ func (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() { +func (iterator *Iterator[K, V]) End() { iterator.node = nil iterator.position = end iterator.entry = nil @@ -184,7 +184,7 @@ func (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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator -func (iterator *Iterator) First() bool { +func (iterator *Iterator[K, V]) First() bool { iterator.Begin() return iterator.Next() } @@ -192,7 +192,7 @@ func (iterator *Iterator) First() bool { // 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. -func (iterator *Iterator) Last() bool { +func (iterator *Iterator[K, V]) Last() bool { iterator.End() return iterator.Prev() } @@ -201,7 +201,7 @@ func (iterator *Iterator) Last() bool { // 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. -func (iterator *Iterator) NextTo(f func(key interface{}, value interface{}) bool) bool { +func (iterator *Iterator[K, V]) NextTo(f func(key K, value V) bool) bool { for iterator.Next() { key, value := iterator.Key(), iterator.Value() if f(key, value) { @@ -215,7 +215,7 @@ func (iterator *Iterator) NextTo(f func(key interface{}, value interface{}) bool // 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. -func (iterator *Iterator) PrevTo(f func(key interface{}, value interface{}) bool) bool { +func (iterator *Iterator[K, V]) PrevTo(f func(key K, value V) bool) bool { for iterator.Prev() { key, value := iterator.Key(), iterator.Value() if f(key, value) { diff --git a/trees/btree/serialization.go b/trees/btree/serialization.go index 460f6e0b..4b9a3139 100644 --- a/trees/btree/serialization.go +++ b/trees/btree/serialization.go @@ -6,43 +6,46 @@ package btree import ( "encoding/json" - "github.com/emirpasic/gods/containers" - "github.com/emirpasic/gods/utils" + + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*Tree)(nil) -var _ containers.JSONDeserializer = (*Tree)(nil) +var _ containers.JSONSerializer = (*Tree[string, int])(nil) +var _ containers.JSONDeserializer = (*Tree[string, int])(nil) // ToJSON outputs the JSON representation of the tree. -func (tree *Tree) ToJSON() ([]byte, error) { - elements := make(map[string]interface{}) +func (tree *Tree[K, V]) ToJSON() ([]byte, error) { + elements := make(map[K]V) it := tree.Iterator() for it.Next() { - elements[utils.ToString(it.Key())] = it.Value() + elements[it.Key()] = it.Value() } return json.Marshal(&elements) } // FromJSON populates the tree from the input JSON representation. -func (tree *Tree) FromJSON(data []byte) error { - elements := make(map[string]interface{}) +func (tree *Tree[K, V]) FromJSON(data []byte) error { + elements := make(map[K]V) err := json.Unmarshal(data, &elements) - if err == nil { - tree.Clear() - for key, value := range elements { - tree.Put(key, value) - } + if err != nil { + return err + } + + tree.Clear() + for key, value := range elements { + tree.Put(key, value) } + return err } // UnmarshalJSON @implements json.Unmarshaler -func (tree *Tree) UnmarshalJSON(bytes []byte) error { +func (tree *Tree[K, V]) UnmarshalJSON(bytes []byte) error { return tree.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (tree *Tree) MarshalJSON() ([]byte, error) { +func (tree *Tree[K, V]) MarshalJSON() ([]byte, error) { return tree.ToJSON() } diff --git a/trees/redblacktree/iterator.go b/trees/redblacktree/iterator.go index e39da7d4..9aa5605e 100644 --- a/trees/redblacktree/iterator.go +++ b/trees/redblacktree/iterator.go @@ -4,15 +4,15 @@ package redblacktree -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Assert Iterator implementation -var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) +var _ containers.ReverseIteratorWithKey[string, int] = (*Iterator[string, int])(nil) // Iterator holding the iterator's state -type Iterator struct { - tree *Tree - node *Node +type Iterator[K comparable, V any] struct { + tree *Tree[K, V] + node *Node[K, V] position position } @@ -23,20 +23,20 @@ const ( ) // Iterator returns a stateful iterator whose elements are key/value pairs. -func (tree *Tree) Iterator() Iterator { - return Iterator{tree: tree, node: nil, position: begin} +func (tree *Tree[K, V]) Iterator() *Iterator[K, V] { + return &Iterator[K, V]{tree: tree, node: nil, position: begin} } // IteratorAt returns a stateful iterator whose elements are key/value pairs that is initialised at a particular node. -func (tree *Tree) IteratorAt(node *Node) Iterator { - return Iterator{tree: tree, node: node, position: between} +func (tree *Tree[K, V]) IteratorAt(node *Node[K, V]) *Iterator[K, V] { + return &Iterator[K, V]{tree: tree, node: node, position: between} } // 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. // Modifies the state of the iterator. -func (iterator *Iterator) Next() bool { +func (iterator *Iterator[K, V]) Next() bool { if iterator.position == end { goto end } @@ -76,7 +76,7 @@ between: // 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. -func (iterator *Iterator) Prev() bool { +func (iterator *Iterator[K, V]) Prev() bool { if iterator.position == begin { goto begin } @@ -115,32 +115,32 @@ between: // Value returns the current element's value. // Does not modify the state of the iterator. -func (iterator *Iterator) Value() interface{} { +func (iterator *Iterator[K, V]) Value() V { return iterator.node.Value } // Key returns the current element's key. // Does not modify the state of the iterator. -func (iterator *Iterator) Key() interface{} { +func (iterator *Iterator[K, V]) Key() K { return iterator.node.Key } // Node returns the current element's node. // Does not modify the state of the iterator. -func (iterator *Iterator) Node() *Node { +func (iterator *Iterator[K, V]) Node() *Node[K, V] { return iterator.node } // Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. -func (iterator *Iterator) Begin() { +func (iterator *Iterator[K, V]) Begin() { iterator.node = nil iterator.position = 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() { +func (iterator *Iterator[K, V]) End() { iterator.node = nil iterator.position = end } @@ -148,7 +148,7 @@ func (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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator -func (iterator *Iterator) First() bool { +func (iterator *Iterator[K, V]) First() bool { iterator.Begin() return iterator.Next() } @@ -156,7 +156,7 @@ func (iterator *Iterator) First() bool { // 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 key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. -func (iterator *Iterator) Last() bool { +func (iterator *Iterator[K, V]) Last() bool { iterator.End() return iterator.Prev() } @@ -165,7 +165,7 @@ func (iterator *Iterator) Last() bool { // 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. -func (iterator *Iterator) NextTo(f func(key interface{}, value interface{}) bool) bool { +func (iterator *Iterator[K, V]) NextTo(f func(key K, value V) bool) bool { for iterator.Next() { key, value := iterator.Key(), iterator.Value() if f(key, value) { @@ -179,7 +179,7 @@ func (iterator *Iterator) NextTo(f func(key interface{}, value interface{}) bool // 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. -func (iterator *Iterator) PrevTo(f func(key interface{}, value interface{}) bool) bool { +func (iterator *Iterator[K, V]) PrevTo(f func(key K, value V) bool) bool { for iterator.Prev() { key, value := iterator.Key(), iterator.Value() if f(key, value) { diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index b335e3df..ec53532d 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -12,13 +12,15 @@ package redblacktree import ( + "cmp" "fmt" - "github.com/emirpasic/gods/trees" - "github.com/emirpasic/gods/utils" + + "github.com/emirpasic/gods/v2/trees" + "github.com/emirpasic/gods/v2/utils" ) // Assert Tree implementation -var _ trees.Tree = (*Tree)(nil) +var _ trees.Tree[int] = (*Tree[string, int])(nil) type color bool @@ -27,45 +29,40 @@ const ( ) // Tree holds elements of the red-black tree -type Tree struct { - Root *Node +type Tree[K comparable, V any] struct { + Root *Node[K, V] size int - Comparator utils.Comparator + Comparator utils.Comparator[K] } // Node is a single element within the tree -type Node struct { - Key interface{} - Value interface{} +type Node[K comparable, V any] struct { + Key K + Value V color color - Left *Node - Right *Node - Parent *Node -} - -// NewWith instantiates a red-black tree with the custom comparator. -func NewWith(comparator utils.Comparator) *Tree { - return &Tree{Comparator: comparator} + Left *Node[K, V] + Right *Node[K, V] + Parent *Node[K, V] } -// NewWithIntComparator instantiates a red-black tree with the IntComparator, i.e. keys are of type int. -func NewWithIntComparator() *Tree { - return &Tree{Comparator: utils.IntComparator} +// New instantiates a red-black tree with the built-in comparator for K +func New[K cmp.Ordered, V any]() *Tree[K, V] { + return &Tree[K, V]{Comparator: cmp.Compare[K]} } -// NewWithStringComparator instantiates a red-black tree with the StringComparator, i.e. keys are of type string. -func NewWithStringComparator() *Tree { - return &Tree{Comparator: utils.StringComparator} +// NewWith instantiates a red-black tree with the custom comparator. +func NewWith[K comparable, V any](comparator utils.Comparator[K]) *Tree[K, V] { + return &Tree[K, V]{Comparator: comparator} } // Put inserts node into the tree. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *Tree) Put(key interface{}, value interface{}) { - var insertedNode *Node +func (tree *Tree[K, V]) Put(key K, value V) { + var insertedNode *Node[K, V] if tree.Root == nil { // Assert key is of comparator's type for initial tree tree.Comparator(key, key) - tree.Root = &Node{Key: key, Value: value, color: red} + tree.Root = &Node[K, V]{Key: key, Value: value, color: red} insertedNode = tree.Root } else { node := tree.Root @@ -79,7 +76,7 @@ func (tree *Tree) Put(key interface{}, value interface{}) { return case compare < 0: if node.Left == nil { - node.Left = &Node{Key: key, Value: value, color: red} + node.Left = &Node[K, V]{Key: key, Value: value, color: red} insertedNode = node.Left loop = false } else { @@ -87,7 +84,7 @@ func (tree *Tree) Put(key interface{}, value interface{}) { } case compare > 0: if node.Right == nil { - node.Right = &Node{Key: key, Value: value, color: red} + node.Right = &Node[K, V]{Key: key, Value: value, color: red} insertedNode = node.Right loop = false } else { @@ -104,24 +101,24 @@ func (tree *Tree) Put(key interface{}, value interface{}) { // Get searches the node in the tree by key and returns its value or nil if key is not found in tree. // Second return parameter is true if key was found, otherwise false. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *Tree) Get(key interface{}) (value interface{}, found bool) { +func (tree *Tree[K, V]) Get(key K) (value V, found bool) { node := tree.lookup(key) if node != nil { return node.Value, true } - return nil, false + return value, false } // GetNode searches the node in the tree by key and returns its node or nil if key is not found in tree. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *Tree) GetNode(key interface{}) *Node { +func (tree *Tree[K, V]) GetNode(key K) *Node[K, V] { return tree.lookup(key) } // Remove remove the node from the tree by key. // Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *Tree) Remove(key interface{}) { - var child *Node +func (tree *Tree[K, V]) Remove(key K) { + var child *Node[K, V] node := tree.lookup(key) if node == nil { return @@ -151,18 +148,18 @@ func (tree *Tree) Remove(key interface{}) { } // Empty returns true if tree does not contain any nodes -func (tree *Tree) Empty() bool { +func (tree *Tree[K, V]) Empty() bool { return tree.size == 0 } // Size returns number of nodes in the tree. -func (tree *Tree) Size() int { +func (tree *Tree[K, V]) Size() int { return tree.size } // Size returns the number of elements stored in the subtree. // Computed dynamically on each call, i.e. the subtree is traversed to count the number of the nodes. -func (node *Node) Size() int { +func (node *Node[K, V]) Size() int { if node == nil { return 0 } @@ -177,8 +174,8 @@ func (node *Node) Size() int { } // Keys returns all keys in-order -func (tree *Tree) Keys() []interface{} { - keys := make([]interface{}, tree.size) +func (tree *Tree[K, V]) Keys() []K { + keys := make([]K, tree.size) it := tree.Iterator() for i := 0; it.Next(); i++ { keys[i] = it.Key() @@ -187,8 +184,8 @@ func (tree *Tree) Keys() []interface{} { } // Values returns all values in-order based on the key. -func (tree *Tree) Values() []interface{} { - values := make([]interface{}, tree.size) +func (tree *Tree[K, V]) Values() []V { + values := make([]V, tree.size) it := tree.Iterator() for i := 0; it.Next(); i++ { values[i] = it.Value() @@ -197,8 +194,8 @@ func (tree *Tree) Values() []interface{} { } // Left returns the left-most (min) node or nil if tree is empty. -func (tree *Tree) Left() *Node { - var parent *Node +func (tree *Tree[K, V]) Left() *Node[K, V] { + var parent *Node[K, V] current := tree.Root for current != nil { parent = current @@ -208,8 +205,8 @@ func (tree *Tree) Left() *Node { } // Right returns the right-most (max) node or nil if tree is empty. -func (tree *Tree) Right() *Node { - var parent *Node +func (tree *Tree[K, V]) Right() *Node[K, V] { + var parent *Node[K, V] current := tree.Root for current != nil { parent = current @@ -226,7 +223,7 @@ func (tree *Tree) Right() *Node { // all nodes in the tree are larger than the given node. // // Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *Tree) Floor(key interface{}) (floor *Node, found bool) { +func (tree *Tree[K, V]) Floor(key K) (floor *Node[K, V], found bool) { found = false node := tree.Root for node != nil { @@ -255,7 +252,7 @@ func (tree *Tree) Floor(key interface{}) (floor *Node, found bool) { // all nodes in the tree are smaller than the given node. // // Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *Tree) Ceiling(key interface{}) (ceiling *Node, found bool) { +func (tree *Tree[K, V]) Ceiling(key K) (ceiling *Node[K, V], found bool) { found = false node := tree.Root for node != nil { @@ -277,13 +274,13 @@ func (tree *Tree) Ceiling(key interface{}) (ceiling *Node, found bool) { } // Clear removes all nodes from the tree. -func (tree *Tree) Clear() { +func (tree *Tree[K, V]) Clear() { tree.Root = nil tree.size = 0 } // String returns a string representation of container -func (tree *Tree) String() string { +func (tree *Tree[K, V]) String() string { str := "RedBlackTree\n" if !tree.Empty() { output(tree.Root, "", true, &str) @@ -291,11 +288,11 @@ func (tree *Tree) String() string { return str } -func (node *Node) String() string { +func (node *Node[K, V]) String() string { return fmt.Sprintf("%v", node.Key) } -func output(node *Node, prefix string, isTail bool, str *string) { +func output[K comparable, V any](node *Node[K, V], prefix string, isTail bool, str *string) { if node.Right != nil { newPrefix := prefix if isTail { @@ -323,7 +320,7 @@ func output(node *Node, prefix string, isTail bool, str *string) { } } -func (tree *Tree) lookup(key interface{}) *Node { +func (tree *Tree[K, V]) lookup(key K) *Node[K, V] { node := tree.Root for node != nil { compare := tree.Comparator(key, node.Key) @@ -339,21 +336,21 @@ func (tree *Tree) lookup(key interface{}) *Node { return nil } -func (node *Node) grandparent() *Node { +func (node *Node[K, V]) grandparent() *Node[K, V] { if node != nil && node.Parent != nil { return node.Parent.Parent } return nil } -func (node *Node) uncle() *Node { +func (node *Node[K, V]) uncle() *Node[K, V] { if node == nil || node.Parent == nil || node.Parent.Parent == nil { return nil } return node.Parent.sibling() } -func (node *Node) sibling() *Node { +func (node *Node[K, V]) sibling() *Node[K, V] { if node == nil || node.Parent == nil { return nil } @@ -363,7 +360,7 @@ func (node *Node) sibling() *Node { return node.Parent.Left } -func (tree *Tree) rotateLeft(node *Node) { +func (tree *Tree[K, V]) rotateLeft(node *Node[K, V]) { right := node.Right tree.replaceNode(node, right) node.Right = right.Left @@ -374,7 +371,7 @@ func (tree *Tree) rotateLeft(node *Node) { node.Parent = right } -func (tree *Tree) rotateRight(node *Node) { +func (tree *Tree[K, V]) rotateRight(node *Node[K, V]) { left := node.Left tree.replaceNode(node, left) node.Left = left.Right @@ -385,7 +382,7 @@ func (tree *Tree) rotateRight(node *Node) { node.Parent = left } -func (tree *Tree) replaceNode(old *Node, new *Node) { +func (tree *Tree[K, V]) replaceNode(old *Node[K, V], new *Node[K, V]) { if old.Parent == nil { tree.Root = new } else { @@ -400,7 +397,7 @@ func (tree *Tree) replaceNode(old *Node, new *Node) { } } -func (tree *Tree) insertCase1(node *Node) { +func (tree *Tree[K, V]) insertCase1(node *Node[K, V]) { if node.Parent == nil { node.color = black } else { @@ -408,14 +405,14 @@ func (tree *Tree) insertCase1(node *Node) { } } -func (tree *Tree) insertCase2(node *Node) { +func (tree *Tree[K, V]) insertCase2(node *Node[K, V]) { if nodeColor(node.Parent) == black { return } tree.insertCase3(node) } -func (tree *Tree) insertCase3(node *Node) { +func (tree *Tree[K, V]) insertCase3(node *Node[K, V]) { uncle := node.uncle() if nodeColor(uncle) == red { node.Parent.color = black @@ -427,7 +424,7 @@ func (tree *Tree) insertCase3(node *Node) { } } -func (tree *Tree) insertCase4(node *Node) { +func (tree *Tree[K, V]) insertCase4(node *Node[K, V]) { grandparent := node.grandparent() if node == node.Parent.Right && node.Parent == grandparent.Left { tree.rotateLeft(node.Parent) @@ -439,7 +436,7 @@ func (tree *Tree) insertCase4(node *Node) { tree.insertCase5(node) } -func (tree *Tree) insertCase5(node *Node) { +func (tree *Tree[K, V]) insertCase5(node *Node[K, V]) { node.Parent.color = black grandparent := node.grandparent() grandparent.color = red @@ -450,7 +447,7 @@ func (tree *Tree) insertCase5(node *Node) { } } -func (node *Node) maximumNode() *Node { +func (node *Node[K, V]) maximumNode() *Node[K, V] { if node == nil { return nil } @@ -460,14 +457,14 @@ func (node *Node) maximumNode() *Node { return node } -func (tree *Tree) deleteCase1(node *Node) { +func (tree *Tree[K, V]) deleteCase1(node *Node[K, V]) { if node.Parent == nil { return } tree.deleteCase2(node) } -func (tree *Tree) deleteCase2(node *Node) { +func (tree *Tree[K, V]) deleteCase2(node *Node[K, V]) { sibling := node.sibling() if nodeColor(sibling) == red { node.Parent.color = red @@ -481,7 +478,7 @@ func (tree *Tree) deleteCase2(node *Node) { tree.deleteCase3(node) } -func (tree *Tree) deleteCase3(node *Node) { +func (tree *Tree[K, V]) deleteCase3(node *Node[K, V]) { sibling := node.sibling() if nodeColor(node.Parent) == black && nodeColor(sibling) == black && @@ -494,7 +491,7 @@ func (tree *Tree) deleteCase3(node *Node) { } } -func (tree *Tree) deleteCase4(node *Node) { +func (tree *Tree[K, V]) deleteCase4(node *Node[K, V]) { sibling := node.sibling() if nodeColor(node.Parent) == red && nodeColor(sibling) == black && @@ -507,7 +504,7 @@ func (tree *Tree) deleteCase4(node *Node) { } } -func (tree *Tree) deleteCase5(node *Node) { +func (tree *Tree[K, V]) deleteCase5(node *Node[K, V]) { sibling := node.sibling() if node == node.Parent.Left && nodeColor(sibling) == black && @@ -527,7 +524,7 @@ func (tree *Tree) deleteCase5(node *Node) { tree.deleteCase6(node) } -func (tree *Tree) deleteCase6(node *Node) { +func (tree *Tree[K, V]) deleteCase6(node *Node[K, V]) { sibling := node.sibling() sibling.color = nodeColor(node.Parent) node.Parent.color = black @@ -540,7 +537,7 @@ func (tree *Tree) deleteCase6(node *Node) { } } -func nodeColor(node *Node) color { +func nodeColor[K comparable, V any](node *Node[K, V]) color { if node == nil { return black } diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 4c0f519a..b4e76b1e 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -7,13 +7,13 @@ package redblacktree import ( "encoding/json" "fmt" - "github.com/emirpasic/gods/utils" + "slices" "strings" "testing" ) func TestRedBlackTreeGet(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() if actualValue := tree.Size(); actualValue != 0 { t.Errorf("Got %v expected %v", actualValue, 0) @@ -59,7 +59,7 @@ func TestRedBlackTreeGet(t *testing.T) { } func TestRedBlackTreePut(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(5, "e") tree.Put(6, "f") tree.Put(7, "g") @@ -72,10 +72,10 @@ func TestRedBlackTreePut(t *testing.T) { if actualValue := tree.Size(); actualValue != 7 { t.Errorf("Got %v expected %v", actualValue, 7) } - if actualValue, expectedValue := fmt.Sprintf("%d%d%d%d%d%d%d", tree.Keys()...), "1234567"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Keys(), []int{1, 2, 3, 4, 5, 6, 7}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s", tree.Values()...), "abcdefg"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Values(), []string{"a", "b", "c", "d", "e", "f", "g"}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } @@ -87,12 +87,12 @@ func TestRedBlackTreePut(t *testing.T) { {5, "e", true}, {6, "f", true}, {7, "g", true}, - {8, nil, false}, + {8, "", false}, } for _, test := range tests1 { // retrievals - actualValue, actualFound := tree.Get(test[0]) + actualValue, actualFound := tree.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } @@ -100,7 +100,7 @@ func TestRedBlackTreePut(t *testing.T) { } func TestRedBlackTreeRemove(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(5, "e") tree.Put(6, "f") tree.Put(7, "g") @@ -116,13 +116,10 @@ func TestRedBlackTreeRemove(t *testing.T) { tree.Remove(8) tree.Remove(5) - if actualValue, expectedValue := fmt.Sprintf("%d%d%d%d", tree.Keys()...), "1234"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Keys(), []int{1, 2, 3, 4}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", tree.Values()...), "abcd"; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", tree.Values()...), "abcd"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Values(), []string{"a", "b", "c", "d"}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } if actualValue := tree.Size(); actualValue != 4 { @@ -134,14 +131,14 @@ func TestRedBlackTreeRemove(t *testing.T) { {2, "b", true}, {3, "c", true}, {4, "d", true}, - {5, nil, false}, - {6, nil, false}, - {7, nil, false}, - {8, nil, false}, + {5, "", false}, + {6, "", false}, + {7, "", false}, + {8, "", false}, } for _, test := range tests2 { - actualValue, actualFound := tree.Get(test[0]) + actualValue, actualFound := tree.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } @@ -154,10 +151,10 @@ func TestRedBlackTreeRemove(t *testing.T) { tree.Remove(2) tree.Remove(2) - if actualValue, expectedValue := fmt.Sprintf("%s", tree.Keys()), "[]"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Keys(), []int{}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if actualValue, expectedValue := fmt.Sprintf("%s", tree.Values()), "[]"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Values(), []string{}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } if empty, size := tree.Empty(), tree.Size(); empty != true || size != -0 { @@ -167,7 +164,7 @@ func TestRedBlackTreeRemove(t *testing.T) { } func TestRedBlackTreeLeftAndRight(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() if actualValue := tree.Left(); actualValue != nil { t.Errorf("Got %v expected %v", actualValue, nil) @@ -185,23 +182,23 @@ func TestRedBlackTreeLeftAndRight(t *testing.T) { tree.Put(1, "x") // overwrite tree.Put(2, "b") - if actualValue, expectedValue := fmt.Sprintf("%d", tree.Left().Key), "1"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Left().Key, 1; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if actualValue, expectedValue := fmt.Sprintf("%s", tree.Left().Value), "x"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Left().Value, "x"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if actualValue, expectedValue := fmt.Sprintf("%d", tree.Right().Key), "7"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Right().Key, 7; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if actualValue, expectedValue := fmt.Sprintf("%s", tree.Right().Value), "g"; actualValue != expectedValue { + if actualValue, expectedValue := tree.Right().Value, "g"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } func TestRedBlackTreeCeilingAndFloor(t *testing.T) { - tree := NewWith(utils.IntComparator) + tree := New[int, string]() if node, found := tree.Floor(0); node != nil || found { t.Errorf("Got %v expected %v", node, "") @@ -234,7 +231,7 @@ func TestRedBlackTreeCeilingAndFloor(t *testing.T) { } func TestRedBlackTreeIteratorNextOnEmpty(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() it := tree.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty tree") @@ -242,7 +239,7 @@ func TestRedBlackTreeIteratorNextOnEmpty(t *testing.T) { } func TestRedBlackTreeIteratorPrevOnEmpty(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() it := tree.Iterator() for it.Prev() { t.Errorf("Shouldn't iterate on empty tree") @@ -250,7 +247,7 @@ func TestRedBlackTreeIteratorPrevOnEmpty(t *testing.T) { } func TestRedBlackTreeIterator1Next(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(5, "e") tree.Put(6, "f") tree.Put(7, "g") @@ -281,7 +278,7 @@ func TestRedBlackTreeIterator1Next(t *testing.T) { } func TestRedBlackTreeIterator1Prev(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(5, "e") tree.Put(6, "f") tree.Put(7, "g") @@ -314,7 +311,7 @@ func TestRedBlackTreeIterator1Prev(t *testing.T) { } func TestRedBlackTreeIterator2Next(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") @@ -333,7 +330,7 @@ func TestRedBlackTreeIterator2Next(t *testing.T) { } func TestRedBlackTreeIterator2Prev(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") @@ -354,7 +351,7 @@ func TestRedBlackTreeIterator2Prev(t *testing.T) { } func TestRedBlackTreeIterator3Next(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(1, "a") it := tree.Iterator() count := 0 @@ -371,7 +368,7 @@ func TestRedBlackTreeIterator3Next(t *testing.T) { } func TestRedBlackTreeIterator3Prev(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(1, "a") it := tree.Iterator() for it.Next() { @@ -390,7 +387,7 @@ func TestRedBlackTreeIterator3Prev(t *testing.T) { } func TestRedBlackTreeIterator4Next(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, int]() tree.Put(13, 5) tree.Put(8, 3) tree.Put(17, 7) @@ -426,7 +423,7 @@ func TestRedBlackTreeIterator4Next(t *testing.T) { } func TestRedBlackTreeIterator4Prev(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, int]() tree.Put(13, 5) tree.Put(8, 3) tree.Put(17, 7) @@ -464,7 +461,7 @@ func TestRedBlackTreeIterator4Prev(t *testing.T) { } func TestRedBlackTreeIteratorBegin(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") @@ -496,7 +493,7 @@ func TestRedBlackTreeIteratorBegin(t *testing.T) { } func TestRedBlackTreeIteratorEnd(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() it := tree.Iterator() if it.node != nil { @@ -523,7 +520,7 @@ func TestRedBlackTreeIteratorEnd(t *testing.T) { } func TestRedBlackTreeIteratorFirst(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") @@ -537,7 +534,7 @@ func TestRedBlackTreeIteratorFirst(t *testing.T) { } func TestRedBlackTreeIteratorLast(t *testing.T) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") @@ -552,13 +549,13 @@ func TestRedBlackTreeIteratorLast(t *testing.T) { func TestRedBlackTreeIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index interface{}, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // NextTo (empty) { - tree := NewWithIntComparator() + tree := New[int, string]() it := tree.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty tree") @@ -567,7 +564,7 @@ func TestRedBlackTreeIteratorNextTo(t *testing.T) { // NextTo (not found) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(0, "xx") tree.Put(1, "yy") it := tree.Iterator() @@ -578,7 +575,7 @@ func TestRedBlackTreeIteratorNextTo(t *testing.T) { // NextTo (found) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(2, "cc") tree.Put(0, "aa") tree.Put(1, "bb") @@ -587,13 +584,13 @@ func TestRedBlackTreeIteratorNextTo(t *testing.T) { if !it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty tree") } - if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Key(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Next() { t.Errorf("Should go to first element") } - if index, value := it.Key(), it.Value(); index != 2 || value.(string) != "cc" { + if index, value := it.Key(), it.Value(); index != 2 || value != "cc" { t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") } if it.Next() { @@ -604,13 +601,13 @@ func TestRedBlackTreeIteratorNextTo(t *testing.T) { func TestRedBlackTreeIteratorPrevTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" - seek := func(index interface{}, value interface{}) bool { - return strings.HasSuffix(value.(string), "b") + seek := func(index int, value string) bool { + return strings.HasSuffix(value, "b") } // PrevTo (empty) { - tree := NewWithIntComparator() + tree := New[int, string]() it := tree.Iterator() it.End() for it.PrevTo(seek) { @@ -620,7 +617,7 @@ func TestRedBlackTreeIteratorPrevTo(t *testing.T) { // PrevTo (not found) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(0, "xx") tree.Put(1, "yy") it := tree.Iterator() @@ -632,7 +629,7 @@ func TestRedBlackTreeIteratorPrevTo(t *testing.T) { // PrevTo (found) { - tree := NewWithIntComparator() + tree := New[int, string]() tree.Put(2, "cc") tree.Put(0, "aa") tree.Put(1, "bb") @@ -641,13 +638,13 @@ func TestRedBlackTreeIteratorPrevTo(t *testing.T) { if !it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty tree") } - if index, value := it.Key(), it.Value(); index != 1 || value.(string) != "bb" { + if index, value := it.Key(), it.Value(); index != 1 || value != "bb" { t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") } if !it.Prev() { t.Errorf("Should go to first element") } - if index, value := it.Key(), it.Value(); index != 0 || value.(string) != "aa" { + if index, value := it.Key(), it.Value(); index != 0 || value != "aa" { t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") } if it.Prev() { @@ -657,7 +654,7 @@ func TestRedBlackTreeIteratorPrevTo(t *testing.T) { } func TestRedBlackTreeSerialization(t *testing.T) { - tree := NewWithStringComparator() + tree := New[string, string]() tree.Put("c", "3") tree.Put("b", "2") tree.Put("a", "1") @@ -667,11 +664,11 @@ func TestRedBlackTreeSerialization(t *testing.T) { if actualValue, expectedValue := tree.Size(), 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if actualValue := tree.Keys(); actualValue[0].(string) != "a" || actualValue[1].(string) != "b" || actualValue[2].(string) != "c" { - t.Errorf("Got %v expected %v", actualValue, "[a,b,c]") + if actualValue, expectedValue := tree.Keys(), []string{"a", "b", "c"}; !slices.Equal(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } - if actualValue := tree.Values(); actualValue[0].(string) != "1" || actualValue[1].(string) != "2" || actualValue[2].(string) != "3" { - t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + if actualValue, expectedValue := tree.Values(), []string{"1", "2", "3"}; !slices.Equal(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } if err != nil { t.Errorf("Got error %v", err) @@ -691,21 +688,31 @@ func TestRedBlackTreeSerialization(t *testing.T) { t.Errorf("Got error %v", err) } - err = json.Unmarshal([]byte(`{"a":1,"b":2}`), &tree) + intTree := New[string, int]() + err = json.Unmarshal([]byte(`{"a":1,"b":2}`), intTree) if err != nil { t.Errorf("Got error %v", err) } + if actualValue, expectedValue := intTree.Size(), 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := intTree.Keys(), []string{"a", "b"}; !slices.Equal(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := intTree.Values(), []int{1, 2}; !slices.Equal(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } } func TestRedBlackTreeString(t *testing.T) { - c := NewWithStringComparator() + c := New[string, int]() c.Put("a", 1) if !strings.HasPrefix(c.String(), "RedBlackTree") { t.Errorf("String should start with container name") } } -func benchmarkGet(b *testing.B, tree *Tree, size int) { +func benchmarkGet(b *testing.B, tree *Tree[int, struct{}], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { tree.Get(n) @@ -713,7 +720,7 @@ func benchmarkGet(b *testing.B, tree *Tree, size int) { } } -func benchmarkPut(b *testing.B, tree *Tree, size int) { +func benchmarkPut(b *testing.B, tree *Tree[int, struct{}], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { tree.Put(n, struct{}{}) @@ -721,7 +728,7 @@ func benchmarkPut(b *testing.B, tree *Tree, size int) { } } -func benchmarkRemove(b *testing.B, tree *Tree, size int) { +func benchmarkRemove(b *testing.B, tree *Tree[int, struct{}], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { tree.Remove(n) @@ -732,7 +739,7 @@ func benchmarkRemove(b *testing.B, tree *Tree, size int) { func BenchmarkRedBlackTreeGet100(b *testing.B) { b.StopTimer() size := 100 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -743,7 +750,7 @@ func BenchmarkRedBlackTreeGet100(b *testing.B) { func BenchmarkRedBlackTreeGet1000(b *testing.B) { b.StopTimer() size := 1000 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -754,7 +761,7 @@ func BenchmarkRedBlackTreeGet1000(b *testing.B) { func BenchmarkRedBlackTreeGet10000(b *testing.B) { b.StopTimer() size := 10000 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -765,7 +772,7 @@ func BenchmarkRedBlackTreeGet10000(b *testing.B) { func BenchmarkRedBlackTreeGet100000(b *testing.B) { b.StopTimer() size := 100000 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -776,7 +783,7 @@ func BenchmarkRedBlackTreeGet100000(b *testing.B) { func BenchmarkRedBlackTreePut100(b *testing.B) { b.StopTimer() size := 100 - tree := NewWithIntComparator() + tree := New[int, struct{}]() b.StartTimer() benchmarkPut(b, tree, size) } @@ -784,7 +791,7 @@ func BenchmarkRedBlackTreePut100(b *testing.B) { func BenchmarkRedBlackTreePut1000(b *testing.B) { b.StopTimer() size := 1000 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -795,7 +802,7 @@ func BenchmarkRedBlackTreePut1000(b *testing.B) { func BenchmarkRedBlackTreePut10000(b *testing.B) { b.StopTimer() size := 10000 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -806,7 +813,7 @@ func BenchmarkRedBlackTreePut10000(b *testing.B) { func BenchmarkRedBlackTreePut100000(b *testing.B) { b.StopTimer() size := 100000 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -817,7 +824,7 @@ func BenchmarkRedBlackTreePut100000(b *testing.B) { func BenchmarkRedBlackTreeRemove100(b *testing.B) { b.StopTimer() size := 100 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -828,7 +835,7 @@ func BenchmarkRedBlackTreeRemove100(b *testing.B) { func BenchmarkRedBlackTreeRemove1000(b *testing.B) { b.StopTimer() size := 1000 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -839,7 +846,7 @@ func BenchmarkRedBlackTreeRemove1000(b *testing.B) { func BenchmarkRedBlackTreeRemove10000(b *testing.B) { b.StopTimer() size := 10000 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } @@ -850,7 +857,7 @@ func BenchmarkRedBlackTreeRemove10000(b *testing.B) { func BenchmarkRedBlackTreeRemove100000(b *testing.B) { b.StopTimer() size := 100000 - tree := NewWithIntComparator() + tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } diff --git a/trees/redblacktree/serialization.go b/trees/redblacktree/serialization.go index 9f2a23c0..9311c897 100644 --- a/trees/redblacktree/serialization.go +++ b/trees/redblacktree/serialization.go @@ -6,27 +6,27 @@ package redblacktree import ( "encoding/json" - "github.com/emirpasic/gods/containers" - "github.com/emirpasic/gods/utils" + + "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation -var _ containers.JSONSerializer = (*Tree)(nil) -var _ containers.JSONDeserializer = (*Tree)(nil) +var _ containers.JSONSerializer = (*Tree[string, int])(nil) +var _ containers.JSONDeserializer = (*Tree[string, int])(nil) // ToJSON outputs the JSON representation of the tree. -func (tree *Tree) ToJSON() ([]byte, error) { - elements := make(map[string]interface{}) +func (tree *Tree[K, V]) ToJSON() ([]byte, error) { + elements := make(map[K]V) it := tree.Iterator() for it.Next() { - elements[utils.ToString(it.Key())] = it.Value() + elements[it.Key()] = it.Value() } return json.Marshal(&elements) } // FromJSON populates the tree from the input JSON representation. -func (tree *Tree) FromJSON(data []byte) error { - elements := make(map[string]interface{}) +func (tree *Tree[K, V]) FromJSON(data []byte) error { + elements := make(map[K]V) err := json.Unmarshal(data, &elements) if err == nil { tree.Clear() @@ -38,11 +38,11 @@ func (tree *Tree) FromJSON(data []byte) error { } // UnmarshalJSON @implements json.Unmarshaler -func (tree *Tree) UnmarshalJSON(bytes []byte) error { +func (tree *Tree[K, V]) UnmarshalJSON(bytes []byte) error { return tree.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler -func (tree *Tree) MarshalJSON() ([]byte, error) { +func (tree *Tree[K, V]) MarshalJSON() ([]byte, error) { return tree.ToJSON() } diff --git a/trees/trees.go b/trees/trees.go index 8d1b868f..ad544007 100644 --- a/trees/trees.go +++ b/trees/trees.go @@ -9,11 +9,11 @@ // Reference: https://en.wikipedia.org/wiki/Tree_%28data_structure%29 package trees -import "github.com/emirpasic/gods/containers" +import "github.com/emirpasic/gods/v2/containers" // Tree interface that all trees implement -type Tree interface { - containers.Container +type Tree[V any] interface { + containers.Container[V] // Empty() bool // Size() int // Clear() diff --git a/utils/comparator.go b/utils/comparator.go index 6a9afbf3..37ef49d7 100644 --- a/utils/comparator.go +++ b/utils/comparator.go @@ -6,244 +6,14 @@ package utils import "time" -// Comparator will make type assertion (see IntComparator for example), -// which will panic if a or b are not of the asserted type. -// -// Should return a number: -// negative , if a < b -// zero , if a == b -// positive , if a > b -type Comparator func(a, b interface{}) int - -// StringComparator provides a fast comparison on strings -func StringComparator(a, b interface{}) int { - s1 := a.(string) - s2 := b.(string) - min := len(s2) - if len(s1) < len(s2) { - min = len(s1) - } - diff := 0 - for i := 0; i < min && diff == 0; i++ { - diff = int(s1[i]) - int(s2[i]) - } - if diff == 0 { - diff = len(s1) - len(s2) - } - if diff < 0 { - return -1 - } - if diff > 0 { - return 1 - } - return 0 -} - -// IntComparator provides a basic comparison on int -func IntComparator(a, b interface{}) int { - aAsserted := a.(int) - bAsserted := b.(int) - switch { - case aAsserted > bAsserted: - return 1 - case aAsserted < bAsserted: - return -1 - default: - return 0 - } -} - -// Int8Comparator provides a basic comparison on int8 -func Int8Comparator(a, b interface{}) int { - aAsserted := a.(int8) - bAsserted := b.(int8) - switch { - case aAsserted > bAsserted: - return 1 - case aAsserted < bAsserted: - return -1 - default: - return 0 - } -} - -// Int16Comparator provides a basic comparison on int16 -func Int16Comparator(a, b interface{}) int { - aAsserted := a.(int16) - bAsserted := b.(int16) - switch { - case aAsserted > bAsserted: - return 1 - case aAsserted < bAsserted: - return -1 - default: - return 0 - } -} - -// Int32Comparator provides a basic comparison on int32 -func Int32Comparator(a, b interface{}) int { - aAsserted := a.(int32) - bAsserted := b.(int32) - switch { - case aAsserted > bAsserted: - return 1 - case aAsserted < bAsserted: - return -1 - default: - return 0 - } -} - -// Int64Comparator provides a basic comparison on int64 -func Int64Comparator(a, b interface{}) int { - aAsserted := a.(int64) - bAsserted := b.(int64) - switch { - case aAsserted > bAsserted: - return 1 - case aAsserted < bAsserted: - return -1 - default: - return 0 - } -} - -// UIntComparator provides a basic comparison on uint -func UIntComparator(a, b interface{}) int { - aAsserted := a.(uint) - bAsserted := b.(uint) - switch { - case aAsserted > bAsserted: - return 1 - case aAsserted < bAsserted: - return -1 - default: - return 0 - } -} - -// UInt8Comparator provides a basic comparison on uint8 -func UInt8Comparator(a, b interface{}) int { - aAsserted := a.(uint8) - bAsserted := b.(uint8) - switch { - case aAsserted > bAsserted: - return 1 - case aAsserted < bAsserted: - return -1 - default: - return 0 - } -} - -// UInt16Comparator provides a basic comparison on uint16 -func UInt16Comparator(a, b interface{}) int { - aAsserted := a.(uint16) - bAsserted := b.(uint16) - switch { - case aAsserted > bAsserted: - return 1 - case aAsserted < bAsserted: - return -1 - default: - return 0 - } -} - -// UInt32Comparator provides a basic comparison on uint32 -func UInt32Comparator(a, b interface{}) int { - aAsserted := a.(uint32) - bAsserted := b.(uint32) - switch { - case aAsserted > bAsserted: - return 1 - case aAsserted < bAsserted: - return -1 - default: - return 0 - } -} - -// UInt64Comparator provides a basic comparison on uint64 -func UInt64Comparator(a, b interface{}) int { - aAsserted := a.(uint64) - bAsserted := b.(uint64) - switch { - case aAsserted > bAsserted: - return 1 - case aAsserted < bAsserted: - return -1 - default: - return 0 - } -} - -// Float32Comparator provides a basic comparison on float32 -func Float32Comparator(a, b interface{}) int { - aAsserted := a.(float32) - bAsserted := b.(float32) - switch { - case aAsserted > bAsserted: - return 1 - case aAsserted < bAsserted: - return -1 - default: - return 0 - } -} - -// Float64Comparator provides a basic comparison on float64 -func Float64Comparator(a, b interface{}) int { - aAsserted := a.(float64) - bAsserted := b.(float64) - switch { - case aAsserted > bAsserted: - return 1 - case aAsserted < bAsserted: - return -1 - default: - return 0 - } -} - -// ByteComparator provides a basic comparison on byte -func ByteComparator(a, b interface{}) int { - aAsserted := a.(byte) - bAsserted := b.(byte) - switch { - case aAsserted > bAsserted: - return 1 - case aAsserted < bAsserted: - return -1 - default: - return 0 - } -} - -// RuneComparator provides a basic comparison on rune -func RuneComparator(a, b interface{}) int { - aAsserted := a.(rune) - bAsserted := b.(rune) - switch { - case aAsserted > bAsserted: - return 1 - case aAsserted < bAsserted: - return -1 - default: - return 0 - } -} +type Comparator[T any] func(x, y T) int // TimeComparator provides a basic comparison on time.Time -func TimeComparator(a, b interface{}) int { - aAsserted := a.(time.Time) - bAsserted := b.(time.Time) - +func TimeComparator(a, b time.Time) int { switch { - case aAsserted.After(bAsserted): + case a.After(b): return 1 - case aAsserted.Before(bAsserted): + case a.Before(b): return -1 default: return 0 diff --git a/utils/comparator_test.go b/utils/comparator_test.go index 356c5e26..b985f94c 100644 --- a/utils/comparator_test.go +++ b/utils/comparator_test.go @@ -9,51 +9,6 @@ import ( "time" ) -func TestIntComparator(t *testing.T) { - - // i1,i2,expected - tests := [][]interface{}{ - {1, 1, 0}, - {1, 2, -1}, - {2, 1, 1}, - {11, 22, -1}, - {0, 0, 0}, - {1, 0, 1}, - {0, 1, -1}, - } - - for _, test := range tests { - actual := IntComparator(test[0], test[1]) - expected := test[2] - if actual != expected { - t.Errorf("Got %v expected %v", actual, expected) - } - } -} - -func TestStringComparator(t *testing.T) { - - // s1,s2,expected - tests := [][]interface{}{ - {"a", "a", 0}, - {"a", "b", -1}, - {"b", "a", 1}, - {"aa", "aab", -1}, - {"", "", 0}, - {"a", "", 1}, - {"", "a", -1}, - {"", "aaaaaaa", -1}, - } - - for _, test := range tests { - actual := StringComparator(test[0], test[1]) - expected := test[2] - if actual != expected { - t.Errorf("Got %v expected %v", actual, expected) - } - } -} - func TestTimeComparator(t *testing.T) { now := time.Now() @@ -66,239 +21,7 @@ func TestTimeComparator(t *testing.T) { } for _, test := range tests { - actual := TimeComparator(test[0], test[1]) - expected := test[2] - if actual != expected { - t.Errorf("Got %v expected %v", actual, expected) - } - } -} - -func TestCustomComparator(t *testing.T) { - - type Custom struct { - id int - name string - } - - byID := func(a, b interface{}) int { - c1 := a.(Custom) - c2 := b.(Custom) - switch { - case c1.id > c2.id: - return 1 - case c1.id < c2.id: - return -1 - default: - return 0 - } - } - - // o1,o2,expected - tests := [][]interface{}{ - {Custom{1, "a"}, Custom{1, "a"}, 0}, - {Custom{1, "a"}, Custom{2, "b"}, -1}, - {Custom{2, "b"}, Custom{1, "a"}, 1}, - {Custom{1, "a"}, Custom{1, "b"}, 0}, - } - - for _, test := range tests { - actual := byID(test[0], test[1]) - expected := test[2] - if actual != expected { - t.Errorf("Got %v expected %v", actual, expected) - } - } -} - -func TestInt8ComparatorComparator(t *testing.T) { - tests := [][]interface{}{ - {int8(1), int8(1), 0}, - {int8(0), int8(1), -1}, - {int8(1), int8(0), 1}, - } - for _, test := range tests { - actual := Int8Comparator(test[0], test[1]) - expected := test[2] - if actual != expected { - t.Errorf("Got %v expected %v", actual, expected) - } - } -} - -func TestInt16Comparator(t *testing.T) { - tests := [][]interface{}{ - {int16(1), int16(1), 0}, - {int16(0), int16(1), -1}, - {int16(1), int16(0), 1}, - } - for _, test := range tests { - actual := Int16Comparator(test[0], test[1]) - expected := test[2] - if actual != expected { - t.Errorf("Got %v expected %v", actual, expected) - } - } -} - -func TestInt32Comparator(t *testing.T) { - tests := [][]interface{}{ - {int32(1), int32(1), 0}, - {int32(0), int32(1), -1}, - {int32(1), int32(0), 1}, - } - for _, test := range tests { - actual := Int32Comparator(test[0], test[1]) - expected := test[2] - if actual != expected { - t.Errorf("Got %v expected %v", actual, expected) - } - } -} - -func TestInt64Comparator(t *testing.T) { - tests := [][]interface{}{ - {int64(1), int64(1), 0}, - {int64(0), int64(1), -1}, - {int64(1), int64(0), 1}, - } - for _, test := range tests { - actual := Int64Comparator(test[0], test[1]) - expected := test[2] - if actual != expected { - t.Errorf("Got %v expected %v", actual, expected) - } - } -} - -func TestUIntComparator(t *testing.T) { - tests := [][]interface{}{ - {uint(1), uint(1), 0}, - {uint(0), uint(1), -1}, - {uint(1), uint(0), 1}, - } - for _, test := range tests { - actual := UIntComparator(test[0], test[1]) - expected := test[2] - if actual != expected { - t.Errorf("Got %v expected %v", actual, expected) - } - } -} - -func TestUInt8Comparator(t *testing.T) { - tests := [][]interface{}{ - {uint8(1), uint8(1), 0}, - {uint8(0), uint8(1), -1}, - {uint8(1), uint8(0), 1}, - } - for _, test := range tests { - actual := UInt8Comparator(test[0], test[1]) - expected := test[2] - if actual != expected { - t.Errorf("Got %v expected %v", actual, expected) - } - } -} - -func TestUInt16Comparator(t *testing.T) { - tests := [][]interface{}{ - {uint16(1), uint16(1), 0}, - {uint16(0), uint16(1), -1}, - {uint16(1), uint16(0), 1}, - } - for _, test := range tests { - actual := UInt16Comparator(test[0], test[1]) - expected := test[2] - if actual != expected { - t.Errorf("Got %v expected %v", actual, expected) - } - } -} - -func TestUInt32Comparator(t *testing.T) { - tests := [][]interface{}{ - {uint32(1), uint32(1), 0}, - {uint32(0), uint32(1), -1}, - {uint32(1), uint32(0), 1}, - } - for _, test := range tests { - actual := UInt32Comparator(test[0], test[1]) - expected := test[2] - if actual != expected { - t.Errorf("Got %v expected %v", actual, expected) - } - } -} - -func TestUInt64Comparator(t *testing.T) { - tests := [][]interface{}{ - {uint64(1), uint64(1), 0}, - {uint64(0), uint64(1), -1}, - {uint64(1), uint64(0), 1}, - } - for _, test := range tests { - actual := UInt64Comparator(test[0], test[1]) - expected := test[2] - if actual != expected { - t.Errorf("Got %v expected %v", actual, expected) - } - } -} - -func TestFloat32Comparator(t *testing.T) { - tests := [][]interface{}{ - {float32(1.1), float32(1.1), 0}, - {float32(0.1), float32(1.1), -1}, - {float32(1.1), float32(0.1), 1}, - } - for _, test := range tests { - actual := Float32Comparator(test[0], test[1]) - expected := test[2] - if actual != expected { - t.Errorf("Got %v expected %v", actual, expected) - } - } -} - -func TestFloat64Comparator(t *testing.T) { - tests := [][]interface{}{ - {float64(1.1), float64(1.1), 0}, - {float64(0.1), float64(1.1), -1}, - {float64(1.1), float64(0.1), 1}, - } - for _, test := range tests { - actual := Float64Comparator(test[0], test[1]) - expected := test[2] - if actual != expected { - t.Errorf("Got %v expected %v", actual, expected) - } - } -} - -func TestByteComparator(t *testing.T) { - tests := [][]interface{}{ - {byte(1), byte(1), 0}, - {byte(0), byte(1), -1}, - {byte(1), byte(0), 1}, - } - for _, test := range tests { - actual := ByteComparator(test[0], test[1]) - expected := test[2] - if actual != expected { - t.Errorf("Got %v expected %v", actual, expected) - } - } -} - -func TestRuneComparator(t *testing.T) { - tests := [][]interface{}{ - {rune(1), rune(1), 0}, - {rune(0), rune(1), -1}, - {rune(1), rune(0), 1}, - } - for _, test := range tests { - actual := RuneComparator(test[0], test[1]) + actual := TimeComparator(test[0].(time.Time), test[1].(time.Time)) expected := test[2] if actual != expected { t.Errorf("Got %v expected %v", actual, expected) diff --git a/utils/sort.go b/utils/sort.go deleted file mode 100644 index 79ced1f5..00000000 --- a/utils/sort.go +++ /dev/null @@ -1,29 +0,0 @@ -// 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 utils - -import "sort" - -// Sort sorts values (in-place) with respect to the given comparator. -// -// Uses Go's sort (hybrid of quicksort for large and then insertion sort for smaller slices). -func Sort(values []interface{}, comparator Comparator) { - sort.Sort(sortable{values, comparator}) -} - -type sortable struct { - values []interface{} - comparator Comparator -} - -func (s sortable) Len() int { - return len(s.values) -} -func (s sortable) Swap(i, j int) { - s.values[i], s.values[j] = s.values[j], s.values[i] -} -func (s sortable) Less(i, j int) bool { - return s.comparator(s.values[i], s.values[j]) < 0 -} diff --git a/utils/sort_test.go b/utils/sort_test.go deleted file mode 100644 index 7831fc9b..00000000 --- a/utils/sort_test.go +++ /dev/null @@ -1,104 +0,0 @@ -// 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 utils - -import ( - "math/rand" - "testing" -) - -func TestSortInts(t *testing.T) { - ints := []interface{}{} - ints = append(ints, 4) - ints = append(ints, 1) - ints = append(ints, 2) - ints = append(ints, 3) - - Sort(ints, IntComparator) - - for i := 1; i < len(ints); i++ { - if ints[i-1].(int) > ints[i].(int) { - t.Errorf("Not sorted!") - } - } - -} - -func TestSortStrings(t *testing.T) { - - strings := []interface{}{} - strings = append(strings, "d") - strings = append(strings, "a") - strings = append(strings, "b") - strings = append(strings, "c") - - Sort(strings, StringComparator) - - for i := 1; i < len(strings); i++ { - if strings[i-1].(string) > strings[i].(string) { - t.Errorf("Not sorted!") - } - } -} - -func TestSortStructs(t *testing.T) { - type User struct { - id int - name string - } - - byID := func(a, b interface{}) int { - c1 := a.(User) - c2 := b.(User) - switch { - case c1.id > c2.id: - return 1 - case c1.id < c2.id: - return -1 - default: - return 0 - } - } - - // o1,o2,expected - users := []interface{}{ - User{4, "d"}, - User{1, "a"}, - User{3, "c"}, - User{2, "b"}, - } - - Sort(users, byID) - - for i := 1; i < len(users); i++ { - if users[i-1].(User).id > users[i].(User).id { - t.Errorf("Not sorted!") - } - } -} - -func TestSortRandom(t *testing.T) { - ints := []interface{}{} - for i := 0; i < 10000; i++ { - ints = append(ints, rand.Int()) - } - Sort(ints, IntComparator) - for i := 1; i < len(ints); i++ { - if ints[i-1].(int) > ints[i].(int) { - t.Errorf("Not sorted!") - } - } -} - -func BenchmarkGoSortRandom(b *testing.B) { - b.StopTimer() - ints := []interface{}{} - for i := 0; i < 100000; i++ { - ints = append(ints, rand.Int()) - } - b.StartTimer() - Sort(ints, IntComparator) - b.StopTimer() -} From 454720c27e5f9b59c82fa1e869b3297b81c8d7fb Mon Sep 17 00:00:00 2001 From: Kashiwa <13825170+ksw2000@users.noreply.github.com> Date: Fri, 19 Jul 2024 00:41:44 +0800 Subject: [PATCH 313/320] Improved ArrayList performance by removing `size` field. (#255) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Improved ArrayList performance by removing `size` field. Removed the `size` field from the `List` struct and replaced it with the built-in Go slice length implementation. + Achieved an average reduction of nearly 40% in execution time for `ArrayListGet`. + Achieved an average reduction of nearly 23% in memory usage for `ArrayListAdd`. + However, this change slightly increased the execution time for `ArrayListAdd` by 2.7%. ``` goos: linux goarch: amd64 pkg: github.com/emirpasic/gods/v2/lists/arraylist cpu: Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz │ old.txt │ new.txt │ │ sec/op │ sec/op vs base │ ArrayListGet100-8 51.20n ± 0% 32.49n ± 0% -36.53% (n=50) ArrayListGet1000-8 447.5n ± 0% 270.3n ± 1% -39.60% (n=50) ArrayListGet10000-8 4.418µ ± 1% 2.540µ ± 0% -42.52% (n=50) ArrayListGet100000-8 44.06µ ± 0% 25.15µ ± 0% -42.91% (n=50) ArrayListAdd100-8 726.5n ± 1% 760.5n ± 0% +4.69% (p=0.000 n=50) ArrayListAdd1000-8 7.437µ ± 2% 7.389µ ± 1% ~ (p=0.746 n=50) ArrayListAdd10000-8 70.06µ ± 1% 74.34µ ± 1% +6.11% (p=0.000 n=50) ArrayListAdd100000-8 740.2µ ± 1% 728.9µ ± 2% ~ (p=0.147 n=50) ArrayListRemove100-8 233.8n ± 0% 233.9n ± 0% ~ (p=0.162 n=50) ArrayListRemove1000-8 2.275µ ± 0% 2.276µ ± 0% ~ (p=0.452 n=50) ArrayListRemove10000-8 22.75µ ± 0% 22.75µ ± 0% ~ (p=0.956 n=50) ArrayListRemove100000-8 1.323m ± 1% 1.331m ± 1% ~ (p=0.120 n=50) geomean 7.218µ 6.119µ -15.22% │ old.txt │ new.txt │ │ B/op │ B/op vs base │ ArrayListGet100-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=50) ¹ ArrayListGet1000-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=50) ¹ ArrayListGet10000-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=50) ¹ ArrayListGet100000-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=50) ¹ ArrayListAdd100-8 2.987Ki ± 0% 2.087Ki ± 1% -30.14% (n=50) ArrayListAdd1000-8 27.50Ki ± 1% 23.31Ki ± 2% -15.24% (p=0.000 n=50) ArrayListAdd10000-8 293.9Ki ± 1% 204.7Ki ± 1% -30.36% (n=50) ArrayListAdd100000-8 2.667Mi ± 1% 2.244Mi ± 12% -15.86% (p=0.000 n=50) ArrayListRemove100-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=50) ¹ ArrayListRemove1000-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=50) ¹ ArrayListRemove10000-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=50) ¹ ArrayListRemove100000-8 453.5 ± 1% 457.5 ± 1% ~ (p=0.059 n=50) geomean ² -8.38% ² ¹ all samples are equal ² summaries must be >0 to compute geomean │ old.txt │ new.txt │ │ allocs/op │ allocs/op vs base │ ArrayListGet100-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=50) ¹ ArrayListGet1000-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=50) ¹ ArrayListGet10000-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=50) ¹ ArrayListGet100000-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=50) ¹ ArrayListAdd100-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=50) ¹ ArrayListAdd1000-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=50) ¹ ArrayListAdd10000-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=50) ¹ ArrayListAdd100000-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=50) ¹ ArrayListRemove100-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=50) ¹ ArrayListRemove1000-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=50) ¹ ArrayListRemove10000-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=50) ¹ ArrayListRemove100000-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=50) ¹ geomean ² +0.00% ² ¹ all samples are equal ² summaries must be >0 to compute geomean ``` * Improve ArrayList Remove() by `slices.Delete` The performance of `slices.Delete()` is better ``` goos: linux goarch: amd64 pkg: github.com/emirpasic/gods/v2/lists/arraylist cpu: Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz │ old-remove.txt │ new-remove.txt │ │ sec/op │ sec/op vs base │ ArrayListRemove100-8 234.2n ± 1% 211.2n ± 2% -9.82% (p=0.000 n=10) ArrayListRemove1000-8 2.293µ ± 1% 2.063µ ± 4% -10.05% (p=0.000 n=10) ArrayListRemove10000-8 22.78µ ± 1% 20.53µ ± 2% -9.86% (p=0.000 n=10) ArrayListRemove100000-8 1.318m ± 3% 1.279m ± 2% -2.96% (p=0.019 n=10) geomean 11.27µ 10.34µ -8.22% │ old-remove.txt │ new-remove.txt │ │ B/op │ B/op vs base │ ArrayListRemove100-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ArrayListRemove1000-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ArrayListRemove10000-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ArrayListRemove100000-8 452.0 ± 4% 444.5 ± 1% ~ (p=0.224 n=10) geomean ² -0.42% ² ¹ all samples are equal ² summaries must be >0 to compute geomean │ old-remove.txt │ new-remove.txt │ │ allocs/op │ allocs/op vs base │ ArrayListRemove100-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ArrayListRemove1000-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ArrayListRemove10000-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ArrayListRemove100000-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ geomean ² +0.00% ² ¹ all samples are equal ² summaries must be >0 to compute geomean ``` * Improve ArrayList Clear() by using built-in clear() instead of creating a new one * Refactor code by `slices` package. * Refactor ArrayList Insert() by `slices.Insert()` --- lists/arraylist/arraylist.go | 80 ++++++++++++-------------------- lists/arraylist/iterator.go | 4 +- lists/arraylist/serialization.go | 5 +- 3 files changed, 32 insertions(+), 57 deletions(-) diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index e67ff292..163c28d0 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -24,7 +24,6 @@ var _ lists.List[int] = (*List[int])(nil) // List holds the elements in a slice type List[T comparable] struct { elements []T - size int } const ( @@ -43,10 +42,10 @@ func New[T comparable](values ...T) *List[T] { // Add appends a value at the end of the list func (list *List[T]) Add(values ...T) { + l := len(list.elements) list.growBy(len(values)) - for _, value := range values { - list.elements[list.size] = value - list.size++ + for i := range values { + list.elements[l+i] = values[i] } } @@ -69,10 +68,7 @@ func (list *List[T]) Remove(index int) { return } - clear(list.elements[index : index+1]) - copy(list.elements[index:], list.elements[index+1:list.size]) // shift to the left by one (slow operation, need ways to optimize this) - list.size-- - + list.elements = slices.Delete(list.elements, index, index+1) list.shrink() } @@ -81,16 +77,8 @@ func (list *List[T]) Remove(index int) { // Performance time complexity of n^2. // Returns true if no arguments are passed at all, i.e. set is always super-set of empty set. func (list *List[T]) Contains(values ...T) bool { - for _, searchValue := range values { - found := false - for index := 0; index < list.size; index++ { - if list.elements[index] == searchValue { - found = true - break - } - } - if !found { + if !slices.Contains(list.elements, searchValue) { return false } } @@ -99,38 +87,28 @@ func (list *List[T]) Contains(values ...T) bool { // Values returns all elements in the list. func (list *List[T]) Values() []T { - newElements := make([]T, list.size, list.size) - copy(newElements, list.elements[:list.size]) - return newElements + return slices.Clone(list.elements) } // IndexOf returns index of provided element func (list *List[T]) IndexOf(value T) int { - if list.size == 0 { - return -1 - } - for index, element := range list.elements { - if element == value { - return index - } - } - return -1 + return slices.Index(list.elements, value) } // Empty returns true if list does not contain any elements. func (list *List[T]) Empty() bool { - return list.size == 0 + return len(list.elements) == 0 } // Size returns number of elements within the list. func (list *List[T]) Size() int { - return list.size + return len(list.elements) } // Clear removes all elements from the list. func (list *List[T]) Clear() { - list.size = 0 - list.elements = []T{} + clear(list.elements[:cap(list.elements)]) + list.elements = list.elements[:0] } // Sort sorts values (in-place) using. @@ -138,7 +116,7 @@ func (list *List[T]) Sort(comparator utils.Comparator[T]) { if len(list.elements) < 2 { return } - slices.SortFunc(list.elements[:list.size], comparator) + slices.SortFunc(list.elements, comparator) } // Swap swaps the two values at the specified positions. @@ -152,20 +130,17 @@ func (list *List[T]) Swap(i, j int) { // Does not do anything if position is negative or bigger than list's size // Note: position equal to list's size is valid, i.e. append. func (list *List[T]) Insert(index int, values ...T) { - if !list.withinRange(index) { // Append - if index == list.size { + if index == len(list.elements) { list.Add(values...) } return } - l := len(values) - list.growBy(l) - list.size += l - copy(list.elements[index+l:], list.elements[index:list.size-l]) - copy(list.elements[index:], values) + l := len(list.elements) + list.growBy(len(values)) + list.elements = slices.Insert(list.elements[:l], index, values...) } // Set the value at specified index @@ -175,7 +150,7 @@ func (list *List[T]) Set(index int, value T) { if !list.withinRange(index) { // Append - if index == list.size { + if index == len(list.elements) { list.Add(value) } return @@ -187,8 +162,8 @@ func (list *List[T]) Set(index int, value T) { // String returns a string representation of container func (list *List[T]) String() string { str := "ArrayList\n" - values := make([]string, 0, list.size) - for _, value := range list.elements[:list.size] { + values := make([]string, 0, len(list.elements)) + for _, value := range list.elements { values = append(values, fmt.Sprintf("%v", value)) } str += strings.Join(values, ", ") @@ -197,11 +172,11 @@ func (list *List[T]) String() string { // Check that the index is within bounds of the list func (list *List[T]) withinRange(index int) bool { - return index >= 0 && index < list.size + return index >= 0 && index < len(list.elements) } -func (list *List[T]) resize(cap int) { - newElements := make([]T, cap, cap) +func (list *List[T]) resize(len, cap int) { + newElements := make([]T, len, cap) copy(newElements, list.elements) list.elements = newElements } @@ -210,9 +185,12 @@ func (list *List[T]) resize(cap int) { func (list *List[T]) growBy(n int) { // When capacity is reached, grow by a factor of growthFactor and add number of elements currentCapacity := cap(list.elements) - if list.size+n >= currentCapacity { + + if newLength := len(list.elements) + n; newLength >= currentCapacity { newCapacity := int(growthFactor * float32(currentCapacity+n)) - list.resize(newCapacity) + list.resize(newLength, newCapacity) + } else { + list.elements = list.elements[:newLength] } } @@ -223,7 +201,7 @@ func (list *List[T]) shrink() { } // Shrink when size is at shrinkFactor * capacity currentCapacity := cap(list.elements) - if list.size <= int(float32(currentCapacity)*shrinkFactor) { - list.resize(list.size) + if len(list.elements) <= int(float32(currentCapacity)*shrinkFactor) { + list.resize(len(list.elements), len(list.elements)) } } diff --git a/lists/arraylist/iterator.go b/lists/arraylist/iterator.go index 5a6705ce..3c2c6e78 100644 --- a/lists/arraylist/iterator.go +++ b/lists/arraylist/iterator.go @@ -25,7 +25,7 @@ func (list *List[T]) Iterator() *Iterator[T] { // 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[T]) Next() bool { - if iterator.index < iterator.list.size { + if iterator.index < iterator.list.Size() { iterator.index++ } return iterator.list.withinRange(iterator.index) @@ -62,7 +62,7 @@ func (iterator *Iterator[T]) 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[T]) End() { - iterator.index = iterator.list.size + iterator.index = iterator.list.Size() } // First moves the iterator to the first element and returns true if there was a first element in the container. diff --git a/lists/arraylist/serialization.go b/lists/arraylist/serialization.go index a3aec534..73074102 100644 --- a/lists/arraylist/serialization.go +++ b/lists/arraylist/serialization.go @@ -16,15 +16,12 @@ var _ containers.JSONDeserializer = (*List[int])(nil) // ToJSON outputs the JSON representation of list's elements. func (list *List[T]) ToJSON() ([]byte, error) { - return json.Marshal(list.elements[:list.size]) + return json.Marshal(list.elements) } // FromJSON populates list's elements from the input JSON representation. func (list *List[T]) FromJSON(data []byte) error { err := json.Unmarshal(data, &list.elements) - if err == nil { - list.size = len(list.elements) - } return err } From a062dd859f3c17aca3fc12830bcce4a10dc50d40 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 22 Jul 2024 23:49:43 +0200 Subject: [PATCH 314/320] Delete .github/FUNDING.yml --- .github/FUNDING.yml | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 8a4f7704..00000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,12 +0,0 @@ -# These are supported funding model platforms - -github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] -patreon: godatastructures -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] \ No newline at end of file From 4b9c3ddfba0057f5eeb20919d766798319b10bb7 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 23 Jul 2024 00:15:20 +0200 Subject: [PATCH 315/320] Update config.yml --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4ecc8ccb..fd2ab7e3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -72,4 +72,4 @@ workflows: matrix: parameters: # To test with and without generics (versions prior to 1.18) - version: [ "1.18", "1.17" ] \ No newline at end of file + version: [ "1.19", "1.20", "latest" ] From ade7b27d1c9018a3052e704d3d4c816d881f022c Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 23 Jul 2024 00:20:40 +0200 Subject: [PATCH 316/320] Updated config.yml --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index fd2ab7e3..8dd9697f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ jobs: parameters: version: type: string - default: latest + default: "1.19" docker: - image: cimg/go:<> environment: From 7df43f80c7f566756e689a0fffab922419b848c0 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 23 Jul 2024 00:23:31 +0200 Subject: [PATCH 317/320] Updated config.yml --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8dd9697f..61bdadc4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ jobs: parameters: version: type: string - default: "1.19" + default: "1.21" docker: - image: cimg/go:<> environment: @@ -72,4 +72,4 @@ workflows: matrix: parameters: # To test with and without generics (versions prior to 1.18) - version: [ "1.19", "1.20", "latest" ] + version: [ "1.21", "latest" ] From 8323d02ee3ca1499478f9ccd7a299fb1c5005780 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Tue, 23 Jul 2024 00:25:29 +0200 Subject: [PATCH 318/320] Update config.yml --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 61bdadc4..d40bb66a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -72,4 +72,4 @@ workflows: matrix: parameters: # To test with and without generics (versions prior to 1.18) - version: [ "1.21", "latest" ] + version: [ "1.21" ] From 08eae88bde75929cce4c5a28812349741413be02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Dular?= <22869613+xBlaz3kx@users.noreply.github.com> Date: Tue, 11 Mar 2025 22:13:56 +0100 Subject: [PATCH 319/320] Typo fix --- lists/doublylinkedlist/doublylinkedlist.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 6a34e9de..b92e9007 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -88,7 +88,7 @@ func (list *List[T]) Get(index int) (T, bool) { return t, false } - // determine traveral direction, last to first or first to last + // determine traversal direction, last to first or first to last if list.size-index < index { element := list.last for e := list.size - 1; e != index; e, element = e-1, element.prev { From 67069ef985410e4b6e8419951bff707f18dbfd03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Dular?= <22869613+xBlaz3kx@users.noreply.github.com> Date: Tue, 11 Mar 2025 22:23:02 +0100 Subject: [PATCH 320/320] Typo fix --- lists/doublylinkedlist/doublylinkedlist.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index b92e9007..dcbd0e51 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -209,7 +209,7 @@ func (list *List[T]) Clear() { list.last = nil } -// Sort sorts values (in-place) using. +// Sort sorts values (in-place) using a Comparator. func (list *List[T]) Sort(comparator utils.Comparator[T]) { if list.size < 2 {