Skip to content

Commit f4498c7

Browse files
committed
auto merge of #11497 : huonw/rust/trie-internal-iter, r=alexcrichton
This stores the stack of iterators inline (we have a maximum depth with `uint` keys), and then uses direct pointer offsetting to manipulate it, in a blazing fast way: Before: bench_iter_large ... bench: 43187 ns/iter (+/- 3082) bench_iter_small ... bench: 618 ns/iter (+/- 288) After: bench_iter_large ... bench: 13497 ns/iter (+/- 1575) bench_iter_small ... bench: 220 ns/iter (+/- 91) Also, removes `.each_{key,value}_reverse` as an offering to placate the gods of external iterators for my heinous sin of attempting to add new internal ones (in a previous version of this PR).
2 parents 2ff358c + 0148055 commit f4498c7

File tree

1 file changed

+119
-52
lines changed

1 file changed

+119
-52
lines changed

src/libstd/trie.rs

+119-52
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@
1111
//! Ordered containers with integer keys, implemented as radix tries (`TrieSet` and `TrieMap` types)
1212
1313
use prelude::*;
14+
use mem;
1415
use uint;
1516
use util::replace;
17+
use unstable::intrinsics::init;
1618
use vec;
1719

1820
// FIXME: #5244: need to manually update the TrieNode constructor
1921
static SHIFT: uint = 4;
2022
static SIZE: uint = 1 << SHIFT;
2123
static MASK: uint = SIZE - 1;
24+
static NUM_CHUNKS: uint = uint::bits / SHIFT;
2225

2326
enum Child<T> {
2427
Internal(~TrieNode<T>),
@@ -111,35 +114,27 @@ impl<T> TrieMap<T> {
111114
self.root.each_reverse(f)
112115
}
113116

114-
/// Visit all keys in reverse order
115-
#[inline]
116-
pub fn each_key_reverse(&self, f: |&uint| -> bool) -> bool {
117-
self.each_reverse(|k, _| f(k))
118-
}
119-
120-
/// Visit all values in reverse order
121-
#[inline]
122-
pub fn each_value_reverse(&self, f: |&T| -> bool) -> bool {
123-
self.each_reverse(|_, v| f(v))
124-
}
125-
126117
/// Get an iterator over the key-value pairs in the map
127118
pub fn iter<'a>(&'a self) -> TrieMapIterator<'a, T> {
128-
TrieMapIterator {
129-
stack: ~[self.root.children.iter()],
130-
remaining_min: self.length,
131-
remaining_max: self.length
132-
}
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
133126
}
134127

135128
/// Get an iterator over the key-value pairs in the map, with the
136129
/// ability to mutate the values.
137130
pub fn mut_iter<'a>(&'a mut self) -> TrieMapMutIterator<'a, T> {
138-
TrieMapMutIterator {
139-
stack: ~[self.root.children.mut_iter()],
140-
remaining_min: self.length,
141-
remaining_max: self.length
142-
}
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
143138
}
144139
}
145140

@@ -188,16 +183,16 @@ macro_rules! bound {
188183

189184
let key = $key;
190185

191-
let mut idx = 0;
192-
let mut it = $iterator_name {
193-
stack: ~[],
194-
remaining_min: 0,
195-
remaining_max: this.length
196-
};
186+
let mut it = unsafe {$iterator_name::new()};
187+
// everything else is zero'd, as we want.
188+
it.remaining_max = this.length;
189+
197190
// this addr is necessary for the `Internal` pattern.
198191
addr!(loop {
199192
let children = unsafe {addr!(& $($mut_)* (*node).children)};
200-
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);
201196
let (slice_idx, ret) = match children[child_id] {
202197
Internal(ref $($mut_)* n) => {
203198
node = addr!(& $($mut_)* **n as * $($mut_)* TrieNode<T>);
@@ -214,9 +209,10 @@ macro_rules! bound {
214209
(child_id + 1, true)
215210
}
216211
};
217-
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;
218215
if ret { return it }
219-
idx += 1;
220216
})
221217
}
222218
}
@@ -328,7 +324,7 @@ impl TrieSet {
328324
/// Visit all values in reverse order
329325
#[inline]
330326
pub fn each_reverse(&self, f: |&uint| -> bool) -> bool {
331-
self.map.each_key_reverse(f)
327+
self.map.each_reverse(|k, _| f(k))
332328
}
333329

334330
/// Get an iterator over the values in the set
@@ -479,15 +475,17 @@ fn remove<T>(count: &mut uint, child: &mut Child<T>, key: uint,
479475

480476
/// Forward iterator over a map
481477
pub struct TrieMapIterator<'a, T> {
482-
priv stack: ~[vec::VecIterator<'a, Child<T>>],
478+
priv stack: [vec::VecIterator<'a, Child<T>>, .. NUM_CHUNKS],
479+
priv length: uint,
483480
priv remaining_min: uint,
484481
priv remaining_max: uint
485482
}
486483

487484
/// Forward iterator over the key-value pairs of a map, with the
488485
/// values being mutable.
489486
pub struct TrieMapMutIterator<'a, T> {
490-
priv stack: ~[vec::VecMutIterator<'a, Child<T>>],
487+
priv stack: [vec::VecMutIterator<'a, Child<T>>, .. NUM_CHUNKS],
488+
priv length: uint,
491489
priv remaining_min: uint,
492490
priv remaining_max: uint
493491
}
@@ -499,27 +497,96 @@ macro_rules! iterator_impl {
499497
($name:ident,
500498
iter = $iter:ident,
501499
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+
502528
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).
503545
fn next(&mut self) -> Option<(uint, &'a $($mut_)* T)> {
504-
while !self.stack.is_empty() {
505-
match self.stack[self.stack.len() - 1].next() {
506-
None => {
507-
self.stack.pop();
508-
}
509-
Some(child) => {
510-
addr!(match *child {
511-
Internal(ref $($mut_)* node) => {
512-
self.stack.push(node.children.$iter());
513-
}
514-
External(key, ref $($mut_)* value) => {
515-
self.remaining_max -= 1;
516-
if self.remaining_min > 0 {
517-
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));
518586
}
519-
return Some((key, value));
520-
}
521-
Nothing => {}
522-
})
587+
Nothing => {}
588+
})
589+
}
523590
}
524591
}
525592
}

0 commit comments

Comments
 (0)