mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
add TRing --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: hailaz <739476267@qq.com>
245 lines
6.3 KiB
Go
245 lines
6.3 KiB
Go
// 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
|
|
}
|