EnumerableMap.sol 7.4 KB

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