@@ -48,6 +48,7 @@ pub struct Graphemes<'a> {
48
48
extended : bool ,
49
49
cat : Option < GraphemeCat > ,
50
50
catb : Option < GraphemeCat > ,
51
+ regional_count_back : Option < usize > ,
51
52
}
52
53
53
54
// state machine for cluster boundary rules
@@ -85,6 +86,11 @@ impl<'a> Iterator for Graphemes<'a> {
85
86
let mut idx = 0 ;
86
87
let mut state = Start ;
87
88
let mut cat = gr:: GC_Any ;
89
+
90
+ // caching used by next_back() should be invalidated
91
+ self . regional_count_back = None ;
92
+ self . catb = None ;
93
+
88
94
for ( curr, ch) in self . string . char_indices ( ) {
89
95
idx = curr;
90
96
@@ -292,12 +298,15 @@ impl<'a> DoubleEndedIterator for Graphemes<'a> {
292
298
Regional => { // rule GB12/GB13
293
299
// Need to scan backward to find if this is preceded by an odd or even number
294
300
// of Regional_Indicator characters.
295
- //
296
- // TODO: Save this state to avoid O(n^2) re-scanning in long RI sequences?
297
- let prev_chars = self . string [ ..previdx] . chars ( ) . rev ( ) ;
298
- let count = prev_chars. take_while ( |c| {
299
- gr:: grapheme_category ( * c) == gr:: GC_Regional_Indicator
300
- } ) . count ( ) ;
301
+ let count = match self . regional_count_back {
302
+ Some ( count) => count,
303
+ None => self . string [ ..previdx] . chars ( ) . rev ( ) . take_while ( |c| {
304
+ gr:: grapheme_category ( * c) == gr:: GC_Regional_Indicator
305
+ } ) . count ( )
306
+ } ;
307
+ // Cache the count to avoid re-scanning the same chars on the next iteration.
308
+ self . regional_count_back = count. checked_sub ( 1 ) ;
309
+
301
310
if count % 2 == 0 {
302
311
take_curr = false ;
303
312
break ;
@@ -372,7 +381,13 @@ impl<'a> DoubleEndedIterator for Graphemes<'a> {
372
381
373
382
#[ inline]
374
383
pub fn new_graphemes < ' b > ( s : & ' b str , is_extended : bool ) -> Graphemes < ' b > {
375
- Graphemes { string : s, extended : is_extended, cat : None , catb : None }
384
+ Graphemes {
385
+ string : s,
386
+ extended : is_extended,
387
+ cat : None ,
388
+ catb : None ,
389
+ regional_count_back : None
390
+ }
376
391
}
377
392
378
393
#[ inline]
0 commit comments