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 }