Repository: emirpasic/gods Branch: master Commit: 1d83d5ae39fb Files: 142 Total size: 676.3 KB Directory structure: gitextract_653tot9y/ ├── .circleci/ │ └── config.yml ├── .github/ │ ├── dependabot.yml │ └── workflows/ │ └── codeql-analysis.yml ├── .gitignore ├── LICENSE ├── README.md ├── containers/ │ ├── containers.go │ ├── containers_test.go │ ├── enumerable.go │ ├── iterator.go │ └── serialization.go ├── examples/ │ ├── README.md │ ├── arraylist/ │ │ └── arraylist.go │ ├── arrayqueue/ │ │ └── arrayqqueue.go │ ├── arraystack/ │ │ └── arraystack.go │ ├── avltree/ │ │ └── avltree.go │ ├── binaryheap/ │ │ └── binaryheap.go │ ├── btree/ │ │ └── btree.go │ ├── circularbuffer/ │ │ └── circularbuffer.go │ ├── customcomparator/ │ │ └── customcomparator.go │ ├── doublylinkedlist/ │ │ └── doublylinkedlist.go │ ├── enumerablewithindex/ │ │ └── enumerablewithindex.go │ ├── enumerablewithkey/ │ │ └── enumerablewithkey.go │ ├── hashbidimap/ │ │ └── hashbidimap.go │ ├── hashmap/ │ │ └── hashmap.go │ ├── hashset/ │ │ └── hashset.go │ ├── iteratorwithindex/ │ │ └── iteratorwithindex.go │ ├── iteratorwithkey/ │ │ └── iteratorwithkey.go │ ├── linkedhashmap/ │ │ └── linkedhashmap.go │ ├── linkedhashset/ │ │ └── linkedhashset.go │ ├── linkedlistqueue/ │ │ └── linkedlistqueue.go │ ├── linkedliststack/ │ │ └── linkedliststack.go │ ├── priorityqueue/ │ │ └── priorityqueue.go │ ├── redblacktree/ │ │ └── redblacktree.go │ ├── redblacktreeextended/ │ │ └── redblacktreeextended.go │ ├── serialization/ │ │ └── serialization.go │ ├── singlylinkedlist/ │ │ └── singlylinkedlist.go │ ├── treebidimap/ │ │ └── treebidimap.go │ ├── treemap/ │ │ └── treemap.go │ └── treeset/ │ └── treeset.go ├── go.mod ├── go.sum ├── lists/ │ ├── arraylist/ │ │ ├── arraylist.go │ │ ├── arraylist_test.go │ │ ├── enumerable.go │ │ ├── iterator.go │ │ └── serialization.go │ ├── doublylinkedlist/ │ │ ├── doublylinkedlist.go │ │ ├── doublylinkedlist_test.go │ │ ├── enumerable.go │ │ ├── iterator.go │ │ └── serialization.go │ ├── lists.go │ └── singlylinkedlist/ │ ├── enumerable.go │ ├── iterator.go │ ├── serialization.go │ ├── singlylinkedlist.go │ └── singlylinkedlist_test.go ├── maps/ │ ├── hashbidimap/ │ │ ├── hashbidimap.go │ │ ├── hashbidimap_test.go │ │ └── serialization.go │ ├── hashmap/ │ │ ├── hashmap.go │ │ ├── hashmap_test.go │ │ └── serialization.go │ ├── linkedhashmap/ │ │ ├── enumerable.go │ │ ├── iterator.go │ │ ├── linkedhashmap.go │ │ ├── linkedhashmap_test.go │ │ └── serialization.go │ ├── maps.go │ ├── treebidimap/ │ │ ├── enumerable.go │ │ ├── iterator.go │ │ ├── serialization.go │ │ ├── treebidimap.go │ │ └── treebidimap_test.go │ └── treemap/ │ ├── enumerable.go │ ├── iterator.go │ ├── serialization.go │ ├── treemap.go │ └── treemap_test.go ├── queues/ │ ├── arrayqueue/ │ │ ├── arrayqueue.go │ │ ├── arrayqueue_test.go │ │ ├── iterator.go │ │ └── serialization.go │ ├── circularbuffer/ │ │ ├── circularbuffer.go │ │ ├── circularbuffer_test.go │ │ ├── iterator.go │ │ └── serialization.go │ ├── linkedlistqueue/ │ │ ├── iterator.go │ │ ├── linkedlistqueue.go │ │ ├── linkedlistqueue_test.go │ │ └── serialization.go │ ├── priorityqueue/ │ │ ├── iterator.go │ │ ├── priorityqueue.go │ │ ├── priorityqueue_test.go │ │ └── serialization.go │ └── queues.go ├── sets/ │ ├── hashset/ │ │ ├── hashset.go │ │ ├── hashset_test.go │ │ └── serialization.go │ ├── linkedhashset/ │ │ ├── enumerable.go │ │ ├── iterator.go │ │ ├── linkedhashset.go │ │ ├── linkedhashset_test.go │ │ └── serialization.go │ ├── sets.go │ └── treeset/ │ ├── enumerable.go │ ├── iterator.go │ ├── serialization.go │ ├── treeset.go │ └── treeset_test.go ├── stacks/ │ ├── arraystack/ │ │ ├── arraystack.go │ │ ├── arraystack_test.go │ │ ├── iterator.go │ │ └── serialization.go │ ├── linkedliststack/ │ │ ├── iterator.go │ │ ├── linkedliststack.go │ │ ├── linkedliststack_test.go │ │ └── serialization.go │ └── stacks.go ├── testutils/ │ └── testutils.go ├── trees/ │ ├── avltree/ │ │ ├── avltree.go │ │ ├── avltree_test.go │ │ ├── iterator.go │ │ └── serialization.go │ ├── binaryheap/ │ │ ├── binaryheap.go │ │ ├── binaryheap_test.go │ │ ├── iterator.go │ │ └── serialization.go │ ├── btree/ │ │ ├── btree.go │ │ ├── btree_test.go │ │ ├── iterator.go │ │ └── serialization.go │ ├── redblacktree/ │ │ ├── iterator.go │ │ ├── redblacktree.go │ │ ├── redblacktree_test.go │ │ └── serialization.go │ └── trees.go └── utils/ ├── comparator.go ├── comparator_test.go ├── utils.go └── utils_test.go ================================================ FILE CONTENTS ================================================ ================================================ FILE: .circleci/config.yml ================================================ version: 2.1 jobs: test: parameters: version: type: string default: "1.21" docker: - image: cimg/go:<> environment: TEST_RESULTS: /tmp/test-results working_directory: ~/gods steps: - run: name: Print Go version (go version) command: | go version - checkout - run: 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=coverage.out ./... > /dev/null 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: name: Upload test coverage command: | bash <(curl -s https://codecov.io/bash) - run: name: Lint (golint) command: | go install golang.org/x/lint/golint@latest golint -set_exit_status ./... - run: name: Enforce formatted code (go fmt) command: | ! go fmt ./... 2>&1 | read - run: name: Examine and report suspicious constructs (go vet) command: | go vet -v ./... - run: name: Calculate cyclomatic complexity (gocyclo) command: | go install github.com/fzipp/gocyclo/cmd/gocyclo@latest gocyclo -avg -over 15 ../gods - run: name: Check for unchecked errors (errcheck) 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-results workflows: test: jobs: - test: matrix: parameters: # To test with and without generics (versions prior to 1.18) version: [ "1.21" ] ================================================ FILE: .github/dependabot.yml ================================================ # Ref: https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 updates: - package-ecosystem: "gomod" directory: "/" schedule: interval: "daily" ================================================ FILE: .github/workflows/codeql-analysis.yml ================================================ # 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 ================================================ FILE: .gitignore ================================================ # Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof .idea ================================================ FILE: LICENSE ================================================ 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. ------------------------------------------------------------------------------- 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. ================================================ FILE: README.md ================================================ [![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) [![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) Implementation of various data structures and algorithms in Go. ## Data Structures - [Containers](#containers) - [Lists](#lists) - [ArrayList](#arraylist) - [SinglyLinkedList](#singlylinkedlist) - [DoublyLinkedList](#doublylinkedlist) - [Sets](#sets) - [HashSet](#hashset) - [TreeSet](#treeset) - [LinkedHashSet](#linkedhashset) - [Stacks](#stacks) - [LinkedListStack](#linkedliststack) - [ArrayStack](#arraystack) - [Maps](#maps) - [HashMap](#hashmap) - [TreeMap](#treemap) - [LinkedHashMap](#linkedhashmap) - [HashBidiMap](#hashbidimap) - [TreeBidiMap](#treebidimap) - [Trees](#trees) - [RedBlackTree](#redblacktree) - [AVLTree](#avltree) - [BTree](#btree) - [BinaryHeap](#binaryheap) - [Queues](#queues) - [LinkedListQueue](#linkedlistqueue) - [ArrayQueue](#arrayqueue) - [CircularBuffer](#circularbuffer) - [PriorityQueue](#priorityqueue) - [Functions](#functions) - [Comparator](#comparator) - [Iterator](#iterator) - [IteratorWithIndex](#iteratorwithindex) - [IteratorWithKey](#iteratorwithkey) - [ReverseIteratorWithIndex](#reverseiteratorwithindex) - [ReverseIteratorWithKey](#reverseiteratorwithkey) - [Enumerable](#enumerable) - [EnumerableWithIndex](#enumerablewithindex) - [EnumerableWithKey](#enumerablewithkey) - [Serialization](#serialization) - [JSONSerializer](#jsonserializer) - [JSONDeserializer](#jsondeserializer) - [Sort](#sort) - [Container](#container) - [Appendix](#appendix) ## Containers All data structures implement the container interface with the following methods: ```go type Container interface { Empty() bool Size() int Clear() Values() []interface{} 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** | | :--- |:--------------------------------------| :---: | :---: | :---: | :---: | | [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 | | | [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 | | [Queues](#queues) | | | [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 A list is a data structure that stores values and may have repeated values. Implements [Container](#containers) interface. ```go type List interface { 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{}) Set(index int, value interface{}) containers.Container // Empty() bool // Size() int // Clear() // Values() []interface{} // String() string } ``` #### ArrayList A [list](#lists) backed by a dynamic array that grows and shrinks implicitly. Implements [List](#lists), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main import ( "github.com/emirpasic/gods/lists/arraylist" "github.com/emirpasic/gods/utils" ) func main() { list := arraylist.New() list.Add("a") // ["a"] list.Add("c", "b") // ["a","c","b"] list.Sort(utils.StringComparator) // ["a","b","c"] _, _ = list.Get(0) // "a",true _, _ = list.Get(100) // nil,false _ = list.Contains("a", "b", "c") // true _ = list.Contains("a", "b", "c", "d") // false list.Swap(0, 1) // ["b","a",c"] list.Remove(2) // ["b","a"] list.Remove(1) // ["b"] list.Remove(0) // [] list.Remove(0) // [] (ignored) _ = list.Empty() // true _ = list.Size() // 0 list.Add("a") // ["a"] list.Clear() // [] list.Insert(0, "b") // ["b"] list.Insert(0, "a") // ["a","b"] } ``` #### SinglyLinkedList A [list](#lists) where each element points to the next element in the list. Implements [List](#lists), [IteratorWithIndex](#iteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main import ( sll "github.com/emirpasic/gods/lists/singlylinkedlist" "github.com/emirpasic/gods/utils" ) func main() { list := sll.New() list.Add("a") // ["a"] list.Add("c", "b") // ["a","c","b"] list.Sort(utils.StringComparator) // ["a","b","c"] _, _ = list.Get(0) // "a",true _, _ = list.Get(100) // nil,false _ = list.Contains("a", "b", "c") // true _ = list.Contains("a", "b", "c", "d") // false list.Swap(0, 1) // ["b","a",c"] list.Remove(2) // ["b","a"] list.Remove(1) // ["b"] list.Remove(0) // [] list.Remove(0) // [] (ignored) _ = list.Empty() // true _ = list.Size() // 0 list.Add("a") // ["a"] list.Clear() // [] list.Insert(0, "b") // ["b"] list.Insert(0, "a") // ["a","b"] } ``` #### DoublyLinkedList A [list](#lists) where each element points to the next and previous elements in the list. Implements [List](#lists), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main import ( dll "github.com/emirpasic/gods/lists/doublylinkedlist" "github.com/emirpasic/gods/utils" ) func main() { list := dll.New() list.Add("a") // ["a"] list.Add("c", "b") // ["a","c","b"] list.Sort(utils.StringComparator) // ["a","b","c"] _, _ = list.Get(0) // "a",true _, _ = list.Get(100) // nil,false _ = list.Contains("a", "b", "c") // true _ = list.Contains("a", "b", "c", "d") // false list.Swap(0, 1) // ["b","a",c"] list.Remove(2) // ["b","a"] list.Remove(1) // ["b"] list.Remove(0) // [] list.Remove(0) // [] (ignored) _ = list.Empty() // true _ = list.Size() // 0 list.Add("a") // ["a"] list.Clear() // [] list.Insert(0, "b") // ["b"] list.Insert(0, "a") // ["a","b"] } ``` ### 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 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 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 // Clear() // Values() []interface{} // String() string } ``` #### HashSet 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), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```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 A [set](#sets) backed by a [red-black tree](#redblacktree) to keep the elements ordered with respect to the [comparator](#comparator). Implements [Set](#sets), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```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 } ``` #### 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), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [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. Implements [Container](#containers) interface. ```go type Stack interface { Push(value interface{}) Pop() (value interface{}, ok bool) Peek() (value interface{}, ok bool) containers.Container // Empty() bool // Size() int // Clear() // Values() []interface{} // String() string } ``` #### LinkedListStack A [stack](#stacks) based on a [linked list](#singlylinkedlist). Implements [Stack](#stacks), [IteratorWithIndex](#iteratorwithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main import lls "github.com/emirpasic/gods/stacks/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 } ``` #### ArrayStack A [stack](#stacks) based on a [array list](#arraylist). Implements [Stack](#stacks), [IteratorWithIndex](#iteratorwithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main import "github.com/emirpasic/gods/stacks/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 } ``` ### 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. Implements [Container](#containers) interface. ```go type Map interface { Put(key interface{}, value interface{}) Get(key interface{}) (value interface{}, found bool) Remove(key interface{}) Keys() []interface{} containers.Container // Empty() bool // Size() int // Clear() // Values() []interface{} // String() string } ``` 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. Implements [Map](#maps), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main 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(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 } ``` #### TreeMap A [map](#maps) based on [red-black tree](#redblacktree). Keys are ordered with respect to the [comparator](#comparator). Implements [Map](#maps), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main import "github.com/emirpasic/gods/maps/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 // Other: m.Min() // Returns the minimum key and its value from map. m.Max() // Returns the maximum key and its value from map. } ``` #### 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), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [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. Implements [BidiMap](#maps), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```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 } ``` #### 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), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) 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. Implements [Container](#containers) interface. ```go type Tree interface { containers.Container // Empty() bool // Size() int // Clear() // Values() []interface{} // String() string } ``` #### RedBlackTree 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) Implements [Tree](#trees), [ReverseIteratorWithKey](#reverseiteratorwithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.

```go package main import ( "fmt" rbt "github.com/emirpasic/gods/trees/redblacktree" ) func main() { 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) 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 _ = 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) // // RedBlackTree // │ ┌── 6 // │ ┌── 5 // └── 4 // │ ┌── 3 // └── 1 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 } ``` 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 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), [ReverseIteratorWithKey](#reverseiteratorwithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) 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. 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), [ReverseIteratorWithKey](#reverseiteratorwithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) 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, 7->g (in order) fmt.Println(tree) // BTree // 1 // 3 // 4 // 5 // 6 // 7 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: - Shape property: 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) Implements [Tree](#trees), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.

```go package main import ( "github.com/emirpasic/gods/trees/binaryheap" "github.com/emirpasic/gods/utils" ) 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 // Max-heap inverseIntComparator := func(a, b interface{}) int { return -utils.IntComparator(a, b) } heap = binaryheap.NewWith(inverseIntComparator) // empty (min-heap) heap.Push(2, 3, 1) // 3, 2, 1 (bulk optimized) heap.Values() // 3, 2, 1 } ``` ### 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 } ``` #### 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 } ``` #### 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. ### Comparator 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: Return values (int): ```go negative , if a < b zero , if a == b positive , if a > b ``` Comparator signature: ```go type Comparator func(a, b interface{}) int ``` All common comparators for builtin types are included in the library: ```go func StringComparator(a, b interface{}) int func IntComparator(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 func TimeComparator(a, b interface{}) int ``` Writing custom comparators is easy: ```go package main import ( "fmt" "github.com/emirpasic/gods/sets/treeset" ) type User struct { id int name string } // Custom comparator (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) switch { case c1.id > c2.id: return 1 case c1.id < c2.id: return -1 default: return 0 } } func main() { 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} } ``` ### 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. 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. Typical usage: ```go it := list.Iterator() for it.Next() { index, value := it.Index(), it.Value() ... } ``` Other usages: ```go if it.First() { firstIndex, firstValue := it.Index(), it.Value() ... } ``` ```go 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. Typical usage: ```go 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(); { ... } ``` 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. Typical usage of iteration in reverse: ```go it := list.Iterator() for it.End(); it.Prev(); { index, value := it.Index(), it.Value() ... } ``` Other usages: ```go if it.Last() { lastIndex, lastValue := it.Index(), it.Value() ... } ``` 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. Typical usage of iteration in reverse: ```go 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() ... } ``` ```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. #### 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. ```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. ```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. ```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. ```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{})} ``` **Example:** ```go package main import ( "fmt" "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) printSet("Initial", set) // [ 2 3 4 5 6 7 8 ] even := set.Select(func(index int, value interface{}) bool { return value.(int)%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 }) 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) }) printSet("Numbers squared", square) // [ 4 9 16 25 36 49 64 ] bigger := set.Any(func(index int, value interface{}) bool { return value.(int) > 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 }) 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) }) printSet("Chaining", evenNumbersSquared) // [ 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. ```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 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. ```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. ```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. ```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{}) ``` **Example:** ```go package main import ( "fmt" "github.com/emirpasic/gods/maps/treemap" ) func printMap(txt string, m *treemap.Map) { fmt.Print(txt, " { ") m.Each(func(key interface{}, value interface{}) { fmt.Print(key, ":", value, " ") }) 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) 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 }) 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 }) if foundKey != nil { 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) }) 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 }) 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 }) 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) }) printMap("Chaining", evenNumbersSquared) // { b:4 d:16 f:36 } } ``` ### 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 ( "encoding/json" "fmt" "github.com/emirpasic/gods/maps/hashmap" ) func main() { m := hashmap.New() m.Put("a", "1") m.Put("b", "2") m.Put("c", "3") bytes, err := json.Marshal(m) // Same as "m.ToJSON(m)" if err != nil { fmt.Println(err) } 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" ) func main() { list := arraylist.New() list.Add("a", "b", "c") bytes, err := json.Marshal(list) // Same as "list.ToJSON(list)" if err != nil { fmt.Println(err) } fmt.Println(string(bytes)) // ["a","b","c"] } ``` #### JSONDeserializer 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" ) func main() { hm := hashmap.New() bytes := []byte(`{"a":"1","b":"2"}`) err := json.Unmarshal(bytes, &hm) // Same as "hm.FromJSON(bytes)" if err != nil { fmt.Println(err) } fmt.Println(hm) // HashMap map[b:2 a:1] } ``` Typical usage for value-only structures: ```go package main import ( "encoding/json" "fmt" "github.com/emirpasic/gods/lists/arraylist" ) func main() { list := arraylist.New() bytes := []byte(`["a","b"]`) err := json.Unmarshal(bytes, &list) // Same as "list.FromJSON(bytes)" if err != nil { fmt.Println(err) } fmt.Println(list) // ArrayList ["a","b"] } ``` ### Sort Sort is a general purpose sort function. 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 import "github.com/emirpasic/gods/utils" 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"] } ``` ### Container Container specific operations: ```go // 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{} ``` 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 ### Motivation Collections and data structures found in other languages: Java Collections, C++ Standard Template Library (STL) containers, Qt Containers, Ruby Enumerable etc. ### Goals **Fast algorithms**: - Based on decades of knowledge and experiences of other libraries mentioned above. **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-structured library with minimalistic set of atomic operations from which more complex operations can be crafted. **Stable library**: - Only additions are permitted keeping the library backward compatible. **Solid documentation and examples**: - Learning by example. **Production ready**: - 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. ### Testing and Benchmarking This takes a while, so test within sub-packages: `go test -run=NO_TEST -bench . -benchmem -benchtime 1s ./...`

### Contributing 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 branch or ask to become a contributor. Coding style: ```shell # Install tooling and set path: 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 ./... && go test -v ./... && golint -set_exit_status ./... && ! go fmt ./... 2>&1 | read && go vet -v ./... && gocyclo -avg -over 15 ../gods && errcheck ./... ``` ### 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. ================================================ FILE: containers/containers.go ================================================ // 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. // // 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. // // Serialization provides serializers (marshalers) and deserializers (unmarshalers). package containers import ( "cmp" "slices" "github.com/emirpasic/gods/v2/utils" ) // Container is base interface that all data structures implement. type Container[T any] interface { Empty() bool Size() int Clear() 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[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 } slices.SortFunc(values, comparator) return values } ================================================ FILE: containers/containers_test.go ================================================ // 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 package containers import ( "cmp" "fmt" "strings" "testing" ) // For testing purposes type ContainerTest[T any] struct { values []T } func (container ContainerTest[T]) Empty() bool { return len(container.values) == 0 } func (container ContainerTest[T]) Size() int { return len(container.values) } func (container ContainerTest[T]) Clear() { container.values = []T{} } func (container ContainerTest[T]) Values() []T { return container.values } func (container ContainerTest[T]) 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[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] > values[i] { t.Errorf("Not sorted!") } } } 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].i > values[i].i { t.Errorf("Not sorted!") } } } ================================================ FILE: containers/enumerable.go ================================================ // 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 // EnumerableWithIndex provides functions for ordered containers whose values can be fetched by an index. 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 T)) // Map 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 // Select returns a new container containing all elements for which the given function returns a true value. // 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(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 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 T) bool) (int, T) } // EnumerableWithKey provides functions for ordered containers whose values whose elements are key/value pairs. 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 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. // 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(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(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 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 K, value V) bool) (K, V) } ================================================ FILE: containers/iterator.go ================================================ // 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 // IteratorWithIndex is stateful iterator for ordered containers whose values can be fetched by an index. 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. // Modifies the state of the iterator. Next() bool // Value returns the current element's value. // Does not modify the state of the iterator. Value() T // Index returns the current element's index. // Does not modify the state of the iterator. Index() int // Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. 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. 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 T) bool) bool } // IteratorWithKey is a stateful iterator for ordered containers whose elements are key value pairs. 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. // Modifies the state of the iterator. Next() bool // Value returns the current element's value. // Does not modify the state of the iterator. Value() V // Key returns the current element's key. // Does not modify the state of the iterator. Key() K // Begin resets the iterator to its initial state (one-before-first) // Call Next() to fetch the first element if any. 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. 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 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 // // 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[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. 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 // 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 T) bool) bool 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 // // Last() function to move the iterator to the last element. 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. 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 // 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 K, value V) bool) bool IteratorWithKey[K, V] } ================================================ FILE: containers/serialization.go ================================================ // 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) // 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 } ================================================ FILE: examples/README.md ================================================ # 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) ================================================ FILE: examples/arraylist/arraylist.go ================================================ // 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 ( "cmp" "github.com/emirpasic/gods/v2/lists/arraylist" ) // ArrayListExample to demonstrate basic usage of ArrayList func main() { list := arraylist.New[string]() list.Add("a") // ["a"] list.Add("c", "b") // ["a","c","b"] list.Sort(cmp.Compare[string]) // ["a","b","c"] _, _ = list.Get(0) // "a",true _, _ = list.Get(100) // nil,false _ = list.Contains("a", "b", "c") // true _ = list.Contains("a", "b", "c", "d") // false list.Swap(0, 1) // ["b","a",c"] list.Remove(2) // ["b","a"] list.Remove(1) // ["b"] list.Remove(0) // [] list.Remove(0) // [] (ignored) _ = list.Empty() // true _ = list.Size() // 0 list.Add("a") // ["a"] list.Clear() // [] } ================================================ FILE: examples/arrayqueue/arrayqqueue.go ================================================ // 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/v2/queues/arrayqueue" // ArrayQueueExample to demonstrate basic usage of ArrayQueue func main() { queue := aq.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 } ================================================ FILE: examples/arraystack/arraystack.go ================================================ // 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/v2/stacks/arraystack" // ArrayStackExample to demonstrate basic usage of ArrayStack func main() { 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 } ================================================ FILE: examples/avltree/avltree.go ================================================ // 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 ( "fmt" avl "github.com/emirpasic/gods/v2/trees/avltree" ) // AVLTreeExample to demonstrate basic usage of AVLTree func main() { 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) 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 } ================================================ FILE: examples/binaryheap/binaryheap.go ================================================ // 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 ( "cmp" "github.com/emirpasic/gods/v2/trees/binaryheap" ) // BinaryHeapExample to demonstrate basic usage of BinaryHeap func main() { // Min-heap 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 int) int { return -cmp.Compare(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.Values() // 3, 2, 1 } ================================================ FILE: examples/btree/btree.go ================================================ // 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 ( "fmt" "github.com/emirpasic/gods/v2/trees/btree" ) // BTreeExample to demonstrate basic usage of BTree func main() { 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) 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 } ================================================ FILE: examples/circularbuffer/circularbuffer.go ================================================ // 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/v2/queues/circularbuffer" // CircularBufferExample to demonstrate basic usage of CircularBuffer func main() { 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 } ================================================ FILE: examples/customcomparator/customcomparator.go ================================================ // 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 ( "fmt" "github.com/emirpasic/gods/v2/sets/treeset" ) // User model (id and name) type User struct { id int name string } // Comparator function (sort by IDs) func byID(a, b User) int { switch { case a.id > b.id: return 1 case a.id < b.id: return -1 default: return 0 } } // CustomComparatorExample to demonstrate basic usage of CustomComparator func main() { 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} } ================================================ FILE: examples/doublylinkedlist/doublylinkedlist.go ================================================ // 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 ( "cmp" dll "github.com/emirpasic/gods/v2/lists/doublylinkedlist" ) // DoublyLinkedListExample to demonstrate basic usage of DoublyLinkedList func main() { list := dll.New[string]() list.Add("a") // ["a"] list.Append("b") // ["a","b"] (same as Add()) list.Prepend("c") // ["c","a","b"] list.Sort(cmp.Compare[string]) // ["a","b","c"] _, _ = list.Get(0) // "a",true _, _ = list.Get(100) // nil,false _ = list.Contains("a", "b", "c") // true _ = list.Contains("a", "b", "c", "d") // false list.Remove(2) // ["a","b"] list.Remove(1) // ["a"] list.Remove(0) // [] list.Remove(0) // [] (ignored) _ = list.Empty() // true _ = list.Size() // 0 list.Add("a") // ["a"] list.Clear() // [] } ================================================ FILE: examples/enumerablewithindex/enumerablewithindex.go ================================================ // 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 ( "fmt" "github.com/emirpasic/gods/v2/sets/treeset" ) func printSet(txt string, set *treeset.Set[int]) { fmt.Print(txt, "[ ") set.Each(func(index int, value int) { fmt.Print(value, " ") }) fmt.Println("]") } // EnumerableWithIndexExample to demonstrate basic usage of EnumerableWithIndex func main() { 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 int) bool { return value%2 == 0 }) printSet("Even numbers", even) // [ 2 4 6 8 ] 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 int) int { return value * value }) printSet("Numbers squared", square) // [ 4 9 16 25 36 49 64 ] 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 int) bool { return value > 0 }) fmt.Println("All numbers are positive is", positive) // true 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 ] } ================================================ FILE: examples/enumerablewithkey/enumerablewithkey.go ================================================ // 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 ( "fmt" "github.com/emirpasic/gods/v2/maps/treemap" ) func printMap(txt string, m *treemap.Map[string, int]) { fmt.Print(txt, " { ") m.Each(func(key string, value int) { fmt.Print(key, ":", value, " ") }) fmt.Println("}") } // EunumerableWithKeyExample to demonstrate basic usage of EunumerableWithKey func main() { m := treemap.New[string, int]() 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) printMap("Initial", m) // { a:1 b:2 c:3 d:4 e:5 f:6 g:7 } 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 string, value int) bool { return value%2 == 0 && value%3 == 0 }) 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 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 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 string, value int) bool { return value > 0 }) fmt.Println("All map's elements have positive values is", positive) // true 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 } } ================================================ FILE: examples/hashbidimap/hashbidimap.go ================================================ // 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/v2/maps/hashbidimap" // HashBidiMapExample to demonstrate basic usage of HashMap func main() { 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 } ================================================ FILE: examples/hashmap/hashmap.go ================================================ // 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/v2/maps/hashmap" // HashMapExample to demonstrate basic usage of HashMap func main() { 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 } ================================================ FILE: examples/hashset/hashset.go ================================================ // 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/v2/sets/hashset" // HashSetExample to demonstrate basic usage of HashSet func main() { 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 } ================================================ FILE: examples/iteratorwithindex/iteratorwithindex.go ================================================ // 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 ( "fmt" "strings" "github.com/emirpasic/gods/v2/sets/treeset" ) // IteratorWithIndexExample to demonstrate basic usage of IteratorWithIndex func main() { set := treeset.New[string]() set.Add("a", "b", "c") it := set.Iterator() fmt.Print("\nForward iteration\n") for it.Next() { index, value := it.Index(), it.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] } fmt.Print("\nBackward iteration (again)\n") for it.End(); it.Prev(); { index, value := it.Index(), it.Value() 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 } // Seek element starting with "b" seek := func(index int, value string) bool { return strings.HasSuffix(value, "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" */ } ================================================ FILE: examples/iteratorwithkey/iteratorwithkey.go ================================================ // 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 ( "fmt" "strings" "github.com/emirpasic/gods/v2/maps/treemap" ) // IteratorWithKeyExample to demonstrate basic usage of IteratorWithKey func main() { m := treemap.New[int, string]() m.Put(0, "a") m.Put(1, "b") m.Put(2, "c") 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: 2 fmt.Print("\nLast value: ", it.Value()) // Last value: c } // Seek key-value pair whose value starts with "b" seek := func(key int, value string) bool { return strings.HasSuffix(value, "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" */ } ================================================ FILE: examples/linkedhashmap/linkedhashmap.go ================================================ // 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/v2/maps/linkedhashmap" // LinkedHashMapExample to demonstrate basic usage of LinkedHashMapExample func main() { 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 } ================================================ FILE: examples/linkedhashset/linkedhashset.go ================================================ // 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/v2/sets/linkedhashset" // LinkedHashSetExample to demonstrate basic usage of LinkedHashSet func main() { 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 } ================================================ FILE: examples/linkedlistqueue/linkedlistqueue.go ================================================ // 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/v2/queues/linkedlistqueue" // LinkedListQueueExample to demonstrate basic usage of LinkedListQueue func main() { 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 } ================================================ FILE: examples/linkedliststack/linkedliststack.go ================================================ // 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 lls "github.com/emirpasic/gods/v2/stacks/linkedliststack" // LinkedListStackExample to demonstrate basic usage of LinkedListStack func main() { 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 } ================================================ FILE: examples/priorityqueue/priorityqueue.go ================================================ // 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 ( "cmp" pq "github.com/emirpasic/gods/v2/queues/priorityqueue" ) // 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 Element) int { return -cmp.Compare(a.priority, b.priority) // "-" 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 } ================================================ FILE: examples/redblacktree/redblacktree.go ================================================ // 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 ( "fmt" rbt "github.com/emirpasic/gods/v2/trees/redblacktree" ) // RedBlackTreeExample to demonstrate basic usage of RedBlackTree func main() { 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) 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 _ = 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) // // RedBlackTree // │ ┌── 6 // │ ┌── 5 // └── 4 // │ ┌── 3 // └── 1 tree.Clear() // empty tree.Empty() // true tree.Size() // 0 } ================================================ FILE: examples/redblacktreeextended/redblacktreeextended.go ================================================ // 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 redblacktreeextended import ( "fmt" rbt "github.com/emirpasic/gods/v2/trees/redblacktree" ) // RedBlackTreeExtended to demonstrate how to extend a RedBlackTree to include new functions type RedBlackTreeExtended[K comparable, V any] struct { *rbt.Tree[K, V] } // GetMin gets the min value and flag if found func (tree *RedBlackTreeExtended[K, V]) GetMin() (value V, found bool) { node, found := tree.getMinFromNode(tree.Root) if found { return node.Value, found } return value, false } // GetMax gets the max value and flag if found func (tree *RedBlackTreeExtended[K, V]) GetMax() (value V, found bool) { node, found := tree.getMaxFromNode(tree.Root) if found { return node.Value, found } return value, false } // RemoveMin removes the min value and flag if found 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 value, false } // RemoveMax removes the max value and flag if found 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 value, false } func (tree *RedBlackTreeExtended[K, V]) getMinFromNode(node *rbt.Node[K, V]) (foundNode *rbt.Node[K, V], found bool) { if node == nil { return nil, false } if node.Left == nil { return node, true } return tree.getMinFromNode(node.Left) } func (tree *RedBlackTreeExtended[K, V]) getMaxFromNode(node *rbt.Node[K, V]) (foundNode *rbt.Node[K, V], found bool) { if node == nil { return nil, false } if node.Right == nil { return node, true } return tree.getMaxFromNode(node.Right) } func print(tree *RedBlackTreeExtended[int, string]) { 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) } // RedBlackTreeExtendedExample main method on how to use the custom red-black tree above func main() { 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) 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 } ================================================ FILE: examples/serialization/serialization.go ================================================ package serialization import ( "fmt" "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[string]() 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[string, string]() 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"} } ================================================ FILE: examples/singlylinkedlist/singlylinkedlist.go ================================================ // 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 ( "cmp" sll "github.com/emirpasic/gods/v2/lists/singlylinkedlist" ) // SinglyLinkedListExample to demonstrate basic usage of SinglyLinkedList func main() { list := sll.New[string]() list.Add("a") // ["a"] list.Append("b") // ["a","b"] (same as Add()) list.Prepend("c") // ["c","a","b"] list.Sort(cmp.Compare[string]) // ["a","b","c"] _, _ = list.Get(0) // "a",true _, _ = list.Get(100) // nil,false _ = list.Contains("a", "b", "c") // true _ = list.Contains("a", "b", "c", "d") // false list.Remove(2) // ["a","b"] list.Remove(1) // ["a"] list.Remove(0) // [] list.Remove(0) // [] (ignored) _ = list.Empty() // true _ = list.Size() // 0 list.Add("a") // ["a"] list.Clear() // [] } ================================================ FILE: examples/treebidimap/treebidimap.go ================================================ // 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/v2/maps/treebidimap" ) // TreeBidiMapExample to demonstrate basic usage of TreeBidiMap func main() { 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) 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 } ================================================ FILE: examples/treemap/treemap.go ================================================ // 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/v2/maps/treemap" // TreeMapExample to demonstrate basic usage of TreeMap func main() { 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 } ================================================ FILE: examples/treeset/treeset.go ================================================ // 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/v2/sets/treeset" // TreeSetExample to demonstrate basic usage of TreeSet func main() { 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 } ================================================ FILE: go.mod ================================================ module github.com/emirpasic/gods/v2 go 1.21 ================================================ FILE: go.sum ================================================ github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= ================================================ FILE: lists/arraylist/arraylist.go ================================================ // 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. // // Structure is not thread safe. // // Reference: https://en.wikipedia.org/wiki/List_%28abstract_data_type%29 package arraylist import ( "fmt" "slices" "strings" "github.com/emirpasic/gods/v2/lists" "github.com/emirpasic/gods/v2/utils" ) // Assert List implementation var _ lists.List[int] = (*List[int])(nil) // List holds the elements in a slice type List[T comparable] struct { elements []T } const ( growthFactor = float32(2.0) // growth by 100% shrinkFactor = float32(0.25) // shrink when size is 25% of capacity (0 means never shrink) ) // New instantiates a new list and adds the passed values, if any, to the list func New[T comparable](values ...T) *List[T] { list := &List[T]{} if len(values) > 0 { list.Add(values...) } return list } // 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 i := range values { list.elements[l+i] = values[i] } } // 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[T]) Get(index int) (T, bool) { if !list.withinRange(index) { 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[T]) Remove(index int) { if !list.withinRange(index) { return } list.elements = slices.Delete(list.elements, index, index+1) list.shrink() } // 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. func (list *List[T]) Contains(values ...T) bool { for _, searchValue := range values { if !slices.Contains(list.elements, searchValue) { return false } } return true } // Values returns all elements in the list. func (list *List[T]) Values() []T { return slices.Clone(list.elements) } // IndexOf returns index of provided element func (list *List[T]) IndexOf(value T) int { return slices.Index(list.elements, value) } // Empty returns true if list does not contain any elements. func (list *List[T]) Empty() bool { return len(list.elements) == 0 } // Size returns number of elements within the list. func (list *List[T]) Size() int { return len(list.elements) } // Clear removes all elements from the list. func (list *List[T]) Clear() { clear(list.elements[:cap(list.elements)]) list.elements = list.elements[:0] } // Sort sorts values (in-place) using. func (list *List[T]) Sort(comparator utils.Comparator[T]) { if len(list.elements) < 2 { return } slices.SortFunc(list.elements, comparator) } // Swap swaps the two values at the specified positions. 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] } } // 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[T]) Insert(index int, values ...T) { if !list.withinRange(index) { // Append if index == len(list.elements) { list.Add(values...) } return } l := len(list.elements) list.growBy(len(values)) list.elements = slices.Insert(list.elements[:l], 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[T]) Set(index int, value T) { if !list.withinRange(index) { // Append if index == len(list.elements) { list.Add(value) } return } list.elements[index] = value } // String returns a string representation of container func (list *List[T]) String() string { str := "ArrayList\n" values := make([]string, 0, len(list.elements)) for _, value := range list.elements { values = append(values, fmt.Sprintf("%v", value)) } str += strings.Join(values, ", ") return str } // Check that the index is within bounds of the list func (list *List[T]) withinRange(index int) bool { return index >= 0 && index < len(list.elements) } func (list *List[T]) resize(len, cap int) { newElements := make([]T, len, 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[T]) growBy(n int) { // When capacity is reached, grow by a factor of growthFactor and add number of elements currentCapacity := cap(list.elements) if newLength := len(list.elements) + n; newLength >= currentCapacity { newCapacity := int(growthFactor * float32(currentCapacity+n)) list.resize(newLength, newCapacity) } else { list.elements = list.elements[:newLength] } } // Shrink the array if necessary, i.e. when size is shrinkFactor percent of current capacity func (list *List[T]) shrink() { if shrinkFactor == 0.0 { return } // Shrink when size is at shrinkFactor * capacity currentCapacity := cap(list.elements) if len(list.elements) <= int(float32(currentCapacity)*shrinkFactor) { list.resize(len(list.elements), len(list.elements)) } } ================================================ FILE: lists/arraylist/arraylist_test.go ================================================ // 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 ( "cmp" "encoding/json" "slices" "strings" "testing" ) func TestListNew(t *testing.T) { list1 := New[int]() if actualValue := list1.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } list2 := New[int](1, 2) 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 != 2 || !ok { t.Errorf("Got %v expected %v", actualValue, 2) } if actualValue, ok := list2.Get(2); actualValue != 0 || ok { t.Errorf("Got %v expected %v", actualValue, 0) } } func TestListAdd(t *testing.T) { list := New[string]() 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") } } func TestListIndexOf(t *testing.T) { list := New[string]() 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[string]() list.Add("a") list.Add("b", "c") list.Remove(2) if actualValue, ok := list.Get(2); actualValue != "" || ok { t.Errorf("Got %v expected %v", actualValue, "") } 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[string]() list.Add("a") list.Add("b", "c") if actualValue, ok := list.Get(0); actualValue != "a" || !ok { t.Errorf("Got %v expected %v", actualValue, "a") } 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 != "" || ok { t.Errorf("Got %v expected %v", actualValue, "") } 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[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, "b") } } func TestListSort(t *testing.T) { list := New[string]() list.Sort(cmp.Compare[string]) list.Add("e", "f", "g", "a", "b", "c", "d") list.Sort(cmp.Compare[string]) for i := 1; i < list.Size(); i++ { a, _ := list.Get(i - 1) b, _ := list.Get(i) if a > b { t.Errorf("Not sorted! %s > %s", a, b) } } } func TestListClear(t *testing.T) { list := New[string]() 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) } } func TestListContains(t *testing.T) { 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) } 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 := list.Contains("a", "b", "c"); actualValue != false { t.Errorf("Got %v expected %v", actualValue, false) } } func TestListValues(t *testing.T) { list := New[string]() list.Add("a") list.Add("b", "c") 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[string]() 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 := strings.Join(list.Values(), ""), "abcd"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } func TestListSet(t *testing.T) { list := New[string]() 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 := 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[string]() list.Add("a", "b", "c") list.Each(func(index int, value string) { 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") } }) } func TestListMap(t *testing.T) { list := New[string]() list.Add("a", "b", "c") 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") } 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) } } func TestListSelect(t *testing.T) { list := New[string]() list.Add("a", "b", "c") 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") } 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) } } func TestListAny(t *testing.T) { list := New[string]() list.Add("a", "b", "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 string) bool { return value == "x" }) if any != false { t.Errorf("Got %v expected %v", any, false) } } func TestListAll(t *testing.T) { list := New[string]() list.Add("a", "b", "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 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[string]() list.Add("a", "b", "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 string) bool { return value == "x" }) 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[string]() list.Add("a", "b", "c") 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) } 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") } } func TestListIteratorNextOnEmpty(t *testing.T) { list := New[string]() it := list.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty list") } } func TestListIteratorNext(t *testing.T) { list := New[string]() list.Add("a", "b", "c") it := list.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 := count, 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } func TestListIteratorPrevOnEmpty(t *testing.T) { list := New[string]() it := list.Iterator() for it.Prev() { t.Errorf("Shouldn't iterate on empty list") } } func TestListIteratorPrev(t *testing.T) { list := New[string]() 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 TestListIteratorBegin(t *testing.T) { list := New[string]() it := list.Iterator() it.Begin() list.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 TestListIteratorEnd(t *testing.T) { list := New[string]() 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[string]() 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[string]() 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 TestListIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" seek := func(index int, value string) bool { return strings.HasSuffix(value, "b") } // NextTo (empty) { list := New[string]() it := list.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") } } // NextTo (not found) { list := New[string]() list.Add("xx", "yy") it := list.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") } } // NextTo (found) { 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 != "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 != "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 string) bool { return strings.HasSuffix(value, "b") } // PrevTo (empty) { list := New[string]() it := list.Iterator() it.End() for it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty list") } } // PrevTo (not found) { list := New[string]() 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[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 != "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 != "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[string]() list.Add("a", "b", "c") var err error assert := func() { 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 { t.Errorf("Got %v expected %v", actualValue, expectedValue) } if err != nil { t.Errorf("Got error %v", err) } } assert() bytes, err := list.ToJSON() assert() err = list.FromJSON(bytes) assert() bytes, err = json.Marshal([]any{"a", "b", "c", list}) if err != nil { t.Errorf("Got error %v", err) } 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[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[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { list.Get(n) } } } 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) } } } 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) } } } func BenchmarkArrayListGet100(b *testing.B) { b.StopTimer() size := 100 list := New[int]() 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[int]() 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[int]() 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[int]() 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[int]() b.StartTimer() benchmarkAdd(b, list, size) } func BenchmarkArrayListAdd1000(b *testing.B) { b.StopTimer() size := 1000 list := New[int]() 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[int]() 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[int]() 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[int]() 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[int]() 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[int]() 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[int]() for n := 0; n < size; n++ { list.Add(n) } b.StartTimer() benchmarkRemove(b, list, size) } ================================================ FILE: lists/arraylist/enumerable.go ================================================ // 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 "github.com/emirpasic/gods/v2/containers" // Assert Enumerable implementation 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[T]) Each(f func(index int, value T)) { 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[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())) } return newList } // Select returns a new container containing all elements for which the given function returns a true value. 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()) { 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[T]) Any(f func(index int, value T) 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[T]) All(f func(index int, value T) 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[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() } } var t T return -1, t } ================================================ FILE: lists/arraylist/iterator.go ================================================ // 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 "github.com/emirpasic/gods/v2/containers" // Assert Iterator implementation var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator holding the iterator's state 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[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[T]) 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[T]) 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[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[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[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[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[T]) 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[T]) 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[T]) NextTo(f func(index int, value T) 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[T]) PrevTo(f func(index int, value T) bool) bool { for iterator.Prev() { index, value := iterator.Index(), iterator.Value() if f(index, value) { return true } } return false } ================================================ FILE: lists/arraylist/serialization.go ================================================ // 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/v2/containers" ) // Assert Serialization implementation var _ containers.JSONSerializer = (*List[int])(nil) 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) } // FromJSON populates list's elements from the input JSON representation. func (list *List[T]) FromJSON(data []byte) error { err := json.Unmarshal(data, &list.elements) return err } // UnmarshalJSON @implements json.Unmarshaler func (list *List[T]) UnmarshalJSON(bytes []byte) error { return list.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (list *List[T]) MarshalJSON() ([]byte, error) { return list.ToJSON() } ================================================ FILE: lists/doublylinkedlist/doublylinkedlist.go ================================================ // 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. // // Structure is not thread safe. // // Reference: https://en.wikipedia.org/wiki/List_%28abstract_data_type%29 package doublylinkedlist import ( "fmt" "slices" "strings" "github.com/emirpasic/gods/v2/lists" "github.com/emirpasic/gods/v2/utils" ) // Assert List implementation var _ lists.List[any] = (*List[any])(nil) // List holds the elements, where each element points to the next and previous element type List[T comparable] struct { first *element[T] last *element[T] size int } 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[T comparable](values ...T) *List[T] { list := &List[T]{} if len(values) > 0 { list.Add(values...) } return list } // Add appends a value (one or more) at the end of the list (same as Append()) func (list *List[T]) Add(values ...T) { for _, value := range values { newElement := &element[T]{value: value, prev: list.last} if list.size == 0 { list.first = newElement list.last = newElement } else { list.last.next = newElement list.last = newElement } list.size++ } } // Append appends a value (one or more) at the end of the list (same as Add()) func (list *List[T]) Append(values ...T) { list.Add(values...) } // Prepend prepends a values (or more) 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[T]{value: values[v], next: list.first} if list.size == 0 { list.first = newElement list.last = newElement } else { list.first.prev = newElement list.first = newElement } list.size++ } } // 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[T]) Get(index int) (T, bool) { if !list.withinRange(index) { var t T return t, false } // 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 { } return element.value, true } element := list.first for e := 0; e != index; e, element = e+1, element.next { } return element.value, true } // Remove removes the element at the given index from the list. func (list *List[T]) Remove(index int) { if !list.withinRange(index) { return } if list.size == 1 { list.Clear() return } var element *element[T] // 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 { } } else { element = list.first for e := 0; e != index; e, element = e+1, element.next { } } if element == list.first { list.first = element.next } if element == list.last { list.last = element.prev } if element.prev != nil { element.prev.next = element.next } if element.next != nil { element.next.prev = element.prev } element = nil list.size-- } // 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. func (list *List[T]) Contains(values ...T) bool { if len(values) == 0 { return true } if list.size == 0 { return false } for _, value := range values { found := false for element := list.first; element != nil; element = element.next { if element.value == value { found = true break } } if !found { return false } } return true } // Values returns all elements in the list. 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[T]) IndexOf(value T) 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[T]) Empty() bool { return list.size == 0 } // Size returns number of elements within the list. func (list *List[T]) Size() int { return list.size } // Clear removes all elements from the list. func (list *List[T]) Clear() { list.size = 0 list.first = nil list.last = nil } // Sort sorts values (in-place) using a Comparator. func (list *List[T]) Sort(comparator utils.Comparator[T]) { if list.size < 2 { return } values := list.Values() slices.SortFunc(values, comparator) list.Clear() list.Add(values...) } // Swap swaps values of two elements at the given indices. func (list *List[T]) Swap(i, j int) { if list.withinRange(i) && list.withinRange(j) && i != j { 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: element1 = currentElement case j: element2 = currentElement } } element1.value, element2.value = element2.value, element1.value } } // 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[T]) Insert(index int, values ...T) { if !list.withinRange(index) { // Append if index == list.size { list.Add(values...) } return } 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 beforeElement = list.last.prev for e := list.size - 1; e != index; e, foundElement = e-1, foundElement.prev { beforeElement = beforeElement.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[T]{value: value} 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[T]{value: value} newElement.prev = beforeElement beforeElement.next = newElement beforeElement = newElement } oldNextElement.prev = beforeElement beforeElement.next = oldNextElement } list.size += len(values) } // 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[T]) Set(index int, value T) { if !list.withinRange(index) { // Append if index == list.size { list.Add(value) } return } var foundElement *element[T] // 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[T]) String() string { str := "DoublyLinkedList\n" values := []string{} for element := list.first; element != nil; element = element.next { values = append(values, fmt.Sprintf("%v", element.value)) } str += strings.Join(values, ", ") return str } // Check that the index is within bounds of the list func (list *List[T]) withinRange(index int) bool { return index >= 0 && index < list.size } ================================================ FILE: lists/doublylinkedlist/doublylinkedlist_test.go ================================================ // 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 ( "cmp" "encoding/json" "slices" "strings" "testing" ) func TestListNew(t *testing.T) { list1 := New[int]() if actualValue := list1.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } list2 := New[int](1, 2) 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 != 2 || !ok { t.Errorf("Got %v expected %v", actualValue, 2) } if actualValue, ok := list2.Get(2); actualValue != 0 || ok { t.Errorf("Got %v expected %v", actualValue, 0) } } func TestListAdd(t *testing.T) { list := New[string]() 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") } } func TestListAppendAndPrepend(t *testing.T) { list := New[string]() 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[string]() list.Add("a") list.Add("b", "c") list.Remove(2) if actualValue, ok := list.Get(2); actualValue != "" || ok { t.Errorf("Got %v expected %v", actualValue, "") } 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[string]() list.Add("a") list.Add("b", "c") if actualValue, ok := list.Get(0); actualValue != "a" || !ok { t.Errorf("Got %v expected %v", actualValue, "a") } 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 != "" || ok { t.Errorf("Got %v expected %v", actualValue, "") } 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[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, "b") } } func TestListSort(t *testing.T) { list := New[string]() list.Sort(cmp.Compare[string]) list.Add("e", "f", "g", "a", "b", "c", "d") list.Sort(cmp.Compare[string]) for i := 1; i < list.Size(); i++ { a, _ := list.Get(i - 1) b, _ := list.Get(i) if a > b { t.Errorf("Not sorted! %s > %s", a, b) } } } func TestListClear(t *testing.T) { list := New[string]() 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) } } func TestListContains(t *testing.T) { 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) } 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 := list.Contains("a", "b", "c"); actualValue != false { t.Errorf("Got %v expected %v", actualValue, false) } } func TestListValues(t *testing.T) { list := New[string]() list.Add("a") list.Add("b", "c") 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[string]() list.Insert(0, "b", "c", "d") list.Insert(0, "a") list.Insert(10, "x") // ignore if actualValue := list.Size(); actualValue != 4 { t.Errorf("Got %v expected %v", actualValue, 4) } list.Insert(4, "g") // append if actualValue := list.Size(); actualValue != 5 { t.Errorf("Got %v expected %v", actualValue, 5) } 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 := strings.Join(list.Values(), ""), "abcdefg"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } func TestListSet(t *testing.T) { list := New[string]() 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 := 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[string]() list.Add("a", "b", "c") list.Each(func(index int, value string) { 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") } }) } func TestListMap(t *testing.T) { list := New[string]() list.Add("a", "b", "c") 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") } 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) } } func TestListSelect(t *testing.T) { list := New[string]() list.Add("a", "b", "c") 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") } 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) } } func TestListAny(t *testing.T) { list := New[string]() list.Add("a", "b", "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 string) bool { return value == "x" }) if any != false { t.Errorf("Got %v expected %v", any, false) } } func TestListAll(t *testing.T) { list := New[string]() list.Add("a", "b", "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 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[string]() list.Add("a", "b", "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 string) bool { return value == "x" }) 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[string]() list.Add("a", "b", "c") 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) } 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") } } func TestListIteratorNextOnEmpty(t *testing.T) { list := New[string]() it := list.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty list") } } func TestListIteratorNext(t *testing.T) { list := New[string]() list.Add("a", "b", "c") it := list.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 := count, 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } func TestListIteratorPrevOnEmpty(t *testing.T) { list := New[string]() it := list.Iterator() for it.Prev() { t.Errorf("Shouldn't iterate on empty list") } } func TestListIteratorPrev(t *testing.T) { list := New[string]() 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 TestListIteratorBegin(t *testing.T) { list := New[string]() it := list.Iterator() it.Begin() list.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 TestListIteratorEnd(t *testing.T) { list := New[string]() 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[string]() 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[string]() 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 TestListIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" seek := func(index int, value string) bool { return strings.HasSuffix(value, "b") } // NextTo (empty) { list := New[string]() it := list.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") } } // NextTo (not found) { list := New[string]() list.Add("xx", "yy") it := list.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") } } // NextTo (found) { 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 != "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 != "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 string) bool { return strings.HasSuffix(value, "b") } // PrevTo (empty) { list := New[string]() it := list.Iterator() it.End() for it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty list") } } // PrevTo (not found) { list := New[string]() 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[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 != "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 != "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[string]() list.Add("a", "b", "c") var err error assert := func() { 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 { t.Errorf("Got %v expected %v", actualValue, expectedValue) } if err != nil { t.Errorf("Got error %v", err) } } assert() bytes, err := list.ToJSON() assert() err = list.FromJSON(bytes) assert() bytes, err = json.Marshal([]any{"a", "b", "c", list}) if err != nil { t.Errorf("Got error %v", err) } 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[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[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { list.Get(n) } } } 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) } } } 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) } } } func BenchmarkDoublyLinkedListGet100(b *testing.B) { b.StopTimer() size := 100 list := New[int]() 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[int]() 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[int]() 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[int]() 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[int]() b.StartTimer() benchmarkAdd(b, list, size) } func BenchmarkDoublyLinkedListAdd1000(b *testing.B) { b.StopTimer() size := 1000 list := New[int]() 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[int]() 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[int]() 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[int]() 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[int]() 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[int]() 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[int]() for n := 0; n < size; n++ { list.Add(n) } b.StartTimer() benchmarkRemove(b, list, size) } ================================================ FILE: lists/doublylinkedlist/enumerable.go ================================================ // 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 "github.com/emirpasic/gods/v2/containers" // Assert Enumerable implementation 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[T]) Each(f func(index int, value T)) { 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[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())) } return newList } // Select returns a new container containing all elements for which the given function returns a true value. 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()) { 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[T]) Any(f func(index int, value T) 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[T]) All(f func(index int, value T) 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[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() } } var t T return -1, t } ================================================ FILE: lists/doublylinkedlist/iterator.go ================================================ // 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 "github.com/emirpasic/gods/v2/containers" // Assert Iterator implementation var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator holding the iterator's state type Iterator[T comparable] struct { list *List[T] index int element *element[T] } // Iterator returns a stateful iterator whose values can be fetched by an index. 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[T]) 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[T]) 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[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[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[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[T]) 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[T]) 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[T]) 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[T]) NextTo(f func(index int, value T) 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[T]) PrevTo(f func(index int, value T) bool) bool { for iterator.Prev() { index, value := iterator.Index(), iterator.Value() if f(index, value) { return true } } return false } ================================================ FILE: lists/doublylinkedlist/serialization.go ================================================ // 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/v2/containers" ) // Assert Serialization implementation var _ containers.JSONSerializer = (*List[int])(nil) 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.Values()) } // FromJSON populates list's elements from the input JSON representation. func (list *List[T]) FromJSON(data []byte) error { var elements []T err := json.Unmarshal(data, &elements) if err == nil { list.Clear() list.Add(elements...) } return err } // UnmarshalJSON @implements json.Unmarshaler func (list *List[T]) UnmarshalJSON(bytes []byte) error { return list.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (list *List[T]) MarshalJSON() ([]byte, error) { return list.ToJSON() } ================================================ FILE: lists/lists.go ================================================ // 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. // // 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 ( "github.com/emirpasic/gods/v2/containers" "github.com/emirpasic/gods/v2/utils" ) // List interface that all lists implement type List[T comparable] interface { Get(index int) (T, bool) Remove(index int) Add(values ...T) Contains(values ...T) bool Sort(comparator utils.Comparator[T]) Swap(index1, index2 int) Insert(index int, values ...T) Set(index int, value T) containers.Container[T] // Empty() bool // Size() int // Clear() // Values() []interface{} // String() string } ================================================ FILE: lists/singlylinkedlist/enumerable.go ================================================ // 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 "github.com/emirpasic/gods/v2/containers" // Assert Enumerable implementation 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[T]) Each(f func(index int, value T)) { 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[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())) } return newList } // Select returns a new container containing all elements for which the given function returns a true value. 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()) { 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[T]) Any(f func(index int, value T) 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[T]) All(f func(index int, value T) 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[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, value } ================================================ FILE: lists/singlylinkedlist/iterator.go ================================================ // 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 "github.com/emirpasic/gods/v2/containers" // Assert Iterator implementation var _ containers.IteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator holding the iterator's state type Iterator[T comparable] struct { list *List[T] index int element *element[T] } // Iterator returns a stateful iterator whose values can be fetched by an index. 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[T]) 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[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[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[T]) 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[T]) 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[T]) NextTo(f func(index int, value T) bool) bool { for iterator.Next() { index, value := iterator.Index(), iterator.Value() if f(index, value) { return true } } return false } ================================================ FILE: lists/singlylinkedlist/serialization.go ================================================ // 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/v2/containers" ) // Assert Serialization implementation var _ containers.JSONSerializer = (*List[int])(nil) 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.Values()) } // FromJSON populates list's elements from the input JSON representation. func (list *List[T]) FromJSON(data []byte) error { var elements []T err := json.Unmarshal(data, &elements) if err == nil { list.Clear() list.Add(elements...) } return err } // UnmarshalJSON @implements json.Unmarshaler func (list *List[T]) UnmarshalJSON(bytes []byte) error { return list.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (list *List[T]) MarshalJSON() ([]byte, error) { return list.ToJSON() } ================================================ FILE: lists/singlylinkedlist/singlylinkedlist.go ================================================ // 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. // // Structure is not thread safe. // // Reference: https://en.wikipedia.org/wiki/List_%28abstract_data_type%29 package singlylinkedlist import ( "fmt" "slices" "strings" "github.com/emirpasic/gods/v2/lists" "github.com/emirpasic/gods/v2/utils" ) // Assert List implementation var _ lists.List[int] = (*List[int])(nil) // List holds the elements, where each element points to the next element type List[T comparable] struct { first *element[T] last *element[T] size int } 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[T comparable](values ...T) *List[T] { list := &List[T]{} if len(values) > 0 { list.Add(values...) } return list } // Add appends a value (one or more) at the end of the list (same as Append()) func (list *List[T]) Add(values ...T) { for _, value := range values { newElement := &element[T]{value: value} if list.size == 0 { list.first = newElement list.last = newElement } else { list.last.next = newElement list.last = newElement } list.size++ } } // Append appends a value (one or more) at the end of the list (same as Add()) func (list *List[T]) Append(values ...T) { list.Add(values...) } // Prepend prepends a values (or more) 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[T]{value: values[v], next: list.first} list.first = newElement if list.size == 0 { list.last = newElement } list.size++ } } // 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[T]) Get(index int) (T, bool) { if !list.withinRange(index) { var t T return t, false } element := list.first for e := 0; e != index; e, element = e+1, element.next { } return element.value, true } // Remove removes the element at the given index from the list. func (list *List[T]) Remove(index int) { if !list.withinRange(index) { return } if list.size == 1 { list.Clear() return } var beforeElement *element[T] element := list.first for e := 0; e != index; e, element = e+1, element.next { beforeElement = element } if element == list.first { list.first = element.next } if element == list.last { list.last = beforeElement } if beforeElement != nil { beforeElement.next = element.next } element = nil list.size-- } // 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. func (list *List[T]) Contains(values ...T) bool { if len(values) == 0 { return true } if list.size == 0 { return false } for _, value := range values { found := false for element := list.first; element != nil; element = element.next { if element.value == value { found = true break } } if !found { return false } } return true } // Values returns all elements in the list. 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[T]) IndexOf(value T) 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[T]) Empty() bool { return list.size == 0 } // Size returns number of elements within the list. func (list *List[T]) Size() int { return list.size } // Clear removes all elements from the list. func (list *List[T]) Clear() { list.size = 0 list.first = nil list.last = nil } // Sort sort values (in-place) using. func (list *List[T]) Sort(comparator utils.Comparator[T]) { if list.size < 2 { return } values := list.Values() slices.SortFunc(values, comparator) list.Clear() list.Add(values...) } // Swap swaps values of two elements at the given indices. func (list *List[T]) Swap(i, j int) { if list.withinRange(i) && list.withinRange(j) && i != j { 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: element1 = currentElement case j: element2 = currentElement } } element1.value, element2.value = element2.value, element1.value } } // 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[T]) Insert(index int, values ...T) { if !list.withinRange(index) { // Append if index == list.size { list.Add(values...) } return } list.size += len(values) var beforeElement *element[T] 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[T]{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[T]{value: value} beforeElement.next = newElement beforeElement = newElement } beforeElement.next = oldNextElement } } // 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[T]) Set(index int, value T) { 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[T]) String() string { str := "SinglyLinkedList\n" values := []string{} for element := list.first; element != nil; element = element.next { values = append(values, fmt.Sprintf("%v", element.value)) } str += strings.Join(values, ", ") return str } // Check that the index is within bounds of the list func (list *List[T]) withinRange(index int) bool { return index >= 0 && index < list.size } ================================================ FILE: lists/singlylinkedlist/singlylinkedlist_test.go ================================================ // 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 ( "cmp" "encoding/json" "slices" "strings" "testing" ) func TestListNew(t *testing.T) { list1 := New[int]() if actualValue := list1.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } list2 := New[int](1, 2) 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 != 2 || !ok { t.Errorf("Got %v expected %v", actualValue, 2) } if actualValue, ok := list2.Get(2); actualValue != 0 || ok { t.Errorf("Got %v expected %v", actualValue, 0) } } func TestListAdd(t *testing.T) { list := New[string]() 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") } } func TestListAppendAndPrepend(t *testing.T) { list := New[string]() 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[string]() list.Add("a") list.Add("b", "c") list.Remove(2) if actualValue, ok := list.Get(2); actualValue != "" || ok { t.Errorf("Got %v expected %v", actualValue, "") } 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[string]() list.Add("a") list.Add("b", "c") if actualValue, ok := list.Get(0); actualValue != "a" || !ok { t.Errorf("Got %v expected %v", actualValue, "a") } 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 != "" || ok { t.Errorf("Got %v expected %v", actualValue, "") } 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[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, "b") } } func TestListSort(t *testing.T) { list := New[string]() list.Sort(cmp.Compare[string]) list.Add("e", "f", "g", "a", "b", "c", "d") list.Sort(cmp.Compare[string]) for i := 1; i < list.Size(); i++ { a, _ := list.Get(i - 1) b, _ := list.Get(i) if a > b { t.Errorf("Not sorted! %s > %s", a, b) } } } func TestListClear(t *testing.T) { list := New[string]() 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) } } func TestListContains(t *testing.T) { 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) } 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 := list.Contains("a", "b", "c"); actualValue != false { t.Errorf("Got %v expected %v", actualValue, false) } } func TestListValues(t *testing.T) { list := New[string]() list.Add("a") list.Add("b", "c") 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[string]() 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[string]() 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 := strings.Join(list.Values(), ""), "abcd"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } func TestListSet(t *testing.T) { list := New[string]() 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 := 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[string]() list.Add("a", "b", "c") list.Each(func(index int, value string) { 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") } }) } func TestListMap(t *testing.T) { list := New[string]() list.Add("a", "b", "c") 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") } 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) } } func TestListSelect(t *testing.T) { list := New[string]() list.Add("a", "b", "c") 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") } 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) } } func TestListAny(t *testing.T) { list := New[string]() list.Add("a", "b", "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 string) bool { return value == "x" }) if any != false { t.Errorf("Got %v expected %v", any, false) } } func TestListAll(t *testing.T) { list := New[string]() list.Add("a", "b", "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 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[string]() list.Add("a", "b", "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 string) bool { return value == "x" }) 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[string]() list.Add("a", "b", "c") 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) } 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") } } func TestListIteratorNextOnEmpty(t *testing.T) { list := New[string]() it := list.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty list") } } func TestListIteratorNext(t *testing.T) { list := New[string]() list.Add("a", "b", "c") it := list.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 := count, 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } func TestListIteratorBegin(t *testing.T) { list := New[string]() it := list.Iterator() it.Begin() list.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 TestListIteratorFirst(t *testing.T) { list := New[string]() 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 TestListIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" seek := func(index int, value string) bool { return strings.HasSuffix(value, "b") } // NextTo (empty) { list := New[string]() it := list.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") } } // NextTo (not found) { list := New[string]() list.Add("xx", "yy") it := list.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") } } // NextTo (found) { 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 != "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 != "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[string]() list.Add("a", "b", "c") var err error assert := func() { 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 { t.Errorf("Got %v expected %v", actualValue, expectedValue) } if err != nil { t.Errorf("Got error %v", err) } } assert() bytes, err := list.ToJSON() assert() err = list.FromJSON(bytes) assert() bytes, err = json.Marshal([]any{"a", "b", "c", list}) if err != nil { t.Errorf("Got error %v", err) } 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[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[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { list.Get(n) } } } 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) } } } 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) } } } func BenchmarkSinglyLinkedListGet100(b *testing.B) { b.StopTimer() size := 100 list := New[int]() 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[int]() 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[int]() 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[int]() 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[int]() b.StartTimer() benchmarkAdd(b, list, size) } func BenchmarkSinglyLinkedListAdd1000(b *testing.B) { b.StopTimer() size := 1000 list := New[int]() 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[int]() 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[int]() 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[int]() 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[int]() 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[int]() 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[int]() for n := 0; n < size; n++ { list.Add(n) } b.StartTimer() benchmarkRemove(b, list, size) } ================================================ FILE: maps/hashbidimap/hashbidimap.go ================================================ // 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/v2/maps" "github.com/emirpasic/gods/v2/maps/hashmap" ) // Assert Map implementation var _ maps.BidiMap[string, int] = (*Map[string, int])(nil) // Map holds the elements in two hashmaps. type Map[K, V comparable] struct { forwardMap hashmap.Map[K, V] inverseMap hashmap.Map[V, K] } // New instantiates a bidirectional map. 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[K, V]) Put(key K, value V) { 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[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[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[K, V]) Remove(key K) { 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[K, V]) Empty() bool { return m.Size() == 0 } // Size returns number of elements in the map. func (m *Map[K, V]) Size() int { return m.forwardMap.Size() } // Keys returns all keys (random order). func (m *Map[K, V]) Keys() []K { return m.forwardMap.Keys() } // Values returns all values (random order). func (m *Map[K, V]) Values() []V { return m.inverseMap.Keys() } // Clear removes all elements from the map. func (m *Map[K, V]) Clear() { m.forwardMap.Clear() m.inverseMap.Clear() } // String returns a string representation of container func (m *Map[K, V]) String() string { str := "HashBidiMap\n" str += fmt.Sprintf("%v", m.forwardMap) return str } ================================================ FILE: maps/hashbidimap/hashbidimap_test.go ================================================ // 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" "strings" "testing" "github.com/emirpasic/gods/v2/testutils" ) func TestMapPut(t *testing.T) { m := New[int, string]() 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) } 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{}{ {1, "a", true}, {2, "b", true}, {3, "c", true}, {4, "d", true}, {5, "e", true}, {6, "f", true}, {7, "g", true}, {8, "", false}, } for _, test := range tests1 { // retrievals actualValue, actualFound := m.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } } } func TestMapRemove(t *testing.T) { m := New[int, string]() 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) testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4}) testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d"}) 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, "", false}, {6, "", false}, {7, "", false}, {8, "", false}, } for _, test := range tests2 { actualValue, actualFound := m.Get(test[0].(int)) 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) 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) } if actualValue := m.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } } func TestMapGetKey(t *testing.T) { m := New[int, string]() 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}, {0, "x", false}, } for _, test := range tests1 { // retrievals actualValue, actualFound := m.GetKey(test[1].(string)) if actualValue != test[0] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[0]) } } } func TestMapSerialization(t *testing.T) { m := New[string, float64]() m.Put("a", 1.0) m.Put("b", 2.0) m.Put("c", 3.0) var err error assert := func() { 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) } if err != nil { t.Errorf("Got error %v", err) } } assert() bytes, err := m.ToJSON() assert() err = m.FromJSON(bytes) assert() bytes, err = json.Marshal([]interface{}{"a", "b", "c", m}) 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[string, int]() c.Put("a", 1) if !strings.HasPrefix(c.String(), "HashBidiMap") { t.Errorf("String should start with container name") } } 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) } } } 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) } } } 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) } } } func BenchmarkHashBidiMapGet100(b *testing.B) { b.StopTimer() size := 100 m := New[int, int]() 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[int, int]() 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[int, int]() 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[int, int]() 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[int, int]() b.StartTimer() benchmarkPut(b, m, size) } func BenchmarkHashBidiMapPut1000(b *testing.B) { b.StopTimer() size := 1000 m := New[int, int]() 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[int, int]() 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[int, int]() 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[int, int]() 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[int, int]() 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[int, int]() 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[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkRemove(b, m, size) } ================================================ FILE: maps/hashbidimap/serialization.go ================================================ // 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/v2/containers" ) // Assert Serialization implementation 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[K, V]) ToJSON() ([]byte, error) { return m.forwardMap.ToJSON() } // FromJSON populates the map from the input JSON representation. func (m *Map[K, V]) FromJSON(data []byte) error { var elements map[K]V err := json.Unmarshal(data, &elements) if err != nil { return err } m.Clear() for k, v := range elements { m.Put(k, v) } return nil } // UnmarshalJSON @implements json.Unmarshaler func (m *Map[K, V]) UnmarshalJSON(bytes []byte) error { return m.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (m *Map[K, V]) MarshalJSON() ([]byte, error) { return m.ToJSON() } ================================================ FILE: maps/hashmap/hashmap.go ================================================ // 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. // // Elements are unordered in the map. // // Structure is not thread safe. // // Reference: http://en.wikipedia.org/wiki/Associative_array package hashmap import ( "fmt" "github.com/emirpasic/gods/v2/maps" ) // Assert Map implementation var _ maps.Map[string, int] = (*Map[string, int])(nil) // Map holds the elements in go's native map type Map[K comparable, V any] struct { m map[K]V } // New instantiates a hash map. 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[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[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[K, V]) Remove(key K) { delete(m.m, key) } // Empty returns true if map does not contain any elements func (m *Map[K, V]) Empty() bool { return m.Size() == 0 } // Size returns number of elements in the map. func (m *Map[K, V]) Size() int { return len(m.m) } // Keys returns all keys (random order). func (m *Map[K, V]) Keys() []K { keys := make([]K, m.Size()) count := 0 for key := range m.m { keys[count] = key count++ } return keys } // Values returns all values (random order). func (m *Map[K, V]) Values() []V { values := make([]V, m.Size()) count := 0 for _, value := range m.m { values[count] = value count++ } return values } // Clear removes all elements from the map. func (m *Map[K, V]) Clear() { clear(m.m) } // String returns a string representation of container func (m *Map[K, V]) String() string { str := "HashMap\n" str += fmt.Sprintf("%v", m.m) return str } ================================================ FILE: maps/hashmap/hashmap_test.go ================================================ // 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" "strings" "testing" "github.com/emirpasic/gods/v2/testutils" ) func TestMapPut(t *testing.T) { m := New[int, string]() 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) } 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{}{ {1, "a", true}, {2, "b", true}, {3, "c", true}, {4, "d", true}, {5, "e", true}, {6, "f", true}, {7, "g", true}, {8, "", false}, } for _, test := range tests1 { // retrievals actualValue, actualFound := m.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } } } func TestMapRemove(t *testing.T) { m := New[int, string]() 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) testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4}) testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d"}) 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, "", false}, {6, "", false}, {7, "", false}, {8, "", false}, } for _, test := range tests2 { actualValue, actualFound := m.Get(test[0].(int)) 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) 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) } if actualValue := m.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } } func TestMapSerialization(t *testing.T) { m := New[string, float64]() m.Put("a", 1.0) m.Put("b", 2.0) m.Put("c", 3.0) var err error assert := func() { 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) } if err != nil { t.Errorf("Got error %v", err) } } assert() bytes, err := m.ToJSON() assert() err = m.FromJSON(bytes) assert() bytes, err = json.Marshal([]interface{}{"a", "b", "c", m}) 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[string, int]() c.Put("a", 1) if !strings.HasPrefix(c.String(), "HashMap") { t.Errorf("String should start with container name") } } 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) } } } 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) } } } 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) } } } func BenchmarkHashMapGet100(b *testing.B) { b.StopTimer() size := 100 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkGet(b, m, size) } func BenchmarkHashMapGet1000(b *testing.B) { b.StopTimer() size := 1000 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkGet(b, m, size) } func BenchmarkHashMapGet10000(b *testing.B) { b.StopTimer() size := 10000 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkGet(b, m, size) } func BenchmarkHashMapGet100000(b *testing.B) { b.StopTimer() size := 100000 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkGet(b, m, size) } func BenchmarkHashMapPut100(b *testing.B) { b.StopTimer() size := 100 m := New[int, int]() b.StartTimer() benchmarkPut(b, m, size) } func BenchmarkHashMapPut1000(b *testing.B) { b.StopTimer() size := 1000 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkPut(b, m, size) } func BenchmarkHashMapPut10000(b *testing.B) { b.StopTimer() size := 10000 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkPut(b, m, size) } func BenchmarkHashMapPut100000(b *testing.B) { b.StopTimer() size := 100000 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkPut(b, m, size) } func BenchmarkHashMapRemove100(b *testing.B) { b.StopTimer() size := 100 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkRemove(b, m, size) } func BenchmarkHashMapRemove1000(b *testing.B) { b.StopTimer() size := 1000 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkRemove(b, m, size) } func BenchmarkHashMapRemove10000(b *testing.B) { b.StopTimer() size := 10000 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkRemove(b, m, size) } func BenchmarkHashMapRemove100000(b *testing.B) { b.StopTimer() size := 100000 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkRemove(b, m, size) } ================================================ FILE: maps/hashmap/serialization.go ================================================ // 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/v2/containers" ) // Assert Serialization implementation 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[K, V]) ToJSON() ([]byte, error) { return json.Marshal(m.m) } // FromJSON populates the map from the input JSON representation. func (m *Map[K, V]) FromJSON(data []byte) error { return json.Unmarshal(data, &m.m) } // UnmarshalJSON @implements json.Unmarshaler func (m *Map[K, V]) UnmarshalJSON(bytes []byte) error { return m.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (m *Map[K, V]) MarshalJSON() ([]byte, error) { return m.ToJSON() } ================================================ FILE: maps/linkedhashmap/enumerable.go ================================================ // 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/v2/containers" // Assert Enumerable implementation 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[K, V]) Each(f func(key K, value V)) { 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[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()) 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[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()) { 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[K, V]) Any(f func(key K, value V) 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[K, V]) All(f func(key K, value V) 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[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 k, v } ================================================ FILE: maps/linkedhashmap/iterator.go ================================================ // 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/v2/containers" "github.com/emirpasic/gods/v2/lists/doublylinkedlist" ) // Assert Iterator implementation var _ containers.ReverseIteratorWithKey[string, int] = (*Iterator[string, int])(nil) // Iterator holding the iterator's state 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[K, V]) Iterator() *Iterator[K, V] { return &Iterator[K, V]{ 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[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[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[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[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[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[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[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[K, V]) 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[K, V]) NextTo(f func(key K, value V) 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[K, V]) PrevTo(f func(key K, value V) bool) bool { for iterator.Prev() { key, value := iterator.Key(), iterator.Value() if f(key, value) { return true } } return false } ================================================ FILE: maps/linkedhashmap/linkedhashmap.go ================================================ // 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" "strings" "github.com/emirpasic/gods/v2/lists/doublylinkedlist" "github.com/emirpasic/gods/v2/maps" ) // Assert Map implementation 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[K comparable, V any] struct { table map[K]V ordering *doublylinkedlist.List[K] } // New instantiates a linked-hash-map. 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[K, V]) Put(key K, value V) { 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[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[K, V]) Remove(key K) { 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[K, V]) Empty() bool { return m.Size() == 0 } // Size returns number of elements in the map. func (m *Map[K, V]) Size() int { return m.ordering.Size() } // Keys returns all keys in-order func (m *Map[K, V]) Keys() []K { return m.ordering.Values() } // Values returns all values in-order based on the key. func (m *Map[K, V]) Values() []V { values := make([]V, 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[K, V]) Clear() { clear(m.table) m.ordering.Clear() } // String returns a string representation of container func (m *Map[K, V]) String() string { str := "LinkedHashMap\nmap[" it := m.Iterator() for it.Next() { str += fmt.Sprintf("%v:%v ", it.Key(), it.Value()) } return strings.TrimRight(str, " ") + "]" } ================================================ FILE: maps/linkedhashmap/linkedhashmap_test.go ================================================ // 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 ( "encoding/json" "strings" "testing" "github.com/emirpasic/gods/v2/testutils" ) func TestMapPut(t *testing.T) { m := New[int, string]() 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) } 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{}{ {1, "a", true}, {2, "b", true}, {3, "c", true}, {4, "d", true}, {5, "e", true}, {6, "f", true}, {7, "g", true}, {8, "", false}, } for _, test := range tests1 { // retrievals actualValue, actualFound := m.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } } } func TestMapRemove(t *testing.T) { m := New[int, string]() 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) testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4}) testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d"}) 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, "", false}, {6, "", false}, {7, "", false}, {8, "", false}, } for _, test := range tests2 { actualValue, actualFound := m.Get(test[0].(int)) 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) 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) } if actualValue := m.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } } func TestMapEach(t *testing.T) { m := New[string, int]() m.Put("c", 1) m.Put("a", 2) m.Put("b", 3) count := 0 m.Each(func(key string, value int) { 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[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) 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") } 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[string, int]() m.Put("c", 3) m.Put("b", 1) m.Put("a", 2) 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") } 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[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) 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 string, value int) bool { return value == 4 }) if any != false { t.Errorf("Got %v expected %v", any, false) } } func TestMapAll(t *testing.T) { m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) 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 string, value int) bool { return key >= "a" && key <= "b" }) if all != false { t.Errorf("Got %v expected %v", all, false) } } func TestMapFind(t *testing.T) { m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) 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 string, value int) bool { return key == "x" }) if foundKey != "" || foundValue != 0 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundKey, "", 0) } } func TestMapChaining(t *testing.T) { m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) 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 != 0 || 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[string, int]() it := m.Iterator() it = m.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty map") } } func TestMapIteratorPrevOnEmpty(t *testing.T) { m := New[string, int]() it := m.Iterator() it = m.Iterator() for it.Prev() { t.Errorf("Shouldn't iterate on empty map") } } func TestMapIteratorNext(t *testing.T) { m := New[string, int]() 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[string, int]() 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[int, string]() 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 TestMapIteratorEnd(t *testing.T) { m := New[int, string]() 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[int, string]() 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[int, string]() 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 TestMapIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" seek := func(index int, value string) bool { return strings.HasSuffix(value, "b") } // NextTo (empty) { m := New[int, string]() it := m.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty map") } } // NextTo (not found) { m := New[int, string]() 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[int, string]() 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 != "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 != "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 int, value string) bool { return strings.HasSuffix(value, "b") } // PrevTo (empty) { m := New[int, string]() it := m.Iterator() it.End() for it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty map") } } // PrevTo (not found) { m := New[int, string]() 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[int, string]() 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 != "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 != "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[string, string]() original.Put("d", "4") original.Put("e", "5") original.Put("c", "3") original.Put("b", "2") original.Put("a", "1") serialized, err := original.ToJSON() if err != nil { t.Errorf("Got error %v", err) } deserialized := New[string, string]() err = deserialized.FromJSON(serialized) if err != nil { t.Errorf("Got error %v", err) } 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[string, float64]() 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) } 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[string, int]() c.Put("a", 1) if !strings.HasPrefix(c.String(), "LinkedHashMap") { t.Errorf("String should start with container name") } } 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) } } } 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) } } } 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) } } } func BenchmarkTreeMapGet100(b *testing.B) { b.StopTimer() size := 100 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkGet(b, m, size) } func BenchmarkTreeMapGet1000(b *testing.B) { b.StopTimer() size := 1000 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkGet(b, m, size) } func BenchmarkTreeMapGet10000(b *testing.B) { b.StopTimer() size := 10000 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkGet(b, m, size) } func BenchmarkTreeMapGet100000(b *testing.B) { b.StopTimer() size := 100000 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkGet(b, m, size) } func BenchmarkTreeMapPut100(b *testing.B) { b.StopTimer() size := 100 m := New[int, int]() b.StartTimer() benchmarkPut(b, m, size) } func BenchmarkTreeMapPut1000(b *testing.B) { b.StopTimer() size := 1000 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkPut(b, m, size) } func BenchmarkTreeMapPut10000(b *testing.B) { b.StopTimer() size := 10000 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkPut(b, m, size) } func BenchmarkTreeMapPut100000(b *testing.B) { b.StopTimer() size := 100000 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkPut(b, m, size) } func BenchmarkTreeMapRemove100(b *testing.B) { b.StopTimer() size := 100 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkRemove(b, m, size) } func BenchmarkTreeMapRemove1000(b *testing.B) { b.StopTimer() size := 1000 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkRemove(b, m, size) } func BenchmarkTreeMapRemove10000(b *testing.B) { b.StopTimer() size := 10000 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkRemove(b, m, size) } func BenchmarkTreeMapRemove100000(b *testing.B) { b.StopTimer() size := 100000 m := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkRemove(b, m, size) } ================================================ FILE: maps/linkedhashmap/serialization.go ================================================ // 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" "cmp" "encoding/json" "slices" "github.com/emirpasic/gods/v2/containers" ) // Assert Serialization implementation var _ containers.JSONSerializer = (*Map[string, int])(nil) var _ containers.JSONDeserializer = (*Map[string, int])(nil) // ToJSON outputs the JSON representation of map. func (m *Map[K, V]) 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[K, V]) 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[K, V]) FromJSON(data []byte) error { elements := make(map[K]V) err := json.Unmarshal(data, &elements) if err != nil { return err } 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(key1, key2 K) int { return cmp.Compare(index[key1], index[key2]) } slices.SortFunc(keys, byIndex) m.Clear() for _, key := range keys { m.Put(key, elements[key]) } return nil } // UnmarshalJSON @implements json.Unmarshaler func (m *Map[K, V]) UnmarshalJSON(bytes []byte) error { return m.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (m *Map[K, V]) MarshalJSON() ([]byte, error) { return m.ToJSON() } ================================================ FILE: maps/maps.go ================================================ // 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. // // 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/v2/containers" // Map interface that all maps implement 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[V] // Empty() bool // Size() int // Clear() // Values() []interface{} // String() string } // BidiMap interface that all bidirectional maps implement (extends the Map interface) type BidiMap[K comparable, V comparable] interface { GetKey(value V) (key K, found bool) Map[K, V] } ================================================ FILE: maps/treebidimap/enumerable.go ================================================ // 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/v2/containers" // Assert Enumerable implementation 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[K, V]) Each(f func(key K, value V)) { 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[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()) 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[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()) { 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[K, V]) Any(f func(key K, value V) 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[K, V]) All(f func(key K, value V) 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[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 k, v } ================================================ FILE: maps/treebidimap/iterator.go ================================================ // 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/v2/containers" rbt "github.com/emirpasic/gods/v2/trees/redblacktree" ) // Assert Iterator implementation var _ containers.ReverseIteratorWithKey[string, int] = (*Iterator[string, int])(nil) // Iterator holding the iterator's state 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[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[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[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[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[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[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[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[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[K, V]) 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[K, V]) NextTo(f func(key K, value V) 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[K, V]) PrevTo(f func(key K, value V) bool) bool { for iterator.Prev() { key, value := iterator.Key(), iterator.Value() if f(key, value) { return true } } return false } ================================================ FILE: maps/treebidimap/serialization.go ================================================ // 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/v2/containers" ) // Assert Serialization implementation 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[K, V]) ToJSON() ([]byte, error) { return m.forwardMap.ToJSON() } // FromJSON populates the map from the input JSON representation. func (m *Map[K, V]) FromJSON(data []byte) error { var elements map[K]V err := json.Unmarshal(data, &elements) if err != nil { return err } m.Clear() for key, value := range elements { m.Put(key, value) } return nil } // UnmarshalJSON @implements json.Unmarshaler func (m *Map[K, V]) UnmarshalJSON(bytes []byte) error { return m.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (m *Map[K, V]) MarshalJSON() ([]byte, error) { return m.ToJSON() } ================================================ FILE: maps/treebidimap/treebidimap.go ================================================ // 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 two red-black tree. // // This structure 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, 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. // // Structure is not thread safe. // // Reference: https://en.wikipedia.org/wiki/Bidirectional_map package treebidimap import ( "cmp" "fmt" "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[string, int] = (*Map[string, int])(nil) // Map holds the elements in two red-black trees. type Map[K, V comparable] struct { forwardMap redblacktree.Tree[K, V] inverseMap redblacktree.Tree[V, K] } // 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[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), } } // Put inserts element into the map. func (m *Map[K, V]) Put(key K, value V) { if v, ok := m.forwardMap.Get(key); ok { m.inverseMap.Remove(v) } if k, ok := m.inverseMap.Get(value); ok { m.forwardMap.Remove(k) } 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[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[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[K, V]) Remove(key K) { if v, found := m.forwardMap.Get(key); found { m.forwardMap.Remove(key) m.inverseMap.Remove(v) } } // Empty returns true if map does not contain any elements func (m *Map[K, V]) Empty() bool { return m.Size() == 0 } // Size returns number of elements in the map. func (m *Map[K, V]) Size() int { return m.forwardMap.Size() } // Keys returns all keys (ordered). func (m *Map[K, V]) Keys() []K { return m.forwardMap.Keys() } // Values returns all values (ordered). func (m *Map[K, V]) Values() []V { return m.inverseMap.Keys() } // Clear removes all elements from the map. func (m *Map[K, V]) Clear() { m.forwardMap.Clear() m.inverseMap.Clear() } // String returns a string representation of container func (m *Map[K, V]) String() string { str := "TreeBidiMap\nmap[" it := m.Iterator() for it.Next() { str += fmt.Sprintf("%v:%v ", it.Key(), it.Value()) } return strings.TrimRight(str, " ") + "]" } ================================================ FILE: maps/treebidimap/treebidimap_test.go ================================================ // 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" "strings" "testing" "github.com/emirpasic/gods/v2/testutils" ) func TestMapPut(t *testing.T) { m := New[int, string]() 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) } 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{}{ {1, "a", true}, {2, "b", true}, {3, "c", true}, {4, "d", true}, {5, "e", true}, {6, "f", true}, {7, "g", true}, {8, "", false}, } for _, test := range tests1 { // retrievals actualValue, actualFound := m.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } } } func TestMapRemove(t *testing.T) { m := New[int, string]() 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) testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4}) testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d"}) 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, "", false}, {6, "", false}, {7, "", false}, {8, "", false}, } for _, test := range tests2 { actualValue, actualFound := m.Get(test[0].(int)) 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) 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) } if actualValue := m.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } } func TestMapGetKey(t *testing.T) { m := New[int, string]() 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}, {0, "x", false}, } for _, test := range tests1 { // retrievals actualValue, actualFound := m.GetKey(test[1].(string)) 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 TestMapEach(t *testing.T) { m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) count := 0 m.Each(func(key string, value int) { 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 := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) 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") } 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 := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) 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") } 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 := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) 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 string, value int) bool { return value == 4 }) if any != false { t.Errorf("Got %v expected %v", any, false) } } func TestMapAll(t *testing.T) { m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) 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 string, value int) bool { return key >= "a" && key <= "b" }) if all != false { t.Errorf("Got %v expected %v", all, false) } } func TestMapFind(t *testing.T) { m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) 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 string, value int) bool { return key == "x" }) if foundKey != "" || foundValue != 0 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundKey, nil, nil) } } func TestMapChaining(t *testing.T) { m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) 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 != 0 || 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[string, string]() it := m.Iterator() it = m.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty map") } } func TestMapIteratorPrevOnEmpty(t *testing.T) { m := New[string, string]() it := m.Iterator() it = m.Iterator() for it.Prev() { t.Errorf("Shouldn't iterate on empty map") } } func TestMapIteratorNext(t *testing.T) { m := New[string, int]() 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 := New[string, int]() 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 := New[int, string]() 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 TestMapIteratorEnd(t *testing.T) { m := New[int, string]() 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 := New[int, string]() 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 := New[int, string]() 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 TestMapIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" seek := func(index int, value string) bool { return strings.HasSuffix(value, "b") } // NextTo (empty) { m := New[int, string]() it := m.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty map") } } // NextTo (not found) { m := New[int, string]() 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[int, string]() 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 != "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 != "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 int, value string) bool { return strings.HasSuffix(value, "b") } // PrevTo (empty) { m := New[int, string]() it := m.Iterator() it.End() for it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty map") } } // PrevTo (not found) { m := New[int, string]() 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[int, string]() 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 != "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 != "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[string, string]() original.Put("d", "4") original.Put("e", "5") original.Put("c", "3") original.Put("b", "2") original.Put("a", "1") serialized, err := original.ToJSON() if err != nil { t.Errorf("Got error %v", err) } deserialized := New[string, string]() err = deserialized.FromJSON(serialized) if err != nil { t.Errorf("Got error %v", err) } 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 := New[string, float64]() 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) } 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[string, string]() c.Put("a", "a") if !strings.HasPrefix(c.String(), "TreeBidiMap") { t.Errorf("String should start with container name") } } 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) } } } 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) } } } 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) } } } func BenchmarkTreeBidiMapGet100(b *testing.B) { b.StopTimer() size := 100 m := New[int, int]() 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 := New[int, int]() 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 := New[int, int]() 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 := New[int, int]() 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 := New[int, int]() b.StartTimer() benchmarkPut(b, m, size) } func BenchmarkTreeBidiMapPut1000(b *testing.B) { b.StopTimer() size := 1000 m := New[int, int]() 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 := New[int, int]() 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 := New[int, int]() 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 := New[int, int]() 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 := New[int, int]() 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 := New[int, int]() 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 := New[int, int]() for n := 0; n < size; n++ { m.Put(n, n) } b.StartTimer() benchmarkRemove(b, m, size) } ================================================ FILE: maps/treemap/enumerable.go ================================================ // 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/v2/containers" rbt "github.com/emirpasic/gods/v2/trees/redblacktree" ) // Assert Enumerable implementation 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[K, V]) Each(f func(key K, value V)) { 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[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()) 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[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()) { 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[K, V]) Any(f func(key K, value V) 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[K, V]) All(f func(key K, value V) 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[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 k, v } ================================================ FILE: maps/treemap/iterator.go ================================================ // 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/v2/containers" rbt "github.com/emirpasic/gods/v2/trees/redblacktree" ) // Assert Iterator implementation var _ containers.ReverseIteratorWithKey[string, int] = (*Iterator[string, int])(nil) // Iterator holding the iterator's state 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[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[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[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[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[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[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[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[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[K, V]) 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[K, V]) NextTo(f func(key K, value V) 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[K, V]) PrevTo(f func(key K, value V) bool) bool { for iterator.Prev() { key, value := iterator.Key(), iterator.Value() if f(key, value) { return true } } return false } ================================================ FILE: maps/treemap/serialization.go ================================================ // 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/v2/containers" ) // Assert Serialization implementation 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[K, V]) ToJSON() ([]byte, error) { return m.tree.ToJSON() } // FromJSON populates the map from the input JSON representation. func (m *Map[K, V]) FromJSON(data []byte) error { return m.tree.FromJSON(data) } // UnmarshalJSON @implements json.Unmarshaler func (m *Map[K, V]) UnmarshalJSON(bytes []byte) error { return m.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (m *Map[K, V]) MarshalJSON() ([]byte, error) { return m.ToJSON() } ================================================ FILE: maps/treemap/treemap.go ================================================ // 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. // // Elements are ordered by key in the map. // // Structure is not thread safe. // // Reference: http://en.wikipedia.org/wiki/Associative_array package treemap import ( "cmp" "fmt" "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[string, int] = (*Map[string, int])(nil) // Map holds the elements in a red-black tree type Map[K comparable, V any] struct { tree *rbt.Tree[K, V] } // 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]()} } // 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[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[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[K, V]) Remove(key K) { m.tree.Remove(key) } // Empty returns true if map does not contain any elements func (m *Map[K, V]) Empty() bool { return m.tree.Empty() } // Size returns number of elements in the map. func (m *Map[K, V]) Size() int { return m.tree.Size() } // Keys returns all keys in-order func (m *Map[K, V]) Keys() []K { return m.tree.Keys() } // Values returns all values in-order based on the key. func (m *Map[K, V]) Values() []V { return m.tree.Values() } // Clear removes all elements from the map. func (m *Map[K, V]) Clear() { m.tree.Clear() } // Min returns the minimum key and its value from the tree map. // 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, true } return key, value, false } // Max returns the maximum key and its value from the tree map. // 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, true } return key, value, 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[K, V]) Floor(key K) (foundKey K, foundValue V, ok bool) { node, found := m.tree.Floor(key) if found { return node.Key, node.Value, true } return foundKey, foundValue, 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[K, V]) Ceiling(key K) (foundKey K, foundValue V, ok bool) { node, found := m.tree.Ceiling(key) if found { return node.Key, node.Value, true } return foundKey, foundValue, false } // String returns a string representation of container func (m *Map[K, V]) String() string { str := "TreeMap\nmap[" it := m.Iterator() for it.Next() { str += fmt.Sprintf("%v:%v ", it.Key(), it.Value()) } return strings.TrimRight(str, " ") + "]" } ================================================ FILE: maps/treemap/treemap_test.go ================================================ // 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 ( "encoding/json" "strings" "testing" "github.com/emirpasic/gods/v2/testutils" ) func TestMapPut(t *testing.T) { m := New[int, string]() 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) } 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{}{ {1, "a", true}, {2, "b", true}, {3, "c", true}, {4, "d", true}, {5, "e", true}, {6, "f", true}, {7, "g", true}, {8, "", false}, } for _, test := range tests1 { // retrievals actualValue, actualFound := m.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } } } func TestMapMin(t *testing.T) { m := New[int, string]() 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") 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, 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 := New[int, string]() 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") 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, 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 := New[int, string]() 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 := New[int, string]() 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) testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4}) testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d"}) 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, "", false}, {6, "", false}, {7, "", false}, {8, "", false}, } for _, test := range tests2 { actualValue, actualFound := m.Get(test[0].(int)) 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) 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) } if actualValue := m.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } } func TestMapFloor(t *testing.T) { m := New[int, string]() m.Put(7, "g") m.Put(3, "c") m.Put(1, "a") // key,expectedKey,expectedValue,expectedFound tests1 := [][]interface{}{ {-1, 0, "", false}, {0, 0, "", 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, 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 := New[int, string]() 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, 0, "", false}, } for _, test := range tests1 { // retrievals 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]) } } } func TestMapEach(t *testing.T) { m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) count := 0 m.Each(func(key string, value int) { 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 := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) 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") } 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 := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) 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") } 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 := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) 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 string, value int) bool { return value == 4 }) if any != false { t.Errorf("Got %v expected %v", any, false) } } func TestMapAll(t *testing.T) { m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) 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 string, value int) bool { return key >= "a" && key <= "b" }) if all != false { t.Errorf("Got %v expected %v", all, false) } } func TestMapFind(t *testing.T) { m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) 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 string, value int) bool { return key == "x" }) if foundKey != "" || foundValue != 0 { t.Errorf("Got %v at %v expected %v at %v", foundValue, foundKey, nil, nil) } } func TestMapChaining(t *testing.T) { m := New[string, int]() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) 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 != 0 || 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[string, int]() it := m.Iterator() it = m.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty map") } } func TestMapIteratorPrevOnEmpty(t *testing.T) { m := New[string, int]() it := m.Iterator() it = m.Iterator() for it.Prev() { t.Errorf("Shouldn't iterate on empty map") } } func TestMapIteratorNext(t *testing.T) { m := New[string, int]() 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 := New[string, int]() 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 := New[int, string]() 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 TestMapIteratorEnd(t *testing.T) { m := New[int, string]() 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 := New[int, string]() 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 := New[int, string]() 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 TestMapIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" seek := func(index int, value string) bool { return strings.HasSuffix(value, "b") } // NextTo (empty) { m := New[int, string]() it := m.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty map") } } // NextTo (not found) { m := New[int, string]() 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[int, string]() 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 != "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 != "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 int, value string) bool { return strings.HasSuffix(value, "b") } // PrevTo (empty) { m := New[int, string]() it := m.Iterator() it.End() for it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty map") } } // PrevTo (not found) { m := New[int, string]() 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[int, string]() 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 != "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 != "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[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[string, string]() err = deserialized.FromJSON(serialized) if err != nil { t.Errorf("Got error %v", err) } assertSerialization(deserialized, "C", t) } m := New[string, float64]() 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) } 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[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[string, string], txt string, t *testing.T) { if actualValue := m.Keys(); false || 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] != "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 { t.Errorf("[%s] Got %v expected %v", txt, actualValue, expectedValue) } } 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) } } } 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{}{}) } } } 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) } } } func BenchmarkTreeMapGet100(b *testing.B) { b.StopTimer() size := 100 m := New[int, struct{}]() 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[int, struct{}]() 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[int, struct{}]() 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[int, struct{}]() 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[int, struct{}]() b.StartTimer() benchmarkPut(b, m, size) } func BenchmarkTreeMapPut1000(b *testing.B) { b.StopTimer() size := 1000 m := New[int, struct{}]() 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[int, struct{}]() 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[int, struct{}]() 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[int, struct{}]() 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[int, struct{}]() 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[int, struct{}]() 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[int, struct{}]() for n := 0; n < size; n++ { m.Put(n, struct{}{}) } b.StartTimer() benchmarkRemove(b, m, size) } ================================================ FILE: queues/arrayqueue/arrayqueue.go ================================================ // 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/v2/lists/arraylist" "github.com/emirpasic/gods/v2/queues" ) // Assert Queue implementation var _ queues.Queue[int] = (*Queue[int])(nil) // Queue holds elements in an array-list type Queue[T comparable] struct { list *arraylist.List[T] } // New instantiates a new empty queue 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[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[T]) Dequeue() (value T, 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[T]) Peek() (value T, ok bool) { return queue.list.Get(0) } // Empty returns true if queue does not contain any elements. func (queue *Queue[T]) Empty() bool { return queue.list.Empty() } // Size returns number of elements within the queue. func (queue *Queue[T]) Size() int { return queue.list.Size() } // Clear removes all elements from the queue. func (queue *Queue[T]) Clear() { queue.list.Clear() } // Values returns all elements in the queue (FIFO order). func (queue *Queue[T]) Values() []T { return queue.list.Values() } // String returns a string representation of container func (queue *Queue[T]) 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[T]) withinRange(index int) bool { return index >= 0 && index < queue.list.Size() } ================================================ FILE: queues/arrayqueue/arrayqueue_test.go ================================================ // 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" "strings" "testing" "github.com/emirpasic/gods/v2/testutils" ) func TestQueueEnqueue(t *testing.T) { queue := New[int]() 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] != 1 || actualValue[1] != 2 || actualValue[2] != 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[int]() if actualValue, ok := queue.Peek(); actualValue != 0 || 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[int]() 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 != 0 || 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[int]() it := queue.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty queue") } } func TestQueueIteratorNext(t *testing.T) { queue := New[string]() 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[string]() 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[string]() 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[string]() 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[string]() 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[string]() 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 string) bool { return strings.HasSuffix(value, "b") } // NextTo (empty) { queue := New[string]() it := queue.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty queue") } } // NextTo (not found) { queue := New[string]() 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[string]() 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 != "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 != "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 string) bool { return strings.HasSuffix(value, "b") } // PrevTo (empty) { queue := New[string]() it := queue.Iterator() it.End() for it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty queue") } } // PrevTo (not found) { queue := New[string]() 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[string]() 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 != "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 != "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[string]() queue.Enqueue("a") queue.Enqueue("b") queue.Enqueue("c") var err error assert := func() { 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) } 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(`["a","b","c"]`), &queue) if err != nil { t.Errorf("Got error %v", err) } assert() } func TestQueueString(t *testing.T) { 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[int], 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[int], 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[int]() 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[int]() 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[int]() 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[int]() 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[int]() b.StartTimer() benchmarkEnqueue(b, queue, size) } func BenchmarkArrayQueueEnqueue1000(b *testing.B) { b.StopTimer() size := 1000 queue := New[int]() 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[int]() 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[int]() for n := 0; n < size; n++ { queue.Enqueue(n) } b.StartTimer() benchmarkEnqueue(b, queue, size) } ================================================ FILE: queues/arrayqueue/iterator.go ================================================ // 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/v2/containers" // Assert Iterator implementation var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. 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[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[T]) 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[T]) 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[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[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[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[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[T]) 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[T]) 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[T]) NextTo(f func(index int, value T) 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[T]) PrevTo(f func(index int, value T) bool) bool { for iterator.Prev() { index, value := iterator.Index(), iterator.Value() if f(index, value) { return true } } return false } ================================================ FILE: queues/arrayqueue/serialization.go ================================================ // 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/v2/containers" ) // Assert Serialization implementation var _ containers.JSONSerializer = (*Queue[int])(nil) var _ containers.JSONDeserializer = (*Queue[int])(nil) // ToJSON outputs the JSON representation of the queue. func (queue *Queue[T]) ToJSON() ([]byte, error) { return queue.list.ToJSON() } // FromJSON populates the queue from the input JSON representation. func (queue *Queue[T]) FromJSON(data []byte) error { return queue.list.FromJSON(data) } // UnmarshalJSON @implements json.Unmarshaler func (queue *Queue[T]) UnmarshalJSON(bytes []byte) error { return queue.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (queue *Queue[T]) MarshalJSON() ([]byte, error) { return queue.ToJSON() } ================================================ FILE: queues/circularbuffer/circularbuffer.go ================================================ // 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/v2/queues" ) // Assert Queue implementation var _ queues.Queue[int] = (*Queue[int])(nil) // Queue holds values in a slice. type Queue[T comparable] struct { values []T 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[T comparable](maxSize int) *Queue[T] { if maxSize < 1 { panic("Invalid maxSize, should be at least 1") } queue := &Queue[T]{maxSize: maxSize} queue.Clear() return queue } // Enqueue adds a value to the end of the queue func (queue *Queue[T]) Enqueue(value T) { 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 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[T]) Dequeue() (value T, ok bool) { if queue.Empty() { return value, false } value, ok = queue.values[queue.start], true 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[T]) Peek() (value T, ok bool) { if queue.Empty() { return value, false } return queue.values[queue.start], true } // Empty returns true if queue does not contain any elements. 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[T]) Full() bool { return queue.Size() == queue.maxSize } // Size returns number of elements within the queue. func (queue *Queue[T]) Size() int { return queue.size } // Clear removes all elements from the queue. func (queue *Queue[T]) Clear() { queue.values = make([]T, 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[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] } return values } // String returns a string representation of container func (queue *Queue[T]) 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[T]) withinRange(index int) bool { return index >= 0 && index < queue.size } func (queue *Queue[T]) 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 } ================================================ FILE: queues/circularbuffer/circularbuffer_test.go ================================================ // 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" "strings" "testing" "github.com/emirpasic/gods/v2/testutils" ) func TestQueueEnqueue(t *testing.T) { queue := New[int](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] != 1 || actualValue[1] != 2 || actualValue[2] != 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[int](3) if actualValue, ok := queue.Peek(); actualValue != 0 || 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) { assert := func(actualValue interface{}, expectedValue interface{}) { if actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } queue := New[int](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) assert(queue.Size(), 2) queue.Enqueue(3) assert(queue.Size(), 3) assert(queue.Empty(), false) assert(queue.Full(), true) queue.Dequeue() assert(queue.Size(), 2) 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) } assert(queue.Size(), 1) if actualValue, ok := queue.Dequeue(); actualValue != 3 || !ok { t.Errorf("Got %v expected %v", actualValue, 3) } assert(queue.Size(), 0) assert(queue.Empty(), true) assert(queue.Full(), false) if actualValue, ok := queue.Dequeue(); actualValue != 0 || ok { t.Errorf("Got %v expected %v", actualValue, nil) } assert(queue.Size(), 0) assert(queue.Empty(), true) assert(queue.Full(), false) assert(len(queue.Values()), 0) } func TestQueueDequeueFull(t *testing.T) { assert := func(actualValue interface{}, expectedValue interface{}) { if actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } queue := New[int](2) assert(queue.Empty(), true) assert(queue.Full(), false) assert(queue.Size(), 0) queue.Enqueue(1) assert(queue.Size(), 1) queue.Enqueue(2) 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 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) } 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) } assert(queue.Size(), 0) if actualValue, ok := queue.Dequeue(); actualValue != 0 || ok { t.Errorf("Got %v expected %v", actualValue, nil) } assert(queue.Empty(), true) assert(queue.Full(), false) assert(len(queue.Values()), 0) } func TestQueueIteratorOnEmpty(t *testing.T) { queue := New[int](3) it := queue.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty queue") } } func TestQueueIteratorNext(t *testing.T) { queue := New[string](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[string](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[string](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[string](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[string](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[string](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 string) bool { return strings.HasSuffix(value, "b") } // NextTo (empty) { queue := New[string](3) it := queue.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty queue") } } // NextTo (not found) { queue := New[string](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[string](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 != "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 != "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 string) bool { return strings.HasSuffix(value, "b") } // PrevTo (empty) { queue := New[string](3) it := queue.Iterator() it.End() for it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty queue") } } // PrevTo (not found) { queue := New[string](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[string](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 != "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 != "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) { assert := func(actualValue interface{}, expectedValue interface{}) { if actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } queue := New[string](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) } 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) } 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) } assert(it.Next(), false) if actualIndex, expectedIndex := it.Index(), 2; actualIndex != expectedIndex { t.Errorf("Got %v expected %v", actualIndex, expectedIndex) } assert(it.Next(), false) 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) } 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) } assert(it.Prev(), false) if actualIndex, expectedIndex := it.Index(), -1; actualIndex != expectedIndex { t.Errorf("Got %v expected %v", actualIndex, expectedIndex) } } func TestQueueSerialization(t *testing.T) { queue := New[string](3) queue.Enqueue("a") queue.Enqueue("b") queue.Enqueue("c") var err error assert := func() { 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) } 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(`["a","b","c"]`), &queue) if err != nil { t.Errorf("Got error %v", err) } assert() } func TestQueueString(t *testing.T) { 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[int], 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[int], 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[int](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[int](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[int](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[int](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[int](3) b.StartTimer() benchmarkEnqueue(b, queue, size) } func BenchmarkArrayQueueEnqueue1000(b *testing.B) { b.StopTimer() size := 1000 queue := New[int](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[int](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[int](3) for n := 0; n < size; n++ { queue.Enqueue(n) } b.StartTimer() benchmarkEnqueue(b, queue, size) } ================================================ FILE: queues/circularbuffer/iterator.go ================================================ // 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/v2/containers" // Assert Iterator implementation var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. 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[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[T]) 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[T]) 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[T]) Value() T { 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[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[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[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[T]) 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[T]) 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[T]) NextTo(f func(index int, value T) 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[T]) PrevTo(f func(index int, value T) bool) bool { for iterator.Prev() { index, value := iterator.Index(), iterator.Value() if f(index, value) { return true } } return false } ================================================ FILE: queues/circularbuffer/serialization.go ================================================ // 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/v2/containers" ) // Assert Serialization implementation var _ containers.JSONSerializer = (*Queue[int])(nil) var _ containers.JSONDeserializer = (*Queue[int])(nil) // ToJSON outputs the JSON representation of queue's elements. 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[T]) FromJSON(data []byte) error { var values []T err := json.Unmarshal(data, &values) if err == nil { for _, value := range values { queue.Enqueue(value) } } return err } // UnmarshalJSON @implements json.Unmarshaler func (queue *Queue[T]) UnmarshalJSON(bytes []byte) error { return queue.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (queue *Queue[T]) MarshalJSON() ([]byte, error) { return queue.ToJSON() } ================================================ FILE: queues/linkedlistqueue/iterator.go ================================================ // 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/v2/containers" // Assert Iterator implementation var _ containers.IteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. 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[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[T]) 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[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[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[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[T]) 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[T]) NextTo(f func(index int, value T) bool) bool { for iterator.Next() { index, value := iterator.Index(), iterator.Value() if f(index, value) { return true } } return false } ================================================ FILE: queues/linkedlistqueue/linkedlistqueue.go ================================================ // 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/v2/lists/singlylinkedlist" "github.com/emirpasic/gods/v2/queues" ) // Assert Queue implementation var _ queues.Queue[int] = (*Queue[int])(nil) // Queue holds elements in a singly-linked-list type Queue[T comparable] struct { list *singlylinkedlist.List[T] } // New instantiates a new empty queue 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[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[T]) Dequeue() (value T, 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[T]) Peek() (value T, ok bool) { return queue.list.Get(0) } // Empty returns true if queue does not contain any elements. func (queue *Queue[T]) Empty() bool { return queue.list.Empty() } // Size returns number of elements within the queue. func (queue *Queue[T]) Size() int { return queue.list.Size() } // Clear removes all elements from the queue. func (queue *Queue[T]) Clear() { queue.list.Clear() } // Values returns all elements in the queue (FIFO order). func (queue *Queue[T]) Values() []T { return queue.list.Values() } // String returns a string representation of container func (queue *Queue[T]) 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[T]) withinRange(index int) bool { return index >= 0 && index < queue.list.Size() } ================================================ FILE: queues/linkedlistqueue/linkedlistqueue_test.go ================================================ // 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" "strings" "testing" "github.com/emirpasic/gods/v2/testutils" ) func TestQueueEnqueue(t *testing.T) { queue := New[int]() 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] != 1 || actualValue[1] != 2 || actualValue[2] != 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[int]() if actualValue, ok := queue.Peek(); actualValue != 0 || 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[int]() 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 != 0 || 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[int]() it := queue.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty queue") } } func TestQueueIteratorNext(t *testing.T) { queue := New[string]() 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[string]() 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[string]() 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 string) bool { return strings.HasSuffix(value, "b") } // NextTo (empty) { queue := New[string]() it := queue.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty queue") } } // NextTo (not found) { queue := New[string]() 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[string]() 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 != "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 != "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[string]() queue.Enqueue("a") queue.Enqueue("b") queue.Enqueue("c") var err error assert := func() { 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) } 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(`["a","b","c"]`), &queue) if err != nil { t.Errorf("Got error %v", err) } assert() } func TestQueueString(t *testing.T) { 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[int], 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[int], 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[int]() 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[int]() 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[int]() 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[int]() 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[int]() b.StartTimer() benchmarkEnqueue(b, queue, size) } func BenchmarkArrayQueueEnqueue1000(b *testing.B) { b.StopTimer() size := 1000 queue := New[int]() 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[int]() 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[int]() for n := 0; n < size; n++ { queue.Enqueue(n) } b.StartTimer() benchmarkEnqueue(b, queue, size) } ================================================ FILE: queues/linkedlistqueue/serialization.go ================================================ // 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/v2/containers" ) // Assert Serialization implementation var _ containers.JSONSerializer = (*Queue[int])(nil) var _ containers.JSONDeserializer = (*Queue[int])(nil) // ToJSON outputs the JSON representation of the queue. func (queue *Queue[T]) ToJSON() ([]byte, error) { return queue.list.ToJSON() } // FromJSON populates the queue from the input JSON representation. func (queue *Queue[T]) FromJSON(data []byte) error { return queue.list.FromJSON(data) } // UnmarshalJSON @implements json.Unmarshaler func (queue *Queue[T]) UnmarshalJSON(bytes []byte) error { return queue.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (queue *Queue[T]) MarshalJSON() ([]byte, error) { return queue.ToJSON() } ================================================ FILE: queues/priorityqueue/iterator.go ================================================ // 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/v2/containers" "github.com/emirpasic/gods/v2/trees/binaryheap" ) // Assert Iterator implementation var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. 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[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[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[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[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[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[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[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[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[T]) 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[T]) NextTo(f func(index int, value T) 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[T]) PrevTo(f func(index int, value T) bool) bool { return iterator.iterator.PrevTo(f) } ================================================ FILE: queues/priorityqueue/priorityqueue.go ================================================ // 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 ( "cmp" "fmt" "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[int] = (*Queue[int])(nil) // Queue holds elements in an array-list 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[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[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[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[T]) Peek() (value T, ok bool) { return queue.heap.Peek() } // Empty returns true if queue does not contain any elements. func (queue *Queue[T]) Empty() bool { return queue.heap.Empty() } // Size returns number of elements within the queue. func (queue *Queue[T]) Size() int { return queue.heap.Size() } // Clear removes all elements from the queue. func (queue *Queue[T]) Clear() { queue.heap.Clear() } // Values returns all elements in the queue. func (queue *Queue[T]) Values() []T { return queue.heap.Values() } // String returns a string representation of container 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() { values[index] = fmt.Sprintf("%v", value) } str += strings.Join(values, ", ") return str } ================================================ FILE: queues/priorityqueue/priorityqueue_test.go ================================================ // 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 ( "cmp" "encoding/json" "fmt" "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 Element) int { return -cmp.Compare(a.priority, b.priority) // Note "-" for descending order } func TestBinaryQueueEnqueue(t *testing.T) { queue := NewWith[Element](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.name, "c"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } case 1: if actualValue, expectedValue := value.name, "b"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } case 2: if actualValue, expectedValue := value.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].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 := New[int]() 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) } queue.Clear() if actualValue := queue.Empty(); !actualValue { t.Errorf("Got %v expected %v", actualValue, true) } } func TestBinaryQueueDequeue(t *testing.T) { queue := New[int]() 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 != 0 || 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 := New[int]() 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 > curr { t.Errorf("Queue property invalidated. prev: %v current: %v", prev, curr) } prev = curr } } func TestBinaryQueueIteratorOnEmpty(t *testing.T) { queue := New[int]() it := queue.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty queue") } } func TestBinaryQueueIteratorNext(t *testing.T) { queue := New[int]() 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 := New[int]() 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 := New[int]() 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 := New[int]() 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 := New[int]() 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 := New[int]() 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 string) bool { return strings.HasSuffix(value, "b") } // NextTo (empty) { tree := New[string]() it := tree.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") } } // NextTo (not found) { tree := New[string]() tree.Enqueue("xx") tree.Enqueue("yy") it := tree.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") } } // NextTo (found) { tree := New[string]() 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 != "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 != "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 string) bool { return strings.HasSuffix(value, "b") } // PrevTo (empty) { tree := New[string]() it := tree.Iterator() it.End() for it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty list") } } // PrevTo (not found) { tree := New[string]() 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 := New[string]() 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 != "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 != "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 := New[string]() queue.Enqueue("c") queue.Enqueue("b") queue.Enqueue("a") var err error assert := func() { 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 { 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(`["a","b","c"]`), &queue) if err != nil { t.Errorf("Got error %v", err) } assert() } func TestBTreeString(t *testing.T) { 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[Element], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { queue.Enqueue(Element{}) } } } 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() } } } func BenchmarkBinaryQueueDequeue100(b *testing.B) { b.StopTimer() size := 100 queue := NewWith[Element](byPriority) for n := 0; n < size; n++ { queue.Enqueue(Element{}) } b.StartTimer() benchmarkDequeue(b, queue, size) } func BenchmarkBinaryQueueDequeue1000(b *testing.B) { b.StopTimer() size := 1000 queue := NewWith[Element](byPriority) for n := 0; n < size; n++ { queue.Enqueue(Element{}) } b.StartTimer() benchmarkDequeue(b, queue, size) } func BenchmarkBinaryQueueDequeue10000(b *testing.B) { b.StopTimer() size := 10000 queue := NewWith[Element](byPriority) for n := 0; n < size; n++ { queue.Enqueue(Element{}) } b.StartTimer() benchmarkDequeue(b, queue, size) } func BenchmarkBinaryQueueDequeue100000(b *testing.B) { b.StopTimer() size := 100000 queue := NewWith[Element](byPriority) for n := 0; n < size; n++ { queue.Enqueue(Element{}) } 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[Element](byPriority) for n := 0; n < size; n++ { queue.Enqueue(Element{}) } b.StartTimer() benchmarkEnqueue(b, queue, size) } func BenchmarkBinaryQueueEnqueue10000(b *testing.B) { b.StopTimer() size := 10000 queue := NewWith[Element](byPriority) for n := 0; n < size; n++ { queue.Enqueue(Element{}) } b.StartTimer() benchmarkEnqueue(b, queue, size) } func BenchmarkBinaryQueueEnqueue100000(b *testing.B) { b.StopTimer() size := 100000 queue := NewWith[Element](byPriority) for n := 0; n < size; n++ { queue.Enqueue(Element{}) } b.StartTimer() benchmarkEnqueue(b, queue, size) } ================================================ FILE: queues/priorityqueue/serialization.go ================================================ // 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/v2/containers" ) // Assert Serialization implementation var _ containers.JSONSerializer = (*Queue[int])(nil) var _ containers.JSONDeserializer = (*Queue[int])(nil) // ToJSON outputs the JSON representation of the queue. func (queue *Queue[T]) ToJSON() ([]byte, error) { return queue.heap.ToJSON() } // FromJSON populates the queue from the input JSON representation. func (queue *Queue[T]) FromJSON(data []byte) error { return queue.heap.FromJSON(data) } // UnmarshalJSON @implements json.Unmarshaler func (queue *Queue[T]) UnmarshalJSON(bytes []byte) error { return queue.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (queue *Queue[T]) MarshalJSON() ([]byte, error) { return queue.ToJSON() } ================================================ FILE: queues/queues.go ================================================ // 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/v2/containers" // Queue interface that all queues implement type Queue[T comparable] interface { Enqueue(value T) Dequeue() (value T, ok bool) Peek() (value T, ok bool) containers.Container[T] // Empty() bool // Size() int // Clear() // Values() []interface{} // String() string } ================================================ FILE: sets/hashset/hashset.go ================================================ // 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. // // Structure is not thread safe. // // References: http://en.wikipedia.org/wiki/Set_%28abstract_data_type%29 package hashset import ( "fmt" "strings" "github.com/emirpasic/gods/v2/sets" ) // Assert Set implementation var _ sets.Set[int] = (*Set[int])(nil) // Set holds elements in go's native map 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[T comparable](values ...T) *Set[T] { set := &Set[T]{items: make(map[T]struct{})} if len(values) > 0 { set.Add(values...) } return set } // Add adds the items (one or more) to the set. 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[T]) Remove(items ...T) { for _, item := range items { delete(set.items, item) } } // 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[T]) Contains(items ...T) 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[T]) Empty() bool { return set.Size() == 0 } // Size returns number of elements within the set. func (set *Set[T]) Size() int { return len(set.items) } // Clear clears all values in the set. func (set *Set[T]) Clear() { set.items = make(map[T]struct{}) } // Values returns all items in the set. func (set *Set[T]) Values() []T { values := make([]T, set.Size()) count := 0 for item := range set.items { values[count] = item count++ } return values } // String returns a string representation of container func (set *Set[T]) String() string { str := "HashSet\n" items := []string{} for k := range set.items { items = append(items, fmt.Sprintf("%v", k)) } 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[T]) Intersection(another *Set[T]) *Set[T] { result := New[T]() // 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[T]) Union(another *Set[T]) *Set[T] { result := New[T]() 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[T]) Difference(another *Set[T]) *Set[T] { result := New[T]() for item := range set.items { if _, contains := another.items[item]; !contains { result.Add(item) } } return result } ================================================ FILE: sets/hashset/hashset_test.go ================================================ // 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" "strings" "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[int]() 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[int]() 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[int]() 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 TestSetSerialization(t *testing.T) { set := New[string]() 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() bytes, err := set.ToJSON() assert() err = set.FromJSON(bytes) assert() bytes, err = json.Marshal([]interface{}{"a", "b", "c", set}) if err != nil { t.Errorf("Got error %v", err) } 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[int]() c.Add(1) if !strings.HasPrefix(c.String(), "HashSet") { t.Errorf("String should start with container name") } } func TestSetIntersection(t *testing.T) { set := New[string]() another := New[string]() 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[string]() another := New[string]() 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[string]() another := New[string]() 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[int], 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[int], 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[int], 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[int]() 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[int]() 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[int]() 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[int]() 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[int]() b.StartTimer() benchmarkAdd(b, set, size) } func BenchmarkHashSetAdd1000(b *testing.B) { b.StopTimer() size := 1000 set := New[int]() 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[int]() 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[int]() 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[int]() 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[int]() 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[int]() 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[int]() for n := 0; n < size; n++ { set.Add(n) } b.StartTimer() benchmarkRemove(b, set, size) } ================================================ FILE: sets/hashset/serialization.go ================================================ // 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/v2/containers" ) // Assert Serialization implementation var _ containers.JSONSerializer = (*Set[int])(nil) var _ containers.JSONDeserializer = (*Set[int])(nil) // ToJSON outputs the JSON representation of the set. func (set *Set[T]) ToJSON() ([]byte, error) { return json.Marshal(set.Values()) } // FromJSON populates the set from the input JSON representation. func (set *Set[T]) FromJSON(data []byte) error { var elements []T err := json.Unmarshal(data, &elements) if err == nil { set.Clear() set.Add(elements...) } return err } // UnmarshalJSON @implements json.Unmarshaler func (set *Set[T]) UnmarshalJSON(bytes []byte) error { return set.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (set *Set[T]) MarshalJSON() ([]byte, error) { return set.ToJSON() } ================================================ FILE: sets/linkedhashset/enumerable.go ================================================ // 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/v2/containers" // Assert Enumerable implementation 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[T]) Each(f func(index int, value T)) { 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[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())) } return newSet } // Select returns a new container containing all elements for which the given function returns a true value. 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()) { 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[T]) Any(f func(index int, value T) 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[T]) All(f func(index int, value T) 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[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() } } var t T return -1, t } ================================================ FILE: sets/linkedhashset/iterator.go ================================================ // 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/v2/containers" "github.com/emirpasic/gods/v2/lists/doublylinkedlist" ) // Assert Iterator implementation var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator holding the iterator's state 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[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[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[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[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[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[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[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[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[T]) 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[T]) NextTo(f func(index int, value T) 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[T]) PrevTo(f func(index int, value T) bool) bool { for iterator.Prev() { index, value := iterator.Index(), iterator.Value() if f(index, value) { return true } } return false } ================================================ FILE: sets/linkedhashset/linkedhashset.go ================================================ // 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 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. // // Structure is not thread safe. // // References: http://en.wikipedia.org/wiki/Set_%28abstract_data_type%29 package linkedhashset import ( "fmt" "strings" "github.com/emirpasic/gods/v2/lists/doublylinkedlist" "github.com/emirpasic/gods/v2/sets" ) // Assert Set implementation var _ sets.Set[int] = (*Set[int])(nil) // Set holds elements in go's native map 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[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...) } return 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[T]) Add(items ...T) { for _, item := range items { if _, contains := set.table[item]; !contains { set.table[item] = itemExists set.ordering.Append(item) } } } // Remove removes the items (one or more) from the set. // Slow operation, worst-case O(n^2). func (set *Set[T]) Remove(items ...T) { for _, item := range items { if _, contains := set.table[item]; contains { delete(set.table, item) index := set.ordering.IndexOf(item) set.ordering.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[T]) Contains(items ...T) bool { for _, item := range items { if _, contains := set.table[item]; !contains { return false } } return true } // Empty returns true if set does not contain any elements. func (set *Set[T]) Empty() bool { return set.Size() == 0 } // Size returns number of elements within the set. func (set *Set[T]) Size() int { return set.ordering.Size() } // Clear clears all values in the set. func (set *Set[T]) Clear() { set.table = make(map[T]struct{}) set.ordering.Clear() } // Values returns all items in the set. func (set *Set[T]) Values() []T { values := make([]T, 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[T]) 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 } // 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[T]) Intersection(another *Set[T]) *Set[T] { result := New[T]() // 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[T]) Union(another *Set[T]) *Set[T] { result := New[T]() 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[T]) Difference(another *Set[T]) *Set[T] { result := New[T]() for item := range set.table { if _, contains := another.table[item]; !contains { result.Add(item) } } return result } ================================================ FILE: sets/linkedhashset/linkedhashset_test.go ================================================ // 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" "fmt" "strings" "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[int]() 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[int]() 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[int]() 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[string]() set.Add("c", "a", "b") set.Each(func(index int, value string) { 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[string]() set.Add("c", "a", "b") 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) } 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[string]() set.Add("c", "a", "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")) 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[string]() set.Add("c", "a", "b") 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 string) bool { return value == "x" }) if any != false { t.Errorf("Got %v expected %v", any, false) } } func TestSetAll(t *testing.T) { set := New[string]() set.Add("c", "a", "b") 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 string) bool { return value >= "a" && value <= "b" }) if all != false { t.Errorf("Got %v expected %v", all, false) } } func TestSetFind(t *testing.T) { set := New[string]() set.Add("c", "a", "b") 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 string) bool { return value == "x" }) 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[string]() set.Add("c", "a", "b") } func TestSetIteratorPrevOnEmpty(t *testing.T) { set := New[string]() it := set.Iterator() for it.Prev() { t.Errorf("Shouldn't iterate on empty set") } } func TestSetIteratorNext(t *testing.T) { set := New[string]() 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[string]() 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[string]() 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[string]() 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[string]() 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[string]() 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 TestSetIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" seek := func(index int, value string) bool { return strings.HasSuffix(value, "b") } // NextTo (empty) { set := New[string]() it := set.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty set") } } // NextTo (not found) { set := New[string]() set.Add("xx", "yy") it := set.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty set") } } // NextTo (found) { 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 != "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 != "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 string) bool { return strings.HasSuffix(value, "b") } // PrevTo (empty) { set := New[string]() it := set.Iterator() it.End() for it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty set") } } // PrevTo (not found) { set := New[string]() 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[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 != "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 != "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[string]() 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() bytes, err := set.ToJSON() assert() err = set.FromJSON(bytes) assert() bytes, err = json.Marshal([]interface{}{"a", "b", "c", set}) if err != nil { t.Errorf("Got error %v", err) } 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[int]() c.Add(1) if !strings.HasPrefix(c.String(), "LinkedHashSet") { t.Errorf("String should start with container name") } } func TestSetIntersection(t *testing.T) { set := New[string]() another := New[string]() 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[string]() another := New[string]() 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[string]() another := New[string]() 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[int], 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[int], 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[int], 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[int]() 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[int]() 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[int]() 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[int]() 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[int]() b.StartTimer() benchmarkAdd(b, set, size) } func BenchmarkHashSetAdd1000(b *testing.B) { b.StopTimer() size := 1000 set := New[int]() 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[int]() 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[int]() 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[int]() 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[int]() 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[int]() 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[int]() for n := 0; n < size; n++ { set.Add(n) } b.StartTimer() benchmarkRemove(b, set, size) } ================================================ FILE: sets/linkedhashset/serialization.go ================================================ // 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/v2/containers" ) // Assert Serialization implementation var _ containers.JSONSerializer = (*Set[int])(nil) var _ containers.JSONDeserializer = (*Set[int])(nil) // ToJSON outputs the JSON representation of the set. func (set *Set[T]) ToJSON() ([]byte, error) { return json.Marshal(set.Values()) } // FromJSON populates the set from the input JSON representation. func (set *Set[T]) FromJSON(data []byte) error { var elements []T err := json.Unmarshal(data, &elements) if err == nil { set.Clear() set.Add(elements...) } return err } // UnmarshalJSON @implements json.Unmarshaler func (set *Set[T]) UnmarshalJSON(bytes []byte) error { return set.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (set *Set[T]) MarshalJSON() ([]byte, error) { return set.ToJSON() } ================================================ FILE: sets/sets.go ================================================ // 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. // // 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/v2/containers" ) // Set interface that all sets implement type Set[T comparable] interface { Add(elements ...T) Remove(elements ...T) Contains(elements ...T) bool containers.Container[T] // Empty() bool // Size() int // Clear() // Values() []interface{} // String() string } ================================================ FILE: sets/treeset/enumerable.go ================================================ // 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 ( "github.com/emirpasic/gods/v2/containers" rbt "github.com/emirpasic/gods/v2/trees/redblacktree" ) // Assert Enumerable implementation 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[T]) Each(f func(index int, value T)) { 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[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())) } return newSet } // Select returns a new container containing all elements for which the given function returns a true value. 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()) { 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[T]) Any(f func(index int, value T) 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[T]) All(f func(index int, value T) 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[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() } } var t T return -1, t } ================================================ FILE: sets/treeset/iterator.go ================================================ // 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 ( "github.com/emirpasic/gods/v2/containers" rbt "github.com/emirpasic/gods/v2/trees/redblacktree" ) // Assert Iterator implementation var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. type Iterator[T comparable] struct { index int iterator *rbt.Iterator[T, struct{}] tree *rbt.Tree[T, struct{}] } // Iterator holding the iterator's state 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[T]) 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[T]) 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[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[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[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[T]) 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[T]) 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[T]) 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[T]) NextTo(f func(index int, value T) 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[T]) PrevTo(f func(index int, value T) bool) bool { for iterator.Prev() { index, value := iterator.Index(), iterator.Value() if f(index, value) { return true } } return false } ================================================ FILE: sets/treeset/serialization.go ================================================ // 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/v2/containers" ) // Assert Serialization implementation var _ containers.JSONSerializer = (*Set[int])(nil) var _ containers.JSONDeserializer = (*Set[int])(nil) // ToJSON outputs the JSON representation of the set. func (set *Set[T]) ToJSON() ([]byte, error) { return json.Marshal(set.Values()) } // FromJSON populates the set from the input JSON representation. func (set *Set[T]) FromJSON(data []byte) error { var elements []T err := json.Unmarshal(data, &elements) if err == nil { set.Clear() set.Add(elements...) } return err } // UnmarshalJSON @implements json.Unmarshaler func (set *Set[T]) UnmarshalJSON(bytes []byte) error { return set.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (set *Set[T]) MarshalJSON() ([]byte, error) { return set.ToJSON() } ================================================ FILE: sets/treeset/treeset.go ================================================ // 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. // // Structure is not thread safe. // // Reference: http://en.wikipedia.org/wiki/Set_%28abstract_data_type%29 package treeset import ( "cmp" "fmt" "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[int] = (*Set[int])(nil) // Set holds elements in a red-black tree type Set[T comparable] struct { tree *rbt.Tree[T, struct{}] } var itemExists = struct{}{} func New[T cmp.Ordered](values ...T) *Set[T] { return NewWith[T](cmp.Compare[T], values...) } // 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...) } return set } // Add adds the items (one or more) to the set. 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[T]) Remove(items ...T) { for _, item := range items { set.tree.Remove(item) } } // 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[T]) Contains(items ...T) bool { for _, item := range items { if _, contains := set.tree.Get(item); !contains { return false } } return true } // Empty returns true if set does not contain any elements. func (set *Set[T]) Empty() bool { return set.tree.Size() == 0 } // Size returns number of elements within the set. func (set *Set[T]) Size() int { return set.tree.Size() } // Clear clears all values in the set. func (set *Set[T]) Clear() { set.tree.Clear() } // Values returns all items in the set. func (set *Set[T]) Values() []T { return set.tree.Keys() } // String returns a string representation of container func (set *Set[T]) String() string { str := "TreeSet\n" items := []string{} for _, v := range set.tree.Keys() { items = append(items, fmt.Sprintf("%v", v)) } 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[T]) Intersection(another *Set[T]) *Set[T] { 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[T]) Union(another *Set[T]) *Set[T] { 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[T]) Difference(another *Set[T]) *Set[T] { 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 } ================================================ FILE: sets/treeset/treeset_test.go ================================================ // 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" "fmt" "strings" "testing" "github.com/emirpasic/gods/v2/testutils" ) func TestSetNew(t *testing.T) { set := New[int](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 := New[int]() 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) } testutils.SameElements(t, set.Values(), []int{1, 2, 3}) } func TestSetContains(t *testing.T) { set := New[int]() 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) } } func TestSetRemove(t *testing.T) { set := New[int]() 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[string]() set.Add("c", "a", "b") set.Each(func(index int, value string) { 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") } }) } func TestSetMap(t *testing.T) { set := New[string]() set.Add("c", "a", "b") 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) } 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) } } func TestSetSelect(t *testing.T) { set := New[string]() set.Add("c", "a", "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")) 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[string]() set.Add("c", "a", "b") 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 string) bool { return value == "x" }) if any != false { t.Errorf("Got %v expected %v", any, false) } } func TestSetAll(t *testing.T) { set := New[string]() set.Add("c", "a", "b") 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 string) bool { return value >= "a" && value <= "b" }) if all != false { t.Errorf("Got %v expected %v", all, false) } } func TestSetFind(t *testing.T) { set := New[string]() set.Add("c", "a", "b") 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 string) bool { return value == "x" }) 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[string]() set.Add("c", "a", "b") } func TestSetIteratorNextOnEmpty(t *testing.T) { set := New[string]() it := set.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty set") } } func TestSetIteratorPrevOnEmpty(t *testing.T) { set := New[string]() it := set.Iterator() for it.Prev() { t.Errorf("Shouldn't iterate on empty set") } } func TestSetIteratorNext(t *testing.T) { set := New[string]() 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, "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) } } func TestSetIteratorPrev(t *testing.T) { set := New[string]() 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, "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) } } func TestSetIteratorBegin(t *testing.T) { set := New[string]() 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[string]() 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[string]() 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[string]() 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, 2, "c") } } func TestSetIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" seek := func(index int, value string) bool { return strings.HasSuffix(value, "b") } // NextTo (empty) { set := New[string]() it := set.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty set") } } // NextTo (not found) { set := New[string]() set.Add("xx", "yy") it := set.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty set") } } // NextTo (found) { 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 != "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 != "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 string) bool { return strings.HasSuffix(value, "b") } // PrevTo (empty) { set := New[string]() it := set.Iterator() it.End() for it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty set") } } // PrevTo (not found) { set := New[string]() 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[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 != "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 != "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[string]() 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() bytes, err := set.ToJSON() assert() err = set.FromJSON(bytes) assert() bytes, err = json.Marshal([]interface{}{"a", "b", "c", set}) 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[int]() c.Add(1) if !strings.HasPrefix(c.String(), "TreeSet") { t.Errorf("String should start with container name") } } func TestSetIntersection(t *testing.T) { set := New[string]() another := New[string]() 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[string]() another := New[string]() 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[string]() another := New[string]() 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[int], 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[int], 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[int], 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 := New[int]() 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 := New[int]() 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 := New[int]() 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 := New[int]() 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 := New[int]() b.StartTimer() benchmarkAdd(b, set, size) } func BenchmarkTreeSetAdd1000(b *testing.B) { b.StopTimer() size := 1000 set := New[int]() 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 := New[int]() 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 := New[int]() 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 := New[int]() 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 := New[int]() 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 := New[int]() 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 := New[int]() for n := 0; n < size; n++ { set.Add(n) } b.StartTimer() benchmarkRemove(b, set, size) } ================================================ FILE: stacks/arraystack/arraystack.go ================================================ // 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. // // Structure is not thread safe. // // Reference: https://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29#Array package arraystack import ( "fmt" "strings" "github.com/emirpasic/gods/v2/lists/arraylist" "github.com/emirpasic/gods/v2/stacks" ) // Assert Stack implementation var _ stacks.Stack[int] = (*Stack[int])(nil) // Stack holds elements in an array-list type Stack[T comparable] struct { list *arraylist.List[T] } // New instantiates a new empty stack 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[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[T]) Pop() (value T, ok bool) { value, ok = stack.list.Get(stack.list.Size() - 1) stack.list.Remove(stack.list.Size() - 1) return } // 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[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[T]) Empty() bool { return stack.list.Empty() } // Size returns number of elements within the stack. func (stack *Stack[T]) Size() int { return stack.list.Size() } // Clear removes all elements from the stack. func (stack *Stack[T]) Clear() { stack.list.Clear() } // Values returns all elements in the stack (LIFO order). func (stack *Stack[T]) Values() []T { size := stack.list.Size() elements := make([]T, size, size) for i := 1; i <= size; i++ { elements[size-i], _ = stack.list.Get(i - 1) // in reverse (LIFO) } return elements } // String returns a string representation of container func (stack *Stack[T]) String() string { str := "ArrayStack\n" values := []string{} for _, value := range stack.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 (stack *Stack[T]) withinRange(index int) bool { return index >= 0 && index < stack.list.Size() } ================================================ FILE: stacks/arraystack/arraystack_test.go ================================================ // 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 ( "encoding/json" "strings" "testing" "github.com/emirpasic/gods/v2/testutils" ) func TestStackPush(t *testing.T) { stack := New[int]() if actualValue := stack.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } stack.Push(1) stack.Push(2) stack.Push(3) 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 { 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[int]() if actualValue, ok := stack.Peek(); actualValue != 0 || 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[int]() 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 != 0 || 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 TestStackIteratorOnEmpty(t *testing.T) { stack := New[string]() it := stack.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty stack") } } func TestStackIteratorNext(t *testing.T) { stack := New[string]() stack.Push("a") stack.Push("b") stack.Push("c") it := stack.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, "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, 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() { t.Errorf("Shouldn't iterate on empty stack") } } func TestStackIteratorPrev(t *testing.T) { stack := New[string]() stack.Push("a") stack.Push("b") stack.Push("c") it := stack.Iterator() for it.Next() { } 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) } } func TestStackIteratorBegin(t *testing.T) { stack := New[string]() it := stack.Iterator() it.Begin() stack.Push("a") stack.Push("b") stack.Push("c") for it.Next() { } 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") } } func TestStackIteratorEnd(t *testing.T) { stack := New[string]() 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[string]() 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[string]() 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 TestStackIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" seek := func(index int, value string) bool { return strings.HasSuffix(value, "b") } // NextTo (empty) { stack := New[string]() it := stack.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty stack") } } // NextTo (not found) { stack := New[string]() 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[string]() 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 != "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 != "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 string) bool { return strings.HasSuffix(value, "b") } // PrevTo (empty) { stack := New[string]() it := stack.Iterator() it.End() for it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty stack") } } // PrevTo (not found) { stack := New[string]() 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[string]() 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 != "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 != "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[string]() stack.Push("a") stack.Push("b") stack.Push("c") var err error assert := func() { 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) } if err != nil { t.Errorf("Got error %v", err) } } assert() bytes, err := stack.ToJSON() assert() err = stack.FromJSON(bytes) assert() bytes, err = json.Marshal([]interface{}{"a", "b", "c", stack}) if err != nil { t.Errorf("Got error %v", err) } 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[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[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { stack.Push(n) } } } 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() } } } func BenchmarkArrayStackPop100(b *testing.B) { b.StopTimer() size := 100 stack := New[int]() 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[int]() 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[int]() 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[int]() 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[int]() b.StartTimer() benchmarkPush(b, stack, size) } func BenchmarkArrayStackPush1000(b *testing.B) { b.StopTimer() size := 1000 stack := New[int]() 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[int]() 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[int]() for n := 0; n < size; n++ { stack.Push(n) } b.StartTimer() benchmarkPush(b, stack, size) } ================================================ FILE: stacks/arraystack/iterator.go ================================================ // 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/v2/containers" // Assert Iterator implementation var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. 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[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[T]) 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[T]) 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[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[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[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[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[T]) 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[T]) 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[T]) NextTo(f func(index int, value T) 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[T]) PrevTo(f func(index int, value T) bool) bool { for iterator.Prev() { index, value := iterator.Index(), iterator.Value() if f(index, value) { return true } } return false } ================================================ FILE: stacks/arraystack/serialization.go ================================================ // 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/v2/containers" ) // Assert Serialization implementation var _ containers.JSONSerializer = (*Stack[int])(nil) var _ containers.JSONDeserializer = (*Stack[int])(nil) // ToJSON outputs the JSON representation of the stack. func (stack *Stack[T]) ToJSON() ([]byte, error) { return stack.list.ToJSON() } // FromJSON populates the stack from the input JSON representation. func (stack *Stack[T]) FromJSON(data []byte) error { return stack.list.FromJSON(data) } // UnmarshalJSON @implements json.Unmarshaler func (stack *Stack[T]) UnmarshalJSON(bytes []byte) error { return stack.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (stack *Stack[T]) MarshalJSON() ([]byte, error) { return stack.ToJSON() } ================================================ FILE: stacks/linkedliststack/iterator.go ================================================ // 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/v2/containers" // Assert Iterator implementation var _ containers.IteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. 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[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[T]) 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[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[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[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[T]) 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[T]) NextTo(f func(index int, value T) bool) bool { for iterator.Next() { index, value := iterator.Index(), iterator.Value() if f(index, value) { return true } } return false } ================================================ FILE: stacks/linkedliststack/linkedliststack.go ================================================ // 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. // // Structure is not thread safe. // // Reference:https://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29#Linked_list package linkedliststack import ( "fmt" "strings" "github.com/emirpasic/gods/v2/lists/singlylinkedlist" "github.com/emirpasic/gods/v2/stacks" ) // Assert Stack implementation var _ stacks.Stack[int] = (*Stack[int])(nil) // Stack holds elements in a singly-linked-list type Stack[T comparable] struct { list *singlylinkedlist.List[T] } // New nnstantiates a new empty stack 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[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[T]) Pop() (value T, ok bool) { value, ok = stack.list.Get(0) stack.list.Remove(0) return } // 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[T]) Peek() (value T, ok bool) { return stack.list.Get(0) } // Empty returns true if stack does not contain any elements. func (stack *Stack[T]) Empty() bool { return stack.list.Empty() } // Size returns number of elements within the stack. func (stack *Stack[T]) Size() int { return stack.list.Size() } // Clear removes all elements from the stack. func (stack *Stack[T]) Clear() { stack.list.Clear() } // Values returns all elements in the stack (LIFO order). func (stack *Stack[T]) Values() []T { return stack.list.Values() } // String returns a string representation of container func (stack *Stack[T]) String() string { str := "LinkedListStack\n" values := []string{} for _, value := range stack.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 (stack *Stack[T]) withinRange(index int) bool { return index >= 0 && index < stack.list.Size() } ================================================ FILE: stacks/linkedliststack/linkedliststack_test.go ================================================ // 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 ( "encoding/json" "strings" "testing" "github.com/emirpasic/gods/v2/testutils" ) func TestStackPush(t *testing.T) { stack := New[int]() if actualValue := stack.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } stack.Push(1) stack.Push(2) stack.Push(3) 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 { 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[int]() if actualValue, ok := stack.Peek(); actualValue != 0 || 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[int]() 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 != 0 || 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 TestStackIterator(t *testing.T) { stack := New[string]() stack.Push("a") stack.Push("b") stack.Push("c") // Iterator it := stack.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, "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, 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() { t.Errorf("Shouldn't iterate on empty stack") } } func TestStackIteratorBegin(t *testing.T) { stack := New[string]() it := stack.Iterator() it.Begin() stack.Push("a") stack.Push("b") stack.Push("c") for it.Next() { } 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") } } func TestStackIteratorFirst(t *testing.T) { stack := New[string]() 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 TestStackIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" seek := func(index int, value string) bool { return strings.HasSuffix(value, "b") } // NextTo (empty) { stack := New[string]() it := stack.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty stack") } } // NextTo (not found) { stack := New[string]() 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[string]() 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 != "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 != "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[string]() stack.Push("a") stack.Push("b") stack.Push("c") var err error assert := func() { 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) } if err != nil { t.Errorf("Got error %v", err) } } assert() bytes, err := stack.ToJSON() assert() err = stack.FromJSON(bytes) assert() bytes, err = json.Marshal([]interface{}{"a", "b", "c", stack}) if err != nil { t.Errorf("Got error %v", err) } 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[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[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { stack.Push(n) } } } 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() } } } func BenchmarkLinkedListStackPop100(b *testing.B) { b.StopTimer() size := 100 stack := New[int]() 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[int]() 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[int]() 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[int]() 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[int]() b.StartTimer() benchmarkPush(b, stack, size) } func BenchmarkLinkedListStackPush1000(b *testing.B) { b.StopTimer() size := 1000 stack := New[int]() 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[int]() 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[int]() for n := 0; n < size; n++ { stack.Push(n) } b.StartTimer() benchmarkPush(b, stack, size) } ================================================ FILE: stacks/linkedliststack/serialization.go ================================================ // 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/v2/containers" ) // Assert Serialization implementation var _ containers.JSONSerializer = (*Stack[int])(nil) var _ containers.JSONDeserializer = (*Stack[int])(nil) // ToJSON outputs the JSON representation of the stack. func (stack *Stack[T]) ToJSON() ([]byte, error) { return stack.list.ToJSON() } // FromJSON populates the stack from the input JSON representation. func (stack *Stack[T]) FromJSON(data []byte) error { return stack.list.FromJSON(data) } // UnmarshalJSON @implements json.Unmarshaler func (stack *Stack[T]) UnmarshalJSON(bytes []byte) error { return stack.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (stack *Stack[T]) MarshalJSON() ([]byte, error) { return stack.ToJSON() } ================================================ FILE: stacks/stacks.go ================================================ // 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. // // 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/v2/containers" // Stack interface that all stacks implement type Stack[T any] interface { Push(value T) Pop() (value T, ok bool) Peek() (value T, ok bool) containers.Container[T] // Empty() bool // Size() int // Clear() // Values() []interface{} // String() string } ================================================ FILE: testutils/testutils.go ================================================ 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) } } ================================================ FILE: trees/avltree/avltree.go ================================================ // 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 avltree implements an AVL balanced binary tree. // // Structure is not thread safe. // // References: https://en.wikipedia.org/wiki/AVL_tree package avltree import ( "cmp" "fmt" "github.com/emirpasic/gods/v2/trees" "github.com/emirpasic/gods/v2/utils" ) // Assert Tree implementation var _ trees.Tree[int] = (*Tree[string, int])(nil) // Tree holds elements of the AVL 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[K comparable, V any] struct { Key K Value V Parent *Node[K, V] // Parent node Children [2]*Node[K, V] // Children nodes b int8 } // 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]} } // 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 (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 (tree *Tree[K, V]) Get(key K) (value V, found bool) { n := tree.GetNode(key) if n != nil { return n.Value, true } 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[K, V]) GetNode(key K) *Node[K, V] { n := tree.Root for n != nil { cmp := tree.Comparator(key, n.Key) switch { case cmp == 0: return n case cmp < 0: n = n.Children[0] case cmp > 0: n = n.Children[1] } } return n } // Remove remove the node from the tree by key. // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree[K, V]) Remove(key K) { tree.remove(key, &tree.Root) } // Empty returns true if tree does not contain any nodes. func (tree *Tree[K, V]) Empty() bool { return tree.size == 0 } // Size returns the number of elements stored in the tree. 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[K, V]) 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 (tree *Tree[K, V]) Keys() []K { keys := make([]K, 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[K, V]) Values() []V { values := make([]V, tree.size) it := tree.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 (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 (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. // 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[K, V]) Floor(key K) (floor *Node[K, V], found bool) { found = false n := tree.Root for n != nil { c := tree.Comparator(key, n.Key) switch { case c == 0: return n, true case c < 0: n = n.Children[0] case c > 0: floor, found = n, true n = n.Children[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 (tree *Tree[K, V]) Ceiling(key K) (floor *Node[K, V], found bool) { found = false n := tree.Root for n != nil { c := tree.Comparator(key, n.Key) switch { case c == 0: return n, true case c < 0: floor, found = n, true n = n.Children[0] case c > 0: n = n.Children[1] } } if found { return } return nil, false } // Clear removes all nodes from the tree. func (tree *Tree[K, V]) Clear() { tree.Root = nil tree.size = 0 } // String returns a string representation of container func (tree *Tree[K, V]) String() string { str := "AVLTree\n" if !tree.Empty() { output(tree.Root, "", true, &str) } return str } func (n *Node[K, V]) String() string { return fmt.Sprintf("%v", n.Key) } func (tree *Tree[K, V]) put(key K, value V, p *Node[K, V], qp **Node[K, V]) bool { q := *qp if q == nil { tree.size++ *qp = &Node[K, V]{Key: key, Value: value, Parent: p} return true } c := tree.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 = tree.put(key, value, q, &q.Children[a]) if fix { return putFix(int8(c), qp) } return false } func (tree *Tree[K, V]) remove(key K, qp **Node[K, V]) bool { q := *qp if q == nil { return false } c := tree.Comparator(key, q.Key) if c == 0 { tree.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 } if c < 0 { c = -1 } else { c = 1 } a := (c + 1) / 2 fix := tree.remove(key, &q.Children[a]) if fix { return removeFix(int8(-c), qp) } return false } 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 *minVal = q.Value if q.Children[1] != nil { q.Children[1].Parent = q.Parent } *qp = q.Children[1] return true } fix := removeMin(&q.Children[0], minKey, minVal) if fix { return removeFix(1, qp) } return false } func putFix[K comparable, V any](c int8, t **Node[K, V]) bool { s := *t if s.b == 0 { s.b = c return true } if s.b == -c { s.b = 0 return false } if s.Children[(c+1)/2].b == c { s = singlerot(c, s) } else { s = doublerot(c, s) } *t = s return false } func removeFix[K comparable, V any](c int8, t **Node[K, V]) 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.Children[a].b == 0 { s = rotate(c, s) s.b = -c *t = s return false } if s.Children[a].b == c { s = singlerot(c, s) } else { s = doublerot(c, s) } *t = s return true } 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[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]) p := rotate(c, s) 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 return p } 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] if s.Children[a] != nil { s.Children[a].Parent = s } r.Children[a^1] = s r.Parent = s.Parent s.Parent = r return r } func (tree *Tree[K, V]) bottom(d int) *Node[K, V] { n := tree.Root if n == nil { return nil } for c := n.Children[d]; c != nil; c = n.Children[d] { n = c } return n } // Prev returns the previous element in an inorder // walk of the AVL tree. 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[K, V]) Next() *Node[K, V] { return n.walk1(1) } func (n *Node[K, V]) walk1(a int) *Node[K, V] { if n == nil { return nil } if n.Children[a] != nil { n = n.Children[a] for n.Children[a^1] != nil { n = n.Children[a^1] } return n } p := n.Parent for p != nil && p.Children[a] == n { n = p p = p.Parent } return p } 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 { newPrefix += "│ " } else { newPrefix += " " } output(node.Children[1], newPrefix, false, str) } *str += prefix if isTail { *str += "└── " } else { *str += "┌── " } *str += node.String() + "\n" if node.Children[0] != nil { newPrefix := prefix if isTail { newPrefix += " " } else { newPrefix += "│ " } output(node.Children[0], newPrefix, true, str) } } ================================================ FILE: trees/avltree/avltree_test.go ================================================ // 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" "slices" "strings" "testing" ) func TestAVLTreeGet(t *testing.T) { tree := New[int, string]() 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 := New[int, string]() 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 := 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 := tree.Values(), []string{"a", "b", "c", "d", "e", "f", "g"}; !slices.Equal(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, "", false}, } for _, test := range tests1 { // retrievals actualValue, actualFound := tree.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } } } func TestAVLTreeRemove(t *testing.T) { tree := New[int, string]() 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 := tree.Keys(), []int{1, 2, 3, 4}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", 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 { t.Errorf("Got %v expected %v", actualValue, 7) } tests2 := [][]interface{}{ {1, "a", true}, {2, "b", true}, {3, "c", true}, {4, "d", true}, {5, "", false}, {6, "", false}, {7, "", false}, {8, "", false}, } for _, test := range tests2 { actualValue, actualFound := tree.Get(test[0].(int)) 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 := tree.Keys(), []int{}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", 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 { t.Errorf("Got %v expected %v", empty, true) } } func TestAVLTreeLeftAndRight(t *testing.T) { tree := New[int, string]() 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.Left().Key, 1; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } if actualValue, expectedValue := tree.Left().Value, "x"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } if actualValue, expectedValue := tree.Right().Key, 7; actualValue != expectedValue { t.Errorf("Got %v expected %v", 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 := New[int, string]() 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 TestAVLTreeIteratorNextOnEmpty(t *testing.T) { tree := New[int, string]() it := tree.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty tree") } } func TestAVLTreeIteratorPrevOnEmpty(t *testing.T) { tree := New[int, string]() it := tree.Iterator() for it.Prev() { t.Errorf("Shouldn't iterate on empty tree") } } func TestAVLTreeIterator1Next(t *testing.T) { tree := New[int, string]() 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() 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 TestAVLTreeIterator1Prev(t *testing.T) { tree := New[int, string]() 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() 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 TestAVLTreeIterator2Next(t *testing.T) { tree := New[int, string]() tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") it := tree.Iterator() count := 0 for it.Next() { count++ key := it.Key() 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 TestAVLTreeIterator2Prev(t *testing.T) { tree := New[int, string]() 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() 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 TestAVLTreeIterator3Next(t *testing.T) { tree := New[int, string]() tree.Put(1, "a") it := tree.Iterator() count := 0 for it.Next() { count++ key := it.Key() 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 TestAVLTreeIterator3Prev(t *testing.T) { tree := New[int, string]() tree.Put(1, "a") it := tree.Iterator() for it.Next() { } countDown := tree.size for it.Prev() { key := it.Key() 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 TestAVLTreeIterator4Next(t *testing.T) { tree := New[int, int]() 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() 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 TestAVLTreeIterator4Prev(t *testing.T) { tree := New[int, int]() 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() 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 TestAVLTreeIteratorBegin(t *testing.T) { tree := New[int, string]() tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") it := tree.Iterator() if it.Key() != 0 { t.Errorf("Got %v expected %v", it.Key(), 0) } it.Begin() if it.Key() != 0 { t.Errorf("Got %v expected %v", it.Key(), 0) } for it.Next() { } it.Begin() if it.Key() != 0 { t.Errorf("Got %v expected %v", it.Key(), 0) } 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 TestAVLTreeIteratorEnd(t *testing.T) { tree := New[int, string]() it := tree.Iterator() if it.Key() != 0 { t.Errorf("Got %v expected %v", it.Key(), 0) } it.End() 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() != 0 { t.Errorf("Got %v expected %v", it.Key(), 0) } 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 TestAVLTreeIteratorFirst(t *testing.T) { tree := New[int, string]() 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 TestAVLTreeIteratorLast(t *testing.T) { tree := New[int, string]() 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 TestAVLTreeIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" seek := func(index int, value string) bool { return strings.HasSuffix(value, "b") } // NextTo (empty) { tree := New[int, string]() it := tree.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty tree") } } // NextTo (not found) { tree := New[int, string]() 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 := New[int, string]() 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 != "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 != "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 int, value string) bool { return strings.HasSuffix(value, "b") } // PrevTo (empty) { tree := New[int, string]() it := tree.Iterator() it.End() for it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty tree") } } // PrevTo (not found) { tree := New[int, string]() 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 := New[int, string]() 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 != "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 != "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 := New[string, string]() 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, expectedValue := tree.Keys(), []string{"a", "b", "c"}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } 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) } } assert() bytes, err := tree.ToJSON() assert() err = tree.FromJSON(bytes) assert() bytes, err = json.Marshal([]interface{}{"a", "b", "c", tree}) if err != nil { t.Errorf("Got error %v", err) } 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 := New[int, int]() 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[int, struct{}], 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[int, struct{}], 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[int, struct{}], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { tree.Remove(n) } } } func BenchmarkAVLTreeGet100(b *testing.B) { b.StopTimer() size := 100 tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } b.StartTimer() benchmarkGet(b, tree, size) } func BenchmarkAVLTreeGet1000(b *testing.B) { b.StopTimer() size := 1000 tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } b.StartTimer() benchmarkGet(b, tree, size) } func BenchmarkAVLTreeGet10000(b *testing.B) { b.StopTimer() size := 10000 tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } b.StartTimer() benchmarkGet(b, tree, size) } func BenchmarkAVLTreeGet100000(b *testing.B) { b.StopTimer() size := 100000 tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } b.StartTimer() benchmarkGet(b, tree, size) } func BenchmarkAVLTreePut100(b *testing.B) { b.StopTimer() size := 100 tree := New[int, struct{}]() b.StartTimer() benchmarkPut(b, tree, size) } func BenchmarkAVLTreePut1000(b *testing.B) { b.StopTimer() size := 1000 tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } b.StartTimer() benchmarkPut(b, tree, size) } func BenchmarkAVLTreePut10000(b *testing.B) { b.StopTimer() size := 10000 tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } b.StartTimer() benchmarkPut(b, tree, size) } func BenchmarkAVLTreePut100000(b *testing.B) { b.StopTimer() size := 100000 tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } b.StartTimer() benchmarkPut(b, tree, size) } func BenchmarkAVLTreeRemove100(b *testing.B) { b.StopTimer() size := 100 tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } b.StartTimer() benchmarkRemove(b, tree, size) } func BenchmarkAVLTreeRemove1000(b *testing.B) { b.StopTimer() size := 1000 tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } b.StartTimer() benchmarkRemove(b, tree, size) } func BenchmarkAVLTreeRemove10000(b *testing.B) { b.StopTimer() size := 10000 tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } b.StartTimer() benchmarkRemove(b, tree, size) } func BenchmarkAVLTreeRemove100000(b *testing.B) { b.StopTimer() size := 100000 tree := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } b.StartTimer() benchmarkRemove(b, tree, size) } ================================================ FILE: trees/avltree/iterator.go ================================================ // 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 avltree import "github.com/emirpasic/gods/v2/containers" // Assert Iterator implementation var _ containers.ReverseIteratorWithKey[string, int] = (*Iterator[string, int])(nil) // Iterator holding the iterator's state type Iterator[K comparable, V any] struct { tree *Tree[K, V] node *Node[K, V] 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[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[K, V]) Next() bool { switch iterator.position { case begin: iterator.position = between iterator.node = iterator.tree.Left() case between: iterator.node = iterator.node.Next() } if iterator.node == nil { iterator.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 (iterator *Iterator[K, V]) Prev() bool { switch iterator.position { case end: iterator.position = between iterator.node = iterator.tree.Right() case between: iterator.node = iterator.node.Prev() } if iterator.node == nil { iterator.position = begin return false } return true } // Value returns the current element's value. // Does not modify the state of the iterator. func (iterator *Iterator[K, V]) Value() (v V) { if iterator.node == 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[K, V]) Key() (k K) { if iterator.node == 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[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[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[K, V]) 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[K, V]) 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[K, V]) 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[K, V]) NextTo(f func(key K, value V) 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[K, V]) PrevTo(f func(key K, value V) bool) bool { for iterator.Prev() { key, value := iterator.Key(), iterator.Value() if f(key, value) { return true } } return false } ================================================ FILE: trees/avltree/serialization.go ================================================ // 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/v2/containers" ) // Assert Serialization implementation 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[K, V]) ToJSON() ([]byte, error) { elements := make(map[K]V) it := tree.Iterator() for it.Next() { elements[it.Key()] = it.Value() } return json.Marshal(&elements) } // FromJSON populates the tree from the input JSON representation. func (tree *Tree[K, V]) FromJSON(data []byte) error { elements := make(map[K]V) err := json.Unmarshal(data, &elements) if err != nil { return err } tree.Clear() for key, value := range elements { tree.Put(key, value) } return nil } // UnmarshalJSON @implements json.Unmarshaler func (tree *Tree[K, V]) UnmarshalJSON(bytes []byte) error { return tree.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (tree *Tree[K, V]) MarshalJSON() ([]byte, error) { return tree.ToJSON() } ================================================ FILE: trees/binaryheap/binaryheap.go ================================================ // 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. // // 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 ( "cmp" "fmt" "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[int] = (*Heap[int])(nil) // Heap holds elements in an array-list type Heap[T comparable] struct { list *arraylist.List[T] Comparator utils.Comparator[T] } // 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]} } // 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[T]) Push(values ...T) { 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. // Second return parameter is true, unless the heap was empty and there was nothing to pop. func (heap *Heap[T]) Pop() (value T, ok bool) { value, ok = heap.list.Get(0) if !ok { return } lastIndex := heap.list.Size() - 1 heap.list.Swap(0, lastIndex) heap.list.Remove(lastIndex) heap.bubbleDown() return } // 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[T]) Peek() (value T, ok bool) { return heap.list.Get(0) } // Empty returns true if heap does not contain any elements. func (heap *Heap[T]) Empty() bool { return heap.list.Empty() } // Size returns number of elements within the heap. func (heap *Heap[T]) Size() int { return heap.list.Size() } // Clear removes all elements from the heap. func (heap *Heap[T]) Clear() { heap.list.Clear() } // Values returns all elements in the heap. 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() } return values } // String returns a string representation of container func (heap *Heap[T]) String() string { str := "BinaryHeap\n" values := []string{} for it := heap.Iterator(); it.Next(); { values = append(values, fmt.Sprintf("%v", it.Value())) } str += strings.Join(values, ", ") 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. 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[T]) bubbleDownIndex(index int) { size := heap.list.Size() for leftIndex := index<<1 + 1; leftIndex < size; leftIndex = index<<1 + 1 { rightIndex := index<<1 + 2 smallerIndex := leftIndex leftValue, _ := heap.list.Get(leftIndex) rightValue, _ := heap.list.Get(rightIndex) 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 { heap.list.Swap(index, smallerIndex) } else { break } index = smallerIndex } } // 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[T]) bubbleUp() { index := heap.list.Size() - 1 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 { break } heap.list.Swap(index, parentIndex) index = parentIndex } } // Check that the index is within bounds of the list func (heap *Heap[T]) withinRange(index int) bool { return index >= 0 && index < heap.list.Size() } ================================================ FILE: trees/binaryheap/binaryheap_test.go ================================================ // 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 ( "encoding/json" "math/rand" "slices" "strings" "testing" ) func TestBinaryHeapPush(t *testing.T) { heap := New[int]() if actualValue := heap.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } heap.Push(3) heap.Push(2) heap.Push(1) 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) } 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 TestBinaryHeapPushBulk(t *testing.T) { heap := New[int]() heap.Push(15, 20, 3, 1, 2) 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) } } func TestBinaryHeapPop(t *testing.T) { heap := New[int]() if actualValue := heap.Empty(); actualValue != true { t.Errorf("Got %v expected %v", actualValue, true) } 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) } 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 != 0 || 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 := New[int]() rand.Seed(3) for i := 0; i < 10000; i++ { r := int(rand.Int31n(30)) heap.Push(r) } prev, _ := heap.Pop() for !heap.Empty() { curr, _ := heap.Pop() if prev > curr { t.Errorf("Heap property invalidated. prev: %v current: %v", prev, curr) } prev = curr } } func TestBinaryHeapIteratorOnEmpty(t *testing.T) { heap := New[int]() it := heap.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty heap") } } func TestBinaryHeapIteratorNext(t *testing.T) { heap := New[int]() heap.Push(3) heap.Push(2) heap.Push(1) it := heap.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 TestBinaryHeapIteratorPrev(t *testing.T) { heap := New[int]() heap.Push(3) heap.Push(2) heap.Push(1) it := heap.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 TestBinaryHeapIteratorBegin(t *testing.T) { heap := New[int]() it := heap.Iterator() it.Begin() heap.Push(2) heap.Push(3) heap.Push(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 TestBinaryHeapIteratorEnd(t *testing.T) { heap := New[int]() 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) 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 != 3 { t.Errorf("Got %v,%v expected %v,%v", index, value, heap.Size()-1, 3) } } func TestBinaryHeapIteratorFirst(t *testing.T) { heap := New[int]() it := heap.Iterator() if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } 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) } 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 := New[int]() 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) 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 TestBinaryHeapIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" seek := func(index int, value string) bool { return strings.HasSuffix(value, "b") } // NextTo (empty) { tree := New[string]() it := tree.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") } } // NextTo (not found) { tree := New[string]() tree.Push("xx") tree.Push("yy") it := tree.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty list") } } // NextTo (found) { tree := New[string]() 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 != "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 != "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 string) bool { return strings.HasSuffix(value, "b") } // PrevTo (empty) { tree := New[string]() it := tree.Iterator() it.End() for it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty list") } } // PrevTo (not found) { tree := New[string]() 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 := New[string]() 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 != "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 != "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 := New[string]() heap.Push("c") heap.Push("b") heap.Push("a") var err error assert := func() { 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) } 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() bytes, err := heap.ToJSON() assert() err = heap.FromJSON(bytes) assert() bytes, err = json.Marshal([]interface{}{"a", "b", "c", heap}) if err != nil { t.Errorf("Got error %v", err) } 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 := 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[int], size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { heap.Push(n) } } } 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() } } } func BenchmarkBinaryHeapPop100(b *testing.B) { b.StopTimer() size := 100 heap := New[int]() 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 := New[int]() 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 := New[int]() 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 := New[int]() 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 := New[int]() b.StartTimer() benchmarkPush(b, heap, size) } func BenchmarkBinaryHeapPush1000(b *testing.B) { b.StopTimer() size := 1000 heap := New[int]() 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 := New[int]() 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 := New[int]() for n := 0; n < size; n++ { heap.Push(n) } b.StartTimer() benchmarkPush(b, heap, size) } ================================================ FILE: trees/binaryheap/iterator.go ================================================ // 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/v2/containers" ) // Assert Iterator implementation var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil) // Iterator returns a stateful iterator whose values can be fetched by an index. 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[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[T]) 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[T]) 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[T]) Value() T { 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 } // Index returns the current element's index. // Does not modify the state of the iterator. 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[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[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[T]) 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[T]) 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[T]) NextTo(f func(index int, value T) 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[T]) PrevTo(f func(index int, value T) bool) bool { for iterator.Prev() { index, value := iterator.Index(), iterator.Value() if f(index, value) { return true } } 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< tree.maxEntries() } func (tree *Tree[K, V]) maxChildren() int { return tree.m } func (tree *Tree[K, V]) minChildren() int { return (tree.m + 1) / 2 // ceil(m/2) } func (tree *Tree[K, V]) maxEntries() int { return tree.maxChildren() - 1 } func (tree *Tree[K, V]) minEntries() int { return tree.minChildren() - 1 } 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[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 { mid = (high + low) / 2 compare := tree.Comparator(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 } // searchRecursively searches recursively down the tree starting at the startNode 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 } 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[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[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 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 tree.split(node) return true } 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 return false } return tree.insert(node.Children[insertPosition], entry) } func (tree *Tree[K, V]) split(node *Node[K, V]) { if !tree.shouldSplit(node) { return } if node == tree.Root { tree.splitRoot() return } tree.splitNonRoot(node) } func (tree *Tree[K, V]) splitNonRoot(node *Node[K, V]) { middle := tree.middle() parent := node.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[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) } 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 tree.split(parent) } func (tree *Tree[K, V]) splitRoot() { middle := tree.middle() 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[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[K, V]{ Entries: []*Entry[K, V]{tree.Root.Entries[middle]}, Children: []*Node[K, V]{left, right}, } left.Parent = newRoot right.Parent = newRoot tree.Root = newRoot } func setParent[K comparable, V any](nodes []*Node[K, V], parent *Node[K, V]) { for _, node := range nodes { node.Parent = parent } } func (tree *Tree[K, V]) left(node *Node[K, V]) *Node[K, V] { if tree.Empty() { return nil } current := node for { if tree.isLeaf(current) { return current } current = current.Children[0] } } func (tree *Tree[K, V]) right(node *Node[K, V]) *Node[K, V] { 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[K, V]) leftSibling(node *Node[K, V], key K) (*Node[K, V], 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[K, V]) rightSibling(node *Node[K, V], key K) (*Node[K, V], 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[K, V]) delete(node *Node[K, V], index int) { // deleting from a leaf node if tree.isLeaf(node) { 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 (assumed to exist) 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[K, V]) rebalance(node *Node[K, V], deletedKey K) { // check if rebalancing is needed if node == nil || 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[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[K, V]{leftSiblingRightMostChild}, node.Children...) tree.deleteChild(leftSibling, len(leftSibling.Children)-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) if !tree.isLeaf(rightSibling) { rightSiblingLeftMostChild := rightSibling.Children[0] rightSiblingLeftMostChild.Parent = node node.Children = append(node.Children, rightSiblingLeftMostChild) tree.deleteChild(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[K, V](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) } // 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[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[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[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[K, V]) deleteChild(node *Node[K, V], index int) { if index >= len(node.Children) { return } copy(node.Children[index:], node.Children[index+1:]) node.Children[len(node.Children)-1] = nil node.Children = node.Children[:len(node.Children)-1] } ================================================ FILE: trees/btree/btree_test.go ================================================ // 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" "slices" "strings" "testing" ) func TestBTreeGet1(t *testing.T) { tree := New[int, string](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, "", false}, {1, "a", true}, {2, "b", true}, {3, "c", true}, {4, "d", true}, {5, "e", true}, {6, "f", true}, {7, "g", true}, {8, "", false}, } for _, test := range tests { 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 := New[int, string](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, "", 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, "", false}, } for _, test := range tests { 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 := New[int, string](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 := New[int, int](3) assertValidTree(t, tree, 0) tree.Put(1, 0) assertValidTree(t, tree, 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}, false) tree.Put(3, 2) assertValidTree(t, tree, 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}, 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}, 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}, 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}, 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 TestBTreePut2(t *testing.T) { tree := New[int, int](4) assertValidTree(t, tree, 0) tree.Put(0, 0) assertValidTree(t, tree, 1) 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}, false) tree.Put(1, 1) assertValidTree(t, tree, 3) 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}, false) tree.Put(3, 3) assertValidTree(t, tree, 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], 2, 0, []int{2, 3}, true) tree.Put(4, 4) assertValidTree(t, tree, 5) 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}, 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 TestBTreePut3(t *testing.T) { // http://www.geeksforgeeks.org/b-tree-set-1-insert-2/ tree := New[int, int](6) assertValidTree(t, tree, 0) tree.Put(10, 0) assertValidTree(t, tree, 1) 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}, false) tree.Put(30, 2) assertValidTree(t, tree, 3) 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}, false) tree.Put(50, 4) assertValidTree(t, tree, 5) 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}, 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}, 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}, 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}, 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 := New[int, *struct{}](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) 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) 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) 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) 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) 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 TestBTreeRemove1(t *testing.T) { // empty tree := New[int, int](3) tree.Remove(1) assertValidTree(t, tree, 0) } func TestBTreeRemove2(t *testing.T) { // leaf node (no underflow) tree := New[int, *struct{}](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) } func TestBTreeRemove3(t *testing.T) { // merge with right (underflow) { tree := New[int, *struct{}](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 := New[int, *struct{}](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 := New[int, *struct{}](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 := New[int, *struct{}](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 := New[int, *struct{}](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 := New[int, *struct{}](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 TestBTreeRemove8(t *testing.T) { // use simulator: https://www.cs.usfca.edu/~galles/visualization/BTree.html tree := New[int, *struct{}](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 := New[int, int](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 := New[int, int](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) } 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) { tree := New[int, string](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 TestBTreeIteratorValuesAndKeys(t *testing.T) { tree := New[int, string](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 := 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 := 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 { t.Errorf("Got %v expected %v", actualValue, 7) } } func TestBTreeIteratorNextOnEmpty(t *testing.T) { tree := New[int, string](3) it := tree.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty tree") } } func TestBTreeIteratorPrevOnEmpty(t *testing.T) { tree := New[int, string](3) it := tree.Iterator() for it.Prev() { t.Errorf("Shouldn't iterate on empty tree") } } func TestBTreeIterator1Next(t *testing.T) { tree := New[int, string](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() 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 := New[int, string](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() 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 := New[int, string](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() 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 := New[int, string](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() 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 := New[int, string](3) tree.Put(1, "a") it := tree.Iterator() count := 0 for it.Next() { count++ key := it.Key() 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 := New[int, string](3) tree.Put(1, "a") it := tree.Iterator() for it.Next() { } countDown := tree.size for it.Prev() { key := it.Key() 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 := New[int, int](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() 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 := New[int, int](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() 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 := New[int, string](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 := New[int, string](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 := New[int, string](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 := New[int, string](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 TestBTreeSearch(t *testing.T) { { 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].(int)) 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 := 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}, {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].(int)) 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[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[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) } 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 TestBTreeIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" seek := func(index int, value string) bool { return strings.HasSuffix(value, "b") } // NextTo (empty) { tree := New[int, string](3) it := tree.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty tree") } } // NextTo (not found) { tree := New[int, string](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 := New[int, string](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 != "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 != "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 int, value string) bool { return strings.HasSuffix(value, "b") } // PrevTo (empty) { tree := New[int, string](3) it := tree.Iterator() it.End() for it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty tree") } } // PrevTo (not found) { tree := New[int, string](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 := New[int, string](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 != "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 != "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 := New[string, string](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, expectedValue := tree.Keys(), []string{"a", "b", "c"}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } 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) } } assert() bytes, err := tree.ToJSON() assert() err = tree.FromJSON(bytes) assert() bytes, err = json.Marshal([]interface{}{"a", "b", "c", tree}) if err != nil { t.Errorf("Got error %v", err) } 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 := 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[int, struct{}], 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[int, struct{}], 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[int, struct{}], 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 := New[int, struct{}](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 := New[int, struct{}](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 := New[int, struct{}](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 := New[int, struct{}](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 := New[int, struct{}](128) b.StartTimer() benchmarkPut(b, tree, size) } func BenchmarkBTreePut1000(b *testing.B) { b.StopTimer() size := 1000 tree := New[int, struct{}](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 := New[int, struct{}](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 := New[int, struct{}](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 := New[int, struct{}](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 := New[int, struct{}](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 := New[int, struct{}](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 := New[int, struct{}](128) for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } b.StartTimer() benchmarkRemove(b, tree, size) } ================================================ FILE: trees/btree/iterator.go ================================================ // 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/v2/containers" // Assert Iterator implementation var _ containers.ReverseIteratorWithKey[string, int] = (*Iterator[string, int])(nil) // Iterator holding the iterator's state type Iterator[K comparable, V any] struct { tree *Tree[K, V] node *Node[K, V] entry *Entry[K, V] 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[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[K, V]) 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[K, V]) 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[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[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[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[K, V]) 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[K, V]) 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[K, V]) 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[K, V]) 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[K, V]) NextTo(f func(key K, value V) 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[K, V]) PrevTo(f func(key K, value V) bool) bool { for iterator.Prev() { key, value := iterator.Key(), iterator.Value() if f(key, value) { return true } } return false } ================================================ FILE: trees/btree/serialization.go ================================================ // 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/v2/containers" ) // Assert Serialization implementation 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[K, V]) ToJSON() ([]byte, error) { elements := make(map[K]V) it := tree.Iterator() for it.Next() { elements[it.Key()] = it.Value() } return json.Marshal(&elements) } // FromJSON populates the tree from the input JSON representation. func (tree *Tree[K, V]) FromJSON(data []byte) error { elements := make(map[K]V) err := json.Unmarshal(data, &elements) 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[K, V]) UnmarshalJSON(bytes []byte) error { return tree.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (tree *Tree[K, V]) MarshalJSON() ([]byte, error) { return tree.ToJSON() } ================================================ FILE: trees/redblacktree/iterator.go ================================================ // 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 "github.com/emirpasic/gods/v2/containers" // Assert Iterator implementation var _ containers.ReverseIteratorWithKey[string, int] = (*Iterator[string, int])(nil) // Iterator holding the iterator's state type Iterator[K comparable, V any] struct { tree *Tree[K, V] node *Node[K, V] 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[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[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[K, V]) 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 } for iterator.node.Parent != nil { node := iterator.node iterator.node = iterator.node.Parent if node == iterator.node.Left { 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[K, V]) 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 } for iterator.node.Parent != nil { node := iterator.node iterator.node = iterator.node.Parent if node == iterator.node.Right { 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[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[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[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[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[K, V]) 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[K, V]) 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[K, V]) 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[K, V]) NextTo(f func(key K, value V) 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[K, V]) PrevTo(f func(key K, value V) bool) bool { for iterator.Prev() { key, value := iterator.Key(), iterator.Value() if f(key, value) { return true } } return false } ================================================ FILE: trees/redblacktree/redblacktree.go ================================================ // 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. // // Used by TreeSet and TreeMap. // // Structure is not thread safe. // // References: http://en.wikipedia.org/wiki/Red%E2%80%93black_tree package redblacktree import ( "cmp" "fmt" "github.com/emirpasic/gods/v2/trees" "github.com/emirpasic/gods/v2/utils" ) // Assert Tree implementation var _ trees.Tree[int] = (*Tree[string, int])(nil) type color bool const ( black, red color = true, false ) // Tree holds elements of the red-black tree type Tree[K comparable, V any] struct { Root *Node[K, V] size int Comparator utils.Comparator[K] } // Node is a single element within the tree type Node[K comparable, V any] struct { Key K Value V color color Left *Node[K, V] Right *Node[K, V] Parent *Node[K, V] } // 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]} } // 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[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[K, V]{Key: key, Value: value, color: red} insertedNode = tree.Root } else { node := tree.Root loop := true for loop { compare := tree.Comparator(key, node.Key) switch { case compare == 0: node.Key = key node.Value = value return case compare < 0: if node.Left == nil { node.Left = &Node[K, V]{Key: key, Value: value, color: red} insertedNode = node.Left loop = false } else { node = node.Left } case compare > 0: if node.Right == nil { node.Right = &Node[K, V]{Key: key, Value: value, color: red} insertedNode = node.Right loop = false } else { node = node.Right } } } insertedNode.Parent = node } tree.insertCase1(insertedNode) 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[K, V]) Get(key K) (value V, found bool) { node := tree.lookup(key) if node != nil { return node.Value, true } 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[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[K, V]) Remove(key K) { var child *Node[K, V] 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 node = pred } if node.Left == nil || node.Right == nil { if node.Right == nil { child = node.Left } else { child = node.Right } if node.color == black { node.color = nodeColor(child) tree.deleteCase1(node) } tree.replaceNode(node, child) if node.Parent == nil && child != nil { child.color = black } } tree.size-- } // Empty returns true if tree does not contain any nodes func (tree *Tree[K, V]) Empty() bool { return tree.size == 0 } // Size returns number of nodes in the tree. 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[K, V]) 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[K, V]) Keys() []K { keys := make([]K, 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[K, V]) Values() []V { values := make([]V, tree.size) it := tree.Iterator() for i := 0; it.Next(); i++ { values[i] = it.Value() } return values } // Left returns the left-most (min) node or nil if tree is empty. func (tree *Tree[K, V]) Left() *Node[K, V] { var parent *Node[K, V] current := tree.Root for current != nil { parent = current current = current.Left } return parent } // Right returns the right-most (max) node or nil if tree is empty. func (tree *Tree[K, V]) Right() *Node[K, V] { var parent *Node[K, V] current := tree.Root for current != nil { parent = current current = current.Right } return parent } // 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 are larger than the given node. // // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree[K, V]) Floor(key K) (floor *Node[K, V], 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 } // 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 are smaller than the given node. // // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *Tree[K, V]) Ceiling(key K) (ceiling *Node[K, V], 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 } // Clear removes all nodes from the tree. func (tree *Tree[K, V]) Clear() { tree.Root = nil tree.size = 0 } // String returns a string representation of container func (tree *Tree[K, V]) String() string { str := "RedBlackTree\n" if !tree.Empty() { output(tree.Root, "", true, &str) } return str } func (node *Node[K, V]) String() string { return fmt.Sprintf("%v", node.Key) } func output[K comparable, V any](node *Node[K, V], prefix string, isTail bool, str *string) { if node.Right != nil { newPrefix := prefix if isTail { newPrefix += "│ " } else { newPrefix += " " } output(node.Right, newPrefix, false, str) } *str += prefix if isTail { *str += "└── " } else { *str += "┌── " } *str += node.String() + "\n" if node.Left != nil { newPrefix := prefix if isTail { newPrefix += " " } else { newPrefix += "│ " } output(node.Left, newPrefix, true, str) } } func (tree *Tree[K, V]) lookup(key K) *Node[K, V] { node := tree.Root for node != nil { compare := tree.Comparator(key, node.Key) switch { case compare == 0: return node case compare < 0: node = node.Left case compare > 0: node = node.Right } } return nil } func (node *Node[K, V]) grandparent() *Node[K, V] { if node != nil && node.Parent != nil { return node.Parent.Parent } return nil } 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[K, V]) sibling() *Node[K, V] { if node == nil || node.Parent == nil { return nil } if node == node.Parent.Left { return node.Parent.Right } return node.Parent.Left } func (tree *Tree[K, V]) rotateLeft(node *Node[K, V]) { right := node.Right tree.replaceNode(node, right) node.Right = right.Left if right.Left != nil { right.Left.Parent = node } right.Left = node node.Parent = right } func (tree *Tree[K, V]) rotateRight(node *Node[K, V]) { left := node.Left tree.replaceNode(node, left) node.Left = left.Right if left.Right != nil { left.Right.Parent = node } left.Right = node node.Parent = left } func (tree *Tree[K, V]) replaceNode(old *Node[K, V], new *Node[K, V]) { if old.Parent == nil { tree.Root = new } else { if old == old.Parent.Left { old.Parent.Left = new } else { old.Parent.Right = new } } if new != nil { new.Parent = old.Parent } } func (tree *Tree[K, V]) insertCase1(node *Node[K, V]) { if node.Parent == nil { node.color = black } else { tree.insertCase2(node) } } func (tree *Tree[K, V]) insertCase2(node *Node[K, V]) { if nodeColor(node.Parent) == black { return } tree.insertCase3(node) } func (tree *Tree[K, V]) insertCase3(node *Node[K, V]) { uncle := node.uncle() if nodeColor(uncle) == red { node.Parent.color = black uncle.color = black node.grandparent().color = red tree.insertCase1(node.grandparent()) } else { tree.insertCase4(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) 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[K, V]) insertCase5(node *Node[K, V]) { node.Parent.color = black grandparent := node.grandparent() grandparent.color = red if node == node.Parent.Left && node.Parent == grandparent.Left { tree.rotateRight(grandparent) } else if node == node.Parent.Right && node.Parent == grandparent.Right { tree.rotateLeft(grandparent) } } func (node *Node[K, V]) maximumNode() *Node[K, V] { if node == nil { return nil } for node.Right != nil { node = node.Right } return node } func (tree *Tree[K, V]) deleteCase1(node *Node[K, V]) { if node.Parent == nil { return } tree.deleteCase2(node) } func (tree *Tree[K, V]) deleteCase2(node *Node[K, V]) { sibling := node.sibling() if nodeColor(sibling) == red { node.Parent.color = red sibling.color = black if node == node.Parent.Left { tree.rotateLeft(node.Parent) } else { tree.rotateRight(node.Parent) } } tree.deleteCase3(node) } func (tree *Tree[K, V]) deleteCase3(node *Node[K, V]) { sibling := node.sibling() if nodeColor(node.Parent) == black && nodeColor(sibling) == black && nodeColor(sibling.Left) == black && nodeColor(sibling.Right) == black { sibling.color = red tree.deleteCase1(node.Parent) } else { tree.deleteCase4(node) } } func (tree *Tree[K, V]) deleteCase4(node *Node[K, V]) { sibling := node.sibling() if nodeColor(node.Parent) == red && nodeColor(sibling) == black && nodeColor(sibling.Left) == black && nodeColor(sibling.Right) == black { sibling.color = red node.Parent.color = black } else { tree.deleteCase5(node) } } func (tree *Tree[K, V]) deleteCase5(node *Node[K, V]) { sibling := node.sibling() if node == node.Parent.Left && nodeColor(sibling) == black && nodeColor(sibling.Left) == red && nodeColor(sibling.Right) == black { sibling.color = red sibling.Left.color = black tree.rotateRight(sibling) } else if node == node.Parent.Right && nodeColor(sibling) == black && nodeColor(sibling.Right) == red && nodeColor(sibling.Left) == black { sibling.color = red sibling.Right.color = black tree.rotateLeft(sibling) } tree.deleteCase6(node) } func (tree *Tree[K, V]) deleteCase6(node *Node[K, V]) { 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) } } func nodeColor[K comparable, V any](node *Node[K, V]) color { if node == nil { return black } return node.color } ================================================ FILE: trees/redblacktree/redblacktree_test.go ================================================ // 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" "fmt" "slices" "strings" "testing" ) func TestRedBlackTreeGet(t *testing.T) { tree := New[int, string]() 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 := New[int, string]() 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 := 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 := tree.Values(), []string{"a", "b", "c", "d", "e", "f", "g"}; !slices.Equal(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, "", false}, } for _, test := range tests1 { // retrievals actualValue, actualFound := tree.Get(test[0].(int)) if actualValue != test[1] || actualFound != test[2] { t.Errorf("Got %v expected %v", actualValue, test[1]) } } } func TestRedBlackTreeRemove(t *testing.T) { tree := New[int, string]() 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 := tree.Keys(), []int{1, 2, 3, 4}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", 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 { t.Errorf("Got %v expected %v", actualValue, 7) } tests2 := [][]interface{}{ {1, "a", true}, {2, "b", true}, {3, "c", true}, {4, "d", true}, {5, "", false}, {6, "", false}, {7, "", false}, {8, "", false}, } for _, test := range tests2 { actualValue, actualFound := tree.Get(test[0].(int)) 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 := tree.Keys(), []int{}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", 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 { t.Errorf("Got %v expected %v", empty, true) } } func TestRedBlackTreeLeftAndRight(t *testing.T) { tree := New[int, string]() 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.Left().Key, 1; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } if actualValue, expectedValue := tree.Left().Value, "x"; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } if actualValue, expectedValue := tree.Right().Key, 7; actualValue != expectedValue { t.Errorf("Got %v expected %v", 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 := New[int, string]() 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 TestRedBlackTreeIteratorNextOnEmpty(t *testing.T) { tree := New[int, string]() it := tree.Iterator() for it.Next() { t.Errorf("Shouldn't iterate on empty tree") } } func TestRedBlackTreeIteratorPrevOnEmpty(t *testing.T) { tree := New[int, string]() it := tree.Iterator() for it.Prev() { t.Errorf("Shouldn't iterate on empty tree") } } func TestRedBlackTreeIterator1Next(t *testing.T) { tree := New[int, string]() 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() 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 := New[int, string]() 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() 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 TestRedBlackTreeIterator2Next(t *testing.T) { tree := New[int, string]() tree.Put(3, "c") tree.Put(1, "a") tree.Put(2, "b") it := tree.Iterator() count := 0 for it.Next() { count++ key := it.Key() 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 TestRedBlackTreeIterator2Prev(t *testing.T) { tree := New[int, string]() 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() 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 TestRedBlackTreeIterator3Next(t *testing.T) { tree := New[int, string]() tree.Put(1, "a") it := tree.Iterator() count := 0 for it.Next() { count++ key := it.Key() 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 TestRedBlackTreeIterator3Prev(t *testing.T) { tree := New[int, string]() tree.Put(1, "a") it := tree.Iterator() for it.Next() { } countDown := tree.size for it.Prev() { key := it.Key() 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 TestRedBlackTreeIterator4Next(t *testing.T) { tree := New[int, int]() 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() 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 TestRedBlackTreeIterator4Prev(t *testing.T) { tree := New[int, int]() 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() 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 TestRedBlackTreeIteratorBegin(t *testing.T) { tree := New[int, string]() 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 TestRedBlackTreeIteratorEnd(t *testing.T) { tree := New[int, string]() 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 := New[int, string]() 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 := New[int, string]() 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 TestRedBlackTreeIteratorNextTo(t *testing.T) { // Sample seek function, i.e. string starting with "b" seek := func(index int, value string) bool { return strings.HasSuffix(value, "b") } // NextTo (empty) { tree := New[int, string]() it := tree.Iterator() for it.NextTo(seek) { t.Errorf("Shouldn't iterate on empty tree") } } // NextTo (not found) { tree := New[int, string]() 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 := New[int, string]() 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 != "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 != "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 int, value string) bool { return strings.HasSuffix(value, "b") } // PrevTo (empty) { tree := New[int, string]() it := tree.Iterator() it.End() for it.PrevTo(seek) { t.Errorf("Shouldn't iterate on empty tree") } } // PrevTo (not found) { tree := New[int, string]() 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 := New[int, string]() 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 != "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 != "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 := New[string, string]() 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, expectedValue := tree.Keys(), []string{"a", "b", "c"}; !slices.Equal(actualValue, expectedValue) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } 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) } } assert() bytes, err := tree.ToJSON() assert() err = tree.FromJSON(bytes) assert() bytes, err = json.Marshal([]interface{}{"a", "b", "c", tree}) if err != nil { t.Errorf("Got error %v", err) } 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 := 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[int, struct{}], 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[int, struct{}], 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[int, struct{}], 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 := New[int, struct{}]() 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 := New[int, struct{}]() 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 := New[int, struct{}]() 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 := New[int, struct{}]() 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 := New[int, struct{}]() b.StartTimer() benchmarkPut(b, tree, size) } func BenchmarkRedBlackTreePut1000(b *testing.B) { b.StopTimer() size := 1000 tree := New[int, struct{}]() 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 := New[int, struct{}]() 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 := New[int, struct{}]() 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 := New[int, struct{}]() 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 := New[int, struct{}]() 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 := New[int, struct{}]() 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 := New[int, struct{}]() for n := 0; n < size; n++ { tree.Put(n, struct{}{}) } b.StartTimer() benchmarkRemove(b, tree, size) } ================================================ FILE: trees/redblacktree/serialization.go ================================================ // 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/v2/containers" ) // Assert Serialization implementation 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[K, V]) ToJSON() ([]byte, error) { elements := make(map[K]V) it := tree.Iterator() for it.Next() { elements[it.Key()] = it.Value() } return json.Marshal(&elements) } // FromJSON populates the tree from the input JSON representation. 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) } } return err } // UnmarshalJSON @implements json.Unmarshaler func (tree *Tree[K, V]) UnmarshalJSON(bytes []byte) error { return tree.FromJSON(bytes) } // MarshalJSON @implements json.Marshaler func (tree *Tree[K, V]) MarshalJSON() ([]byte, error) { return tree.ToJSON() } ================================================ FILE: trees/trees.go ================================================ // 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. // // 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/v2/containers" // Tree interface that all trees implement type Tree[V any] interface { containers.Container[V] // Empty() bool // Size() int // Clear() // Values() []interface{} // String() string } ================================================ FILE: utils/comparator.go ================================================ // 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 "time" type Comparator[T any] func(x, y T) int // TimeComparator provides a basic comparison on time.Time func TimeComparator(a, b time.Time) int { switch { case a.After(b): return 1 case a.Before(b): return -1 default: return 0 } } ================================================ FILE: utils/comparator_test.go ================================================ // 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 ( "testing" "time" ) 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].(time.Time), test[1].(time.Time)) expected := test[2] if actual != expected { t.Errorf("Got %v expected %v", actual, expected) } } } ================================================ FILE: utils/utils.go ================================================ // 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. // // Provided functionalities: // - sorting // - comparators package utils import ( "fmt" "strconv" ) // ToString converts a value to string. func ToString(value interface{}) string { switch value := value.(type) { case string: return value case int8: return strconv.FormatInt(int64(value), 10) case int16: return strconv.FormatInt(int64(value), 10) case int32: return strconv.FormatInt(int64(value), 10) case int64: return strconv.FormatInt(value, 10) case uint8: return strconv.FormatUint(uint64(value), 10) case uint16: return strconv.FormatUint(uint64(value), 10) case uint32: return strconv.FormatUint(uint64(value), 10) case uint64: return strconv.FormatUint(value, 10) case float32: return strconv.FormatFloat(float64(value), 'g', -1, 64) case float64: return strconv.FormatFloat(value, 'g', -1, 64) case bool: return strconv.FormatBool(value) default: return fmt.Sprintf("%+v", value) } } ================================================ FILE: utils/utils_test.go ================================================ // 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 = float64(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) } }