@@ -42,7 +42,7 @@ library strings {
42
42
uint _ptr;
43
43
}
44
44
45
- function memcpy (uint dest , uint src , uint len ) private {
45
+ function memcpy (uint dest , uint src , uint len ) private pure {
46
46
// Copy word-length chunks while possible
47
47
for (; len >= 32 ; len -= 32 ) {
48
48
assembly {
@@ -66,7 +66,7 @@ library strings {
66
66
* @param self The string to make a slice from.
67
67
* @return A newly allocated slice containing the entire string.
68
68
*/
69
- function toSlice (string self ) internal returns (slice) {
69
+ function toSlice (string self ) internal pure returns (slice) {
70
70
uint ptr;
71
71
assembly {
72
72
ptr := add (self, 0x20 )
@@ -79,7 +79,7 @@ library strings {
79
79
* @param self The value to find the length of.
80
80
* @return The length of the string, from 0 to 32.
81
81
*/
82
- function len (bytes32 self ) internal returns (uint ) {
82
+ function len (bytes32 self ) internal pure returns (uint ) {
83
83
uint ret;
84
84
if (self == 0 )
85
85
return 0 ;
@@ -112,7 +112,7 @@ library strings {
112
112
* @return A new slice containing the value of the input argument up to the
113
113
* first null.
114
114
*/
115
- function toSliceB32 (bytes32 self ) internal returns (slice ret ) {
115
+ function toSliceB32 (bytes32 self ) internal pure returns (slice ret ) {
116
116
// Allocate space for `self` in memory, copy it there, and point ret at it
117
117
assembly {
118
118
let ptr := mload (0x40 )
@@ -128,7 +128,7 @@ library strings {
128
128
* @param self The slice to copy.
129
129
* @return A new slice containing the same data as `self`.
130
130
*/
131
- function copy (slice self ) internal returns (slice) {
131
+ function copy (slice self ) internal pure returns (slice) {
132
132
return slice (self._len, self._ptr);
133
133
}
134
134
@@ -137,7 +137,7 @@ library strings {
137
137
* @param self The slice to copy.
138
138
* @return A newly allocated string containing the slice's text.
139
139
*/
140
- function toString (slice self ) internal returns (string ) {
140
+ function toString (slice self ) internal pure returns (string ) {
141
141
string memory ret = new string (self._len);
142
142
uint retptr;
143
143
assembly { retptr := add (ret, 32 ) }
@@ -146,10 +146,6 @@ library strings {
146
146
return ret;
147
147
}
148
148
149
- function len (string self ) internal returns (uint l ) {
150
- return len (toSlice (self));
151
- }
152
-
153
149
/*
154
150
* @dev Returns the length in runes of the slice. Note that this operation
155
151
* takes time proportional to the length of the slice; avoid using it
@@ -158,7 +154,7 @@ library strings {
158
154
* @param self The slice to operate on.
159
155
* @return The length of the slice in runes.
160
156
*/
161
- function len (slice self ) internal returns (uint l ) {
157
+ function len (slice self ) internal pure returns (uint l ) {
162
158
// Starting at ptr-31 means the LSB will be the byte we care about
163
159
uint ptr = self._ptr - 31 ;
164
160
uint end = ptr + self._len;
@@ -186,22 +182,10 @@ library strings {
186
182
* @param self The slice to operate on.
187
183
* @return True if the slice is empty, False otherwise.
188
184
*/
189
- function empty (slice self ) internal returns (bool ) {
185
+ function empty (slice self ) internal pure returns (bool ) {
190
186
return self._len == 0 ;
191
187
}
192
188
193
- function compare (string self , string other ) internal returns (int ) {
194
- return compare (toSlice (self), toSlice (other));
195
- }
196
-
197
- function compare (string self , slice other ) internal returns (int ) {
198
- return compare (toSlice (self), other);
199
- }
200
-
201
- function compare (slice self , string other ) internal returns (int ) {
202
- return compare (self, toSlice (other));
203
- }
204
-
205
189
/*
206
190
* @dev Returns a positive number if `other` comes lexicographically after
207
191
* `self`, a negative number if it comes before, or zero if the
@@ -211,7 +195,7 @@ library strings {
211
195
* @param other The second slice to compare.
212
196
* @return The result of the comparison.
213
197
*/
214
- function compare (slice self , slice other ) internal returns (int ) {
198
+ function compare (slice self , slice other ) internal pure returns (int ) {
215
199
uint shortest = self._len;
216
200
if (other._len < self._len)
217
201
shortest = other._len;
@@ -244,7 +228,7 @@ library strings {
244
228
* @param self The second slice to compare.
245
229
* @return True if the slices are equal, false otherwise.
246
230
*/
247
- function equals (slice self , slice other ) internal returns (bool ) {
231
+ function equals (slice self , slice other ) internal pure returns (bool ) {
248
232
return compare (self, other) == 0 ;
249
233
}
250
234
@@ -255,7 +239,7 @@ library strings {
255
239
* @param rune The slice that will contain the first rune.
256
240
* @return `rune`.
257
241
*/
258
- function nextRune (slice self , slice rune ) internal returns (slice) {
242
+ function nextRune (slice self , slice rune ) internal pure returns (slice) {
259
243
rune._ptr = self._ptr;
260
244
261
245
if (self._len == 0 ) {
@@ -297,7 +281,7 @@ library strings {
297
281
* @param self The slice to operate on.
298
282
* @return A slice containing only the first rune from `self`.
299
283
*/
300
- function nextRune (slice self ) internal returns (slice ret ) {
284
+ function nextRune (slice self ) internal pure returns (slice ret ) {
301
285
nextRune (self, ret);
302
286
}
303
287
@@ -306,7 +290,7 @@ library strings {
306
290
* @param self The slice to operate on.
307
291
* @return The number of the first codepoint in the slice.
308
292
*/
309
- function ord (slice self ) internal returns (uint ret ) {
293
+ function ord (slice self ) internal pure returns (uint ret ) {
310
294
if (self._len == 0 ) {
311
295
return 0 ;
312
296
}
@@ -355,7 +339,7 @@ library strings {
355
339
* @param self The slice to hash.
356
340
* @return The hash of the slice.
357
341
*/
358
- function keccak (slice self ) internal returns (bytes32 ret ) {
342
+ function keccak (slice self ) internal pure returns (bytes32 ret ) {
359
343
assembly {
360
344
ret := keccak256 (mload (add (self, 32 )), mload (self))
361
345
}
@@ -367,7 +351,7 @@ library strings {
367
351
* @param needle The slice to search for.
368
352
* @return True if the slice starts with the provided text, false otherwise.
369
353
*/
370
- function startsWith (slice self , slice needle ) internal returns (bool ) {
354
+ function startsWith (slice self , slice needle ) internal pure returns (bool ) {
371
355
if (self._len < needle._len) {
372
356
return false ;
373
357
}
@@ -393,7 +377,7 @@ library strings {
393
377
* @param needle The slice to search for.
394
378
* @return `self`
395
379
*/
396
- function beyond (slice self , slice needle ) internal returns (slice) {
380
+ function beyond (slice self , slice needle ) internal pure returns (slice) {
397
381
if (self._len < needle._len) {
398
382
return self;
399
383
}
@@ -422,7 +406,7 @@ library strings {
422
406
* @param needle The slice to search for.
423
407
* @return True if the slice starts with the provided text, false otherwise.
424
408
*/
425
- function endsWith (slice self , slice needle ) internal returns (bool ) {
409
+ function endsWith (slice self , slice needle ) internal pure returns (bool ) {
426
410
if (self._len < needle._len) {
427
411
return false ;
428
412
}
@@ -450,7 +434,7 @@ library strings {
450
434
* @param needle The slice to search for.
451
435
* @return `self`
452
436
*/
453
- function until (slice self , slice needle ) internal returns (slice) {
437
+ function until (slice self , slice needle ) internal pure returns (slice) {
454
438
if (self._len < needle._len) {
455
439
return self;
456
440
}
@@ -472,33 +456,37 @@ library strings {
472
456
return self;
473
457
}
474
458
459
+ event log_bytemask (bytes32 mask );
460
+
475
461
// Returns the memory address of the first byte of the first occurrence of
476
462
// `needle` in `self`, or the first byte after `self` if not found.
477
- function findPtr (uint selflen , uint selfptr , uint needlelen , uint needleptr ) private returns (uint ) {
478
- uint ptr;
463
+ function findPtr (uint selflen , uint selfptr , uint needlelen , uint needleptr ) private pure returns (uint ) {
464
+ uint ptr = selfptr ;
479
465
uint idx;
480
466
481
467
if (needlelen <= selflen) {
482
468
if (needlelen <= 32 ) {
483
- // Optimized assembly for 68 gas per byte on short strings
484
- assembly {
485
- let mask := not (sub (exp (2 , mul (8 , sub (32 , needlelen))), 1 ))
486
- let needledata := and (mload (needleptr), mask)
487
- let end := add (selfptr, sub (selflen, needlelen))
488
- ptr := selfptr
489
- loop:
490
- jumpi (exit, eq (and (mload (ptr), mask), needledata))
491
- ptr := add (ptr, 1 )
492
- jumpi (loop, lt (sub (ptr, 1 ), end))
493
- ptr := add (selfptr, selflen)
494
- exit:
469
+ bytes32 mask = bytes32 (~ (2 ** (8 * (32 - needlelen)) - 1 ));
470
+
471
+ bytes32 needledata;
472
+ assembly { needledata := and (mload (needleptr), mask) }
473
+
474
+ uint end = selfptr + selflen - needlelen;
475
+ bytes32 ptrdata;
476
+ assembly { ptrdata := and (mload (ptr), mask) }
477
+
478
+ while (ptrdata != needledata) {
479
+ if (ptr >= end)
480
+ return selfptr + selflen;
481
+ ptr++ ;
482
+ assembly { ptrdata := and (mload (ptr), mask) }
495
483
}
496
484
return ptr;
497
485
} else {
498
486
// For long needles, use hashing
499
487
bytes32 hash;
500
488
assembly { hash := sha3 (needleptr, needlelen) }
501
- ptr = selfptr;
489
+
502
490
for (idx = 0 ; idx <= selflen - needlelen; idx++ ) {
503
491
bytes32 testHash;
504
492
assembly { testHash := sha3 (ptr, needlelen) }
@@ -513,27 +501,27 @@ library strings {
513
501
514
502
// Returns the memory address of the first byte after the last occurrence of
515
503
// `needle` in `self`, or the address of `self` if not found.
516
- function rfindPtr (uint selflen , uint selfptr , uint needlelen , uint needleptr ) private returns (uint ) {
504
+ function rfindPtr (uint selflen , uint selfptr , uint needlelen , uint needleptr ) private pure returns (uint ) {
517
505
uint ptr;
518
506
519
507
if (needlelen <= selflen) {
520
508
if (needlelen <= 32 ) {
521
- // Optimized assembly for 69 gas per byte on short strings
522
- assembly {
523
- let mask := not ( sub ( exp ( 2 , mul ( 8 , sub ( 32 , needlelen))), 1 ))
524
- let needledata := and (mload (needleptr), mask)
525
- ptr := add (selfptr, sub (selflen, needlelen))
526
- loop:
527
- jumpi (ret, eq ( and ( mload (ptr), mask), needledata))
528
- ptr := sub ( ptr, 1 )
529
- jumpi (loop, gt ( add (ptr, 1 ), selfptr))
530
- ptr := selfptr
531
- jump (exit)
532
- ret:
533
- ptr := add (ptr, needlelen)
534
- exit:
509
+ bytes32 mask = bytes32 ( ~ ( 2 ** ( 8 * ( 32 - needlelen)) - 1 ));
510
+
511
+ bytes32 needledata;
512
+ assembly { needledata := and (mload (needleptr), mask) }
513
+
514
+ ptr = selfptr + selflen - needlelen;
515
+ bytes32 ptrdata;
516
+ assembly { ptrdata := and ( mload ( ptr), mask) }
517
+
518
+ while (ptrdata != needledata) {
519
+ if (ptr <= selfptr)
520
+ return selfptr;
521
+ ptr-- ;
522
+ assembly { ptrdata := and ( mload (ptr), mask) }
535
523
}
536
- return ptr;
524
+ return ptr + needlelen ;
537
525
} else {
538
526
// For long needles, use hashing
539
527
bytes32 hash;
@@ -559,7 +547,7 @@ library strings {
559
547
* @param needle The text to search for.
560
548
* @return `self`.
561
549
*/
562
- function find (slice self , slice needle ) internal returns (slice) {
550
+ function find (slice self , slice needle ) internal pure returns (slice) {
563
551
uint ptr = findPtr (self._len, self._ptr, needle._len, needle._ptr);
564
552
self._len -= ptr - self._ptr;
565
553
self._ptr = ptr;
@@ -574,7 +562,7 @@ library strings {
574
562
* @param needle The text to search for.
575
563
* @return `self`.
576
564
*/
577
- function rfind (slice self , slice needle ) internal returns (slice) {
565
+ function rfind (slice self , slice needle ) internal pure returns (slice) {
578
566
uint ptr = rfindPtr (self._len, self._ptr, needle._len, needle._ptr);
579
567
self._len = ptr - self._ptr;
580
568
return self;
@@ -590,7 +578,7 @@ library strings {
590
578
* @param token An output parameter to which the first token is written.
591
579
* @return `token`.
592
580
*/
593
- function split (slice self , slice needle , slice token ) internal returns (slice) {
581
+ function split (slice self , slice needle , slice token ) internal pure returns (slice) {
594
582
uint ptr = findPtr (self._len, self._ptr, needle._len, needle._ptr);
595
583
token._ptr = self._ptr;
596
584
token._len = ptr - self._ptr;
@@ -613,7 +601,7 @@ library strings {
613
601
* @param needle The text to search for in `self`.
614
602
* @return The part of `self` up to the first occurrence of `delim`.
615
603
*/
616
- function split (slice self , slice needle ) internal returns (slice token ) {
604
+ function split (slice self , slice needle ) internal pure returns (slice token ) {
617
605
split (self, needle, token);
618
606
}
619
607
@@ -627,7 +615,7 @@ library strings {
627
615
* @param token An output parameter to which the first token is written.
628
616
* @return `token`.
629
617
*/
630
- function rsplit (slice self , slice needle , slice token ) internal returns (slice) {
618
+ function rsplit (slice self , slice needle , slice token ) internal pure returns (slice) {
631
619
uint ptr = rfindPtr (self._len, self._ptr, needle._len, needle._ptr);
632
620
token._ptr = ptr;
633
621
token._len = self._len - (ptr - self._ptr);
@@ -649,7 +637,7 @@ library strings {
649
637
* @param needle The text to search for in `self`.
650
638
* @return The part of `self` after the last occurrence of `delim`.
651
639
*/
652
- function rsplit (slice self , slice needle ) internal returns (slice token ) {
640
+ function rsplit (slice self , slice needle ) internal pure returns (slice token ) {
653
641
rsplit (self, needle, token);
654
642
}
655
643
@@ -659,7 +647,7 @@ library strings {
659
647
* @param needle The text to search for in `self`.
660
648
* @return The number of occurrences of `needle` found in `self`.
661
649
*/
662
- function count (slice self , slice needle ) internal returns (uint cnt ) {
650
+ function count (slice self , slice needle ) internal pure returns (uint cnt ) {
663
651
uint ptr = findPtr (self._len, self._ptr, needle._len, needle._ptr) + needle._len;
664
652
while (ptr <= self._ptr + self._len) {
665
653
cnt++ ;
@@ -673,7 +661,7 @@ library strings {
673
661
* @param needle The text to search for in `self`.
674
662
* @return True if `needle` is found in `self`, false otherwise.
675
663
*/
676
- function contains (slice self , slice needle ) internal returns (bool ) {
664
+ function contains (slice self , slice needle ) internal pure returns (bool ) {
677
665
return rfindPtr (self._len, self._ptr, needle._len, needle._ptr) != self._ptr;
678
666
}
679
667
@@ -684,7 +672,7 @@ library strings {
684
672
* @param other The second slice to concatenate.
685
673
* @return The concatenation of the two strings.
686
674
*/
687
- function concat (slice self , slice other ) internal returns (string ) {
675
+ function concat (slice self , slice other ) internal pure returns (string ) {
688
676
string memory ret = new string (self._len + other._len);
689
677
uint retptr;
690
678
assembly { retptr := add (ret, 32 ) }
@@ -701,7 +689,7 @@ library strings {
701
689
* @return A newly allocated string containing all the slices in `parts`,
702
690
* joined with `self`.
703
691
*/
704
- function join (slice self , slice[] parts ) internal returns (string ) {
692
+ function join (slice self , slice[] parts ) internal pure returns (string ) {
705
693
if (parts.length == 0 )
706
694
return "" ;
707
695
0 commit comments