DoubleEndedQueue.sol 5.8 KB

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