mirror of https://github.com/emirpasic/gods
Compare commits
75 Commits
Author | SHA1 | Date |
---|---|---|
|
14f714261f | 6 months ago |
|
10d6c5b4f2 | 10 months ago |
|
608766492e | 10 months ago |
|
702a6b2c26 | 1 year ago |
|
9f3e98d84a | 1 year ago |
|
5dd72bf1e0 | 2 years ago |
|
789e39cb69 | 2 years ago |
|
dbdbadc158 | 2 years ago |
|
b486cc91bf | 2 years ago |
|
e63524608b | 2 years ago |
|
773505cfec | 2 years ago |
|
2bf1bd3aff | 2 years ago |
|
8ace639fc3 | 2 years ago |
|
6b0ffefe7f | 2 years ago |
|
33e824351c | 2 years ago |
|
60093dc4a3 | 2 years ago |
|
9606c1a0e8 | 2 years ago |
|
da429eb24e | 2 years ago |
|
5b2385446e | 2 years ago |
|
6bf61e32be | 2 years ago |
|
6a0f91bdd5 | 2 years ago |
|
77ed4cc146 | 2 years ago |
|
7815e7de4e | 2 years ago |
|
74d62f4f1e | 2 years ago |
|
4665f56318 | 2 years ago |
|
44253054e3 | 2 years ago |
|
9e4f7a11c4 | 2 years ago |
|
08cf24a0a0 | 2 years ago |
|
1dd397e12c | 2 years ago |
|
6356a9e470 | 2 years ago |
|
f70d3dd117 | 2 years ago |
|
08ae186640 | 2 years ago |
|
05959cbe35 | 2 years ago |
|
92b8f18bff | 2 years ago |
|
d953513772 | 2 years ago |
|
41012c6c58 | 2 years ago |
|
e2b92bbc7a | 2 years ago |
|
363df0e21f | 2 years ago |
|
1711af552f | 2 years ago |
|
0d3ddc1d74 | 2 years ago |
|
138c2712da | 2 years ago |
|
5bcba54b52 | 2 years ago |
|
b2dbe95e30 | 2 years ago |
|
155dd74f32 | 2 years ago |
|
74d4456375 | 2 years ago |
|
e438e7b77b | 2 years ago |
|
7cf7ceab6f | 2 years ago |
|
ae81334c3e | 2 years ago |
|
74bf8a8b7d | 2 years ago |
|
d7c0bc8651 | 2 years ago |
|
9641d19f46 | 2 years ago |
|
364a244af9 | 2 years ago |
|
a27d480bcc | 2 years ago |
|
3bca87dfc4 | 2 years ago |
|
9548245e86 | 2 years ago |
|
f93cc2b042 | 2 years ago |
|
56b5cc16a1 | 2 years ago |
|
1f0b87f0e1 | 2 years ago |
|
b5735bcc4d | 2 years ago |
|
49b5b79c62 | 2 years ago |
|
7487c6a604 | 2 years ago |
|
69d2184011 | 2 years ago |
|
55346e985b | 2 years ago |
|
17e5fd5a36 | 2 years ago |
|
08ae493e8a | 2 years ago |
|
4209f34363 | 2 years ago |
|
c9a2dcad62 | 3 years ago |
|
3c9a1ea06f | 3 years ago |
|
b2f992450d | 3 years ago |
|
327ef4525b | 3 years ago |
|
386e3be586 | 3 years ago |
|
222ea6c374 | 3 years ago |
|
508e436ad1 | 4 years ago |
|
419d73a3b6 | 4 years ago |
|
3e279ba9ab | 4 years ago |
@ -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,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
|
||||
}
|
@ -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
|
||||
}
|
@ -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"]
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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=
|
@ -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
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue