Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TASK] TRK-2258 Add FIFO queue #29

Merged
merged 4 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: [ '1.18', '1.19.x' ]
go-version: [ '1.21', '1.21.x' ]

steps:
- name: Checkout the repository
Expand All @@ -26,7 +26,7 @@ jobs:
run: go version

- name: Install staticcheck
run: go install honnef.co/go/tools/cmd/staticcheck@2022.1.3
run: go install honnef.co/go/tools/cmd/staticcheck@latest

- name: Install cover
run: go get -u golang.org/x/tools/cmd/cover
Expand All @@ -38,7 +38,7 @@ jobs:
run: go get -u github.com/mattn/goveralls

- name: Staticcheck
run: staticcheck -checks="all,-ST1000" github.com/msales/gox/...
run: staticcheck -checks="all,-ST1000,-SA1019" github.com/msales/gox/...

- name: Vet
run: go vet ./...
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module github.com/msales/gox

go 1.16
go 1.21
48 changes: 48 additions & 0 deletions queuex/fifo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package queuex

import "sync"

// FIFO is simple implementation of FIFO (first-in-first-out) queue with locks.
type FIFO[T any] struct {
m sync.Mutex

vals []T
}

// NewFIFO initializes queue with values.
func NewFIFO[T any](vals ...T) *FIFO[T] {
return &FIFO[T]{vals: vals}
}

// Push adds elements at the end of the queue.
func (f *FIFO[T]) Push(v T) *FIFO[T] {
f.m.Lock()
defer f.m.Unlock()

f.vals = append(f.vals, v)
return f
}

// Pop returns first element from the queue.
// Bool is also returned to indicate if queue has run out of the values.
func (f *FIFO[T]) Pop() (T, bool) {
f.m.Lock()
defer f.m.Unlock()

if len(f.vals) == 0 {
var t T
return t, false
}

v := f.vals[0]
f.vals = f.vals[1:]
return v, true
}

// Len returns length of queue.
func (f *FIFO[T]) Len() int {
f.m.Lock()
defer f.m.Unlock()

return len(f.vals)
}
146 changes: 146 additions & 0 deletions queuex/fifo_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package queuex_test

import (
"github.com/msales/gox/queuex"
"testing"
)

func TestFIFO(t *testing.T) {
queue := queuex.NewFIFO([]int{
1, 2,
}...)

queue.Push(3)

got, ok := queue.Pop()
wantVal := 1
wantOK := true
if wantVal != got {
t.Errorf("Got %+v, want %+v", got, wantVal)
}

if ok != wantOK {
t.Errorf("Got %+v, want %+v", ok, wantOK)
}

got, ok = queue.Pop()
wantVal = 2
wantOK = true
if wantVal != got {
t.Errorf("Got %+v, want %+v", got, wantVal)
}

if ok != wantOK {
t.Errorf("Got %+v, want %+v", ok, wantOK)
}

got, ok = queue.Pop()
wantVal = 3
wantOK = true
if wantVal != got {
t.Errorf("Got %+v, want %+v", got, wantVal)
}

if ok != wantOK {
t.Errorf("Got %+v, want %+v", ok, wantOK)
}

got, ok = queue.Pop()
wantVal = 0
wantOK = false
if wantVal != got {
t.Errorf("Got %+v, want %+v", got, wantVal)
}

if ok != wantOK {
t.Errorf("Got %+v, want %+v", ok, wantOK)
}
}

func TestFIFO_EmptyQueue(t *testing.T) {
queue := queuex.NewFIFO[int]()

got, ok := queue.Pop()
wantVal := 0
wantOK := false
if wantVal != got {
t.Errorf("Got %+v, want %+v", got, wantVal)
}

if ok != wantOK {
t.Errorf("Got %+v, want %+v", ok, wantOK)
}

got, ok = queue.Pop()
if wantVal != got {
t.Errorf("Got %+v, want %+v", got, wantVal)
}

if ok != wantOK {
t.Errorf("Got %+v, want %+v", ok, wantOK)
}
}

func BenchmarkFIFO_Pop(b *testing.B) {
vals := make([]int, 1000)
for i := 0; i < 1000; i++ {
vals[i] = i
}

queue := queuex.NewFIFO(vals...)

b.ReportAllocs()
b.ResetTimer()

for i := 0; i < b.N; i++ {
queue.Pop()
}
}

func BenchmarkFIFO_Push(b *testing.B) {
vals := make([]int, 1000)
for i := 0; i < 1000; i++ {
vals[i] = i
}

queue := queuex.NewFIFO(vals...)

b.ReportAllocs()
b.ResetTimer()

for i := 0; i < b.N; i++ {
queue.Push(i)
}
}

func BenchmarkFIFO_EmptyPush(b *testing.B) {
queue := queuex.NewFIFO[int]()

b.ReportAllocs()
b.ResetTimer()

for i := 0; i < b.N; i++ {
queue.Push(i)
}
}

func BenchmarkFIFO_RandomPushPop(b *testing.B) {
vals := make([]int, 1000)
for i := 0; i < 1000; i++ {
vals[i] = i
}

queue := queuex.NewFIFO(vals...)

b.ReportAllocs()
b.ResetTimer()

for i := 0; i < b.N; i++ {
if i%2 == 0 {
queue.Pop()
continue
} else {
queue.Push(i)
}
}
}