EnumerableMap.sol 8.1 KB

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