11
11
//! Ordered containers with integer keys, implemented as radix tries (`TrieSet` and `TrieMap` types)
12
12
13
13
use prelude:: * ;
14
+ use mem;
14
15
use uint;
15
16
use util:: replace;
17
+ use unstable:: intrinsics:: init;
16
18
use vec;
17
19
18
20
// FIXME: #5244: need to manually update the TrieNode constructor
19
21
static SHIFT : uint = 4 ;
20
22
static SIZE : uint = 1 << SHIFT ;
21
23
static MASK : uint = SIZE - 1 ;
24
+ static NUM_CHUNKS : uint = uint:: bits / SHIFT ;
22
25
23
26
enum Child < T > {
24
27
Internal ( ~TrieNode < T > ) ,
@@ -113,21 +116,25 @@ impl<T> TrieMap<T> {
113
116
114
117
/// Get an iterator over the key-value pairs in the map
115
118
pub fn iter < ' a > ( & ' a self ) -> TrieMapIterator < ' a , T > {
116
- TrieMapIterator {
117
- stack : ~[ self . root . children . iter ( ) ] ,
118
- remaining_min : self . length ,
119
- remaining_max : self . length
120
- }
119
+ let mut iter = unsafe { TrieMapIterator :: new ( ) } ;
120
+ iter. stack [ 0 ] = self . root . children . iter ( ) ;
121
+ iter. length = 1 ;
122
+ iter. remaining_min = self . length ;
123
+ iter. remaining_max = self . length ;
124
+
125
+ iter
121
126
}
122
127
123
128
/// Get an iterator over the key-value pairs in the map, with the
124
129
/// ability to mutate the values.
125
130
pub fn mut_iter < ' a > ( & ' a mut self ) -> TrieMapMutIterator < ' a , T > {
126
- TrieMapMutIterator {
127
- stack : ~[ self . root . children . mut_iter ( ) ] ,
128
- remaining_min : self . length ,
129
- remaining_max : self . length
130
- }
131
+ let mut iter = unsafe { TrieMapMutIterator :: new ( ) } ;
132
+ iter. stack [ 0 ] = self . root . children . mut_iter ( ) ;
133
+ iter. length = 1 ;
134
+ iter. remaining_min = self . length ;
135
+ iter. remaining_max = self . length ;
136
+
137
+ iter
131
138
}
132
139
}
133
140
@@ -176,16 +183,16 @@ macro_rules! bound {
176
183
177
184
let key = $key;
178
185
179
- let mut idx = 0 ;
180
- let mut it = $iterator_name {
181
- stack: ~[ ] ,
182
- remaining_min: 0 ,
183
- remaining_max: this. length
184
- } ;
186
+ let mut it = unsafe { $iterator_name:: new( ) } ;
187
+ // everything else is zero'd, as we want.
188
+ it. remaining_max = this. length;
189
+
185
190
// this addr is necessary for the `Internal` pattern.
186
191
addr!( loop {
187
192
let children = unsafe { addr!( & $( $mut_) * ( * node) . children) } ;
188
- let child_id = chunk( key, idx) ;
193
+ // it.length is the current depth in the iterator and the
194
+ // current depth through the `uint` key we've traversed.
195
+ let child_id = chunk( key, it. length) ;
189
196
let ( slice_idx, ret) = match children[ child_id] {
190
197
Internal ( ref $( $mut_) * n) => {
191
198
node = addr!( & $( $mut_) * * * n as * $( $mut_) * TrieNode <T >) ;
@@ -202,9 +209,10 @@ macro_rules! bound {
202
209
( child_id + 1 , true )
203
210
}
204
211
} ;
205
- it. stack. push( children. $slice_from( slice_idx) . $iter( ) ) ;
212
+ // push to the stack.
213
+ it. stack[ it. length] = children. $slice_from( slice_idx) . $iter( ) ;
214
+ it. length += 1 ;
206
215
if ret { return it }
207
- idx += 1 ;
208
216
} )
209
217
}
210
218
}
@@ -467,15 +475,17 @@ fn remove<T>(count: &mut uint, child: &mut Child<T>, key: uint,
467
475
468
476
/// Forward iterator over a map
469
477
pub struct TrieMapIterator < ' a , T > {
470
- priv stack : ~[ vec:: VecIterator < ' a , Child < T > > ] ,
478
+ priv stack : [ vec:: VecIterator < ' a , Child < T > > , .. NUM_CHUNKS ] ,
479
+ priv length : uint ,
471
480
priv remaining_min : uint ,
472
481
priv remaining_max : uint
473
482
}
474
483
475
484
/// Forward iterator over the key-value pairs of a map, with the
476
485
/// values being mutable.
477
486
pub struct TrieMapMutIterator < ' a , T > {
478
- priv stack : ~[ vec:: VecMutIterator < ' a , Child < T > > ] ,
487
+ priv stack : [ vec:: VecMutIterator < ' a , Child < T > > , .. NUM_CHUNKS ] ,
488
+ priv length : uint ,
479
489
priv remaining_min : uint ,
480
490
priv remaining_max : uint
481
491
}
@@ -487,27 +497,96 @@ macro_rules! iterator_impl {
487
497
( $name: ident,
488
498
iter = $iter: ident,
489
499
mutability = $( $mut_: tt) * ) => {
500
+ impl <' a, T > $name<' a, T > {
501
+ // Create new zero'd iterator. We have a thin gilding of safety by
502
+ // using init rather than uninit, so that the worst that can happen
503
+ // from failing to initialise correctly after calling these is a
504
+ // segfault.
505
+ #[ cfg( target_word_size="32" ) ]
506
+ unsafe fn new( ) -> $name<' a, T > {
507
+ $name {
508
+ remaining_min: 0 ,
509
+ remaining_max: 0 ,
510
+ length: 0 ,
511
+ // ick :( ... at least the compiler will tell us if we screwed up.
512
+ stack: [ init( ) , init( ) , init( ) , init( ) , init( ) , init( ) , init( ) , init( ) ]
513
+ }
514
+ }
515
+
516
+ #[ cfg( target_word_size="64" ) ]
517
+ unsafe fn new( ) -> $name<' a, T > {
518
+ $name {
519
+ remaining_min: 0 ,
520
+ remaining_max: 0 ,
521
+ length: 0 ,
522
+ stack: [ init( ) , init( ) , init( ) , init( ) , init( ) , init( ) , init( ) , init( ) ,
523
+ init( ) , init( ) , init( ) , init( ) , init( ) , init( ) , init( ) , init( ) ]
524
+ }
525
+ }
526
+ }
527
+
490
528
item!( impl <' a, T > Iterator <( uint, & ' a $( $mut_) * T ) > for $name<' a, T > {
529
+ // you might wonder why we're not even trying to act within the
530
+ // rules, and are just manipulating raw pointers like there's no
531
+ // such thing as invalid pointers and memory unsafety. The
532
+ // reason is performance, without doing this we can get the
533
+ // bench_iter_large microbenchmark down to about 30000 ns/iter
534
+ // (using .unsafe_ref to index self.stack directly, 38000
535
+ // ns/iter with [] checked indexing), but this smashes that down
536
+ // to 13500 ns/iter.
537
+ //
538
+ // Fortunately, it's still safe...
539
+ //
540
+ // We have an invariant that every Internal node
541
+ // corresponds to one push to self.stack, and one pop,
542
+ // nested appropriately. self.stack has enough storage
543
+ // to store the maximum depth of Internal nodes in the
544
+ // trie (8 on 32-bit platforms, 16 on 64-bit).
491
545
fn next( & mut self ) -> Option <( uint, & ' a $( $mut_) * T ) > {
492
- while !self . stack. is_empty( ) {
493
- match self . stack[ self . stack. len( ) - 1 ] . next( ) {
494
- None => {
495
- self . stack. pop( ) ;
496
- }
497
- Some ( child) => {
498
- addr!( match * child {
499
- Internal ( ref $( $mut_) * node) => {
500
- self . stack. push( node. children. $iter( ) ) ;
501
- }
502
- External ( key, ref $( $mut_) * value) => {
503
- self . remaining_max -= 1 ;
504
- if self . remaining_min > 0 {
505
- self . remaining_min -= 1 ;
546
+ let start_ptr = self . stack. as_mut_ptr( ) ;
547
+
548
+ unsafe {
549
+ // write_ptr is the next place to write to the stack.
550
+ // invariant: start_ptr <= write_ptr < end of the
551
+ // vector.
552
+ let mut write_ptr = start_ptr. offset( self . length as int) ;
553
+ while write_ptr != start_ptr {
554
+ // indexing back one is safe, since write_ptr >
555
+ // start_ptr now.
556
+ match ( * write_ptr. offset( -1 ) ) . next( ) {
557
+ // exhausted this iterator (i.e. finished this
558
+ // Internal node), so pop from the stack.
559
+ //
560
+ // don't bother clearing the memory, because the
561
+ // next time we use it we'll've written to it
562
+ // first.
563
+ None => write_ptr = write_ptr. offset( -1 ) ,
564
+ Some ( child) => {
565
+ addr!( match * child {
566
+ Internal ( ref $( $mut_) * node) => {
567
+ // going down a level, so push
568
+ // to the stack (this is the
569
+ // write referenced above)
570
+ * write_ptr = node. children. $iter( ) ;
571
+ write_ptr = write_ptr. offset( 1 ) ;
572
+ }
573
+ External ( key, ref $( $mut_) * value) => {
574
+ self . remaining_max -= 1 ;
575
+ if self . remaining_min > 0 {
576
+ self . remaining_min -= 1 ;
577
+ }
578
+ // store the new length of the
579
+ // stack, based on our current
580
+ // position.
581
+ self . length = ( write_ptr as uint
582
+ - start_ptr as uint) /
583
+ mem:: size_of_val( & * write_ptr) ;
584
+
585
+ return Some ( ( key, value) ) ;
506
586
}
507
- return Some ( ( key, value) ) ;
508
- }
509
- Nothing => { }
510
- } )
587
+ Nothing => { }
588
+ } )
589
+ }
511
590
}
512
591
}
513
592
}
0 commit comments