github.com/dubbogo/gost@v1.14.0/container/queue/circular_unbounded_queue.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package gxqueue
    19  
    20  const (
    21  	fastGrowThreshold = 1024
    22  )
    23  
    24  // CircularUnboundedQueue is a circular structure and will grow automatically if it exceeds the capacity.
    25  // CircularUnboundedQueue is not thread-safe.
    26  type CircularUnboundedQueue struct {
    27  	data       []interface{}
    28  	head, tail int
    29  	icap       int // initial capacity
    30  	quota      int // specify the maximum size of the queue, setting to 0 denotes unlimited.
    31  }
    32  
    33  func NewCircularUnboundedQueue(capacity int) *CircularUnboundedQueue {
    34  	return NewCircularUnboundedQueueWithQuota(capacity, 0)
    35  }
    36  
    37  func NewCircularUnboundedQueueWithQuota(capacity, quota int) *CircularUnboundedQueue {
    38  	if capacity < 0 {
    39  		panic("capacity should be greater than zero")
    40  	}
    41  	if quota < 0 {
    42  		panic("quota should be greater or equal to zero")
    43  	}
    44  	if quota != 0 && capacity > quota {
    45  		capacity = quota
    46  	}
    47  	return &CircularUnboundedQueue{
    48  		data:  make([]interface{}, capacity+1),
    49  		icap:  capacity,
    50  		quota: quota,
    51  	}
    52  }
    53  
    54  func (q *CircularUnboundedQueue) IsEmpty() bool {
    55  	return q.head == q.tail
    56  }
    57  
    58  func (q *CircularUnboundedQueue) Push(t interface{}) bool {
    59  	if nextTail := (q.tail + 1) % len(q.data); nextTail != q.head {
    60  		q.data[q.tail] = t
    61  		q.tail = nextTail
    62  		return true
    63  	}
    64  
    65  	if q.grow() {
    66  		// grow succeed
    67  		q.data[q.tail] = t
    68  		q.tail = (q.tail + 1) % len(q.data)
    69  		return true
    70  	}
    71  
    72  	return false
    73  }
    74  
    75  func (q *CircularUnboundedQueue) Pop() interface{} {
    76  	if q.IsEmpty() {
    77  		panic("queue has no element")
    78  	}
    79  
    80  	t := q.data[q.head]
    81  	q.head = (q.head + 1) % len(q.data)
    82  
    83  	return t
    84  }
    85  
    86  func (q *CircularUnboundedQueue) Peek() interface{} {
    87  	if q.IsEmpty() {
    88  		panic("queue has no element")
    89  	}
    90  	return q.data[q.head]
    91  }
    92  
    93  func (q *CircularUnboundedQueue) Cap() int {
    94  	return len(q.data) - 1
    95  }
    96  
    97  func (q *CircularUnboundedQueue) Len() int {
    98  	head, tail := q.head, q.tail
    99  	if head > tail {
   100  		tail += len(q.data)
   101  	}
   102  	return tail - head
   103  }
   104  
   105  func (q *CircularUnboundedQueue) Reset() {
   106  	q.data = make([]interface{}, q.icap+1)
   107  	q.head, q.tail = 0, 0
   108  }
   109  
   110  func (q *CircularUnboundedQueue) InitialCap() int {
   111  	return q.icap
   112  }
   113  
   114  func (q *CircularUnboundedQueue) grow() bool {
   115  	oldcap := q.Cap()
   116  	if oldcap == 0 {
   117  		oldcap++
   118  	}
   119  	var newcap int
   120  	if oldcap < fastGrowThreshold {
   121  		newcap = oldcap * 2
   122  	} else {
   123  		newcap = oldcap + oldcap/4
   124  	}
   125  	if q.quota != 0 && newcap > q.quota {
   126  		newcap = q.quota
   127  	}
   128  
   129  	if newcap == q.Cap() {
   130  		return false
   131  	}
   132  
   133  	newdata := make([]interface{}, newcap+1)
   134  	copy(newdata[0:], q.data[q.head:])
   135  	if q.head > q.tail {
   136  		copy(newdata[len(q.data)-q.head:], q.data[:q.head-1])
   137  	}
   138  
   139  	q.head, q.tail = 0, q.Cap()
   140  	q.data = newdata
   141  
   142  	return true
   143  }