ipld-eth-server/vendor/gopkg.in/karalabe/cookiejar.v2/collections/deque/deque.go

142 lines
4.1 KiB
Go
Raw Normal View History

// CookieJar - A contestant's algorithm toolbox
// Copyright (c) 2013 Peter Szilagyi. All rights reserved.
//
// CookieJar is dual licensed: use of this source code is governed by a BSD
// license that can be found in the LICENSE file. Alternatively, the CookieJar
// toolbox may be used in accordance with the terms and conditions contained
// in a signed written agreement between you and the author(s).
// Package deque implements a double ended queue supporting arbitrary types
// (even a mixture).
//
// Internally it uses a dynamically growing circular slice of blocks, resulting
// in faster resizes than a simple dynamic array/slice would allow, yet less gc
// overhead.
package deque
// The size of a block of data
const blockSize = 4096
// Double ended queue data structure.
type Deque struct {
leftIdx int
leftOff int
rightIdx int
rightOff int
blocks [][]interface{}
left []interface{}
right []interface{}
}
// Creates a new, empty deque.
func New() *Deque {
result := new(Deque)
result.blocks = [][]interface{}{make([]interface{}, blockSize)}
result.right = result.blocks[0]
result.left = result.blocks[0]
return result
}
// Pushes a new element into the queue from the right, expanding it if necessary.
func (d *Deque) PushRight(data interface{}) {
d.right[d.rightOff] = data
d.rightOff++
if d.rightOff == blockSize {
d.rightOff = 0
d.rightIdx = (d.rightIdx + 1) % len(d.blocks)
// If we wrapped over to the left, insert a new block and update indices
if d.rightIdx == d.leftIdx {
buffer := make([][]interface{}, len(d.blocks)+1)
copy(buffer[:d.rightIdx], d.blocks[:d.rightIdx])
buffer[d.rightIdx] = make([]interface{}, blockSize)
copy(buffer[d.rightIdx+1:], d.blocks[d.rightIdx:])
d.blocks = buffer
d.leftIdx++
d.left = d.blocks[d.leftIdx]
}
d.right = d.blocks[d.rightIdx]
}
}
// Pops out an element from the queue from the right. Note, no bounds checking are done.
func (d *Deque) PopRight() (res interface{}) {
d.rightOff--
if d.rightOff < 0 {
d.rightOff = blockSize - 1
d.rightIdx = (d.rightIdx - 1 + len(d.blocks)) % len(d.blocks)
d.right = d.blocks[d.rightIdx]
}
res, d.right[d.rightOff] = d.right[d.rightOff], nil
return
}
// Returns the rightmost element from the deque. No bounds are checked.
func (d *Deque) Right() interface{} {
if d.rightOff > 0 {
return d.right[d.rightOff-1]
} else {
return d.blocks[(d.rightIdx-1+len(d.blocks))%len(d.blocks)][blockSize-1]
}
}
// Pushes a new element into the queue from the left, expanding it if necessary.
func (d *Deque) PushLeft(data interface{}) {
d.leftOff--
if d.leftOff < 0 {
d.leftOff = blockSize - 1
d.leftIdx = (d.leftIdx - 1 + len(d.blocks)) % len(d.blocks)
// If we wrapped over to the right, insert a new block and update indices
if d.leftIdx == d.rightIdx {
d.leftIdx++
buffer := make([][]interface{}, len(d.blocks)+1)
copy(buffer[:d.leftIdx], d.blocks[:d.leftIdx])
buffer[d.leftIdx] = make([]interface{}, blockSize)
copy(buffer[d.leftIdx+1:], d.blocks[d.leftIdx:])
d.blocks = buffer
}
d.left = d.blocks[d.leftIdx]
}
d.left[d.leftOff] = data
}
// Pops out an element from the queue from the left. Note, no bounds checking are done.
func (d *Deque) PopLeft() (res interface{}) {
res, d.left[d.leftOff] = d.left[d.leftOff], nil
d.leftOff++
if d.leftOff == blockSize {
d.leftOff = 0
d.leftIdx = (d.leftIdx + 1) % len(d.blocks)
d.left = d.blocks[d.leftIdx]
}
return
}
// Returns the leftmost element from the deque. No bounds are checked.
func (d *Deque) Left() interface{} {
return d.left[d.leftOff]
}
// Checks whether the queue is empty.
func (d *Deque) Empty() bool {
return d.leftIdx == d.rightIdx && d.leftOff == d.rightOff
}
// Returns the number of elements in the queue.
func (d *Deque) Size() int {
if d.rightIdx > d.leftIdx {
return (d.rightIdx-d.leftIdx)*blockSize - d.leftOff + d.rightOff
} else if d.rightIdx < d.leftIdx {
return (len(d.blocks)-d.leftIdx+d.rightIdx)*blockSize - d.leftOff + d.rightOff
} else {
return d.rightOff - d.leftOff
}
}
// Clears out the contents of the queue.
func (d *Deque) Reset() {
*d = *New()
}