Skip to content

Commit

Permalink
Merge pull request #38 from dl-solidity-library/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
Arvolear authored Feb 20, 2023
2 parents 3e93a14 + 40b3721 commit d6e8bee
Show file tree
Hide file tree
Showing 18 changed files with 1,318 additions and 2,030 deletions.
6 changes: 3 additions & 3 deletions contracts/access-control/RBAC.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

import "../interfaces/access-control/IRBAC.sol";

import "../libs/arrays/ArrayHelper.sol";
import "../libs/utils/TypeCaster.sol";
import "../libs/arrays/SetHelper.sol";

/**
Expand All @@ -24,7 +24,7 @@ import "../libs/arrays/SetHelper.sol";
abstract contract RBAC is IRBAC, Initializable {
using StringSet for StringSet.Set;
using SetHelper for StringSet.Set;
using ArrayHelper for string;
using TypeCaster for string;

string public constant MASTER_ROLE = "MASTER";

Expand Down Expand Up @@ -57,7 +57,7 @@ abstract contract RBAC is IRBAC, Initializable {
* @notice The init function
*/
function __RBAC_init() internal onlyInitializing {
_addPermissionsToRole(MASTER_ROLE, ALL_RESOURCE, ALL_PERMISSION.asArray(), true);
_addPermissionsToRole(MASTER_ROLE, ALL_RESOURCE, ALL_PERMISSION.asSingletonArray(), true);
}

/**
Expand Down
90 changes: 73 additions & 17 deletions contracts/libs/arrays/ArrayHelper.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/utils/math/Math.sol";

/**
* @notice A simple library to work with arrays
*/
Expand Down Expand Up @@ -40,6 +42,16 @@ library ArrayHelper {
}
}

function reverse(bytes32[] memory arr_) internal pure returns (bytes32[] memory reversed_) {
reversed_ = new bytes32[](arr_.length);
uint256 i = arr_.length;

while (i > 0) {
i--;
reversed_[arr_.length - 1 - i] = arr_[i];
}
}

/**
* @notice The function to insert an array into the other array
* @param to_ the array to insert into
Expand Down Expand Up @@ -83,24 +95,16 @@ library ArrayHelper {
return index_ + what_.length;
}

/**
* @notice The function to transform an element into an array
* @param elem_ the element
* @return array_ the element as an array
*/
function asArray(uint256 elem_) internal pure returns (uint256[] memory array_) {
array_ = new uint256[](1);
array_[0] = elem_;
}

function asArray(address elem_) internal pure returns (address[] memory array_) {
array_ = new address[](1);
array_[0] = elem_;
}
function insert(
bytes32[] memory to_,
uint256 index_,
bytes32[] memory what_
) internal pure returns (uint256) {
for (uint256 i = 0; i < what_.length; i++) {
to_[index_ + i] = what_[i];
}

function asArray(string memory elem_) internal pure returns (string[] memory array_) {
array_ = new string[](1);
array_[0] = elem_;
return index_ + what_.length;
}

/**
Expand Down Expand Up @@ -143,4 +147,56 @@ library ArrayHelper {

return prefixes_[endIndex_] - prefixes_[beginIndex_ - 1];
}

/**
* @notice The function that searches for the index of the first occurring element, which is
* greater than or equal to the `element_`. The time complexity is O(log n)
* @param array_ the array to search in
* @param element_ the element
* @return index_ the index of the found element or the length of the `array_` if no such element
*/
function lowerBound(
uint256[] memory array_,
uint256 element_
) internal pure returns (uint256 index_) {
(uint256 low_, uint256 high_) = (0, array_.length);

while (low_ < high_) {
uint256 mid_ = Math.average(low_, high_);

if (array_[mid_] >= element_) {
high_ = mid_;
} else {
low_ = mid_ + 1;
}
}

return high_;
}

/**
* @notice The function that searches for the index of the first occurring element, which is
* greater than the `element_`. The time complexity is O(log n)
* @param array_ the array to search in
* @param element_ the element
* @return index_ the index of the found element or the length of the `array_` if no such element
*/
function upperBound(
uint256[] memory array_,
uint256 element_
) internal pure returns (uint256 index_) {
(uint256 low_, uint256 high_) = (0, array_.length);

while (low_ < high_) {
uint256 mid_ = Math.average(low_, high_);

if (array_[mid_] > element_) {
high_ = mid_;
} else {
low_ = mid_ + 1;
}
}

return high_;
}
}
128 changes: 52 additions & 76 deletions contracts/libs/data-structures/PriorityQueue.sol
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "../utils/TypeCaster.sol";

