-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove dependency on solidity-stringutils
#91
base: main
Are you sure you want to change the base?
Conversation
* Returns whether the subject string contains the search string. | ||
*/ | ||
function contains(string memory subject, string memory search) internal returns (bool) { | ||
Vm vm = Vm(Utils.CHEATCODE_ADDRESS); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thing that can be defined only once as a library constant:
library StringFinder {
Vm private constant VM = Vm(Utils.CHEATCODE_ADDRESS);
function contains(string memory subject, string memory search) internal returns (bool) {
return VM.contains(subject, search);
}
function startsWith(string memory subject, string memory search) internal pure returns (bool) {
return VM.indexOf(subject, search) == 0;
}
// ...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't work on some older versions of Solidity 0.8.x which should be supported for previous versions of OpenZeppelin Contracts.
Vm vm = Vm(Utils.CHEATCODE_ADDRESS); | ||
uint256 index = vm.indexOf(subject, search); | ||
return index == 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could do without the Vm:
return return bytes(subject).length >= bytes(search).length
&& string(bytes(subject).slice(0, bytes(search).length)).equal(search);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that it would be pure, without would allow all the previously view function to remain view
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't use Bytes.slice
here because we want to support OpenZeppelin Contracts 4.x and 5.x, and Bytes isn't available in some older versions. We also can't just copy in the Bytes.slice
code because older versions of Solidity don't support mcopy
.
src/internal/StringFinder.sol
Outdated
Vm vm = Vm(Utils.CHEATCODE_ADDRESS); | ||
if (!vm.contains(subject, search)) { | ||
return false; | ||
} | ||
string[] memory tokens = vm.split(subject, search); | ||
return bytes(tokens[tokens.length - 1]).length == 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same:
return bytes(subject).length >= bytes(search).length
&& string(bytes(subject).slice(bytes(subject).length - bytes(search).length)).equal(search);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same reasoning as my other comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the use of vm.contains
, similar to the suggestion in count()
. This allows this to be pure
, and reverted some other functions' mutability to view.
src/internal/StringFinder.sol
Outdated
if (!vm.contains(subject, search)) { | ||
return 0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is the contains really needed ?
I'm expecting vm.split(subject, search)
to return a string[1] that contains everything when search is not present in subject.
So tokens.length
is 1, and tokens.length - 1
is 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that neither this is not a correct implementation of count. It will not return the correct value when the instances overlap. For example, count("aaa", "aa")
should return 2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed vm.split
. Changed function documentation to say that this is for non-overlapping occurrences, as we currently don't have a use case for counting overlaps.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm thinking that there may be stuff from solidity-stringutils that we want to put in our String.sol
solidity-stringutils
. Instead, uses a combination of OpenZeppelin's Strings library, Forge's string cheatcodes, and an internal library for additional string finder functions.Core._deployFromBytecode
as/// @solidity memory-safe-assembly
. This annotation is used instead ofassembly ("memory-safe")
so that it remains compatible with versions of Solidity used in both OpenZeppelin Contracts v4 and v5.Fixes #89