EnumerableMap.sol 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.6.0;
  3. /**
  4. * @dev Library for managing an enumerable variant of Solidity's
  5. * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
  6. * type.
  7. *
  8. * Maps have the following properties:
  9. *
  10. * - Entries are added, removed, and checked for existence in constant time
  11. * (O(1)).
  12. * - Entries are enumerated in O(n). No guarantees are made on the ordering.
  13. *
  14. * ```
  15. * contract Example {
  16. * // Add the library methods
  17. * using EnumerableMap for EnumerableMap.UintToAddressMap;
  18. *
  19. * // Declare a set state variable
  20. * EnumerableMap.UintToAddressMap private myMap;
  21. * }
  22. * ```
  23. *
  24. * As of v3.0.0, only maps of type `uint256 -> address` (`UintToAddressMap`) are
  25. * supported.
  26. */
  27. library EnumerableMap {
  28. // To implement this library for multiple types with as little code
  29. // repetition as possible, we write it in terms of a generic Map type with
  30. // bytes32 keys and values.
  31. // The Map implementation uses private functions, and user-facing
  32. // implementations (such as Uint256ToAddressMap) are just wrappers around
  33. // the underlying Map.
  34. // This means that we can only create new EnumerableMaps for types that fit
  35. // in bytes32.
  36. struct MapEntry {
  37. bytes32 _key;
  38. bytes32 _value;
  39. }
  40. struct Map {
  41. // Storage of map keys and values
  42. MapEntry[] _entries;
  43. // Position of the entry defined by a key in the `entries` array, plus 1
  44. // because index 0 means a key is not in the map.
  45. mapping (bytes32 => uint256) _indexes;
  46. }
  47. /**
  48. * @dev Adds a key-value pair to a map, or updates the value for an existing
  49. * key. O(1).
  50. *
  51. * Returns true if the key was added to the map, that is if it was not
  52. * already present.
  53. */
  54. function _set(Map storage map, bytes32 key, bytes32 value) private returns (bool) {
  55. // We read and store the key's index to prevent multiple reads from the same storage slot
  56. uint256 keyIndex = map._indexes[key];
  57. if (keyIndex == 0) { // Equivalent to !contains(map, key)
  58. map._entries.push(MapEntry({ _key: key, _value: value }));
  59. // The entry is stored at length-1, but we add 1 to all indexes
  60. // and use 0 as a sentinel value
  61. map._indexes[key] = map._entries.length;
  62. return true;
  63. } else {
  64. map._entries[keyIndex - 1]._value = value;
  65. return false;
  66. }
  67. }
  68. /**
  69. * @dev Removes a key-value pair from a map. O(1).
  70. *
  71. * Returns true if the key was removed from the map, that is if it was present.
  72. */
  73. function _remove(Map storage map, bytes32 key) private returns (bool) {
  74. // We read and store the key's index to prevent multiple reads from the same storage slot
  75. uint256 keyIndex = map._indexes[key];
  76. if (keyIndex != 0) { // Equivalent to contains(map, key)
  77. // To delete a key-value pair from the _entries array in O(1), we swap the entry to delete with the last one
  78. // in the array, and then remove the last entry (sometimes called as 'swap and pop').
  79. // This modifies the order of the array, as noted in {at}.
  80. uint256 toDeleteIndex = keyIndex - 1;
  81. uint256 lastIndex = map._entries.length - 1;
  82. // When the entry to delete is the last one, the swap operation is unnecessary. However, since this occurs
  83. // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
  84. MapEntry storage lastEntry = map._entries[lastIndex];
  85. // Move the last entry to the index where the entry to delete is
  86. map._entries[toDeleteIndex] = lastEntry;
  87. // Update the index for the moved entry
  88. map._indexes[lastEntry._key] = toDeleteIndex + 1; // All indexes are 1-based
  89. // Delete the slot where the moved entry was stored
  90. map._entries.pop();
  91. // Delete the index for the deleted slot
  92. delete map._indexes[key];
  93. return true;
  94. } else {
  95. return false;
  96. }
  97. }
  98. /**
  99. * @dev Returns true if the key is in the map. O(1).
  100. */
  101. function _contains(Map storage map, bytes32 key) private view returns (bool) {
  102. return map._indexes[key] != 0;
  103. }
  104. /**
  105. * @dev Returns the number of key-value pairs in the map. O(1).
  106. */
  107. function _length(Map storage map) private view returns (uint256) {
  108. return map._entries.length;
  109. }
  110. /**
  111. * @dev Returns the key-value pair stored at position `index` in the map. O(1).
  112. *
  113. * Note that there are no guarantees on the ordering of entries inside the
  114. * array, and it may change when more entries are added or removed.
  115. *
  116. * Requirements:
  117. *
  118. * - `index` must be strictly less than {length}.
  119. */
  120. function _at(Map storage map, uint256 index) private view returns (bytes32, bytes32) {
  121. require(map._entries.length > index, "EnumerableMap: index out of bounds");
  122. MapEntry storage entry = map._entries[index];
  123. return (entry._key, entry._value);
  124. }
  125. /**
  126. * @dev Returns the value associated with `key`. O(1).
  127. *
  128. * Requirements:
  129. *
  130. * - `key` must be in the map.
  131. */
  132. function _get(Map storage map, bytes32 key) private view returns (bytes32) {
  133. return _get(map, key, "EnumerableMap: nonexistent key");
  134. }
  135. /**
  136. * @dev Same as {_get}, with a custom error message when `key` is not in the map.
  137. */
  138. function _get(Map storage map, bytes32 key, string memory errorMessage) private view returns (bytes32) {
  139. uint256 keyIndex = map._indexes[key];
  140. require(keyIndex != 0, errorMessage); // Equivalent to contains(map, key)
  141. return map._entries[keyIndex - 1]._value; // All indexes are 1-based
  142. }
  143. // UintToAddressMap
  144. struct UintToAddressMap {
  145. Map _inner;
  146. }
  147. /**
  148. * @dev Adds a key-value pair to a map, or updates the value for an existing
  149. * key. O(1).
  150. *
  151. * Returns true if the key was added to the map, that is if it was not
  152. * already present.
  153. */
  154. function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
  155. return _set(map._inner, bytes32(key), bytes32(uint256(value)));
  156. }
  157. /**
  158. * @dev Removes a value from a set. O(1).
  159. *
  160. * Returns true if the key was removed from the map, that is if it was present.
  161. */
  162. function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
  163. return _remove(map._inner, bytes32(key));
  164. }
  165. /**
  166. * @dev Returns true if the key is in the map. O(1).
  167. */
  168. function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
  169. return _contains(map._inner, bytes32(key));
  170. }
  171. /**
  172. * @dev Returns the number of elements in the map. O(1).
  173. */
  174. function length(UintToAddressMap storage map) internal view returns (uint256) {
  175. return _length(map._inner);
  176. }
  177. /**
  178. * @dev Returns the element stored at position `index` in the set. O(1).
  179. * Note that there are no guarantees on the ordering of values inside the
  180. * array, and it may change when more values are added or removed.
  181. *
  182. * Requirements:
  183. *
  184. * - `index` must be strictly less than {length}.
  185. */
  186. function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
  187. (bytes32 key, bytes32 value) = _at(map._inner, index);
  188. return (uint256(key), address(uint256(value)));
  189. }
  190. /**
  191. * @dev Returns the value associated with `key`. O(1).
  192. *
  193. * Requirements:
  194. *
  195. * - `key` must be in the map.
  196. */
  197. function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
  198. return address(uint256(_get(map._inner, bytes32(key))));
  199. }
  200. /**
  201. * @dev Same as {get}, with a custom error message when `key` is not in the map.
  202. */
  203. function get(UintToAddressMap storage map, uint256 key, string memory errorMessage) internal view returns (address) {
  204. return address(uint256(_get(map._inner, bytes32(key), errorMessage)));
  205. }
  206. }