github.com/gogf/gf@v1.16.9/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/gogf/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/gogf/gf/container/gtype"
    14  	"github.com/gogf/gf/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  // New creates and returns a Ring structure of <cap> elements.
    27  // The optional parameter <safe> specifies whether using this structure in concurrent safety,
    28  // which is false in default.
    29  func New(cap int, safe ...bool) *Ring {
    30  	return &Ring{
    31  		mu:    rwmutex.New(safe...),
    32  		ring:  ring.New(cap),
    33  		len:   gtype.NewInt(),
    34  		cap:   gtype.NewInt(cap),
    35  		dirty: gtype.NewBool(),
    36  	}
    37  }
    38  
    39  // Val returns the item's value of current position.
    40  func (r *Ring) Val() interface{} {
    41  	r.mu.RLock()
    42  	v := r.ring.Value
    43  	r.mu.RUnlock()
    44  	return v
    45  }
    46  
    47  // Len returns the size of ring.
    48  func (r *Ring) Len() int {
    49  	r.checkAndUpdateLenAndCap()
    50  	return r.len.Val()
    51  }
    52  
    53  // Cap returns the capacity of ring.
    54  func (r *Ring) Cap() int {
    55  	r.checkAndUpdateLenAndCap()
    56  	return r.cap.Val()
    57  }
    58  
    59  // Checks and updates the len and cap of ring when ring is dirty.
    60  func (r *Ring) checkAndUpdateLenAndCap() {
    61  	if !r.dirty.Val() {
    62  		return
    63  	}
    64  	totalLen := 0
    65  	emptyLen := 0
    66  	if r.ring != nil {
    67  		r.mu.RLock()
    68  		for p := r.ring.Next(); p != r.ring; p = p.Next() {
    69  			if p.Value == nil {
    70  				emptyLen++
    71  			}
    72  			totalLen++
    73  		}
    74  		r.mu.RUnlock()
    75  	}
    76  	r.cap.Set(totalLen)
    77  	r.len.Set(totalLen - emptyLen)
    78  	r.dirty.Set(false)
    79  }
    80  
    81  // Set sets value to the item of current position.
    82  func (r *Ring) Set(value interface{}) *Ring {
    83  	r.mu.Lock()
    84  	if r.ring.Value == nil {
    85  		r.len.Add(1)
    86  	}
    87  	r.ring.Value = value
    88  	r.mu.Unlock()
    89  	return r
    90  }
    91  
    92  // Put sets <value> to current item of ring and moves position to next item.
    93  func (r *Ring) Put(value interface{}) *Ring {
    94  	r.mu.Lock()
    95  	if r.ring.Value == nil {
    96  		r.len.Add(1)
    97  	}
    98  	r.ring.Value = value
    99  	r.ring = r.ring.Next()
   100  	r.mu.Unlock()
   101  	return r
   102  }
   103  
   104  // Move moves n % r.Len() elements backward (n < 0) or forward (n >= 0)
   105  // in the ring and returns that ring element. r must not be empty.
   106  func (r *Ring) Move(n int) *Ring {
   107  	r.mu.Lock()
   108  	r.ring = r.ring.Move(n)
   109  	r.mu.Unlock()
   110  	return r
   111  }
   112  
   113  // Prev returns the previous ring element. r must not be empty.
   114  func (r *Ring) Prev() *Ring {
   115  	r.mu.Lock()
   116  	r.ring = r.ring.Prev()
   117  	r.mu.Unlock()
   118  	return r
   119  }
   120  
   121  // Next returns the next ring element. r must not be empty.
   122  func (r *Ring) Next() *Ring {
   123  	r.mu.Lock()
   124  	r.ring = r.ring.Next()
   125  	r.mu.Unlock()
   126  	return r
   127  }
   128  
   129  // Link connects ring r with ring s such that r.Next()
   130  // becomes s and returns the original value for r.Next().
   131  // r must not be empty.
   132  //
   133  // If r and s point to the same ring, linking
   134  // them removes the elements between r and s from the ring.
   135  // The removed elements form a subring and the result is a
   136  // reference to that subring (if no elements were removed,
   137  // the result is still the original value for r.Next(),
   138  // and not nil).
   139  //
   140  // If r and s point to different rings, linking
   141  // them creates a single ring with the elements of s inserted
   142  // after r. The result points to the element following the
   143  // last element of s after insertion.
   144  //
   145  func (r *Ring) Link(s *Ring) *Ring {
   146  	r.mu.Lock()
   147  	s.mu.Lock()
   148  	r.ring.Link(s.ring)
   149  	s.mu.Unlock()
   150  	r.mu.Unlock()
   151  	r.dirty.Set(true)
   152  	s.dirty.Set(true)
   153  	return r
   154  }
   155  
   156  // Unlink removes n % r.Len() elements from the ring r, starting
   157  // at r.Next(). If n % r.Len() == 0, r remains unchanged.
   158  // The result is the removed subring. r must not be empty.
   159  //
   160  func (r *Ring) Unlink(n int) *Ring {
   161  	r.mu.Lock()
   162  	r.ring = r.ring.Unlink(n)
   163  	r.dirty.Set(true)
   164  	r.mu.Unlock()
   165  	return r
   166  }
   167  
   168  // RLockIteratorNext iterates and locks reading forward
   169  // with given callback function <f> within RWMutex.RLock.
   170  // If <f> returns true, then it continues iterating; or false to stop.
   171  func (r *Ring) RLockIteratorNext(f func(value interface{}) bool) {
   172  	r.mu.RLock()
   173  	defer r.mu.RUnlock()
   174  	if !f(r.ring.Value) {
   175  		return
   176  	}
   177  	for p := r.ring.Next(); p != r.ring; p = p.Next() {
   178  		if !f(p.Value) {
   179  			break
   180  		}
   181  	}
   182  }
   183  
   184  // RLockIteratorPrev iterates and locks reading backward
   185  // with given callback function <f> within RWMutex.RLock.
   186  // If <f> returns true, then it continues iterating; or false to stop.
   187  func (r *Ring) RLockIteratorPrev(f func(value interface{}) bool) {
   188  	r.mu.RLock()
   189  	defer r.mu.RUnlock()
   190  	if !f(r.ring.Value) {
   191  		return
   192  	}
   193  	for p := r.ring.Prev(); p != r.ring; p = p.Prev() {
   194  		if !f(p.Value) {
   195  			break
   196  		}
   197  	}
   198  }
   199  
   200  // LockIteratorNext iterates and locks writing forward
   201  // with given callback function <f> within RWMutex.RLock.
   202  // If <f> returns true, then it continues iterating; or false to stop.
   203  func (r *Ring) LockIteratorNext(f func(item *ring.Ring) bool) {
   204  	r.mu.RLock()
   205  	defer r.mu.RUnlock()
   206  	if !f(r.ring) {
   207  		return
   208  	}
   209  	for p := r.ring.Next(); p != r.ring; p = p.Next() {
   210  		if !f(p) {
   211  			break
   212  		}
   213  	}
   214  }
   215  
   216  // LockIteratorPrev iterates and locks writing backward
   217  // with given callback function <f> within RWMutex.RLock.
   218  // If <f> returns true, then it continues iterating; or false to stop.
   219  func (r *Ring) LockIteratorPrev(f func(item *ring.Ring) bool) {
   220  	r.mu.RLock()
   221  	defer r.mu.RUnlock()
   222  	if !f(r.ring) {
   223  		return
   224  	}
   225  	for p := r.ring.Prev(); p != r.ring; p = p.Prev() {
   226  		if !f(p) {
   227  			break
   228  		}
   229  	}
   230  }
   231  
   232  // SliceNext returns a copy of all item values as slice forward from current position.
   233  func (r *Ring) SliceNext() []interface{} {
   234  	s := make([]interface{}, 0)
   235  	r.mu.RLock()
   236  	if r.ring.Value != nil {
   237  		s = append(s, r.ring.Value)
   238  	}
   239  	for p := r.ring.Next(); p != r.ring; p = p.Next() {
   240  		if p.Value != nil {
   241  			s = append(s, p.Value)
   242  		}
   243  	}
   244  	r.mu.RUnlock()
   245  	return s
   246  }
   247  
   248  // SlicePrev returns a copy of all item values as slice backward from current position.
   249  func (r *Ring) SlicePrev() []interface{} {
   250  	s := make([]interface{}, 0)
   251  	r.mu.RLock()
   252  	if r.ring.Value != nil {
   253  		s = append(s, r.ring.Value)
   254  	}
   255  	for p := r.ring.Prev(); p != r.ring; p = p.Prev() {
   256  		if p.Value != nil {
   257  			s = append(s, p.Value)
   258  		}
   259  	}
   260  	r.mu.RUnlock()
   261  	return s
   262  }