142 lines
4.1 KiB
Go
142 lines
4.1 KiB
Go
|
// 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()
|
||
|
}
|