EnumerableSet.sol 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. pragma solidity ^0.6.0;
  2. /**
  3. * @dev Library for managing
  4. * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
  5. * types.
  6. *
  7. * Sets have the following properties:
  8. *
  9. * - Elements are added, removed, and checked for existence in constant time
  10. * (O(1)).
  11. * - Elements are enumerated in O(n). No guarantees are made on the ordering.
  12. *
  13. * As of v2.5.0, only `address` sets are supported.
  14. *
  15. * Include with `using EnumerableSet for EnumerableSet.AddressSet;`.
  16. *
  17. * @author Alberto Cuesta Cañada
  18. */
  19. library EnumerableSet {
  20. struct AddressSet {
  21. address[] _values;
  22. // Position of the value in the `values` array, plus 1 because index 0
  23. // means a value is not in the set.
  24. mapping (address => uint256) _indexes;
  25. }
  26. /**
  27. * @dev Add a value to a set. O(1).
  28. *
  29. * Returns false if the value was already in the set.
  30. */
  31. function add(AddressSet storage set, address value)
  32. internal
  33. returns (bool)
  34. {
  35. if (!contains(set, value)) {
  36. set._values.push(value);
  37. // The value is stored at length-1, but we add 1 to all indexes
  38. // and use 0 as a sentinel value
  39. set._indexes[value] = set._values.length;
  40. return true;
  41. } else {
  42. return false;
  43. }
  44. }
  45. /**
  46. * @dev Removes a value from a set. O(1).
  47. *
  48. * Returns false if the value was not present in the set.
  49. */
  50. function remove(AddressSet storage set, address value)
  51. internal
  52. returns (bool)
  53. {
  54. if (contains(set, value)){
  55. uint256 toDeleteIndex = set._indexes[value] - 1;
  56. uint256 lastIndex = set._values.length - 1;
  57. // If the value we're deleting is the last one, we can just remove it without doing a swap
  58. if (lastIndex != toDeleteIndex) {
  59. address lastvalue = set._values[lastIndex];
  60. // Move the last value to the index where the deleted value is
  61. set._values[toDeleteIndex] = lastvalue;
  62. // Update the index for the moved value
  63. set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based
  64. }
  65. // Delete the slot where the moved value was stored
  66. set._values.pop();
  67. // Delete the index for the deleted slot
  68. delete set._indexes[value];
  69. return true;
  70. } else {
  71. return false;
  72. }
  73. }
  74. /**
  75. * @dev Returns true if the value is in the set. O(1).
  76. */
  77. function contains(AddressSet storage set, address value)
  78. internal
  79. view
  80. returns (bool)
  81. {
  82. return set._indexes[value] != 0;
  83. }
  84. /**
  85. * @dev Returns an array with all values in the set. O(N).
  86. *
  87. * Note that there are no guarantees on the ordering of values inside the
  88. * array, and it may change when more values are added or removed.
  89. * WARNING: This function may run out of gas on large sets: use {length} and
  90. * {at} instead in these cases.
  91. */
  92. function enumerate(AddressSet storage set)
  93. internal
  94. view
  95. returns (address[] memory)
  96. {
  97. address[] memory output = new address[](set._values.length);
  98. for (uint256 i; i < set._values.length; i++){
  99. output[i] = set._values[i];
  100. }
  101. return output;
  102. }
  103. /**
  104. * @dev Returns the number of values on the set. O(1).
  105. */
  106. function length(AddressSet storage set)
  107. internal
  108. view
  109. returns (uint256)
  110. {
  111. return set._values.length;
  112. }
  113. /**
  114. * @dev Returns the value stored at position `index` in the set. O(1).
  115. *
  116. * Note that there are no guarantees on the ordering of values inside the
  117. * array, and it may change when more values are added or removed.
  118. *
  119. * Requirements:
  120. *
  121. * - `index` must be strictly less than {length}.
  122. */
  123. function at(AddressSet storage set, uint256 index)
  124. internal
  125. view
  126. returns (address)
  127. {
  128. require(set._values.length > index, "EnumerableSet: index out of bounds");
  129. return set._values[index];
  130. }
  131. }