Sets and Set Repos

Crane provides type-specific set libraries optimized for Diamond storage (mutate storage in place, avoid unnecessary copies).

Types

SetRepoTypical use
AddressSetAddressSetRepoFacet addresses, registry membership
Bytes32SetBytes32SetRepoGeneral 32-byte keys
Bytes4SetBytes4SetRepoSelectors (ERC2535, comparators)
StringSetStringSetRepoNamed registries
UInt256SetUInt256SetRepoNumeric id sets

Path: contracts/utils/collections/sets/.

Storage shape (AddressSet example)

struct AddressSet {
    mapping(address => uint256) indexes; // 0 = absent; values are 1-indexed
    address[] values;
}

Repo operations

Common pattern on *SetRepo libraries:

  • _add / _remove (idempotent membership)
  • _contains, _length, _index, _indexOf
  • _values (often returns storage pointer for gas)
  • _asArray, _range
  • _addAsc / _removeAsc / _sortAsc — ordered variants for deterministic enumeration

Repos typically expose dual overloads: operate on an explicit Storage/set parameter, or on a default layout when applicable.

Why not OpenZeppelin EnumerableSet only?

Crane sets are tuned for:

  • Direct storage mutation in Diamond Repos
  • Ascending/ordered membership for deterministic walks (registries, facets)
  • Multi-value add/remove loops without copying entire sets into memory unnecessarily

Where they appear

  • FacetRegistryRepo — facets by name/interface/function
  • ERC2535Repo — facet addresses + per-facet selector sets
  • DiamondFactoryPackageRegistryRepo — package membership
  • OperableRepo — function operator sets
  • Test handlers and Bytes4SetComparator / comparator repos

Testing tip

Handlers and Behavior libraries often track expected sets in ghost state and assert equality with on-chain membership after fuzz ops. See Testing Patterns.

See also