queue.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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 about 15%-45% faster than container/list at the price
  9. // of potentially wasting some memory because we grow by doubling.
  10. // We seem to even beat Go's channels by a small 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]; gotta love those invariants.
  19. rep []interface{}
  20. front int
  21. back int
  22. length int
  23. }
  24. // New returns an initialized empty queue.
  25. func New() *Queue {
  26. return new(Queue).Init()
  27. }
  28. // Init initializes or clears queue q.
  29. func (q *Queue) Init() *Queue {
  30. // start with a slice of length 2 even if that "wastes"
  31. // some memory; we do front/back arithmetic modulo the
  32. // length, so starting at 1 would require special cases
  33. q.rep = make([]interface{}, 2)
  34. // for some time I considered reusing the existing slice
  35. // if all a client does is re-initialize the queue; the
  36. // big problem with that is that the previous queue might
  37. // have been huge while the current queue doesn't grow
  38. // much at all; if that were to happen we'd hold on to a
  39. // huge chunk of memory for just a few elements and nobody
  40. // could do anything about it; so instead I decided to
  41. // just allocate a new slice and let the GC take care of
  42. // the previous one; seems a better tradeoff all around
  43. q.front, q.back, q.length = 0, 0, 0
  44. return q
  45. }
  46. // lazyInit lazily initializes a zero Queue value.
  47. //
  48. // I am mostly doing this because container/list does the same thing.
  49. // Personally I think it's a little wasteful because every single
  50. // PushFront/PushBack is going to pay the overhead of calling this.
  51. // But that's the price for making zero values useful immediately,
  52. // something Go folks apparently like a lot.
  53. func (q *Queue) lazyInit() {
  54. if q.rep == nil {
  55. q.Init()
  56. }
  57. }
  58. // Len returns the number of elements of queue q.
  59. func (q *Queue) Len() int {
  60. return q.length
  61. }
  62. // empty returns true if the queue q has no elements.
  63. func (q *Queue) empty() bool {
  64. return q.length == 0
  65. }
  66. // full returns true if the queue q is at capacity.
  67. func (q *Queue) full() bool {
  68. return q.length == len(q.rep)
  69. }
  70. // grow doubles the size of queue q's underlying slice/array.
  71. func (q *Queue) grow() {
  72. bigger := make([]interface{}, q.length*2)
  73. // Kudos to Rodrigo Moraes, see https://gist.github.com/moraes/2141121
  74. copy(bigger, q.rep[q.front:])
  75. copy(bigger[q.length-q.front:], q.rep[:q.front])
  76. // The above replaced the "obvious" for loop and is a bit tricky.
  77. // First note that q.front == q.back if we're full; if that wasn't
  78. // true, things would be more complicated. Second recall that for
  79. // a slice [lo:hi] the lo bound is inclusive whereas the hi bound
  80. // is exclusive. If that doesn't convince you that the above works
  81. // maybe drawing out some pictures for a concrete example will?
  82. q.rep = bigger
  83. q.front = 0
  84. q.back = q.length
  85. }
  86. // lazyGrow grows the underlying slice/array if necessary.
  87. func (q *Queue) lazyGrow() {
  88. if q.full() {
  89. q.grow()
  90. }
  91. }
  92. // String returns a string representation of queue q formatted
  93. // from front to back.
  94. func (q *Queue) String() string {
  95. result := ""
  96. result = result + "["
  97. j := q.front
  98. for i := 0; i < q.length; i++ {
  99. if i == q.length-1 {
  100. result = result + fmt.Sprintf("%v", q.rep[j])
  101. } else {
  102. result = result + fmt.Sprintf("%v, ", q.rep[j])
  103. }
  104. j = q.inc(j)
  105. }
  106. result = result + "]"
  107. return result
  108. }
  109. // inc returns the next integer position wrapping around queue q.
  110. func (q *Queue) inc(i int) int {
  111. l := len(q.rep)
  112. return (i + 1 + l) % l
  113. }
  114. // dec returns the previous integer position wrapping around queue q.
  115. func (q *Queue) dec(i int) int {
  116. l := len(q.rep)
  117. return (i - 1 + l) % l
  118. }
  119. // Front returns the first element of queue q or nil.
  120. func (q *Queue) Front() interface{} {
  121. if q.empty() {
  122. return nil
  123. }
  124. return q.rep[q.front]
  125. }
  126. // Back returns the last element of queue q or nil.
  127. func (q *Queue) Back() interface{} {
  128. if q.empty() {
  129. return nil
  130. }
  131. return q.rep[q.dec(q.back)]
  132. }
  133. // PushFront inserts a new value v at the front of queue q.
  134. func (q *Queue) PushFront(v interface{}) {
  135. q.lazyInit()
  136. q.lazyGrow()
  137. q.front = q.dec(q.front)
  138. q.rep[q.front] = v
  139. q.length++
  140. }
  141. // PushBack inserts a new value v at the back of queue q.
  142. func (q *Queue) PushBack(v interface{}) {
  143. q.lazyInit()
  144. q.lazyGrow()
  145. q.rep[q.back] = v
  146. q.back = q.inc(q.back)
  147. q.length++
  148. }
  149. // Both PopFront and PopBack set the newly free slot to nil
  150. // in an attempt to be nice to the garbage collector.
  151. // PopFront removes and returns the first element of queue q or nil.
  152. func (q *Queue) PopFront() interface{} {
  153. if q.empty() {
  154. return nil
  155. }
  156. v := q.rep[q.front]
  157. q.rep[q.front] = nil
  158. q.front = q.inc(q.front)
  159. q.length--
  160. return v
  161. }
  162. // PopBack removes and returns the last element of queue q or nil.
  163. func (q *Queue) PopBack() interface{} {
  164. if q.empty() {
  165. return nil
  166. }
  167. q.back = q.dec(q.back)
  168. v := q.rep[q.back]
  169. q.rep[q.back] = nil
  170. q.length--
  171. return v
  172. }