diff --git a/container/gring/gring.go b/container/gring/gring.go index 3a0893c61a6..13921111458 100644 --- a/container/gring/gring.go +++ b/container/gring/gring.go @@ -9,27 +9,11 @@ // Deprecated. package gring -import ( - "container/ring" - - "github.com/gogf/gf/v2/container/gtype" - "github.com/gogf/gf/v2/internal/rwmutex" -) - // Ring is a struct of ring structure. // // Deprecated. type Ring struct { - mu *rwmutex.RWMutex - ring *ring.Ring // Underlying ring. - len *gtype.Int // Length(already used size). - cap *gtype.Int // Capability(>=len). - dirty *gtype.Bool // Dirty, which means the len and cap should be recalculated. It's marked dirty when the size of ring changes. -} - -// internalRingItem stores the ring element value. -type internalRingItem struct { - Value any + *TRing[any] } // New creates and returns a Ring structure of `cap` elements. @@ -39,108 +23,53 @@ type internalRingItem struct { // Deprecated. func New(cap int, safe ...bool) *Ring { return &Ring{ - mu: rwmutex.New(safe...), - ring: ring.New(cap), - len: gtype.NewInt(), - cap: gtype.NewInt(cap), - dirty: gtype.NewBool(), + TRing: NewTRing[any](cap, safe...), } } // Val returns the item's value of current position. func (r *Ring) Val() any { - var value any - r.mu.RLock() - if r.ring.Value != nil { - value = r.ring.Value.(internalRingItem).Value - } - r.mu.RUnlock() - return value + return r.TRing.Val() } // Len returns the size of ring. func (r *Ring) Len() int { - r.checkAndUpdateLenAndCap() - return r.len.Val() + return r.TRing.Len() } // Cap returns the capacity of ring. func (r *Ring) Cap() int { - r.checkAndUpdateLenAndCap() - return r.cap.Val() -} - -// Checks and updates the len and cap of ring when ring is dirty. -func (r *Ring) checkAndUpdateLenAndCap() { - if !r.dirty.Val() { - return - } - r.mu.RLock() - defer r.mu.RUnlock() - totalLen := 0 - emptyLen := 0 - if r.ring != nil { - if r.ring.Value == nil { - emptyLen++ - } - totalLen++ - for p := r.ring.Next(); p != r.ring; p = p.Next() { - if p.Value == nil { - emptyLen++ - } - totalLen++ - } - } - r.cap.Set(totalLen) - r.len.Set(totalLen - emptyLen) - r.dirty.Set(false) + return r.TRing.Cap() } // Set sets value to the item of current position. func (r *Ring) Set(value any) *Ring { - r.mu.Lock() - if r.ring.Value == nil { - r.len.Add(1) - } - r.ring.Value = internalRingItem{Value: value} - r.mu.Unlock() + r.TRing.Set(value) return r } // Put sets `value` to current item of ring and moves position to next item. func (r *Ring) Put(value any) *Ring { - r.mu.Lock() - if r.ring.Value == nil { - r.len.Add(1) - } - r.ring.Value = internalRingItem{Value: value} - r.ring = r.ring.Next() - r.mu.Unlock() + r.TRing.Put(value) return r } // Move moves n % r.Len() elements backward (n < 0) or forward (n >= 0) // in the ring and returns that ring element. r must not be empty. func (r *Ring) Move(n int) *Ring { - r.mu.Lock() - r.ring = r.ring.Move(n) - r.mu.Unlock() + r.TRing.Move(n) return r } // Prev returns the previous ring element. r must not be empty. func (r *Ring) Prev() *Ring { - r.mu.Lock() - r.ring = r.ring.Prev() - r.mu.Unlock() + r.TRing.Prev() return r } // Next returns the next ring element. r must not be empty. func (r *Ring) Next() *Ring { - r.mu.Lock() - r.ring = r.ring.Next() - r.mu.Unlock() + r.TRing.Next() return r } @@ -160,13 +89,7 @@ func (r *Ring) Next() *Ring { // after r. The result points to the element following the // last element of s after insertion. func (r *Ring) Link(s *Ring) *Ring { - r.mu.Lock() - s.mu.Lock() - r.ring.Link(s.ring) - s.mu.Unlock() - r.mu.Unlock() - r.dirty.Set(true) - s.dirty.Set(true) + r.TRing.Link(s.TRing) return r } @@ -174,78 +97,31 @@ func (r *Ring) Link(s *Ring) *Ring { // at r.Next(). If n % r.Len() == 0, r remains unchanged. // The result is the removed sub-ring. r must not be empty. func (r *Ring) Unlink(n int) *Ring { - r.mu.Lock() - resultRing := r.ring.Unlink(n) - r.dirty.Set(true) - r.mu.Unlock() - resultGRing := New(resultRing.Len()) - resultGRing.ring = resultRing - resultGRing.dirty.Set(true) - return resultGRing + return &Ring{ + TRing: r.TRing.Unlink(n), + } } // RLockIteratorNext iterates and locks reading forward // with given callback function `f` within RWMutex.RLock. // If `f` returns true, then it continues iterating; or false to stop. func (r *Ring) RLockIteratorNext(f func(value any) bool) { - r.mu.RLock() - defer r.mu.RUnlock() - if r.ring.Value != nil && !f(r.ring.Value.(internalRingItem).Value) { - return - } - for p := r.ring.Next(); p != r.ring; p = p.Next() { - if p.Value == nil || !f(p.Value.(internalRingItem).Value) { - break - } - } + r.TRing.RLockIteratorNext(f) } -// RLockIteratorPrev iterates and locks writing backward +// RLockIteratorPrev iterates and locks reading backward // with given callback function `f` within RWMutex.RLock. // If `f` returns true, then it continues iterating; or false to stop. func (r *Ring) RLockIteratorPrev(f func(value any) bool) { - r.mu.RLock() - defer r.mu.RUnlock() - if r.ring.Value != nil && !f(r.ring.Value.(internalRingItem).Value) { - return - } - for p := r.ring.Prev(); p != r.ring; p = p.Prev() { - if p.Value == nil || !f(p.Value.(internalRingItem).Value) { - break - } - } + r.TRing.RLockIteratorPrev(f) } // SliceNext returns a copy of all item values as slice forward from current position. func (r *Ring) SliceNext() []any { - s := make([]any, 0) - r.mu.RLock() - if r.ring.Value != nil { - s = append(s, r.ring.Value.(internalRingItem).Value) - } - for p := r.ring.Next(); p != r.ring; p = p.Next() { - if p.Value == nil { - break - } - s = append(s, p.Value.(internalRingItem).Value) - } - r.mu.RUnlock() - return s + return r.TRing.SliceNext() } // SlicePrev returns a copy of all item values as slice backward from current position. func (r *Ring) SlicePrev() []any { - s := make([]any, 0) - r.mu.RLock() - if r.ring.Value != nil { - s = append(s, r.ring.Value.(internalRingItem).Value) - } - for p := r.ring.Prev(); p != r.ring; p = p.Prev() { - if p.Value == nil { - break - } - s = append(s, p.Value.(internalRingItem).Value) - } - r.mu.RUnlock() - return s + return r.TRing.SlicePrev() } diff --git a/container/gring/gring_t.go b/container/gring/gring_t.go new file mode 100644 index 00000000000..1926f2a7f28 --- /dev/null +++ b/container/gring/gring_t.go @@ -0,0 +1,244 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gring + +import ( + "container/ring" + + "github.com/gogf/gf/v2/container/gtype" + "github.com/gogf/gf/v2/internal/rwmutex" +) + +// TRing is a struct of ring structure. +type TRing[T any] struct { + mu *rwmutex.RWMutex + ring *ring.Ring // Underlying ring. + len *gtype.Int // Length(already used size). + cap *gtype.Int // Capability(>=len). + dirty *gtype.Bool // Dirty, which means the len and cap should be recalculated. It's marked dirty when the size of ring changes. +} + +// internalTRingItem[T] stores the ring element value. +type internalTRingItem[T any] struct { + Value T +} + +// NewTRing creates and returns a Ring structure of `cap` elements. +// The optional parameter `safe` specifies whether using this structure in concurrent safety, +// which is false in default. +func NewTRing[T any](cap int, safe ...bool) *TRing[T] { + return &TRing[T]{ + mu: rwmutex.New(safe...), + ring: ring.New(cap), + len: gtype.NewInt(), + cap: gtype.NewInt(cap), + dirty: gtype.NewBool(), + } +} + +// Val returns the item's value of current position. +func (r *TRing[T]) Val() T { + var value T + r.mu.RLock() + if r.ring.Value != nil { + value = r.ring.Value.(internalTRingItem[T]).Value + } + r.mu.RUnlock() + return value +} + +// Len returns the size of ring. +func (r *TRing[T]) Len() int { + r.checkAndUpdateLenAndCap() + return r.len.Val() +} + +// Cap returns the capacity of ring. +func (r *TRing[T]) Cap() int { + r.checkAndUpdateLenAndCap() + return r.cap.Val() +} + +// Checks and updates the len and cap of ring when ring is dirty. +func (r *TRing[T]) checkAndUpdateLenAndCap() { + if !r.dirty.Val() { + return + } + r.mu.RLock() + defer r.mu.RUnlock() + totalLen := 0 + emptyLen := 0 + if r.ring != nil { + if r.ring.Value == nil { + emptyLen++ + } + totalLen++ + for p := r.ring.Next(); p != r.ring; p = p.Next() { + if p.Value == nil { + emptyLen++ + } + totalLen++ + } + } + r.cap.Set(totalLen) + r.len.Set(totalLen - emptyLen) + r.dirty.Set(false) +} + +// Set sets value to the item of current position. +func (r *TRing[T]) Set(value T) *TRing[T] { + r.mu.Lock() + if r.ring.Value == nil { + r.len.Add(1) + } + r.ring.Value = internalTRingItem[T]{Value: value} + r.mu.Unlock() + return r +} + +// Put sets `value` to current item of ring and moves position to next item. +func (r *TRing[T]) Put(value T) *TRing[T] { + r.mu.Lock() + if r.ring.Value == nil { + r.len.Add(1) + } + r.ring.Value = internalTRingItem[T]{Value: value} + r.ring = r.ring.Next() + r.mu.Unlock() + return r +} + +// Move moves n % r.Len() elements backward (n < 0) or forward (n >= 0) +// in the ring and returns that ring element. r must not be empty. +func (r *TRing[T]) Move(n int) *TRing[T] { + r.mu.Lock() + r.ring = r.ring.Move(n) + r.mu.Unlock() + return r +} + +// Prev returns the previous ring element. r must not be empty. +func (r *TRing[T]) Prev() *TRing[T] { + r.mu.Lock() + r.ring = r.ring.Prev() + r.mu.Unlock() + return r +} + +// Next returns the next ring element. r must not be empty. +func (r *TRing[T]) Next() *TRing[T] { + r.mu.Lock() + r.ring = r.ring.Next() + r.mu.Unlock() + return r +} + +// Link connects ring r with ring s such that r.Next() +// becomes s and returns the original value for r.Next(). +// r must not be empty. +// +// If r and s point to the same ring, linking +// them removes the elements between r and s from the ring. +// The removed elements form a sub-ring and the result is a +// reference to that sub-ring (if no elements were removed, +// the result is still the original value for r.Next(), +// and not nil). +// +// If r and s point to different rings, linking +// them creates a single ring with the elements of s inserted +// after r. The result points to the element following the +// last element of s after insertion. +func (r *TRing[T]) Link(s *TRing[T]) *TRing[T] { + r.mu.Lock() + s.mu.Lock() + r.ring.Link(s.ring) + s.mu.Unlock() + r.mu.Unlock() + r.dirty.Set(true) + s.dirty.Set(true) + return r +} + +// Unlink removes n % r.Len() elements from the ring r, starting +// at r.Next(). If n % r.Len() == 0, r remains unchanged. +// The result is the removed sub-ring. r must not be empty. +func (r *TRing[T]) Unlink(n int) *TRing[T] { + r.mu.Lock() + resultRing := r.ring.Unlink(n) + r.dirty.Set(true) + r.mu.Unlock() + resultGRing := NewTRing[T](resultRing.Len()) + resultGRing.ring = resultRing + resultGRing.dirty.Set(true) + return resultGRing +} + +// RLockIteratorNext iterates and locks reading forward +// with given callback function `f` within RWMutex.RLock. +// If `f` returns true, then it continues iterating; or false to stop. +func (r *TRing[T]) RLockIteratorNext(f func(value T) bool) { + r.mu.RLock() + defer r.mu.RUnlock() + if r.ring.Value != nil && !f(r.ring.Value.(internalTRingItem[T]).Value) { + return + } + for p := r.ring.Next(); p != r.ring; p = p.Next() { + if p.Value == nil || !f(p.Value.(internalTRingItem[T]).Value) { + break + } + } +} + +// RLockIteratorPrev iterates and locks reading backward +// with given callback function `f` within RWMutex.RLock. +// If `f` returns true, then it continues iterating; or false to stop. +func (r *TRing[T]) RLockIteratorPrev(f func(value T) bool) { + r.mu.RLock() + defer r.mu.RUnlock() + if r.ring.Value != nil && !f(r.ring.Value.(internalTRingItem[T]).Value) { + return + } + for p := r.ring.Prev(); p != r.ring; p = p.Prev() { + if p.Value == nil || !f(p.Value.(internalTRingItem[T]).Value) { + break + } + } +} + +// SliceNext returns a copy of all item values as slice forward from current position. +func (r *TRing[T]) SliceNext() []T { + s := make([]T, 0, r.Len()) + r.mu.RLock() + if r.ring.Value != nil { + s = append(s, r.ring.Value.(internalTRingItem[T]).Value) + } + for p := r.ring.Next(); p != r.ring; p = p.Next() { + if p.Value == nil { + break + } + s = append(s, p.Value.(internalTRingItem[T]).Value) + } + r.mu.RUnlock() + return s +} + +// SlicePrev returns a copy of all item values as slice backward from current position. +func (r *TRing[T]) SlicePrev() []T { + s := make([]T, 0, r.Len()) + r.mu.RLock() + if r.ring.Value != nil { + s = append(s, r.ring.Value.(internalTRingItem[T]).Value) + } + for p := r.ring.Prev(); p != r.ring; p = p.Prev() { + if p.Value == nil { + break + } + s = append(s, p.Value.(internalTRingItem[T]).Value) + } + r.mu.RUnlock() + return s +} diff --git a/container/gring/gring_z_unit_test.go b/container/gring/gring_z_unit_test.go index 4f3c847e9a7..9e861734e33 100644 --- a/container/gring/gring_z_unit_test.go +++ b/container/gring/gring_z_unit_test.go @@ -148,14 +148,11 @@ func Test_Issue1394(t *testing.T) { for i := 0; i < 10; i++ { gRing.Put(i) } - t.Logf("the length:%d", gRing.Len()) gRingResult := gRing.Unlink(6) for i := 0; i < 10; i++ { t.Log(gRing.Val()) gRing = gRing.Next() } - t.Logf("the ring length:%d", gRing.Len()) - t.Logf("the result length:%d", gRingResult.Len()) // stdring stdRing := ring.New(10) @@ -163,14 +160,11 @@ func Test_Issue1394(t *testing.T) { stdRing.Value = i stdRing = stdRing.Next() } - t.Logf("the length:%d", stdRing.Len()) stdRingResult := stdRing.Unlink(6) for i := 0; i < 10; i++ { t.Log(stdRing.Value) stdRing = stdRing.Next() } - t.Logf("the ring length:%d", stdRing.Len()) - t.Logf("the result length:%d", stdRingResult.Len()) // Assertion. t.Assert(gRing.Len(), stdRing.Len())