2022-12-22 10:29:06 +01:00

251 lines
7.8 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
library SetMap {
using EnumerableSet for EnumerableSet.Bytes32Set;
using EnumerableSet for EnumerableSet.AddressSet;
type Bytes32SetMapKey is bytes32;
struct Bytes32SetMap {
mapping(Bytes32SetMapKey =>
mapping(address =>
mapping(uint8 =>
EnumerableSet.Bytes32Set))) _values;
mapping(Bytes32SetMapKey => uint8) _index;
EnumerableSet.Bytes32Set _keys;
}
/// @notice Returns the EnumerableSet.Bytes32 containing the values for a key
/// and address in an Bytes32SetMap
/// @dev This is used internally to the library only. `.values()` should only
/// be called on its return value in a view/pure function.
/// @param map Bytes32SetMap to list values
/// @param key key of the values to be listed
/// @param addr address of the values to be listed
/// @return bytes32[] array of bytes32 values
function _set(Bytes32SetMap storage map,
Bytes32SetMapKey key,
address addr)
private
view
returns (EnumerableSet.Bytes32Set storage)
{
uint8 id = map._index[key];
return map._values[key][addr][id];
}
/// @notice Lists all values for a key and address in an Bytes32SetMap
/// @param map Bytes32SetMap to list values
/// @param key key of the values to be listed
/// @param addr address of the values to be listed
/// @return bytes32[] array of bytes32 values
function values(Bytes32SetMap storage map,
Bytes32SetMapKey key,
address addr)
internal
view
returns (bytes32[] memory)
{
return _set(map, key, addr).values();
}
function _toKeys(bytes32[] memory array)
private
pure
returns (Bytes32SetMapKey[] memory result)
{
// solhint-disable-next-line no-inline-assembly
assembly {
result := array
}
}
/// @notice Lists all keys for an Bytes32SetMap
/// @param map Bytes32SetMap to list keys
/// @return bytes32[] array of bytes32 values
function keys(Bytes32SetMap storage map)
internal
view
returns (Bytes32SetMapKey[] memory)
{
return _toKeys(map._keys.values());
}
/// @notice Adds a single value to an Bytes32SetMap
/// @param map Bytes32SetMap to add the value to
/// @param key key of the value to be added
/// @param addr address of the value to be added
/// @param value the value to be added
/// @return true if the value was added to the set, that is if it was not
/// already present.
function add(Bytes32SetMap storage map,
Bytes32SetMapKey key,
address addr,
bytes32 value)
internal
returns (bool)
{
map._keys.add(Bytes32SetMapKey.unwrap(key));
return _set(map, key, addr).add(value);
}
/// @notice Removes a single value from an Bytes32SetMap
/// @param map Bytes32SetMap to remove the value from
/// @param key key of the value to be removed
/// @param addr address of the value to be removed
/// @param value the value to be removed
/// @return true if the value was removed from the set, that is if it was
/// present.
function remove(Bytes32SetMap storage map,
Bytes32SetMapKey key,
address addr,
bytes32 value)
internal
returns (bool)
{
EnumerableSet.Bytes32Set storage set = _set(map, key, addr);
bool success = set.remove(value);
if (success && set.length() == 0) {
map._keys.remove(Bytes32SetMapKey.unwrap(key));
}
return success;
}
/// @notice Clears values for a key.
/// @dev Does not clear the addresses for the key, simply updates an index
/// such that the next time values for that key and address are
/// retrieved, it will reference a new EnumerableSet.
/// @param map Bytes32SetMap for which to clear values
/// @param key key for which to clear values
function clear(Bytes32SetMap storage map, Bytes32SetMapKey key)
internal
{
map._index[key]++;
}
type AddressSetMapKey is address;
struct AddressSetMap {
mapping(AddressSetMapKey =>
mapping(uint8 =>
EnumerableSet.Bytes32Set)) _values;
mapping(AddressSetMapKey => uint8) _index;
EnumerableSet.AddressSet _keys;
EnumerableSet.Bytes32Set _allValues;
}
/// @notice Returns the EnumerableSet.AddressSet containing the values for a
/// key in an AddressSetMap.
/// @dev This is used internally to the library only. `.values()` should only
/// be called on its return value in a view/pure function.
/// @param map AddressSetMap containing the set to be retrieved.
/// @param key key of the set to be retrieved.
/// @return bytes32[] array of bytes32 values.
function _set(AddressSetMap storage map,
AddressSetMapKey key)
private
view
returns (EnumerableSet.Bytes32Set storage)
{
uint8 id = map._index[key];
return map._values[key][id];
}
/// @notice Lists all values contained in an AddressSetMap, regardless of
/// the key.
/// @param map AddressSetMap to list values
/// @return bytes32[] array of bytes32 values
function values(AddressSetMap storage map)
internal
view
returns (bytes32[] memory)
{
return map._allValues.values();
}
/// @notice Lists all values for a key in an AddressSetMap
/// @param map AddressSetMap to list values
/// @param key key of the values to be listed
/// @return bytes32[] array of bytes32 values
function values(AddressSetMap storage map, AddressSetMapKey key)
internal
view
returns (bytes32[] memory)
{
return _set(map, key).values();
}
function _toAddressSetMapKeys(address[] memory array)
private
pure
returns (AddressSetMapKey[] memory result)
{
// solhint-disable-next-line no-inline-assembly
assembly {
result := array
}
}
/// @notice Lists all keys for an Bytes32SetMap.
/// @param map AddressSetMap to list keys.
/// @return bytes32[] array of bytes32 values.
function keys(AddressSetMap storage map)
internal
view
returns (AddressSetMapKey[] memory)
{
return _toAddressSetMapKeys(map._keys.values());
}
/// @notice Adds a single value to an AddressSetMap
/// @param map AddressSetMap to add the value to.
/// @param key key of the value to be added.
/// @param value the value to be added.
/// @return true if the value was added to the set, that is if it was not
/// already present.
function add(AddressSetMap storage map,
AddressSetMapKey key,
bytes32 value)
internal
returns (bool)
{
map._keys.add(AddressSetMapKey.unwrap(key));
map._allValues.add(value);
return _set(map, key).add(value);
}
/// @notice Removes a single value from an AddressSetMap
/// @param map AddressSetMap to remove the value from
/// @param key key of the value to be removed
/// @param value the value to be removed
/// @return true if the value was removed from the set, that is if it was
/// present.
function remove(AddressSetMap storage map,
AddressSetMapKey key,
bytes32 value)
internal
returns (bool)
{
EnumerableSet.Bytes32Set storage set = _set(map, key);
bool success = set.remove(value);
if (success && set.length() == 0) {
map._keys.remove(AddressSetMapKey.unwrap(key));
}
map._allValues.remove(value);
return success;
}
/// @notice Clears values for a key.
/// @dev Updates an index such that the next time values for that key are
/// retrieved, it will reference a new EnumerableSet.
/// @param map AddressSetMap for which to clear values
/// @param key key for which to clear values
function clear(AddressSetMap storage map, AddressSetMapKey key)
internal
{
map._index[key]++;
}
}