-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstrings.sol
114 lines (108 loc) · 4.31 KB
/
strings.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/*
* @title String & slice utility library for Solidity contracts.
* @author Nick Johnson <[email protected]>
*
* @dev Functionality in this library is largely implemented using an
* abstraction called a 'slice'. A slice represents a part of a string -
* anything from the entire string to a single character, or even no
* characters at all (a 0-length slice). Since a slice only has to specify
* an offset and a length, copying and manipulating slices is a lot less
* expensive than copying and manipulating the strings they reference.
*
* To further reduce gas costs, most functions on slice that need to return
* a slice modify the original one instead of allocating a new one; for
* instance, `s.split(".")` will return the text up to the first '.',
* modifying s to only contain the remainder of the string after the '.'.
* In situations where you do not want to modify the original slice, you
* can make a copy first with `.copy()`, for example:
* `s.copy().split(".")`. Try and avoid using this idiom in loops; since
* Solidity has no memory management, it will result in allocating many
* short-lived slices that are later discarded.
*
* Functions that return two slices come in two versions: a non-allocating
* version that takes the second slice as an argument, modifying it in
* place, and an allocating version that allocates and returns the second
* slice; see `nextRune` for example.
*
* Functions that have to copy string data will return strings rather than
* slices; these can be cast back to slices for further processing if
* required.
*
* For convenience, some functions are provided with non-modifying
* variants that create a new slice and return both; for instance,
* `s.splitNew('.')` leaves s unmodified, and returns two values
* corresponding to the left and right parts of the string.
*/
pragma solidity ^0.8.0;
library strings {
struct slice {
uint256 _len;
uint256 _ptr;
}
/*
* @dev Returns a slice containing the entire string.
* @param self The string to make a slice from.
* @return A newly allocated slice containing the entire string.
*/
function toSlice(string memory self) internal pure returns (slice memory) {
uint256 ptr;
assembly {
ptr := add(self, 0x20)
}
return slice(bytes(self).length, ptr);
}
/*
* @dev Returns a positive number if `other` comes lexicographically after
* `self`, a negative number if it comes before, or zero if the
* contents of the two slices are equal. Comparison is done per-rune,
* on unicode codepoints.
* @param self The first slice to compare.
* @param other The second slice to compare.
* @return The result of the comparison.
*/
function compare(slice memory self, slice memory other)
internal
pure
returns (int256)
{
uint256 shortest = self._len;
if (other._len < self._len) shortest = other._len;
uint256 selfptr = self._ptr;
uint256 otherptr = other._ptr;
for (uint256 idx = 0; idx < shortest; idx += 32) {
uint256 a;
uint256 b;
assembly {
a := mload(selfptr)
b := mload(otherptr)
}
if (a != b) {
// Mask out irrelevant bytes and check again
uint256 mask = type(uint256).max; // 0xffff...
if (shortest < 32) {
mask = ~(2**(8 * (32 - shortest + idx)) - 1);
}
unchecked {
uint256 diff = (a & mask) - (b & mask);
if (diff != 0) return int256(diff);
}
}
selfptr += 32;
otherptr += 32;
}
return int256(self._len) - int256(other._len);
}
/*
* @dev Returns true if the two slices contain the same text.
* @param self The first slice to compare.
* @param self The second slice to compare.
* @return True if the slices are equal, false otherwise.
*/
function equals(slice memory self, slice memory other)
internal
pure
returns (bool)
{
return compare(self, other) == 0;
}
}