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 "fmt"
  13. // Queue represents a double-ended queue.
  14. // The zero value for Queue is an empty queue ready to use.
  15. type Queue struct {
  16. // PushBack writes to rep[back] and then increments
  17. // back; PushFront decrements front and then writes
  18. // to rep[front]; len(rep) must be a power of two;
  19. // gotta love those invariants.
  20. rep []interface{}
  21. front int
  22. back int
  23. length int
  24. }
  25. // New returns an initialized empty queue.
  26. func New() *Queue {
  27. return new(Queue).Init()
  28. }
  29. // Init initializes or clears queue q.
  30. func (q *Queue) Init() *Queue {
  31. q.rep = make([]interface{}, 1)
  32. // I considered reusing the existing slice if all a client does
  33. // is re-initialize the queue. The problem is that the current
  34. // queue might be huge, but the next one might not grow much. So
  35. // we'd hold on to a huge chunk of memory for just a few elements
  36. // and nobody can do anything. Making a new slice and letting the
  37. // GC take care of the old one seems like a better tradeoff.
  38. q.front, q.back, q.length = 0, 0, 0
  39. return q
  40. }
  41. // lazyInit lazily initializes a zero Queue value.
  42. //
  43. // I am mostly doing this because container/list does the same thing.
  44. // Personally I think it's a little wasteful because every single
  45. // PushFront/PushBack is going to pay the overhead of calling this.
  46. // But that's the price for making zero values useful immediately,
  47. // something Go folks apparently like a lot.
  48. func (q *Queue) lazyInit() {
  49. if q.rep == nil {
  50. q.Init()
  51. }
  52. }
  53. // Len returns the number of elements of queue q.
  54. func (q *Queue) Len() int {
  55. return q.length
  56. }
  57. // empty returns true if the queue q has no elements.
  58. func (q *Queue) empty() bool {
  59. return q.length == 0
  60. }
  61. // full returns true if the queue q is at capacity.
  62. func (q *Queue) full() bool {
  63. return q.length == len(q.rep)
  64. }
  65. // grow doubles the size of queue q's underlying slice/array.
  66. func (q *Queue) grow() {
  67. bigger := make([]interface{}, q.length*2)
  68. // Kudos to Rodrigo Moraes, see https://gist.github.com/moraes/2141121
  69. // Kudos to Dariusz Górecki, see https://github.com/eapache/queue/commit/334cc1b02398be651373851653017e6cbf588f9e
  70. n := copy(bigger, q.rep[q.front:])
  71. copy(bigger[n:], q.rep[:q.front])
  72. // The above replaced the "obvious" for loop and is a bit tricky.
  73. // First note that q.front == q.back if we're full; if that wasn't
  74. // true, things would be more complicated. Second recall that for
  75. // a slice [lo:hi] the lo bound is inclusive whereas the hi bound
  76. // is exclusive. If that doesn't convince you that the above works
  77. // maybe drawing out some pictures for a concrete example will?
  78. q.rep = bigger
  79. q.front = 0
  80. q.back = q.length
  81. }
  82. // lazyGrow grows the underlying slice/array if necessary.
  83. func (q *Queue) lazyGrow() {
  84. if q.full() {
  85. q.grow()
  86. }
  87. }
  88. // String returns a string representation of queue q formatted
  89. // from front to back.
  90. func (q *Queue) String() string {
  91. result := ""
  92. result = result + "["
  93. j := q.front
  94. for i := 0; i < q.length; i++ {
  95. if i == q.length-1 {
  96. result = result + fmt.Sprintf("%v", q.rep[j])
  97. } else {
  98. result = result + fmt.Sprintf("%v, ", q.rep[j])
  99. }
  100. j = q.inc(j)
  101. }
  102. result = result + "]"
  103. return result
  104. }
  105. // inc returns the next integer position wrapping around queue q.
  106. func (q *Queue) inc(i int) int {
  107. l := len(q.rep)
  108. return (i + 1) & (l - 1) // requires l = 2^n
  109. }
  110. // dec returns the previous integer position wrapping around queue q.
  111. func (q *Queue) dec(i int) int {
  112. l := len(q.rep)
  113. return (i - 1) & (l - 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. }