/// @title HashMap
/// @notice SPDX-License-Identifier: MIT
/// @author asnared <https://github.com/abigger87>
/// @notice A Module Encapsulating HashMap Methods
/// @notice Adapted from <https://github.com/huff-language/huff-examples/blob/main/erc20/contracts/utils/HashMap.huff>
/// @notice Given a piece of data (ie an address), hash it, generating the storage slot for a hashmap.
#define macro GET_SLOT_FROM_KEY(mem_ptr) = takes(1) returns (1) {
// Input stack: [key]
// Load the data into memory and hash it, while preserving the memory location.
<mem_ptr> // [<mem_ptr>, key]
mstore // []
// Hash the data, generating a key.
0x20 // [32]
<mem_ptr> // [<mem_ptr>, 32]
sha3 // [slot]
}
/// @notice Given two keys (ie an address and a number), hash them together, generating a slot for a secondary hashmap.
/// This should only be used if you have multiple maps in your contract.
#define macro GET_SLOT_FROM_KEYS(mem_ptr) = takes(2) returns (1) {
// Input stack: [key1, key2]
// Load the data into memory.
<mem_ptr> // [<mem_ptr>, key1, key2]
mstore // [key2]
<mem_ptr> 0x20 add // [<mem_ptr> + 32, key2]
mstore // []
// Hash the data, generating a key.
0x40 // [64]
<mem_ptr> // [<mem_ptr>, 64]
sha3 // [key]
}
/// @notice Calculate the slot from two keys
#define macro GET_SLOT_FROM_KEYS_2D(mem_ptr) = takes(3) returns (1) {
// Input stack: [slot, key1, key2]
// Load the data into memory
<mem_ptr> // [<mem_ptr>, slot, key1, key2]
mstore // [key1, key2]
// next byte
<mem_ptr> 0x20 add // [<mem_ptr> + 32, key1, key2]
mstore // [key2]
0x40 // [0x40, key2]
<mem_ptr> // [<mem_ptr>, 0x40, key2]
sha3 // [slot1, key2]
// concat the two keys
<mem_ptr> 0x20 add // [<mem_ptr> + 0x20, key2] put slot1 in memory
mstore // [key2]
// next byte
<mem_ptr> // [<mem_ptr>, key2]
mstore // []
// Hash the data, generating a key.
0x40 // [0x40]
<mem_ptr> // [<mem_ptr>, 0x40]
sha3 // [key]
}
/// @notice Load an element onto the stack from a key
#define macro LOAD_ELEMENT(mem_ptr) = takes(1) returns(1) {
// Input stack: [key]
GET_SLOT_FROM_KEY(<mem_ptr>) // [slot]
sload // [value]
}
/// @notice Load an element onto the stack from two keys
#define macro LOAD_ELEMENT_FROM_KEYS(mem_ptr) = takes(2) returns(1) {
// Input stack: [key1, key2]
GET_SLOT_FROM_KEYS(<mem_ptr>) // [slot]
sload // [value]
}
/// @notice Load an element onto the stack from a slot and two keys
#define macro LOAD_ELEMENT_FROM_KEYS_2D(mem_ptr) = takes(3) returns(1) {
// Input stack: [slot, key1, key2]
GET_SLOT_FROM_KEYS_2D(<mem_ptr>) // [slot]
sload // [value]
}
/// @notice Store an element from a key
#define macro STORE_ELEMENT(mem_ptr) = takes(2) returns(0) {
// Input stack: [key, value]
GET_SLOT_FROM_KEY(<mem_ptr>) // [slot, value]
sstore // []
}
/// @notice Store an element from two keys
#define macro STORE_ELEMENT_FROM_KEYS(mem_ptr) = takes(3) returns (0) {
// Input stack: [key1, key2, value]
GET_SLOT_FROM_KEYS(<mem_ptr>) // [slot, value]
sstore // []
}
/// @notice Store an element from a slot and two keys
#define macro STORE_ELEMENT_FROM_KEYS_2D(mem_ptr) = takes(4) returns (0) {
// Input stack: [slot, key1, key2, value]
GET_SLOT_FROM_KEYS_2D(<mem_ptr>) // [slot, value]
sstore // []
}