queue.odin 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. package container_queue
  2. import "core:builtin"
  3. import "core:runtime"
  4. _ :: runtime
  5. // Dynamically resizable double-ended queue/ring-buffer
  6. Queue :: struct($T: typeid) {
  7. data: [dynamic]T,
  8. len: uint,
  9. offset: uint,
  10. }
  11. DEFAULT_CAPACITY :: 16
  12. // Procedure to initialize a queue
  13. init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := context.allocator) -> bool {
  14. if q.data.allocator.procedure == nil {
  15. q.data.allocator = allocator
  16. }
  17. clear(q)
  18. return reserve(q, capacity)
  19. }
  20. // Procedure to initialize a queue from a fixed backing slice
  21. init_from_slice :: proc(q: ^$Q/Queue($T), backing: []T) -> bool {
  22. clear(q)
  23. q.data = transmute([dynamic]T)runtime.Raw_Dynamic_Array{
  24. data = raw_data(backing),
  25. len = builtin.len(backing),
  26. cap = builtin.len(backing),
  27. allocator = {procedure=runtime.nil_allocator_proc, data=nil},
  28. }
  29. return true
  30. }
  31. // Procedure to destroy a queue
  32. destroy :: proc(q: ^$Q/Queue($T)) {
  33. delete(q.data)
  34. }
  35. // The length of the queue
  36. len :: proc(q: $Q/Queue($T)) -> int {
  37. return int(q.len)
  38. }
  39. // The current capacity of the queue
  40. cap :: proc(q: $Q/Queue($T)) -> int {
  41. return builtin.len(q.data)
  42. }
  43. // Remaining space in the queue (cap-len)
  44. space :: proc(q: $Q/Queue($T)) -> int {
  45. return builtin.len(q.data) - int(q.len)
  46. }
  47. // Reserve enough space for at least the specified capacity
  48. reserve :: proc(q: ^$Q/Queue($T), capacity: int) -> bool {
  49. if uint(capacity) > q.len {
  50. return _grow(q, uint(capacity))
  51. }
  52. return true
  53. }
  54. get :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> T {
  55. runtime.bounds_check_error_loc(loc, i, builtin.len(q.data))
  56. idx := (uint(i)+q.offset)%builtin.len(q.data)
  57. return q.data[idx]
  58. }
  59. set :: proc(q: ^$Q/Queue($T), #any_int i: int, val: T, loc := #caller_location) {
  60. runtime.bounds_check_error_loc(loc, i, builtin.len(q.data))
  61. idx := (uint(i)+q.offset)%builtin.len(q.data)
  62. q.data[idx] = val
  63. }
  64. get_ptr :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> ^T {
  65. runtime.bounds_check_error_loc(loc, i, builtin.len(q.data))
  66. idx := (uint(i)+q.offset)%builtin.len(q.data)
  67. return &q.data[idx]
  68. }
  69. // Push an element to the back of the queue
  70. push_back :: proc(q: ^$Q/Queue($T), elem: T) -> bool {
  71. if space(q^) == 0 {
  72. _grow(q) or_return
  73. }
  74. idx := (q.offset+uint(q.len))%builtin.len(q.data)
  75. q.data[idx] = elem
  76. q.len += 1
  77. return true
  78. }
  79. // Push an element to the front of the queue
  80. push_front :: proc(q: ^$Q/Queue($T), elem: T) -> bool {
  81. if space(q^) == 0 {
  82. _grow(q) or_return
  83. }
  84. q.offset = uint(q.offset - 1 + builtin.len(q.data)) % builtin.len(q.data)
  85. q.len += 1
  86. q.data[q.offset] = elem
  87. return true
  88. }
  89. // Pop an element from the back of the queue
  90. pop_back :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> (elem: T) {
  91. assert(condition=q.len > 0, loc=loc)
  92. q.len -= 1
  93. idx := (q.offset+uint(q.len))%builtin.len(q.data)
  94. elem = q.data[idx]
  95. return
  96. }
  97. // Safely pop an element from the back of the queue
  98. pop_back_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) {
  99. if q.len > 0 {
  100. q.len -= 1
  101. idx := (q.offset+uint(q.len))%builtin.len(q.data)
  102. elem = q.data[idx]
  103. ok = true
  104. }
  105. return
  106. }
  107. // Pop an element from the front of the queue
  108. pop_front :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> (elem: T) {
  109. assert(condition=q.len > 0, loc=loc)
  110. elem = q.data[q.offset]
  111. q.offset = (q.offset+1)%builtin.len(q.data)
  112. q.len -= 1
  113. return
  114. }
  115. // Safely pop an element from the front of the queue
  116. pop_front_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) {
  117. if q.len > 0 {
  118. elem = q.data[q.offset]
  119. q.offset = (q.offset+1)%builtin.len(q.data)
  120. q.len -= 1
  121. ok = true
  122. }
  123. return
  124. }
  125. // Push multiple elements to the front of the queue
  126. push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> bool {
  127. n := uint(builtin.len(elems))
  128. if space(q^) < int(n) {
  129. _grow(q, q.len + n) or_return
  130. }
  131. sz := uint(builtin.len(q.data))
  132. insert_from := (q.offset + q.len) % sz
  133. insert_to := n
  134. if insert_from + insert_to > sz {
  135. insert_to = sz - insert_from
  136. }
  137. copy(q.data[insert_from:], elems[:insert_to])
  138. copy(q.data[:insert_from], elems[insert_to:])
  139. q.len += n
  140. return true
  141. }
  142. // Consume `n` elements from the front of the queue
  143. consume_front :: proc(q: ^$Q/Queue($T), n: int, loc := #caller_location) {
  144. assert(condition=int(q.len) >= n, loc=loc)
  145. if n > 0 {
  146. nu := uint(n)
  147. q.offset = (q.offset + nu) % builtin.len(q.data)
  148. q.len -= nu
  149. }
  150. }
  151. // Consume `n` elements from the back of the queue
  152. consume_back :: proc(q: ^$Q/Queue($T), n: int, loc := #caller_location) {
  153. assert(condition=int(q.len) >= n, loc=loc)
  154. if n > 0 {
  155. q.len -= uint(n)
  156. }
  157. }
  158. append_elem :: push_back
  159. append_elems :: push_back_elems
  160. push :: proc{push_back, push_back_elems}
  161. append :: proc{push_back, push_back_elems}
  162. // Clear the contents of the queue
  163. clear :: proc(q: ^$Q/Queue($T)) {
  164. q.len = 0
  165. q.offset = 0
  166. }
  167. // Internal growinh procedure
  168. _grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> bool {
  169. new_capacity := max(min_capacity, uint(8), uint(builtin.len(q.data))*2)
  170. n := uint(builtin.len(q.data))
  171. builtin.resize(&q.data, int(new_capacity)) or_return
  172. if q.offset + q.len > n {
  173. diff := n - q.offset
  174. copy(q.data[new_capacity-diff:], q.data[q.offset:][:diff])
  175. q.offset += new_capacity - n
  176. }
  177. return true
  178. }