github.com/cloudwego/kitex@v0.9.0/pkg/utils/ring_single.go (about)

     1  /*
     2   * Copyright 2021 CloudWeGo Authors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package utils
    18  
    19  import "sync"
    20  
    21  // ring implements a fixed size ring buffer to manage data
    22  type ring struct {
    23  	l    sync.RWMutex
    24  	arr  []interface{}
    25  	size int
    26  	tail int
    27  	head int
    28  }
    29  
    30  // newRing creates a ringbuffer with fixed size.
    31  func newRing(size int) *ring {
    32  	if size <= 0 {
    33  		// When size is an invalid number, we still return an instance
    34  		// with zero-size to reduce error checks of the callers.
    35  		size = 0
    36  	}
    37  	return &ring{
    38  		arr:  make([]interface{}, size+1),
    39  		size: size,
    40  	}
    41  }
    42  
    43  // Push appends item to the ring.
    44  func (r *ring) Push(i interface{}) error {
    45  	r.l.Lock()
    46  	defer r.l.Unlock()
    47  	if r.isFull() {
    48  		return ErrRingFull
    49  	}
    50  	r.arr[r.head] = i
    51  	r.head = r.inc()
    52  	return nil
    53  }
    54  
    55  // Pop returns the last item and removes it from the ring.
    56  func (r *ring) Pop() interface{} {
    57  	r.l.Lock()
    58  	defer r.l.Unlock()
    59  	if r.isEmpty() {
    60  		return nil
    61  	}
    62  	c := r.arr[r.tail]
    63  	r.arr[r.tail] = nil
    64  	r.tail = r.dec()
    65  	return c
    66  }
    67  
    68  type ringDump struct {
    69  	Array []interface{} `json:"array"`
    70  	Len   int           `json:"len"`
    71  	Cap   int           `json:"cap"`
    72  }
    73  
    74  // Dump dumps the data in the ring.
    75  func (r *ring) Dump(m *ringDump) {
    76  	r.l.RLock()
    77  	defer r.l.RUnlock()
    78  	m.Cap = r.size + 1
    79  	m.Len = (r.head - r.tail + r.size + 1) % (r.size + 1)
    80  	m.Array = make([]interface{}, 0, m.Len)
    81  	for i := 0; i < m.Len; i++ {
    82  		m.Array = append(m.Array, r.arr[(r.tail+i)%(r.size+1)])
    83  	}
    84  }
    85  
    86  func (r *ring) inc() int {
    87  	return (r.head + 1) % (r.size + 1)
    88  }
    89  
    90  func (r *ring) dec() int {
    91  	return (r.tail + 1) % (r.size + 1)
    92  }
    93  
    94  func (r *ring) isEmpty() bool {
    95  	return r.tail == r.head
    96  }
    97  
    98  func (r *ring) isFull() bool {
    99  	return r.inc() == r.tail
   100  }