github.com/wangyougui/gf/v2@v2.6.5/container/gring/gring.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/wangyougui/gf.
     6  
     7  // Package gring provides a concurrent-safe/unsafe ring(circular lists).
     8  package gring
     9  
    10  import (
    11  	"container/ring"
    12  
    13  	"github.com/wangyougui/gf/v2/container/gtype"
    14  	"github.com/wangyougui/gf/v2/internal/rwmutex"
    15  )
    16  
    17  // Ring is a struct of ring structure.
    18  type Ring struct {
    19  	mu    *rwmutex.RWMutex
    20  	ring  *ring.Ring  // Underlying ring.
    21  	len   *gtype.Int  // Length(already used size).
    22  	cap   *gtype.Int  // Capability(>=len).
    23  	dirty *gtype.Bool // Dirty, which means the len and cap should be recalculated. It's marked dirty when the size of ring changes.
    24  }
    25  
    26  // internalRingItem stores the ring element value.
    27  type internalRingItem struct {
    28  	Value interface{}
    29  }
    30  
    31  // New creates and returns a Ring structure of `cap` elements.
    32  // The optional parameter `safe` specifies whether using this structure in concurrent safety,
    33  // which is false in default.
    34  func New(cap int, safe ...bool) *Ring {
    35  	return &Ring{
    36  		mu:    rwmutex.New(safe...),
    37  		ring:  ring.New(cap),
    38  		len:   gtype.NewInt(),
    39  		cap:   gtype.NewInt(cap),
    40  		dirty: gtype.NewBool(),
    41  	}
    42  }
    43  
    44  // Val returns the item's value of current position.
    45  func (r *Ring) Val() interface{} {
    46  	var value interface{}
    47  	r.mu.RLock()
    48  	if r.ring.Value != nil {
    49  		value = r.ring.Value.(internalRingItem).Value
    50  	}
    51  	r.mu.RUnlock()
    52  	return value
    53  }
    54  
    55  // Len returns the size of ring.
    56  func (r *Ring) Len() int {
    57  	r.checkAndUpdateLenAndCap()
    58  	return r.len.Val()
    59  }
    60  
    61  // Cap returns the capacity of ring.
    62  func (r *Ring) Cap() int {
    63  	r.checkAndUpdateLenAndCap()
    64  	return r.cap.Val()
    65  }
    66  
    67  // Checks and updates the len and cap of ring when ring is dirty.
    68  func (r *Ring) checkAndUpdateLenAndCap() {
    69  	if !r.dirty.Val() {
    70  		return
    71  	}
    72  	r.mu.RLock()
    73  	defer r.mu.RUnlock()
    74  	totalLen := 0
    75  	emptyLen := 0
    76  	if r.ring != nil {
    77  		if r.ring.Value == nil {
    78  			emptyLen++
    79  		}
    80  		totalLen++
    81  		for p := r.ring.Next(); p != r.ring; p = p.Next() {
    82  			if p.Value == nil {
    83  				emptyLen++
    84  			}
    85  			totalLen++
    86  		}
    87  	}
    88  	r.cap.Set(totalLen)
    89  	r.len.Set(totalLen - emptyLen)
    90  	r.dirty.Set(false)
    91  }
    92  
    93  // Set sets value to the item of current position.
    94  func (r *Ring) Set(value interface{}) *Ring {
    95  	r.mu.Lock()
    96  	if r.ring.Value == nil {
    97  		r.len.Add(1)
    98  	}
    99  	r.ring.Value = internalRingItem{Value: value}
   100  	r.mu.Unlock()
   101  	return r
   102  }
   103  
   104  // Put sets `value` to current item of ring and moves position to next item.
   105  func (r *Ring) Put(value interface{}) *Ring {
   106  	r.mu.Lock()
   107  	if r.ring.Value == nil {
   108  		r.len.Add(1)
   109  	}
   110  	r.ring.Value = internalRingItem{Value: value}
   111  	r.ring = r.ring.Next()
   112  	r.mu.Unlock()
   113  	return r
   114  }
   115  
   116  // Move moves n % r.Len() elements backward (n < 0) or forward (n >= 0)
   117  // in the ring and returns that ring element. r must not be empty.
   118  func (r *Ring) Move(n int) *Ring {
   119  	r.mu.Lock()
   120  	r.ring = r.ring.Move(n)
   121  	r.mu.Unlock()
   122  	return r
   123  }
   124  
   125  // Prev returns the previous ring element. r must not be empty.
   126  func (r *Ring) Prev() *Ring {
   127  	r.mu.Lock()
   128  	r.ring = r.ring.Prev()
   129  	r.mu.Unlock()
   130  	return r
   131  }
   132  
   133  // Next returns the next ring element. r must not be empty.
   134  func (r *Ring) Next() *Ring {
   135  	r.mu.Lock()
   136  	r.ring = r.ring.Next()
   137  	r.mu.Unlock()
   138  	return r
   139  }
   140  
   141  // Link connects ring r with ring s such that r.Next()
   142  // becomes s and returns the original value for r.Next().
   143  // r must not be empty.
   144  //
   145  // If r and s point to the same ring, linking
   146  // them removes the elements between r and s from the ring.
   147  // The removed elements form a sub-ring and the result is a
   148  // reference to that sub-ring (if no elements were removed,
   149  // the result is still the original value for r.Next(),
   150  // and not nil).
   151  //
   152  // If r and s point to different rings, linking
   153  // them creates a single ring with the elements of s inserted
   154  // after r. The result points to the element following the
   155  // last element of s after insertion.
   156  func (r *Ring) Link(s *Ring) *Ring {
   157  	r.mu.Lock()
   158  	s.mu.Lock()
   159  	r.ring.Link(s.ring)
   160  	s.mu.Unlock()
   161  	r.mu.Unlock()
   162  	r.dirty.Set(true)
   163  	s.dirty.Set(true)
   164  	return r
   165  }
   166  
   167  // Unlink removes n % r.Len() elements from the ring r, starting
   168  // at r.Next(). If n % r.Len() == 0, r remains unchanged.
   169  // The result is the removed sub-ring. r must not be empty.
   170  func (r *Ring) Unlink(n int) *Ring {
   171  	r.mu.Lock()
   172  	resultRing := r.ring.Unlink(n)
   173  	r.dirty.Set(true)
   174  	r.mu.Unlock()
   175  	resultGRing := New(resultRing.Len())
   176  	resultGRing.ring = resultRing
   177  	resultGRing.dirty.Set(true)
   178  	return resultGRing
   179  }
   180  
   181  // RLockIteratorNext iterates and locks reading forward
   182  // with given callback function `f` within RWMutex.RLock.
   183  // If `f` returns true, then it continues iterating; or false to stop.
   184  func (r *Ring) RLockIteratorNext(f func(value interface{}) bool) {
   185  	r.mu.RLock()
   186  	defer r.mu.RUnlock()
   187  	if r.ring.Value != nil && !f(r.ring.Value.(internalRingItem).Value) {
   188  		return
   189  	}
   190  	for p := r.ring.Next(); p != r.ring; p = p.Next() {
   191  		if p.Value == nil || !f(p.Value.(internalRingItem).Value) {
   192  			break
   193  		}
   194  	}
   195  }
   196  
   197  // RLockIteratorPrev iterates and locks writing backward
   198  // with given callback function `f` within RWMutex.RLock.
   199  // If `f` returns true, then it continues iterating; or false to stop.
   200  func (r *Ring) RLockIteratorPrev(f func(value interface{}) bool) {
   201  	r.mu.RLock()
   202  	defer r.mu.RUnlock()
   203  	if r.ring.Value != nil && !f(r.ring.Value.(internalRingItem).Value) {
   204  		return
   205  	}
   206  	for p := r.ring.Prev(); p != r.ring; p = p.Prev() {
   207  		if p.Value == nil || !f(p.Value.(internalRingItem).Value) {
   208  			break
   209  		}
   210  	}
   211  }
   212  
   213  // SliceNext returns a copy of all item values as slice forward from current position.
   214  func (r *Ring) SliceNext() []interface{} {
   215  	s := make([]interface{}, 0)
   216  	r.mu.RLock()
   217  	if r.ring.Value != nil {
   218  		s = append(s, r.ring.Value.(internalRingItem).Value)
   219  	}
   220  	for p := r.ring.Next(); p != r.ring; p = p.Next() {
   221  		if p.Value == nil {
   222  			break
   223  		}
   224  		s = append(s, p.Value.(internalRingItem).Value)
   225  	}
   226  	r.mu.RUnlock()
   227  	return s
   228  }
   229  
   230  // SlicePrev returns a copy of all item values as slice backward from current position.
   231  func (r *Ring) SlicePrev() []interface{} {
   232  	s := make([]interface{}, 0)
   233  	r.mu.RLock()
   234  	if r.ring.Value != nil {
   235  		s = append(s, r.ring.Value.(internalRingItem).Value)
   236  	}
   237  	for p := r.ring.Prev(); p != r.ring; p = p.Prev() {
   238  		if p.Value == nil {
   239  			break
   240  		}
   241  		s = append(s, p.Value.(internalRingItem).Value)
   242  	}
   243  	r.mu.RUnlock()
   244  	return s
   245  }