EnumerableSet.sol 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. pragma solidity ^0.5.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;`, and use
  16. * {newAddressSet} to create a new `AddressSet`.
  17. *
  18. * _Available since v2.5.0._
  19. *
  20. * @author Alberto Cuesta Cañada
  21. */
  22. library EnumerableSet {
  23. struct AddressSet {
  24. // Position of the value in the `values` array, plus 1 because index 0
  25. // means a value is not in the set.
  26. mapping (address => uint256) index;
  27. address[] values;
  28. }
  29. /**
  30. * @dev Creates a new empty address set.
  31. */
  32. function newAddressSet()
  33. internal
  34. pure
  35. returns (AddressSet memory)
  36. {
  37. return AddressSet({values: new address[](0)});
  38. }
  39. /**
  40. * @dev Add a value to a set. O(1).
  41. * Returns false if the value was already in the set.
  42. */
  43. function add(AddressSet storage set, address value)
  44. internal
  45. returns (bool)
  46. {
  47. if (!contains(set, value)){
  48. set.index[value] = set.values.push(value);
  49. return true;
  50. } else {
  51. return false;
  52. }
  53. }
  54. /**
  55. * @dev Removes a value from a set. O(1).
  56. * Returns false if the value was not present in the set.
  57. */
  58. function remove(AddressSet storage set, address value)
  59. internal
  60. returns (bool)
  61. {
  62. if (contains(set, value)){
  63. uint256 toDeleteIndex = set.index[value] - 1;
  64. uint256 lastIndex = set.values.length - 1;
  65. // If the element we're deleting is the last one, we can just remove it without doing a swap
  66. if (lastIndex != toDeleteIndex) {
  67. address lastValue = set.values[lastIndex];
  68. // Move the last value to the index where the deleted value is
  69. set.values[toDeleteIndex] = lastValue;
  70. // Update the index for the moved value
  71. set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based
  72. }
  73. // Delete the index entry for the deleted value
  74. delete set.index[value];
  75. // Delete the old entry for the moved value
  76. set.values.pop();
  77. return true;
  78. } else {
  79. return false;
  80. }
  81. }
  82. /**
  83. * @dev Returns true if the value is in the set. O(1).
  84. */
  85. function contains(AddressSet storage set, address value)
  86. internal
  87. view
  88. returns (bool)
  89. {
  90. return set.index[value] != 0;
  91. }
  92. /**
  93. * @dev Returns an array with all values in the set. O(N).
  94. * Note that there are no guarantees on the ordering of values inside the
  95. * array, and it may change when more values are added or removed.
  96. */
  97. function enumerate(AddressSet storage set)
  98. internal
  99. view
  100. returns (address[] memory)
  101. {
  102. address[] memory output = new address[](set.values.length);
  103. for (uint256 i; i < set.values.length; i++){
  104. output[i] = set.values[i];
  105. }
  106. return output;
  107. }
  108. }