improve package gring; remove function LockIteratorNext/LockIteratorPrev from package gring

This commit is contained in:
John Guo 2021-09-14 20:15:21 +08:00
parent 727f58a24b
commit cc08ceb797
2 changed files with 47 additions and 162 deletions

View File

@ -23,6 +23,11 @@ type Ring struct {
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 interface{}
}
// New 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.
@ -38,10 +43,13 @@ func New(cap int, safe ...bool) *Ring {
// Val returns the item's value of current position.
func (r *Ring) Val() interface{} {
var value interface{}
r.mu.RLock()
v := r.ring.Value
if r.ring.Value != nil {
value = r.ring.Value.(internalRingItem).Value
}
r.mu.RUnlock()
return v
return value
}
// Len returns the size of ring.
@ -61,17 +69,21 @@ func (r *Ring) checkAndUpdateLenAndCap() {
if !r.dirty.Val() {
return
}
r.mu.RLock()
defer r.mu.RUnlock()
totalLen := 0
emptyLen := 0
if r.ring != nil {
r.mu.RLock()
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.mu.RUnlock()
}
r.cap.Set(totalLen)
r.len.Set(totalLen - emptyLen)
@ -84,18 +96,18 @@ func (r *Ring) Set(value interface{}) *Ring {
if r.ring.Value == nil {
r.len.Add(1)
}
r.ring.Value = value
r.ring.Value = internalRingItem{Value: value}
r.mu.Unlock()
return r
}
// Put sets <value> to current item of ring and moves position to next item.
// Put sets `value` to current item of ring and moves position to next item.
func (r *Ring) Put(value interface{}) *Ring {
r.mu.Lock()
if r.ring.Value == nil {
r.len.Add(1)
}
r.ring.Value = value
r.ring.Value = internalRingItem{Value: value}
r.ring = r.ring.Next()
r.mu.Unlock()
return r
@ -132,8 +144,8 @@ func (r *Ring) Next() *Ring {
//
// 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 subring and the result is a
// reference to that subring (if no elements were removed,
// 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).
//
@ -155,7 +167,7 @@ func (r *Ring) Link(s *Ring) *Ring {
// 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 subring. r must not be empty.
// The result is the removed sub-ring. r must not be empty.
//
func (r *Ring) Unlink(n int) *Ring {
r.mu.Lock()
@ -166,56 +178,24 @@ func (r *Ring) Unlink(n int) *Ring {
}
// 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.
// 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 interface{}) bool) {
r.mu.RLock()
defer r.mu.RUnlock()
if !f(r.ring.Value) {
if r.ring.Value != nil && !f(r.ring.Value.(internalRingItem).Value) {
return
}
for p := r.ring.Next(); p != r.ring; p = p.Next() {
if !f(p.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 *Ring) RLockIteratorPrev(f func(value interface{}) bool) {
r.mu.RLock()
defer r.mu.RUnlock()
if !f(r.ring.Value) {
return
}
for p := r.ring.Prev(); p != r.ring; p = p.Prev() {
if !f(p.Value) {
break
}
}
}
// LockIteratorNext iterates and locks writing forward
// with given callback function <f> within RWMutex.RLock.
// If <f> returns true, then it continues iterating; or false to stop.
func (r *Ring) LockIteratorNext(f func(item *ring.Ring) bool) {
r.mu.RLock()
defer r.mu.RUnlock()
if !f(r.ring) {
return
}
for p := r.ring.Next(); p != r.ring; p = p.Next() {
if !f(p) {
if p.Value == nil || !f(p.Value.(internalRingItem).Value) {
break
}
}
}
// LockIteratorPrev iterates and locks writing backward
// with given callback function <f> within RWMutex.RLock.
// If <f> returns true, then it continues iterating; or false to stop.
// with given callback function `f` within RWMutex.RLock.
// If `f` returns true, then it continues iterating; or false to stop.
func (r *Ring) LockIteratorPrev(f func(item *ring.Ring) bool) {
r.mu.RLock()
defer r.mu.RUnlock()
@ -234,12 +214,13 @@ func (r *Ring) SliceNext() []interface{} {
s := make([]interface{}, 0)
r.mu.RLock()
if r.ring.Value != nil {
s = append(s, r.ring.Value)
s = append(s, r.ring.Value.(internalRingItem).Value)
}
for p := r.ring.Next(); p != r.ring; p = p.Next() {
if p.Value != nil {
s = append(s, p.Value)
if p.Value == nil {
break
}
s = append(s, p.Value.(internalRingItem).Value)
}
r.mu.RUnlock()
return s
@ -250,12 +231,13 @@ func (r *Ring) SlicePrev() []interface{} {
s := make([]interface{}, 0)
r.mu.RLock()
if r.ring.Value != nil {
s = append(s, r.ring.Value)
s = append(s, r.ring.Value.(internalRingItem).Value)
}
for p := r.ring.Prev(); p != r.ring; p = p.Prev() {
if p.Value != nil {
s = append(s, p.Value)
if p.Value == nil {
break
}
s = append(s, p.Value.(internalRingItem).Value)
}
r.mu.RUnlock()
return s

View File

@ -7,7 +7,6 @@
package gring_test
import (
"container/ring"
"testing"
"github.com/gogf/gf/container/gring"
@ -44,6 +43,11 @@ func TestRing_Val(t *testing.T) {
})
}
func TestRing_CapLen(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
r := gring.New(10)
t.Assert(r.Cap(), 10)
t.Assert(r.Len(), 0)
})
gtest.C(t, func(t *gtest.T) {
r := gring.New(10)
r.Put("goframe")
@ -81,22 +85,22 @@ func TestRing_Link(t *testing.T) {
rs := r.Link(s)
t.Assert(rs.Move(2).Val(), "b")
})
}
func TestRing_Unlink(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
r := gring.New(5)
for i := 0; i < 5; i++ {
r.Put(i + 1)
for i := 1; i <= 5; i++ {
r.Put(i)
}
t.Assert(r.Val(), 1)
// 1 2 3 4
// 删除当前位置往后的2个数据返回被删除的数据
// 重新计算s len
s := r.Unlink(2) // 2 3
t.Assert(s.Val(), 2)
t.Assert(s.Len(), 1)
t.Assert(s.Len(), 2)
})
}
@ -120,10 +124,10 @@ func TestRing_Slice(t *testing.T) {
r.Set(nil)
array2 := r.SliceNext() //[4 5 1 2]
//返回当前位置往后不为空的元素数组长度为4
t.Assert(array2, g.Slice{4, 5, 1, 2})
t.Assert(array2, g.Slice{nil, 4, 5, 1, 2})
array3 := r.SlicePrev() //[2 1 5 4]
t.Assert(array3, g.Slice{2, 1, 5, 4})
t.Assert(array3, g.Slice{nil, 2, 1, 5, 4})
s := gring.New(ringLen)
for i := 0; i < ringLen; i++ {
@ -131,106 +135,5 @@ func TestRing_Slice(t *testing.T) {
}
array4 := s.SlicePrev() // []
t.Assert(array4, g.Slice{1, 5, 4, 3, 2})
})
}
func TestRing_RLockIterator(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
ringLen := 5
r := gring.New(ringLen)
//ring不存在有值元素
r.RLockIteratorNext(func(v interface{}) bool {
t.Assert(v, nil)
return false
})
r.RLockIteratorNext(func(v interface{}) bool {
t.Assert(v, nil)
return true
})
r.RLockIteratorPrev(func(v interface{}) bool {
t.Assert(v, nil)
return true
})
for i := 0; i < ringLen; i++ {
r.Put(i + 1)
}
//回调函数返回true,RLockIteratorNext遍历5次,期望值分别是1、2、3、4、5
i := 0
r.RLockIteratorNext(func(v interface{}) bool {
t.Assert(v, i+1)
i++
return true
})
//RLockIteratorPrev遍历1次返回 false,退出遍历
r.RLockIteratorPrev(func(v interface{}) bool {
t.Assert(v, 1)
return false
})
})
}
func TestRing_LockIterator(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
ringLen := 5
r := gring.New(ringLen)
//不存在有值元素
r.LockIteratorNext(func(item *ring.Ring) bool {
t.Assert(item.Value, nil)
return false
})
r.LockIteratorNext(func(item *ring.Ring) bool {
t.Assert(item.Value, nil)
return false
})
r.LockIteratorNext(func(item *ring.Ring) bool {
t.Assert(item.Value, nil)
return true
})
r.LockIteratorPrev(func(item *ring.Ring) bool {
t.Assert(item.Value, nil)
return false
})
r.LockIteratorPrev(func(item *ring.Ring) bool {
t.Assert(item.Value, nil)
return true
})
//ring初始化元素值
for i := 0; i < ringLen; i++ {
r.Put(i + 1)
}
//往后遍历组成数据 [1,2,3,4,5]
array1 := g.Slice{1, 2, 3, 4, 5}
ii := 0
r.LockIteratorNext(func(item *ring.Ring) bool {
//校验每一次遍历取值是否是期望值
t.Assert(item.Value, array1[ii])
ii++
return true
})
//往后取3个元素组成数组
//获得 [1,5,4]
i := 0
a := g.Slice{1, 5, 4}
r.LockIteratorPrev(func(item *ring.Ring) bool {
if i > 2 {
return false
}
t.Assert(item.Value, a[i])
i++
return true
})
})
}