Compare commits

...

75 Commits

Author SHA1 Message Date
Paul Chesnais 14f714261f
Generics migration (#237)
* Generics migration

This attempts to migrate this library in the least invasive way by preserving as
much of the original API as possible. It does not change the tests in a
meaningful way nor does it attempt to upgrade any logic that can be simplified
or improved with generics. This is purely an API migration, and still requires a
lot of additional work to be fully ready.

* Fix a few broken tests around serialization

* Add v2 suffix

* Temporarily change mod name for testing

* Rename module to /v2
6 months ago
Emir Pasic 10d6c5b4f2
Merge pull request #227 from thebenkogan/master
fix: doublylinkedlist insertion with last to first traversal
10 months ago
Ben Kogan 608766492e fix: doublylinkedlist insertion with last to first traversal 10 months ago
Emir Pasic 702a6b2c26
Merge pull request #220 from ugurcsen/patch-1
Benchmark bug fixed(interface conversion).
1 year ago
Ugur SEN 9f3e98d84a
Benchmark bug fixed(interface conversion).
go test -run=NO_TEST -bench . -benchmem -benchtime 1s
This command gives an error (panic: interface conversion: interface {} is int, not priorityqueue.Element) and to fix this enqueue(n)s changed to enqueu(Element{})s.
1 year ago
Emir Pasic 5dd72bf1e0
Merge pull request #213 from rakiyoshi/fix-doc
Fix documentation
2 years ago
Ryoh Akiyoshi 789e39cb69
fix documentation 2 years ago
Emir Pasic dbdbadc158
Merge pull request #205 from emirpasic/development
Fix in ArrayList.Contains function against nil values
2 years ago
Emir Pasic b486cc91bf Fix in ArrayList.Contains function against nil values 2 years ago
Emir Pasic e63524608b Testing funding.yml 2 years ago
Emir Pasic 773505cfec
Merge pull request #203 from emirpasic/development
Implements PriorityQueue and CircularBuffer
2 years ago
Emir Pasic 2bf1bd3aff Implements PriorityQueue 2 years ago
Emir Pasic 8ace639fc3 Implements PriorityQueue 2 years ago
Emir Pasic 6b0ffefe7f Fix iterator in binary heap 2 years ago
Emir Pasic 33e824351c Fix circular buffer tests 2 years ago
Emir Pasic 60093dc4a3 circualbuffer example 2 years ago
Emir Pasic 9606c1a0e8 Implements CircularBuffer 2 years ago
Emir Pasic da429eb24e
Merge pull request #202 from emirpasic/development
Implements queues, LinkedListQueue and ArrayQueue
2 years ago
Emir Pasic 5b2385446e Documentation fix 2 years ago
Emir Pasic 6bf61e32be Implements queues, LinkedListQueue and ArrayQueue 2 years ago
Emir Pasic 6a0f91bdd5 Add String() to comments for all structures 2 years ago
Emir Pasic 77ed4cc146
Merge pull request #148 from AryanAhadinia/issue_146
Add Queue
2 years ago
Emir Pasic 7815e7de4e
Merge pull request #201 from emirpasic/development
SonarQube
2 years ago
Emir Pasic 74d62f4f1e SonarQube 2 years ago
Emir Pasic 4665f56318 tmp 2 years ago
Emir Pasic 44253054e3
Merge pull request #200 from emirpasic/development
SonarQube
2 years ago
Emir Pasic 9e4f7a11c4 SonarQube 2 years ago
Emir Pasic 08cf24a0a0 SonarQube badge 2 years ago
Emir Pasic 1dd397e12c SonarQube fixes 2 years ago
Emir Pasic 6356a9e470
Create sonarcloud.yml 2 years ago
Emir Pasic f70d3dd117
Create codeql-analysis.yml 2 years ago
Emir Pasic 08ae186640
Create dependabot.yml 2 years ago
Emir Pasic 05959cbe35 Add release badge 2 years ago
Emir Pasic 92b8f18bff Integrate sourcegraph badge 2 years ago
Emir Pasic d953513772
Merge pull request #197 from emirpasic/development
Improve code coverage
2 years ago
Emir Pasic 41012c6c58 Improve code coverage 2 years ago
Emir Pasic e2b92bbc7a Interface implementation assertions moved outside the functions 2 years ago
Emir Pasic 363df0e21f Comparator tests 2 years ago
Emir Pasic 1711af552f
Merge pull request #196 from emirpasic/development
Code Coverage Report with Badge
2 years ago
Emir Pasic 0d3ddc1d74 codeconv integration 2 years ago
Emir Pasic 138c2712da codeconv integration 2 years ago
Emir Pasic 5bcba54b52 codeconv integration 2 years ago
Emir Pasic b2dbe95e30 codeconv integration 2 years ago
Emir Pasic 155dd74f32
Merge pull request #195 from emirpasic/development
Set operations: intersection, union, difference
2 years ago
Emir Pasic 74d4456375 Fix lint errors 2 years ago
Emir Pasic e438e7b77b Set operations: intersection, union, difference 2 years ago
Emir Pasic 7cf7ceab6f Update README 2 years ago
Emir Pasic ae81334c3e
Merge pull request #142 from jmdacruz/implement-set-intersection
Simple implementation of set intersection
2 years ago
Emir Pasic 74bf8a8b7d Update documentation on JSON serialization with the new json/encoding interface implementation 2 years ago
Emir Pasic d7c0bc8651 Update documentation on JSON serialization with the new json/encoding interface implementation 2 years ago
Emir Pasic 9641d19f46 Merge branch 'development' 2 years ago
Emir Pasic 364a244af9 Enforce String() inteface on Container 2 years ago
Emir Pasic a27d480bcc Simplify ToString function for types (avoid unnecessary casting) 2 years ago
Emir Pasic 3bca87dfc4 Merge branch 'development' 2 years ago
Emir Pasic 9548245e86
Merge pull request #135 from doshiraki/origin/modifyRBTree
I modified Prev and Next Because it uses Compare function.
2 years ago
Emir Pasic f93cc2b042 Merge branch 'development' 2 years ago
Emir Pasic 56b5cc16a1
Merge pull request #192 from emirpasic/json-interfaces
Implements json.Marshaler and json.Unmarshaler interfaces
2 years ago
Emir Pasic 1f0b87f0e1 Implements json.Marshaler and json.Unmarshaler interfaces 2 years ago
Emir Pasic b5735bcc4d
Merge pull request #165 from yvvlee/feature/implements_jsonMarshaler_and_Unmarshaler
Implements json.Marshaler and json.Unmarshaler interfaces
2 years ago
Emir Pasic 49b5b79c62 Merge branch 'development' 2 years ago
Emir Pasic 7487c6a604
Merge pull request #191 from emirpasic/tree-iterator-node
Implement GetNode() for trees and Node() function for their iterators
2 years ago
Emir Pasic 69d2184011 Implement GetNode() for BTree AVLTree and RedBlackTree and Node() function for their iterators 2 years ago
Emir Pasic 55346e985b
Merge pull request #190 from emirpasic/development
Development
2 years ago
Emir Pasic 17e5fd5a36
Merge pull request #189 from emirpasic/iterator-features
Implement NextTo and PrevTo on iterator
2 years ago
Emir Pasic 08ae493e8a Implement NextTo and PrevTo for all iterators and containers (index or key, forward-only or reversable) 2 years ago
Emir Pasic 4209f34363 Update license badge 2 years ago
mshadow c9a2dcad62 Implements json.Marshaler and json.Unmarshaler 3 years ago
Aryan Ahadinia 3c9a1ea06f
Update README.md 3 years ago
AryanAhadinia b2f992450d Add queue to README 3 years ago
AryanAhadinia 327ef4525b Add linkedlistqueue 3 years ago
AryanAhadinia 386e3be586 Add arrayqueue 3 years ago
AryanAhadinia 222ea6c374 Add queue interface 3 years ago
Marcelo Da cruz pinto 508e436ad1 Adding Intersection function to the Set interface 4 years ago
Marcelo Da cruz pinto 419d73a3b6 Simple implementation of set intersection 4 years ago
doshiraki 3e279ba9ab I modified Prev and Next Because it uses Compare function. 4 years ago

@ -28,9 +28,14 @@ jobs:
name: Calculate test coverage
command: |
mkdir -p $TEST_RESULTS
go test -coverprofile=c.out ./... > /dev/null
go tool cover -html=c.out -o coverage.html
go test -coverprofile=coverage.out ./... > /dev/null
go 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: |
@ -67,4 +72,4 @@ workflows:
matrix:
parameters:
# To test with and without generics (versions prior to 1.18)
version: ["1.18", "1.17"]
version: [ "1.18", "1.17" ]

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: godatastructures
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

@ -0,0 +1,8 @@
# Ref: https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"

@ -0,0 +1,70 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '30 4 * * 5'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'go' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

@ -1,4 +1,11 @@
[![GoDoc](https://godoc.org/github.com/emirpasic/gods?status.svg)](https://godoc.org/github.com/emirpasic/gods) [![Build Status](https://circleci.com/gh/emirpasic/gods/tree/master.svg?style=shield)](https://circleci.com/gh/emirpasic/gods?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/emirpasic/gods)](https://goreportcard.com/report/github.com/emirpasic/gods) [![PyPI](https://img.shields.io/pypi/l/Django.svg?maxAge=2592000)](https://github.com/emirpasic/gods/blob/master/LICENSE)
[![GoDoc](https://godoc.org/github.com/emirpasic/gods?status.svg)](https://godoc.org/github.com/emirpasic/gods)
[![Build Status](https://circleci.com/gh/emirpasic/gods/tree/master.svg?style=shield)](https://circleci.com/gh/emirpasic/gods?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/emirpasic/gods)](https://goreportcard.com/report/github.com/emirpasic/gods)
[![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)
@ -29,6 +36,11 @@ Implementation of various data structures and algorithms in Go.
- [AVLTree](#avltree)
- [BTree](#btree)
- [BinaryHeap](#binaryheap)
- [Queues](#queues)
- [LinkedListQueue](#linkedlistqueue)
- [ArrayQueue](#arrayqueue)
- [CircularBuffer](#circularbuffer)
- [PriorityQueue](#priorityqueue)
- [Functions](#functions)
- [Comparator](#comparator)
- [Iterator](#iterator)
@ -57,36 +69,42 @@ type Container interface {
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** |
| :--- | :--- | :---: | :---: | :---: | :---: |
| **Data** | **Structure** | **Ordered** | **[Iterator](#iterator)** | **[Enumerable](#enumerable)** | **Referenced by** |
| :--- |:--------------------------------------| :---: | :---: | :---: | :---: |
| [Lists](#lists) |
| | [ArrayList](#arraylist) | yes | yes* | yes | index |
| | [ArrayList](#arraylist) | yes | yes* | yes | index |
| | [SinglyLinkedList](#singlylinkedlist) | yes | yes | yes | index |
| | [DoublyLinkedList](#doublylinkedlist) | yes | yes* | yes | index |
| [Sets](#sets) |
| | [HashSet](#hashset) | no | no | no | index |
| | [TreeSet](#treeset) | yes | yes* | yes | index |
| | [LinkedHashSet](#linkedhashset) | yes | yes* | yes | index |
| | [HashSet](#hashset) | no | no | no | index |
| | [TreeSet](#treeset) | yes | yes* | yes | index |
| | [LinkedHashSet](#linkedhashset) | yes | yes* | yes | index |
| [Stacks](#stacks) |
| | [LinkedListStack](#linkedliststack) | yes | yes | no | index |
| | [ArrayStack](#arraystack) | yes | yes* | no | index |
| | [LinkedListStack](#linkedliststack) | yes | yes | no | index |
| | [ArrayStack](#arraystack) | yes | yes* | no | index |
| [Maps](#maps) |
| | [HashMap](#hashmap) | no | no | no | key |
| | [TreeMap](#treemap) | yes | yes* | yes | key |
| | [LinkedHashMap](#linkedhashmap) | yes | yes* | yes | key |
| | [HashBidiMap](#hashbidimap) | no | no | no | key* |
| | [TreeBidiMap](#treebidimap) | yes | yes* | yes | key* |
| | [HashMap](#hashmap) | no | no | no | key |
| | [TreeMap](#treemap) | yes | yes* | yes | key |
| | [LinkedHashMap](#linkedhashmap) | yes | yes* | yes | key |
| | [HashBidiMap](#hashbidimap) | no | no | no | key* |
| | [TreeBidiMap](#treebidimap) | yes | yes* | yes | key* |
| [Trees](#trees) |
| | [RedBlackTree](#redblacktree) | yes | yes* | no | key |
| | [AVLTree](#avltree) | yes | yes* | no | key |
| | [BTree](#btree) | yes | yes* | no | key |
| | [BinaryHeap](#binaryheap) | yes | yes* | no | index |
| | | | <sub><sup>*reversible</sup></sub> | | <sub><sup>*bidirectional</sup></sub> |
| | [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 |
| | | | <sub><sup>*reversible</sup></sub> | | <sub><sup>*bidirectional</sup></sub> |
### Lists
@ -110,6 +128,7 @@ type List interface {
// Size() int
// Clear()
// Values() []interface{}
// String() string
}
```
@ -117,7 +136,7 @@ type List interface {
A [list](#lists) backed by a dynamic array that grows and shrinks implicitly.
Implements [List](#lists), [IteratorWithIndex](#iteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.
Implements [List](#lists), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.
```go
package main
@ -191,7 +210,7 @@ func main() {
A [list](#lists) where each element points to the next and previous elements in the list.
Implements [List](#lists), [IteratorWithIndex](#iteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.
Implements [List](#lists), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.
```go
package main
@ -228,6 +247,8 @@ func main() {
A set is a data structure that can store elements and has no repeated values. It is a computer implementation of the mathematical concept of a finite set. Unlike most other collection types, rather than retrieving a specific element from a set, one typically tests an element for membership in a set. This structure is often used to ensure that no duplicates are present in a container.
Set additionally allow set operations such as [intersection](https://en.wikipedia.org/wiki/Intersection_(set_theory)), [union](https://en.wikipedia.org/wiki/Union_(set_theory)), [difference](https://proofwiki.org/wiki/Definition:Set_Difference), etc.
Implements [Container](#containers) interface.
```go
@ -235,12 +256,16 @@ 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
}
```
@ -275,7 +300,7 @@ func main() {
A [set](#sets) backed by a [red-black tree](#redblacktree) to keep the elements ordered with respect to the [comparator](#comparator).
Implements [Set](#sets), [IteratorWithIndex](#iteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.
Implements [Set](#sets), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.
```go
package main
@ -302,7 +327,7 @@ func main() {
A [set](#sets) that preserves insertion-order. Data structure is backed by a hash table to store values and [doubly-linked list](#doublylinkedlist) to store insertion ordering.
Implements [Set](#sets), [IteratorWithIndex](#iteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.
Implements [Set](#sets), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.
```go
package main
@ -343,6 +368,7 @@ type Stack interface {
// Size() int
// Clear()
// Values() []interface{}
// String() string
}
```
@ -418,6 +444,7 @@ type Map interface {
// Size() int
// Clear()
// Values() []interface{}
// String() string
}
```
@ -462,7 +489,7 @@ func main() {
A [map](#maps) based on [red-black tree](#redblacktree). Keys are ordered with respect to the [comparator](#comparator).
Implements [Map](#maps), [IteratorWithKey](#iteratorwithkey), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.
Implements [Map](#maps), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.
```go
package main
@ -493,7 +520,7 @@ func main() {
A [map](#maps) that preserves insertion-order. It is backed by a hash table to store values and [doubly-linked list](doublylinkedlist) to store ordering.
Implements [Map](#maps), [IteratorWithKey](#iteratorwithkey), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.
Implements [Map](#maps), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.
```go
package main
@ -550,7 +577,7 @@ func main() {
A [map](#maps) based on red-black tree. This map guarantees that the map will be in both ascending key and value order. Other than key and value ordering, the goal with this structure is to avoid duplication of elements (unlike in [HashBidiMap](#hashbidimap)), which can be significant if contained elements are large.
Implements [BidiMap](#maps), [IteratorWithKey](#iteratorwithkey), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.
Implements [BidiMap](#maps), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces.
```go
package main
@ -591,6 +618,7 @@ type Tree interface {
// Size() int
// Clear()
// Values() []interface{}
// String() string
}
```
@ -846,6 +874,167 @@ func main() {
}
```
### Queues
A queue that represents a first-in-first-out (FIFO) data structure. The usual enqueue and dequeue operations are provided, as well as a method to peek at the first item in the queue.
<p align="center"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/5/52/Data_Queue.svg/300px-Data_Queue.svg.png" width="200px" height="120px" /></p>
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.
<p align="center"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/fd/Circular_Buffer_Animation.gif/400px-Circular_Buffer_Animation.gif" width="300px" height="300px" /></p>
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() // <nil> false (nothing to dequeue)
queue.Clear() // empty
_ = queue.Empty() // true
_ = queue.Size() // 0
}
```
## Functions
Various helper functions used throughout the library.
@ -983,6 +1172,22 @@ for it.Begin(); it.Next(); {
}
```
Seeking to a specific element:
```go
// Seek function, i.e. find element starting with "b"
seek := func(index int, value interface{}) bool {
return strings.HasSuffix(value.(string), "b")
}
// Seek to the condition and continue traversal from that point (forward).
// assumes it.Begin() was called.
for found := it.NextTo(seek); found; found = it.Next() {
index, value := it.Index(), it.Value()
...
}
```
#### IteratorWithKey
An [iterator](#iterator) whose elements are referenced by a key.
@ -1010,6 +1215,22 @@ for it.Begin(); it.Next(); {
}
```
Seeking to a specific element from the current iterator position:
```go
// Seek function, i.e. find element starting with "b"
seek := func(key interface{}, value interface{}) bool {
return strings.HasSuffix(value.(string), "b")
}
// Seek to the condition and continue traversal from that point (forward).
// assumes it.Begin() was called.
for found := it.NextTo(seek); found; found = it.Next() {
key, value := it.Key(), it.Value()
...
}
```
#### ReverseIteratorWithIndex
An [iterator](#iterator) whose elements are referenced by an index. Provides all functions as [IteratorWithIndex](#iteratorwithindex), but can also be used for reverse iteration.
@ -1031,6 +1252,22 @@ if it.Last() {
}
```
Seeking to a specific element:
```go
// Seek function, i.e. find element starting with "b"
seek := func(index int, value interface{}) bool {
return strings.HasSuffix(value.(string), "b")
}
// Seek to the condition and continue traversal from that point (in reverse).
// assumes it.End() was called.
for found := it.PrevTo(seek); found; found = it.Prev() {
index, value := it.Index(), it.Value()
...
}
```
#### ReverseIteratorWithKey
An [iterator](#iterator) whose elements are referenced by a key. Provides all functions as [IteratorWithKey](#iteratorwithkey), but can also be used for reverse iteration.
@ -1052,6 +1289,20 @@ if it.Last() {
}
```
```go
// Seek function, i.e. find element starting with "b"
seek := func(key interface{}, value interface{}) bool {
return strings.HasSuffix(value.(string), "b")
}
// Seek to the condition and continue traversal from that point (in reverse).
// assumes it.End() was called.
for found := it.PrevTo(seek); found; found = it.Prev() {
key, value := it.Key(), it.Value()
...
}
```
### Enumerable
Enumerable functions for ordered containers that implement [EnumerableWithIndex](#enumerablewithindex) or [EnumerableWithKey](#enumerablewithkey) interfaces.
@ -1286,17 +1537,19 @@ func main() {
### Serialization
All data structures can be serialized (marshalled) and deserialized (unmarshalled). Currently only JSON support is available.
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"
)
@ -1307,18 +1560,21 @@ func main() {
m.Put("b", "2")
m.Put("c", "3")
json, err := m.ToJSON()
bytes, err := json.Marshal(m) // Same as "m.ToJSON(m)"
if err != nil {
fmt.Println(err)
}
fmt.Println(string(json)) // {"a":"1","b":"2","c":"3"}
fmt.Println(string(bytes)) // {"a":"1","b":"2","c":"3"}
}
```
Typical usage for value-only structures:
```go
package main
import (
"encoding/json"
"fmt"
"github.com/emirpasic/gods/lists/arraylist"
)
@ -1327,11 +1583,11 @@ func main() {
list := arraylist.New()
list.Add("a", "b", "c")
json, err := list.ToJSON()
bytes, err := json.Marshal(list) // Same as "list.ToJSON(list)"
if err != nil {
fmt.Println(err)
}
fmt.Println(string(json)) // ["a","b","c"]
fmt.Println(string(bytes)) // ["a","b","c"]
}
```
@ -1340,10 +1596,12 @@ func main() {
Populates the container with elements from the input JSON representation.
Typical usage for key-value structures:
```go
package main
import (
"encoding/json"
"fmt"
"github.com/emirpasic/gods/maps/hashmap"
)
@ -1351,8 +1609,8 @@ import (
func main() {
hm := hashmap.New()
json := []byte(`{"a":"1","b":"2"}`)
err := hm.FromJSON(json)
bytes := []byte(`{"a":"1","b":"2"}`)
err := json.Unmarshal(bytes, &hm) // Same as "hm.FromJSON(bytes)"
if err != nil {
fmt.Println(err)
}
@ -1361,10 +1619,12 @@ func main() {
```
Typical usage for value-only structures:
```go
package main
import (
"encoding/json"
"fmt"
"github.com/emirpasic/gods/lists/arraylist"
)
@ -1372,8 +1632,8 @@ import (
func main() {
list := arraylist.New()
json := []byte(`["a","b"]`)
err := list.FromJSON(json)
bytes := []byte(`["a","b"]`)
err := json.Unmarshal(bytes, &list) // Same as "list.FromJSON(bytes)"
if err != nil {
fmt.Println(err)
}
@ -1410,7 +1670,7 @@ Container specific operations:
```go
// Returns sorted container''s elements with respect to the passed comparator.
// Does not effect the ordering of elements within the container.
// Does not affect the ordering of elements within the container.
func GetSortedValues(container Container, comparator utils.Comparator) []interface{}
```
@ -1489,13 +1749,19 @@ Coding style:
```shell
# Install tooling and set path:
go get github.com/golang/lint/golint
go get github.com/fzipp/gocyclo
go get github.com/kisielk/errcheck
go install gotest.tools/gotestsum@latest
go install golang.org/x/lint/golint@latest
go install github.com/kisielk/errcheck@latest
export PATH=$PATH:$GOPATH/bin
# Fix errors and warnings:
go fmt ./... && gofmt -s -w . && go vet ./... && go get ./... && go test ./... && golint ./... && gocyclo -avg -over 15 . && errcheck ./...
go fmt ./... &&
go test -v ./... &&
golint -set_exit_status ./... &&
! go fmt ./... 2>&1 | read &&
go vet -v ./... &&
gocyclo -avg -over 15 ../gods &&
errcheck ./...
```
### License

@ -13,23 +13,39 @@
// Serialization provides serializers (marshalers) and deserializers (unmarshalers).
package containers
import "github.com/emirpasic/gods/utils"
import (
"cmp"
"slices"
"github.com/emirpasic/gods/v2/utils"
)
// Container is base interface that all data structures implement.
type Container interface {
type Container[T any] interface {
Empty() bool
Size() int
Clear()
Values() []interface{}
Values() []T
String() string
}
// GetSortedValues returns sorted container's elements with respect to the passed comparator.
// Does not effect the ordering of elements within the container.
func GetSortedValues(container Container, comparator utils.Comparator) []interface{} {
// 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
}
utils.Sort(values, comparator)
slices.SortFunc(values, comparator)
return values
}

@ -7,48 +7,70 @@
package containers
import (
"github.com/emirpasic/gods/utils"
"cmp"
"fmt"
"strings"
"testing"
)
// For testing purposes
type ContainerTest struct {
values []interface{}
type ContainerTest[T any] struct {
values []T
}
func (container ContainerTest) Empty() bool {
func (container ContainerTest[T]) Empty() bool {
return len(container.values) == 0
}
func (container ContainerTest) Size() int {
func (container ContainerTest[T]) Size() int {
return len(container.values)
}
func (container ContainerTest) Clear() {
container.values = []interface{}{}
func (container ContainerTest[T]) Clear() {
container.values = []T{}
}
func (container ContainerTest) Values() []interface{} {
func (container ContainerTest[T]) Values() []T {
return container.values
}
func (container ContainerTest[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{}
container.values = []interface{}{5, 1, 3, 2, 4}
values := GetSortedValues(container, utils.IntComparator)
container := ContainerTest[int]{}
GetSortedValues(container)
container.values = []int{5, 1, 3, 2, 4}
values := GetSortedValues(container)
for i := 1; i < container.Size(); i++ {
if values[i-1].(int) > values[i].(int) {
if values[i-1] > values[i] {
t.Errorf("Not sorted!")
}
}
}
func TestGetSortedValuesStrings(t *testing.T) {
container := ContainerTest{}
container.values = []interface{}{"g", "a", "d", "e", "f", "c", "b"}
values := GetSortedValues(container, utils.StringComparator)
type NotInt struct {
i int
}
func TestGetSortedValuesNotInts(t *testing.T) {
container := ContainerTest[NotInt]{}
GetSortedValuesFunc(container, func(x, y NotInt) int {
return cmp.Compare(x.i, y.i)
})
container.values = []NotInt{{5}, {1}, {3}, {2}, {4}}
values := GetSortedValuesFunc(container, func(x, y NotInt) int {
return cmp.Compare(x.i, y.i)
})
for i := 1; i < container.Size(); i++ {
if values[i-1].(string) > values[i].(string) {
if values[i-1].i > values[i].i {
t.Errorf("Not sorted!")
}
}

@ -5,57 +5,53 @@
package containers
// EnumerableWithIndex provides functions for ordered containers whose values can be fetched by an index.
type EnumerableWithIndex interface {
type EnumerableWithIndex[T any] interface {
// Each calls the given function once for each element, passing that element's index and value.
Each(func(index int, value interface{}))
Each(func(index int, value T))
// Map invokes the given function once for each element and returns a
// container containing the values returned by the given function.
// TODO would appreciate help on how to enforce this in containers (don't want to type assert when chaining)
// Map(func(index int, value interface{}) interface{}) Container
// Select returns a new container containing all elements for which the given function returns a true value.
// TODO need help on how to enforce this in containers (don't want to type assert when chaining)
// Select(func(index int, value interface{}) bool) Container
// Any passes each element of the container to the given function and
// returns true if the function ever returns true for any element.
Any(func(index int, value interface{}) bool) bool
Any(func(index int, value T) bool) bool
// All passes each element of the container to the given function and
// returns true if the function returns true for all elements.
All(func(index int, value interface{}) bool) bool
All(func(index int, value T) bool) bool
// Find passes each element of the container to the given function and returns
// the first (index,value) for which the function is true or -1,nil otherwise
// if no element matches the criteria.
Find(func(index int, value interface{}) bool) (int, interface{})
Find(func(index int, value T) bool) (int, T)
}
// EnumerableWithKey provides functions for ordered containers whose values whose elements are key/value pairs.
type EnumerableWithKey interface {
type EnumerableWithKey[K, V any] interface {
// Each calls the given function once for each element, passing that element's key and value.
Each(func(key interface{}, value interface{}))
Each(func(key K, value V))
// Map invokes the given function once for each element and returns a container
// containing the values returned by the given function as key/value pairs.
// TODO need help on how to enforce this in containers (don't want to type assert when chaining)
// Map(func(key interface{}, value interface{}) (interface{}, interface{})) Container
// Select returns a new container containing all elements for which the given function returns a true value.
// TODO need help on how to enforce this in containers (don't want to type assert when chaining)
// Select(func(key interface{}, value interface{}) bool) Container
// Any passes each element of the container to the given function and
// returns true if the function ever returns true for any element.
Any(func(key interface{}, value interface{}) bool) bool
Any(func(key K, value V) bool) bool
// All passes each element of the container to the given function and
// returns true if the function returns true for all elements.
All(func(key interface{}, value interface{}) bool) bool
All(func(key K, value V) bool) bool
// Find passes each element of the container to the given function and returns
// the first (key,value) for which the function is true or nil,nil otherwise if no element
// matches the criteria.
Find(func(key interface{}, value interface{}) bool) (interface{}, interface{})
Find(func(key K, value V) bool) (K, V)
}

@ -5,7 +5,7 @@
package containers
// IteratorWithIndex is stateful iterator for ordered containers whose values can be fetched by an index.
type IteratorWithIndex interface {
type IteratorWithIndex[T any] interface {
// Next moves the iterator to the next element and returns true if there was a next element in the container.
// If Next() returns true, then next element's index and value can be retrieved by Index() and Value().
// If Next() was called for the first time, then it will point the iterator to the first element if it exists.
@ -14,7 +14,7 @@ type IteratorWithIndex interface {
// Value returns the current element's value.
// Does not modify the state of the iterator.
Value() interface{}
Value() T
// Index returns the current element's index.
// Does not modify the state of the iterator.
@ -28,10 +28,16 @@ type IteratorWithIndex interface {
// If First() returns true, then first element's index and value can be retrieved by Index() and Value().
// Modifies the state of the iterator.
First() bool
// NextTo moves the iterator to the next element from current position that satisfies the condition given by the
// passed function, and returns true if there was a next element in the container.
// If NextTo() returns true, then next element's index and value can be retrieved by Index() and Value().
// Modifies the state of the iterator.
NextTo(func(index int, value T) bool) bool
}
// IteratorWithKey is a stateful iterator for ordered containers whose elements are key value pairs.
type IteratorWithKey interface {
type IteratorWithKey[K, V any] interface {
// Next moves the iterator to the next element and returns true if there was a next element in the container.
// If Next() returns true, then next element's key and value can be retrieved by Key() and Value().
// If Next() was called for the first time, then it will point the iterator to the first element if it exists.
@ -40,11 +46,11 @@ type IteratorWithKey interface {
// Value returns the current element's value.
// Does not modify the state of the iterator.
Value() interface{}
Value() V
// Key returns the current element's key.
// Does not modify the state of the iterator.
Key() interface{}
Key() K
// Begin resets the iterator to its initial state (one-before-first)
// Call Next() to fetch the first element if any.
@ -54,18 +60,24 @@ type IteratorWithKey interface {
// If First() returns true, then first element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator.
First() bool
// NextTo moves the iterator to the next element from current position that satisfies the condition given by the
// passed function, and returns true if there was a next element in the container.
// If NextTo() returns true, then next element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator.
NextTo(func(key K, value V) bool) bool
}
// ReverseIteratorWithIndex is stateful iterator for ordered containers whose values can be fetched by an index.
//
// Essentially it is the same as IteratorWithIndex, but provides additional:
//
// Prev() function to enable traversal in reverse
// # Prev() function to enable traversal in reverse
//
// Last() function to move the iterator to the last element.
//
// End() function to move the iterator past the last element (one-past-the-end).
type ReverseIteratorWithIndex interface {
type ReverseIteratorWithIndex[T any] interface {
// Prev moves the iterator to the previous element and returns true if there was a previous element in the container.
// If Prev() returns true, then previous element's index and value can be retrieved by Index() and Value().
// Modifies the state of the iterator.
@ -80,17 +92,23 @@ type ReverseIteratorWithIndex interface {
// Modifies the state of the iterator.
Last() bool
IteratorWithIndex
// 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
// # Prev() function to enable traversal in reverse
//
// Last() function to move the iterator to the last element.
type ReverseIteratorWithKey interface {
type ReverseIteratorWithKey[K, V any] interface {
// Prev moves the iterator to the previous element and returns true if there was a previous element in the container.
// If Prev() returns true, then previous element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator.
@ -105,5 +123,11 @@ type ReverseIteratorWithKey interface {
// Modifies the state of the iterator.
Last() bool
IteratorWithKey
// 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]
}

@ -8,10 +8,14 @@ package containers
type JSONSerializer interface {
// ToJSON outputs the JSON representation of containers's elements.
ToJSON() ([]byte, error)
// MarshalJSON @implements json.Marshaler
MarshalJSON() ([]byte, error)
}
// JSONDeserializer provides JSON deserialization
type JSONDeserializer interface {
// FromJSON populates containers's elements from the input JSON representation.
FromJSON([]byte) error
// UnmarshalJSON @implements json.Unmarshaler
UnmarshalJSON([]byte) error
}

@ -5,16 +5,17 @@
package main
import (
"github.com/emirpasic/gods/lists/arraylist"
"github.com/emirpasic/gods/utils"
"cmp"
"github.com/emirpasic/gods/v2/lists/arraylist"
)
// ArrayListExample to demonstrate basic usage of ArrayList
func main() {
list := arraylist.New()
list := arraylist.New[string]()
list.Add("a") // ["a"]
list.Add("c", "b") // ["a","c","b"]
list.Sort(utils.StringComparator) // ["a","b","c"]
list.Sort(cmp.Compare[string]) // ["a","b","c"]
_, _ = list.Get(0) // "a",true
_, _ = list.Get(100) // nil,false
_ = list.Contains("a", "b", "c") // true

@ -0,0 +1,23 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import aq "github.com/emirpasic/gods/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
}

@ -4,20 +4,20 @@
package main
import "github.com/emirpasic/gods/stacks/arraystack"
import "github.com/emirpasic/gods/v2/stacks/arraystack"
// ArrayStackExample to demonstrate basic usage of ArrayStack
func main() {
stack := arraystack.New() // empty
stack.Push(1) // 1
stack.Push(2) // 1, 2
stack.Values() // 2, 1 (LIFO order)
_, _ = stack.Peek() // 2,true
_, _ = stack.Pop() // 2, true
_, _ = stack.Pop() // 1, true
_, _ = stack.Pop() // nil, false (nothing to pop)
stack.Push(1) // 1
stack.Clear() // empty
stack.Empty() // true
stack.Size() // 0
stack := arraystack.New[int]() // empty
stack.Push(1) // 1
stack.Push(2) // 1, 2
stack.Values() // 2, 1 (LIFO order)
_, _ = stack.Peek() // 2,true
_, _ = stack.Pop() // 2, true
_, _ = stack.Pop() // 1, true
_, _ = stack.Pop() // nil, false (nothing to pop)
stack.Push(1) // 1
stack.Clear() // empty
stack.Empty() // true
stack.Size() // 0
}

@ -6,12 +6,13 @@ package main
import (
"fmt"
avl "github.com/emirpasic/gods/trees/avltree"
avl "github.com/emirpasic/gods/v2/trees/avltree"
)
// AVLTreeExample to demonstrate basic usage of AVLTree
func main() {
tree := avl.NewWithIntComparator() // empty(keys are of type int)
tree := avl.New[int, string]() // empty(keys are of type int)
tree.Put(1, "x") // 1->x
tree.Put(2, "b") // 1->x, 2->b (in order)

@ -5,32 +5,33 @@
package main
import (
"github.com/emirpasic/gods/trees/binaryheap"
"github.com/emirpasic/gods/utils"
"cmp"
"github.com/emirpasic/gods/v2/trees/binaryheap"
)
// BinaryHeapExample to demonstrate basic usage of BinaryHeap
func main() {
// Min-heap
heap := binaryheap.NewWithIntComparator() // empty (min-heap)
heap.Push(2) // 2
heap.Push(3) // 2, 3
heap.Push(1) // 1, 3, 2
heap.Values() // 1, 3, 2
_, _ = heap.Peek() // 1,true
_, _ = heap.Pop() // 1, true
_, _ = heap.Pop() // 2, true
_, _ = heap.Pop() // 3, true
_, _ = heap.Pop() // nil, false (nothing to pop)
heap.Push(1) // 1
heap.Clear() // empty
heap.Empty() // true
heap.Size() // 0
heap := binaryheap.New[int]() // empty (min-heap)
heap.Push(2) // 2
heap.Push(3) // 2, 3
heap.Push(1) // 1, 3, 2
heap.Values() // 1, 3, 2
_, _ = heap.Peek() // 1,true
_, _ = heap.Pop() // 1, true
_, _ = heap.Pop() // 2, true
_, _ = heap.Pop() // 3, true
_, _ = heap.Pop() // nil, false (nothing to pop)
heap.Push(1) // 1
heap.Clear() // empty
heap.Empty() // true
heap.Size() // 0
// Max-heap
inverseIntComparator := func(a, b interface{}) int {
return -utils.IntComparator(a, b)
inverseIntComparator := func(a, b int) int {
return -cmp.Compare(a, b)
}
heap = binaryheap.NewWith(inverseIntComparator) // empty (min-heap)
heap.Push(2) // 2

@ -6,12 +6,13 @@ package main
import (
"fmt"
"github.com/emirpasic/gods/trees/btree"
"github.com/emirpasic/gods/v2/trees/btree"
)
// BTreeExample to demonstrate basic usage of BTree
func main() {
tree := btree.NewWithIntComparator(3) // empty (keys are of type int)
tree := btree.New[int, string](3) // empty (keys are of type int)
tree.Put(1, "x") // 1->x
tree.Put(2, "b") // 1->x, 2->b (in order)

@ -0,0 +1,26 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import cb "github.com/emirpasic/gods/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
}

@ -6,7 +6,8 @@ package main
import (
"fmt"
"github.com/emirpasic/gods/sets/treeset"
"github.com/emirpasic/gods/v2/sets/treeset"
)
// User model (id and name)
@ -16,16 +17,12 @@ type User struct {
}
// Comparator function (sort by IDs)
func byID(a, b interface{}) int {
// Type assertion, program will panic if this is not respected
c1 := a.(User)
c2 := b.(User)
func byID(a, b User) int {
switch {
case c1.id > c2.id:
case a.id > b.id:
return 1
case c1.id < c2.id:
case a.id < b.id:
return -1
default:
return 0

@ -5,17 +5,18 @@
package main
import (
dll "github.com/emirpasic/gods/lists/doublylinkedlist"
"github.com/emirpasic/gods/utils"
"cmp"
dll "github.com/emirpasic/gods/v2/lists/doublylinkedlist"
)
// DoublyLinkedListExample to demonstrate basic usage of DoublyLinkedList
func main() {
list := dll.New()
list := dll.New[string]()
list.Add("a") // ["a"]
list.Append("b") // ["a","b"] (same as Add())
list.Prepend("c") // ["c","a","b"]
list.Sort(utils.StringComparator) // ["a","b","c"]
list.Sort(cmp.Compare[string]) // ["a","b","c"]
_, _ = list.Get(0) // "a",true
_, _ = list.Get(100) // nil,false
_ = list.Contains("a", "b", "c") // true

@ -6,12 +6,13 @@ package main
import (
"fmt"
"github.com/emirpasic/gods/sets/treeset"
"github.com/emirpasic/gods/v2/sets/treeset"
)
func printSet(txt string, set *treeset.Set) {
func printSet(txt string, set *treeset.Set[int]) {
fmt.Print(txt, "[ ")
set.Each(func(index int, value interface{}) {
set.Each(func(index int, value int) {
fmt.Print(value, " ")
})
fmt.Println("]")
@ -19,41 +20,41 @@ func printSet(txt string, set *treeset.Set) {
// EnumerableWithIndexExample to demonstrate basic usage of EnumerableWithIndex
func main() {
set := treeset.NewWithIntComparator()
set := treeset.New[int]()
set.Add(2, 3, 4, 2, 5, 6, 7, 8)
printSet("Initial", set) // [ 2 3 4 5 6 7 8 ]
even := set.Select(func(index int, value interface{}) bool {
return value.(int)%2 == 0
even := set.Select(func(index int, value int) bool {
return value%2 == 0
})
printSet("Even numbers", even) // [ 2 4 6 8 ]
foundIndex, foundValue := set.Find(func(index int, value interface{}) bool {
return value.(int)%2 == 0 && value.(int)%3 == 0
foundIndex, foundValue := set.Find(func(index int, value int) bool {
return value%2 == 0 && value%3 == 0
})
if foundIndex != -1 {
fmt.Println("Number divisible by 2 and 3 found is", foundValue, "at index", foundIndex) // value: 6, index: 4
}
square := set.Map(func(index int, value interface{}) interface{} {
return value.(int) * value.(int)
square := set.Map(func(index int, value int) int {
return value * value
})
printSet("Numbers squared", square) // [ 4 9 16 25 36 49 64 ]
bigger := set.Any(func(index int, value interface{}) bool {
return value.(int) > 5
bigger := set.Any(func(index int, value int) bool {
return value > 5
})
fmt.Println("Set contains a number bigger than 5 is ", bigger) // true
positive := set.All(func(index int, value interface{}) bool {
return value.(int) > 0
positive := set.All(func(index int, value int) bool {
return value > 0
})
fmt.Println("All numbers are positive is", positive) // true
evenNumbersSquared := set.Select(func(index int, value interface{}) bool {
return value.(int)%2 == 0
}).Map(func(index int, value interface{}) interface{} {
return value.(int) * value.(int)
evenNumbersSquared := set.Select(func(index int, value int) bool {
return value%2 == 0
}).Map(func(index int, value int) int {
return value * value
})
printSet("Chaining", evenNumbersSquared) // [ 4 16 36 64 ]
}

@ -6,12 +6,13 @@ package main
import (
"fmt"
"github.com/emirpasic/gods/maps/treemap"
"github.com/emirpasic/gods/v2/maps/treemap"
)
func printMap(txt string, m *treemap.Map) {
func printMap(txt string, m *treemap.Map[string, int]) {
fmt.Print(txt, " { ")
m.Each(func(key interface{}, value interface{}) {
m.Each(func(key string, value int) {
fmt.Print(key, ":", value, " ")
})
fmt.Println("}")
@ -19,7 +20,7 @@ func printMap(txt string, m *treemap.Map) {
// EunumerableWithKeyExample to demonstrate basic usage of EunumerableWithKey
func main() {
m := treemap.NewWithStringComparator()
m := treemap.New[string, int]()
m.Put("g", 7)
m.Put("f", 6)
m.Put("e", 5)
@ -29,37 +30,37 @@ func main() {
m.Put("a", 1)
printMap("Initial", m) // { a:1 b:2 c:3 d:4 e:5 f:6 g:7 }
even := m.Select(func(key interface{}, value interface{}) bool {
return value.(int)%2 == 0
even := m.Select(func(key string, value int) bool {
return value%2 == 0
})
printMap("Elements with even values", even) // { b:2 d:4 f:6 }
foundKey, foundValue := m.Find(func(key interface{}, value interface{}) bool {
return value.(int)%2 == 0 && value.(int)%3 == 0
foundKey, foundValue := m.Find(func(key string, value int) bool {
return value%2 == 0 && value%3 == 0
})
if foundKey != nil {
if foundKey != "" {
fmt.Println("Element with value divisible by 2 and 3 found is", foundValue, "with key", foundKey) // value: 6, index: 4
}
square := m.Map(func(key interface{}, value interface{}) (interface{}, interface{}) {
return key.(string) + key.(string), value.(int) * value.(int)
square := m.Map(func(key string, value int) (string, int) {
return key + key, value * value
})
printMap("Elements' values squared and letters duplicated", square) // { aa:1 bb:4 cc:9 dd:16 ee:25 ff:36 gg:49 }
bigger := m.Any(func(key interface{}, value interface{}) bool {
return value.(int) > 5
bigger := m.Any(func(key string, value int) bool {
return value > 5
})
fmt.Println("Map contains element whose value is bigger than 5 is", bigger) // true
positive := m.All(func(key interface{}, value interface{}) bool {
return value.(int) > 0
positive := m.All(func(key string, value int) bool {
return value > 0
})
fmt.Println("All map's elements have positive values is", positive) // true
evenNumbersSquared := m.Select(func(key interface{}, value interface{}) bool {
return value.(int)%2 == 0
}).Map(func(key interface{}, value interface{}) (interface{}, interface{}) {
return key, value.(int) * value.(int)
evenNumbersSquared := m.Select(func(key string, value int) bool {
return value%2 == 0
}).Map(func(key string, value int) (string, int) {
return key, value * value
})
printMap("Chaining", evenNumbersSquared) // { b:4 d:16 f:36 }
}

@ -1,17 +0,0 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import "github.com/emirpasic/gods/utils"
// SortExample to demonstrate basic usage of basic sort
func main() {
strings := []interface{}{} // []
strings = append(strings, "d") // ["d"]
strings = append(strings, "a") // ["d","a"]
strings = append(strings, "b") // ["d","a",b"
strings = append(strings, "c") // ["d","a",b","c"]
utils.Sort(strings, utils.StringComparator) // ["a","b","c","d"]
}

@ -4,22 +4,22 @@
package main
import "github.com/emirpasic/gods/maps/hashbidimap"
import "github.com/emirpasic/gods/v2/maps/hashbidimap"
// HashBidiMapExample to demonstrate basic usage of HashMap
func main() {
m := hashbidimap.New() // empty
m.Put(1, "x") // 1->x
m.Put(3, "b") // 1->x, 3->b (random order)
m.Put(1, "a") // 1->a, 3->b (random order)
m.Put(2, "b") // 1->a, 2->b (random order)
_, _ = m.GetKey("a") // 1, true
_, _ = m.Get(2) // b, true
_, _ = m.Get(3) // nil, false
_ = m.Values() // []interface {}{"a", "b"} (random order)
_ = m.Keys() // []interface {}{1, 2} (random order)
m.Remove(1) // 2->b
m.Clear() // empty
m.Empty() // true
m.Size() // 0
m := hashbidimap.New[int, string]() // empty
m.Put(1, "x") // 1->x
m.Put(3, "b") // 1->x, 3->b (random order)
m.Put(1, "a") // 1->a, 3->b (random order)
m.Put(2, "b") // 1->a, 2->b (random order)
_, _ = m.GetKey("a") // 1, true
_, _ = m.Get(2) // b, true
_, _ = m.Get(3) // nil, false
_ = m.Values() // []interface {}{"a", "b"} (random order)
_ = m.Keys() // []interface {}{1, 2} (random order)
m.Remove(1) // 2->b
m.Clear() // empty
m.Empty() // true
m.Size() // 0
}

@ -4,20 +4,20 @@
package main
import "github.com/emirpasic/gods/maps/hashmap"
import "github.com/emirpasic/gods/v2/maps/hashmap"
// HashMapExample to demonstrate basic usage of HashMap
func main() {
m := hashmap.New() // empty
m.Put(1, "x") // 1->x
m.Put(2, "b") // 2->b, 1->x (random order)
m.Put(1, "a") // 2->b, 1->a (random order)
_, _ = m.Get(2) // b, true
_, _ = m.Get(3) // nil, false
_ = m.Values() // []interface {}{"b", "a"} (random order)
_ = m.Keys() // []interface {}{1, 2} (random order)
m.Remove(1) // 2->b
m.Clear() // empty
m.Empty() // true
m.Size() // 0
m := hashmap.New[int, string]() // empty
m.Put(1, "x") // 1->x
m.Put(2, "b") // 2->b, 1->x (random order)
m.Put(1, "a") // 2->b, 1->a (random order)
_, _ = m.Get(2) // b, true
_, _ = m.Get(3) // nil, false
_ = m.Values() // []interface {}{"b", "a"} (random order)
_ = m.Keys() // []interface {}{1, 2} (random order)
m.Remove(1) // 2->b
m.Clear() // empty
m.Empty() // true
m.Size() // 0
}

@ -4,20 +4,20 @@
package main
import "github.com/emirpasic/gods/sets/hashset"
import "github.com/emirpasic/gods/v2/sets/hashset"
// HashSetExample to demonstrate basic usage of HashSet
func main() {
set := hashset.New() // empty (keys are of type int)
set.Add(1) // 1
set.Add(2, 2, 3, 4, 5) // 3, 1, 2, 4, 5 (random order, duplicates ignored)
set.Remove(4) // 5, 3, 2, 1 (random order)
set.Remove(2, 3) // 1, 5 (random order)
set.Contains(1) // true
set.Contains(1, 5) // true
set.Contains(1, 6) // false
_ = set.Values() // []int{5,1} (random order)
set.Clear() // empty
set.Empty() // true
set.Size() // 0
set := hashset.New[int]() // empty (keys are of type int)
set.Add(1) // 1
set.Add(2, 2, 3, 4, 5) // 3, 1, 2, 4, 5 (random order, duplicates ignored)
set.Remove(4) // 5, 3, 2, 1 (random order)
set.Remove(2, 3) // 1, 5 (random order)
set.Contains(1) // true
set.Contains(1, 5) // true
set.Contains(1, 6) // false
_ = set.Values() // []int{5,1} (random order)
set.Clear() // empty
set.Empty() // true
set.Size() // 0
}

@ -6,12 +6,14 @@ package main
import (
"fmt"
"github.com/emirpasic/gods/sets/treeset"
"strings"
"github.com/emirpasic/gods/v2/sets/treeset"
)
// IteratorWithIndexExample to demonstrate basic usage of IteratorWithIndex
func main() {
set := treeset.NewWithStringComparator()
set := treeset.New[string]()
set.Add("a", "b", "c")
it := set.Iterator()
@ -48,4 +50,32 @@ func main() {
fmt.Print("\nLast index: ", it.Index()) // Last index: 3
fmt.Print("\nLast value: ", it.Value()) // Last value: c
}
// Seek element starting with "b"
seek := func(index int, value 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"
*/
}

@ -6,15 +6,17 @@ package main
import (
"fmt"
"github.com/emirpasic/gods/maps/treemap"
"strings"
"github.com/emirpasic/gods/v2/maps/treemap"
)
// IteratorWithKeyExample to demonstrate basic usage of IteratorWithKey
func main() {
m := treemap.NewWithIntComparator()
m.Put(1, "a")
m.Put(2, "b")
m.Put(3, "a")
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")
@ -47,7 +49,34 @@ func main() {
}
if it.Last() {
fmt.Print("\nLast key: ", it.Key()) // Last key: 3
fmt.Print("\nLast key: ", it.Key()) // Last key: 2
fmt.Print("\nLast value: ", it.Value()) // Last value: c
}
// Seek key-value pair whose value starts with "b"
seek := func(key 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"
*/
}

@ -4,20 +4,20 @@
package main
import "github.com/emirpasic/gods/maps/linkedhashmap"
import "github.com/emirpasic/gods/v2/maps/linkedhashmap"
// LinkedHashMapExample to demonstrate basic usage of LinkedHashMapExample
func main() {
m := linkedhashmap.New() // empty (keys are of type int)
m.Put(2, "b") // 2->b
m.Put(1, "x") // 2->b, 1->x (insertion-order)
m.Put(1, "a") // 2->b, 1->a (insertion-order)
_, _ = m.Get(2) // b, true
_, _ = m.Get(3) // nil, false
_ = m.Values() // []interface {}{"b", "a"} (insertion-order)
_ = m.Keys() // []interface {}{2, 1} (insertion-order)
m.Remove(1) // 2->b
m.Clear() // empty
m.Empty() // true
m.Size() // 0
m := linkedhashmap.New[int, string]() // empty (keys are of type int)
m.Put(2, "b") // 2->b
m.Put(1, "x") // 2->b, 1->x (insertion-order)
m.Put(1, "a") // 2->b, 1->a (insertion-order)
_, _ = m.Get(2) // b, true
_, _ = m.Get(3) // nil, false
_ = m.Values() // []interface {}{"b", "a"} (insertion-order)
_ = m.Keys() // []interface {}{2, 1} (insertion-order)
m.Remove(1) // 2->b
m.Clear() // empty
m.Empty() // true
m.Size() // 0
}

@ -4,20 +4,20 @@
package main
import "github.com/emirpasic/gods/sets/linkedhashset"
import "github.com/emirpasic/gods/v2/sets/linkedhashset"
// LinkedHashSetExample to demonstrate basic usage of LinkedHashSet
func main() {
set := linkedhashset.New() // empty
set.Add(5) // 5
set.Add(4, 4, 3, 2, 1) // 5, 4, 3, 2, 1 (in insertion-order, duplicates ignored)
set.Remove(4) // 5, 3, 2, 1 (in insertion-order)
set.Remove(2, 3) // 5, 1 (in insertion-order)
set.Contains(1) // true
set.Contains(1, 5) // true
set.Contains(1, 6) // false
_ = set.Values() // []int{5, 1} (in insertion-order)
set.Clear() // empty
set.Empty() // true
set.Size() // 0
set := linkedhashset.New[int]() // empty
set.Add(5) // 5
set.Add(4, 4, 3, 2, 1) // 5, 4, 3, 2, 1 (in insertion-order, duplicates ignored)
set.Remove(4) // 5, 3, 2, 1 (in insertion-order)
set.Remove(2, 3) // 5, 1 (in insertion-order)
set.Contains(1) // true
set.Contains(1, 5) // true
set.Contains(1, 6) // false
_ = set.Values() // []int{5, 1} (in insertion-order)
set.Clear() // empty
set.Empty() // true
set.Size() // 0
}

@ -0,0 +1,23 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import llq "github.com/emirpasic/gods/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
}

@ -4,20 +4,20 @@
package main
import lls "github.com/emirpasic/gods/stacks/linkedliststack"
import lls "github.com/emirpasic/gods/v2/stacks/linkedliststack"
// LinkedListStackExample to demonstrate basic usage of LinkedListStack
func main() {
stack := lls.New() // empty
stack.Push(1) // 1
stack.Push(2) // 1, 2
stack.Values() // 2, 1 (LIFO order)
_, _ = stack.Peek() // 2,true
_, _ = stack.Pop() // 2, true
_, _ = stack.Pop() // 1, true
_, _ = stack.Pop() // nil, false (nothing to pop)
stack.Push(1) // 1
stack.Clear() // empty
stack.Empty() // true
stack.Size() // 0
stack := lls.New[int]() // empty
stack.Push(1) // 1
stack.Push(2) // 1, 2
stack.Values() // 2, 1 (LIFO order)
_, _ = stack.Peek() // 2,true
_, _ = stack.Pop() // 2, true
_, _ = stack.Pop() // 1, true
_, _ = stack.Pop() // nil, false (nothing to pop)
stack.Push(1) // 1
stack.Clear() // empty
stack.Empty() // true
stack.Size() // 0
}

@ -0,0 +1,43 @@
// 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() // <nil> false (nothing to dequeue)
queue.Clear() // empty
_ = queue.Empty() // true
_ = queue.Size() // 0
}

@ -6,12 +6,13 @@ package main
import (
"fmt"
rbt "github.com/emirpasic/gods/trees/redblacktree"
rbt "github.com/emirpasic/gods/v2/trees/redblacktree"
)
// RedBlackTreeExample to demonstrate basic usage of RedBlackTree
func main() {
tree := rbt.NewWithIntComparator() // empty(keys are of type int)
tree := rbt.New[int, string]() // empty(keys are of type int)
tree.Put(1, "x") // 1->x
tree.Put(2, "b") // 1->x, 2->b (in order)

@ -6,53 +6,54 @@ package redblacktreeextended
import (
"fmt"
rbt "github.com/emirpasic/gods/trees/redblacktree"
rbt "github.com/emirpasic/gods/v2/trees/redblacktree"
)
// RedBlackTreeExtended to demonstrate how to extend a RedBlackTree to include new functions
type RedBlackTreeExtended struct {
*rbt.Tree
type RedBlackTreeExtended[K comparable, V any] struct {
*rbt.Tree[K, V]
}
// GetMin gets the min value and flag if found
func (tree *RedBlackTreeExtended) GetMin() (value interface{}, found bool) {
func (tree *RedBlackTreeExtended[K, V]) GetMin() (value V, found bool) {
node, found := tree.getMinFromNode(tree.Root)
if node != nil {
if found {
return node.Value, found
}
return nil, false
return value, false
}
// GetMax gets the max value and flag if found
func (tree *RedBlackTreeExtended) GetMax() (value interface{}, found bool) {
func (tree *RedBlackTreeExtended[K, V]) GetMax() (value V, found bool) {
node, found := tree.getMaxFromNode(tree.Root)
if node != nil {
if found {
return node.Value, found
}
return nil, false
return value, false
}
// RemoveMin removes the min value and flag if found
func (tree *RedBlackTreeExtended) RemoveMin() (value interface{}, deleted bool) {
func (tree *RedBlackTreeExtended[K, V]) RemoveMin() (value V, deleted bool) {
node, found := tree.getMinFromNode(tree.Root)
if found {
tree.Remove(node.Key)
return node.Value, found
}
return nil, false
return value, false
}
// RemoveMax removes the max value and flag if found
func (tree *RedBlackTreeExtended) RemoveMax() (value interface{}, deleted bool) {
func (tree *RedBlackTreeExtended[K, V]) RemoveMax() (value V, deleted bool) {
node, found := tree.getMaxFromNode(tree.Root)
if found {
tree.Remove(node.Key)
return node.Value, found
}
return nil, false
return value, false
}
func (tree *RedBlackTreeExtended) getMinFromNode(node *rbt.Node) (foundNode *rbt.Node, found bool) {
func (tree *RedBlackTreeExtended[K, V]) getMinFromNode(node *rbt.Node[K, V]) (foundNode *rbt.Node[K, V], found bool) {
if node == nil {
return nil, false
}
@ -62,7 +63,7 @@ func (tree *RedBlackTreeExtended) getMinFromNode(node *rbt.Node) (foundNode *rbt
return tree.getMinFromNode(node.Left)
}
func (tree *RedBlackTreeExtended) getMaxFromNode(node *rbt.Node) (foundNode *rbt.Node, found bool) {
func (tree *RedBlackTreeExtended[K, V]) getMaxFromNode(node *rbt.Node[K, V]) (foundNode *rbt.Node[K, V], found bool) {
if node == nil {
return nil, false
}
@ -72,7 +73,7 @@ func (tree *RedBlackTreeExtended) getMaxFromNode(node *rbt.Node) (foundNode *rbt
return tree.getMaxFromNode(node.Right)
}
func print(tree *RedBlackTreeExtended) {
func print(tree *RedBlackTreeExtended[int, string]) {
max, _ := tree.GetMax()
min, _ := tree.GetMin()
fmt.Printf("Value for max key: %v \n", max)
@ -82,7 +83,7 @@ func print(tree *RedBlackTreeExtended) {
// RedBlackTreeExtendedExample main method on how to use the custom red-black tree above
func main() {
tree := RedBlackTreeExtended{rbt.NewWithIntComparator()}
tree := RedBlackTreeExtended[int, string]{rbt.New[int, string]()}
tree.Put(1, "a") // 1->x (in order)
tree.Put(2, "b") // 1->x, 2->b (in order)

@ -2,13 +2,14 @@ package serialization
import (
"fmt"
"github.com/emirpasic/gods/lists/arraylist"
"github.com/emirpasic/gods/maps/hashmap"
"github.com/emirpasic/gods/v2/lists/arraylist"
"github.com/emirpasic/gods/v2/maps/hashmap"
)
// ListSerializationExample demonstrates how to serialize and deserialize lists to and from JSON
func ListSerializationExample() {
list := arraylist.New()
list := arraylist.New[string]()
list.Add("a", "b", "c")
// Serialization (marshalling)
@ -29,7 +30,7 @@ func ListSerializationExample() {
// MapSerializationExample demonstrates how to serialize and deserialize maps to and from JSON
func MapSerializationExample() {
m := hashmap.New()
m := hashmap.New[string, string]()
m.Put("a", "1")
m.Put("b", "2")
m.Put("c", "3")

@ -5,17 +5,18 @@
package main
import (
sll "github.com/emirpasic/gods/lists/singlylinkedlist"
"github.com/emirpasic/gods/utils"
"cmp"
sll "github.com/emirpasic/gods/v2/lists/singlylinkedlist"
)
// SinglyLinkedListExample to demonstrate basic usage of SinglyLinkedList
func main() {
list := sll.New()
list := sll.New[string]()
list.Add("a") // ["a"]
list.Append("b") // ["a","b"] (same as Add())
list.Prepend("c") // ["c","a","b"]
list.Sort(utils.StringComparator) // ["a","b","c"]
list.Sort(cmp.Compare[string]) // ["a","b","c"]
_, _ = list.Get(0) // "a",true
_, _ = list.Get(100) // nil,false
_ = list.Contains("a", "b", "c") // true

@ -5,13 +5,12 @@
package main
import (
"github.com/emirpasic/gods/maps/treebidimap"
"github.com/emirpasic/gods/utils"
"github.com/emirpasic/gods/v2/maps/treebidimap"
)
// TreeBidiMapExample to demonstrate basic usage of TreeBidiMap
func main() {
m := treebidimap.NewWith(utils.IntComparator, utils.StringComparator)
m := treebidimap.New[int, string]()
m.Put(1, "x") // 1->x
m.Put(3, "b") // 1->x, 3->b (ordered)
m.Put(1, "a") // 1->a, 3->b (ordered)

@ -4,20 +4,20 @@
package main
import "github.com/emirpasic/gods/maps/treemap"
import "github.com/emirpasic/gods/v2/maps/treemap"
// TreeMapExample to demonstrate basic usage of TreeMap
func main() {
m := treemap.NewWithIntComparator() // empty (keys are of type int)
m.Put(1, "x") // 1->x
m.Put(2, "b") // 1->x, 2->b (in order)
m.Put(1, "a") // 1->a, 2->b (in order)
_, _ = m.Get(2) // b, true
_, _ = m.Get(3) // nil, false
_ = m.Values() // []interface {}{"a", "b"} (in order)
_ = m.Keys() // []interface {}{1, 2} (in order)
m.Remove(1) // 2->b
m.Clear() // empty
m.Empty() // true
m.Size() // 0
m := treemap.New[int, string]() // empty
m.Put(1, "x") // 1->x
m.Put(2, "b") // 1->x, 2->b (in order)
m.Put(1, "a") // 1->a, 2->b (in order)
_, _ = m.Get(2) // b, true
_, _ = m.Get(3) // nil, false
_ = m.Values() // []interface {}{"a", "b"} (in order)
_ = m.Keys() // []interface {}{1, 2} (in order)
m.Remove(1) // 2->b
m.Clear() // empty
m.Empty() // true
m.Size() // 0
}

@ -4,20 +4,20 @@
package main
import "github.com/emirpasic/gods/sets/treeset"
import "github.com/emirpasic/gods/v2/sets/treeset"
// TreeSetExample to demonstrate basic usage of TreeSet
func main() {
set := treeset.NewWithIntComparator() // empty
set.Add(1) // 1
set.Add(2, 2, 3, 4, 5) // 1, 2, 3, 4, 5 (in order, duplicates ignored)
set.Remove(4) // 1, 2, 3, 5 (in order)
set.Remove(2, 3) // 1, 5 (in order)
set.Contains(1) // true
set.Contains(1, 5) // true
set.Contains(1, 6) // false
_ = set.Values() // []int{1,5} (in order)
set.Clear() // empty
set.Empty() // true
set.Size() // 0
set := treeset.New[int]() // empty
set.Add(1) // 1
set.Add(2, 2, 3, 4, 5) // 1, 2, 3, 4, 5 (in order, duplicates ignored)
set.Remove(4) // 1, 2, 3, 5 (in order)
set.Remove(2, 3) // 1, 5 (in order)
set.Contains(1) // true
set.Contains(1, 5) // true
set.Contains(1, 6) // false
_ = set.Values() // []int{1,5} (in order)
set.Clear() // empty
set.Empty() // true
set.Size() // 0
}

@ -1,3 +1,3 @@
module github.com/emirpasic/gods
module github.com/emirpasic/gods/v2
go 1.2
go 1.21

@ -0,0 +1,2 @@
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=

@ -11,19 +11,19 @@ package arraylist
import (
"fmt"
"slices"
"strings"
"github.com/emirpasic/gods/lists"
"github.com/emirpasic/gods/utils"
"github.com/emirpasic/gods/v2/lists"
"github.com/emirpasic/gods/v2/utils"
)
func assertListImplementation() {
var _ lists.List = (*List)(nil)
}
// Assert List implementation
var _ lists.List[int] = (*List[int])(nil)
// List holds the elements in a slice
type List struct {
elements []interface{}
type List[T comparable] struct {
elements []T
size int
}
@ -33,8 +33,8 @@ const (
)
// New instantiates a new list and adds the passed values, if any, to the list
func New(values ...interface{}) *List {
list := &List{}
func New[T comparable](values ...T) *List[T] {
list := &List[T]{}
if len(values) > 0 {
list.Add(values...)
}
@ -42,7 +42,7 @@ func New(values ...interface{}) *List {
}
// Add appends a value at the end of the list
func (list *List) Add(values ...interface{}) {
func (list *List[T]) Add(values ...T) {
list.growBy(len(values))
for _, value := range values {
list.elements[list.size] = value
@ -52,23 +52,24 @@ func (list *List) Add(values ...interface{}) {
// Get returns the element at index.
// Second return parameter is true if index is within bounds of the array and array is not empty, otherwise false.
func (list *List) Get(index int) (interface{}, bool) {
func (list *List[T]) Get(index int) (T, bool) {
if !list.withinRange(index) {
return nil, false
var t T
return t, false
}
return list.elements[index], true
}
// Remove removes the element at the given index from the list.
func (list *List) Remove(index int) {
func (list *List[T]) Remove(index int) {
if !list.withinRange(index) {
return
}
list.elements[index] = nil // cleanup reference
clear(list.elements[index : index+1])
copy(list.elements[index:], list.elements[index+1:list.size]) // shift to the left by one (slow operation, need ways to optimize this)
list.size--
@ -79,12 +80,12 @@ func (list *List) Remove(index int) {
// All elements have to be present in the set for the method to return true.
// Performance time complexity of n^2.
// Returns true if no arguments are passed at all, i.e. set is always super-set of empty set.
func (list *List) Contains(values ...interface{}) bool {
func (list *List[T]) Contains(values ...T) bool {
for _, searchValue := range values {
found := false
for _, element := range list.elements {
if element == searchValue {
for index := 0; index < list.size; index++ {
if list.elements[index] == searchValue {
found = true
break
}
@ -97,14 +98,14 @@ func (list *List) Contains(values ...interface{}) bool {
}
// Values returns all elements in the list.
func (list *List) Values() []interface{} {
newElements := make([]interface{}, list.size, list.size)
func (list *List[T]) Values() []T {
newElements := make([]T, list.size, list.size)
copy(newElements, list.elements[:list.size])
return newElements
}
//IndexOf returns index of provided element
func (list *List) IndexOf(value interface{}) int {
// IndexOf returns index of provided element
func (list *List[T]) IndexOf(value T) int {
if list.size == 0 {
return -1
}
@ -117,31 +118,31 @@ func (list *List) IndexOf(value interface{}) int {
}
// Empty returns true if list does not contain any elements.
func (list *List) Empty() bool {
func (list *List[T]) Empty() bool {
return list.size == 0
}
// Size returns number of elements within the list.
func (list *List) Size() int {
func (list *List[T]) Size() int {
return list.size
}
// Clear removes all elements from the list.
func (list *List) Clear() {
func (list *List[T]) Clear() {
list.size = 0
list.elements = []interface{}{}
list.elements = []T{}
}
// Sort sorts values (in-place) using.
func (list *List) Sort(comparator utils.Comparator) {
func (list *List[T]) Sort(comparator utils.Comparator[T]) {
if len(list.elements) < 2 {
return
}
utils.Sort(list.elements[:list.size], comparator)
slices.SortFunc(list.elements[:list.size], comparator)
}
// Swap swaps the two values at the specified positions.
func (list *List) Swap(i, j int) {
func (list *List[T]) Swap(i, j int) {
if list.withinRange(i) && list.withinRange(j) {
list.elements[i], list.elements[j] = list.elements[j], list.elements[i]
}
@ -150,7 +151,7 @@ func (list *List) Swap(i, j int) {
// Insert inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right.
// Does not do anything if position is negative or bigger than list's size
// Note: position equal to list's size is valid, i.e. append.
func (list *List) Insert(index int, values ...interface{}) {
func (list *List[T]) Insert(index int, values ...T) {
if !list.withinRange(index) {
// Append
@ -170,7 +171,7 @@ func (list *List) Insert(index int, values ...interface{}) {
// Set the value at specified index
// Does not do anything if position is negative or bigger than list's size
// Note: position equal to list's size is valid, i.e. append.
func (list *List) Set(index int, value interface{}) {
func (list *List[T]) Set(index int, value T) {
if !list.withinRange(index) {
// Append
@ -184,9 +185,9 @@ func (list *List) Set(index int, value interface{}) {
}
// String returns a string representation of container
func (list *List) String() string {
func (list *List[T]) String() string {
str := "ArrayList\n"
values := []string{}
values := make([]string, 0, list.size)
for _, value := range list.elements[:list.size] {
values = append(values, fmt.Sprintf("%v", value))
}
@ -195,18 +196,18 @@ func (list *List) String() string {
}
// Check that the index is within bounds of the list
func (list *List) withinRange(index int) bool {
func (list *List[T]) withinRange(index int) bool {
return index >= 0 && index < list.size
}
func (list *List) resize(cap int) {
newElements := make([]interface{}, cap, cap)
func (list *List[T]) resize(cap int) {
newElements := make([]T, cap, cap)
copy(newElements, list.elements)
list.elements = newElements
}
// Expand the array if necessary, i.e. capacity will be reached if we add n elements
func (list *List) growBy(n int) {
func (list *List[T]) growBy(n int) {
// When capacity is reached, grow by a factor of growthFactor and add number of elements
currentCapacity := cap(list.elements)
if list.size+n >= currentCapacity {
@ -216,7 +217,7 @@ func (list *List) growBy(n int) {
}
// Shrink the array if necessary, i.e. when size is shrinkFactor percent of current capacity
func (list *List) shrink() {
func (list *List[T]) shrink() {
if shrinkFactor == 0.0 {
return
}

@ -5,19 +5,21 @@
package arraylist
import (
"fmt"
"github.com/emirpasic/gods/utils"
"cmp"
"encoding/json"
"slices"
"strings"
"testing"
)
func TestListNew(t *testing.T) {
list1 := New()
list1 := New[int]()
if actualValue := list1.Empty(); actualValue != true {
t.Errorf("Got %v expected %v", actualValue, true)
}
list2 := New(1, "b")
list2 := New[int](1, 2)
if actualValue := list2.Size(); actualValue != 2 {
t.Errorf("Got %v expected %v", actualValue, 2)
@ -27,17 +29,17 @@ func TestListNew(t *testing.T) {
t.Errorf("Got %v expected %v", actualValue, 1)
}
if actualValue, ok := list2.Get(1); actualValue != "b" || !ok {
t.Errorf("Got %v expected %v", actualValue, "b")
if actualValue, ok := list2.Get(1); actualValue != 2 || !ok {
t.Errorf("Got %v expected %v", actualValue, 2)
}
if actualValue, ok := list2.Get(2); actualValue != nil || ok {
t.Errorf("Got %v expected %v", actualValue, nil)
if actualValue, ok := list2.Get(2); actualValue != 0 || ok {
t.Errorf("Got %v expected %v", actualValue, 0)
}
}
func TestListAdd(t *testing.T) {
list := New()
list := New[string]()
list.Add("a")
list.Add("b", "c")
if actualValue := list.Empty(); actualValue != false {
@ -52,7 +54,7 @@ func TestListAdd(t *testing.T) {
}
func TestListIndexOf(t *testing.T) {
list := New()
list := New[string]()
expectedIndex := -1
if index := list.IndexOf("a"); index != expectedIndex {
@ -79,12 +81,12 @@ func TestListIndexOf(t *testing.T) {
}
func TestListRemove(t *testing.T) {
list := New()
list := New[string]()
list.Add("a")
list.Add("b", "c")
list.Remove(2)
if actualValue, ok := list.Get(2); actualValue != nil || ok {
t.Errorf("Got %v expected %v", actualValue, nil)
if actualValue, ok := list.Get(2); actualValue != "" || ok {
t.Errorf("Got %v expected %v", actualValue, "")
}
list.Remove(1)
list.Remove(0)
@ -98,7 +100,7 @@ func TestListRemove(t *testing.T) {
}
func TestListGet(t *testing.T) {
list := New()
list := New[string]()
list.Add("a")
list.Add("b", "c")
if actualValue, ok := list.Get(0); actualValue != "a" || !ok {
@ -110,8 +112,8 @@ func TestListGet(t *testing.T) {
if actualValue, ok := list.Get(2); actualValue != "c" || !ok {
t.Errorf("Got %v expected %v", actualValue, "c")
}
if actualValue, ok := list.Get(3); actualValue != nil || ok {
t.Errorf("Got %v expected %v", actualValue, nil)
if actualValue, ok := list.Get(3); actualValue != "" || ok {
t.Errorf("Got %v expected %v", actualValue, "")
}
list.Remove(0)
if actualValue, ok := list.Get(0); actualValue != "b" || !ok {
@ -120,7 +122,7 @@ func TestListGet(t *testing.T) {
}
func TestListSwap(t *testing.T) {
list := New()
list := New[string]()
list.Add("a")
list.Add("b", "c")
list.Swap(0, 1)
@ -130,21 +132,21 @@ func TestListSwap(t *testing.T) {
}
func TestListSort(t *testing.T) {
list := New()
list.Sort(utils.StringComparator)
list := New[string]()
list.Sort(cmp.Compare[string])
list.Add("e", "f", "g", "a", "b", "c", "d")
list.Sort(utils.StringComparator)
list.Sort(cmp.Compare[string])
for i := 1; i < list.Size(); i++ {
a, _ := list.Get(i - 1)
b, _ := list.Get(i)
if a.(string) > b.(string) {
if a > b {
t.Errorf("Not sorted! %s > %s", a, b)
}
}
}
func TestListClear(t *testing.T) {
list := New()
list := New[string]()
list.Add("e", "f", "g", "a", "b", "c", "d")
list.Clear()
if actualValue := list.Empty(); actualValue != true {
@ -156,12 +158,15 @@ func TestListClear(t *testing.T) {
}
func TestListContains(t *testing.T) {
list := New()
list := New[string]()
list.Add("a")
list.Add("b", "c")
if actualValue := list.Contains("a"); actualValue != true {
t.Errorf("Got %v expected %v", actualValue, true)
}
if actualValue := list.Contains(""); actualValue != false {
t.Errorf("Got %v expected %v", actualValue, false)
}
if actualValue := list.Contains("a", "b", "c"); actualValue != true {
t.Errorf("Got %v expected %v", actualValue, true)
}
@ -178,16 +183,16 @@ func TestListContains(t *testing.T) {
}
func TestListValues(t *testing.T) {
list := New()
list := New[string]()
list.Add("a")
list.Add("b", "c")
if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abc"; actualValue != expectedValue {
if actualValue, expectedValue := list.Values(), []string{"a", "b", "c"}; !slices.Equal(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
}
func TestListInsert(t *testing.T) {
list := New()
list := New[string]()
list.Insert(0, "b", "c")
list.Insert(0, "a")
list.Insert(10, "x") // ignore
@ -198,13 +203,13 @@ func TestListInsert(t *testing.T) {
if actualValue := list.Size(); actualValue != 4 {
t.Errorf("Got %v expected %v", actualValue, 4)
}
if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", list.Values()...), "abcd"; actualValue != expectedValue {
if actualValue, expectedValue := strings.Join(list.Values(), ""), "abcd"; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
}
func TestListSet(t *testing.T) {
list := New()
list := New[string]()
list.Set(0, "a")
list.Set(1, "b")
if actualValue := list.Size(); actualValue != 2 {
@ -219,15 +224,15 @@ func TestListSet(t *testing.T) {
if actualValue := list.Size(); actualValue != 3 {
t.Errorf("Got %v expected %v", actualValue, 3)
}
if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abbc"; actualValue != expectedValue {
if actualValue, expectedValue := list.Values(), []string{"a", "bb", "c"}; !slices.Equal(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
}
func TestListEach(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
list.Each(func(index int, value interface{}) {
list.Each(func(index int, value string) {
switch index {
case 0:
if actualValue, expectedValue := value, "a"; actualValue != expectedValue {
@ -248,10 +253,10 @@ func TestListEach(t *testing.T) {
}
func TestListMap(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
mappedList := list.Map(func(index int, value interface{}) interface{} {
return "mapped: " + value.(string)
mappedList := list.Map(func(index int, value string) string {
return "mapped: " + value
})
if actualValue, _ := mappedList.Get(0); actualValue != "mapped: a" {
t.Errorf("Got %v expected %v", actualValue, "mapped: a")
@ -268,10 +273,10 @@ func TestListMap(t *testing.T) {
}
func TestListSelect(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
selectedList := list.Select(func(index int, value interface{}) bool {
return value.(string) >= "a" && value.(string) <= "b"
selectedList := list.Select(func(index int, value string) bool {
return value >= "a" && value <= "b"
})
if actualValue, _ := selectedList.Get(0); actualValue != "a" {
t.Errorf("Got %v expected %v", actualValue, "value: a")
@ -285,60 +290,60 @@ func TestListSelect(t *testing.T) {
}
func TestListAny(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
any := list.Any(func(index int, value interface{}) bool {
return value.(string) == "c"
any := list.Any(func(index int, value string) bool {
return value == "c"
})
if any != true {
t.Errorf("Got %v expected %v", any, true)
}
any = list.Any(func(index int, value interface{}) bool {
return value.(string) == "x"
any = list.Any(func(index int, value string) bool {
return value == "x"
})
if any != false {
t.Errorf("Got %v expected %v", any, false)
}
}
func TestListAll(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
all := list.All(func(index int, value interface{}) bool {
return value.(string) >= "a" && value.(string) <= "c"
all := list.All(func(index int, value string) bool {
return value >= "a" && value <= "c"
})
if all != true {
t.Errorf("Got %v expected %v", all, true)
}
all = list.All(func(index int, value interface{}) bool {
return value.(string) >= "a" && value.(string) <= "b"
all = list.All(func(index int, value string) bool {
return value >= "a" && value <= "b"
})
if all != false {
t.Errorf("Got %v expected %v", all, false)
}
}
func TestListFind(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
foundIndex, foundValue := list.Find(func(index int, value interface{}) bool {
return value.(string) == "c"
foundIndex, foundValue := list.Find(func(index int, value string) bool {
return value == "c"
})
if foundValue != "c" || foundIndex != 2 {
t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, "c", 2)
}
foundIndex, foundValue = list.Find(func(index int, value interface{}) bool {
return value.(string) == "x"
foundIndex, foundValue = list.Find(func(index int, value string) bool {
return value == "x"
})
if foundValue != nil || foundIndex != -1 {
if foundValue != "" || foundIndex != -1 {
t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil)
}
}
func TestListChaining(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
chainedList := list.Select(func(index int, value interface{}) bool {
return value.(string) > "a"
}).Map(func(index int, value interface{}) interface{} {
return value.(string) + value.(string)
chainedList := list.Select(func(index int, value string) bool {
return value > "a"
}).Map(func(index int, value string) string {
return value + value
})
if chainedList.Size() != 2 {
t.Errorf("Got %v expected %v", chainedList.Size(), 2)
@ -352,7 +357,7 @@ func TestListChaining(t *testing.T) {
}
func TestListIteratorNextOnEmpty(t *testing.T) {
list := New()
list := New[string]()
it := list.Iterator()
for it.Next() {
t.Errorf("Shouldn't iterate on empty list")
@ -360,7 +365,7 @@ func TestListIteratorNextOnEmpty(t *testing.T) {
}
func TestListIteratorNext(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
it := list.Iterator()
count := 0
@ -391,7 +396,7 @@ func TestListIteratorNext(t *testing.T) {
}
func TestListIteratorPrevOnEmpty(t *testing.T) {
list := New()
list := New[string]()
it := list.Iterator()
for it.Prev() {
t.Errorf("Shouldn't iterate on empty list")
@ -399,7 +404,7 @@ func TestListIteratorPrevOnEmpty(t *testing.T) {
}
func TestListIteratorPrev(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
it := list.Iterator()
for it.Next() {
@ -432,7 +437,7 @@ func TestListIteratorPrev(t *testing.T) {
}
func TestListIteratorBegin(t *testing.T) {
list := New()
list := New[string]()
it := list.Iterator()
it.Begin()
list.Add("a", "b", "c")
@ -446,7 +451,7 @@ func TestListIteratorBegin(t *testing.T) {
}
func TestListIteratorEnd(t *testing.T) {
list := New()
list := New[string]()
it := list.Iterator()
if index := it.Index(); index != -1 {
@ -471,7 +476,7 @@ func TestListIteratorEnd(t *testing.T) {
}
func TestListIteratorFirst(t *testing.T) {
list := New()
list := New[string]()
it := list.Iterator()
if actualValue, expectedValue := it.First(), false; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
@ -486,7 +491,7 @@ func TestListIteratorFirst(t *testing.T) {
}
func TestListIteratorLast(t *testing.T) {
list := New()
list := New[string]()
it := list.Iterator()
if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
@ -500,13 +505,113 @@ func TestListIteratorLast(t *testing.T) {
}
}
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()
list := New[string]()
list.Add("a", "b", "c")
var err error
assert := func() {
if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abc"; actualValue != expectedValue {
if actualValue, expectedValue := list.Values(), []string{"a", "b", "c"}; !slices.Equal(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue, expectedValue := list.Size(), 3; actualValue != expectedValue {
@ -519,14 +624,33 @@ func TestListSerialization(t *testing.T) {
assert()
json, err := list.ToJSON()
bytes, err := list.ToJSON()
assert()
err = list.FromJSON(json)
err = list.FromJSON(bytes)
assert()
bytes, err = json.Marshal([]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, size int) {
func benchmarkGet(b *testing.B, list *List[int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
list.Get(n)
@ -534,7 +658,7 @@ func benchmarkGet(b *testing.B, list *List, size int) {
}
}
func benchmarkAdd(b *testing.B, list *List, size int) {
func benchmarkAdd(b *testing.B, list *List[int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
list.Add(n)
@ -542,7 +666,7 @@ func benchmarkAdd(b *testing.B, list *List, size int) {
}
}
func benchmarkRemove(b *testing.B, list *List, size int) {
func benchmarkRemove(b *testing.B, list *List[int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
list.Remove(n)
@ -553,7 +677,7 @@ func benchmarkRemove(b *testing.B, list *List, size int) {
func BenchmarkArrayListGet100(b *testing.B) {
b.StopTimer()
size := 100
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -564,7 +688,7 @@ func BenchmarkArrayListGet100(b *testing.B) {
func BenchmarkArrayListGet1000(b *testing.B) {
b.StopTimer()
size := 1000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -575,7 +699,7 @@ func BenchmarkArrayListGet1000(b *testing.B) {
func BenchmarkArrayListGet10000(b *testing.B) {
b.StopTimer()
size := 10000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -586,7 +710,7 @@ func BenchmarkArrayListGet10000(b *testing.B) {
func BenchmarkArrayListGet100000(b *testing.B) {
b.StopTimer()
size := 100000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -597,7 +721,7 @@ func BenchmarkArrayListGet100000(b *testing.B) {
func BenchmarkArrayListAdd100(b *testing.B) {
b.StopTimer()
size := 100
list := New()
list := New[int]()
b.StartTimer()
benchmarkAdd(b, list, size)
}
@ -605,7 +729,7 @@ func BenchmarkArrayListAdd100(b *testing.B) {
func BenchmarkArrayListAdd1000(b *testing.B) {
b.StopTimer()
size := 1000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -616,7 +740,7 @@ func BenchmarkArrayListAdd1000(b *testing.B) {
func BenchmarkArrayListAdd10000(b *testing.B) {
b.StopTimer()
size := 10000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -627,7 +751,7 @@ func BenchmarkArrayListAdd10000(b *testing.B) {
func BenchmarkArrayListAdd100000(b *testing.B) {
b.StopTimer()
size := 100000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -638,7 +762,7 @@ func BenchmarkArrayListAdd100000(b *testing.B) {
func BenchmarkArrayListRemove100(b *testing.B) {
b.StopTimer()
size := 100
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -649,7 +773,7 @@ func BenchmarkArrayListRemove100(b *testing.B) {
func BenchmarkArrayListRemove1000(b *testing.B) {
b.StopTimer()
size := 1000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -660,7 +784,7 @@ func BenchmarkArrayListRemove1000(b *testing.B) {
func BenchmarkArrayListRemove10000(b *testing.B) {
b.StopTimer()
size := 10000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -671,7 +795,7 @@ func BenchmarkArrayListRemove10000(b *testing.B) {
func BenchmarkArrayListRemove100000(b *testing.B) {
b.StopTimer()
size := 100000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}

@ -4,14 +4,13 @@
package arraylist
import "github.com/emirpasic/gods/containers"
import "github.com/emirpasic/gods/v2/containers"
func assertEnumerableImplementation() {
var _ containers.EnumerableWithIndex = (*List)(nil)
}
// 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) Each(f func(index int, value interface{})) {
func (list *List[T]) Each(f func(index int, value T)) {
iterator := list.Iterator()
for iterator.Next() {
f(iterator.Index(), iterator.Value())
@ -20,8 +19,8 @@ func (list *List) Each(f func(index int, value interface{})) {
// Map invokes the given function once for each element and returns a
// container containing the values returned by the given function.
func (list *List) Map(f func(index int, value interface{}) interface{}) *List {
newList := &List{}
func (list *List[T]) Map(f func(index int, value T) T) *List[T] {
newList := &List[T]{}
iterator := list.Iterator()
for iterator.Next() {
newList.Add(f(iterator.Index(), iterator.Value()))
@ -30,8 +29,8 @@ func (list *List) Map(f func(index int, value interface{}) interface{}) *List {
}
// Select returns a new container containing all elements for which the given function returns a true value.
func (list *List) Select(f func(index int, value interface{}) bool) *List {
newList := &List{}
func (list *List[T]) Select(f func(index int, value T) bool) *List[T] {
newList := &List[T]{}
iterator := list.Iterator()
for iterator.Next() {
if f(iterator.Index(), iterator.Value()) {
@ -43,7 +42,7 @@ func (list *List) Select(f func(index int, value interface{}) bool) *List {
// Any passes each element of the collection to the given function and
// returns true if the function ever returns true for any element.
func (list *List) Any(f func(index int, value interface{}) bool) bool {
func (list *List[T]) Any(f func(index int, value T) bool) bool {
iterator := list.Iterator()
for iterator.Next() {
if f(iterator.Index(), iterator.Value()) {
@ -55,7 +54,7 @@ func (list *List) Any(f func(index int, value interface{}) bool) bool {
// All passes each element of the collection to the given function and
// returns true if the function returns true for all elements.
func (list *List) All(f func(index int, value interface{}) bool) bool {
func (list *List[T]) All(f func(index int, value T) bool) bool {
iterator := list.Iterator()
for iterator.Next() {
if !f(iterator.Index(), iterator.Value()) {
@ -68,12 +67,13 @@ func (list *List) All(f func(index int, value interface{}) bool) bool {
// Find passes each element of the container to the given function and returns
// the first (index,value) for which the function is true or -1,nil otherwise
// if no element matches the criteria.
func (list *List) Find(f func(index int, value interface{}) bool) (int, interface{}) {
func (list *List[T]) Find(f func(index int, value T) bool) (int, T) {
iterator := list.Iterator()
for iterator.Next() {
if f(iterator.Index(), iterator.Value()) {
return iterator.Index(), iterator.Value()
}
}
return -1, nil
var t T
return -1, t
}

@ -4,28 +4,27 @@
package arraylist
import "github.com/emirpasic/gods/containers"
import "github.com/emirpasic/gods/v2/containers"
func assertIteratorImplementation() {
var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil)
}
// Assert Iterator implementation
var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil)
// Iterator holding the iterator's state
type Iterator struct {
list *List
type Iterator[T comparable] struct {
list *List[T]
index int
}
// Iterator returns a stateful iterator whose values can be fetched by an index.
func (list *List) Iterator() Iterator {
return Iterator{list: list, index: -1}
func (list *List[T]) Iterator() *Iterator[T] {
return &Iterator[T]{list: list, index: -1}
}
// Next moves the iterator to the next element and returns true if there was a next element in the container.
// If Next() returns true, then next element's index and value can be retrieved by Index() and Value().
// If Next() was called for the first time, then it will point the iterator to the first element if it exists.
// Modifies the state of the iterator.
func (iterator *Iterator) Next() bool {
func (iterator *Iterator[T]) Next() bool {
if iterator.index < iterator.list.size {
iterator.index++
}
@ -35,7 +34,7 @@ func (iterator *Iterator) Next() bool {
// Prev moves the iterator to the previous element and returns true if there was a previous element in the container.
// If Prev() returns true, then previous element's index and value can be retrieved by Index() and Value().
// Modifies the state of the iterator.
func (iterator *Iterator) Prev() bool {
func (iterator *Iterator[T]) Prev() bool {
if iterator.index >= 0 {
iterator.index--
}
@ -44,32 +43,32 @@ func (iterator *Iterator) Prev() bool {
// Value returns the current element's value.
// Does not modify the state of the iterator.
func (iterator *Iterator) Value() interface{} {
func (iterator *Iterator[T]) Value() T {
return iterator.list.elements[iterator.index]
}
// Index returns the current element's index.
// Does not modify the state of the iterator.
func (iterator *Iterator) Index() int {
func (iterator *Iterator[T]) Index() int {
return iterator.index
}
// Begin resets the iterator to its initial state (one-before-first)
// Call Next() to fetch the first element if any.
func (iterator *Iterator) Begin() {
func (iterator *Iterator[T]) Begin() {
iterator.index = -1
}
// End moves the iterator past the last element (one-past-the-end).
// Call Prev() to fetch the last element if any.
func (iterator *Iterator) End() {
func (iterator *Iterator[T]) End() {
iterator.index = iterator.list.size
}
// First moves the iterator to the first element and returns true if there was a first element in the container.
// If First() returns true, then first element's index and value can be retrieved by Index() and Value().
// Modifies the state of the iterator.
func (iterator *Iterator) First() bool {
func (iterator *Iterator[T]) First() bool {
iterator.Begin()
return iterator.Next()
}
@ -77,7 +76,35 @@ func (iterator *Iterator) First() bool {
// Last moves the iterator to the last element and returns true if there was a last element in the container.
// If Last() returns true, then last element's index and value can be retrieved by Index() and Value().
// Modifies the state of the iterator.
func (iterator *Iterator) Last() bool {
func (iterator *Iterator[T]) Last() bool {
iterator.End()
return iterator.Prev()
}
// 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
}

@ -6,24 +6,34 @@ package arraylist
import (
"encoding/json"
"github.com/emirpasic/gods/containers"
"github.com/emirpasic/gods/v2/containers"
)
func assertSerializationImplementation() {
var _ containers.JSONSerializer = (*List)(nil)
var _ containers.JSONDeserializer = (*List)(nil)
}
// 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) ToJSON() ([]byte, error) {
func (list *List[T]) ToJSON() ([]byte, error) {
return json.Marshal(list.elements[:list.size])
}
// FromJSON populates list's elements from the input JSON representation.
func (list *List) FromJSON(data []byte) error {
func (list *List[T]) FromJSON(data []byte) error {
err := json.Unmarshal(data, &list.elements)
if err == nil {
list.size = len(list.elements)
}
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()
}

@ -11,32 +11,32 @@ package doublylinkedlist
import (
"fmt"
"slices"
"strings"
"github.com/emirpasic/gods/lists"
"github.com/emirpasic/gods/utils"
"github.com/emirpasic/gods/v2/lists"
"github.com/emirpasic/gods/v2/utils"
)
func assertListImplementation() {
var _ lists.List = (*List)(nil)
}
// 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 struct {
first *element
last *element
type List[T comparable] struct {
first *element[T]
last *element[T]
size int
}
type element struct {
value interface{}
prev *element
next *element
type element[T comparable] struct {
value T
prev *element[T]
next *element[T]
}
// New instantiates a new list and adds the passed values, if any, to the list
func New(values ...interface{}) *List {
list := &List{}
func New[T comparable](values ...T) *List[T] {
list := &List[T]{}
if len(values) > 0 {
list.Add(values...)
}
@ -44,9 +44,9 @@ func New(values ...interface{}) *List {
}
// Add appends a value (one or more) at the end of the list (same as Append())
func (list *List) Add(values ...interface{}) {
func (list *List[T]) Add(values ...T) {
for _, value := range values {
newElement := &element{value: value, prev: list.last}
newElement := &element[T]{value: value, prev: list.last}
if list.size == 0 {
list.first = newElement
list.last = newElement
@ -59,15 +59,15 @@ func (list *List) Add(values ...interface{}) {
}
// Append appends a value (one or more) at the end of the list (same as Add())
func (list *List) Append(values ...interface{}) {
func (list *List[T]) Append(values ...T) {
list.Add(values...)
}
// Prepend prepends a values (or more)
func (list *List) Prepend(values ...interface{}) {
func (list *List[T]) Prepend(values ...T) {
// in reverse to keep passed order i.e. ["c","d"] -> Prepend(["a","b"]) -> ["a","b","c",d"]
for v := len(values) - 1; v >= 0; v-- {
newElement := &element{value: values[v], next: list.first}
newElement := &element[T]{value: values[v], next: list.first}
if list.size == 0 {
list.first = newElement
list.last = newElement
@ -81,10 +81,11 @@ func (list *List) Prepend(values ...interface{}) {
// Get returns the element at index.
// Second return parameter is true if index is within bounds of the array and array is not empty, otherwise false.
func (list *List) Get(index int) (interface{}, bool) {
func (list *List[T]) Get(index int) (T, bool) {
if !list.withinRange(index) {
return nil, false
var t T
return t, false
}
// determine traveral direction, last to first or first to last
@ -101,7 +102,7 @@ func (list *List) Get(index int) (interface{}, bool) {
}
// Remove removes the element at the given index from the list.
func (list *List) Remove(index int) {
func (list *List[T]) Remove(index int) {
if !list.withinRange(index) {
return
@ -112,7 +113,7 @@ func (list *List) Remove(index int) {
return
}
var element *element
var element *element[T]
// determine traversal direction, last to first or first to last
if list.size-index < index {
element = list.last
@ -146,7 +147,7 @@ func (list *List) Remove(index int) {
// All values have to be present in the set for the method to return true.
// Performance time complexity of n^2.
// Returns true if no arguments are passed at all, i.e. set is always super-set of empty set.
func (list *List) Contains(values ...interface{}) bool {
func (list *List[T]) Contains(values ...T) bool {
if len(values) == 0 {
return true
@ -170,16 +171,16 @@ func (list *List) Contains(values ...interface{}) bool {
}
// Values returns all elements in the list.
func (list *List) Values() []interface{} {
values := make([]interface{}, list.size, list.size)
func (list *List[T]) Values() []T {
values := make([]T, list.size, list.size)
for e, element := 0, list.first; element != nil; e, element = e+1, element.next {
values[e] = element.value
}
return values
}
//IndexOf returns index of provided element
func (list *List) IndexOf(value interface{}) int {
// IndexOf returns index of provided element
func (list *List[T]) IndexOf(value T) int {
if list.size == 0 {
return -1
}
@ -192,31 +193,31 @@ func (list *List) IndexOf(value interface{}) int {
}
// Empty returns true if list does not contain any elements.
func (list *List) Empty() bool {
func (list *List[T]) Empty() bool {
return list.size == 0
}
// Size returns number of elements within the list.
func (list *List) Size() int {
func (list *List[T]) Size() int {
return list.size
}
// Clear removes all elements from the list.
func (list *List) Clear() {
func (list *List[T]) Clear() {
list.size = 0
list.first = nil
list.last = nil
}
// Sort sorts values (in-place) using.
func (list *List) Sort(comparator utils.Comparator) {
func (list *List[T]) Sort(comparator utils.Comparator[T]) {
if list.size < 2 {
return
}
values := list.Values()
utils.Sort(values, comparator)
slices.SortFunc(values, comparator)
list.Clear()
@ -225,9 +226,9 @@ func (list *List) Sort(comparator utils.Comparator) {
}
// Swap swaps values of two elements at the given indices.
func (list *List) Swap(i, j int) {
func (list *List[T]) Swap(i, j int) {
if list.withinRange(i) && list.withinRange(j) && i != j {
var element1, element2 *element
var element1, element2 *element[T]
for e, currentElement := 0, list.first; element1 == nil || element2 == nil; e, currentElement = e+1, currentElement.next {
switch e {
case i:
@ -243,7 +244,7 @@ func (list *List) Swap(i, j int) {
// Insert inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right.
// Does not do anything if position is negative or bigger than list's size
// Note: position equal to list's size is valid, i.e. append.
func (list *List) Insert(index int, values ...interface{}) {
func (list *List[T]) Insert(index int, values ...T) {
if !list.withinRange(index) {
// Append
@ -253,15 +254,14 @@ func (list *List) Insert(index int, values ...interface{}) {
return
}
list.size += len(values)
var beforeElement *element
var foundElement *element
var beforeElement *element[T]
var foundElement *element[T]
// determine traversal direction, last to first or first to last
if list.size-index < index {
foundElement = list.last
beforeElement = list.last.prev
for e := list.size - 1; e != index; e, foundElement = e-1, foundElement.prev {
beforeElement = foundElement.prev
beforeElement = beforeElement.prev
}
} else {
foundElement = list.first
@ -273,7 +273,7 @@ func (list *List) Insert(index int, values ...interface{}) {
if foundElement == list.first {
oldNextElement := list.first
for i, value := range values {
newElement := &element{value: value}
newElement := &element[T]{value: value}
if i == 0 {
list.first = newElement
} else {
@ -287,7 +287,7 @@ func (list *List) Insert(index int, values ...interface{}) {
} else {
oldNextElement := beforeElement.next
for _, value := range values {
newElement := &element{value: value}
newElement := &element[T]{value: value}
newElement.prev = beforeElement
beforeElement.next = newElement
beforeElement = newElement
@ -295,12 +295,14 @@ func (list *List) Insert(index int, values ...interface{}) {
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) Set(index int, value interface{}) {
func (list *List[T]) Set(index int, value T) {
if !list.withinRange(index) {
// Append
@ -310,7 +312,7 @@ func (list *List) Set(index int, value interface{}) {
return
}
var foundElement *element
var foundElement *element[T]
// determine traversal direction, last to first or first to last
if list.size-index < index {
foundElement = list.last
@ -329,7 +331,7 @@ func (list *List) Set(index int, value interface{}) {
}
// String returns a string representation of container
func (list *List) String() string {
func (list *List[T]) String() string {
str := "DoublyLinkedList\n"
values := []string{}
for element := list.first; element != nil; element = element.next {
@ -340,6 +342,6 @@ func (list *List) String() string {
}
// Check that the index is within bounds of the list
func (list *List) withinRange(index int) bool {
func (list *List[T]) withinRange(index int) bool {
return index >= 0 && index < list.size
}

@ -5,20 +5,21 @@
package doublylinkedlist
import (
"fmt"
"cmp"
"encoding/json"
"slices"
"strings"
"testing"
"github.com/emirpasic/gods/utils"
)
func TestListNew(t *testing.T) {
list1 := New()
list1 := New[int]()
if actualValue := list1.Empty(); actualValue != true {
t.Errorf("Got %v expected %v", actualValue, true)
}
list2 := New(1, "b")
list2 := New[int](1, 2)
if actualValue := list2.Size(); actualValue != 2 {
t.Errorf("Got %v expected %v", actualValue, 2)
@ -28,17 +29,17 @@ func TestListNew(t *testing.T) {
t.Errorf("Got %v expected %v", actualValue, 1)
}
if actualValue, ok := list2.Get(1); actualValue != "b" || !ok {
t.Errorf("Got %v expected %v", actualValue, "b")
if actualValue, ok := list2.Get(1); actualValue != 2 || !ok {
t.Errorf("Got %v expected %v", actualValue, 2)
}
if actualValue, ok := list2.Get(2); actualValue != nil || ok {
t.Errorf("Got %v expected %v", actualValue, nil)
if actualValue, ok := list2.Get(2); actualValue != 0 || ok {
t.Errorf("Got %v expected %v", actualValue, 0)
}
}
func TestListAdd(t *testing.T) {
list := New()
list := New[string]()
list.Add("a")
list.Add("b", "c")
if actualValue := list.Empty(); actualValue != false {
@ -52,13 +53,35 @@ func TestListAdd(t *testing.T) {
}
}
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()
list := New[string]()
list.Add("a")
list.Add("b", "c")
list.Remove(2)
if actualValue, ok := list.Get(2); actualValue != nil || ok {
t.Errorf("Got %v expected %v", actualValue, nil)
if actualValue, ok := list.Get(2); actualValue != "" || ok {
t.Errorf("Got %v expected %v", actualValue, "")
}
list.Remove(1)
list.Remove(0)
@ -72,7 +95,7 @@ func TestListRemove(t *testing.T) {
}
func TestListGet(t *testing.T) {
list := New()
list := New[string]()
list.Add("a")
list.Add("b", "c")
if actualValue, ok := list.Get(0); actualValue != "a" || !ok {
@ -84,8 +107,8 @@ func TestListGet(t *testing.T) {
if actualValue, ok := list.Get(2); actualValue != "c" || !ok {
t.Errorf("Got %v expected %v", actualValue, "c")
}
if actualValue, ok := list.Get(3); actualValue != nil || ok {
t.Errorf("Got %v expected %v", actualValue, nil)
if actualValue, ok := list.Get(3); actualValue != "" || ok {
t.Errorf("Got %v expected %v", actualValue, "")
}
list.Remove(0)
if actualValue, ok := list.Get(0); actualValue != "b" || !ok {
@ -94,31 +117,31 @@ func TestListGet(t *testing.T) {
}
func TestListSwap(t *testing.T) {
list := New()
list := New[string]()
list.Add("a")
list.Add("b", "c")
list.Swap(0, 1)
if actualValue, ok := list.Get(0); actualValue != "b" || !ok {
t.Errorf("Got %v expected %v", actualValue, "c")
t.Errorf("Got %v expected %v", actualValue, "b")
}
}
func TestListSort(t *testing.T) {
list := New()
list.Sort(utils.StringComparator)
list := New[string]()
list.Sort(cmp.Compare[string])
list.Add("e", "f", "g", "a", "b", "c", "d")
list.Sort(utils.StringComparator)
list.Sort(cmp.Compare[string])
for i := 1; i < list.Size(); i++ {
a, _ := list.Get(i - 1)
b, _ := list.Get(i)
if a.(string) > b.(string) {
if a > b {
t.Errorf("Not sorted! %s > %s", a, b)
}
}
}
func TestListClear(t *testing.T) {
list := New()
list := New[string]()
list.Add("e", "f", "g", "a", "b", "c", "d")
list.Clear()
if actualValue := list.Empty(); actualValue != true {
@ -130,12 +153,15 @@ func TestListClear(t *testing.T) {
}
func TestListContains(t *testing.T) {
list := New()
list := New[string]()
list.Add("a")
list.Add("b", "c")
if actualValue := list.Contains("a"); actualValue != true {
t.Errorf("Got %v expected %v", actualValue, true)
}
if actualValue := list.Contains(""); actualValue != false {
t.Errorf("Got %v expected %v", actualValue, false)
}
if actualValue := list.Contains("a", "b", "c"); actualValue != true {
t.Errorf("Got %v expected %v", actualValue, true)
}
@ -152,60 +178,40 @@ func TestListContains(t *testing.T) {
}
func TestListValues(t *testing.T) {
list := New()
list := New[string]()
list.Add("a")
list.Add("b", "c")
if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abc"; actualValue != expectedValue {
if actualValue, expectedValue := list.Values(), []string{"a", "b", "c"}; !slices.Equal(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
}
func TestListIndexOf(t *testing.T) {
list := New()
expectedIndex := -1
if index := list.IndexOf("a"); index != expectedIndex {
t.Errorf("Got %v expected %v", index, expectedIndex)
}
list.Add("a")
list.Add("b", "c")
expectedIndex = 0
if index := list.IndexOf("a"); index != expectedIndex {
t.Errorf("Got %v expected %v", index, expectedIndex)
}
expectedIndex = 1
if index := list.IndexOf("b"); index != expectedIndex {
t.Errorf("Got %v expected %v", index, expectedIndex)
}
expectedIndex = 2
if index := list.IndexOf("c"); index != expectedIndex {
t.Errorf("Got %v expected %v", index, expectedIndex)
}
}
func TestListInsert(t *testing.T) {
list := New()
list.Insert(0, "b", "c")
list := New[string]()
list.Insert(0, "b", "c", "d")
list.Insert(0, "a")
list.Insert(10, "x") // ignore
if actualValue := list.Size(); actualValue != 3 {
t.Errorf("Got %v expected %v", actualValue, 3)
}
list.Insert(3, "d") // append
if actualValue := list.Size(); actualValue != 4 {
t.Errorf("Got %v expected %v", actualValue, 4)
}
if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", list.Values()...), "abcd"; actualValue != expectedValue {
list.Insert(4, "g") // append
if actualValue := list.Size(); actualValue != 5 {
t.Errorf("Got %v expected %v", actualValue, 5)
}
if actualValue, expectedValue := 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()
list := New[string]()
list.Set(0, "a")
list.Set(1, "b")
if actualValue := list.Size(); actualValue != 2 {
@ -220,20 +226,15 @@ func TestListSet(t *testing.T) {
if actualValue := list.Size(); actualValue != 3 {
t.Errorf("Got %v expected %v", actualValue, 3)
}
if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abbc"; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
list.Set(2, "cc") // last to first traversal
list.Set(0, "aa") // first to last traversal
if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "aabbcc"; actualValue != expectedValue {
if actualValue, expectedValue := list.Values(), []string{"a", "bb", "c"}; !slices.Equal(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
}
func TestListEach(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
list.Each(func(index int, value interface{}) {
list.Each(func(index int, value string) {
switch index {
case 0:
if actualValue, expectedValue := value, "a"; actualValue != expectedValue {
@ -254,10 +255,10 @@ func TestListEach(t *testing.T) {
}
func TestListMap(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
mappedList := list.Map(func(index int, value interface{}) interface{} {
return "mapped: " + value.(string)
mappedList := list.Map(func(index int, value string) string {
return "mapped: " + value
})
if actualValue, _ := mappedList.Get(0); actualValue != "mapped: a" {
t.Errorf("Got %v expected %v", actualValue, "mapped: a")
@ -274,10 +275,10 @@ func TestListMap(t *testing.T) {
}
func TestListSelect(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
selectedList := list.Select(func(index int, value interface{}) bool {
return value.(string) >= "a" && value.(string) <= "b"
selectedList := list.Select(func(index int, value string) bool {
return value >= "a" && value <= "b"
})
if actualValue, _ := selectedList.Get(0); actualValue != "a" {
t.Errorf("Got %v expected %v", actualValue, "value: a")
@ -291,60 +292,60 @@ func TestListSelect(t *testing.T) {
}
func TestListAny(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
any := list.Any(func(index int, value interface{}) bool {
return value.(string) == "c"
any := list.Any(func(index int, value string) bool {
return value == "c"
})
if any != true {
t.Errorf("Got %v expected %v", any, true)
}
any = list.Any(func(index int, value interface{}) bool {
return value.(string) == "x"
any = list.Any(func(index int, value string) bool {
return value == "x"
})
if any != false {
t.Errorf("Got %v expected %v", any, false)
}
}
func TestListAll(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
all := list.All(func(index int, value interface{}) bool {
return value.(string) >= "a" && value.(string) <= "c"
all := list.All(func(index int, value string) bool {
return value >= "a" && value <= "c"
})
if all != true {
t.Errorf("Got %v expected %v", all, true)
}
all = list.All(func(index int, value interface{}) bool {
return value.(string) >= "a" && value.(string) <= "b"
all = list.All(func(index int, value string) bool {
return value >= "a" && value <= "b"
})
if all != false {
t.Errorf("Got %v expected %v", all, false)
}
}
func TestListFind(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
foundIndex, foundValue := list.Find(func(index int, value interface{}) bool {
return value.(string) == "c"
foundIndex, foundValue := list.Find(func(index int, value string) bool {
return value == "c"
})
if foundValue != "c" || foundIndex != 2 {
t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, "c", 2)
}
foundIndex, foundValue = list.Find(func(index int, value interface{}) bool {
return value.(string) == "x"
foundIndex, foundValue = list.Find(func(index int, value string) bool {
return value == "x"
})
if foundValue != nil || foundIndex != -1 {
if foundValue != "" || foundIndex != -1 {
t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil)
}
}
func TestListChaining(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
chainedList := list.Select(func(index int, value interface{}) bool {
return value.(string) > "a"
}).Map(func(index int, value interface{}) interface{} {
return value.(string) + value.(string)
chainedList := list.Select(func(index int, value string) bool {
return value > "a"
}).Map(func(index int, value string) string {
return value + value
})
if chainedList.Size() != 2 {
t.Errorf("Got %v expected %v", chainedList.Size(), 2)
@ -358,7 +359,7 @@ func TestListChaining(t *testing.T) {
}
func TestListIteratorNextOnEmpty(t *testing.T) {
list := New()
list := New[string]()
it := list.Iterator()
for it.Next() {
t.Errorf("Shouldn't iterate on empty list")
@ -366,7 +367,7 @@ func TestListIteratorNextOnEmpty(t *testing.T) {
}
func TestListIteratorNext(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
it := list.Iterator()
count := 0
@ -397,7 +398,7 @@ func TestListIteratorNext(t *testing.T) {
}
func TestListIteratorPrevOnEmpty(t *testing.T) {
list := New()
list := New[string]()
it := list.Iterator()
for it.Prev() {
t.Errorf("Shouldn't iterate on empty list")
@ -405,7 +406,7 @@ func TestListIteratorPrevOnEmpty(t *testing.T) {
}
func TestListIteratorPrev(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
it := list.Iterator()
for it.Next() {
@ -438,7 +439,7 @@ func TestListIteratorPrev(t *testing.T) {
}
func TestListIteratorBegin(t *testing.T) {
list := New()
list := New[string]()
it := list.Iterator()
it.Begin()
list.Add("a", "b", "c")
@ -452,7 +453,7 @@ func TestListIteratorBegin(t *testing.T) {
}
func TestListIteratorEnd(t *testing.T) {
list := New()
list := New[string]()
it := list.Iterator()
if index := it.Index(); index != -1 {
@ -477,7 +478,7 @@ func TestListIteratorEnd(t *testing.T) {
}
func TestListIteratorFirst(t *testing.T) {
list := New()
list := New[string]()
it := list.Iterator()
if actualValue, expectedValue := it.First(), false; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
@ -492,7 +493,7 @@ func TestListIteratorFirst(t *testing.T) {
}
func TestListIteratorLast(t *testing.T) {
list := New()
list := New[string]()
it := list.Iterator()
if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
@ -506,13 +507,113 @@ func TestListIteratorLast(t *testing.T) {
}
}
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()
list := New[string]()
list.Add("a", "b", "c")
var err error
assert := func() {
if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abc"; actualValue != expectedValue {
if actualValue, expectedValue := list.Values(), []string{"a", "b", "c"}; !slices.Equal(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue, expectedValue := list.Size(), 3; actualValue != expectedValue {
@ -525,14 +626,33 @@ func TestListSerialization(t *testing.T) {
assert()
json, err := list.ToJSON()
bytes, err := list.ToJSON()
assert()
err = list.FromJSON(json)
err = list.FromJSON(bytes)
assert()
bytes, err = json.Marshal([]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 benchmarkGet(b *testing.B, list *List, size int) {
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)
@ -540,7 +660,7 @@ func benchmarkGet(b *testing.B, list *List, size int) {
}
}
func benchmarkAdd(b *testing.B, list *List, size int) {
func benchmarkAdd(b *testing.B, list *List[int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
list.Add(n)
@ -548,7 +668,7 @@ func benchmarkAdd(b *testing.B, list *List, size int) {
}
}
func benchmarkRemove(b *testing.B, list *List, size int) {
func benchmarkRemove(b *testing.B, list *List[int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
list.Remove(n)
@ -559,7 +679,7 @@ func benchmarkRemove(b *testing.B, list *List, size int) {
func BenchmarkDoublyLinkedListGet100(b *testing.B) {
b.StopTimer()
size := 100
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -570,7 +690,7 @@ func BenchmarkDoublyLinkedListGet100(b *testing.B) {
func BenchmarkDoublyLinkedListGet1000(b *testing.B) {
b.StopTimer()
size := 1000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -581,7 +701,7 @@ func BenchmarkDoublyLinkedListGet1000(b *testing.B) {
func BenchmarkDoublyLinkedListGet10000(b *testing.B) {
b.StopTimer()
size := 10000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -592,7 +712,7 @@ func BenchmarkDoublyLinkedListGet10000(b *testing.B) {
func BenchmarkDoublyLinkedListGet100000(b *testing.B) {
b.StopTimer()
size := 100000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -603,7 +723,7 @@ func BenchmarkDoublyLinkedListGet100000(b *testing.B) {
func BenchmarkDoublyLinkedListAdd100(b *testing.B) {
b.StopTimer()
size := 100
list := New()
list := New[int]()
b.StartTimer()
benchmarkAdd(b, list, size)
}
@ -611,7 +731,7 @@ func BenchmarkDoublyLinkedListAdd100(b *testing.B) {
func BenchmarkDoublyLinkedListAdd1000(b *testing.B) {
b.StopTimer()
size := 1000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -622,7 +742,7 @@ func BenchmarkDoublyLinkedListAdd1000(b *testing.B) {
func BenchmarkDoublyLinkedListAdd10000(b *testing.B) {
b.StopTimer()
size := 10000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -633,7 +753,7 @@ func BenchmarkDoublyLinkedListAdd10000(b *testing.B) {
func BenchmarkDoublyLinkedListAdd100000(b *testing.B) {
b.StopTimer()
size := 100000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -644,7 +764,7 @@ func BenchmarkDoublyLinkedListAdd100000(b *testing.B) {
func BenchmarkDoublyLinkedListRemove100(b *testing.B) {
b.StopTimer()
size := 100
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -655,7 +775,7 @@ func BenchmarkDoublyLinkedListRemove100(b *testing.B) {
func BenchmarkDoublyLinkedListRemove1000(b *testing.B) {
b.StopTimer()
size := 1000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -666,7 +786,7 @@ func BenchmarkDoublyLinkedListRemove1000(b *testing.B) {
func BenchmarkDoublyLinkedListRemove10000(b *testing.B) {
b.StopTimer()
size := 10000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -677,7 +797,7 @@ func BenchmarkDoublyLinkedListRemove10000(b *testing.B) {
func BenchmarkDoublyLinkedListRemove100000(b *testing.B) {
b.StopTimer()
size := 100000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}

@ -4,14 +4,13 @@
package doublylinkedlist
import "github.com/emirpasic/gods/containers"
import "github.com/emirpasic/gods/v2/containers"
func assertEnumerableImplementation() {
var _ containers.EnumerableWithIndex = (*List)(nil)
}
// 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) Each(f func(index int, value interface{})) {
func (list *List[T]) Each(f func(index int, value T)) {
iterator := list.Iterator()
for iterator.Next() {
f(iterator.Index(), iterator.Value())
@ -20,8 +19,8 @@ func (list *List) Each(f func(index int, value interface{})) {
// Map invokes the given function once for each element and returns a
// container containing the values returned by the given function.
func (list *List) Map(f func(index int, value interface{}) interface{}) *List {
newList := &List{}
func (list *List[T]) Map(f func(index int, value T) T) *List[T] {
newList := &List[T]{}
iterator := list.Iterator()
for iterator.Next() {
newList.Add(f(iterator.Index(), iterator.Value()))
@ -30,8 +29,8 @@ func (list *List) Map(f func(index int, value interface{}) interface{}) *List {
}
// Select returns a new container containing all elements for which the given function returns a true value.
func (list *List) Select(f func(index int, value interface{}) bool) *List {
newList := &List{}
func (list *List[T]) Select(f func(index int, value T) bool) *List[T] {
newList := &List[T]{}
iterator := list.Iterator()
for iterator.Next() {
if f(iterator.Index(), iterator.Value()) {
@ -43,7 +42,7 @@ func (list *List) Select(f func(index int, value interface{}) bool) *List {
// Any passes each element of the container to the given function and
// returns true if the function ever returns true for any element.
func (list *List) Any(f func(index int, value interface{}) bool) bool {
func (list *List[T]) Any(f func(index int, value T) bool) bool {
iterator := list.Iterator()
for iterator.Next() {
if f(iterator.Index(), iterator.Value()) {
@ -55,7 +54,7 @@ func (list *List) Any(f func(index int, value interface{}) bool) bool {
// All passes each element of the container to the given function and
// returns true if the function returns true for all elements.
func (list *List) All(f func(index int, value interface{}) bool) bool {
func (list *List[T]) All(f func(index int, value T) bool) bool {
iterator := list.Iterator()
for iterator.Next() {
if !f(iterator.Index(), iterator.Value()) {
@ -68,12 +67,13 @@ func (list *List) All(f func(index int, value interface{}) bool) bool {
// Find passes each element of the container to the given function and returns
// the first (index,value) for which the function is true or -1,nil otherwise
// if no element matches the criteria.
func (list *List) Find(f func(index int, value interface{}) bool) (index int, value interface{}) {
func (list *List[T]) Find(f func(index int, value T) bool) (index int, value T) {
iterator := list.Iterator()
for iterator.Next() {
if f(iterator.Index(), iterator.Value()) {
return iterator.Index(), iterator.Value()
}
}
return -1, nil
var t T
return -1, t
}

@ -4,29 +4,28 @@
package doublylinkedlist
import "github.com/emirpasic/gods/containers"
import "github.com/emirpasic/gods/v2/containers"
func assertIteratorImplementation() {
var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil)
}
// Assert Iterator implementation
var _ containers.ReverseIteratorWithIndex[int] = (*Iterator[int])(nil)
// Iterator holding the iterator's state
type Iterator struct {
list *List
type Iterator[T comparable] struct {
list *List[T]
index int
element *element
element *element[T]
}
// Iterator returns a stateful iterator whose values can be fetched by an index.
func (list *List) Iterator() Iterator {
return Iterator{list: list, index: -1, element: nil}
func (list *List[T]) Iterator() Iterator[T] {
return Iterator[T]{list: list, index: -1, element: nil}
}
// Next moves the iterator to the next element and returns true if there was a next element in the container.
// If Next() returns true, then next element's index and value can be retrieved by Index() and Value().
// If Next() was called for the first time, then it will point the iterator to the first element if it exists.
// Modifies the state of the iterator.
func (iterator *Iterator) Next() bool {
func (iterator *Iterator[T]) Next() bool {
if iterator.index < iterator.list.size {
iterator.index++
}
@ -45,7 +44,7 @@ func (iterator *Iterator) Next() bool {
// Prev moves the iterator to the previous element and returns true if there was a previous element in the container.
// If Prev() returns true, then previous element's index and value can be retrieved by Index() and Value().
// Modifies the state of the iterator.
func (iterator *Iterator) Prev() bool {
func (iterator *Iterator[T]) Prev() bool {
if iterator.index >= 0 {
iterator.index--
}
@ -63,26 +62,26 @@ func (iterator *Iterator) Prev() bool {
// Value returns the current element's value.
// Does not modify the state of the iterator.
func (iterator *Iterator) Value() interface{} {
func (iterator *Iterator[T]) Value() T {
return iterator.element.value
}
// Index returns the current element's index.
// Does not modify the state of the iterator.
func (iterator *Iterator) Index() int {
func (iterator *Iterator[T]) Index() int {
return iterator.index
}
// Begin resets the iterator to its initial state (one-before-first)
// Call Next() to fetch the first element if any.
func (iterator *Iterator) Begin() {
func (iterator *Iterator[T]) Begin() {
iterator.index = -1
iterator.element = nil
}
// End moves the iterator past the last element (one-past-the-end).
// Call Prev() to fetch the last element if any.
func (iterator *Iterator) End() {
func (iterator *Iterator[T]) End() {
iterator.index = iterator.list.size
iterator.element = iterator.list.last
}
@ -90,7 +89,7 @@ func (iterator *Iterator) End() {
// First moves the iterator to the first element and returns true if there was a first element in the container.
// If First() returns true, then first element's index and value can be retrieved by Index() and Value().
// Modifies the state of the iterator.
func (iterator *Iterator) First() bool {
func (iterator *Iterator[T]) First() bool {
iterator.Begin()
return iterator.Next()
}
@ -98,7 +97,35 @@ func (iterator *Iterator) First() bool {
// Last moves the iterator to the last element and returns true if there was a last element in the container.
// If Last() returns true, then last element's index and value can be retrieved by Index() and Value().
// Modifies the state of the iterator.
func (iterator *Iterator) Last() bool {
func (iterator *Iterator[T]) Last() bool {
iterator.End()
return iterator.Prev()
}
// 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
}

@ -6,22 +6,22 @@ package doublylinkedlist
import (
"encoding/json"
"github.com/emirpasic/gods/containers"
"github.com/emirpasic/gods/v2/containers"
)
func assertSerializationImplementation() {
var _ containers.JSONSerializer = (*List)(nil)
var _ containers.JSONDeserializer = (*List)(nil)
}
// 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) ToJSON() ([]byte, error) {
func (list *List[T]) ToJSON() ([]byte, error) {
return json.Marshal(list.Values())
}
// FromJSON populates list's elements from the input JSON representation.
func (list *List) FromJSON(data []byte) error {
elements := []interface{}{}
func (list *List[T]) FromJSON(data []byte) error {
var elements []T
err := json.Unmarshal(data, &elements)
if err == nil {
list.Clear()
@ -29,3 +29,13 @@ func (list *List) FromJSON(data []byte) error {
}
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()
}

@ -10,24 +10,25 @@
package lists
import (
"github.com/emirpasic/gods/containers"
"github.com/emirpasic/gods/utils"
"github.com/emirpasic/gods/v2/containers"
"github.com/emirpasic/gods/v2/utils"
)
// List interface that all lists implement
type List interface {
Get(index int) (interface{}, bool)
type List[T comparable] interface {
Get(index int) (T, bool)
Remove(index int)
Add(values ...interface{})
Contains(values ...interface{}) bool
Sort(comparator utils.Comparator)
Add(values ...T)
Contains(values ...T) bool
Sort(comparator utils.Comparator[T])
Swap(index1, index2 int)
Insert(index int, values ...interface{})
Set(index int, value interface{})
Insert(index int, values ...T)
Set(index int, value T)
containers.Container
containers.Container[T]
// Empty() bool
// Size() int
// Clear()
// Values() []interface{}
// String() string
}

@ -4,14 +4,13 @@
package singlylinkedlist
import "github.com/emirpasic/gods/containers"
import "github.com/emirpasic/gods/v2/containers"
func assertEnumerableImplementation() {
var _ containers.EnumerableWithIndex = (*List)(nil)
}
// 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) Each(f func(index int, value interface{})) {
func (list *List[T]) Each(f func(index int, value T)) {
iterator := list.Iterator()
for iterator.Next() {
f(iterator.Index(), iterator.Value())
@ -20,8 +19,8 @@ func (list *List) Each(f func(index int, value interface{})) {
// Map invokes the given function once for each element and returns a
// container containing the values returned by the given function.
func (list *List) Map(f func(index int, value interface{}) interface{}) *List {
newList := &List{}
func (list *List[T]) Map(f func(index int, value T) T) *List[T] {
newList := &List[T]{}
iterator := list.Iterator()
for iterator.Next() {
newList.Add(f(iterator.Index(), iterator.Value()))
@ -30,8 +29,8 @@ func (list *List) Map(f func(index int, value interface{}) interface{}) *List {
}
// Select returns a new container containing all elements for which the given function returns a true value.
func (list *List) Select(f func(index int, value interface{}) bool) *List {
newList := &List{}
func (list *List[T]) Select(f func(index int, value T) bool) *List[T] {
newList := &List[T]{}
iterator := list.Iterator()
for iterator.Next() {
if f(iterator.Index(), iterator.Value()) {
@ -43,7 +42,7 @@ func (list *List) Select(f func(index int, value interface{}) bool) *List {
// Any passes each element of the container to the given function and
// returns true if the function ever returns true for any element.
func (list *List) Any(f func(index int, value interface{}) bool) bool {
func (list *List[T]) Any(f func(index int, value T) bool) bool {
iterator := list.Iterator()
for iterator.Next() {
if f(iterator.Index(), iterator.Value()) {
@ -55,7 +54,7 @@ func (list *List) Any(f func(index int, value interface{}) bool) bool {
// All passes each element of the container to the given function and
// returns true if the function returns true for all elements.
func (list *List) All(f func(index int, value interface{}) bool) bool {
func (list *List[T]) All(f func(index int, value T) bool) bool {
iterator := list.Iterator()
for iterator.Next() {
if !f(iterator.Index(), iterator.Value()) {
@ -68,12 +67,12 @@ func (list *List) All(f func(index int, value interface{}) bool) bool {
// Find passes each element of the container to the given function and returns
// the first (index,value) for which the function is true or -1,nil otherwise
// if no element matches the criteria.
func (list *List) Find(f func(index int, value interface{}) bool) (index int, value interface{}) {
func (list *List[T]) Find(f func(index int, value T) bool) (index int, value T) {
iterator := list.Iterator()
for iterator.Next() {
if f(iterator.Index(), iterator.Value()) {
return iterator.Index(), iterator.Value()
}
}
return -1, nil
return -1, value
}

@ -4,29 +4,28 @@
package singlylinkedlist
import "github.com/emirpasic/gods/containers"
import "github.com/emirpasic/gods/v2/containers"
func assertIteratorImplementation() {
var _ containers.IteratorWithIndex = (*Iterator)(nil)
}
// Assert Iterator implementation
var _ containers.IteratorWithIndex[int] = (*Iterator[int])(nil)
// Iterator holding the iterator's state
type Iterator struct {
list *List
type Iterator[T comparable] struct {
list *List[T]
index int
element *element
element *element[T]
}
// Iterator returns a stateful iterator whose values can be fetched by an index.
func (list *List) Iterator() Iterator {
return Iterator{list: list, index: -1, element: nil}
func (list *List[T]) Iterator() *Iterator[T] {
return &Iterator[T]{list: list, index: -1, element: nil}
}
// Next moves the iterator to the next element and returns true if there was a next element in the container.
// If Next() returns true, then next element's index and value can be retrieved by Index() and Value().
// If Next() was called for the first time, then it will point the iterator to the first element if it exists.
// Modifies the state of the iterator.
func (iterator *Iterator) Next() bool {
func (iterator *Iterator[T]) Next() bool {
if iterator.index < iterator.list.size {
iterator.index++
}
@ -44,19 +43,19 @@ func (iterator *Iterator) Next() bool {
// Value returns the current element's value.
// Does not modify the state of the iterator.
func (iterator *Iterator) Value() interface{} {
func (iterator *Iterator[T]) Value() T {
return iterator.element.value
}
// Index returns the current element's index.
// Does not modify the state of the iterator.
func (iterator *Iterator) Index() int {
func (iterator *Iterator[T]) Index() int {
return iterator.index
}
// Begin resets the iterator to its initial state (one-before-first)
// Call Next() to fetch the first element if any.
func (iterator *Iterator) Begin() {
func (iterator *Iterator[T]) Begin() {
iterator.index = -1
iterator.element = nil
}
@ -64,7 +63,21 @@ func (iterator *Iterator) Begin() {
// First moves the iterator to the first element and returns true if there was a first element in the container.
// If First() returns true, then first element's index and value can be retrieved by Index() and Value().
// Modifies the state of the iterator.
func (iterator *Iterator) First() bool {
func (iterator *Iterator[T]) First() bool {
iterator.Begin()
return iterator.Next()
}
// 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
}

@ -6,22 +6,22 @@ package singlylinkedlist
import (
"encoding/json"
"github.com/emirpasic/gods/containers"
"github.com/emirpasic/gods/v2/containers"
)
func assertSerializationImplementation() {
var _ containers.JSONSerializer = (*List)(nil)
var _ containers.JSONDeserializer = (*List)(nil)
}
// 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) ToJSON() ([]byte, error) {
func (list *List[T]) ToJSON() ([]byte, error) {
return json.Marshal(list.Values())
}
// FromJSON populates list's elements from the input JSON representation.
func (list *List) FromJSON(data []byte) error {
elements := []interface{}{}
func (list *List[T]) FromJSON(data []byte) error {
var elements []T
err := json.Unmarshal(data, &elements)
if err == nil {
list.Clear()
@ -29,3 +29,13 @@ func (list *List) FromJSON(data []byte) error {
}
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()
}

@ -11,31 +11,31 @@ package singlylinkedlist
import (
"fmt"
"slices"
"strings"
"github.com/emirpasic/gods/lists"
"github.com/emirpasic/gods/utils"
"github.com/emirpasic/gods/v2/lists"
"github.com/emirpasic/gods/v2/utils"
)
func assertListImplementation() {
var _ lists.List = (*List)(nil)
}
// Assert List implementation
var _ lists.List[int] = (*List[int])(nil)
// List holds the elements, where each element points to the next element
type List struct {
first *element
last *element
type List[T comparable] struct {
first *element[T]
last *element[T]
size int
}
type element struct {
value interface{}
next *element
type element[T comparable] struct {
value T
next *element[T]
}
// New instantiates a new list and adds the passed values, if any, to the list
func New(values ...interface{}) *List {
list := &List{}
func New[T comparable](values ...T) *List[T] {
list := &List[T]{}
if len(values) > 0 {
list.Add(values...)
}
@ -43,9 +43,9 @@ func New(values ...interface{}) *List {
}
// Add appends a value (one or more) at the end of the list (same as Append())
func (list *List) Add(values ...interface{}) {
func (list *List[T]) Add(values ...T) {
for _, value := range values {
newElement := &element{value: value}
newElement := &element[T]{value: value}
if list.size == 0 {
list.first = newElement
list.last = newElement
@ -58,15 +58,15 @@ func (list *List) Add(values ...interface{}) {
}
// Append appends a value (one or more) at the end of the list (same as Add())
func (list *List) Append(values ...interface{}) {
func (list *List[T]) Append(values ...T) {
list.Add(values...)
}
// Prepend prepends a values (or more)
func (list *List) Prepend(values ...interface{}) {
func (list *List[T]) Prepend(values ...T) {
// in reverse to keep passed order i.e. ["c","d"] -> Prepend(["a","b"]) -> ["a","b","c",d"]
for v := len(values) - 1; v >= 0; v-- {
newElement := &element{value: values[v], next: list.first}
newElement := &element[T]{value: values[v], next: list.first}
list.first = newElement
if list.size == 0 {
list.last = newElement
@ -77,10 +77,11 @@ func (list *List) Prepend(values ...interface{}) {
// Get returns the element at index.
// Second return parameter is true if index is within bounds of the array and array is not empty, otherwise false.
func (list *List) Get(index int) (interface{}, bool) {
func (list *List[T]) Get(index int) (T, bool) {
if !list.withinRange(index) {
return nil, false
var t T
return t, false
}
element := list.first
@ -91,7 +92,7 @@ func (list *List) Get(index int) (interface{}, bool) {
}
// Remove removes the element at the given index from the list.
func (list *List) Remove(index int) {
func (list *List[T]) Remove(index int) {
if !list.withinRange(index) {
return
@ -102,7 +103,7 @@ func (list *List) Remove(index int) {
return
}
var beforeElement *element
var beforeElement *element[T]
element := list.first
for e := 0; e != index; e, element = e+1, element.next {
beforeElement = element
@ -127,7 +128,7 @@ func (list *List) Remove(index int) {
// All values have to be present in the set for the method to return true.
// Performance time complexity of n^2.
// Returns true if no arguments are passed at all, i.e. set is always super-set of empty set.
func (list *List) Contains(values ...interface{}) bool {
func (list *List[T]) Contains(values ...T) bool {
if len(values) == 0 {
return true
@ -151,16 +152,16 @@ func (list *List) Contains(values ...interface{}) bool {
}
// Values returns all elements in the list.
func (list *List) Values() []interface{} {
values := make([]interface{}, list.size, list.size)
func (list *List[T]) Values() []T {
values := make([]T, list.size, list.size)
for e, element := 0, list.first; element != nil; e, element = e+1, element.next {
values[e] = element.value
}
return values
}
//IndexOf returns index of provided element
func (list *List) IndexOf(value interface{}) int {
// IndexOf returns index of provided element
func (list *List[T]) IndexOf(value T) int {
if list.size == 0 {
return -1
}
@ -173,31 +174,31 @@ func (list *List) IndexOf(value interface{}) int {
}
// Empty returns true if list does not contain any elements.
func (list *List) Empty() bool {
func (list *List[T]) Empty() bool {
return list.size == 0
}
// Size returns number of elements within the list.
func (list *List) Size() int {
func (list *List[T]) Size() int {
return list.size
}
// Clear removes all elements from the list.
func (list *List) Clear() {
func (list *List[T]) Clear() {
list.size = 0
list.first = nil
list.last = nil
}
// Sort sort values (in-place) using.
func (list *List) Sort(comparator utils.Comparator) {
func (list *List[T]) Sort(comparator utils.Comparator[T]) {
if list.size < 2 {
return
}
values := list.Values()
utils.Sort(values, comparator)
slices.SortFunc(values, comparator)
list.Clear()
@ -206,9 +207,9 @@ func (list *List) Sort(comparator utils.Comparator) {
}
// Swap swaps values of two elements at the given indices.
func (list *List) Swap(i, j int) {
func (list *List[T]) Swap(i, j int) {
if list.withinRange(i) && list.withinRange(j) && i != j {
var element1, element2 *element
var element1, element2 *element[T]
for e, currentElement := 0, list.first; element1 == nil || element2 == nil; e, currentElement = e+1, currentElement.next {
switch e {
case i:
@ -224,7 +225,7 @@ func (list *List) Swap(i, j int) {
// Insert inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right.
// Does not do anything if position is negative or bigger than list's size
// Note: position equal to list's size is valid, i.e. append.
func (list *List) Insert(index int, values ...interface{}) {
func (list *List[T]) Insert(index int, values ...T) {
if !list.withinRange(index) {
// Append
@ -236,7 +237,7 @@ func (list *List) Insert(index int, values ...interface{}) {
list.size += len(values)
var beforeElement *element
var beforeElement *element[T]
foundElement := list.first
for e := 0; e != index; e, foundElement = e+1, foundElement.next {
beforeElement = foundElement
@ -245,7 +246,7 @@ func (list *List) Insert(index int, values ...interface{}) {
if foundElement == list.first {
oldNextElement := list.first
for i, value := range values {
newElement := &element{value: value}
newElement := &element[T]{value: value}
if i == 0 {
list.first = newElement
} else {
@ -257,7 +258,7 @@ func (list *List) Insert(index int, values ...interface{}) {
} else {
oldNextElement := beforeElement.next
for _, value := range values {
newElement := &element{value: value}
newElement := &element[T]{value: value}
beforeElement.next = newElement
beforeElement = newElement
}
@ -268,7 +269,7 @@ func (list *List) Insert(index int, values ...interface{}) {
// Set value at specified index
// Does not do anything if position is negative or bigger than list's size
// Note: position equal to list's size is valid, i.e. append.
func (list *List) Set(index int, value interface{}) {
func (list *List[T]) Set(index int, value T) {
if !list.withinRange(index) {
// Append
@ -286,7 +287,7 @@ func (list *List) Set(index int, value interface{}) {
}
// String returns a string representation of container
func (list *List) String() string {
func (list *List[T]) String() string {
str := "SinglyLinkedList\n"
values := []string{}
for element := list.first; element != nil; element = element.next {
@ -297,6 +298,6 @@ func (list *List) String() string {
}
// Check that the index is within bounds of the list
func (list *List) withinRange(index int) bool {
func (list *List[T]) withinRange(index int) bool {
return index >= 0 && index < list.size
}

@ -5,20 +5,21 @@
package singlylinkedlist
import (
"fmt"
"cmp"
"encoding/json"
"slices"
"strings"
"testing"
"github.com/emirpasic/gods/utils"
)
func TestListNew(t *testing.T) {
list1 := New()
list1 := New[int]()
if actualValue := list1.Empty(); actualValue != true {
t.Errorf("Got %v expected %v", actualValue, true)
}
list2 := New(1, "b")
list2 := New[int](1, 2)
if actualValue := list2.Size(); actualValue != 2 {
t.Errorf("Got %v expected %v", actualValue, 2)
@ -28,17 +29,17 @@ func TestListNew(t *testing.T) {
t.Errorf("Got %v expected %v", actualValue, 1)
}
if actualValue, ok := list2.Get(1); actualValue != "b" || !ok {
t.Errorf("Got %v expected %v", actualValue, "b")
if actualValue, ok := list2.Get(1); actualValue != 2 || !ok {
t.Errorf("Got %v expected %v", actualValue, 2)
}
if actualValue, ok := list2.Get(2); actualValue != nil || ok {
t.Errorf("Got %v expected %v", actualValue, nil)
if actualValue, ok := list2.Get(2); actualValue != 0 || ok {
t.Errorf("Got %v expected %v", actualValue, 0)
}
}
func TestListAdd(t *testing.T) {
list := New()
list := New[string]()
list.Add("a")
list.Add("b", "c")
if actualValue := list.Empty(); actualValue != false {
@ -52,13 +53,35 @@ func TestListAdd(t *testing.T) {
}
}
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()
list := New[string]()
list.Add("a")
list.Add("b", "c")
list.Remove(2)
if actualValue, ok := list.Get(2); actualValue != nil || ok {
t.Errorf("Got %v expected %v", actualValue, nil)
if actualValue, ok := list.Get(2); actualValue != "" || ok {
t.Errorf("Got %v expected %v", actualValue, "")
}
list.Remove(1)
list.Remove(0)
@ -72,7 +95,7 @@ func TestListRemove(t *testing.T) {
}
func TestListGet(t *testing.T) {
list := New()
list := New[string]()
list.Add("a")
list.Add("b", "c")
if actualValue, ok := list.Get(0); actualValue != "a" || !ok {
@ -84,8 +107,8 @@ func TestListGet(t *testing.T) {
if actualValue, ok := list.Get(2); actualValue != "c" || !ok {
t.Errorf("Got %v expected %v", actualValue, "c")
}
if actualValue, ok := list.Get(3); actualValue != nil || ok {
t.Errorf("Got %v expected %v", actualValue, nil)
if actualValue, ok := list.Get(3); actualValue != "" || ok {
t.Errorf("Got %v expected %v", actualValue, "")
}
list.Remove(0)
if actualValue, ok := list.Get(0); actualValue != "b" || !ok {
@ -94,31 +117,31 @@ func TestListGet(t *testing.T) {
}
func TestListSwap(t *testing.T) {
list := New()
list := New[string]()
list.Add("a")
list.Add("b", "c")
list.Swap(0, 1)
if actualValue, ok := list.Get(0); actualValue != "b" || !ok {
t.Errorf("Got %v expected %v", actualValue, "c")
t.Errorf("Got %v expected %v", actualValue, "b")
}
}
func TestListSort(t *testing.T) {
list := New()
list.Sort(utils.StringComparator)
list := New[string]()
list.Sort(cmp.Compare[string])
list.Add("e", "f", "g", "a", "b", "c", "d")
list.Sort(utils.StringComparator)
list.Sort(cmp.Compare[string])
for i := 1; i < list.Size(); i++ {
a, _ := list.Get(i - 1)
b, _ := list.Get(i)
if a.(string) > b.(string) {
if a > b {
t.Errorf("Not sorted! %s > %s", a, b)
}
}
}
func TestListClear(t *testing.T) {
list := New()
list := New[string]()
list.Add("e", "f", "g", "a", "b", "c", "d")
list.Clear()
if actualValue := list.Empty(); actualValue != true {
@ -130,12 +153,15 @@ func TestListClear(t *testing.T) {
}
func TestListContains(t *testing.T) {
list := New()
list := New[string]()
list.Add("a")
list.Add("b", "c")
if actualValue := list.Contains("a"); actualValue != true {
t.Errorf("Got %v expected %v", actualValue, true)
}
if actualValue := list.Contains(""); actualValue != false {
t.Errorf("Got %v expected %v", actualValue, false)
}
if actualValue := list.Contains("a", "b", "c"); actualValue != true {
t.Errorf("Got %v expected %v", actualValue, true)
}
@ -152,16 +178,16 @@ func TestListContains(t *testing.T) {
}
func TestListValues(t *testing.T) {
list := New()
list := New[string]()
list.Add("a")
list.Add("b", "c")
if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abc"; actualValue != expectedValue {
if actualValue, expectedValue := list.Values(), []string{"a", "b", "c"}; !slices.Equal(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
}
func TestListIndexOf(t *testing.T) {
list := New()
list := New[string]()
expectedIndex := -1
if index := list.IndexOf("a"); index != expectedIndex {
@ -188,7 +214,7 @@ func TestListIndexOf(t *testing.T) {
}
func TestListInsert(t *testing.T) {
list := New()
list := New[string]()
list.Insert(0, "b", "c")
list.Insert(0, "a")
list.Insert(10, "x") // ignore
@ -199,13 +225,13 @@ func TestListInsert(t *testing.T) {
if actualValue := list.Size(); actualValue != 4 {
t.Errorf("Got %v expected %v", actualValue, 4)
}
if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", list.Values()...), "abcd"; actualValue != expectedValue {
if actualValue, expectedValue := strings.Join(list.Values(), ""), "abcd"; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
}
func TestListSet(t *testing.T) {
list := New()
list := New[string]()
list.Set(0, "a")
list.Set(1, "b")
if actualValue := list.Size(); actualValue != 2 {
@ -220,15 +246,15 @@ func TestListSet(t *testing.T) {
if actualValue := list.Size(); actualValue != 3 {
t.Errorf("Got %v expected %v", actualValue, 3)
}
if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abbc"; actualValue != expectedValue {
if actualValue, expectedValue := list.Values(), []string{"a", "bb", "c"}; !slices.Equal(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
}
func TestListEach(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
list.Each(func(index int, value interface{}) {
list.Each(func(index int, value string) {
switch index {
case 0:
if actualValue, expectedValue := value, "a"; actualValue != expectedValue {
@ -249,10 +275,10 @@ func TestListEach(t *testing.T) {
}
func TestListMap(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
mappedList := list.Map(func(index int, value interface{}) interface{} {
return "mapped: " + value.(string)
mappedList := list.Map(func(index int, value string) string {
return "mapped: " + value
})
if actualValue, _ := mappedList.Get(0); actualValue != "mapped: a" {
t.Errorf("Got %v expected %v", actualValue, "mapped: a")
@ -269,10 +295,10 @@ func TestListMap(t *testing.T) {
}
func TestListSelect(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
selectedList := list.Select(func(index int, value interface{}) bool {
return value.(string) >= "a" && value.(string) <= "b"
selectedList := list.Select(func(index int, value string) bool {
return value >= "a" && value <= "b"
})
if actualValue, _ := selectedList.Get(0); actualValue != "a" {
t.Errorf("Got %v expected %v", actualValue, "value: a")
@ -286,60 +312,60 @@ func TestListSelect(t *testing.T) {
}
func TestListAny(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
any := list.Any(func(index int, value interface{}) bool {
return value.(string) == "c"
any := list.Any(func(index int, value string) bool {
return value == "c"
})
if any != true {
t.Errorf("Got %v expected %v", any, true)
}
any = list.Any(func(index int, value interface{}) bool {
return value.(string) == "x"
any = list.Any(func(index int, value string) bool {
return value == "x"
})
if any != false {
t.Errorf("Got %v expected %v", any, false)
}
}
func TestListAll(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
all := list.All(func(index int, value interface{}) bool {
return value.(string) >= "a" && value.(string) <= "c"
all := list.All(func(index int, value string) bool {
return value >= "a" && value <= "c"
})
if all != true {
t.Errorf("Got %v expected %v", all, true)
}
all = list.All(func(index int, value interface{}) bool {
return value.(string) >= "a" && value.(string) <= "b"
all = list.All(func(index int, value string) bool {
return value >= "a" && value <= "b"
})
if all != false {
t.Errorf("Got %v expected %v", all, false)
}
}
func TestListFind(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
foundIndex, foundValue := list.Find(func(index int, value interface{}) bool {
return value.(string) == "c"
foundIndex, foundValue := list.Find(func(index int, value string) bool {
return value == "c"
})
if foundValue != "c" || foundIndex != 2 {
t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, "c", 2)
}
foundIndex, foundValue = list.Find(func(index int, value interface{}) bool {
return value.(string) == "x"
foundIndex, foundValue = list.Find(func(index int, value string) bool {
return value == "x"
})
if foundValue != nil || foundIndex != -1 {
if foundValue != "" || foundIndex != -1 {
t.Errorf("Got %v at %v expected %v at %v", foundValue, foundIndex, nil, nil)
}
}
func TestListChaining(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
chainedList := list.Select(func(index int, value interface{}) bool {
return value.(string) > "a"
}).Map(func(index int, value interface{}) interface{} {
return value.(string) + value.(string)
chainedList := list.Select(func(index int, value string) bool {
return value > "a"
}).Map(func(index int, value string) string {
return value + value
})
if chainedList.Size() != 2 {
t.Errorf("Got %v expected %v", chainedList.Size(), 2)
@ -353,7 +379,7 @@ func TestListChaining(t *testing.T) {
}
func TestListIteratorNextOnEmpty(t *testing.T) {
list := New()
list := New[string]()
it := list.Iterator()
for it.Next() {
t.Errorf("Shouldn't iterate on empty list")
@ -361,7 +387,7 @@ func TestListIteratorNextOnEmpty(t *testing.T) {
}
func TestListIteratorNext(t *testing.T) {
list := New()
list := New[string]()
list.Add("a", "b", "c")
it := list.Iterator()
count := 0
@ -392,7 +418,7 @@ func TestListIteratorNext(t *testing.T) {
}
func TestListIteratorBegin(t *testing.T) {
list := New()
list := New[string]()
it := list.Iterator()
it.Begin()
list.Add("a", "b", "c")
@ -406,7 +432,7 @@ func TestListIteratorBegin(t *testing.T) {
}
func TestListIteratorFirst(t *testing.T) {
list := New()
list := New[string]()
it := list.Iterator()
if actualValue, expectedValue := it.First(), false; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
@ -420,13 +446,62 @@ func TestListIteratorFirst(t *testing.T) {
}
}
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()
list := New[string]()
list.Add("a", "b", "c")
var err error
assert := func() {
if actualValue, expectedValue := fmt.Sprintf("%s%s%s", list.Values()...), "abc"; actualValue != expectedValue {
if actualValue, expectedValue := list.Values(), []string{"a", "b", "c"}; !slices.Equal(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue, expectedValue := list.Size(), 3; actualValue != expectedValue {
@ -439,14 +514,33 @@ func TestListSerialization(t *testing.T) {
assert()
json, err := list.ToJSON()
bytes, err := list.ToJSON()
assert()
err = list.FromJSON(bytes)
assert()
err = list.FromJSON(json)
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 benchmarkGet(b *testing.B, list *List, size int) {
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)
@ -454,7 +548,7 @@ func benchmarkGet(b *testing.B, list *List, size int) {
}
}
func benchmarkAdd(b *testing.B, list *List, size int) {
func benchmarkAdd(b *testing.B, list *List[int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
list.Add(n)
@ -462,7 +556,7 @@ func benchmarkAdd(b *testing.B, list *List, size int) {
}
}
func benchmarkRemove(b *testing.B, list *List, size int) {
func benchmarkRemove(b *testing.B, list *List[int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
list.Remove(n)
@ -473,7 +567,7 @@ func benchmarkRemove(b *testing.B, list *List, size int) {
func BenchmarkSinglyLinkedListGet100(b *testing.B) {
b.StopTimer()
size := 100
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -484,7 +578,7 @@ func BenchmarkSinglyLinkedListGet100(b *testing.B) {
func BenchmarkSinglyLinkedListGet1000(b *testing.B) {
b.StopTimer()
size := 1000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -495,7 +589,7 @@ func BenchmarkSinglyLinkedListGet1000(b *testing.B) {
func BenchmarkSinglyLinkedListGet10000(b *testing.B) {
b.StopTimer()
size := 10000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -506,7 +600,7 @@ func BenchmarkSinglyLinkedListGet10000(b *testing.B) {
func BenchmarkSinglyLinkedListGet100000(b *testing.B) {
b.StopTimer()
size := 100000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -517,7 +611,7 @@ func BenchmarkSinglyLinkedListGet100000(b *testing.B) {
func BenchmarkSinglyLinkedListAdd100(b *testing.B) {
b.StopTimer()
size := 100
list := New()
list := New[int]()
b.StartTimer()
benchmarkAdd(b, list, size)
}
@ -525,7 +619,7 @@ func BenchmarkSinglyLinkedListAdd100(b *testing.B) {
func BenchmarkSinglyLinkedListAdd1000(b *testing.B) {
b.StopTimer()
size := 1000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -536,7 +630,7 @@ func BenchmarkSinglyLinkedListAdd1000(b *testing.B) {
func BenchmarkSinglyLinkedListAdd10000(b *testing.B) {
b.StopTimer()
size := 10000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -547,7 +641,7 @@ func BenchmarkSinglyLinkedListAdd10000(b *testing.B) {
func BenchmarkSinglyLinkedListAdd100000(b *testing.B) {
b.StopTimer()
size := 100000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -558,7 +652,7 @@ func BenchmarkSinglyLinkedListAdd100000(b *testing.B) {
func BenchmarkSinglyLinkedListRemove100(b *testing.B) {
b.StopTimer()
size := 100
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -569,7 +663,7 @@ func BenchmarkSinglyLinkedListRemove100(b *testing.B) {
func BenchmarkSinglyLinkedListRemove1000(b *testing.B) {
b.StopTimer()
size := 1000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -580,7 +674,7 @@ func BenchmarkSinglyLinkedListRemove1000(b *testing.B) {
func BenchmarkSinglyLinkedListRemove10000(b *testing.B) {
b.StopTimer()
size := 10000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}
@ -591,7 +685,7 @@ func BenchmarkSinglyLinkedListRemove10000(b *testing.B) {
func BenchmarkSinglyLinkedListRemove100000(b *testing.B) {
b.StopTimer()
size := 100000
list := New()
list := New[int]()
for n := 0; n < size; n++ {
list.Add(n)
}

@ -17,27 +17,27 @@ package hashbidimap
import (
"fmt"
"github.com/emirpasic/gods/maps"
"github.com/emirpasic/gods/maps/hashmap"
"github.com/emirpasic/gods/v2/maps"
"github.com/emirpasic/gods/v2/maps/hashmap"
)
func assertMapImplementation() {
var _ maps.BidiMap = (*Map)(nil)
}
// Assert Map implementation
var _ maps.BidiMap[string, int] = (*Map[string, int])(nil)
// Map holds the elements in two hashmaps.
type Map struct {
forwardMap hashmap.Map
inverseMap hashmap.Map
type Map[K, V comparable] struct {
forwardMap hashmap.Map[K, V]
inverseMap hashmap.Map[V, K]
}
// New instantiates a bidirectional map.
func New() *Map {
return &Map{*hashmap.New(), *hashmap.New()}
func New[K, V comparable]() *Map[K, V] {
return &Map[K, V]{*hashmap.New[K, V](), *hashmap.New[V, K]()}
}
// Put inserts element into the map.
func (m *Map) Put(key interface{}, value interface{}) {
func (m *Map[K, V]) Put(key K, value V) {
if valueByKey, ok := m.forwardMap.Get(key); ok {
m.inverseMap.Remove(valueByKey)
}
@ -50,18 +50,18 @@ func (m *Map) Put(key interface{}, value interface{}) {
// Get searches the element in the map by key and returns its value or nil if key is not found in map.
// Second return parameter is true if key was found, otherwise false.
func (m *Map) Get(key interface{}) (value interface{}, found bool) {
func (m *Map[K, V]) Get(key K) (value V, found bool) {
return m.forwardMap.Get(key)
}
// GetKey searches the element in the map by value and returns its key or nil if value is not found in map.
// Second return parameter is true if value was found, otherwise false.
func (m *Map) GetKey(value interface{}) (key interface{}, found bool) {
func (m *Map[K, V]) GetKey(value V) (key K, found bool) {
return m.inverseMap.Get(value)
}
// Remove removes the element from the map by key.
func (m *Map) Remove(key interface{}) {
func (m *Map[K, V]) Remove(key K) {
if value, found := m.forwardMap.Get(key); found {
m.forwardMap.Remove(key)
m.inverseMap.Remove(value)
@ -69,33 +69,33 @@ func (m *Map) Remove(key interface{}) {
}
// Empty returns true if map does not contain any elements
func (m *Map) Empty() bool {
func (m *Map[K, V]) Empty() bool {
return m.Size() == 0
}
// Size returns number of elements in the map.
func (m *Map) Size() int {
func (m *Map[K, V]) Size() int {
return m.forwardMap.Size()
}
// Keys returns all keys (random order).
func (m *Map) Keys() []interface{} {
func (m *Map[K, V]) Keys() []K {
return m.forwardMap.Keys()
}
// Values returns all values (random order).
func (m *Map) Values() []interface{} {
func (m *Map[K, V]) Values() []V {
return m.inverseMap.Keys()
}
// Clear removes all elements from the map.
func (m *Map) Clear() {
func (m *Map[K, V]) Clear() {
m.forwardMap.Clear()
m.inverseMap.Clear()
}
// String returns a string representation of container
func (m *Map) String() string {
func (m *Map[K, V]) String() string {
str := "HashBidiMap\n"
str += fmt.Sprintf("%v", m.forwardMap)
return str

@ -5,12 +5,15 @@
package hashbidimap
import (
"fmt"
"encoding/json"
"strings"
"testing"
"github.com/emirpasic/gods/v2/testutils"
)
func TestMapPut(t *testing.T) {
m := New()
m := New[int, string]()
m.Put(5, "e")
m.Put(6, "f")
m.Put(7, "g")
@ -23,12 +26,8 @@ func TestMapPut(t *testing.T) {
if actualValue := m.Size(); actualValue != 7 {
t.Errorf("Got %v expected %v", actualValue, 7)
}
if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "e", "f", "g"}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4, 5, 6, 7})
testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d", "e", "f", "g"})
// key,expectedValue,expectedFound
tests1 := [][]interface{}{
@ -39,12 +38,12 @@ func TestMapPut(t *testing.T) {
{5, "e", true},
{6, "f", true},
{7, "g", true},
{8, nil, false},
{8, "", false},
}
for _, test := range tests1 {
// retrievals
actualValue, actualFound := m.Get(test[0])
actualValue, actualFound := m.Get(test[0].(int))
if actualValue != test[1] || actualFound != test[2] {
t.Errorf("Got %v expected %v", actualValue, test[1])
}
@ -52,7 +51,7 @@ func TestMapPut(t *testing.T) {
}
func TestMapRemove(t *testing.T) {
m := New()
m := New[int, string]()
m.Put(5, "e")
m.Put(6, "f")
m.Put(7, "g")
@ -68,13 +67,9 @@ func TestMapRemove(t *testing.T) {
m.Remove(8)
m.Remove(5)
if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4})
testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d"})
if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d"}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue := m.Size(); actualValue != 4 {
t.Errorf("Got %v expected %v", actualValue, 4)
}
@ -84,14 +79,14 @@ func TestMapRemove(t *testing.T) {
{2, "b", true},
{3, "c", true},
{4, "d", true},
{5, nil, false},
{6, nil, false},
{7, nil, false},
{8, nil, false},
{5, "", false},
{6, "", false},
{7, "", false},
{8, "", false},
}
for _, test := range tests2 {
actualValue, actualFound := m.Get(test[0])
actualValue, actualFound := m.Get(test[0].(int))
if actualValue != test[1] || actualFound != test[2] {
t.Errorf("Got %v expected %v", actualValue, test[1])
}
@ -104,12 +99,8 @@ func TestMapRemove(t *testing.T) {
m.Remove(2)
m.Remove(2)
if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
testutils.SameElements(t, m.Keys(), nil)
testutils.SameElements(t, m.Values(), nil)
if actualValue := m.Size(); actualValue != 0 {
t.Errorf("Got %v expected %v", actualValue, 0)
}
@ -119,7 +110,7 @@ func TestMapRemove(t *testing.T) {
}
func TestMapGetKey(t *testing.T) {
m := New()
m := New[int, string]()
m.Put(5, "e")
m.Put(6, "f")
m.Put(7, "g")
@ -138,12 +129,12 @@ func TestMapGetKey(t *testing.T) {
{5, "e", true},
{6, "f", true},
{7, "g", true},
{nil, "x", false},
{0, "x", false},
}
for _, test := range tests1 {
// retrievals
actualValue, actualFound := m.GetKey(test[1])
actualValue, actualFound := m.GetKey(test[1].(string))
if actualValue != test[0] || actualFound != test[2] {
t.Errorf("Got %v expected %v", actualValue, test[0])
}
@ -151,19 +142,15 @@ func TestMapGetKey(t *testing.T) {
}
func TestMapSerialization(t *testing.T) {
m := New()
m := New[string, float64]()
m.Put("a", 1.0)
m.Put("b", 2.0)
m.Put("c", 3.0)
var err error
assert := func() {
if actualValue, expectedValue := m.Keys(), []interface{}{"a", "b", "c"}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue, expectedValue := m.Values(), []interface{}{1.0, 2.0, 3.0}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
testutils.SameElements(t, m.Keys(), []string{"a", "b", "c"})
testutils.SameElements(t, m.Values(), []float64{1.0, 2.0, 3.0})
if actualValue, expectedValue := m.Size(), 3; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
@ -174,33 +161,32 @@ func TestMapSerialization(t *testing.T) {
assert()
json, err := m.ToJSON()
bytes, err := m.ToJSON()
assert()
err = m.FromJSON(json)
err = m.FromJSON(bytes)
assert()
}
func sameElements(a []interface{}, b []interface{}) bool {
if len(a) != len(b) {
return false
bytes, err = json.Marshal([]interface{}{"a", "b", "c", m})
if err != nil {
t.Errorf("Got error %v", err)
}
for _, av := range a {
found := false
for _, bv := range b {
if av == bv {
found = true
break
}
}
if !found {
return false
}
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")
}
return true
}
func benchmarkGet(b *testing.B, m *Map, size int) {
func benchmarkGet(b *testing.B, m *Map[int, int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
m.Get(n)
@ -208,7 +194,7 @@ func benchmarkGet(b *testing.B, m *Map, size int) {
}
}
func benchmarkPut(b *testing.B, m *Map, size int) {
func benchmarkPut(b *testing.B, m *Map[int, int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
m.Put(n, n)
@ -216,7 +202,7 @@ func benchmarkPut(b *testing.B, m *Map, size int) {
}
}
func benchmarkRemove(b *testing.B, m *Map, size int) {
func benchmarkRemove(b *testing.B, m *Map[int, int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
m.Remove(n)
@ -227,7 +213,7 @@ func benchmarkRemove(b *testing.B, m *Map, size int) {
func BenchmarkHashBidiMapGet100(b *testing.B) {
b.StopTimer()
size := 100
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -238,7 +224,7 @@ func BenchmarkHashBidiMapGet100(b *testing.B) {
func BenchmarkHashBidiMapGet1000(b *testing.B) {
b.StopTimer()
size := 1000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -249,7 +235,7 @@ func BenchmarkHashBidiMapGet1000(b *testing.B) {
func BenchmarkHashBidiMapGet10000(b *testing.B) {
b.StopTimer()
size := 10000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -260,7 +246,7 @@ func BenchmarkHashBidiMapGet10000(b *testing.B) {
func BenchmarkHashBidiMapGet100000(b *testing.B) {
b.StopTimer()
size := 100000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -271,7 +257,7 @@ func BenchmarkHashBidiMapGet100000(b *testing.B) {
func BenchmarkHashBidiMapPut100(b *testing.B) {
b.StopTimer()
size := 100
m := New()
m := New[int, int]()
b.StartTimer()
benchmarkPut(b, m, size)
}
@ -279,7 +265,7 @@ func BenchmarkHashBidiMapPut100(b *testing.B) {
func BenchmarkHashBidiMapPut1000(b *testing.B) {
b.StopTimer()
size := 1000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -290,7 +276,7 @@ func BenchmarkHashBidiMapPut1000(b *testing.B) {
func BenchmarkHashBidiMapPut10000(b *testing.B) {
b.StopTimer()
size := 10000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -301,7 +287,7 @@ func BenchmarkHashBidiMapPut10000(b *testing.B) {
func BenchmarkHashBidiMapPut100000(b *testing.B) {
b.StopTimer()
size := 100000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -312,7 +298,7 @@ func BenchmarkHashBidiMapPut100000(b *testing.B) {
func BenchmarkHashBidiMapRemove100(b *testing.B) {
b.StopTimer()
size := 100
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -323,7 +309,7 @@ func BenchmarkHashBidiMapRemove100(b *testing.B) {
func BenchmarkHashBidiMapRemove1000(b *testing.B) {
b.StopTimer()
size := 1000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -334,7 +320,7 @@ func BenchmarkHashBidiMapRemove1000(b *testing.B) {
func BenchmarkHashBidiMapRemove10000(b *testing.B) {
b.StopTimer()
size := 10000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -345,7 +331,7 @@ func BenchmarkHashBidiMapRemove10000(b *testing.B) {
func BenchmarkHashBidiMapRemove100000(b *testing.B) {
b.StopTimer()
size := 100000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}

@ -6,28 +6,41 @@ package hashbidimap
import (
"encoding/json"
"github.com/emirpasic/gods/containers"
"github.com/emirpasic/gods/v2/containers"
)
func assertSerializationImplementation() {
var _ containers.JSONSerializer = (*Map)(nil)
var _ containers.JSONDeserializer = (*Map)(nil)
}
// 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) ToJSON() ([]byte, error) {
func (m *Map[K, V]) ToJSON() ([]byte, error) {
return m.forwardMap.ToJSON()
}
// FromJSON populates the map from the input JSON representation.
func (m *Map) FromJSON(data []byte) error {
elements := make(map[string]interface{})
func (m *Map[K, V]) FromJSON(data []byte) error {
var elements map[K]V
err := json.Unmarshal(data, &elements)
if err == nil {
m.Clear()
for key, value := range elements {
m.Put(key, value)
}
if err != nil {
return err
}
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()
}

@ -13,53 +13,53 @@ package hashmap
import (
"fmt"
"github.com/emirpasic/gods/maps"
"github.com/emirpasic/gods/v2/maps"
)
func assertMapImplementation() {
var _ maps.Map = (*Map)(nil)
}
// Assert Map implementation
var _ maps.Map[string, int] = (*Map[string, int])(nil)
// Map holds the elements in go's native map
type Map struct {
m map[interface{}]interface{}
type Map[K comparable, V any] struct {
m map[K]V
}
// New instantiates a hash map.
func New() *Map {
return &Map{m: make(map[interface{}]interface{})}
func New[K comparable, V any]() *Map[K, V] {
return &Map[K, V]{m: make(map[K]V)}
}
// Put inserts element into the map.
func (m *Map) Put(key interface{}, value interface{}) {
func (m *Map[K, V]) Put(key K, value V) {
m.m[key] = value
}
// Get searches the element in the map by key and returns its value or nil if key is not found in map.
// Second return parameter is true if key was found, otherwise false.
func (m *Map) Get(key interface{}) (value interface{}, found bool) {
func (m *Map[K, V]) Get(key K) (value V, found bool) {
value, found = m.m[key]
return
}
// Remove removes the element from the map by key.
func (m *Map) Remove(key interface{}) {
func (m *Map[K, V]) Remove(key K) {
delete(m.m, key)
}
// Empty returns true if map does not contain any elements
func (m *Map) Empty() bool {
func (m *Map[K, V]) Empty() bool {
return m.Size() == 0
}
// Size returns number of elements in the map.
func (m *Map) Size() int {
func (m *Map[K, V]) Size() int {
return len(m.m)
}
// Keys returns all keys (random order).
func (m *Map) Keys() []interface{} {
keys := make([]interface{}, m.Size())
func (m *Map[K, V]) Keys() []K {
keys := make([]K, m.Size())
count := 0
for key := range m.m {
keys[count] = key
@ -69,8 +69,8 @@ func (m *Map) Keys() []interface{} {
}
// Values returns all values (random order).
func (m *Map) Values() []interface{} {
values := make([]interface{}, m.Size())
func (m *Map[K, V]) Values() []V {
values := make([]V, m.Size())
count := 0
for _, value := range m.m {
values[count] = value
@ -80,12 +80,12 @@ func (m *Map) Values() []interface{} {
}
// Clear removes all elements from the map.
func (m *Map) Clear() {
m.m = make(map[interface{}]interface{})
func (m *Map[K, V]) Clear() {
clear(m.m)
}
// String returns a string representation of container
func (m *Map) String() string {
func (m *Map[K, V]) String() string {
str := "HashMap\n"
str += fmt.Sprintf("%v", m.m)
return str

@ -5,12 +5,15 @@
package hashmap
import (
"fmt"
"encoding/json"
"strings"
"testing"
"github.com/emirpasic/gods/v2/testutils"
)
func TestMapPut(t *testing.T) {
m := New()
m := New[int, string]()
m.Put(5, "e")
m.Put(6, "f")
m.Put(7, "g")
@ -23,12 +26,8 @@ func TestMapPut(t *testing.T) {
if actualValue := m.Size(); actualValue != 7 {
t.Errorf("Got %v expected %v", actualValue, 7)
}
if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "e", "f", "g"}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4, 5, 6, 7})
testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d", "e", "f", "g"})
// key,expectedValue,expectedFound
tests1 := [][]interface{}{
@ -39,12 +38,12 @@ func TestMapPut(t *testing.T) {
{5, "e", true},
{6, "f", true},
{7, "g", true},
{8, nil, false},
{8, "", false},
}
for _, test := range tests1 {
// retrievals
actualValue, actualFound := m.Get(test[0])
actualValue, actualFound := m.Get(test[0].(int))
if actualValue != test[1] || actualFound != test[2] {
t.Errorf("Got %v expected %v", actualValue, test[1])
}
@ -52,7 +51,7 @@ func TestMapPut(t *testing.T) {
}
func TestMapRemove(t *testing.T) {
m := New()
m := New[int, string]()
m.Put(5, "e")
m.Put(6, "f")
m.Put(7, "g")
@ -68,13 +67,9 @@ func TestMapRemove(t *testing.T) {
m.Remove(8)
m.Remove(5)
if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4})
testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d"})
if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d"}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue := m.Size(); actualValue != 4 {
t.Errorf("Got %v expected %v", actualValue, 4)
}
@ -84,14 +79,14 @@ func TestMapRemove(t *testing.T) {
{2, "b", true},
{3, "c", true},
{4, "d", true},
{5, nil, false},
{6, nil, false},
{7, nil, false},
{8, nil, false},
{5, "", false},
{6, "", false},
{7, "", false},
{8, "", false},
}
for _, test := range tests2 {
actualValue, actualFound := m.Get(test[0])
actualValue, actualFound := m.Get(test[0].(int))
if actualValue != test[1] || actualFound != test[2] {
t.Errorf("Got %v expected %v", actualValue, test[1])
}
@ -104,12 +99,8 @@ func TestMapRemove(t *testing.T) {
m.Remove(2)
m.Remove(2)
if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
testutils.SameElements(t, m.Keys(), nil)
testutils.SameElements(t, m.Values(), nil)
if actualValue := m.Size(); actualValue != 0 {
t.Errorf("Got %v expected %v", actualValue, 0)
}
@ -119,19 +110,15 @@ func TestMapRemove(t *testing.T) {
}
func TestMapSerialization(t *testing.T) {
m := New()
m := New[string, float64]()
m.Put("a", 1.0)
m.Put("b", 2.0)
m.Put("c", 3.0)
var err error
assert := func() {
if actualValue, expectedValue := m.Keys(), []interface{}{"a", "b", "c"}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue, expectedValue := m.Values(), []interface{}{1.0, 2.0, 3.0}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
testutils.SameElements(t, m.Keys(), []string{"a", "b", "c"})
testutils.SameElements(t, m.Values(), []float64{1.0, 2.0, 3.0})
if actualValue, expectedValue := m.Size(), 3; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
@ -142,33 +129,32 @@ func TestMapSerialization(t *testing.T) {
assert()
json, err := m.ToJSON()
bytes, err := m.ToJSON()
assert()
err = m.FromJSON(json)
err = m.FromJSON(bytes)
assert()
}
func sameElements(a []interface{}, b []interface{}) bool {
if len(a) != len(b) {
return false
bytes, err = json.Marshal([]interface{}{"a", "b", "c", m})
if err != nil {
t.Errorf("Got error %v", err)
}
for _, av := range a {
found := false
for _, bv := range b {
if av == bv {
found = true
break
}
}
if !found {
return false
}
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")
}
return true
}
func benchmarkGet(b *testing.B, m *Map, size int) {
func benchmarkGet(b *testing.B, m *Map[int, int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
m.Get(n)
@ -176,15 +162,15 @@ func benchmarkGet(b *testing.B, m *Map, size int) {
}
}
func benchmarkPut(b *testing.B, m *Map, size int) {
func benchmarkPut(b *testing.B, m *Map[int, int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
}
}
func benchmarkRemove(b *testing.B, m *Map, size int) {
func benchmarkRemove(b *testing.B, m *Map[int, int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
m.Remove(n)
@ -195,9 +181,9 @@ func benchmarkRemove(b *testing.B, m *Map, size int) {
func BenchmarkHashMapGet100(b *testing.B) {
b.StopTimer()
size := 100
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkGet(b, m, size)
@ -206,9 +192,9 @@ func BenchmarkHashMapGet100(b *testing.B) {
func BenchmarkHashMapGet1000(b *testing.B) {
b.StopTimer()
size := 1000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkGet(b, m, size)
@ -217,9 +203,9 @@ func BenchmarkHashMapGet1000(b *testing.B) {
func BenchmarkHashMapGet10000(b *testing.B) {
b.StopTimer()
size := 10000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkGet(b, m, size)
@ -228,9 +214,9 @@ func BenchmarkHashMapGet10000(b *testing.B) {
func BenchmarkHashMapGet100000(b *testing.B) {
b.StopTimer()
size := 100000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkGet(b, m, size)
@ -239,7 +225,7 @@ func BenchmarkHashMapGet100000(b *testing.B) {
func BenchmarkHashMapPut100(b *testing.B) {
b.StopTimer()
size := 100
m := New()
m := New[int, int]()
b.StartTimer()
benchmarkPut(b, m, size)
}
@ -247,9 +233,9 @@ func BenchmarkHashMapPut100(b *testing.B) {
func BenchmarkHashMapPut1000(b *testing.B) {
b.StopTimer()
size := 1000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkPut(b, m, size)
@ -258,9 +244,9 @@ func BenchmarkHashMapPut1000(b *testing.B) {
func BenchmarkHashMapPut10000(b *testing.B) {
b.StopTimer()
size := 10000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkPut(b, m, size)
@ -269,9 +255,9 @@ func BenchmarkHashMapPut10000(b *testing.B) {
func BenchmarkHashMapPut100000(b *testing.B) {
b.StopTimer()
size := 100000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkPut(b, m, size)
@ -280,9 +266,9 @@ func BenchmarkHashMapPut100000(b *testing.B) {
func BenchmarkHashMapRemove100(b *testing.B) {
b.StopTimer()
size := 100
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkRemove(b, m, size)
@ -291,9 +277,9 @@ func BenchmarkHashMapRemove100(b *testing.B) {
func BenchmarkHashMapRemove1000(b *testing.B) {
b.StopTimer()
size := 1000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkRemove(b, m, size)
@ -302,9 +288,9 @@ func BenchmarkHashMapRemove1000(b *testing.B) {
func BenchmarkHashMapRemove10000(b *testing.B) {
b.StopTimer()
size := 10000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkRemove(b, m, size)
@ -313,9 +299,9 @@ func BenchmarkHashMapRemove10000(b *testing.B) {
func BenchmarkHashMapRemove100000(b *testing.B) {
b.StopTimer()
size := 100000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkRemove(b, m, size)

@ -6,33 +6,30 @@ package hashmap
import (
"encoding/json"
"github.com/emirpasic/gods/containers"
"github.com/emirpasic/gods/utils"
"github.com/emirpasic/gods/v2/containers"
)
func assertSerializationImplementation() {
var _ containers.JSONSerializer = (*Map)(nil)
var _ containers.JSONDeserializer = (*Map)(nil)
}
// 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) ToJSON() ([]byte, error) {
elements := make(map[string]interface{})
for key, value := range m.m {
elements[utils.ToString(key)] = value
}
return json.Marshal(&elements)
func (m *Map[K, V]) ToJSON() ([]byte, error) {
return json.Marshal(m.m)
}
// FromJSON populates the map from the input JSON representation.
func (m *Map) FromJSON(data []byte) error {
elements := make(map[string]interface{})
err := json.Unmarshal(data, &elements)
if err == nil {
m.Clear()
for key, value := range elements {
m.m[key] = value
}
}
return err
func (m *Map[K, V]) FromJSON(data []byte) error {
return json.Unmarshal(data, &m.m)
}
// UnmarshalJSON @implements json.Unmarshaler
func (m *Map[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()
}

@ -4,14 +4,13 @@
package linkedhashmap
import "github.com/emirpasic/gods/containers"
import "github.com/emirpasic/gods/v2/containers"
func assertEnumerableImplementation() {
var _ containers.EnumerableWithKey = (*Map)(nil)
}
// 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) Each(f func(key interface{}, value interface{})) {
func (m *Map[K, V]) Each(f func(key K, value V)) {
iterator := m.Iterator()
for iterator.Next() {
f(iterator.Key(), iterator.Value())
@ -20,8 +19,8 @@ func (m *Map) Each(f func(key interface{}, value interface{})) {
// Map invokes the given function once for each element and returns a container
// containing the values returned by the given function as key/value pairs.
func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) *Map {
newMap := New()
func (m *Map[K, V]) Map(f func(key1 K, value1 V) (K, V)) *Map[K, V] {
newMap := New[K, V]()
iterator := m.Iterator()
for iterator.Next() {
key2, value2 := f(iterator.Key(), iterator.Value())
@ -31,8 +30,8 @@ func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, int
}
// Select returns a new container containing all elements for which the given function returns a true value.
func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map {
newMap := New()
func (m *Map[K, V]) Select(f func(key K, value V) bool) *Map[K, V] {
newMap := New[K, V]()
iterator := m.Iterator()
for iterator.Next() {
if f(iterator.Key(), iterator.Value()) {
@ -44,7 +43,7 @@ func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map {
// Any passes each element of the container to the given function and
// returns true if the function ever returns true for any element.
func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool {
func (m *Map[K, V]) Any(f func(key K, value V) bool) bool {
iterator := m.Iterator()
for iterator.Next() {
if f(iterator.Key(), iterator.Value()) {
@ -56,7 +55,7 @@ func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool {
// All passes each element of the container to the given function and
// returns true if the function returns true for all elements.
func (m *Map) All(f func(key interface{}, value interface{}) bool) bool {
func (m *Map[K, V]) All(f func(key K, value V) bool) bool {
iterator := m.Iterator()
for iterator.Next() {
if !f(iterator.Key(), iterator.Value()) {
@ -69,12 +68,12 @@ func (m *Map) All(f func(key interface{}, value interface{}) bool) bool {
// Find passes each element of the container to the given function and returns
// the first (key,value) for which the function is true or nil,nil otherwise if no element
// matches the criteria.
func (m *Map) Find(f func(key interface{}, value interface{}) bool) (interface{}, interface{}) {
func (m *Map[K, V]) Find(f func(key K, value V) bool) (k K, v V) {
iterator := m.Iterator()
for iterator.Next() {
if f(iterator.Key(), iterator.Value()) {
return iterator.Key(), iterator.Value()
}
}
return nil, nil
return k, v
}

@ -5,77 +5,105 @@
package linkedhashmap
import (
"github.com/emirpasic/gods/containers"
"github.com/emirpasic/gods/lists/doublylinkedlist"
"github.com/emirpasic/gods/v2/containers"
"github.com/emirpasic/gods/v2/lists/doublylinkedlist"
)
func assertIteratorImplementation() {
var _ containers.ReverseIteratorWithKey = (*Iterator)(nil)
}
// Assert Iterator implementation
var _ containers.ReverseIteratorWithKey[string, int] = (*Iterator[string, int])(nil)
// Iterator holding the iterator's state
type Iterator struct {
iterator doublylinkedlist.Iterator
table map[interface{}]interface{}
type Iterator[K comparable, V any] struct {
iterator doublylinkedlist.Iterator[K]
table map[K]V
}
// Iterator returns a stateful iterator whose elements are key/value pairs.
func (m *Map) Iterator() Iterator {
return Iterator{
func (m *Map[K, V]) Iterator() *Iterator[K, V] {
return &Iterator[K, V]{
iterator: m.ordering.Iterator(),
table: m.table}
table: m.table,
}
}
// Next moves the iterator to the next element and returns true if there was a next element in the container.
// If Next() returns true, then next element's key and value can be retrieved by Key() and Value().
// If Next() was called for the first time, then it will point the iterator to the first element if it exists.
// Modifies the state of the iterator.
func (iterator *Iterator) Next() bool {
func (iterator *Iterator[K, V]) Next() bool {
return iterator.iterator.Next()
}
// Prev moves the iterator to the previous element and returns true if there was a previous element in the container.
// If Prev() returns true, then previous element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator.
func (iterator *Iterator) Prev() bool {
func (iterator *Iterator[K, V]) Prev() bool {
return iterator.iterator.Prev()
}
// Value returns the current element's value.
// Does not modify the state of the iterator.
func (iterator *Iterator) Value() interface{} {
func (iterator *Iterator[K, V]) Value() V {
key := iterator.iterator.Value()
return iterator.table[key]
}
// Key returns the current element's key.
// Does not modify the state of the iterator.
func (iterator *Iterator) Key() interface{} {
func (iterator *Iterator[K, V]) Key() K {
return iterator.iterator.Value()
}
// Begin resets the iterator to its initial state (one-before-first)
// Call Next() to fetch the first element if any.
func (iterator *Iterator) Begin() {
func (iterator *Iterator[K, V]) Begin() {
iterator.iterator.Begin()
}
// End moves the iterator past the last element (one-past-the-end).
// Call Prev() to fetch the last element if any.
func (iterator *Iterator) End() {
func (iterator *Iterator[K, V]) End() {
iterator.iterator.End()
}
// First moves the iterator to the first element and returns true if there was a first element in the container.
// If First() returns true, then first element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator
func (iterator *Iterator) First() bool {
func (iterator *Iterator[K, V]) First() bool {
return iterator.iterator.First()
}
// Last moves the iterator to the last element and returns true if there was a last element in the container.
// If Last() returns true, then last element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator.
func (iterator *Iterator) Last() bool {
func (iterator *Iterator[K, V]) Last() bool {
return iterator.iterator.Last()
}
// 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
}

@ -13,32 +13,32 @@ package linkedhashmap
import (
"fmt"
"github.com/emirpasic/gods/lists/doublylinkedlist"
"github.com/emirpasic/gods/maps"
"strings"
"github.com/emirpasic/gods/v2/lists/doublylinkedlist"
"github.com/emirpasic/gods/v2/maps"
)
func assertMapImplementation() {
var _ maps.Map = (*Map)(nil)
}
// 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 struct {
table map[interface{}]interface{}
ordering *doublylinkedlist.List
type Map[K comparable, V any] struct {
table map[K]V
ordering *doublylinkedlist.List[K]
}
// New instantiates a linked-hash-map.
func New() *Map {
return &Map{
table: make(map[interface{}]interface{}),
ordering: doublylinkedlist.New(),
func New[K comparable, V any]() *Map[K, V] {
return &Map[K, V]{
table: make(map[K]V),
ordering: doublylinkedlist.New[K](),
}
}
// Put inserts key-value pair into the map.
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (m *Map) Put(key interface{}, value interface{}) {
func (m *Map[K, V]) Put(key K, value V) {
if _, contains := m.table[key]; !contains {
m.ordering.Append(key)
}
@ -48,15 +48,14 @@ func (m *Map) Put(key interface{}, value interface{}) {
// Get searches the element in the map by key and returns its value or nil if key is not found in tree.
// Second return parameter is true if key was found, otherwise false.
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (m *Map) Get(key interface{}) (value interface{}, found bool) {
value = m.table[key]
found = value != nil
return
func (m *Map[K, V]) Get(key K) (value V, found bool) {
value, found = m.table[key]
return value, found
}
// Remove removes the element from the map by key.
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (m *Map) Remove(key interface{}) {
func (m *Map[K, V]) Remove(key K) {
if _, contains := m.table[key]; contains {
delete(m.table, key)
index := m.ordering.IndexOf(key)
@ -65,23 +64,23 @@ func (m *Map) Remove(key interface{}) {
}
// Empty returns true if map does not contain any elements
func (m *Map) Empty() bool {
func (m *Map[K, V]) Empty() bool {
return m.Size() == 0
}
// Size returns number of elements in the map.
func (m *Map) Size() int {
func (m *Map[K, V]) Size() int {
return m.ordering.Size()
}
// Keys returns all keys in-order
func (m *Map) Keys() []interface{} {
func (m *Map[K, V]) Keys() []K {
return m.ordering.Values()
}
// Values returns all values in-order based on the key.
func (m *Map) Values() []interface{} {
values := make([]interface{}, m.Size())
func (m *Map[K, V]) Values() []V {
values := make([]V, m.Size())
count := 0
it := m.Iterator()
for it.Next() {
@ -92,13 +91,13 @@ func (m *Map) Values() []interface{} {
}
// Clear removes all elements from the map.
func (m *Map) Clear() {
m.table = make(map[interface{}]interface{})
func (m *Map[K, V]) Clear() {
clear(m.table)
m.ordering.Clear()
}
// String returns a string representation of container
func (m *Map) String() string {
func (m *Map[K, V]) String() string {
str := "LinkedHashMap\nmap["
it := m.Iterator()
for it.Next() {

@ -5,12 +5,15 @@
package linkedhashmap
import (
"fmt"
"encoding/json"
"strings"
"testing"
"github.com/emirpasic/gods/v2/testutils"
)
func TestMapPut(t *testing.T) {
m := New()
m := New[int, string]()
m.Put(5, "e")
m.Put(6, "f")
m.Put(7, "g")
@ -23,12 +26,8 @@ func TestMapPut(t *testing.T) {
if actualValue := m.Size(); actualValue != 7 {
t.Errorf("Got %v expected %v", actualValue, 7)
}
if actualValue, expectedValue := m.Keys(), []interface{}{5, 6, 7, 3, 4, 1, 2}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue, expectedValue := m.Values(), []interface{}{"e", "f", "g", "c", "d", "a", "b"}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4, 5, 6, 7})
testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d", "e", "f", "g"})
// key,expectedValue,expectedFound
tests1 := [][]interface{}{
@ -39,12 +38,12 @@ func TestMapPut(t *testing.T) {
{5, "e", true},
{6, "f", true},
{7, "g", true},
{8, nil, false},
{8, "", false},
}
for _, test := range tests1 {
// retrievals
actualValue, actualFound := m.Get(test[0])
actualValue, actualFound := m.Get(test[0].(int))
if actualValue != test[1] || actualFound != test[2] {
t.Errorf("Got %v expected %v", actualValue, test[1])
}
@ -52,7 +51,7 @@ func TestMapPut(t *testing.T) {
}
func TestMapRemove(t *testing.T) {
m := New()
m := New[int, string]()
m.Put(5, "e")
m.Put(6, "f")
m.Put(7, "g")
@ -68,13 +67,9 @@ func TestMapRemove(t *testing.T) {
m.Remove(8)
m.Remove(5)
if actualValue, expectedValue := m.Keys(), []interface{}{3, 4, 1, 2}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4})
testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d"})
if actualValue, expectedValue := m.Values(), []interface{}{"c", "d", "a", "b"}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue := m.Size(); actualValue != 4 {
t.Errorf("Got %v expected %v", actualValue, 4)
}
@ -84,14 +79,14 @@ func TestMapRemove(t *testing.T) {
{2, "b", true},
{3, "c", true},
{4, "d", true},
{5, nil, false},
{6, nil, false},
{7, nil, false},
{8, nil, false},
{5, "", false},
{6, "", false},
{7, "", false},
{8, "", false},
}
for _, test := range tests2 {
actualValue, actualFound := m.Get(test[0])
actualValue, actualFound := m.Get(test[0].(int))
if actualValue != test[1] || actualFound != test[2] {
t.Errorf("Got %v expected %v", actualValue, test[1])
}
@ -104,12 +99,8 @@ func TestMapRemove(t *testing.T) {
m.Remove(2)
m.Remove(2)
if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
testutils.SameElements(t, m.Keys(), nil)
testutils.SameElements(t, m.Values(), nil)
if actualValue := m.Size(); actualValue != 0 {
t.Errorf("Got %v expected %v", actualValue, 0)
}
@ -118,32 +109,13 @@ func TestMapRemove(t *testing.T) {
}
}
func sameElements(a []interface{}, b []interface{}) bool {
// If one is nil, the other must also be nil.
if (a == nil) != (b == nil) {
return false
}
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}
func TestMapEach(t *testing.T) {
m := New()
m := New[string, int]()
m.Put("c", 1)
m.Put("a", 2)
m.Put("b", 3)
count := 0
m.Each(func(key interface{}, value interface{}) {
m.Each(func(key string, value int) {
count++
if actualValue, expectedValue := count, value; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
@ -168,12 +140,12 @@ func TestMapEach(t *testing.T) {
}
func TestMapMap(t *testing.T) {
m := New()
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
mappedMap := m.Map(func(key1 interface{}, value1 interface{}) (key2 interface{}, value2 interface{}) {
return key1, value1.(int) * value1.(int)
mappedMap := m.Map(func(key1 string, value1 int) (key2 string, value2 int) {
return key1, value1 * value1
})
if actualValue, _ := mappedMap.Get("c"); actualValue != 9 {
t.Errorf("Got %v expected %v", actualValue, "mapped: c")
@ -190,12 +162,12 @@ func TestMapMap(t *testing.T) {
}
func TestMapSelect(t *testing.T) {
m := New()
m := New[string, int]()
m.Put("c", 3)
m.Put("b", 1)
m.Put("a", 2)
selectedMap := m.Select(func(key interface{}, value interface{}) bool {
return key.(string) >= "a" && key.(string) <= "b"
selectedMap := m.Select(func(key string, value int) bool {
return key >= "a" && key <= "b"
})
if actualValue, _ := selectedMap.Get("b"); actualValue != 1 {
t.Errorf("Got %v expected %v", actualValue, "value: a")
@ -209,18 +181,18 @@ func TestMapSelect(t *testing.T) {
}
func TestMapAny(t *testing.T) {
m := New()
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
any := m.Any(func(key interface{}, value interface{}) bool {
return value.(int) == 3
any := m.Any(func(key string, value int) bool {
return value == 3
})
if any != true {
t.Errorf("Got %v expected %v", any, true)
}
any = m.Any(func(key interface{}, value interface{}) bool {
return value.(int) == 4
any = m.Any(func(key string, value int) bool {
return value == 4
})
if any != false {
t.Errorf("Got %v expected %v", any, false)
@ -228,18 +200,18 @@ func TestMapAny(t *testing.T) {
}
func TestMapAll(t *testing.T) {
m := New()
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
all := m.All(func(key interface{}, value interface{}) bool {
return key.(string) >= "a" && key.(string) <= "c"
all := m.All(func(key string, value int) bool {
return key >= "a" && key <= "c"
})
if all != true {
t.Errorf("Got %v expected %v", all, true)
}
all = m.All(func(key interface{}, value interface{}) bool {
return key.(string) >= "a" && key.(string) <= "b"
all = m.All(func(key string, value int) bool {
return key >= "a" && key <= "b"
})
if all != false {
t.Errorf("Got %v expected %v", all, false)
@ -247,38 +219,38 @@ func TestMapAll(t *testing.T) {
}
func TestMapFind(t *testing.T) {
m := New()
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
foundKey, foundValue := m.Find(func(key interface{}, value interface{}) bool {
return key.(string) == "c"
foundKey, foundValue := m.Find(func(key string, value int) bool {
return key == "c"
})
if foundKey != "c" || foundValue != 3 {
t.Errorf("Got %v -> %v expected %v -> %v", foundKey, foundValue, "c", 3)
}
foundKey, foundValue = m.Find(func(key interface{}, value interface{}) bool {
return key.(string) == "x"
foundKey, foundValue = m.Find(func(key string, value int) bool {
return key == "x"
})
if foundKey != nil || foundValue != nil {
t.Errorf("Got %v at %v expected %v at %v", foundValue, foundKey, nil, nil)
if foundKey != "" || foundValue != 0 {
t.Errorf("Got %v at %v expected %v at %v", foundValue, foundKey, "", 0)
}
}
func TestMapChaining(t *testing.T) {
m := New()
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
chainedMap := m.Select(func(key interface{}, value interface{}) bool {
return value.(int) > 1
}).Map(func(key interface{}, value interface{}) (interface{}, interface{}) {
return key.(string) + key.(string), value.(int) * value.(int)
chainedMap := m.Select(func(key string, value int) bool {
return value > 1
}).Map(func(key string, value int) (string, int) {
return key + key, value * value
})
if actualValue := chainedMap.Size(); actualValue != 2 {
t.Errorf("Got %v expected %v", actualValue, 2)
}
if actualValue, found := chainedMap.Get("aa"); actualValue != nil || found {
if actualValue, found := chainedMap.Get("aa"); actualValue != 0 || found {
t.Errorf("Got %v expected %v", actualValue, nil)
}
if actualValue, found := chainedMap.Get("bb"); actualValue != 4 || !found {
@ -290,7 +262,7 @@ func TestMapChaining(t *testing.T) {
}
func TestMapIteratorNextOnEmpty(t *testing.T) {
m := New()
m := New[string, int]()
it := m.Iterator()
it = m.Iterator()
for it.Next() {
@ -299,7 +271,7 @@ func TestMapIteratorNextOnEmpty(t *testing.T) {
}
func TestMapIteratorPrevOnEmpty(t *testing.T) {
m := New()
m := New[string, int]()
it := m.Iterator()
it = m.Iterator()
for it.Prev() {
@ -308,7 +280,7 @@ func TestMapIteratorPrevOnEmpty(t *testing.T) {
}
func TestMapIteratorNext(t *testing.T) {
m := New()
m := New[string, int]()
m.Put("c", 1)
m.Put("a", 2)
m.Put("b", 3)
@ -345,7 +317,7 @@ func TestMapIteratorNext(t *testing.T) {
}
func TestMapIteratorPrev(t *testing.T) {
m := New()
m := New[string, int]()
m.Put("c", 1)
m.Put("a", 2)
m.Put("b", 3)
@ -384,7 +356,7 @@ func TestMapIteratorPrev(t *testing.T) {
}
func TestMapIteratorBegin(t *testing.T) {
m := New()
m := New[int, string]()
it := m.Iterator()
it.Begin()
m.Put(3, "c")
@ -399,8 +371,8 @@ func TestMapIteratorBegin(t *testing.T) {
}
}
func TestMapTreeIteratorEnd(t *testing.T) {
m := New()
func TestMapIteratorEnd(t *testing.T) {
m := New[int, string]()
it := m.Iterator()
m.Put(3, "c")
m.Put(1, "a")
@ -413,7 +385,7 @@ func TestMapTreeIteratorEnd(t *testing.T) {
}
func TestMapIteratorFirst(t *testing.T) {
m := New()
m := New[int, string]()
m.Put(3, "c")
m.Put(1, "a")
m.Put(2, "b")
@ -427,7 +399,7 @@ func TestMapIteratorFirst(t *testing.T) {
}
func TestMapIteratorLast(t *testing.T) {
m := New()
m := New[int, string]()
m.Put(3, "c")
m.Put(1, "a")
m.Put(2, "b")
@ -440,56 +412,168 @@ func TestMapIteratorLast(t *testing.T) {
}
}
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()
original := New[string, string]()
original.Put("d", "4")
original.Put("e", "5")
original.Put("c", "3")
original.Put("b", "2")
original.Put("a", "1")
assertSerialization(original, "A", t)
serialized, err := original.ToJSON()
if err != nil {
t.Errorf("Got error %v", err)
}
assertSerialization(original, "B", t)
deserialized := New()
deserialized := New[string, string]()
err = deserialized.FromJSON(serialized)
if err != nil {
t.Errorf("Got error %v", err)
}
assertSerialization(deserialized, "C", t)
if original.Size() != deserialized.Size() {
t.Errorf("Got map of size %d, expected %d", original.Size(), deserialized.Size())
}
original.Each(func(key string, expected string) {
actual, ok := deserialized.Get(key)
if !ok || actual != expected {
t.Errorf("Did not find expected value %v for key %v in deserialied map (got %v)", expected, key, actual)
}
})
}
}
//noinspection GoBoolExpressions
func assertSerialization(m *Map, txt string, t *testing.T) {
if actualValue := m.Keys(); false ||
actualValue[0].(string) != "d" ||
actualValue[1].(string) != "e" ||
actualValue[2].(string) != "c" ||
actualValue[3].(string) != "b" ||
actualValue[4].(string) != "a" {
t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[d,e,c,b,a]")
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)
}
if actualValue := m.Values(); false ||
actualValue[0].(string) != "4" ||
actualValue[1].(string) != "5" ||
actualValue[2].(string) != "3" ||
actualValue[3].(string) != "2" ||
actualValue[4].(string) != "1" {
t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[4,5,3,2,1]")
err = json.Unmarshal([]byte(`{"a":1,"b":2}`), &m)
if err != nil {
t.Errorf("Got error %v", err)
}
if actualValue, expectedValue := m.Size(), 5; actualValue != expectedValue {
t.Errorf("[%s] Got %v expected %v", txt, actualValue, expectedValue)
}
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, size int) {
func benchmarkGet(b *testing.B, m *Map[int, int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
m.Get(n)
@ -497,15 +581,15 @@ func benchmarkGet(b *testing.B, m *Map, size int) {
}
}
func benchmarkPut(b *testing.B, m *Map, size int) {
func benchmarkPut(b *testing.B, m *Map[int, int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
}
}
func benchmarkRemove(b *testing.B, m *Map, size int) {
func benchmarkRemove(b *testing.B, m *Map[int, int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
m.Remove(n)
@ -516,9 +600,9 @@ func benchmarkRemove(b *testing.B, m *Map, size int) {
func BenchmarkTreeMapGet100(b *testing.B) {
b.StopTimer()
size := 100
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkGet(b, m, size)
@ -527,9 +611,9 @@ func BenchmarkTreeMapGet100(b *testing.B) {
func BenchmarkTreeMapGet1000(b *testing.B) {
b.StopTimer()
size := 1000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkGet(b, m, size)
@ -538,9 +622,9 @@ func BenchmarkTreeMapGet1000(b *testing.B) {
func BenchmarkTreeMapGet10000(b *testing.B) {
b.StopTimer()
size := 10000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkGet(b, m, size)
@ -549,9 +633,9 @@ func BenchmarkTreeMapGet10000(b *testing.B) {
func BenchmarkTreeMapGet100000(b *testing.B) {
b.StopTimer()
size := 100000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkGet(b, m, size)
@ -560,7 +644,7 @@ func BenchmarkTreeMapGet100000(b *testing.B) {
func BenchmarkTreeMapPut100(b *testing.B) {
b.StopTimer()
size := 100
m := New()
m := New[int, int]()
b.StartTimer()
benchmarkPut(b, m, size)
}
@ -568,9 +652,9 @@ func BenchmarkTreeMapPut100(b *testing.B) {
func BenchmarkTreeMapPut1000(b *testing.B) {
b.StopTimer()
size := 1000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkPut(b, m, size)
@ -579,9 +663,9 @@ func BenchmarkTreeMapPut1000(b *testing.B) {
func BenchmarkTreeMapPut10000(b *testing.B) {
b.StopTimer()
size := 10000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkPut(b, m, size)
@ -590,9 +674,9 @@ func BenchmarkTreeMapPut10000(b *testing.B) {
func BenchmarkTreeMapPut100000(b *testing.B) {
b.StopTimer()
size := 100000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkPut(b, m, size)
@ -601,9 +685,9 @@ func BenchmarkTreeMapPut100000(b *testing.B) {
func BenchmarkTreeMapRemove100(b *testing.B) {
b.StopTimer()
size := 100
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkRemove(b, m, size)
@ -612,9 +696,9 @@ func BenchmarkTreeMapRemove100(b *testing.B) {
func BenchmarkTreeMapRemove1000(b *testing.B) {
b.StopTimer()
size := 1000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkRemove(b, m, size)
@ -623,9 +707,9 @@ func BenchmarkTreeMapRemove1000(b *testing.B) {
func BenchmarkTreeMapRemove10000(b *testing.B) {
b.StopTimer()
size := 10000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkRemove(b, m, size)
@ -634,9 +718,9 @@ func BenchmarkTreeMapRemove10000(b *testing.B) {
func BenchmarkTreeMapRemove100000(b *testing.B) {
b.StopTimer()
size := 100000
m := New()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
m.Put(n, n)
}
b.StartTimer()
benchmarkRemove(b, m, size)

@ -6,18 +6,19 @@ package linkedhashmap
import (
"bytes"
"cmp"
"encoding/json"
"github.com/emirpasic/gods/containers"
"github.com/emirpasic/gods/utils"
"slices"
"github.com/emirpasic/gods/v2/containers"
)
func assertSerializationImplementation() {
var _ containers.JSONSerializer = (*Map)(nil)
var _ containers.JSONDeserializer = (*Map)(nil)
}
// 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) ToJSON() ([]byte, error) {
func (m *Map[K, V]) ToJSON() ([]byte, error) {
var b []byte
buf := bytes.NewBuffer(b)
@ -55,7 +56,7 @@ func (m *Map) ToJSON() ([]byte, error) {
}
// FromJSON populates map from the input JSON representation.
//func (m *Map) FromJSON(data []byte) error {
//func (m *Map[K, V]) FromJSON(data []byte) error {
// elements := make(map[string]interface{})
// err := json.Unmarshal(data, &elements)
// if err == nil {
@ -68,36 +69,42 @@ func (m *Map) ToJSON() ([]byte, error) {
//}
// FromJSON populates map from the input JSON representation.
func (m *Map) FromJSON(data []byte) error {
elements := make(map[string]interface{})
func (m *Map[K, V]) FromJSON(data []byte) error {
elements := make(map[K]V)
err := json.Unmarshal(data, &elements)
if err != nil {
return err
}
index := make(map[string]int)
var keys []interface{}
index := make(map[K]int)
var keys []K
for key := range elements {
keys = append(keys, key)
esc, _ := json.Marshal(key)
index[key] = bytes.Index(data, esc)
}
byIndex := func(a, b interface{}) int {
key1 := a.(string)
key2 := b.(string)
index1 := index[key1]
index2 := index[key2]
return index1 - index2
byIndex := func(key1, key2 K) int {
return cmp.Compare(index[key1], index[key2])
}
utils.Sort(keys, byIndex)
slices.SortFunc(keys, byIndex)
m.Clear()
for _, key := range keys {
m.Put(key, elements[key.(string)])
m.Put(key, elements[key])
}
return nil
}
// UnmarshalJSON @implements json.Unmarshaler
func (m *Map[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()
}

@ -15,25 +15,26 @@
// Reference: https://en.wikipedia.org/wiki/Associative_array
package maps
import "github.com/emirpasic/gods/containers"
import "github.com/emirpasic/gods/v2/containers"
// Map interface that all maps implement
type Map interface {
Put(key interface{}, value interface{})
Get(key interface{}) (value interface{}, found bool)
Remove(key interface{})
Keys() []interface{}
type Map[K comparable, V any] interface {
Put(key K, value V)
Get(key K) (value V, found bool)
Remove(key K)
Keys() []K
containers.Container
containers.Container[V]
// Empty() bool
// Size() int
// Clear()
// Values() []interface{}
// String() string
}
// BidiMap interface that all bidirectional maps implement (extends the Map interface)
type BidiMap interface {
GetKey(value interface{}) (key interface{}, found bool)
type BidiMap[K comparable, V comparable] interface {
GetKey(value V) (key K, found bool)
Map
Map[K, V]
}

@ -4,14 +4,13 @@
package treebidimap
import "github.com/emirpasic/gods/containers"
import "github.com/emirpasic/gods/v2/containers"
func assertEnumerableImplementation() {
var _ containers.EnumerableWithKey = (*Map)(nil)
}
// 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) Each(f func(key interface{}, value interface{})) {
func (m *Map[K, V]) Each(f func(key K, value V)) {
iterator := m.Iterator()
for iterator.Next() {
f(iterator.Key(), iterator.Value())
@ -20,8 +19,8 @@ func (m *Map) Each(f func(key interface{}, value interface{})) {
// Map invokes the given function once for each element and returns a container
// containing the values returned by the given function as key/value pairs.
func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) *Map {
newMap := NewWith(m.keyComparator, m.valueComparator)
func (m *Map[K, V]) Map(f func(key1 K, value1 V) (K, V)) *Map[K, V] {
newMap := NewWith[K, V](m.forwardMap.Comparator, m.inverseMap.Comparator)
iterator := m.Iterator()
for iterator.Next() {
key2, value2 := f(iterator.Key(), iterator.Value())
@ -31,8 +30,8 @@ func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, int
}
// Select returns a new container containing all elements for which the given function returns a true value.
func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map {
newMap := NewWith(m.keyComparator, m.valueComparator)
func (m *Map[K, V]) Select(f func(key K, value V) bool) *Map[K, V] {
newMap := NewWith[K, V](m.forwardMap.Comparator, m.inverseMap.Comparator)
iterator := m.Iterator()
for iterator.Next() {
if f(iterator.Key(), iterator.Value()) {
@ -44,7 +43,7 @@ func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map {
// Any passes each element of the container to the given function and
// returns true if the function ever returns true for any element.
func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool {
func (m *Map[K, V]) Any(f func(key K, value V) bool) bool {
iterator := m.Iterator()
for iterator.Next() {
if f(iterator.Key(), iterator.Value()) {
@ -56,7 +55,7 @@ func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool {
// All passes each element of the container to the given function and
// returns true if the function returns true for all elements.
func (m *Map) All(f func(key interface{}, value interface{}) bool) bool {
func (m *Map[K, V]) All(f func(key K, value V) bool) bool {
iterator := m.Iterator()
for iterator.Next() {
if !f(iterator.Key(), iterator.Value()) {
@ -69,12 +68,12 @@ func (m *Map) All(f func(key interface{}, value interface{}) bool) bool {
// Find passes each element of the container to the given function and returns
// the first (key,value) for which the function is true or nil,nil otherwise if no element
// matches the criteria.
func (m *Map) Find(f func(key interface{}, value interface{}) bool) (interface{}, interface{}) {
func (m *Map[K, V]) Find(f func(key K, value V) bool) (k K, v V) {
iterator := m.Iterator()
for iterator.Next() {
if f(iterator.Key(), iterator.Value()) {
return iterator.Key(), iterator.Value()
}
}
return nil, nil
return k, v
}

@ -5,73 +5,100 @@
package treebidimap
import (
"github.com/emirpasic/gods/containers"
rbt "github.com/emirpasic/gods/trees/redblacktree"
"github.com/emirpasic/gods/v2/containers"
rbt "github.com/emirpasic/gods/v2/trees/redblacktree"
)
func assertIteratorImplementation() {
var _ containers.ReverseIteratorWithKey = (*Iterator)(nil)
}
// Assert Iterator implementation
var _ containers.ReverseIteratorWithKey[string, int] = (*Iterator[string, int])(nil)
// Iterator holding the iterator's state
type Iterator struct {
iterator rbt.Iterator
type Iterator[K comparable, V any] struct {
iterator *rbt.Iterator[K, V]
}
// Iterator returns a stateful iterator whose elements are key/value pairs.
func (m *Map) Iterator() Iterator {
return Iterator{iterator: m.forwardMap.Iterator()}
func (m *Map[K, V]) Iterator() *Iterator[K, V] {
return &Iterator[K, V]{iterator: m.forwardMap.Iterator()}
}
// Next moves the iterator to the next element and returns true if there was a next element in the container.
// If Next() returns true, then next element's key and value can be retrieved by Key() and Value().
// If Next() was called for the first time, then it will point the iterator to the first element if it exists.
// Modifies the state of the iterator.
func (iterator *Iterator) Next() bool {
func (iterator *Iterator[K, V]) Next() bool {
return iterator.iterator.Next()
}
// Prev moves the iterator to the previous element and returns true if there was a previous element in the container.
// If Prev() returns true, then previous element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator.
func (iterator *Iterator) Prev() bool {
func (iterator *Iterator[K, V]) Prev() bool {
return iterator.iterator.Prev()
}
// Value returns the current element's value.
// Does not modify the state of the iterator.
func (iterator *Iterator) Value() interface{} {
return iterator.iterator.Value().(*data).value
func (iterator *Iterator[K, V]) Value() V {
return iterator.iterator.Value()
}
// Key returns the current element's key.
// Does not modify the state of the iterator.
func (iterator *Iterator) Key() interface{} {
func (iterator *Iterator[K, V]) Key() K {
return iterator.iterator.Key()
}
// Begin resets the iterator to its initial state (one-before-first)
// Call Next() to fetch the first element if any.
func (iterator *Iterator) Begin() {
func (iterator *Iterator[K, V]) Begin() {
iterator.iterator.Begin()
}
// End moves the iterator past the last element (one-past-the-end).
// Call Prev() to fetch the last element if any.
func (iterator *Iterator) End() {
func (iterator *Iterator[K, V]) End() {
iterator.iterator.End()
}
// First moves the iterator to the first element and returns true if there was a first element in the container.
// If First() returns true, then first element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator
func (iterator *Iterator) First() bool {
func (iterator *Iterator[K, V]) First() bool {
return iterator.iterator.First()
}
// Last moves the iterator to the last element and returns true if there was a last element in the container.
// If Last() returns true, then last element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator.
func (iterator *Iterator) Last() bool {
func (iterator *Iterator[K, V]) Last() bool {
return iterator.iterator.Last()
}
// 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
}

@ -6,34 +6,41 @@ package treebidimap
import (
"encoding/json"
"github.com/emirpasic/gods/containers"
"github.com/emirpasic/gods/utils"
"github.com/emirpasic/gods/v2/containers"
)
func assertSerializationImplementation() {
var _ containers.JSONSerializer = (*Map)(nil)
var _ containers.JSONDeserializer = (*Map)(nil)
}
// 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) ToJSON() ([]byte, error) {
elements := make(map[string]interface{})
it := m.Iterator()
for it.Next() {
elements[utils.ToString(it.Key())] = it.Value()
}
return json.Marshal(&elements)
func (m *Map[K, V]) ToJSON() ([]byte, error) {
return m.forwardMap.ToJSON()
}
// FromJSON populates the map from the input JSON representation.
func (m *Map) FromJSON(data []byte) error {
elements := make(map[string]interface{})
func (m *Map[K, V]) FromJSON(data []byte) error {
var elements map[K]V
err := json.Unmarshal(data, &elements)
if err == nil {
m.Clear()
for key, value := range elements {
m.Put(key, value)
}
if err != nil {
return err
}
m.Clear()
for key, value := range elements {
m.Put(key, value)
}
return err
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()
}

@ -18,117 +18,101 @@
package treebidimap
import (
"cmp"
"fmt"
"github.com/emirpasic/gods/maps"
"github.com/emirpasic/gods/trees/redblacktree"
"github.com/emirpasic/gods/utils"
"strings"
"github.com/emirpasic/gods/v2/maps"
"github.com/emirpasic/gods/v2/trees/redblacktree"
"github.com/emirpasic/gods/v2/utils"
)
func assertMapImplementation() {
var _ maps.BidiMap = (*Map)(nil)
}
// Assert Map implementation
var _ maps.BidiMap[string, int] = (*Map[string, int])(nil)
// Map holds the elements in two red-black trees.
type Map struct {
forwardMap redblacktree.Tree
inverseMap redblacktree.Tree
keyComparator utils.Comparator
valueComparator utils.Comparator
type Map[K, V comparable] struct {
forwardMap redblacktree.Tree[K, V]
inverseMap redblacktree.Tree[V, K]
}
type data struct {
key interface{}
value interface{}
// New instantiates a bidirectional map.
func New[K, V cmp.Ordered]() *Map[K, V] {
return &Map[K, V]{
forwardMap: *redblacktree.New[K, V](),
inverseMap: *redblacktree.New[V, K](),
}
}
// NewWith instantiates a bidirectional map.
func NewWith(keyComparator utils.Comparator, valueComparator utils.Comparator) *Map {
return &Map{
forwardMap: *redblacktree.NewWith(keyComparator),
inverseMap: *redblacktree.NewWith(valueComparator),
keyComparator: keyComparator,
valueComparator: valueComparator,
func NewWith[K, V comparable](keyComparator utils.Comparator[K], valueComparator utils.Comparator[V]) *Map[K, V] {
return &Map[K, V]{
forwardMap: *redblacktree.NewWith[K, V](keyComparator),
inverseMap: *redblacktree.NewWith[V, K](valueComparator),
}
}
// NewWithIntComparators instantiates a bidirectional map with the IntComparator for key and value, i.e. keys and values are of type int.
func NewWithIntComparators() *Map {
return NewWith(utils.IntComparator, utils.IntComparator)
}
// NewWithStringComparators instantiates a bidirectional map with the StringComparator for key and value, i.e. keys and values are of type string.
func NewWithStringComparators() *Map {
return NewWith(utils.StringComparator, utils.StringComparator)
}
// Put inserts element into the map.
func (m *Map) Put(key interface{}, value interface{}) {
if d, ok := m.forwardMap.Get(key); ok {
m.inverseMap.Remove(d.(*data).value)
func (m *Map[K, V]) Put(key K, value V) {
if v, ok := m.forwardMap.Get(key); ok {
m.inverseMap.Remove(v)
}
if d, ok := m.inverseMap.Get(value); ok {
m.forwardMap.Remove(d.(*data).key)
if k, ok := m.inverseMap.Get(value); ok {
m.forwardMap.Remove(k)
}
d := &data{key: key, value: value}
m.forwardMap.Put(key, d)
m.inverseMap.Put(value, d)
m.forwardMap.Put(key, value)
m.inverseMap.Put(value, key)
}
// Get searches the element in the map by key and returns its value or nil if key is not found in map.
// Second return parameter is true if key was found, otherwise false.
func (m *Map) Get(key interface{}) (value interface{}, found bool) {
if d, ok := m.forwardMap.Get(key); ok {
return d.(*data).value, true
}
return nil, false
func (m *Map[K, V]) Get(key K) (value V, found bool) {
return m.forwardMap.Get(key)
}
// GetKey searches the element in the map by value and returns its key or nil if value is not found in map.
// Second return parameter is true if value was found, otherwise false.
func (m *Map) GetKey(value interface{}) (key interface{}, found bool) {
if d, ok := m.inverseMap.Get(value); ok {
return d.(*data).key, true
}
return nil, false
func (m *Map[K, V]) GetKey(value V) (key K, found bool) {
return m.inverseMap.Get(value)
}
// Remove removes the element from the map by key.
func (m *Map) Remove(key interface{}) {
if d, found := m.forwardMap.Get(key); found {
func (m *Map[K, V]) Remove(key K) {
if v, found := m.forwardMap.Get(key); found {
m.forwardMap.Remove(key)
m.inverseMap.Remove(d.(*data).value)
m.inverseMap.Remove(v)
}
}
// Empty returns true if map does not contain any elements
func (m *Map) Empty() bool {
func (m *Map[K, V]) Empty() bool {
return m.Size() == 0
}
// Size returns number of elements in the map.
func (m *Map) Size() int {
func (m *Map[K, V]) Size() int {
return m.forwardMap.Size()
}
// Keys returns all keys (ordered).
func (m *Map) Keys() []interface{} {
func (m *Map[K, V]) Keys() []K {
return m.forwardMap.Keys()
}
// Values returns all values (ordered).
func (m *Map) Values() []interface{} {
func (m *Map[K, V]) Values() []V {
return m.inverseMap.Keys()
}
// Clear removes all elements from the map.
func (m *Map) Clear() {
func (m *Map[K, V]) Clear() {
m.forwardMap.Clear()
m.inverseMap.Clear()
}
// String returns a string representation of container
func (m *Map) String() string {
func (m *Map[K, V]) String() string {
str := "TreeBidiMap\nmap["
it := m.Iterator()
for it.Next() {

@ -5,13 +5,15 @@
package treebidimap
import (
"fmt"
"github.com/emirpasic/gods/utils"
"encoding/json"
"strings"
"testing"
"github.com/emirpasic/gods/v2/testutils"
)
func TestMapPut(t *testing.T) {
m := NewWith(utils.IntComparator, utils.StringComparator)
m := New[int, string]()
m.Put(5, "e")
m.Put(6, "f")
m.Put(7, "g")
@ -24,12 +26,8 @@ func TestMapPut(t *testing.T) {
if actualValue := m.Size(); actualValue != 7 {
t.Errorf("Got %v expected %v", actualValue, 7)
}
if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "e", "f", "g"}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4, 5, 6, 7})
testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d", "e", "f", "g"})
// key,expectedValue,expectedFound
tests1 := [][]interface{}{
@ -40,12 +38,12 @@ func TestMapPut(t *testing.T) {
{5, "e", true},
{6, "f", true},
{7, "g", true},
{8, nil, false},
{8, "", false},
}
for _, test := range tests1 {
// retrievals
actualValue, actualFound := m.Get(test[0])
actualValue, actualFound := m.Get(test[0].(int))
if actualValue != test[1] || actualFound != test[2] {
t.Errorf("Got %v expected %v", actualValue, test[1])
}
@ -53,7 +51,7 @@ func TestMapPut(t *testing.T) {
}
func TestMapRemove(t *testing.T) {
m := NewWith(utils.IntComparator, utils.StringComparator)
m := New[int, string]()
m.Put(5, "e")
m.Put(6, "f")
m.Put(7, "g")
@ -69,13 +67,9 @@ func TestMapRemove(t *testing.T) {
m.Remove(8)
m.Remove(5)
if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4})
testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d"})
if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d"}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue := m.Size(); actualValue != 4 {
t.Errorf("Got %v expected %v", actualValue, 4)
}
@ -85,14 +79,14 @@ func TestMapRemove(t *testing.T) {
{2, "b", true},
{3, "c", true},
{4, "d", true},
{5, nil, false},
{6, nil, false},
{7, nil, false},
{8, nil, false},
{5, "", false},
{6, "", false},
{7, "", false},
{8, "", false},
}
for _, test := range tests2 {
actualValue, actualFound := m.Get(test[0])
actualValue, actualFound := m.Get(test[0].(int))
if actualValue != test[1] || actualFound != test[2] {
t.Errorf("Got %v expected %v", actualValue, test[1])
}
@ -105,12 +99,8 @@ func TestMapRemove(t *testing.T) {
m.Remove(2)
m.Remove(2)
if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
testutils.SameElements(t, m.Keys(), nil)
testutils.SameElements(t, m.Values(), nil)
if actualValue := m.Size(); actualValue != 0 {
t.Errorf("Got %v expected %v", actualValue, 0)
}
@ -120,7 +110,7 @@ func TestMapRemove(t *testing.T) {
}
func TestMapGetKey(t *testing.T) {
m := NewWith(utils.IntComparator, utils.StringComparator)
m := New[int, string]()
m.Put(5, "e")
m.Put(6, "f")
m.Put(7, "g")
@ -139,12 +129,12 @@ func TestMapGetKey(t *testing.T) {
{5, "e", true},
{6, "f", true},
{7, "g", true},
{nil, "x", false},
{0, "x", false},
}
for _, test := range tests1 {
// retrievals
actualValue, actualFound := m.GetKey(test[1])
actualValue, actualFound := m.GetKey(test[1].(string))
if actualValue != test[0] || actualFound != test[2] {
t.Errorf("Got %v expected %v", actualValue, test[0])
}
@ -171,12 +161,12 @@ func sameElements(a []interface{}, b []interface{}) bool {
}
func TestMapEach(t *testing.T) {
m := NewWith(utils.StringComparator, utils.IntComparator)
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
count := 0
m.Each(func(key interface{}, value interface{}) {
m.Each(func(key string, value int) {
count++
if actualValue, expectedValue := count, value; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
@ -201,12 +191,12 @@ func TestMapEach(t *testing.T) {
}
func TestMapMap(t *testing.T) {
m := NewWith(utils.StringComparator, utils.IntComparator)
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
mappedMap := m.Map(func(key1 interface{}, value1 interface{}) (key2 interface{}, value2 interface{}) {
return key1, value1.(int) * value1.(int)
mappedMap := m.Map(func(key1 string, value1 int) (key2 string, value2 int) {
return key1, value1 * value1
})
if actualValue, _ := mappedMap.Get("a"); actualValue != 1 {
t.Errorf("Got %v expected %v", actualValue, "mapped: a")
@ -223,12 +213,12 @@ func TestMapMap(t *testing.T) {
}
func TestMapSelect(t *testing.T) {
m := NewWith(utils.StringComparator, utils.IntComparator)
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
selectedMap := m.Select(func(key interface{}, value interface{}) bool {
return key.(string) >= "a" && key.(string) <= "b"
selectedMap := m.Select(func(key string, value int) bool {
return key >= "a" && key <= "b"
})
if actualValue, _ := selectedMap.Get("a"); actualValue != 1 {
t.Errorf("Got %v expected %v", actualValue, "value: a")
@ -242,18 +232,18 @@ func TestMapSelect(t *testing.T) {
}
func TestMapAny(t *testing.T) {
m := NewWith(utils.StringComparator, utils.IntComparator)
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
any := m.Any(func(key interface{}, value interface{}) bool {
return value.(int) == 3
any := m.Any(func(key string, value int) bool {
return value == 3
})
if any != true {
t.Errorf("Got %v expected %v", any, true)
}
any = m.Any(func(key interface{}, value interface{}) bool {
return value.(int) == 4
any = m.Any(func(key string, value int) bool {
return value == 4
})
if any != false {
t.Errorf("Got %v expected %v", any, false)
@ -261,18 +251,18 @@ func TestMapAny(t *testing.T) {
}
func TestMapAll(t *testing.T) {
m := NewWith(utils.StringComparator, utils.IntComparator)
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
all := m.All(func(key interface{}, value interface{}) bool {
return key.(string) >= "a" && key.(string) <= "c"
all := m.All(func(key string, value int) bool {
return key >= "a" && key <= "c"
})
if all != true {
t.Errorf("Got %v expected %v", all, true)
}
all = m.All(func(key interface{}, value interface{}) bool {
return key.(string) >= "a" && key.(string) <= "b"
all = m.All(func(key string, value int) bool {
return key >= "a" && key <= "b"
})
if all != false {
t.Errorf("Got %v expected %v", all, false)
@ -280,38 +270,38 @@ func TestMapAll(t *testing.T) {
}
func TestMapFind(t *testing.T) {
m := NewWith(utils.StringComparator, utils.IntComparator)
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
foundKey, foundValue := m.Find(func(key interface{}, value interface{}) bool {
return key.(string) == "c"
foundKey, foundValue := m.Find(func(key string, value int) bool {
return key == "c"
})
if foundKey != "c" || foundValue != 3 {
t.Errorf("Got %v -> %v expected %v -> %v", foundKey, foundValue, "c", 3)
}
foundKey, foundValue = m.Find(func(key interface{}, value interface{}) bool {
return key.(string) == "x"
foundKey, foundValue = m.Find(func(key string, value int) bool {
return key == "x"
})
if foundKey != nil || foundValue != nil {
if foundKey != "" || foundValue != 0 {
t.Errorf("Got %v at %v expected %v at %v", foundValue, foundKey, nil, nil)
}
}
func TestMapChaining(t *testing.T) {
m := NewWith(utils.StringComparator, utils.IntComparator)
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
chainedMap := m.Select(func(key interface{}, value interface{}) bool {
return value.(int) > 1
}).Map(func(key interface{}, value interface{}) (interface{}, interface{}) {
return key.(string) + key.(string), value.(int) * value.(int)
chainedMap := m.Select(func(key string, value int) bool {
return value > 1
}).Map(func(key string, value int) (string, int) {
return key + key, value * value
})
if actualValue := chainedMap.Size(); actualValue != 2 {
t.Errorf("Got %v expected %v", actualValue, 2)
}
if actualValue, found := chainedMap.Get("aa"); actualValue != nil || found {
if actualValue, found := chainedMap.Get("aa"); actualValue != 0 || found {
t.Errorf("Got %v expected %v", actualValue, nil)
}
if actualValue, found := chainedMap.Get("bb"); actualValue != 4 || !found {
@ -323,7 +313,7 @@ func TestMapChaining(t *testing.T) {
}
func TestMapIteratorNextOnEmpty(t *testing.T) {
m := NewWithStringComparators()
m := New[string, string]()
it := m.Iterator()
it = m.Iterator()
for it.Next() {
@ -332,7 +322,7 @@ func TestMapIteratorNextOnEmpty(t *testing.T) {
}
func TestMapIteratorPrevOnEmpty(t *testing.T) {
m := NewWithStringComparators()
m := New[string, string]()
it := m.Iterator()
it = m.Iterator()
for it.Prev() {
@ -341,7 +331,7 @@ func TestMapIteratorPrevOnEmpty(t *testing.T) {
}
func TestMapIteratorNext(t *testing.T) {
m := NewWith(utils.StringComparator, utils.IntComparator)
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
@ -378,7 +368,7 @@ func TestMapIteratorNext(t *testing.T) {
}
func TestMapIteratorPrev(t *testing.T) {
m := NewWith(utils.StringComparator, utils.IntComparator)
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
@ -417,7 +407,7 @@ func TestMapIteratorPrev(t *testing.T) {
}
func TestMapIteratorBegin(t *testing.T) {
m := NewWith(utils.IntComparator, utils.StringComparator)
m := New[int, string]()
it := m.Iterator()
it.Begin()
m.Put(3, "c")
@ -432,8 +422,8 @@ func TestMapIteratorBegin(t *testing.T) {
}
}
func TestMapTreeIteratorEnd(t *testing.T) {
m := NewWith(utils.IntComparator, utils.StringComparator)
func TestMapIteratorEnd(t *testing.T) {
m := New[int, string]()
it := m.Iterator()
m.Put(3, "c")
m.Put(1, "a")
@ -446,7 +436,7 @@ func TestMapTreeIteratorEnd(t *testing.T) {
}
func TestMapIteratorFirst(t *testing.T) {
m := NewWith(utils.IntComparator, utils.StringComparator)
m := New[int, string]()
m.Put(3, "c")
m.Put(1, "a")
m.Put(2, "b")
@ -460,7 +450,7 @@ func TestMapIteratorFirst(t *testing.T) {
}
func TestMapIteratorLast(t *testing.T) {
m := NewWith(utils.IntComparator, utils.StringComparator)
m := New[int, string]()
m.Put(3, "c")
m.Put(1, "a")
m.Put(2, "b")
@ -473,56 +463,168 @@ func TestMapIteratorLast(t *testing.T) {
}
}
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 := NewWith(utils.StringComparator, utils.StringComparator)
original := New[string, string]()
original.Put("d", "4")
original.Put("e", "5")
original.Put("c", "3")
original.Put("b", "2")
original.Put("a", "1")
assertSerialization(original, "A", t)
serialized, err := original.ToJSON()
if err != nil {
t.Errorf("Got error %v", err)
}
assertSerialization(original, "B", t)
deserialized := NewWith(utils.StringComparator, utils.StringComparator)
deserialized := New[string, string]()
err = deserialized.FromJSON(serialized)
if err != nil {
t.Errorf("Got error %v", err)
}
assertSerialization(deserialized, "C", t)
if original.Size() != deserialized.Size() {
t.Errorf("Got map of size %d, expected %d", original.Size(), deserialized.Size())
}
original.Each(func(key string, expected string) {
actual, ok := deserialized.Get(key)
if !ok || actual != expected {
t.Errorf("Did not find expected value %v for key %v in deserialied map (got %q)", expected, key, actual)
}
})
}
}
//noinspection GoBoolExpressions
func assertSerialization(m *Map, txt string, t *testing.T) {
if actualValue := m.Keys(); false ||
actualValue[0].(string) != "a" ||
actualValue[1].(string) != "b" ||
actualValue[2].(string) != "c" ||
actualValue[3].(string) != "d" ||
actualValue[4].(string) != "e" {
t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[a,b,c,d,e]")
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)
}
if actualValue := m.Values(); false ||
actualValue[0].(string) != "1" ||
actualValue[1].(string) != "2" ||
actualValue[2].(string) != "3" ||
actualValue[3].(string) != "4" ||
actualValue[4].(string) != "5" {
t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[1,2,3,4,5]")
err = json.Unmarshal([]byte(`{"a":1,"b":2}`), &m)
if err != nil {
t.Errorf("Got error %v", err)
}
if actualValue, expectedValue := m.Size(), 5; actualValue != expectedValue {
t.Errorf("[%s] Got %v expected %v", txt, actualValue, expectedValue)
}
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, size int) {
func benchmarkGet(b *testing.B, m *Map[int, int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
m.Get(n)
@ -530,7 +632,7 @@ func benchmarkGet(b *testing.B, m *Map, size int) {
}
}
func benchmarkPut(b *testing.B, m *Map, size int) {
func benchmarkPut(b *testing.B, m *Map[int, int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
m.Put(n, n)
@ -538,7 +640,7 @@ func benchmarkPut(b *testing.B, m *Map, size int) {
}
}
func benchmarkRemove(b *testing.B, m *Map, size int) {
func benchmarkRemove(b *testing.B, m *Map[int, int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
m.Remove(n)
@ -549,7 +651,7 @@ func benchmarkRemove(b *testing.B, m *Map, size int) {
func BenchmarkTreeBidiMapGet100(b *testing.B) {
b.StopTimer()
size := 100
m := NewWithIntComparators()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -560,7 +662,7 @@ func BenchmarkTreeBidiMapGet100(b *testing.B) {
func BenchmarkTreeBidiMapGet1000(b *testing.B) {
b.StopTimer()
size := 1000
m := NewWithIntComparators()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -571,7 +673,7 @@ func BenchmarkTreeBidiMapGet1000(b *testing.B) {
func BenchmarkTreeBidiMapGet10000(b *testing.B) {
b.StopTimer()
size := 10000
m := NewWithIntComparators()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -582,7 +684,7 @@ func BenchmarkTreeBidiMapGet10000(b *testing.B) {
func BenchmarkTreeBidiMapGet100000(b *testing.B) {
b.StopTimer()
size := 100000
m := NewWithIntComparators()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -593,7 +695,7 @@ func BenchmarkTreeBidiMapGet100000(b *testing.B) {
func BenchmarkTreeBidiMapPut100(b *testing.B) {
b.StopTimer()
size := 100
m := NewWithIntComparators()
m := New[int, int]()
b.StartTimer()
benchmarkPut(b, m, size)
}
@ -601,7 +703,7 @@ func BenchmarkTreeBidiMapPut100(b *testing.B) {
func BenchmarkTreeBidiMapPut1000(b *testing.B) {
b.StopTimer()
size := 1000
m := NewWithIntComparators()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -612,7 +714,7 @@ func BenchmarkTreeBidiMapPut1000(b *testing.B) {
func BenchmarkTreeBidiMapPut10000(b *testing.B) {
b.StopTimer()
size := 10000
m := NewWithIntComparators()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -623,7 +725,7 @@ func BenchmarkTreeBidiMapPut10000(b *testing.B) {
func BenchmarkTreeBidiMapPut100000(b *testing.B) {
b.StopTimer()
size := 100000
m := NewWithIntComparators()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -634,7 +736,7 @@ func BenchmarkTreeBidiMapPut100000(b *testing.B) {
func BenchmarkTreeBidiMapRemove100(b *testing.B) {
b.StopTimer()
size := 100
m := NewWithIntComparators()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -645,7 +747,7 @@ func BenchmarkTreeBidiMapRemove100(b *testing.B) {
func BenchmarkTreeBidiMapRemove1000(b *testing.B) {
b.StopTimer()
size := 1000
m := NewWithIntComparators()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -656,7 +758,7 @@ func BenchmarkTreeBidiMapRemove1000(b *testing.B) {
func BenchmarkTreeBidiMapRemove10000(b *testing.B) {
b.StopTimer()
size := 10000
m := NewWithIntComparators()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}
@ -667,7 +769,7 @@ func BenchmarkTreeBidiMapRemove10000(b *testing.B) {
func BenchmarkTreeBidiMapRemove100000(b *testing.B) {
b.StopTimer()
size := 100000
m := NewWithIntComparators()
m := New[int, int]()
for n := 0; n < size; n++ {
m.Put(n, n)
}

@ -5,16 +5,15 @@
package treemap
import (
"github.com/emirpasic/gods/containers"
rbt "github.com/emirpasic/gods/trees/redblacktree"
"github.com/emirpasic/gods/v2/containers"
rbt "github.com/emirpasic/gods/v2/trees/redblacktree"
)
func assertEnumerableImplementation() {
var _ containers.EnumerableWithKey = (*Map)(nil)
}
// 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) Each(f func(key interface{}, value interface{})) {
func (m *Map[K, V]) Each(f func(key K, value V)) {
iterator := m.Iterator()
for iterator.Next() {
f(iterator.Key(), iterator.Value())
@ -23,8 +22,8 @@ func (m *Map) Each(f func(key interface{}, value interface{})) {
// Map invokes the given function once for each element and returns a container
// containing the values returned by the given function as key/value pairs.
func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) *Map {
newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)}
func (m *Map[K, V]) Map(f func(key1 K, value1 V) (K, V)) *Map[K, V] {
newMap := &Map[K, V]{tree: rbt.NewWith[K, V](m.tree.Comparator)}
iterator := m.Iterator()
for iterator.Next() {
key2, value2 := f(iterator.Key(), iterator.Value())
@ -34,8 +33,8 @@ func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, int
}
// Select returns a new container containing all elements for which the given function returns a true value.
func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map {
newMap := &Map{tree: rbt.NewWith(m.tree.Comparator)}
func (m *Map[K, V]) Select(f func(key K, value V) bool) *Map[K, V] {
newMap := &Map[K, V]{tree: rbt.NewWith[K, V](m.tree.Comparator)}
iterator := m.Iterator()
for iterator.Next() {
if f(iterator.Key(), iterator.Value()) {
@ -47,7 +46,7 @@ func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map {
// Any passes each element of the container to the given function and
// returns true if the function ever returns true for any element.
func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool {
func (m *Map[K, V]) Any(f func(key K, value V) bool) bool {
iterator := m.Iterator()
for iterator.Next() {
if f(iterator.Key(), iterator.Value()) {
@ -59,7 +58,7 @@ func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool {
// All passes each element of the container to the given function and
// returns true if the function returns true for all elements.
func (m *Map) All(f func(key interface{}, value interface{}) bool) bool {
func (m *Map[K, V]) All(f func(key K, value V) bool) bool {
iterator := m.Iterator()
for iterator.Next() {
if !f(iterator.Key(), iterator.Value()) {
@ -72,12 +71,12 @@ func (m *Map) All(f func(key interface{}, value interface{}) bool) bool {
// Find passes each element of the container to the given function and returns
// the first (key,value) for which the function is true or nil,nil otherwise if no element
// matches the criteria.
func (m *Map) Find(f func(key interface{}, value interface{}) bool) (interface{}, interface{}) {
func (m *Map[K, V]) Find(f func(key K, value V) bool) (k K, v V) {
iterator := m.Iterator()
for iterator.Next() {
if f(iterator.Key(), iterator.Value()) {
return iterator.Key(), iterator.Value()
}
}
return nil, nil
return k, v
}

@ -5,73 +5,100 @@
package treemap
import (
"github.com/emirpasic/gods/containers"
rbt "github.com/emirpasic/gods/trees/redblacktree"
"github.com/emirpasic/gods/v2/containers"
rbt "github.com/emirpasic/gods/v2/trees/redblacktree"
)
func assertIteratorImplementation() {
var _ containers.ReverseIteratorWithKey = (*Iterator)(nil)
}
// Assert Iterator implementation
var _ containers.ReverseIteratorWithKey[string, int] = (*Iterator[string, int])(nil)
// Iterator holding the iterator's state
type Iterator struct {
iterator rbt.Iterator
type Iterator[K comparable, V any] struct {
iterator *rbt.Iterator[K, V]
}
// Iterator returns a stateful iterator whose elements are key/value pairs.
func (m *Map) Iterator() Iterator {
return Iterator{iterator: m.tree.Iterator()}
func (m *Map[K, V]) Iterator() *Iterator[K, V] {
return &Iterator[K, V]{iterator: m.tree.Iterator()}
}
// Next moves the iterator to the next element and returns true if there was a next element in the container.
// If Next() returns true, then next element's key and value can be retrieved by Key() and Value().
// If Next() was called for the first time, then it will point the iterator to the first element if it exists.
// Modifies the state of the iterator.
func (iterator *Iterator) Next() bool {
func (iterator *Iterator[K, V]) Next() bool {
return iterator.iterator.Next()
}
// Prev moves the iterator to the previous element and returns true if there was a previous element in the container.
// If Prev() returns true, then previous element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator.
func (iterator *Iterator) Prev() bool {
func (iterator *Iterator[K, V]) Prev() bool {
return iterator.iterator.Prev()
}
// Value returns the current element's value.
// Does not modify the state of the iterator.
func (iterator *Iterator) Value() interface{} {
func (iterator *Iterator[K, V]) Value() V {
return iterator.iterator.Value()
}
// Key returns the current element's key.
// Does not modify the state of the iterator.
func (iterator *Iterator) Key() interface{} {
func (iterator *Iterator[K, V]) Key() K {
return iterator.iterator.Key()
}
// Begin resets the iterator to its initial state (one-before-first)
// Call Next() to fetch the first element if any.
func (iterator *Iterator) Begin() {
func (iterator *Iterator[K, V]) Begin() {
iterator.iterator.Begin()
}
// End moves the iterator past the last element (one-past-the-end).
// Call Prev() to fetch the last element if any.
func (iterator *Iterator) End() {
func (iterator *Iterator[K, V]) End() {
iterator.iterator.End()
}
// First moves the iterator to the first element and returns true if there was a first element in the container.
// If First() returns true, then first element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator
func (iterator *Iterator) First() bool {
func (iterator *Iterator[K, V]) First() bool {
return iterator.iterator.First()
}
// Last moves the iterator to the last element and returns true if there was a last element in the container.
// If Last() returns true, then last element's key and value can be retrieved by Key() and Value().
// Modifies the state of the iterator.
func (iterator *Iterator) Last() bool {
func (iterator *Iterator[K, V]) Last() bool {
return iterator.iterator.Last()
}
// 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
}

@ -4,19 +4,30 @@
package treemap
import "github.com/emirpasic/gods/containers"
import (
"github.com/emirpasic/gods/v2/containers"
)
func assertSerializationImplementation() {
var _ containers.JSONSerializer = (*Map)(nil)
var _ containers.JSONDeserializer = (*Map)(nil)
}
// 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) ToJSON() ([]byte, error) {
func (m *Map[K, V]) ToJSON() ([]byte, error) {
return m.tree.ToJSON()
}
// FromJSON populates the map from the input JSON representation.
func (m *Map) FromJSON(data []byte) error {
func (m *Map[K, V]) FromJSON(data []byte) error {
return m.tree.FromJSON(data)
}
// UnmarshalJSON @implements json.Unmarshaler
func (m *Map[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()
}

@ -12,97 +12,93 @@
package treemap
import (
"cmp"
"fmt"
"github.com/emirpasic/gods/maps"
rbt "github.com/emirpasic/gods/trees/redblacktree"
"github.com/emirpasic/gods/utils"
"strings"
"github.com/emirpasic/gods/v2/maps"
rbt "github.com/emirpasic/gods/v2/trees/redblacktree"
"github.com/emirpasic/gods/v2/utils"
)
func assertMapImplementation() {
var _ maps.Map = (*Map)(nil)
}
// Assert Map implementation
var _ maps.Map[string, int] = (*Map[string, int])(nil)
// Map holds the elements in a red-black tree
type Map struct {
tree *rbt.Tree
}
// NewWith instantiates a tree map with the custom comparator.
func NewWith(comparator utils.Comparator) *Map {
return &Map{tree: rbt.NewWith(comparator)}
type Map[K comparable, V any] struct {
tree *rbt.Tree[K, V]
}
// NewWithIntComparator instantiates a tree map with the IntComparator, i.e. keys are of type int.
func NewWithIntComparator() *Map {
return &Map{tree: rbt.NewWithIntComparator()}
// 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]()}
}
// NewWithStringComparator instantiates a tree map with the StringComparator, i.e. keys are of type string.
func NewWithStringComparator() *Map {
return &Map{tree: rbt.NewWithStringComparator()}
// NewWith instantiates a tree map with the custom comparator.
func NewWith[K comparable, V any](comparator utils.Comparator[K]) *Map[K, V] {
return &Map[K, V]{tree: rbt.NewWith[K, V](comparator)}
}
// Put inserts key-value pair into the map.
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (m *Map) Put(key interface{}, value interface{}) {
func (m *Map[K, V]) Put(key K, value V) {
m.tree.Put(key, value)
}
// Get searches the element in the map by key and returns its value or nil if key is not found in tree.
// Second return parameter is true if key was found, otherwise false.
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (m *Map) Get(key interface{}) (value interface{}, found bool) {
func (m *Map[K, V]) Get(key K) (value V, found bool) {
return m.tree.Get(key)
}
// Remove removes the element from the map by key.
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (m *Map) Remove(key interface{}) {
func (m *Map[K, V]) Remove(key K) {
m.tree.Remove(key)
}
// Empty returns true if map does not contain any elements
func (m *Map) Empty() bool {
func (m *Map[K, V]) Empty() bool {
return m.tree.Empty()
}
// Size returns number of elements in the map.
func (m *Map) Size() int {
func (m *Map[K, V]) Size() int {
return m.tree.Size()
}
// Keys returns all keys in-order
func (m *Map) Keys() []interface{} {
func (m *Map[K, V]) Keys() []K {
return m.tree.Keys()
}
// Values returns all values in-order based on the key.
func (m *Map) Values() []interface{} {
func (m *Map[K, V]) Values() []V {
return m.tree.Values()
}
// Clear removes all elements from the map.
func (m *Map) Clear() {
func (m *Map[K, V]) Clear() {
m.tree.Clear()
}
// Min returns the minimum key and its value from the tree map.
// Returns nil, nil if map is empty.
func (m *Map) Min() (key interface{}, value interface{}) {
// Returns 0-value, 0-value, false if map is empty.
func (m *Map[K, V]) Min() (key K, value V, ok bool) {
if node := m.tree.Left(); node != nil {
return node.Key, node.Value
return node.Key, node.Value, true
}
return nil, nil
return key, value, false
}
// Max returns the maximum key and its value from the tree map.
// Returns nil, nil if map is empty.
func (m *Map) Max() (key interface{}, value interface{}) {
// Returns 0-value, 0-value, false if map is empty.
func (m *Map[K, V]) Max() (key K, value V, ok bool) {
if node := m.tree.Right(); node != nil {
return node.Key, node.Value
return node.Key, node.Value, true
}
return nil, nil
return key, value, false
}
// Floor finds the floor key-value pair for the input key.
@ -114,12 +110,12 @@ func (m *Map) Max() (key interface{}, value interface{}) {
// all keys in the map are larger than the given key.
//
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (m *Map) Floor(key interface{}) (foundKey interface{}, foundValue interface{}) {
func (m *Map[K, V]) Floor(key K) (foundKey K, foundValue V, ok bool) {
node, found := m.tree.Floor(key)
if found {
return node.Key, node.Value
return node.Key, node.Value, true
}
return nil, nil
return foundKey, foundValue, false
}
// Ceiling finds the ceiling key-value pair for the input key.
@ -131,16 +127,16 @@ func (m *Map) Floor(key interface{}) (foundKey interface{}, foundValue interface
// all keys in the map are smaller than the given key.
//
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (m *Map) Ceiling(key interface{}) (foundKey interface{}, foundValue interface{}) {
func (m *Map[K, V]) Ceiling(key K) (foundKey K, foundValue V, ok bool) {
node, found := m.tree.Ceiling(key)
if found {
return node.Key, node.Value
return node.Key, node.Value, true
}
return nil, nil
return foundKey, foundValue, false
}
// String returns a string representation of container
func (m *Map) String() string {
func (m *Map[K, V]) String() string {
str := "TreeMap\nmap["
it := m.Iterator()
for it.Next() {

@ -5,12 +5,15 @@
package treemap
import (
"fmt"
"encoding/json"
"strings"
"testing"
"github.com/emirpasic/gods/v2/testutils"
)
func TestMapPut(t *testing.T) {
m := NewWithIntComparator()
m := New[int, string]()
m.Put(5, "e")
m.Put(6, "f")
m.Put(7, "g")
@ -23,12 +26,8 @@ func TestMapPut(t *testing.T) {
if actualValue := m.Size(); actualValue != 7 {
t.Errorf("Got %v expected %v", actualValue, 7)
}
if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "e", "f", "g"}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4, 5, 6, 7})
testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d", "e", "f", "g"})
// key,expectedValue,expectedFound
tests1 := [][]interface{}{
@ -39,20 +38,93 @@ func TestMapPut(t *testing.T) {
{5, "e", true},
{6, "f", true},
{7, "g", true},
{8, nil, false},
{8, "", false},
}
for _, test := range tests1 {
// retrievals
actualValue, actualFound := m.Get(test[0])
actualValue, actualFound := m.Get(test[0].(int))
if actualValue != test[1] || actualFound != test[2] {
t.Errorf("Got %v expected %v", actualValue, test[1])
}
}
}
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 := NewWithIntComparator()
m := New[int, string]()
m.Put(5, "e")
m.Put(6, "f")
m.Put(7, "g")
@ -68,13 +140,9 @@ func TestMapRemove(t *testing.T) {
m.Remove(8)
m.Remove(5)
if actualValue, expectedValue := m.Keys(), []interface{}{1, 2, 3, 4}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
testutils.SameElements(t, m.Keys(), []int{1, 2, 3, 4})
testutils.SameElements(t, m.Values(), []string{"a", "b", "c", "d"})
if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d"}; !sameElements(actualValue, expectedValue) {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue := m.Size(); actualValue != 4 {
t.Errorf("Got %v expected %v", actualValue, 4)
}
@ -84,14 +152,14 @@ func TestMapRemove(t *testing.T) {
{2, "b", true},
{3, "c", true},
{4, "d", true},
{5, nil, false},
{6, nil, false},
{7, nil, false},
{8, nil, false},
{5, "", false},
{6, "", false},
{7, "", false},
{8, "", false},
}
for _, test := range tests2 {
actualValue, actualFound := m.Get(test[0])
actualValue, actualFound := m.Get(test[0].(int))
if actualValue != test[1] || actualFound != test[2] {
t.Errorf("Got %v expected %v", actualValue, test[1])
}
@ -104,12 +172,8 @@ func TestMapRemove(t *testing.T) {
m.Remove(2)
m.Remove(2)
if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
testutils.SameElements(t, m.Keys(), nil)
testutils.SameElements(t, m.Values(), nil)
if actualValue := m.Size(); actualValue != 0 {
t.Errorf("Got %v expected %v", actualValue, 0)
}
@ -119,15 +183,15 @@ func TestMapRemove(t *testing.T) {
}
func TestMapFloor(t *testing.T) {
m := NewWithIntComparator()
m := New[int, string]()
m.Put(7, "g")
m.Put(3, "c")
m.Put(1, "a")
// key,expectedKey,expectedValue,expectedFound
tests1 := [][]interface{}{
{-1, nil, nil, false},
{0, nil, nil, false},
{-1, 0, "", false},
{0, 0, "", false},
{1, 1, "a", true},
{2, 1, "a", true},
{3, 3, "c", true},
@ -138,16 +202,15 @@ func TestMapFloor(t *testing.T) {
for _, test := range tests1 {
// retrievals
actualKey, actualValue := m.Floor(test[0])
actualFound := actualKey != nil && actualValue != nil
if actualKey != test[1] || actualValue != test[2] || actualFound != test[3] {
t.Errorf("Got %v, %v, %v, expected %v, %v, %v", actualKey, actualValue, actualFound, test[1], test[2], test[3])
actualKey, actualValue, actualOk := m.Floor(test[0].(int))
if actualKey != test[1] || actualValue != test[2] || actualOk != test[3] {
t.Errorf("Got %v, %v, %v, expected %v, %v, %v", actualKey, actualValue, actualOk, test[1], test[2], test[3])
}
}
}
func TestMapCeiling(t *testing.T) {
m := NewWithIntComparator()
m := New[int, string]()
m.Put(7, "g")
m.Put(3, "c")
m.Put(1, "a")
@ -161,45 +224,25 @@ func TestMapCeiling(t *testing.T) {
{3, 3, "c", true},
{4, 7, "g", true},
{7, 7, "g", true},
{8, nil, nil, false},
{8, 0, "", false},
}
for _, test := range tests1 {
// retrievals
actualKey, actualValue := m.Ceiling(test[0])
actualFound := actualKey != nil && actualValue != nil
if actualKey != test[1] || actualValue != test[2] || actualFound != test[3] {
t.Errorf("Got %v, %v, %v, expected %v, %v, %v", actualKey, actualValue, actualFound, test[1], test[2], test[3])
}
}
}
func sameElements(a []interface{}, b []interface{}) bool {
if len(a) != len(b) {
return false
}
for _, av := range a {
found := false
for _, bv := range b {
if av == bv {
found = true
break
}
}
if !found {
return false
actualKey, actualValue, actualOk := m.Ceiling(test[0].(int))
if actualKey != test[1] || actualValue != test[2] || actualOk != test[3] {
t.Errorf("Got %v, %v, %v, expected %v, %v, %v", actualKey, actualValue, actualOk, test[1], test[2], test[3])
}
}
return true
}
func TestMapEach(t *testing.T) {
m := NewWithStringComparator()
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
count := 0
m.Each(func(key interface{}, value interface{}) {
m.Each(func(key string, value int) {
count++
if actualValue, expectedValue := count, value; actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
@ -224,12 +267,12 @@ func TestMapEach(t *testing.T) {
}
func TestMapMap(t *testing.T) {
m := NewWithStringComparator()
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
mappedMap := m.Map(func(key1 interface{}, value1 interface{}) (key2 interface{}, value2 interface{}) {
return key1, value1.(int) * value1.(int)
mappedMap := m.Map(func(key1 string, value1 int) (key2 string, value2 int) {
return key1, value1 * value1
})
if actualValue, _ := mappedMap.Get("a"); actualValue != 1 {
t.Errorf("Got %v expected %v", actualValue, "mapped: a")
@ -246,12 +289,12 @@ func TestMapMap(t *testing.T) {
}
func TestMapSelect(t *testing.T) {
m := NewWithStringComparator()
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
selectedMap := m.Select(func(key interface{}, value interface{}) bool {
return key.(string) >= "a" && key.(string) <= "b"
selectedMap := m.Select(func(key string, value int) bool {
return key >= "a" && key <= "b"
})
if actualValue, _ := selectedMap.Get("a"); actualValue != 1 {
t.Errorf("Got %v expected %v", actualValue, "value: a")
@ -265,18 +308,18 @@ func TestMapSelect(t *testing.T) {
}
func TestMapAny(t *testing.T) {
m := NewWithStringComparator()
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
any := m.Any(func(key interface{}, value interface{}) bool {
return value.(int) == 3
any := m.Any(func(key string, value int) bool {
return value == 3
})
if any != true {
t.Errorf("Got %v expected %v", any, true)
}
any = m.Any(func(key interface{}, value interface{}) bool {
return value.(int) == 4
any = m.Any(func(key string, value int) bool {
return value == 4
})
if any != false {
t.Errorf("Got %v expected %v", any, false)
@ -284,18 +327,18 @@ func TestMapAny(t *testing.T) {
}
func TestMapAll(t *testing.T) {
m := NewWithStringComparator()
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
all := m.All(func(key interface{}, value interface{}) bool {
return key.(string) >= "a" && key.(string) <= "c"
all := m.All(func(key string, value int) bool {
return key >= "a" && key <= "c"
})
if all != true {
t.Errorf("Got %v expected %v", all, true)
}
all = m.All(func(key interface{}, value interface{}) bool {
return key.(string) >= "a" && key.(string) <= "b"
all = m.All(func(key string, value int) bool {
return key >= "a" && key <= "b"
})
if all != false {
t.Errorf("Got %v expected %v", all, false)
@ -303,38 +346,38 @@ func TestMapAll(t *testing.T) {
}
func TestMapFind(t *testing.T) {
m := NewWithStringComparator()
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
foundKey, foundValue := m.Find(func(key interface{}, value interface{}) bool {
return key.(string) == "c"
foundKey, foundValue := m.Find(func(key string, value int) bool {
return key == "c"
})
if foundKey != "c" || foundValue != 3 {
t.Errorf("Got %v -> %v expected %v -> %v", foundKey, foundValue, "c", 3)
}
foundKey, foundValue = m.Find(func(key interface{}, value interface{}) bool {
return key.(string) == "x"
foundKey, foundValue = m.Find(func(key string, value int) bool {
return key == "x"
})
if foundKey != nil || foundValue != nil {
if foundKey != "" || foundValue != 0 {
t.Errorf("Got %v at %v expected %v at %v", foundValue, foundKey, nil, nil)
}
}
func TestMapChaining(t *testing.T) {
m := NewWithStringComparator()
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
chainedMap := m.Select(func(key interface{}, value interface{}) bool {
return value.(int) > 1
}).Map(func(key interface{}, value interface{}) (interface{}, interface{}) {
return key.(string) + key.(string), value.(int) * value.(int)
chainedMap := m.Select(func(key string, value int) bool {
return value > 1
}).Map(func(key string, value int) (string, int) {
return key + key, value * value
})
if actualValue := chainedMap.Size(); actualValue != 2 {
t.Errorf("Got %v expected %v", actualValue, 2)
}
if actualValue, found := chainedMap.Get("aa"); actualValue != nil || found {
if actualValue, found := chainedMap.Get("aa"); actualValue != 0 || found {
t.Errorf("Got %v expected %v", actualValue, nil)
}
if actualValue, found := chainedMap.Get("bb"); actualValue != 4 || !found {
@ -346,7 +389,7 @@ func TestMapChaining(t *testing.T) {
}
func TestMapIteratorNextOnEmpty(t *testing.T) {
m := NewWithStringComparator()
m := New[string, int]()
it := m.Iterator()
it = m.Iterator()
for it.Next() {
@ -355,7 +398,7 @@ func TestMapIteratorNextOnEmpty(t *testing.T) {
}
func TestMapIteratorPrevOnEmpty(t *testing.T) {
m := NewWithStringComparator()
m := New[string, int]()
it := m.Iterator()
it = m.Iterator()
for it.Prev() {
@ -364,7 +407,7 @@ func TestMapIteratorPrevOnEmpty(t *testing.T) {
}
func TestMapIteratorNext(t *testing.T) {
m := NewWithStringComparator()
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
@ -401,7 +444,7 @@ func TestMapIteratorNext(t *testing.T) {
}
func TestMapIteratorPrev(t *testing.T) {
m := NewWithStringComparator()
m := New[string, int]()
m.Put("c", 3)
m.Put("a", 1)
m.Put("b", 2)
@ -440,7 +483,7 @@ func TestMapIteratorPrev(t *testing.T) {
}
func TestMapIteratorBegin(t *testing.T) {
m := NewWithIntComparator()
m := New[int, string]()
it := m.Iterator()
it.Begin()
m.Put(3, "c")
@ -455,8 +498,8 @@ func TestMapIteratorBegin(t *testing.T) {
}
}
func TestMapTreeIteratorEnd(t *testing.T) {
m := NewWithIntComparator()
func TestMapIteratorEnd(t *testing.T) {
m := New[int, string]()
it := m.Iterator()
m.Put(3, "c")
m.Put(1, "a")
@ -469,7 +512,7 @@ func TestMapTreeIteratorEnd(t *testing.T) {
}
func TestMapIteratorFirst(t *testing.T) {
m := NewWithIntComparator()
m := New[int, string]()
m.Put(3, "c")
m.Put(1, "a")
m.Put(2, "b")
@ -483,7 +526,7 @@ func TestMapIteratorFirst(t *testing.T) {
}
func TestMapIteratorLast(t *testing.T) {
m := NewWithIntComparator()
m := New[int, string]()
m.Put(3, "c")
m.Put(1, "a")
m.Put(2, "b")
@ -496,9 +539,115 @@ func TestMapIteratorLast(t *testing.T) {
}
}
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 := NewWithStringComparator()
original := New[string, string]()
original.Put("d", "4")
original.Put("e", "5")
original.Put("c", "3")
@ -513,31 +662,54 @@ func TestMapSerialization(t *testing.T) {
}
assertSerialization(original, "B", t)
deserialized := NewWithStringComparator()
deserialized := New[string, string]()
err = deserialized.FromJSON(serialized)
if err != nil {
t.Errorf("Got error %v", err)
}
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, txt string, t *testing.T) {
// noinspection GoBoolExpressions
func assertSerialization(m *Map[string, string], txt string, t *testing.T) {
if actualValue := m.Keys(); false ||
actualValue[0].(string) != "a" ||
actualValue[1].(string) != "b" ||
actualValue[2].(string) != "c" ||
actualValue[3].(string) != "d" ||
actualValue[4].(string) != "e" {
actualValue[0] != "a" ||
actualValue[1] != "b" ||
actualValue[2] != "c" ||
actualValue[3] != "d" ||
actualValue[4] != "e" {
t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[a,b,c,d,e]")
}
if actualValue := m.Values(); false ||
actualValue[0].(string) != "1" ||
actualValue[1].(string) != "2" ||
actualValue[2].(string) != "3" ||
actualValue[3].(string) != "4" ||
actualValue[4].(string) != "5" {
actualValue[0] != "1" ||
actualValue[1] != "2" ||
actualValue[2] != "3" ||
actualValue[3] != "4" ||
actualValue[4] != "5" {
t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[1,2,3,4,5]")
}
if actualValue, expectedValue := m.Size(), 5; actualValue != expectedValue {
@ -545,7 +717,7 @@ func assertSerialization(m *Map, txt string, t *testing.T) {
}
}
func benchmarkGet(b *testing.B, m *Map, size int) {
func benchmarkGet(b *testing.B, m *Map[int, struct{}], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
m.Get(n)
@ -553,7 +725,7 @@ func benchmarkGet(b *testing.B, m *Map, size int) {
}
}
func benchmarkPut(b *testing.B, m *Map, size int) {
func benchmarkPut(b *testing.B, m *Map[int, struct{}], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
@ -561,7 +733,7 @@ func benchmarkPut(b *testing.B, m *Map, size int) {
}
}
func benchmarkRemove(b *testing.B, m *Map, size int) {
func benchmarkRemove(b *testing.B, m *Map[int, struct{}], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
m.Remove(n)
@ -572,7 +744,7 @@ func benchmarkRemove(b *testing.B, m *Map, size int) {
func BenchmarkTreeMapGet100(b *testing.B) {
b.StopTimer()
size := 100
m := NewWithIntComparator()
m := New[int, struct{}]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
@ -583,7 +755,7 @@ func BenchmarkTreeMapGet100(b *testing.B) {
func BenchmarkTreeMapGet1000(b *testing.B) {
b.StopTimer()
size := 1000
m := NewWithIntComparator()
m := New[int, struct{}]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
@ -594,7 +766,7 @@ func BenchmarkTreeMapGet1000(b *testing.B) {
func BenchmarkTreeMapGet10000(b *testing.B) {
b.StopTimer()
size := 10000
m := NewWithIntComparator()
m := New[int, struct{}]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
@ -605,7 +777,7 @@ func BenchmarkTreeMapGet10000(b *testing.B) {
func BenchmarkTreeMapGet100000(b *testing.B) {
b.StopTimer()
size := 100000
m := NewWithIntComparator()
m := New[int, struct{}]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
@ -616,7 +788,7 @@ func BenchmarkTreeMapGet100000(b *testing.B) {
func BenchmarkTreeMapPut100(b *testing.B) {
b.StopTimer()
size := 100
m := NewWithIntComparator()
m := New[int, struct{}]()
b.StartTimer()
benchmarkPut(b, m, size)
}
@ -624,7 +796,7 @@ func BenchmarkTreeMapPut100(b *testing.B) {
func BenchmarkTreeMapPut1000(b *testing.B) {
b.StopTimer()
size := 1000
m := NewWithIntComparator()
m := New[int, struct{}]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
@ -635,7 +807,7 @@ func BenchmarkTreeMapPut1000(b *testing.B) {
func BenchmarkTreeMapPut10000(b *testing.B) {
b.StopTimer()
size := 10000
m := NewWithIntComparator()
m := New[int, struct{}]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
@ -646,7 +818,7 @@ func BenchmarkTreeMapPut10000(b *testing.B) {
func BenchmarkTreeMapPut100000(b *testing.B) {
b.StopTimer()
size := 100000
m := NewWithIntComparator()
m := New[int, struct{}]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
@ -657,7 +829,7 @@ func BenchmarkTreeMapPut100000(b *testing.B) {
func BenchmarkTreeMapRemove100(b *testing.B) {
b.StopTimer()
size := 100
m := NewWithIntComparator()
m := New[int, struct{}]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
@ -668,7 +840,7 @@ func BenchmarkTreeMapRemove100(b *testing.B) {
func BenchmarkTreeMapRemove1000(b *testing.B) {
b.StopTimer()
size := 1000
m := NewWithIntComparator()
m := New[int, struct{}]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
@ -679,7 +851,7 @@ func BenchmarkTreeMapRemove1000(b *testing.B) {
func BenchmarkTreeMapRemove10000(b *testing.B) {
b.StopTimer()
size := 10000
m := NewWithIntComparator()
m := New[int, struct{}]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}
@ -690,7 +862,7 @@ func BenchmarkTreeMapRemove10000(b *testing.B) {
func BenchmarkTreeMapRemove100000(b *testing.B) {
b.StopTimer()
size := 100000
m := NewWithIntComparator()
m := New[int, struct{}]()
for n := 0; n < size; n++ {
m.Put(n, struct{}{})
}

@ -0,0 +1,88 @@
// Copyright (c) 2021, Aryan Ahadinia. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package arrayqueue implements a queue backed by array list.
//
// Structure is not thread safe.
//
// Reference: https://en.wikipedia.org/wiki/Queue_(abstract_data_type)
package arrayqueue
import (
"fmt"
"strings"
"github.com/emirpasic/gods/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()
}

@ -0,0 +1,494 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package arrayqueue
import (
"encoding/json"
"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)
}

@ -0,0 +1,111 @@
// Copyright (c) 2021, Aryan Ahadinia. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package arrayqueue
import "github.com/emirpasic/gods/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
}

@ -0,0 +1,33 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package arrayqueue
import (
"github.com/emirpasic/gods/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()
}

@ -0,0 +1,148 @@
// 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
}

@ -0,0 +1,629 @@
// 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)
}

@ -0,0 +1,112 @@
// Copyright (c) 2021, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package circularbuffer
import "github.com/emirpasic/gods/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
}

@ -0,0 +1,42 @@
// 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()
}

@ -0,0 +1,73 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package linkedlistqueue
import "github.com/emirpasic/gods/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
}

@ -0,0 +1,88 @@
// Copyright (c) 2021, Aryan Ahadinia. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package linkedlistqueue implements a queue backed by a singly-linked list.
//
// Structure is not thread safe.
//
// Reference: https://en.wikipedia.org/wiki/Queue_(abstract_data_type)
package linkedlistqueue
import (
"fmt"
"strings"
"github.com/emirpasic/gods/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()
}

@ -0,0 +1,357 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package linkedlistqueue
import (
"encoding/json"
"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)
}

@ -0,0 +1,33 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package linkedlistqueue
import (
"github.com/emirpasic/gods/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()
}

@ -0,0 +1,92 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package priorityqueue
import (
"github.com/emirpasic/gods/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)
}

@ -0,0 +1,92 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package priorityqueue 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
}

@ -0,0 +1,573 @@
// 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)
}

@ -0,0 +1,33 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package priorityqueue
import (
"github.com/emirpasic/gods/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()
}

@ -0,0 +1,27 @@
// Copyright (c) 2021, Aryan Ahadinia. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package queues provides an abstract Queue interface.
//
// In computer science, a queue is a collection of entities that are maintained in a sequence and can be modified by the addition of entities at one end of the sequence and the removal of entities from the other end of the sequence. By convention, the end of the sequence at which elements are added is called the back, tail, or rear of the queue, and the end at which elements are removed is called the head or front of the queue, analogously to the words used when people line up to wait for goods or services.
// The operation of adding an element to the rear of the queue is known as enqueue, and the operation of removing an element from the front is known as dequeue. Other operations may also be allowed, often including a peek or front operation that returns the value of the next element to be dequeued without remove it.
//
// Reference: https://en.wikipedia.org/wiki/Queue_(abstract_data_type)
package queues
import "github.com/emirpasic/gods/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
}

@ -11,24 +11,24 @@ package hashset
import (
"fmt"
"github.com/emirpasic/gods/sets"
"strings"
"github.com/emirpasic/gods/v2/sets"
)
func assertSetImplementation() {
var _ sets.Set = (*Set)(nil)
}
// Assert Set implementation
var _ sets.Set[int] = (*Set[int])(nil)
// Set holds elements in go's native map
type Set struct {
items map[interface{}]struct{}
type Set[T comparable] struct {
items map[T]struct{}
}
var itemExists = struct{}{}
// New instantiates a new empty set and adds the passed values, if any, to the set
func New(values ...interface{}) *Set {
set := &Set{items: make(map[interface{}]struct{})}
func New[T comparable](values ...T) *Set[T] {
set := &Set[T]{items: make(map[T]struct{})}
if len(values) > 0 {
set.Add(values...)
}
@ -36,14 +36,14 @@ func New(values ...interface{}) *Set {
}
// Add adds the items (one or more) to the set.
func (set *Set) Add(items ...interface{}) {
func (set *Set[T]) Add(items ...T) {
for _, item := range items {
set.items[item] = itemExists
}
}
// Remove removes the items (one or more) from the set.
func (set *Set) Remove(items ...interface{}) {
func (set *Set[T]) Remove(items ...T) {
for _, item := range items {
delete(set.items, item)
}
@ -52,7 +52,7 @@ func (set *Set) Remove(items ...interface{}) {
// Contains check if items (one or more) are present in the set.
// All items have to be present in the set for the method to return true.
// Returns true if no arguments are passed at all, i.e. set is always superset of empty set.
func (set *Set) Contains(items ...interface{}) bool {
func (set *Set[T]) Contains(items ...T) bool {
for _, item := range items {
if _, contains := set.items[item]; !contains {
return false
@ -62,23 +62,23 @@ func (set *Set) Contains(items ...interface{}) bool {
}
// Empty returns true if set does not contain any elements.
func (set *Set) Empty() bool {
func (set *Set[T]) Empty() bool {
return set.Size() == 0
}
// Size returns number of elements within the set.
func (set *Set) Size() int {
func (set *Set[T]) Size() int {
return len(set.items)
}
// Clear clears all values in the set.
func (set *Set) Clear() {
set.items = make(map[interface{}]struct{})
func (set *Set[T]) Clear() {
set.items = make(map[T]struct{})
}
// Values returns all items in the set.
func (set *Set) Values() []interface{} {
values := make([]interface{}, set.Size())
func (set *Set[T]) Values() []T {
values := make([]T, set.Size())
count := 0
for item := range set.items {
values[count] = item
@ -88,7 +88,7 @@ func (set *Set) Values() []interface{} {
}
// String returns a string representation of container
func (set *Set) String() string {
func (set *Set[T]) String() string {
str := "HashSet\n"
items := []string{}
for k := range set.items {
@ -97,3 +97,58 @@ func (set *Set) String() string {
str += strings.Join(items, ", ")
return str
}
// Intersection returns the intersection between two sets.
// The new set consists of all elements that are both in "set" and "another".
// Ref: https://en.wikipedia.org/wiki/Intersection_(set_theory)
func (set *Set[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
}

@ -5,6 +5,8 @@
package hashset
import (
"encoding/json"
"strings"
"testing"
)
@ -26,7 +28,7 @@ func TestSetNew(t *testing.T) {
}
func TestSetAdd(t *testing.T) {
set := New()
set := New[int]()
set.Add()
set.Add(1)
set.Add(2)
@ -41,7 +43,7 @@ func TestSetAdd(t *testing.T) {
}
func TestSetContains(t *testing.T) {
set := New()
set := New[int]()
set.Add(3, 1, 2)
set.Add(2, 3)
set.Add()
@ -60,7 +62,7 @@ func TestSetContains(t *testing.T) {
}
func TestSetRemove(t *testing.T) {
set := New()
set := New[int]()
set.Add(3, 1, 2)
set.Remove()
if actualValue := set.Size(); actualValue != 3 {
@ -80,7 +82,7 @@ func TestSetRemove(t *testing.T) {
}
func TestSetSerialization(t *testing.T) {
set := New()
set := New[string]()
set.Add("a", "b", "c")
var err error
@ -98,14 +100,99 @@ func TestSetSerialization(t *testing.T) {
assert()
json, err := set.ToJSON()
bytes, err := set.ToJSON()
assert()
err = set.FromJSON(json)
err = set.FromJSON(bytes)
assert()
bytes, err = json.Marshal([]interface{}{"a", "b", "c", set})
if err != nil {
t.Errorf("Got error %v", err)
}
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, size int) {
func benchmarkContains(b *testing.B, set *Set[int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
set.Contains(n)
@ -113,7 +200,7 @@ func benchmarkContains(b *testing.B, set *Set, size int) {
}
}
func benchmarkAdd(b *testing.B, set *Set, size int) {
func benchmarkAdd(b *testing.B, set *Set[int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
set.Add(n)
@ -121,7 +208,7 @@ func benchmarkAdd(b *testing.B, set *Set, size int) {
}
}
func benchmarkRemove(b *testing.B, set *Set, size int) {
func benchmarkRemove(b *testing.B, set *Set[int], size int) {
for i := 0; i < b.N; i++ {
for n := 0; n < size; n++ {
set.Remove(n)
@ -132,7 +219,7 @@ func benchmarkRemove(b *testing.B, set *Set, size int) {
func BenchmarkHashSetContains100(b *testing.B) {
b.StopTimer()
size := 100
set := New()
set := New[int]()
for n := 0; n < size; n++ {
set.Add(n)
}
@ -143,7 +230,7 @@ func BenchmarkHashSetContains100(b *testing.B) {
func BenchmarkHashSetContains1000(b *testing.B) {
b.StopTimer()
size := 1000
set := New()
set := New[int]()
for n := 0; n < size; n++ {
set.Add(n)
}
@ -154,7 +241,7 @@ func BenchmarkHashSetContains1000(b *testing.B) {
func BenchmarkHashSetContains10000(b *testing.B) {
b.StopTimer()
size := 10000
set := New()
set := New[int]()
for n := 0; n < size; n++ {
set.Add(n)
}
@ -165,7 +252,7 @@ func BenchmarkHashSetContains10000(b *testing.B) {
func BenchmarkHashSetContains100000(b *testing.B) {
b.StopTimer()
size := 100000
set := New()
set := New[int]()
for n := 0; n < size; n++ {
set.Add(n)
}
@ -176,7 +263,7 @@ func BenchmarkHashSetContains100000(b *testing.B) {
func BenchmarkHashSetAdd100(b *testing.B) {
b.StopTimer()
size := 100
set := New()
set := New[int]()
b.StartTimer()
benchmarkAdd(b, set, size)
}
@ -184,7 +271,7 @@ func BenchmarkHashSetAdd100(b *testing.B) {
func BenchmarkHashSetAdd1000(b *testing.B) {
b.StopTimer()
size := 1000
set := New()
set := New[int]()
for n := 0; n < size; n++ {
set.Add(n)
}
@ -195,7 +282,7 @@ func BenchmarkHashSetAdd1000(b *testing.B) {
func BenchmarkHashSetAdd10000(b *testing.B) {
b.StopTimer()
size := 10000
set := New()
set := New[int]()
for n := 0; n < size; n++ {
set.Add(n)
}
@ -206,7 +293,7 @@ func BenchmarkHashSetAdd10000(b *testing.B) {
func BenchmarkHashSetAdd100000(b *testing.B) {
b.StopTimer()
size := 100000
set := New()
set := New[int]()
for n := 0; n < size; n++ {
set.Add(n)
}
@ -217,7 +304,7 @@ func BenchmarkHashSetAdd100000(b *testing.B) {
func BenchmarkHashSetRemove100(b *testing.B) {
b.StopTimer()
size := 100
set := New()
set := New[int]()
for n := 0; n < size; n++ {
set.Add(n)
}
@ -228,7 +315,7 @@ func BenchmarkHashSetRemove100(b *testing.B) {
func BenchmarkHashSetRemove1000(b *testing.B) {
b.StopTimer()
size := 1000
set := New()
set := New[int]()
for n := 0; n < size; n++ {
set.Add(n)
}
@ -239,7 +326,7 @@ func BenchmarkHashSetRemove1000(b *testing.B) {
func BenchmarkHashSetRemove10000(b *testing.B) {
b.StopTimer()
size := 10000
set := New()
set := New[int]()
for n := 0; n < size; n++ {
set.Add(n)
}
@ -250,7 +337,7 @@ func BenchmarkHashSetRemove10000(b *testing.B) {
func BenchmarkHashSetRemove100000(b *testing.B) {
b.StopTimer()
size := 100000
set := New()
set := New[int]()
for n := 0; n < size; n++ {
set.Add(n)
}

@ -6,22 +6,22 @@ package hashset
import (
"encoding/json"
"github.com/emirpasic/gods/containers"
"github.com/emirpasic/gods/v2/containers"
)
func assertSerializationImplementation() {
var _ containers.JSONSerializer = (*Set)(nil)
var _ containers.JSONDeserializer = (*Set)(nil)
}
// 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) ToJSON() ([]byte, error) {
func (set *Set[T]) ToJSON() ([]byte, error) {
return json.Marshal(set.Values())
}
// FromJSON populates the set from the input JSON representation.
func (set *Set) FromJSON(data []byte) error {
elements := []interface{}{}
func (set *Set[T]) FromJSON(data []byte) error {
var elements []T
err := json.Unmarshal(data, &elements)
if err == nil {
set.Clear()
@ -29,3 +29,13 @@ func (set *Set) FromJSON(data []byte) error {
}
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()
}

@ -4,14 +4,13 @@
package linkedhashset
import "github.com/emirpasic/gods/containers"
import "github.com/emirpasic/gods/v2/containers"
func assertEnumerableImplementation() {
var _ containers.EnumerableWithIndex = (*Set)(nil)
}
// 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) Each(f func(index int, value interface{})) {
func (set *Set[T]) Each(f func(index int, value T)) {
iterator := set.Iterator()
for iterator.Next() {
f(iterator.Index(), iterator.Value())
@ -20,8 +19,8 @@ func (set *Set) Each(f func(index int, value interface{})) {
// Map invokes the given function once for each element and returns a
// container containing the values returned by the given function.
func (set *Set) Map(f func(index int, value interface{}) interface{}) *Set {
newSet := New()
func (set *Set[T]) Map(f func(index int, value T) T) *Set[T] {
newSet := New[T]()
iterator := set.Iterator()
for iterator.Next() {
newSet.Add(f(iterator.Index(), iterator.Value()))
@ -30,8 +29,8 @@ func (set *Set) Map(f func(index int, value interface{}) interface{}) *Set {
}
// Select returns a new container containing all elements for which the given function returns a true value.
func (set *Set) Select(f func(index int, value interface{}) bool) *Set {
newSet := New()
func (set *Set[T]) Select(f func(index int, value T) bool) *Set[T] {
newSet := New[T]()
iterator := set.Iterator()
for iterator.Next() {
if f(iterator.Index(), iterator.Value()) {
@ -43,7 +42,7 @@ func (set *Set) Select(f func(index int, value interface{}) bool) *Set {
// Any passes each element of the container to the given function and
// returns true if the function ever returns true for any element.
func (set *Set) Any(f func(index int, value interface{}) bool) bool {
func (set *Set[T]) Any(f func(index int, value T) bool) bool {
iterator := set.Iterator()
for iterator.Next() {
if f(iterator.Index(), iterator.Value()) {
@ -55,7 +54,7 @@ func (set *Set) Any(f func(index int, value interface{}) bool) bool {
// All passes each element of the container to the given function and
// returns true if the function returns true for all elements.
func (set *Set) All(f func(index int, value interface{}) bool) bool {
func (set *Set[T]) All(f func(index int, value T) bool) bool {
iterator := set.Iterator()
for iterator.Next() {
if !f(iterator.Index(), iterator.Value()) {
@ -68,12 +67,13 @@ func (set *Set) All(f func(index int, value interface{}) bool) bool {
// Find passes each element of the container to the given function and returns
// the first (index,value) for which the function is true or -1,nil otherwise
// if no element matches the criteria.
func (set *Set) Find(f func(index int, value interface{}) bool) (int, interface{}) {
func (set *Set[T]) Find(f func(index int, value T) bool) (int, T) {
iterator := set.Iterator()
for iterator.Next() {
if f(iterator.Index(), iterator.Value()) {
return iterator.Index(), iterator.Value()
}
}
return -1, nil
var t T
return -1, t
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save