/**
* @notice The library that realizes a heap based priority queue.
*
* Courtesy of heap property,
* add(), remove(), and removeTop() operations are O(log(n)) complex
* top() operation is O(1)
* add() and removeTop() operations are O(log(n)) complex
* top(), topValue() operations are O(1)
*
* The library might be useful to implement priority withdrawals/purchases, reputation based systems, and similar logic.
*
* The library is a maximal priority queue. The element with the highest priority is the topmost element.
* If you wish a minimal queue, change the priority of the elements to type(uint256).max - priority.
*
* Note the queue order of the elements with the same priority is not guaranteed.
* IMPORTANT
* The queue order of the elements is NOT guaranteed.
* The interaction with the data structure must be made via the topmost element only.
*
* Usage example:
*
Expand All @@ -22,6 +26,8 @@ pragma solidity ^0.8.4;
* using PriorityQueue for PriorityQueue.Bytes32Queue;
*/
library PriorityQueue {
using TypeCaster for *;

/**
************************
* UintQueue *
Expand All @@ -43,29 +49,31 @@ library PriorityQueue {
}

/**
* @notice The function to remove an element from the queue by index. O(log(n)) complex
* @notice The function to remove the element with the highest priority. O(log(n)) complex
* @param queue self
* @param index_ the index of the element to remove
*/
function remove(UintQueue storage queue, uint256 index_) internal {
_remove(queue._queue, index_);
function removeTop(UintQueue storage queue) internal {
_removeTop(queue._queue);
}

/**
* @notice The function to remove the element with the highest priority. O(log(n)) complex
* @notice The function to read the value of the element with the highest priority. O(1) complex
* @param queue self
* @return the value of the element with the highest priority
*/
function removeTop(UintQueue storage queue) internal {
_removeTop(queue._queue);
function topValue(UintQueue storage queue) internal view returns (uint256) {
return uint256(_topValue(queue._queue));
}

/**
* @notice The function to read the element with the highest priority. O(1) complex
* @param queue self
* @return the element with the highest priority
*/
function top(UintQueue storage queue) internal view returns (uint256) {
return uint256(_top(queue._queue));
function top(UintQueue storage queue) internal view returns (uint256, uint256) {
(bytes32 value_, uint256 priority_) = _top(queue._queue);

return (uint256(value_), priority_);
}

/**
Expand All @@ -78,15 +86,13 @@ library PriorityQueue {
}

/**
* @notice The function to read the element of the queue by index. O(1) complex
* @notice The function to get the values stored in the queue. O(n) complex
* It is very expensive to call this function as it reads all the queue elements. Use cautiously
* @param queue self
* @param index_ the index of the element to read
* @return the value and the priority of the element
* @return values_ the values of the elements stored
*/
function at(UintQueue storage queue, uint256 index_) internal view returns (uint256, uint256) {
(bytes32 value_, uint256 priority_) = _at(queue._queue, index_);

return (uint256(value_), priority_);
function values(UintQueue storage queue) internal view returns (uint256[] memory values_) {
return _values(queue._queue).asUint256Array();
}

/**
Expand All @@ -96,16 +102,10 @@ library PriorityQueue {
* @return values_ the values of the elements stored
* @return priorities_ the priorities of the elements stored
*/
function values(
function elements(
UintQueue storage queue
) internal view returns (uint256[] memory values_, uint256[] memory priorities_) {
bytes32[] memory vals_ = _values(queue._queue);

assembly {
values_ := vals_
}

priorities_ = _priorities(queue._queue);
return (_values(queue._queue).asUint256Array(), _priorities(queue._queue));
}

/**
Expand All @@ -122,30 +122,27 @@ library PriorityQueue {
_add(queue._queue, value_, priority_);
}

function remove(Bytes32Queue storage queue, uint256 index_) internal {
_remove(queue._queue, index_);
}

function removeTop(Bytes32Queue storage queue) internal {
_removeTop(queue._queue);
}

function top(Bytes32Queue storage queue) internal view returns (bytes32) {
function topValue(Bytes32Queue storage queue) internal view returns (bytes32) {
return _topValue(queue._queue);
}

function top(Bytes32Queue storage queue) internal view returns (bytes32, uint256) {
return _top(queue._queue);
}

function length(Bytes32Queue storage queue) internal view returns (uint256) {
return _length(queue._queue);
}

function at(
Bytes32Queue storage queue,
uint256 index_
) internal view returns (bytes32, uint256) {
return _at(queue._queue, index_);
function values(Bytes32Queue storage queue) internal view returns (bytes32[] memory values_) {
values_ = _values(queue._queue);
}

function values(
function elements(
Bytes32Queue storage queue
) internal view returns (bytes32[] memory values_, uint256[] memory priorities_) {
values_ = _values(queue._queue);
Expand All @@ -166,41 +163,32 @@ library PriorityQueue {
_add(queue._queue, bytes32(uint256(uint160(value_))), priority_);
}

function remove(AddressQueue storage queue, uint256 index_) internal {
_remove(queue._queue, index_);
}

function removeTop(AddressQueue storage queue) internal {
_removeTop(queue._queue);
}

function top(AddressQueue storage queue) internal view returns (address) {
return address(uint160(uint256(_top(queue._queue))));
function topValue(AddressQueue storage queue) internal view returns (address) {
return address(uint160(uint256(_topValue(queue._queue))));
}

function top(AddressQueue storage queue) internal view returns (address, uint256) {
(bytes32 value_, uint256 priority_) = _top(queue._queue);

return (address(uint160(uint256(value_))), priority_);
}

function length(AddressQueue storage queue) internal view returns (uint256) {
return _length(queue._queue);
}

function at(
AddressQueue storage queue,
uint256 index_
) internal view returns (address, uint256) {
(bytes32 value_, uint256 priority_) = _at(queue._queue, index_);

return (address(uint160(uint256(value_))), priority_);
function values(AddressQueue storage queue) internal view returns (address[] memory values_) {
return _values(queue._queue).asAddressArray();
}

function values(
function elements(
AddressQueue storage queue
) internal view returns (address[] memory values_, uint256[] memory priorities_) {
bytes32[] memory vals_ = _values(queue._queue);

assembly {
values_ := vals_
}

priorities_ = _priorities(queue._queue);
return (_values(queue._queue).asAddressArray(), _priorities(queue._queue));
}

/**
Expand All @@ -221,18 +209,6 @@ library PriorityQueue {
_shiftUp(queue, queue._values.length - 1);
}

function _remove(Queue storage queue, uint256 index_) private {
_requireNotEmpty(queue);

if (index_ > 0) {
queue._priorities[index_] = queue._priorities[0] + 1;

_shiftUp(queue, index_);
}

_removeTop(queue);
}

function _removeTop(Queue storage queue) private {
_requireNotEmpty(queue);

Expand All @@ -247,18 +223,18 @@ library PriorityQueue {
_shiftDown(queue, 0);
}

function _top(Queue storage queue) private view returns (bytes32) {
function _topValue(Queue storage queue) private view returns (bytes32) {
_requireNotEmpty(queue);

return queue._values[0];
}

function _length(Queue storage queue) private view returns (uint256) {
return queue._values.length;
function _top(Queue storage queue) private view returns (bytes32, uint256) {
return (_topValue(queue), queue._priorities[0]);
}

function _at(Queue storage queue, uint256 index_) private view returns (bytes32, uint256) {
return (queue._values[index_], queue._priorities[index_]);
function _length(Queue storage queue) private view returns (uint256) {
return queue._values.length;
}

function _values(Queue storage queue) private view returns (bytes32[] memory) {
Expand Down
Loading

0 comments on commit d6e8bee

Please sign in to comment.