| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- // Copyright (c) 2013, Peter H. Froehlich. All rights reserved.
- // Use of this source code is governed by a BSD-style license
- // that can be found in the LICENSE file.
- // Package queue implements a double-ended queue abstraction on
- // top of a slice/array. All operations are constant time except
- // for PushFront and PushBack which are amortized constant time.
- package queue
- import "fmt"
- // Queue represents a double-ended queue.
- // The zero value for Queue is an empty queue ready to use.
- type Queue struct {
- // PushBack writes to rep[back] and then increments
- // back; PushFront decrements front and then writes
- // to rep[front]; gotta love those invariants.
- rep []interface{}
- front, back, length int
- }
- // New returns an initialized empty queue.
- func New() *Queue {
- return new(Queue).Init()
- }
- // Init initializes or clears queue q.
- func (q *Queue) Init() *Queue {
- // start with a slice of length 2 even if that "wastes"
- // some memory; we do front/back arithmetic modulo the
- // length, so starting at 1 requires special cases
- q.rep = make([]interface{}, 2) // TODO: keep old slice/array? but what if it's huge?
- q.front, q.back, q.length = 0, 0, 0
- return q
- }
- // TODO: good idea? list.go does it but slows down every insertion...
- // I guess that's the price for allowing zero values to be useful?
- func (q *Queue) lazyInit() {
- if q.rep == nil {
- q.Init()
- }
- }
- // Len returns the number of elements of queue q.
- func (q *Queue) Len() int {
- return q.length
- }
- func (q *Queue) empty() bool {
- return q.length == 0
- }
- func (q *Queue) full() bool {
- return q.length == len(q.rep)
- }
- func (q *Queue) grow() {
- big := make([]interface{}, q.length*2)
- j := q.front
- for i := 0; i < q.length; i++ {
- big[i] = q.rep[j]
- q.inc(&j)
- }
- q.rep = big
- q.front = 0
- q.back = q.length
- }
- // TODO: leave this in or not?
- func (q *Queue) String() string {
- result := fmt.Sprintf("(f: %d b: %d l:%d c:%d)", q.front, q.back, q.length, len(q.rep))
- result = result + "["
- j := q.front
- for i := 0; i < q.length; i++ {
- result = result + fmt.Sprintf("[%v]", q.rep[j])
- q.inc(&j)
- }
- result = result + "]"
- return result
- }
- // TODO: convert these two back to proper functions? see ugliness in Back() below
- func (q *Queue) inc(i *int) {
- l := len(q.rep)
- *i = (*i+1+l) % l
- }
- func (q *Queue) dec(i *int) {
- l := len(q.rep)
- *i = (*i-1+l) % l
- }
- // TODO: I dislike the Go philosophy of avoiding panics at all
- // costs; Front/Back/Pop from an empty Queue SHOULD panic! at
- // least in my mind...
- // Front returns the first element of queue q or nil.
- func (q *Queue) Front() interface{} {
- if q.empty() { return nil }
- return q.rep[q.front]
- }
- // Back returns the last element of queue q or nil.
- func (q *Queue) Back() interface{} {
- if q.empty() { return nil }
- b := q.back
- q.dec(&b)
- return q.rep[b]
- }
- // PushFront inserts a new value v at the front of queue q.
- func (q *Queue) PushFront(v interface{}) {
- q.lazyInit() // TODO: keep?
- if q.full() { q.grow() }
- q.dec(&q.front)
- q.rep[q.front] = v
- q.length++
- }
- // PushBack inserts a new value v at the back of queue q.
- func (q *Queue) PushBack(v interface{}) {
- q.lazyInit() // TODO: keep?
- if q.full() { q.grow() }
- q.rep[q.back] = v
- q.inc(&q.back)
- q.length++
- }
- // PopFront removes and returns the first element of queue q or nil.
- func (q *Queue) PopFront() interface{} {
- if q.empty() { return nil }
- v := q.rep[q.front]
- q.rep[q.front] = nil // nice to GC?
- q.inc(&q.front)
- q.length--
- return v
- }
- // PopBack removes and returns the last element of queue q or nil.
- func (q *Queue) PopBack() interface{} {
- if q.empty() { return nil }
- q.dec(&q.back)
- v := q.rep[q.back]
- q.rep[q.back] = nil // nice to GC?
- q.length--
- return v
- }
|