DoubleEndedQueue.sol 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/DoubleEndedQueue.sol)
  3. pragma solidity ^0.8.20;
  4. /**
  5. * @dev A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends of
  6. * the sequence (called front and back). Among other access patterns, it can be used to implement efficient LIFO and
  7. * FIFO queues. Storage use is optimized, and all operations are O(1) constant time. This includes {clear}, given that
  8. * the existing queue contents are left in storage.
  9. *
  10. * The struct is called `Bytes32Deque`. Other types can be cast to and from `bytes32`. This data structure can only be
  11. * used in storage, and not in memory.
  12. * ```solidity
  13. * DoubleEndedQueue.Bytes32Deque queue;
  14. * ```
  15. */
  16. library DoubleEndedQueue {
  17. /**
  18. * @dev An operation (e.g. {front}) couldn't be completed due to the queue being empty.
  19. */
  20. error QueueEmpty();
  21. /**
  22. * @dev A push operation couldn't be completed due to the queue being full.
  23. */
  24. error QueueFull();
  25. /**
  26. * @dev An operation (e.g. {at}) couldn't be completed due to an index being out of bounds.
  27. */
  28. error QueueOutOfBounds();
  29. /**
  30. * @dev Indices are 128 bits so begin and end are packed in a single storage slot for efficient access.
  31. *
  32. * Struct members have an underscore prefix indicating that they are "private" and should not be read or written to
  33. * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and
  34. * lead to unexpected behavior.
  35. *
  36. * The first item is at data[begin] and the last item is at data[end - 1]. This range can wrap around.
  37. */
  38. struct Bytes32Deque {
  39. uint128 _begin;
  40. uint128 _end;
  41. mapping(uint128 index => bytes32) _data;
  42. }
  43. /**
  44. * @dev Inserts an item at the end of the queue.
  45. *
  46. * Reverts with {QueueFull} if the queue is full.
  47. */
  48. function pushBack(Bytes32Deque storage deque, bytes32 value) internal {
  49. unchecked {
  50. uint128 backIndex = deque._end;
  51. if (backIndex + 1 == deque._begin) revert QueueFull();
  52. deque._data[backIndex] = value;
  53. deque._end = backIndex + 1;
  54. }
  55. }
  56. /**
  57. * @dev Removes the item at the end of the queue and returns it.
  58. *
  59. * Reverts with {QueueEmpty} if the queue is empty.
  60. */
  61. function popBack(Bytes32Deque storage deque) internal returns (bytes32 value) {
  62. unchecked {
  63. uint128 backIndex = deque._end;
  64. if (backIndex == deque._begin) revert QueueEmpty();
  65. --backIndex;
  66. value = deque._data[backIndex];
  67. delete deque._data[backIndex];
  68. deque._end = backIndex;
  69. }
  70. }
  71. /**
  72. * @dev Inserts an item at the beginning of the queue.
  73. *
  74. * Reverts with {QueueFull} if the queue is full.
  75. */
  76. function pushFront(Bytes32Deque storage deque, bytes32 value) internal {
  77. unchecked {
  78. uint128 frontIndex = deque._begin - 1;
  79. if (frontIndex == deque._end) revert QueueFull();
  80. deque._data[frontIndex] = value;
  81. deque._begin = frontIndex;
  82. }
  83. }
  84. /**
  85. * @dev Removes the item at the beginning of the queue and returns it.
  86. *
  87. * Reverts with `QueueEmpty` if the queue is empty.
  88. */
  89. function popFront(Bytes32Deque storage deque) internal returns (bytes32 value) {
  90. unchecked {
  91. uint128 frontIndex = deque._begin;
  92. if (frontIndex == deque._end) revert QueueEmpty();
  93. value = deque._data[frontIndex];
  94. delete deque._data[frontIndex];
  95. deque._begin = frontIndex + 1;
  96. }
  97. }
  98. /**
  99. * @dev Returns the item at the beginning of the queue.
  100. *
  101. * Reverts with `QueueEmpty` if the queue is empty.
  102. */
  103. function front(Bytes32Deque storage deque) internal view returns (bytes32 value) {
  104. if (empty(deque)) revert QueueEmpty();
  105. return deque._data[deque._begin];
  106. }
  107. /**
  108. * @dev Returns the item at the end of the queue.
  109. *
  110. * Reverts with `QueueEmpty` if the queue is empty.
  111. */
  112. function back(Bytes32Deque storage deque) internal view returns (bytes32 value) {
  113. if (empty(deque)) revert QueueEmpty();
  114. unchecked {
  115. return deque._data[deque._end - 1];
  116. }
  117. }
  118. /**
  119. * @dev Return the item at a position in the queue given by `index`, with the first item at 0 and last item at
  120. * `length(deque) - 1`.
  121. *
  122. * Reverts with `QueueOutOfBounds` if the index is out of bounds.
  123. */
  124. function at(Bytes32Deque storage deque, uint256 index) internal view returns (bytes32 value) {
  125. if (index >= length(deque)) revert QueueOutOfBounds();
  126. // By construction, length is a uint128, so the check above ensures that index can be safely downcast to uint128
  127. unchecked {
  128. return deque._data[deque._begin + uint128(index)];
  129. }
  130. }
  131. /**
  132. * @dev Resets the queue back to being empty.
  133. *
  134. * NOTE: The current items are left behind in storage. This does not affect the functioning of the queue, but misses
  135. * out on potential gas refunds.
  136. */
  137. function clear(Bytes32Deque storage deque) internal {
  138. deque._begin = 0;
  139. deque._end = 0;
  140. }
  141. /**
  142. * @dev Returns the number of items in the queue.
  143. */
  144. function length(Bytes32Deque storage deque) internal view returns (uint256) {
  145. unchecked {
  146. return uint256(deque._end - deque._begin);
  147. }
  148. }
  149. /**
  150. * @dev Returns true if the queue is empty.
  151. */
  152. function empty(Bytes32Deque storage deque) internal view returns (bool) {
  153. return deque._end == deque._begin;
  154. }
  155. }