queue.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // Copyright (c) 2013-2017, Peter H. Froehlich. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license
  3. // that can be found in the LICENSE file.
  4. // Package queue implements a double-ended queue abstraction on
  5. // top of a slice/array. All operations are constant time except
  6. // for PushFront and PushBack which are amortized constant time.
  7. //
  8. // We are almost twice as fast as container/list at the price of
  9. // potentially wasting some memory because we grow by doubling.
  10. // We are also faster than Go's channels by a smaller margin.
  11. package queue
  12. import (
  13. "bytes"
  14. "fmt"
  15. )
  16. // Queue represents a double-ended queue.
  17. // The zero value for Queue is an empty queue ready to use.
  18. type Queue struct {
  19. // PushBack writes to rep[back] and then increments
  20. // back; PushFront decrements front and then writes
  21. // to rep[front]; len(rep) must be a power of two;
  22. // gotta love those invariants.
  23. rep []interface{}
  24. front int
  25. back int
  26. length int
  27. }
  28. // New returns an initialized empty queue.
  29. func New() *Queue {
  30. return new(Queue).Init()
  31. }
  32. // Init initializes or clears queue q.
  33. func (q *Queue) Init() *Queue {
  34. q.rep = make([]interface{}, 1)
  35. // I considered reusing the existing slice if all a client does
  36. // is re-initialize the queue. The problem is that the current
  37. // queue might be huge, but the next one might not grow much. So
  38. // we'd hold on to a huge chunk of memory for just a few elements
  39. // and nobody can do anything. Making a new slice and letting the
  40. // GC take care of the old one seems like a better tradeoff.
  41. q.front, q.back, q.length = 0, 0, 0
  42. return q
  43. }
  44. // lazyInit lazily initializes a zero Queue value.
  45. //
  46. // I am mostly doing this because container/list does the same thing.
  47. // Personally I think it's a little wasteful because every single
  48. // PushFront/PushBack is going to pay the overhead of calling this.
  49. // But that's the price for making zero values useful immediately,
  50. // something Go folks apparently like a lot.
  51. func (q *Queue) lazyInit() {
  52. if q.rep == nil {
  53. q.Init()
  54. }
  55. }
  56. // Len returns the number of elements of queue q.
  57. func (q *Queue) Len() int {
  58. return q.length
  59. }
  60. // empty returns true if the queue q has no elements.
  61. func (q *Queue) empty() bool {
  62. return q.length == 0
  63. }
  64. // full returns true if the queue q is at capacity.
  65. func (q *Queue) full() bool {
  66. return q.length == len(q.rep)
  67. }
  68. // grow doubles the size of queue q's underlying slice/array.
  69. func (q *Queue) grow() {
  70. bigger := make([]interface{}, q.length*2)
  71. // Kudos to Rodrigo Moraes, see https://gist.github.com/moraes/2141121
  72. // Kudos to Dariusz Górecki, see https://github.com/eapache/queue/commit/334cc1b02398be651373851653017e6cbf588f9e
  73. n := copy(bigger, q.rep[q.front:])
  74. copy(bigger[n:], q.rep[:q.front])
  75. // The above replaced the "obvious" for loop and is a bit tricky.
  76. // First note that q.front == q.back if we're full; if that wasn't
  77. // true, things would be more complicated. Second recall that for
  78. // a slice [lo:hi] the lo bound is inclusive whereas the hi bound
  79. // is exclusive. If that doesn't convince you that the above works
  80. // maybe drawing out some pictures for a concrete example will?
  81. q.rep = bigger
  82. q.front = 0
  83. q.back = q.length
  84. }
  85. // lazyGrow grows the underlying slice/array if necessary.
  86. func (q *Queue) lazyGrow() {
  87. if q.full() {
  88. q.grow()
  89. }
  90. }
  91. // String returns a string representation of queue q formatted
  92. // from front to back.
  93. func (q *Queue) String() string {
  94. var result bytes.Buffer
  95. result.WriteString("[")
  96. j := q.front
  97. for i := 0; i < q.length; i++ {
  98. result.WriteString(fmt.Sprintf("%v", q.rep[j]))
  99. if i < q.length-1 {
  100. result.WriteRune(' ')
  101. }
  102. j = q.inc(j)
  103. }
  104. result.WriteString("]")
  105. return result.String()
  106. }
  107. // inc returns the next integer position wrapping around queue q.
  108. func (q *Queue) inc(i int) int {
  109. return (i + 1) & (len(q.rep) - 1) // requires l = 2^n
  110. }
  111. // dec returns the previous integer position wrapping around queue q.
  112. func (q *Queue) dec(i int) int {
  113. return (i - 1) & (len(q.rep) - 1) // requires l = 2^n
  114. }
  115. // Front returns the first element of queue q or nil.
  116. func (q *Queue) Front() interface{} {
  117. if q.empty() {
  118. return nil
  119. }
  120. return q.rep[q.front]
  121. }
  122. // Back returns the last element of queue q or nil.
  123. func (q *Queue) Back() interface{} {
  124. if q.empty() {
  125. return nil
  126. }
  127. return q.rep[q.dec(q.back)]
  128. }
  129. // PushFront inserts a new value v at the front of queue q.
  130. func (q *Queue) PushFront(v interface{}) {
  131. q.lazyInit()
  132. q.lazyGrow()
  133. q.front = q.dec(q.front)
  134. q.rep[q.front] = v
  135. q.length++
  136. }
  137. // PushBack inserts a new value v at the back of queue q.
  138. func (q *Queue) PushBack(v interface{}) {
  139. q.lazyInit()
  140. q.lazyGrow()
  141. q.rep[q.back] = v
  142. q.back = q.inc(q.back)
  143. q.length++
  144. }
  145. // Both PopFront and PopBack set the newly free slot to nil
  146. // in an attempt to be nice to the garbage collector.
  147. // PopFront removes and returns the first element of queue q or nil.
  148. func (q *Queue) PopFront() interface{} {
  149. if q.empty() {
  150. return nil
  151. }
  152. v := q.rep[q.front]
  153. q.rep[q.front] = nil
  154. q.front = q.inc(q.front)
  155. q.length--
  156. return v
  157. }
  158. // PopBack removes and returns the last element of queue q or nil.
  159. func (q *Queue) PopBack() interface{} {
  160. if q.empty() {
  161. return nil
  162. }
  163. q.back = q.dec(q.back)
  164. v := q.rep[q.back]
  165. q.rep[q.back] = nil
  166. q.length--
  167. return v
  168. }