@@ -4398,49 +4398,91 @@ protected int notValidUtf8(Object string, int byteIndex,
4398
4398
}
4399
4399
}
4400
4400
4401
+ /** Search pattern in string starting after offset characters, and return a character index or nil */
4401
4402
@ Primitive (name = "string_character_index" , lowerFixnum = 2 )
4402
- public abstract static class StringCharacterIndexPrimitiveNode extends PrimitiveArrayArgumentsNode {
4403
+ @ NodeChild (value = "string" , type = RubyNode .class )
4404
+ @ NodeChild (value = "pattern" , type = RubyNode .class )
4405
+ @ NodeChild (value = "offset" , type = RubyNode .class )
4406
+ public abstract static class StringCharacterIndexNode extends PrimitiveNode {
4403
4407
4404
- @ TruffleBoundary
4405
- @ Specialization
4406
- protected Object stringCharacterIndex (Object string , Object pattern , int offset ,
4407
- @ CachedLibrary (limit = "2" ) RubyStringLibrary stringLibrary ,
4408
- @ CachedLibrary (limit = "2" ) RubyStringLibrary patternLibrary ,
4409
- @ Cached RopeNodes .CalculateCharacterLengthNode calculateCharacterLengthNode ) {
4410
- if (offset < 0 ) {
4411
- return nil ;
4412
- }
4408
+ @ Child SingleByteOptimizableNode singleByteOptimizableNode = SingleByteOptimizableNode .create ();
4413
4409
4414
- final Rope stringRope = stringLibrary .getRope (string );
4415
- final Rope patternRope = patternLibrary .getRope (pattern );
4410
+ @ CreateCast ("string" )
4411
+ protected RubyNode coerceStringToRope (RubyNode string ) {
4412
+ return ToRopeNodeGen .create (string );
4413
+ }
4416
4414
4417
- final int total = stringRope .byteLength ();
4418
- int p = 0 ;
4419
- final int e = p + total ;
4415
+ @ CreateCast ("pattern" )
4416
+ protected RubyNode coercePatternToRope (RubyNode pattern ) {
4417
+ return ToRopeNodeGen .create (pattern );
4418
+ }
4419
+
4420
+ @ Specialization (
4421
+ guards = {
4422
+ "offset >= 0" ,
4423
+ "singleByteOptimizableNode.execute(stringRope)" ,
4424
+ "!patternFits(stringRope, patternRope, offset)" })
4425
+ protected Object patternTooLarge (Rope stringRope , Rope patternRope , int offset ) {
4426
+ return nil ;
4427
+ }
4428
+
4429
+ @ Specialization (
4430
+ guards = {
4431
+ "offset >= 0" ,
4432
+ "singleByteOptimizableNode.execute(stringRope)" ,
4433
+ "patternFits(stringRope, patternRope, offset)" })
4434
+ protected Object singleByteOptimizable (Rope stringRope , Rope patternRope , int offset ,
4435
+ @ Cached RopeNodes .BytesNode stringBytesNode ,
4436
+ @ Cached RopeNodes .BytesNode patternBytesNode ,
4437
+ @ Cached LoopConditionProfile loopProfile ,
4438
+ @ Cached ("createCountingProfile()" ) ConditionProfile matchProfile ) {
4439
+
4440
+ int p = offset ;
4441
+ final int e = stringRope .byteLength ();
4420
4442
final int pe = patternRope .byteLength ();
4421
4443
final int l = e - pe + 1 ;
4422
4444
4423
- final byte [] stringBytes = stringRope . getBytes ( );
4424
- final byte [] patternBytes = patternRope . getBytes ( );
4445
+ final byte [] stringBytes = stringBytesNode . execute ( stringRope );
4446
+ final byte [] patternBytes = patternBytesNode . execute ( patternRope );
4425
4447
4426
- if ( stringRope . isSingleByteOptimizable ()) {
4427
- for (p += offset ; p < l ; p ++) {
4428
- if (ArrayUtils .memcmp (stringBytes , p , patternBytes , 0 , pe ) == 0 ) {
4448
+ try {
4449
+ for (; loopProfile . profile ( p < l ) ; p ++) {
4450
+ if (matchProfile . profile ( ArrayUtils .memcmp (stringBytes , p , patternBytes , 0 , pe ) == 0 ) ) {
4429
4451
return p ;
4430
4452
}
4431
4453
}
4432
-
4433
- return nil ;
4454
+ } finally {
4455
+ LoopNode . reportLoopCount ( this , p - offset ) ;
4434
4456
}
4435
4457
4458
+ return nil ;
4459
+ }
4460
+
4461
+ @ TruffleBoundary
4462
+ @ Specialization (
4463
+ guards = {
4464
+ "offset >= 0" ,
4465
+ "!singleByteOptimizableNode.execute(stringRope)" })
4466
+ protected Object multiByte (Rope stringRope , Rope patternRope , int offset ,
4467
+ @ Cached RopeNodes .CalculateCharacterLengthNode calculateCharacterLengthNode ,
4468
+ @ Cached RopeNodes .BytesNode stringBytesNode ,
4469
+ @ Cached RopeNodes .BytesNode patternBytesNode ) {
4470
+
4471
+ int p = 0 ;
4472
+ final int e = stringRope .byteLength ();
4473
+ final int pe = patternRope .byteLength ();
4474
+ final int l = e - pe + 1 ;
4475
+
4476
+ final byte [] stringBytes = stringBytesNode .execute (stringRope );
4477
+ final byte [] patternBytes = patternBytesNode .execute (patternRope );
4478
+
4436
4479
final Encoding enc = stringRope .getEncoding ();
4437
4480
final CodeRange cr = stringRope .getCodeRange ();
4438
- int index = 0 ;
4439
4481
int c = 0 ;
4482
+ int index = 0 ;
4440
4483
4441
4484
while (p < e && index < offset ) {
4442
4485
c = calculateCharacterLengthNode .characterLength (enc , cr , Bytes .fromRange (stringBytes , p , e ));
4443
-
4444
4486
if (StringSupport .MBCLEN_CHARFOUND_P (c )) {
4445
4487
p += c ;
4446
4488
index ++;
@@ -4461,13 +4503,18 @@ protected Object stringCharacterIndex(Object string, Object pattern, int offset,
4461
4503
4462
4504
return nil ;
4463
4505
}
4506
+
4507
+ protected boolean patternFits (Rope stringRope , Rope patternRope , int offset ) {
4508
+ return offset + patternRope .byteLength () <= stringRope .byteLength ();
4509
+ }
4464
4510
}
4465
4511
4512
+ /** Search pattern in string starting after offset bytes, and return a byte index or nil */
4466
4513
@ Primitive (name = "string_byte_index" , lowerFixnum = 2 )
4467
4514
@ NodeChild (value = "string" , type = RubyNode .class )
4468
4515
@ NodeChild (value = "pattern" , type = RubyNode .class )
4469
4516
@ NodeChild (value = "offset" , type = RubyNode .class )
4470
- public abstract static class StringByteIndexPrimitiveNode extends PrimitiveNode {
4517
+ public abstract static class StringByteIndexNode extends PrimitiveNode {
4471
4518
4472
4519
@ Child SingleByteOptimizableNode singleByteOptimizableNode = SingleByteOptimizableNode .create ();
4473
4520
@@ -4481,26 +4528,17 @@ protected RubyNode coercePatternToRope(RubyNode pattern) {
4481
4528
return ToRopeNodeGen .create (pattern );
4482
4529
}
4483
4530
4484
- @ Specialization (guards = "offset < 0" )
4485
- protected Object stringByteIndexNegativeOffset (Rope stringRope , Rope patternRope , int offset ) {
4486
- return nil ;
4487
- }
4488
-
4489
- @ Specialization (
4490
- guards = {
4491
- "offset >= 0" ,
4492
- "singleByteOptimizableNode.execute(stringRope)" ,
4493
- "patternRope.byteLength() > stringRope.byteLength()" })
4494
- protected Object stringByteIndexPatternTooLarge (Rope stringRope , Rope patternRope , int offset ) {
4531
+ @ Specialization (guards = { "offset >= 0" , "!patternFits(stringRope, patternRope, offset)" })
4532
+ protected Object patternTooLarge (Rope stringRope , Rope patternRope , int offset ) {
4495
4533
return nil ;
4496
4534
}
4497
4535
4498
4536
@ Specialization (
4499
4537
guards = {
4500
4538
"offset >= 0" ,
4501
4539
"singleByteOptimizableNode.execute(stringRope)" ,
4502
- "patternRope.byteLength() <= stringRope.byteLength( )" })
4503
- protected Object stringCharacterIndexSingleByteOptimizable (Rope stringRope , Rope patternRope , int offset ,
4540
+ "patternFits(stringRope, patternRope, offset )" })
4541
+ protected Object singleByteOptimizable (Rope stringRope , Rope patternRope , int offset ,
4504
4542
@ Cached RopeNodes .BytesNode stringBytesNode ,
4505
4543
@ Cached RopeNodes .BytesNode patternBytesNode ,
4506
4544
@ Cached LoopConditionProfile loopProfile ,
@@ -4532,8 +4570,8 @@ protected Object stringCharacterIndexSingleByteOptimizable(Rope stringRope, Rope
4532
4570
guards = {
4533
4571
"offset >= 0" ,
4534
4572
"!singleByteOptimizableNode.execute(stringRope)" ,
4535
- "patternRope.byteLength() <= stringRope.byteLength( )" })
4536
- protected Object stringCharacterIndex (Rope stringRope , Rope patternRope , int offset ,
4573
+ "patternFits(stringRope, patternRope, offset )" })
4574
+ protected Object multiByte (Rope stringRope , Rope patternRope , int offset ,
4537
4575
@ Cached RopeNodes .CalculateCharacterLengthNode calculateCharacterLengthNode ,
4538
4576
@ Cached RopeNodes .BytesNode stringBytesNode ,
4539
4577
@ Cached RopeNodes .BytesNode patternBytesNode ) {
@@ -4548,7 +4586,7 @@ protected Object stringCharacterIndex(Rope stringRope, Rope patternRope, int off
4548
4586
4549
4587
final Encoding enc = stringRope .getEncoding ();
4550
4588
final CodeRange cr = stringRope .getCodeRange ();
4551
- int c = 0 ;
4589
+ int c ;
4552
4590
4553
4591
for (; p < l ; p += c ) {
4554
4592
c = calculateCharacterLengthNode .characterLength (enc , cr , Bytes .fromRange (stringBytes , p , e ));
@@ -4562,6 +4600,10 @@ protected Object stringCharacterIndex(Rope stringRope, Rope patternRope, int off
4562
4600
4563
4601
return nil ;
4564
4602
}
4603
+
4604
+ protected boolean patternFits (Rope stringRope , Rope patternRope , int offset ) {
4605
+ return offset + patternRope .byteLength () <= stringRope .byteLength ();
4606
+ }
4565
4607
}
4566
4608
4567
4609
/** Calculates the byte offset of a character, indicated by a character index, starting from a provided byte offset
0 commit comments