]> 127.0.0.1 Git - part/.git/commitdiff
1 (#20) v0.28.20250204101454
authorqydysky <qydysky@foxmail.com>
Tue, 4 Feb 2025 10:14:43 +0000 (18:14 +0800)
committerGitHub <noreply@github.com>
Tue, 4 Feb 2025 10:14:43 +0000 (18:14 +0800)
.github/workflows/test1.yml
slice/FIFO.go [new file with mode: 0644]
slice/FIFO_test.go [new file with mode: 0644]

index 1c9565c3c086d43d00944014b7cdf80725848201..d5401a4433f40632d5bea1e84b96b9aba1a24c48 100644 (file)
@@ -38,7 +38,7 @@ jobs:
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/component
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/component2
         go test -count 1 -timeout 20s -v -race github.com/qydysky/part/ctx
-        go test -count 1 -timeout 7s -v -race github.com/qydysky/part/slice
+        go test -count 1 -timeout 10s -v -race github.com/qydysky/part/slice
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/bools
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/errors
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/crypto
@@ -77,7 +77,7 @@ jobs:
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/component
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/component2
         go test -count 1 -timeout 20s -v -race github.com/qydysky/part/ctx
-        go test -count 1 -timeout 7s -v -race github.com/qydysky/part/slice
+        go test -count 1 -timeout 10s -v -race github.com/qydysky/part/slice
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/bools
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/errors
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/crypto
@@ -116,7 +116,7 @@ jobs:
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/component
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/component2
         go test -count 1 -timeout 20s -v -race github.com/qydysky/part/ctx
-        go test -count 1 -timeout 7s -v -race github.com/qydysky/part/slice
+        go test -count 1 -timeout 10s -v -race github.com/qydysky/part/slice
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/bools
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/errors
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/crypto
diff --git a/slice/FIFO.go b/slice/FIFO.go
new file mode 100644 (file)
index 0000000..01f2311
--- /dev/null
@@ -0,0 +1,130 @@
+package part
+
+import (
+       "sync"
+
+       "errors"
+)
+
+var (
+       ErrFIFOOverflow = errors.New(`ErrFIFOOverflow`)
+       ErrFIFOEmpty    = errors.New(`ErrFIFOEmpty`)
+)
+
+type item struct {
+       op, ed int
+}
+
+type FIFO[S any, T []S] struct {
+       ed, op, opc int
+       c           chan item
+       buf         []S
+       l           sync.RWMutex
+}
+
+func NewFIFO[S any, T []S](size int) *FIFO[S, T] {
+       return &FIFO[S, T]{
+               c:   make(chan item, size),
+               buf: make([]S, size),
+       }
+}
+
+func (t *FIFO[S, T]) lock() func() {
+       t.l.Lock()
+       return t.l.Unlock
+}
+
+func (t *FIFO[S, T]) rlock() func() {
+       t.l.RLock()
+       return t.l.RUnlock
+}
+
+func (t *FIFO[S, T]) inok(size int) bool {
+       if t.ed+size > len(t.buf) {
+               if size > t.op {
+                       return false
+               }
+               t.ed = 0
+       } else if t.op > t.ed && t.ed+size > t.op {
+               return false
+       }
+       return true
+}
+
+func (t *FIFO[S, T]) In(p T) error {
+       defer t.lock()()
+
+       t.op = t.opc
+       if !t.inok(len(p)) {
+               return ErrFIFOOverflow
+       }
+       select {
+       case t.c <- item{
+               op: t.ed,
+               ed: t.ed + len(p),
+       }:
+               t.ed = t.ed + copy(t.buf[t.ed:], p)
+       default:
+               return ErrFIFOOverflow
+       }
+       return nil
+}
+
+func (t *FIFO[S, T]) Out() (p T, e error) {
+       defer t.rlock()()
+
+       select {
+       case item := <-t.c:
+               p = t.buf[item.op:item.ed]
+               t.opc = item.ed
+       default:
+               e = ErrFIFOEmpty
+       }
+
+       return
+}
+
+func (t *FIFO[S, T]) Size() int {
+       defer t.rlock()()
+
+       if t.opc > t.ed {
+               return len(t.buf) - t.opc - t.ed
+       } else {
+               return t.ed - t.opc
+       }
+}
+
+func (t *FIFO[S, T]) Num() int {
+       return len(t.c)
+}
+
+func (t *FIFO[S, T]) Clear() {
+       defer t.lock()()
+
+       t.op = 0
+       t.opc = 0
+       t.ed = 0
+       for {
+               select {
+               case <-t.c:
+               default:
+                       return
+               }
+       }
+}
+
+func (t *FIFO[S, T]) Reset() {
+       defer t.lock()()
+
+       clear(t.buf)
+       t.op = 0
+       t.opc = 0
+       t.ed = 0
+       for {
+               select {
+               case <-t.c:
+               default:
+                       return
+               }
+       }
+}
diff --git a/slice/FIFO_test.go b/slice/FIFO_test.go
new file mode 100644 (file)
index 0000000..4c8676f
--- /dev/null
@@ -0,0 +1,94 @@
+package part
+
+import (
+       "bytes"
+       "testing"
+)
+
+func TestFIFO(t *testing.T) {
+       fifo := NewFIFO[byte](5)
+
+       if fifo.In([]byte("012345")) != ErrFIFOOverflow {
+               t.Fatal()
+       }
+       fifo.Clear()
+
+       if fifo.In([]byte("012")) != nil {
+               t.Fatal()
+       }
+       if fifo.In([]byte("345")) != ErrFIFOOverflow {
+               t.Fatal()
+       }
+       fifo.Clear()
+
+       if fifo.In([]byte("012")) != nil {
+               t.Fatal()
+       }
+       if fifo.In([]byte("34")) != nil {
+               t.Fatal()
+       }
+       fifo.Clear()
+
+       if fifo.In([]byte("012")) != nil {
+               t.Fatal()
+       }
+       if tmp, e := fifo.Out(); e != nil || !bytes.Equal(tmp, []byte("012")) {
+               t.Fatal()
+       }
+       fifo.Clear()
+
+       if fifo.In([]byte("01")) != nil {
+               t.Fatal()
+       }
+       if fifo.Size() != 2 {
+               t.Fatal()
+       }
+       if e := fifo.In([]byte("234")); e != nil {
+               t.Fatal(e)
+       }
+       if fifo.Size() != 5 {
+               t.Fatal()
+       }
+       if tmp, e := fifo.Out(); e != nil || !bytes.Equal(tmp, []byte("01")) {
+               t.Fatal()
+       }
+       if fifo.In([]byte("56")) != nil {
+               t.Fatal()
+       }
+       if tmp, e := fifo.Out(); e != nil || !bytes.Equal(tmp, []byte("234")) {
+               t.Fatal()
+       }
+       if tmp, e := fifo.Out(); e != nil || !bytes.Equal(tmp, []byte("56")) {
+               t.Fatal()
+       }
+       fifo.Clear()
+
+       // if fifo.In([]byte("012")) != nil {
+       //      t.Fatal()
+       // }
+       // go func() {
+       //      time.Sleep(time.Millisecond * 500)
+       //      fifo.Out()
+       // }()
+       // if e := fifo.In([]byte("345")); e != nil {
+       //      t.Fatal(e)
+       // }
+       // time.Sleep(time.Second * 10)
+       // fifo.Clear()
+}
+
+func BenchmarkFIFO(b *testing.B) {
+       fifo := NewFIFO[byte](5)
+       buf := []byte("12")
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               if e := fifo.In(buf); e != nil {
+                       b.FailNow()
+               }
+               if fifo.Num() > 1 {
+                       if tmp, e := fifo.Out(); e != nil || !bytes.Equal(tmp, buf) {
+                               b.FailNow()
+                       }
+               }
+       }
+}