1313 */
1414final class SequenceMatcher
1515{
16- const OPCODE_DELETE = ' del ' ;
16+ // people may prefer this for debugging
1717 const OPCODE_EQUAL = 'eq ' ;
18+ const OPCODE_DELETE = 'del ' ;
1819 const OPCODE_INSERT = 'ins ' ;
1920 const OPCODE_REPLACE = 'rep ' ;
2021
22+ // people may prefer this for bit operations
23+ const OPCODE_INT_EQUAL = 1 << 0 ;
24+ const OPCODE_INT_DELETE = 1 << 1 ;
25+ const OPCODE_INT_INSERT = 1 << 2 ;
26+ const OPCODE_INT_REPLACE = 1 << 3 ;
27+
2128 /**
2229 * @var null|callable either a string or an array containing a callback function to determine if a line is "junk" or not
2330 */
@@ -34,7 +41,7 @@ final class SequenceMatcher
3441 private $ b = [];
3542
3643 /**
37- * @var array Array of characters that are considered junk from the second sequence. Characters are the array key.
44+ * @var array array of characters that are considered junk from the second sequence. Characters are the array key.
3845 */
3946 private $ junkDict = [];
4047
@@ -54,6 +61,17 @@ final class SequenceMatcher
5461 private static $ defaultOptions = [
5562 'ignoreWhitespace ' => false ,
5663 'ignoreCase ' => false ,
64+ 'useIntOpcodes ' => false ,
65+ ];
66+
67+ /**
68+ * @var array opcode constants
69+ */
70+ private $ ops = [
71+ // 'eq' => ?,
72+ // 'del' => ?,
73+ // 'ins' => ?,
74+ // 'rep' => ?,
5775 ];
5876
5977 /**
@@ -67,7 +85,7 @@ final class SequenceMatcher
6785 private $ matchingBlocks = [];
6886
6987 /**
70- * @var array
88+ * @var array generated opcodes which manipulates seq1 to seq2
7189 */
7290 private $ opcodes = [];
7391
@@ -97,7 +115,23 @@ public function __construct(array $a, array $b, ?callable $junkCallback = null,
97115 */
98116 public function setOptions (array $ options ): self
99117 {
100- $ this ->options = $ options + static ::$ defaultOptions ;
118+ $ this ->options = $ options + self ::$ defaultOptions ;
119+
120+ $ this ->setOps ($ this ->options ['useIntOpcodes ' ]);
121+ $ this ->resetchedResults ();
122+
123+ return $ this ;
124+ }
125+
126+ /**
127+ * Reset cached results.
128+ *
129+ * @return self
130+ */
131+ public function resetchedResults (): self
132+ {
133+ $ this ->matchingBlocks = [];
134+ $ this ->opcodes = [];
101135
102136 return $ this ;
103137 }
@@ -129,8 +163,7 @@ public function setSeq1(array $a): self
129163 {
130164 if ($ this ->a !== $ a ) {
131165 $ this ->a = $ a ;
132- $ this ->matchingBlocks = [];
133- $ this ->opcodes = [];
166+ $ this ->resetchedResults ();
134167 }
135168
136169 return $ this ;
@@ -148,15 +181,25 @@ public function setSeq2(array $b): self
148181 {
149182 if ($ this ->b !== $ b ) {
150183 $ this ->b = $ b ;
151- $ this ->matchingBlocks = [] ;
152- $ this -> opcodes = [];
184+ $ this ->resetchedResults () ;
185+
153186 $ this ->fullBCount = [];
154187 $ this ->chainB ();
155188 }
156189
157190 return $ this ;
158191 }
159192
193+ /**
194+ * Get the ops.
195+ *
196+ * @return array the ops
197+ */
198+ public function getOps (): array
199+ {
200+ return $ this ->ops ;
201+ }
202+
160203 /**
161204 * Find the longest matching block in the two sequences, as defined by the
162205 * lower and upper constraints for each sequence. (for the first sequence,
@@ -403,11 +446,11 @@ public function getOpcodes(): array
403446
404447 foreach ($ this ->getMatchingBlocks () as [$ ai , $ bj , $ size ]) {
405448 if ($ i < $ ai && $ j < $ bj ) {
406- $ tag = static :: OPCODE_REPLACE ;
449+ $ tag = $ this -> ops [ ' rep ' ] ;
407450 } elseif ($ i < $ ai ) {
408- $ tag = static :: OPCODE_DELETE ;
451+ $ tag = $ this -> ops [ ' del ' ] ;
409452 } elseif ($ j < $ bj ) {
410- $ tag = static :: OPCODE_INSERT ;
453+ $ tag = $ this -> ops [ ' ins ' ] ;
411454 } else {
412455 $ tag = null ;
413456 }
@@ -420,7 +463,7 @@ public function getOpcodes(): array
420463 $ j = $ bj + $ size ;
421464
422465 if ($ size ) {
423- $ this ->opcodes [] = [static :: OPCODE_EQUAL , $ ai , $ i , $ bj , $ j ];
466+ $ this ->opcodes [] = [$ this -> ops [ ' eq ' ] , $ ai , $ i , $ bj , $ j ];
424467 }
425468 }
426469
@@ -448,11 +491,11 @@ public function getGroupedOpcodes(int $context = 3): array
448491
449492 if (empty ($ opcodes )) {
450493 $ opcodes = [
451- [static :: OPCODE_EQUAL , 0 , 1 , 0 , 1 ],
494+ [$ this -> ops [ ' eq ' ] , 0 , 1 , 0 , 1 ],
452495 ];
453496 }
454497
455- if ($ opcodes [0 ][0 ] === static :: OPCODE_EQUAL ) {
498+ if ($ opcodes [0 ][0 ] === $ this -> ops [ ' eq ' ] ) {
456499 $ opcodes [0 ] = [
457500 $ opcodes [0 ][0 ],
458501 \max ($ opcodes [0 ][1 ], $ opcodes [0 ][2 ] - $ context ),
@@ -463,7 +506,7 @@ public function getGroupedOpcodes(int $context = 3): array
463506 }
464507
465508 $ lastItem = \count ($ opcodes ) - 1 ;
466- if ($ opcodes [$ lastItem ][0 ] === static :: OPCODE_EQUAL ) {
509+ if ($ opcodes [$ lastItem ][0 ] === $ this -> ops [ ' eq ' ] ) {
467510 [$ tag , $ i1 , $ i2 , $ j1 , $ j2 ] = $ opcodes [$ lastItem ];
468511 $ opcodes [$ lastItem ] = [
469512 $ tag ,
@@ -477,7 +520,7 @@ public function getGroupedOpcodes(int $context = 3): array
477520 $ maxRange = $ context << 1 ;
478521 $ groups = $ group = [];
479522 foreach ($ opcodes as [$ tag , $ i1 , $ i2 , $ j1 , $ j2 ]) {
480- if ($ tag === static :: OPCODE_EQUAL && $ i2 - $ i1 > $ maxRange ) {
523+ if ($ tag === $ this -> ops [ ' eq ' ] && $ i2 - $ i1 > $ maxRange ) {
481524 $ group [] = [
482525 $ tag ,
483526 $ i1 ,
@@ -496,7 +539,7 @@ public function getGroupedOpcodes(int $context = 3): array
496539
497540 if (
498541 !empty ($ group ) &&
499- (\count ($ group ) !== 1 || $ group [0 ][0 ] !== static :: OPCODE_EQUAL )
542+ (\count ($ group ) !== 1 || $ group [0 ][0 ] !== $ this -> ops [ ' eq ' ] )
500543 ) {
501544 $ groups [] = $ group ;
502545 }
@@ -529,6 +572,36 @@ public function ratio(): float
529572 return $ this ->calculateRatio ($ matchesCount , \count ($ this ->a ) + \count ($ this ->b ));
530573 }
531574
575+ /**
576+ * Set the ops.
577+ *
578+ * @param bool $useIntOpcodes to use int opcodes or not
579+ *
580+ * @return self
581+ */
582+ private function setOps (bool $ useIntOpcodes ): self
583+ {
584+ if ($ useIntOpcodes ) {
585+ $ this ->ops = [
586+ 'del ' => self ::OPCODE_INT_DELETE ,
587+ 'eq ' => self ::OPCODE_INT_EQUAL ,
588+ 'ins ' => self ::OPCODE_INT_INSERT ,
589+ 'rep ' => self ::OPCODE_INT_REPLACE ,
590+ ];
591+ } else {
592+ $ this ->ops = [
593+ 'del ' => self ::OPCODE_DELETE ,
594+ 'eq ' => self ::OPCODE_EQUAL ,
595+ 'ins ' => self ::OPCODE_INSERT ,
596+ 'rep ' => self ::OPCODE_REPLACE ,
597+ ];
598+ }
599+
600+ $ this ->resetchedResults ();
601+
602+ return $ this ;
603+ }
604+
532605 /**
533606 * Generate the internal arrays containing the list of junk and non-junk
534607 * characters for the second ($b) sequence.
0 commit comments