├── .gitignore ├── .travis.yml ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md └── src ├── bench_macros.rs ├── bin └── mem.rs ├── lib.rs └── map.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled files 2 | *.o 3 | *.so 4 | *.rlib 5 | *.dll 6 | 7 | # Executables 8 | *.exe 9 | 10 | # Generated by Cargo 11 | target 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - nightly 4 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | [root] 2 | name = "burst_trie" 3 | version = "0.0.1" 4 | dependencies = [ 5 | "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", 6 | ] 7 | 8 | [[package]] 9 | name = "libc" 10 | version = "0.2.17" 11 | source = "registry+https://github.com/rust-lang/crates.io-index" 12 | 13 | [[package]] 14 | name = "rand" 15 | version = "0.3.14" 16 | source = "registry+https://github.com/rust-lang/crates.io-index" 17 | dependencies = [ 18 | "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", 19 | ] 20 | 21 | [metadata] 22 | "checksum libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "044d1360593a78f5c8e5e710beccdc24ab71d1f01bc19a29bcacdba22e8475d8" 23 | "checksum rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2791d88c6defac799c3f20d74f094ca33b9332612d9aef9078519c82e4fe04a5" 24 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "burst_trie" 4 | version = "0.0.1" 5 | authors = ["arthurprs "] 6 | 7 | [dependencies] 8 | rand = "0.3.7" 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Arthur Silva 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BurstTrie 2 | 3 | [![Build Status](https://travis-ci.org/arthurprs/burst-trie.svg)](https://travis-ci.org/arthurprs/burst-trie) 4 | 5 | Implements an ordered map as an Adaptive Burst Trie. It's a very fast Trie variant specialized for byte ordered types (like strings). 6 | 7 | ***This is a work in progress*** 8 | 9 | This structure achieves better performance than a BTree implementations for common operations while 10 | still allowing range scanning and ordered iteration. 11 | 12 | Performance is always better than the std lib BTreeMap and it pulls ahead further if keys have common prefixes (See [benchmarks](#benchmarks)). In some specific cases it's even comparable to a HashMap while keeping the extra functionality of an ordered collections. 13 | Memory wise it consumes 80~100% as much memory as the equivalent BTreeMap/HashMap. 14 | 15 | *The Burst Trie was original described by S. Heinz. You can find the original paper in the internet by it's title 16 | "Burst Tries: A Fast, Efficient Data Structure for String Keys"* 17 | 18 | #### Limitations 19 | 20 | It's specialized for byte ordered keys, like String, &str and &[u8], adapters for other types could be implemented though. 21 | 22 | # TODO 23 | 24 | - [x] BTreeMap API 25 | - [x] Performance 26 | - [x] Reasonable Memory efficient (could be improved further with other node types) 27 | - [ ] Entry API 28 | - [ ] Compile on Rust Stable 29 | - [ ] Iterators 30 | - [ ] Range search 31 | - [ ] Prefix search 32 | - [ ] Set implementation 33 | - [ ] Path compression (Probably not effective in the Burst variant) 34 | 35 | # Benchmarks 36 | 37 | Benchmarks are most of the time pointless. But I figure the only reason to use this over the stdlib BTree implementation is speed. So let's get this over with and find out if it's useless or not. 38 | 39 | Note: unless stated as "seq" all benchmarks use uniformelly distributed random keys, which are the worst case scenario for the BurstTrie. Still, the average performance is very good. 40 | 41 | ``` 42 | test map::bench::btree_get_medium_1000 ... bench: 182 ns/iter (+/- 7) 43 | test map::bench::btree_get_medium_10000 ... bench: 292 ns/iter (+/- 13) 44 | test map::bench::btree_get_medium_100000 ... bench: 811 ns/iter (+/- 199) 45 | test map::bench::btree_get_prefix_medium_10000 ... bench: 540 ns/iter (+/- 119) 46 | test map::bench::btree_get_prefix_medium_100000 ... bench: 1,194 ns/iter (+/- 196) 47 | test map::bench::btree_get_seq_100000 ... bench: 333 ns/iter (+/- 40) 48 | test map::bench::btree_get_short_1000 ... bench: 142 ns/iter (+/- 10) 49 | test map::bench::btree_get_short_10000 ... bench: 227 ns/iter (+/- 11) 50 | test map::bench::btree_get_short_100000 ... bench: 543 ns/iter (+/- 278) 51 | test map::bench::btree_insert_medium_1000 ... bench: 267 ns/iter (+/- 27) 52 | test map::bench::btree_insert_medium_10000 ... bench: 378 ns/iter (+/- 123) 53 | test map::bench::btree_insert_medium_100000 ... bench: 490 ns/iter (+/- 89) 54 | test map::bench::btree_insert_prefix_medium_10000 ... bench: 491 ns/iter (+/- 82) 55 | test map::bench::btree_insert_prefix_medium_100000 ... bench: 632 ns/iter (+/- 60) 56 | test map::bench::btree_insert_seq_100000 ... bench: 725 ns/iter (+/- 208) 57 | test map::bench::btree_insert_short_1000 ... bench: 221 ns/iter (+/- 21) 58 | test map::bench::btree_insert_short_10000 ... bench: 332 ns/iter (+/- 52) 59 | test map::bench::btree_insert_short_100000 ... bench: 460 ns/iter (+/- 87) 60 | test map::bench::burst_get_medium_1000 ... bench: 148 ns/iter (+/- 15) 61 | test map::bench::burst_get_medium_10000 ... bench: 172 ns/iter (+/- 79) 62 | test map::bench::burst_get_medium_100000 ... bench: 658 ns/iter (+/- 271) 63 | test map::bench::burst_get_prefix_medium_10000 ... bench: 233 ns/iter (+/- 105) 64 | test map::bench::burst_get_prefix_medium_100000 ... bench: 757 ns/iter (+/- 83) 65 | test map::bench::burst_get_seq_100000 ... bench: 209 ns/iter (+/- 21) 66 | test map::bench::burst_get_short_1000 ... bench: 125 ns/iter (+/- 5) 67 | test map::bench::burst_get_short_10000 ... bench: 140 ns/iter (+/- 12) 68 | test map::bench::burst_get_short_100000 ... bench: 423 ns/iter (+/- 140) 69 | test map::bench::burst_insert_medium_1000 ... bench: 203 ns/iter (+/- 23) 70 | test map::bench::burst_insert_medium_10000 ... bench: 287 ns/iter (+/- 151) 71 | test map::bench::burst_insert_medium_100000 ... bench: 507 ns/iter (+/- 79) 72 | test map::bench::burst_insert_prefix_medium_10000 ... bench: 543 ns/iter (+/- 173) 73 | test map::bench::burst_insert_prefix_medium_100000 ... bench: 666 ns/iter (+/- 61) 74 | test map::bench::burst_insert_seq_100000 ... bench: 498 ns/iter (+/- 68) 75 | test map::bench::burst_insert_short_1000 ... bench: 175 ns/iter (+/- 13) 76 | test map::bench::burst_insert_short_10000 ... bench: 191 ns/iter (+/- 31) 77 | test map::bench::burst_insert_short_100000 ... bench: 365 ns/iter (+/- 108) 78 | test map::bench::hash_get_medium_1000 ... bench: 152 ns/iter (+/- 8) 79 | test map::bench::hash_get_medium_10000 ... bench: 183 ns/iter (+/- 98) 80 | test map::bench::hash_get_medium_100000 ... bench: 425 ns/iter (+/- 25) 81 | test map::bench::hash_get_prefix_medium_10000 ... bench: 192 ns/iter (+/- 12) 82 | test map::bench::hash_get_prefix_medium_100000 ... bench: 455 ns/iter (+/- 27) 83 | test map::bench::hash_get_short_1000 ... bench: 109 ns/iter (+/- 2) 84 | test map::bench::hash_get_short_10000 ... bench: 120 ns/iter (+/- 9) 85 | test map::bench::hash_get_short_100000 ... bench: 264 ns/iter (+/- 30) 86 | test map::bench::hash_insert_medium_1000 ... bench: 186 ns/iter (+/- 13) 87 | test map::bench::hash_insert_medium_10000 ... bench: 271 ns/iter (+/- 35) 88 | test map::bench::hash_insert_medium_100000 ... bench: 446 ns/iter (+/- 62) 89 | test map::bench::hash_insert_prefix_medium_10000 ... bench: 292 ns/iter (+/- 43) 90 | test map::bench::hash_insert_prefix_medium_100000 ... bench: 486 ns/iter (+/- 54) 91 | test map::bench::hash_insert_short_1000 ... bench: 133 ns/iter (+/- 6) 92 | test map::bench::hash_insert_short_10000 ... bench: 170 ns/iter (+/- 4) 93 | test map::bench::hash_insert_short_100000 ... bench: 278 ns/iter (+/- 75) 94 | ``` 95 | 96 | You can of course run it in your computer with ```cargo bench``` 97 | -------------------------------------------------------------------------------- /src/bench_macros.rs: -------------------------------------------------------------------------------- 1 | 2 | pub static BENCH_SEED: &'static[usize] = &[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]; 3 | 4 | macro_rules! map_get_rnd_bench { 5 | ($name: ident, $min_len: expr, $max_len: expr, $map_len: expr, $map_type: ident, $key_prefix: expr) => ( 6 | #[bench] 7 | fn $name(b: &mut test::Bencher) { 8 | use rand::{Rng, StdRng, SeedableRng}; 9 | 10 | let mut rng: StdRng = SeedableRng::from_seed(BENCH_SEED); 11 | let mut map = $map_type::new(); 12 | let value = 0usize; 13 | 14 | let keys = (0..$map_len).map(|_| { 15 | let key_len = rng.gen_range($min_len, $max_len); 16 | $key_prefix.to_string() + rng.gen_ascii_chars().take(key_len).collect::().as_ref() 17 | }).collect::>(); 18 | 19 | for key in &keys { 20 | map.insert(key.clone(), value); 21 | } 22 | 23 | b.iter(|| { 24 | let key = rng.choose(&keys).unwrap(); 25 | test::black_box(map.get(key)); 26 | }); 27 | 28 | test::black_box(map); 29 | } 30 | ); 31 | ($name: ident, $min_len: expr, $max_len: expr, $map_len: expr, $map_type: ident) => ( 32 | map_get_rnd_bench!($name, $min_len, $max_len, $map_len, $map_type, ""); 33 | ); 34 | } 35 | 36 | macro_rules! map_insert_rnd_bench { 37 | ($name: ident, $min_len: expr, $max_len: expr, $map_len: expr, $map_type: ident, $key_prefix: expr) => ( 38 | #[bench] 39 | fn $name(b: &mut test::Bencher) { 40 | use rand::{Rng, StdRng, SeedableRng}; 41 | 42 | let mut rng: StdRng = SeedableRng::from_seed(BENCH_SEED); 43 | let mut map = $map_type::new(); 44 | let value = 0usize; 45 | 46 | let keys = (0..$map_len).map(|_| { 47 | let key_len = rng.gen_range($min_len, $max_len); 48 | $key_prefix.to_string() + rng.gen_ascii_chars().take(key_len).collect::().as_ref() 49 | }).collect::>(); 50 | 51 | b.iter(|| { 52 | let key = rng.choose(&keys).unwrap(); 53 | map.insert(key.clone(), value); 54 | }); 55 | 56 | test::black_box(map); 57 | } 58 | ); 59 | ($name: ident, $min_len: expr, $max_len: expr, $map_len: expr, $map_type: ident) => ( 60 | map_insert_rnd_bench!($name, $min_len, $max_len, $map_len, $map_type, ""); 61 | ); 62 | } 63 | 64 | macro_rules! map_get_seq_bench { 65 | ($name: ident, $min_len: expr, $max_len: expr, $map_len: expr, $map_type: ident, $key_prefix: expr) => ( 66 | #[bench] 67 | fn $name(b: &mut test::Bencher) { 68 | use rand::{Rng, StdRng, SeedableRng}; 69 | 70 | let mut rng: StdRng = SeedableRng::from_seed(BENCH_SEED); 71 | let mut map = $map_type::new(); 72 | let value = 0usize; 73 | 74 | let start_num: u64 = "100000000000000000000000000000000000"[..$min_len].parse().unwrap(); 75 | 76 | let keys = (0..$map_len).map(|i| { 77 | let key_len = rng.gen_range(0, $max_len - $min_len); 78 | $key_prefix.to_string() + (start_num + i).to_string().as_ref() + rng.gen_ascii_chars().take(key_len).collect::().as_ref() 79 | }).collect::>(); 80 | 81 | for key in &keys { 82 | map.insert(key.clone(), value); 83 | } 84 | 85 | let mut i = 0; 86 | b.iter(|| { 87 | test::black_box(map.get(&keys[i % keys.len()])); 88 | i += 1; 89 | }); 90 | 91 | test::black_box(map); 92 | } 93 | ); 94 | ($name: ident, $min_len: expr, $max_len: expr, $map_len: expr, $map_type: ident) => ( 95 | map_get_seq_bench!($name, $min_len, $max_len, $map_len, $map_type, ""); 96 | ); 97 | } 98 | 99 | macro_rules! map_insert_seq_bench { 100 | ($name: ident, $min_len: expr, $max_len: expr, $map_len: expr, $map_type: ident, $key_prefix: expr) => ( 101 | #[bench] 102 | fn $name(b: &mut test::Bencher) { 103 | use rand::{Rng, StdRng, SeedableRng}; 104 | 105 | let mut rng: StdRng = SeedableRng::from_seed(BENCH_SEED); 106 | let mut map = $map_type::new(); 107 | let value = 0usize; 108 | 109 | let start_num: u64 = "100000000000000000000000000000000000"[..$min_len].parse().unwrap(); 110 | 111 | let keys = (0..$map_len).map(|i| { 112 | let key_len = rng.gen_range(0, $max_len - $min_len); 113 | $key_prefix.to_string() + (start_num + i).to_string().as_ref() + rng.gen_ascii_chars().take(key_len).collect::().as_ref() 114 | }).collect::>(); 115 | 116 | let mut i = 0; 117 | b.iter(|| { 118 | map.insert(keys[i % keys.len()].clone(), value); 119 | i += 1; 120 | }); 121 | 122 | test::black_box(map); 123 | } 124 | ); 125 | ($name: ident, $min_len: expr, $max_len: expr, $map_len: expr, $map_type: ident) => ( 126 | map_insert_seq_bench!($name, $min_len, $max_len, $map_len, $map_type, ""); 127 | ); 128 | } 129 | 130 | macro_rules! map_iter_bench { 131 | ($name: ident, $min_len: expr, $max_len: expr, $map_len: expr, $map_type: ident, $key_prefix: expr) => ( 132 | #[bench] 133 | fn $name(b: &mut test::Bencher) { 134 | use rand::{Rng, StdRng, SeedableRng}; 135 | 136 | let mut rng: StdRng = SeedableRng::from_seed(BENCH_SEED); 137 | let mut map = $map_type::new(); 138 | let value = 0usize; 139 | 140 | (0..$map_len).map(|_| { 141 | let key_len = rng.gen_range($min_len, $max_len); 142 | let key = $key_prefix.to_string() + rng.gen_ascii_chars().take(key_len).collect::().as_ref(); 143 | map.insert(key, value); 144 | }).count(); 145 | 146 | b.iter(|| { 147 | for (key, value) in map.iter() { 148 | test::black_box(key); 149 | test::black_box(value); 150 | } 151 | }); 152 | } 153 | ); 154 | ($name: ident, $min_len: expr, $max_len: expr, $map_len: expr, $map_type: ident) => ( 155 | map_iter_bench!($name, $min_len, $max_len, $map_len, $map_type, ""); 156 | ); 157 | } 158 | 159 | macro_rules! map_range_bench { 160 | ($name: ident, $min_len: expr, $max_len: expr, $map_len: expr, $map_type: ident, $key_prefix: expr) => ( 161 | #[bench] 162 | fn $name(b: &mut test::Bencher) { 163 | use rand::{Rng, StdRng, SeedableRng}; 164 | use std::collections::Bound; 165 | 166 | let mut rng: StdRng = SeedableRng::from_seed(BENCH_SEED); 167 | let mut map = $map_type::new(); 168 | let value = 0usize; 169 | 170 | (0..$map_len).map(|_| { 171 | let key_len = rng.gen_range($min_len, $max_len); 172 | let key = $key_prefix.to_string() + rng.gen_ascii_chars().take(key_len).collect::().as_ref(); 173 | map.insert(key.clone(), value); 174 | key 175 | }).count(); 176 | 177 | let keys = map.keys().collect::>(); 178 | 179 | b.iter(|| { 180 | let min = Bound::Included(keys[keys.len() / 4]); 181 | let max = Bound::Excluded(keys[keys.len() - keys.len() / 4]); 182 | for (key, value) in map.range(min, max) { 183 | test::black_box(key); 184 | test::black_box(value); 185 | } 186 | }); 187 | } 188 | ); 189 | ($name: ident, $min_len: expr, $max_len: expr, $map_len: expr, $map_type: ident) => ( 190 | map_range_bench!($name, $min_len, $max_len, $map_len, $map_type, ""); 191 | ); 192 | } 193 | -------------------------------------------------------------------------------- /src/bin/mem.rs: -------------------------------------------------------------------------------- 1 | #![feature(libc)] 2 | 3 | extern crate rand; 4 | extern crate burst_trie; 5 | extern crate libc; 6 | 7 | use std::io::Read; 8 | use std::io; 9 | use std::default::Default; 10 | #[allow(unused_imports)] 11 | use burst_trie::BurstTrieMap; 12 | #[allow(unused_imports)] 13 | use std::collections::{HashMap, BTreeMap}; 14 | use libc::*; 15 | 16 | extern {fn je_stats_print (write_cb: extern fn (*const c_void, *const c_char), cbopaque: *const c_void, opts: *const c_char);} 17 | extern fn write_cb (_: *const c_void, message: *const c_char) { 18 | print! ("{}", String::from_utf8_lossy (unsafe {std::ffi::CStr::from_ptr (message as *const i8) .to_bytes()})); 19 | } 20 | 21 | fn stats_print() { 22 | unsafe {je_stats_print (write_cb, std::ptr::null(), std::ptr::null())}; 23 | } 24 | 25 | fn main() { 26 | // let words = gen_words(10000, 3, 25); 27 | let words = read_words(); 28 | println!("--sample--\n{:#?}--", &words[..10]); 29 | let mut word_counts: BTreeMap = Default::default(); 30 | for word in words { 31 | let len = word.len(); 32 | word_counts.insert(word, len); 33 | } 34 | stats_print(); 35 | 36 | // word_counts.print_structure(); 37 | } 38 | 39 | #[allow(dead_code)] 40 | fn read_words() -> Vec { 41 | let mut input = String::new(); 42 | io::stdin().read_to_string(&mut input).unwrap(); 43 | input.split_whitespace() 44 | .map(|w| w.trim_matches(|c| ['.', '"', ':', ';', ',', '!', '?', ')', '(', '_'] 45 | .contains(&c))) 46 | .map(|w| w.to_lowercase()) 47 | .filter(|w| !w.is_empty()) 48 | .collect() 49 | } 50 | 51 | #[allow(dead_code)] 52 | fn gen_words(count: usize, min_len: usize, max_len: usize) -> Vec { 53 | use rand::{Rng, StdRng, SeedableRng}; 54 | static SEED: &'static[usize] = &[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]; 55 | let mut rng: StdRng = SeedableRng::from_seed(SEED); 56 | (0..count).map(|_| { 57 | let key_len = rng.gen_range(min_len, max_len); 58 | rng.gen_ascii_chars().take(key_len).collect::() 59 | }).collect() 60 | } 61 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(test, feature(test))] 2 | #![feature(box_patterns)] 3 | #![cfg_attr(test, feature(collections_bound))] 4 | #![cfg_attr(test, feature(btree_range))] 5 | #![feature(asm)] 6 | 7 | #[cfg(test)] 8 | extern crate test; 9 | 10 | #[cfg(test)] 11 | extern crate rand; 12 | 13 | #[cfg(test)] 14 | #[macro_use] 15 | mod bench_macros; 16 | 17 | mod map; 18 | pub use map::*; 19 | -------------------------------------------------------------------------------- /src/map.rs: -------------------------------------------------------------------------------- 1 | /// Implements an ordered map as an Adaptive BurstTrie. 2 | /// 3 | /// This structure achieves better performance than a BTree implementations for common operations while 4 | /// still allowing range scanning and ordered iteration. Performance wise it's usually 50+% faster than 5 | /// the std lib BTreeMap for random keys and pulls ahead further if keys have common prefixes. 6 | /// 7 | /// It's specialized for byte ordered keys, like ASCII or UTF-8 strings. 8 | /// 9 | /// The Burst Trie was originaly described by S. Heinz. 10 | /// You can find the original paper in the internet by it's title 11 | /// "Burst Tries: A Fast, Efficient Data Structure for String Keys" 12 | 13 | use std::ptr; 14 | use std::mem; 15 | use std::cmp::{self, Ordering}; 16 | use std::default::Default; 17 | use std::ops::{Index, IndexMut}; 18 | use std::marker; 19 | use std::fmt; 20 | 21 | const ALPHABET_SIZE: usize = 256; 22 | const CONTAINER_SIZE: usize = 32; 23 | const SMALL_ACCESS_SIZE: usize = 64; 24 | 25 | /// An BurstTrie implementation of an ordered map. Specialized for byte ordered types. 26 | /// 27 | /// See module level docs for details. 28 | pub struct BurstTrieMap where K: AsRef<[u8]> { 29 | root: *mut BurstTrieNode, 30 | len: usize 31 | } 32 | 33 | // it should be possible to use ptr::Unique instead of *mut to avoid the following 34 | unsafe impl Send for BurstTrieMap where K: AsRef<[u8]> + Send, V: Send {} 35 | 36 | #[derive(Copy, Clone, Debug)] 37 | #[repr(u8)] 38 | enum BurstTrieNodeType { 39 | Empty, 40 | Container, 41 | Access, 42 | SmallAccess, 43 | } 44 | 45 | #[repr(C)] 46 | struct BurstTrieNode where K: AsRef<[u8]> { 47 | _type: BurstTrieNodeType, 48 | marker: marker::PhantomData<(K, V)>, 49 | } 50 | 51 | #[repr(C)] 52 | struct ContainerNode where K: AsRef<[u8]> { 53 | _type: BurstTrieNodeType, 54 | items: Vec<(K, V)> 55 | } 56 | 57 | #[repr(C)] 58 | struct AccessNode where K: AsRef<[u8]> { 59 | _type: BurstTrieNodeType, 60 | nodes: [*mut BurstTrieNode; ALPHABET_SIZE], 61 | terminator: Option<(K, V)> 62 | } 63 | 64 | #[repr(C)] 65 | struct SmallAccessNode where K: AsRef<[u8]> { 66 | _type: BurstTrieNodeType, 67 | len: u8, 68 | index: [u8; ALPHABET_SIZE], 69 | snodes: [*mut BurstTrieNode; SMALL_ACCESS_SIZE], 70 | terminator: Option<(K, V)> 71 | } 72 | 73 | impl BurstTrieMap where K: AsRef<[u8]> { 74 | 75 | /// Returns a new empty BurstTrieMap 76 | pub fn new() -> BurstTrieMap { 77 | BurstTrieMap { 78 | root: ptr::null_mut(), 79 | len: 0, 80 | } 81 | } 82 | 83 | /// Inserts a key-value pair from the map. If the key already had a value 84 | /// present in the map, that value is returned. Otherwise, `None` is returned. 85 | /// 86 | /// # Examples 87 | /// 88 | /// ```rust 89 | /// use burst_trie::BurstTrieMap; 90 | /// 91 | /// let mut a = BurstTrieMap::new(); 92 | /// assert_eq!(a.len(), 0); 93 | /// a.insert("a", 0u32); 94 | /// assert_eq!(a.len(), 1); 95 | /// assert_eq!(a.insert("a", 1), Some(0)); 96 | /// assert_eq!(a.len(), 1); 97 | /// ``` 98 | pub fn insert(&mut self, key: K, value: V) -> Option { 99 | let opt_old_value = BurstTrieNode::insert(self.root, key, value, 0, &mut self.root); 100 | if opt_old_value.is_none() { 101 | self.len += 1; 102 | } 103 | opt_old_value 104 | } 105 | 106 | 107 | /// Returns a reference to the value corresponding to the key. 108 | /// 109 | /// The key may be any borrowed form of the map's key type, but the ordering on the borrowed form must match the ordering on the key type. 110 | /// 111 | /// # Examples 112 | /// 113 | /// ```rust 114 | /// use burst_trie::BurstTrieMap; 115 | /// 116 | /// let mut a = BurstTrieMap::new(); 117 | /// a.insert("a", 0); 118 | /// assert_eq!(a.get("a"), Some(&0)); 119 | /// assert_eq!(a.get("b"), None); 120 | /// ``` 121 | pub fn get(&self, key: &Q) -> Option<&V> where Q: AsRef<[u8]> { 122 | BurstTrieNode::get(self.root, key, 0) 123 | } 124 | 125 | /// Returns a mutable reference to the value corresponding to the key. 126 | /// 127 | /// The key may be any borrowed form of the map's key type, but the ordering on the borrowed form must match the ordering on the key type. 128 | /// 129 | /// # Examples 130 | /// 131 | /// ```rust 132 | /// use burst_trie::BurstTrieMap; 133 | /// 134 | /// let mut a = BurstTrieMap::new(); 135 | /// a.insert("a", 0); 136 | /// assert_eq!(a.get("a"), Some(&0)); 137 | /// assert_eq!(a.get("b"), None); 138 | /// if let Some(mv) = a.get_mut("a") { 139 | /// *mv = 1; 140 | /// } 141 | /// assert_eq!(a.get("a"), Some(&1)); 142 | /// ``` 143 | pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> where Q: AsRef<[u8]> { 144 | unsafe { mem::transmute(self.get(key)) } 145 | } 146 | 147 | /// Returns true if the map contains a value for the specified key. 148 | /// 149 | /// # Examples 150 | /// 151 | /// ```rust 152 | /// use burst_trie::BurstTrieMap; 153 | /// 154 | /// let mut a = BurstTrieMap::new(); 155 | /// a.insert("a", 0); 156 | /// assert_eq!(a.contains_key("a"), true); 157 | /// assert_eq!(a.contains_key("b"), false); 158 | /// ``` 159 | pub fn contains_key(&self, key: &Q) -> bool where Q: AsRef<[u8]> { 160 | self.get(key).is_some() 161 | } 162 | 163 | /// Removes a key from the map, returning the value at the key if the key 164 | /// was previously in the map. 165 | /// 166 | /// # Examples 167 | /// 168 | /// ```rust 169 | /// use burst_trie::BurstTrieMap; 170 | /// 171 | /// let mut a = BurstTrieMap::new(); 172 | /// assert_eq!(a.len(), 0); 173 | /// a.insert("a", 0u32); 174 | /// assert_eq!(a.len(), 1); 175 | /// assert_eq!(a.remove("a"), Some(0)); 176 | /// assert_eq!(a.len(), 0); 177 | /// ``` 178 | pub fn remove(&mut self, key: &Q) -> Option where Q: AsRef<[u8]> { 179 | let opt_old_value = BurstTrieNode::remove(self.root, key, 0, &mut self.root); 180 | if opt_old_value.is_some() { 181 | self.len -= 1; 182 | } 183 | opt_old_value 184 | } 185 | 186 | /// Return the number of elements in the map. 187 | /// 188 | /// # Examples 189 | /// 190 | /// ```rust 191 | /// use burst_trie::BurstTrieMap; 192 | /// 193 | /// let mut a = BurstTrieMap::new(); 194 | /// assert_eq!(a.len(), 0); 195 | /// a.insert("a", 0u32); 196 | /// assert_eq!(a.len(), 1); 197 | /// ``` 198 | pub fn len(&self) -> usize { 199 | self.len 200 | } 201 | 202 | /// Returns *true* if the map is empty. 203 | pub fn is_empty(&self) -> bool { 204 | self.len == 0 205 | } 206 | 207 | /// Clears all elements from the map. 208 | /// 209 | /// # Examples 210 | /// 211 | /// ```rust 212 | /// use burst_trie::BurstTrieMap; 213 | /// 214 | /// let mut a = BurstTrieMap::new(); 215 | /// assert_eq!(a.len(), 0); 216 | /// a.insert("a", 0u32); 217 | /// assert_eq!(a.len(), 1); 218 | /// a.clear(); 219 | /// assert_eq!(a.len(), 0); 220 | /// ``` 221 | pub fn clear(&mut self) { 222 | BurstTrieNode::drop(self.root); 223 | self.root = ptr::null_mut(); 224 | self.len = 0; 225 | } 226 | 227 | pub fn print_structure(&self) { 228 | BurstTrieNode::print_structure(self.root, 0); 229 | } 230 | 231 | // pub fn iter(&self) -> Iter { 232 | // Iter { 233 | // stack: vec![&self.root], 234 | // container_iter: None, 235 | // remaining_len: self.len 236 | // } 237 | // } 238 | 239 | // pub fn into_iter(self) -> IntoIter { 240 | // IntoIter { 241 | // stack: vec![self.root], 242 | // container_iter: None, 243 | // remaining_len: self.len 244 | // } 245 | // } 246 | 247 | // pub fn keys<'a>(&'a self) -> Map, fn((&'a K, &'a V)) -> &'a K> { 248 | // #[inline(always)] 249 | // fn map_fn<'a, K, V>(kv: (&'a K, &'a V)) -> &'a K { 250 | // &kv.0 251 | // } 252 | // self.iter().map(map_fn) 253 | // } 254 | 255 | // pub fn values<'a>(&'a self) -> Map, fn((&'a K, &'a V)) -> &'a V> { 256 | // #[inline(always)] 257 | // fn map_fn<'a, K, V>(kv: (&'a K, &'a V)) -> &'a V { 258 | // &kv.1 259 | // } 260 | // self.iter().map(map_fn) 261 | // } 262 | 263 | // pub fn range<'a, Q: ?Sized>(&'a self, min: Bound<&'a Q>, max: Bound<&'a Q>) -> Range where Q: AsRef<[u8]> { 264 | // Range::new(&self.root, min, max) 265 | // } 266 | } 267 | 268 | impl Drop for BurstTrieMap where K: AsRef<[u8]> { 269 | fn drop(&mut self) { 270 | BurstTrieNode::drop(self.root); 271 | } 272 | } 273 | 274 | type BurstTrieNodeRef = *mut *mut BurstTrieNode; 275 | 276 | impl BurstTrieNode where K: AsRef<[u8]> { 277 | #[inline] 278 | fn _type(n: *const Self) -> BurstTrieNodeType { 279 | if n.is_null() { 280 | BurstTrieNodeType::Empty 281 | } else { 282 | unsafe { (*n)._type } 283 | } 284 | } 285 | 286 | #[inline] 287 | fn as_container<'a>(n: *const Self) -> &'a mut ContainerNode { 288 | unsafe { mem::transmute(n) } 289 | } 290 | 291 | #[inline] 292 | fn as_small_access<'a>(n: *const Self) -> &'a mut SmallAccessNode { 293 | unsafe { mem::transmute(n) } 294 | } 295 | 296 | #[inline] 297 | fn as_access<'a>(n: *const Self) -> &'a mut AccessNode { 298 | unsafe { mem::transmute(n) } 299 | } 300 | 301 | #[inline] 302 | fn insert(n: *mut Self, key: K, value: V, depth: usize, node_ref: BurstTrieNodeRef) -> Option { 303 | match BurstTrieNode::_type(n) { 304 | BurstTrieNodeType::Container => { 305 | BurstTrieNode::as_container(n).insert(key, value, depth, node_ref) 306 | }, 307 | BurstTrieNodeType::Access => { 308 | BurstTrieNode::as_access(n).insert(key, value, depth, node_ref) 309 | }, 310 | BurstTrieNodeType::SmallAccess => { 311 | BurstTrieNode::as_small_access(n).insert(key, value, depth, node_ref) 312 | }, 313 | BurstTrieNodeType::Empty => { 314 | unsafe { 315 | *node_ref = Box::into_raw(ContainerNode::from_key_value(key, value)) as *mut _; 316 | } 317 | None 318 | }, 319 | } 320 | } 321 | 322 | #[inline] 323 | fn remove(n: *mut Self, key: &Q, depth: usize, node_ref: BurstTrieNodeRef) -> Option 324 | where Q: AsRef<[u8]> { 325 | // FIXME: we probably want to do some node colapsing here or in a shrink_to_fit method 326 | match BurstTrieNode::_type(n) { 327 | BurstTrieNodeType::Container => { 328 | BurstTrieNode::as_container(n).remove(key, depth, node_ref) 329 | }, 330 | BurstTrieNodeType::Access => { 331 | BurstTrieNode::as_access(n).remove(key, depth, node_ref) 332 | }, 333 | BurstTrieNodeType::SmallAccess => { 334 | BurstTrieNode::as_small_access(n).remove(key, depth, node_ref) 335 | }, 336 | BurstTrieNodeType::Empty => { 337 | None 338 | }, 339 | } 340 | } 341 | 342 | #[inline] 343 | fn get<'a, Q:?Sized>(n: *mut Self, key: &Q, depth: usize) -> Option<&'a V> 344 | where Q: AsRef<[u8]>, K: 'a { 345 | match BurstTrieNode::_type(n) { 346 | BurstTrieNodeType::Container => { 347 | BurstTrieNode::as_container(n).get(key, depth) 348 | }, 349 | BurstTrieNodeType::Access => { 350 | BurstTrieNode::as_access(n).get(key, depth) 351 | }, 352 | BurstTrieNodeType::SmallAccess => { 353 | BurstTrieNode::as_small_access(n).get(key, depth) 354 | }, 355 | BurstTrieNodeType::Empty => { 356 | None 357 | }, 358 | } 359 | } 360 | 361 | #[inline] 362 | fn drop(n: *mut Self) { 363 | unsafe { 364 | match BurstTrieNode::_type(n) { 365 | BurstTrieNodeType::Container => { 366 | drop(Box::from_raw(n as *mut ContainerNode)) 367 | }, 368 | BurstTrieNodeType::Access => { 369 | drop(Box::from_raw(n as *mut AccessNode)) 370 | }, 371 | BurstTrieNodeType::SmallAccess => { 372 | drop(Box::from_raw(n as *mut SmallAccessNode)) 373 | }, 374 | BurstTrieNodeType::Empty => () 375 | } 376 | } 377 | } 378 | 379 | #[inline] 380 | fn print_structure(n: *mut Self, mut depth: usize) { 381 | match BurstTrieNode::_type(n) { 382 | BurstTrieNodeType::Container => { 383 | println!("{}Container(LEN {})", 384 | (0..depth).map(|_| ' ').collect::(), 385 | Self::as_container(n).items.len()); 386 | }, 387 | BurstTrieNodeType::Access => { 388 | let access = Self::as_access(n); 389 | for (c, &node) in access.nodes.iter().enumerate() { 390 | println!("{}Access({})", 391 | (0..depth).map(|_| ' ').collect::(), 392 | c as u8 as char); 393 | Self::print_structure(node, depth + 1); 394 | } 395 | }, 396 | BurstTrieNodeType::SmallAccess => { 397 | let small_access = Self::as_small_access(n); 398 | println!("{}SmallAccess(LEN {})", 399 | (0..depth).map(|_| ' ').collect::(), 400 | small_access.len); 401 | depth += 1; 402 | for (c, &i) in small_access.index.iter().enumerate() { 403 | if (i as usize) < SMALL_ACCESS_SIZE { 404 | let node = small_access.snodes[i as usize]; 405 | println!("{}SmallAccess({})", 406 | (0..depth).map(|_| ' ').collect::(), 407 | c as u8 as char); 408 | Self::print_structure(node, depth + 1); 409 | } 410 | } 411 | }, 412 | BurstTrieNodeType::Empty => () 413 | } 414 | } 415 | } 416 | 417 | fn opt_binary_search_by(slice: &[K], mut f: F) -> Result 418 | where F: FnMut(&K) -> Ordering 419 | { 420 | let mut base : usize = 0; 421 | let mut lim : usize = slice.len(); 422 | 423 | while lim != 0 { 424 | let ix = base + (lim >> 1); 425 | match f(unsafe { &slice.get_unchecked(ix) }) { 426 | Ordering::Equal => return Ok(ix), 427 | Ordering::Less => { 428 | base = ix + 1; 429 | lim -= 1; 430 | } 431 | Ordering::Greater => () 432 | } 433 | lim >>= 1; 434 | } 435 | Err(base) 436 | } 437 | 438 | /// Bytewise slice comparison. 439 | /// NOTE: This uses the system's memcmp, which is currently dramatically 440 | /// faster than comparing each byte in a loop. 441 | #[inline(always)] 442 | fn cmp_slice_offset(a: &[u8], b: &[u8], offset: usize) -> Ordering { 443 | // NOTE: In theory n should be libc::size_t and not usize, but libc is not available here 444 | #[allow(improper_ctypes)] 445 | extern { fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; } 446 | let cmp = unsafe { 447 | memcmp( 448 | a.as_ptr().offset(offset as isize), 449 | b.as_ptr().offset(offset as isize), 450 | cmp::min(a.len(), b.len()) - offset 451 | ) 452 | }; 453 | 454 | if cmp == 0 { 455 | a.len().cmp(&b.len()) 456 | } else if cmp < 0 { 457 | Ordering::Less 458 | } else { 459 | Ordering::Greater 460 | } 461 | } 462 | 463 | impl ContainerNode where K: AsRef<[u8]> { 464 | fn from_key_value(key: K, value: V) -> Box { 465 | Box::new(ContainerNode { 466 | _type: BurstTrieNodeType::Container, 467 | items: vec![(key, value)] 468 | }) 469 | } 470 | 471 | fn burst(&mut self, depth: usize, node_ref: BurstTrieNodeRef) -> *mut BurstTrieNode { 472 | let container = unsafe { Box::from_raw(self as *mut Self) }; 473 | let mut cardinality = 0; 474 | if CONTAINER_SIZE > SMALL_ACCESS_SIZE { 475 | // otherwise the code inside is useless 476 | let mut index = [false; ALPHABET_SIZE]; 477 | for &(ref key, _) in &container.items { 478 | if depth < key.as_ref().len() { 479 | let idx = key.as_ref()[depth] as usize; 480 | if ! index[idx] { 481 | index[idx] = true; 482 | cardinality += 1; 483 | } 484 | } else { 485 | cardinality += 1; 486 | } 487 | } 488 | } 489 | unsafe { 490 | if cardinality > SMALL_ACCESS_SIZE { 491 | *node_ref = Box::into_raw(AccessNode::from_container(container, depth)) as *mut _; 492 | } else { 493 | *node_ref = Box::into_raw(SmallAccessNode::from_container(container, depth)) as *mut _; 494 | } 495 | *node_ref 496 | } 497 | } 498 | 499 | fn insert(&mut self, key: K, value: V, depth: usize, node_ref: BurstTrieNodeRef) -> Option { 500 | // optimize insertions at the end 501 | // helps in seq insert and node bursting 502 | let seq_insert = match self.items.last_mut() { 503 | Some(&mut (ref last_key, ref mut last_value)) => 504 | match cmp_slice_offset(last_key.as_ref(), key.as_ref(), depth) { 505 | Ordering::Equal => { 506 | return Some(mem::replace(last_value, value)); 507 | }, 508 | Ordering::Less => true, 509 | Ordering::Greater => false 510 | }, 511 | None => true 512 | }; 513 | 514 | let insert_pos = if seq_insert { 515 | self.items.len() 516 | } else { 517 | // binary search doesn't have to check the last element due to the previous 518 | let res_bs = opt_binary_search_by(&self.items[..self.items.len() - 1], |other| { 519 | cmp_slice_offset(other.0.as_ref(), key.as_ref(), depth) 520 | }); 521 | match res_bs { 522 | Ok(pos) => { 523 | let old_value = unsafe { self.items.get_unchecked_mut(pos) }; 524 | return Some(mem::replace(&mut old_value.1, value)); 525 | }, 526 | Err(pos) => pos 527 | } 528 | }; 529 | 530 | if self.items.len() >= CONTAINER_SIZE { 531 | BurstTrieNode::insert(self.burst(depth, node_ref), key, value, depth, node_ref) 532 | } else { 533 | self.items.insert(insert_pos, (key, value)); 534 | None 535 | } 536 | } 537 | 538 | fn remove(&mut self, key: &Q, depth: usize, _node_ref: BurstTrieNodeRef) -> Option where Q: AsRef<[u8]> { 539 | let res_bs = opt_binary_search_by(&self.items, |other| { 540 | cmp_slice_offset(other.0.as_ref(), key.as_ref(), depth) 541 | }); 542 | match res_bs { 543 | Ok(pos) => Some(self.items.remove(pos).1), 544 | Err(_) => None 545 | } 546 | } 547 | 548 | fn get(&self, key: &Q, depth: usize) -> Option<&V> where Q: AsRef<[u8]> { 549 | let res_bs = opt_binary_search_by(&self.items, |other| { 550 | cmp_slice_offset(other.0.as_ref(), key.as_ref(), depth) 551 | }); 552 | if let Ok(pos) = res_bs { 553 | Some(unsafe { &self.items.get_unchecked(pos).1 }) 554 | } else { 555 | None 556 | } 557 | } 558 | } 559 | 560 | impl AccessNode where K: AsRef<[u8]> { 561 | fn from_container(container: Box>, depth: usize) -> Box { 562 | let mut access_node = Box::new(AccessNode { 563 | _type: BurstTrieNodeType::Access, 564 | nodes: unsafe { mem::zeroed() }, 565 | terminator: None 566 | }); 567 | for (key, value) in container.items { 568 | access_node.insert(key, value, depth, ptr::null_mut()); 569 | } 570 | access_node 571 | } 572 | 573 | fn from_small(mut small: Box>) -> Box { 574 | let mut access_node = Box::new(AccessNode { 575 | _type: BurstTrieNodeType::Access, 576 | nodes: unsafe { mem::zeroed() }, 577 | terminator: small.terminator.take() 578 | }); 579 | for idx in 0..ALPHABET_SIZE { 580 | let small_idx = small.index[idx] as usize; 581 | if small_idx < SMALL_ACCESS_SIZE { 582 | access_node.nodes[idx] = mem::replace(&mut small.snodes[small_idx], ptr::null_mut()); 583 | } 584 | } 585 | access_node 586 | } 587 | 588 | fn insert(&mut self, key: K, value: V, depth: usize, _node_ref: BurstTrieNodeRef) -> Option { 589 | // depth is always <= key.len 590 | if depth < key.as_ref().len() { 591 | let idx = key.as_ref()[depth] as usize; 592 | BurstTrieNode::insert(self.nodes[idx], key, value, depth + 1, &mut self.nodes[idx]) 593 | } else if let Some((_, ref mut old_value)) = self.terminator { 594 | Some(mem::replace(old_value, value)) 595 | } else { 596 | self.terminator = Some((key, value)); 597 | None 598 | } 599 | } 600 | 601 | fn remove(&mut self, key: &Q, depth: usize, _node_ref: BurstTrieNodeRef) -> Option where Q: AsRef<[u8]> { 602 | if depth < key.as_ref().len() { 603 | let idx = key.as_ref()[depth] as usize; 604 | BurstTrieNode::remove(self.nodes[idx], key, depth + 1, &mut self.nodes[idx]) 605 | } else if let Some((_, old_value)) = self.terminator.take() { 606 | Some(old_value) 607 | } else { 608 | None 609 | } 610 | } 611 | 612 | fn get(&self, key: &Q, depth: usize) -> Option<&V> where Q: AsRef<[u8]> { 613 | if depth < key.as_ref().len() { 614 | let idx = key.as_ref()[depth] as usize; 615 | BurstTrieNode::get(self.nodes[idx], key, depth + 1) 616 | } else if let Some((_, ref v)) = self.terminator { 617 | Some(v) 618 | } else { 619 | None 620 | } 621 | } 622 | } 623 | 624 | impl Drop for AccessNode where K: AsRef<[u8]> { 625 | fn drop(&mut self) { 626 | for &ptr in self.nodes.iter() { 627 | BurstTrieNode::drop(ptr); 628 | } 629 | } 630 | } 631 | 632 | impl SmallAccessNode where K: AsRef<[u8]> { 633 | fn from_container(container: Box>, depth: usize) -> Box { 634 | let mut access_node = Box::new(SmallAccessNode { 635 | _type: BurstTrieNodeType::SmallAccess, 636 | len: 0, 637 | index: [SMALL_ACCESS_SIZE as u8; ALPHABET_SIZE], 638 | snodes: unsafe { mem::zeroed() }, 639 | terminator: None 640 | }); 641 | for (key, value) in container.items { 642 | access_node.insert(key, value, depth, ptr::null_mut()); 643 | } 644 | access_node 645 | } 646 | 647 | fn grow(&mut self, node_ref: BurstTrieNodeRef) -> *mut BurstTrieNode { 648 | unsafe { 649 | let small_access = Box::from_raw(self as *mut Self); 650 | *node_ref = Box::into_raw(AccessNode::from_small(small_access)) as *mut _; 651 | *node_ref 652 | } 653 | } 654 | 655 | fn insert(&mut self, key: K, value: V, depth: usize, node_ref: BurstTrieNodeRef) -> Option { 656 | // depth is always <= key.len 657 | if depth < key.as_ref().len() { 658 | let idx = key.as_ref()[depth] as usize; 659 | 660 | let small_idx = if (self.index[idx] as usize) < SMALL_ACCESS_SIZE { 661 | self.index[idx] as usize 662 | } else if (self.len as usize) < SMALL_ACCESS_SIZE { 663 | self.index[idx] = self.len as u8; 664 | let prev_len = self.len; 665 | self.len += 1; 666 | prev_len as usize 667 | } else { 668 | return BurstTrieNode::insert(self.grow(node_ref), key, value, depth, node_ref); 669 | }; 670 | BurstTrieNode::insert(self.snodes[small_idx], key, value, depth + 1, &mut self.snodes[small_idx]) 671 | } else if let Some((_, ref mut old_value)) = self.terminator { 672 | Some(mem::replace(old_value, value)) 673 | } else { 674 | self.terminator = Some((key, value)); 675 | None 676 | } 677 | } 678 | 679 | fn remove(&mut self, key: &Q, depth: usize, _node_ref: BurstTrieNodeRef) -> Option where Q: AsRef<[u8]> { 680 | if depth < key.as_ref().len() { 681 | let idx = key.as_ref()[depth] as usize; 682 | let small_idx = self.index[idx] as usize; 683 | if small_idx < SMALL_ACCESS_SIZE { 684 | BurstTrieNode::remove(self.snodes[small_idx], key, depth + 1, &mut self.snodes[small_idx]) 685 | } else { 686 | None 687 | } 688 | } else if let Some((_, old_value)) = self.terminator.take() { 689 | Some(old_value) 690 | } else { 691 | None 692 | } 693 | } 694 | 695 | fn get(&self, key: &Q, depth: usize) -> Option<&V> where Q: AsRef<[u8]> { 696 | if depth < key.as_ref().len() { 697 | let idx = key.as_ref()[depth] as usize; 698 | let small_idx = self.index[idx] as usize; 699 | if small_idx < SMALL_ACCESS_SIZE { 700 | BurstTrieNode::get(self.snodes[small_idx], key, depth + 1) 701 | } else { 702 | None 703 | } 704 | } else if let Some((_, ref v)) = self.terminator { 705 | Some(v) 706 | } else { 707 | None 708 | } 709 | } 710 | } 711 | 712 | impl Drop for SmallAccessNode where K: AsRef<[u8]> { 713 | fn drop(&mut self) { 714 | for &ptr in self.snodes.iter() { 715 | BurstTrieNode::drop(ptr); 716 | } 717 | } 718 | } 719 | 720 | impl<'a, K, V, Q: ?Sized> Index<&'a Q> for BurstTrieMap where K: AsRef<[u8]>, Q: AsRef<[u8]> { 721 | type Output = V; 722 | 723 | fn index(&self, index: &Q) -> &V { 724 | self.get(index).unwrap() 725 | } 726 | } 727 | 728 | impl<'a, K, V, Q: ?Sized> IndexMut<&'a Q> for BurstTrieMap where K: AsRef<[u8]>, Q: AsRef<[u8]> { 729 | fn index_mut(&mut self, index: &Q) -> &mut V { 730 | self.get_mut(index).unwrap() 731 | } 732 | } 733 | 734 | impl Default for BurstTrieMap where K: AsRef<[u8]> { 735 | #[inline] 736 | fn default() -> BurstTrieMap { BurstTrieMap::new() } 737 | } 738 | 739 | // pub struct Iter<'a, K: 'a, V: 'a> where K: AsRef<[u8]> { 740 | // stack: Vec<&'a BurstTrieNode>, 741 | // container_iter: Option>, 742 | // remaining_len: usize 743 | // } 744 | 745 | // impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> where K: AsRef<[u8]> {} 746 | 747 | // impl<'a, K, V> Iterator for Iter<'a, K, V> where K: AsRef<[u8]> { 748 | // type Item = (&'a K, &'a V); 749 | 750 | // fn next(&mut self) -> Option<(&'a K, &'a V)> { 751 | // if let Some(ref mut iter) = self.container_iter { 752 | // let next = iter.next(); 753 | // if let Some(&(ref key, ref value)) = next { 754 | // self.remaining_len -= 1; 755 | // return Some((key, value)); 756 | // } 757 | // } 758 | 759 | // while let Some(node) = self.stack.pop() { 760 | // match *node { 761 | // BurstTrieNode::Container(box ref container) => { 762 | // let mut iter = container.items.iter(); 763 | // let next = iter.next(); 764 | // mem::replace(&mut self.container_iter, Some(iter)); 765 | // if let Some(&(ref key, ref value)) = next { 766 | // self.remaining_len -= 1; 767 | // return Some((key, value)); 768 | // } 769 | // }, 770 | // BurstTrieNode::Access(box ref access) => { 771 | // // add to stack in reverse order 772 | // for i in (1..ALPHABET_SIZE + 1) { 773 | // let idx = ALPHABET_SIZE - i; 774 | // match access.nodes[idx] { 775 | // ref node @ BurstTrieNode::Container(_) | 776 | // ref node @ BurstTrieNode::SmallAccess(_) | 777 | // ref node @ BurstTrieNode::Access(_) => { 778 | // self.stack.push(node); 779 | // }, 780 | // BurstTrieNode::Empty => () 781 | // } 782 | // } 783 | 784 | // if let Some((ref key, ref value)) = access.terminator { 785 | // self.remaining_len -= 1; 786 | // return Some((key, value)); 787 | // } 788 | // }, 789 | // BurstTrieNode::SmallAccess(box ref small) => { 790 | // // add to stack in reverse order 791 | // for i in (1..ALPHABET_SIZE + 1) { 792 | // let idx = ALPHABET_SIZE - i; 793 | // let small_idx = small.index[idx] as usize; 794 | // if small_idx < SMALL_ACCESS_SIZE { 795 | // match small.snodes[small_idx] { 796 | // ref node @ BurstTrieNode::Container(_) | 797 | // ref node @ BurstTrieNode::SmallAccess(_) | 798 | // ref node @ BurstTrieNode::Access(_) => { 799 | // self.stack.push(node); 800 | // }, 801 | // BurstTrieNode::Empty => () 802 | // } 803 | // } 804 | // } 805 | 806 | // if let Some((ref key, ref value)) = small.terminator { 807 | // self.remaining_len -= 1; 808 | // return Some((key, value)); 809 | // } 810 | // }, 811 | // BurstTrieNode::Empty => () 812 | // } 813 | // } 814 | // None 815 | // } 816 | 817 | // #[inline] 818 | // fn size_hint(&self) -> (usize, Option) { 819 | // (self.remaining_len, Some(self.remaining_len)) 820 | // } 821 | // } 822 | 823 | // pub struct IntoIter where K: AsRef<[u8]> { 824 | // stack: Vec>, 825 | // container_iter: Option>, 826 | // remaining_len: usize 827 | // } 828 | 829 | // impl ExactSizeIterator for IntoIter where K: AsRef<[u8]> {} 830 | 831 | // impl Iterator for IntoIter where K: AsRef<[u8]> { 832 | // type Item = (K, V); 833 | 834 | // fn next(&mut self) -> Option<(K, V)> { 835 | // if let Some(ref mut iter) = self.container_iter { 836 | // let next = iter.next(); 837 | // if next.is_some() { 838 | // self.remaining_len -= 1; 839 | // return next; 840 | // } 841 | // } 842 | 843 | // while let Some(node) = self.stack.pop() { 844 | // match node { 845 | // BurstTrieNode::Container(container) => { 846 | // let mut iter = container.items.into_iter(); 847 | // let next = iter.next(); 848 | // mem::replace(&mut self.container_iter, Some(iter)); 849 | // if next.is_some() { 850 | // self.remaining_len -= 1; 851 | // return next; 852 | // } 853 | // }, 854 | // BurstTrieNode::Access(box mut access) => { 855 | // // add to stack in reverse order 856 | // for i in (1..ALPHABET_SIZE + 1) { 857 | // let idx = ALPHABET_SIZE - i; 858 | // let node = mem::replace(&mut access.nodes[idx], BurstTrieNode::Empty); 859 | // match node { 860 | // BurstTrieNode::Container(_) | 861 | // BurstTrieNode::SmallAccess(_) | 862 | // BurstTrieNode::Access(_) => { 863 | // self.stack.push(node); 864 | // }, 865 | // BurstTrieNode::Empty => () 866 | // } 867 | // } 868 | 869 | 870 | // if access.terminator.is_some() { 871 | // self.remaining_len -= 1; 872 | // return access.terminator; 873 | // } 874 | // }, 875 | // BurstTrieNode::SmallAccess(box mut small) => { 876 | // // add to stack in reverse order 877 | // for i in (1..ALPHABET_SIZE + 1) { 878 | // let idx = ALPHABET_SIZE - i; 879 | // let small_idx = small.index[idx] as usize; 880 | // if small_idx < SMALL_ACCESS_SIZE { 881 | // let node = mem::replace(&mut small.snodes[small_idx], BurstTrieNode::Empty); 882 | // match node { 883 | // BurstTrieNode::Container(_) | 884 | // BurstTrieNode::SmallAccess(_) | 885 | // BurstTrieNode::Access(_) => { 886 | // self.stack.push(node); 887 | // }, 888 | // BurstTrieNode::Empty => () 889 | // } 890 | // } 891 | // } 892 | 893 | // if small.terminator.is_some() { 894 | // self.remaining_len -= 1; 895 | // return small.terminator; 896 | // } 897 | // }, 898 | // BurstTrieNode::Empty => () 899 | // } 900 | // } 901 | // None 902 | // } 903 | 904 | // #[inline] 905 | // fn size_hint(&self) -> (usize, Option) { 906 | // (self.remaining_len, Some(self.remaining_len)) 907 | // } 908 | // } 909 | 910 | // pub struct Range<'a, K: 'a, V: 'a, Q: 'a + ?Sized> where K: AsRef<[u8]>, Q: AsRef<[u8]> { 911 | // stack: VecDeque<(&'a BurstTrieNode, u16, bool, u16, u16)>, 912 | // curr_item: Option<(&'a BurstTrieNode, u16, bool, u16, u16)>, 913 | // min: Bound<&'a Q>, 914 | // max: Bound<&'a Q> 915 | // } 916 | 917 | // impl<'a, K, V, Q: ?Sized> Range<'a, K, V, Q> where K: AsRef<[u8]>, Q: AsRef<[u8]> { 918 | 919 | // fn new(root: &'a BurstTrieNode, min: Bound<&'a Q>, max: Bound<&'a Q>) -> Range<'a, K, V, Q> { 920 | // let mut range = Range { 921 | // stack: VecDeque::new(), 922 | // curr_item: None, 923 | // min: min, 924 | // max: max 925 | // }; 926 | 927 | // match *root { 928 | // BurstTrieNode::Container(box ref container) => 929 | // range.stack.push_back((root, 0, true, 0, container.items.len() as u16)), 930 | // BurstTrieNode::Access(_) | 931 | // BurstTrieNode::SmallAccess(_) => 932 | // range.stack.push_back((root, 0, true, 0, ALPHABET_SIZE as u16)), 933 | // BurstTrieNode::Empty => return range 934 | // } 935 | 936 | // range.find_min(); 937 | // range.find_max(); 938 | 939 | // range 940 | // } 941 | 942 | // fn find_min(&mut self) { 943 | // let (min_key, min_included) = match self.min { 944 | // Bound::Unbounded => return, 945 | // Bound::Included(key) => (key, true), 946 | // Bound::Excluded(key) => (key, false) 947 | // }; 948 | 949 | // while let Some((node, depth, _, _, _)) = self.stack.pop_back() { 950 | // let depthsz = depth as usize; 951 | // match *node { 952 | // BurstTrieNode::Container(box ref container) => { 953 | // let res_bs = opt_binary_search_by(&container.items, |other| { 954 | // other.0.as_ref()[depthsz..].cmp(&min_key.as_ref()[depthsz..]) 955 | // }); 956 | // let start_pos = match res_bs { 957 | // Ok(pos) if ! min_included => pos + 1, 958 | // Ok(pos) | Err(pos) => pos 959 | // }; 960 | // self.stack.push_back((node, depth, false, start_pos as u16, container.items.len() as u16)); 961 | // // can only hit a container once 962 | // return; 963 | // }, 964 | // BurstTrieNode::Access(box ref access) => { 965 | // if depthsz < min_key.as_ref().len() { 966 | // let min_key_byte = min_key.as_ref()[depthsz] as usize; 967 | // self.stack.push_back((node, depth, false, min_key_byte as u16 + 1, ALPHABET_SIZE as u16)); 968 | // match access.nodes[min_key_byte] { 969 | // BurstTrieNode::Container(box ref container) => 970 | // self.stack.push_back((&access.nodes[min_key_byte], depth + 1, false, 0, container.items.len() as u16)), 971 | // BurstTrieNode::Access(_) | 972 | // BurstTrieNode::SmallAccess(_) => 973 | // self.stack.push_back((&access.nodes[min_key_byte], depth + 1, true, 0, ALPHABET_SIZE as u16)), 974 | // BurstTrieNode::Empty => return // exit 975 | // } 976 | // } else { 977 | // // re-add node to the stack with correct terminator and exit 978 | // self.stack.push_back((node, depth, min_included, 0, ALPHABET_SIZE as u16)); 979 | // return; 980 | // } 981 | // }, 982 | // BurstTrieNode::SmallAccess(box ref small) => { 983 | // if depthsz < min_key.as_ref().len() { 984 | // let min_key_byte = min_key.as_ref()[depthsz] as usize; 985 | // self.stack.push_back((node, depth, false, min_key_byte as u16 + 1, ALPHABET_SIZE as u16)); 986 | // let small_idx = small.index[min_key_byte] as usize; 987 | // if small_idx < SMALL_ACCESS_SIZE { 988 | // match small.snodes[small_idx] { 989 | // BurstTrieNode::Container(box ref container) => 990 | // self.stack.push_back((&small.snodes[small_idx], depth + 1, false, 0, container.items.len() as u16)), 991 | // BurstTrieNode::Access(_) | 992 | // BurstTrieNode::SmallAccess(_) => 993 | // self.stack.push_back((&small.snodes[small_idx], depth + 1, true, 0, ALPHABET_SIZE as u16)), 994 | // BurstTrieNode::Empty => return // exit 995 | // } 996 | // } 997 | // } else { 998 | // // re-add node to the stack with correct terminator and exit 999 | // self.stack.push_back((node, depth, min_included, 0, ALPHABET_SIZE as u16)); 1000 | // return; 1001 | // } 1002 | // }, 1003 | // BurstTrieNode::Empty => () 1004 | // } 1005 | // } 1006 | // } 1007 | 1008 | // fn find_max(&mut self) { 1009 | // let (max_key, max_included) = match self.max { 1010 | // Bound::Unbounded => return, 1011 | // Bound::Included(key) => (key, true), 1012 | // Bound::Excluded(key) => (key, false) 1013 | // }; 1014 | 1015 | // while let Some((node, depth, terminator, start_pos, _)) = self.stack.pop_front() { 1016 | // let depthsz = depth as usize; 1017 | // match *node { 1018 | // BurstTrieNode::Container(box ref container) => { 1019 | // let res_bs = opt_binary_search_by(&container.items, |other| { 1020 | // other.0.as_ref()[depthsz..].cmp(&max_key.as_ref()[depthsz..]) 1021 | // }); 1022 | // let end_pos = match res_bs { 1023 | // Ok(pos) if max_included => pos + 1, 1024 | // Ok(pos) | Err(pos) => pos 1025 | // }; 1026 | // self.stack.push_front((node, depth, false, start_pos, end_pos as u16)); 1027 | // // can only hit a container once 1028 | // return; 1029 | // }, 1030 | // BurstTrieNode::Access(box ref access) => { 1031 | // if depthsz < max_key.as_ref().len() { 1032 | // let max_key_byte = max_key.as_ref()[depthsz] as usize; 1033 | // self.stack.push_front((node, depth, terminator, start_pos, max_key_byte as u16)); 1034 | // match access.nodes[max_key_byte] { 1035 | // BurstTrieNode::Container(box ref container) => 1036 | // self.stack.push_front((&access.nodes[max_key_byte], depth + 1, false, 0, container.items.len() as u16)), 1037 | // BurstTrieNode::Access(_) | 1038 | // BurstTrieNode::SmallAccess(_) => 1039 | // self.stack.push_front((&access.nodes[max_key_byte], depth + 1, true, 0, ALPHABET_SIZE as u16)), 1040 | // BurstTrieNode::Empty => return // exit 1041 | // } 1042 | // } else { 1043 | // // re-add node to the stack with correct terminator and exit 1044 | // self.stack.push_front((node, depth, max_included, 0, 0)); 1045 | // return; 1046 | // } 1047 | // }, 1048 | // BurstTrieNode::SmallAccess(box ref small) => { 1049 | // if depthsz < max_key.as_ref().len() { 1050 | // let max_key_byte = max_key.as_ref()[depthsz] as usize; 1051 | // self.stack.push_front((node, depth, terminator, start_pos, max_key_byte as u16)); 1052 | // let small_idx = small.index[max_key_byte] as usize; 1053 | // if small_idx < SMALL_ACCESS_SIZE { 1054 | // match small.snodes[small_idx] { 1055 | // BurstTrieNode::Container(box ref container) => 1056 | // self.stack.push_front((&small.snodes[small_idx], depth + 1, false, 0, container.items.len() as u16)), 1057 | // BurstTrieNode::Access(_) | 1058 | // BurstTrieNode::SmallAccess(_) => 1059 | // self.stack.push_front((&small.snodes[small_idx], depth + 1, true, 0, ALPHABET_SIZE as u16)), 1060 | // BurstTrieNode::Empty => return // exit 1061 | // } 1062 | // } 1063 | // } else { 1064 | // // re-add node to the stack with correct terminator and exit 1065 | // self.stack.push_front((node, depth, max_included, 0, 0)); 1066 | // return; 1067 | // } 1068 | // }, 1069 | // BurstTrieNode::Empty => () 1070 | // } 1071 | // } 1072 | // } 1073 | 1074 | // fn find_next(&mut self) -> Option<(&'a K, &'a V)> { 1075 | // if let Some((&BurstTrieNode::Container(box ref container), _, _, ref mut start_pos, end_pos)) = self.curr_item { 1076 | // if *start_pos < end_pos { 1077 | // let (ref key, ref value) = container.items[*start_pos as usize]; 1078 | // *start_pos += 1; // advance iterator 1079 | // return Some((key, value)); 1080 | // } 1081 | // } 1082 | 1083 | // while let Some((node, depth, terminator, start_pos, end_pos)) = self.stack.pop_back() { 1084 | // match *node { 1085 | // BurstTrieNode::Container(box ref container) => { 1086 | // if start_pos < end_pos { 1087 | // self.curr_item = Some((node, depth, terminator, start_pos + 1, end_pos)); 1088 | // let (ref key, ref value) = container.items[start_pos as usize]; 1089 | // return Some((key, value)); 1090 | // } 1091 | // }, 1092 | // BurstTrieNode::Access(box ref access) => { 1093 | // // add to stack in reverse order 1094 | // for i in ((ALPHABET_SIZE - end_pos as usize) + 1 .. (ALPHABET_SIZE - start_pos as usize) + 1) { 1095 | // let idx = ALPHABET_SIZE - i; 1096 | // match access.nodes[idx] { 1097 | // BurstTrieNode::Container(box ref container) => 1098 | // self.stack.push_back((&access.nodes[idx], depth + 1, false, 0, container.items.len() as u16)), 1099 | // BurstTrieNode::Access(_) | 1100 | // BurstTrieNode::SmallAccess(_) => 1101 | // self.stack.push_back((&access.nodes[idx], depth + 1, true, 0, ALPHABET_SIZE as u16)), 1102 | // BurstTrieNode::Empty => () 1103 | // } 1104 | // } 1105 | 1106 | // if terminator { 1107 | // if let Some((ref key, ref value)) = access.terminator { 1108 | // return Some((key, value)); 1109 | // } 1110 | // } 1111 | // }, 1112 | // BurstTrieNode::SmallAccess(box ref small) => { 1113 | // // add to stack in reverse order 1114 | // for i in ((ALPHABET_SIZE - end_pos as usize) + 1 .. (ALPHABET_SIZE - start_pos as usize) + 1) { 1115 | // let idx = ALPHABET_SIZE - i; 1116 | // let small_idx = small.index[idx] as usize; 1117 | // if small_idx < SMALL_ACCESS_SIZE { 1118 | // match small.snodes[small_idx] { 1119 | // BurstTrieNode::Container(box ref container) => 1120 | // self.stack.push_back((&small.snodes[small_idx], depth + 1, false, 0, container.items.len() as u16)), 1121 | // BurstTrieNode::Access(_) | 1122 | // BurstTrieNode::SmallAccess(_) => 1123 | // self.stack.push_back((&small.snodes[small_idx], depth + 1, true, 0, ALPHABET_SIZE as u16)), 1124 | // BurstTrieNode::Empty => () 1125 | // } 1126 | // } 1127 | // } 1128 | 1129 | // if terminator { 1130 | // if let Some((ref key, ref value)) = small.terminator { 1131 | // return Some((key, value)); 1132 | // } 1133 | // } 1134 | // }, 1135 | // BurstTrieNode::Empty => () 1136 | // } 1137 | // } 1138 | 1139 | // None 1140 | // } 1141 | // } 1142 | 1143 | // impl<'a, K, V, Q: ?Sized> Iterator for Range<'a, K, V, Q> where K: AsRef<[u8]>, Q: AsRef<[u8]> { 1144 | // type Item = (&'a K, &'a V); 1145 | 1146 | // #[inline(always)] 1147 | // fn next(&mut self) -> Option<(&'a K, &'a V)> { 1148 | // self.find_next() 1149 | // } 1150 | 1151 | // #[inline(always)] 1152 | // fn size_hint(&self) -> (usize, Option) { 1153 | // (self.stack.len(), None) 1154 | // } 1155 | // } 1156 | 1157 | #[cfg(test)] 1158 | mod tests { 1159 | use super::{BurstTrieMap, BurstTrieNode}; 1160 | use std::collections::Bound; 1161 | use rand::*; 1162 | 1163 | // #[test] 1164 | // fn test_iter() { 1165 | // let mut map = BurstTrieMap::new(); 1166 | 1167 | // for i in (100000..999999) { 1168 | // map.insert(i.to_string(), i); 1169 | // } 1170 | 1171 | // let mut i = 100000usize; 1172 | // for (key, value) in map.iter() { 1173 | // assert_eq!(key.parse::().unwrap(), i); 1174 | // assert_eq!(*value, i); 1175 | // i += 1; 1176 | // } 1177 | // assert_eq!(i, 999999); 1178 | // } 1179 | 1180 | // #[test] 1181 | // fn test_range1() { 1182 | // let mut map = BurstTrieMap::new(); 1183 | 1184 | // for i in (100000..999999) { 1185 | // map.insert(i.to_string(), i); 1186 | // } 1187 | 1188 | // let mut i = 100000usize; 1189 | // for (key, value) in map.range::(Bound::Unbounded, Bound::Unbounded) { 1190 | // assert_eq!(key.parse::().unwrap(), i); 1191 | // assert_eq!(*value, i); 1192 | // i += 1; 1193 | // } 1194 | // assert_eq!(i, 999999); 1195 | 1196 | // for j in (999000..999999) { 1197 | // let mut i = j; 1198 | // for (key, value) in map.range(Bound::Included(&j.to_string()), Bound::Unbounded) { 1199 | // assert_eq!(key.parse::().unwrap(), i); 1200 | // assert_eq!(*value, i); 1201 | // i += 1; 1202 | // } 1203 | // assert_eq!(i, 999999); 1204 | // } 1205 | 1206 | // for j in (999000..999999) { 1207 | // let mut i = j + 1; 1208 | // for (key, value) in map.range(Bound::Excluded(&j.to_string()), Bound::Unbounded) { 1209 | // assert_eq!(key.parse::().unwrap(), i); 1210 | // assert_eq!(*value, i); 1211 | // i += 1; 1212 | // } 1213 | // assert_eq!(i, 999999); 1214 | // } 1215 | 1216 | // assert_eq!(map.range(Bound::Included("999998"), Bound::Unbounded).count(), 1); 1217 | // assert_eq!(map.range(Bound::Excluded("999998"), Bound::Unbounded).count(), 0); 1218 | // assert_eq!(map.range(Bound::Excluded("999999"), Bound::Unbounded).count(), 0); 1219 | 1220 | // // 2 items that will be at the terminator slots 1221 | // map.insert("1".to_string(), 1); 1222 | // map.insert("2".to_string(), 2); 1223 | // assert_eq!(map.range(Bound::Included("1"), Bound::Unbounded).count(), (999999 - 100000) + 2); 1224 | // assert_eq!(map.range(Bound::Excluded("1"), Bound::Unbounded).count(), (999999 - 100000) + 1); 1225 | // assert_eq!(map.range(Bound::Included("2"), Bound::Unbounded).count(), (999999 - 100000) + 1 - 100000); 1226 | // assert_eq!(map.range(Bound::Excluded("2"), Bound::Unbounded).count(), (999999 - 100000) - 100000); 1227 | // // max specified 1228 | // assert_eq!(map.range(Bound::Excluded("1"), Bound::Excluded("2")).count(), 100000); 1229 | // assert_eq!(map.range(Bound::Excluded("2"), Bound::Excluded("3")).count(), 100000); 1230 | // assert_eq!(map.range(Bound::Included("1"), Bound::Included("2")).count(), 100000 + 2); 1231 | // assert_eq!(map.range(Bound::Included("2"), Bound::Included("3")).count(), 100000 + 1); 1232 | // } 1233 | 1234 | // #[test] 1235 | // fn test_range2() { 1236 | // use rand::{Rng, weak_rng}; 1237 | // use std::collections::{BTreeMap, Bound}; 1238 | 1239 | // let mut rng = weak_rng(); 1240 | // let mut tree = BTreeMap::new(); 1241 | // let mut trie = BurstTrieMap::new(); 1242 | // let value = 0usize; 1243 | 1244 | // (0..10000).map(|_| { 1245 | // let key_len = rng.gen_range(0, 100); 1246 | // let key = rng.gen_ascii_chars().take(key_len).collect::(); 1247 | // tree.insert(key.clone(), value); 1248 | // trie.insert(key, value); 1249 | // }).count(); 1250 | 1251 | // let keys = tree.keys().collect::>(); 1252 | // assert_eq!(keys, trie.keys().collect::>()); 1253 | 1254 | // for _ in 0..1000 { 1255 | // let x0 = rng.gen_range(0usize, keys.len()); 1256 | // let x1 = rng.gen_range(x0, keys.len()); 1257 | // let min1 = Bound::Included(keys[x0]); 1258 | // let max1 = Bound::Excluded(keys[x1]); 1259 | // let min2 = Bound::Included(keys[x0]); 1260 | // let max2 = Bound::Excluded(keys[x1]); 1261 | // for ((key1, _), (key2, _)) in tree.range(min1, max1).zip(trie.range(min2, max2)) { 1262 | // assert_eq!(key1, key2); 1263 | // } 1264 | // } 1265 | // } 1266 | 1267 | // #[test] 1268 | // fn test_into_iter() { 1269 | // let mut map = BurstTrieMap::new(); 1270 | 1271 | // // use a dropable value so it crashes if double drop 1272 | // for i in (100000..999999) { 1273 | // map.insert(i.to_string(), i.to_string()); 1274 | // } 1275 | 1276 | // let mut i = 100000usize; 1277 | // for (key, value) in map.into_iter() { 1278 | // assert_eq!(key.parse::().unwrap(), i); 1279 | // assert_eq!(value.parse::().unwrap(), i); 1280 | // i += 1; 1281 | // } 1282 | // assert_eq!(i, 999999); 1283 | // } 1284 | 1285 | // #[test] 1286 | // fn test_keys() { 1287 | // let mut map = BurstTrieMap::new(); 1288 | 1289 | // for i in (100000..999999) { 1290 | // map.insert(i.to_string(), i); 1291 | // } 1292 | 1293 | // let mut i = 100000usize; 1294 | // for key in map.keys() { 1295 | // assert_eq!(key.parse::().unwrap(), i); 1296 | // i += 1; 1297 | // } 1298 | // assert_eq!(i, 999999); 1299 | // } 1300 | 1301 | // #[test] 1302 | // fn test_values() { 1303 | // let mut map = BurstTrieMap::new(); 1304 | 1305 | // for i in (100000..999999) { 1306 | // map.insert(i.to_string(), i); 1307 | // } 1308 | 1309 | // let mut i = 100000usize; 1310 | // for value in map.values() { 1311 | // assert_eq!(*value, i); 1312 | // i += 1; 1313 | // } 1314 | // assert_eq!(i, 999999); 1315 | // } 1316 | 1317 | #[test] 1318 | fn test_correctness() { 1319 | let mut rng = weak_rng(); 1320 | for _ in 0..10 { 1321 | let mut trie = BurstTrieMap::new(); 1322 | for _ in 0..10000 { 1323 | let key_len = rng.gen_range(1usize, 1000); 1324 | let key = rng.gen_ascii_chars().take(key_len).collect::(); 1325 | let value = rng.gen::(); 1326 | trie.insert(key.clone(), value); 1327 | if let Some(r_value) = trie.get(&key) { 1328 | assert_eq!(value, *r_value); 1329 | } else { 1330 | panic!("key: {} not found", key); 1331 | } 1332 | } 1333 | } 1334 | } 1335 | 1336 | #[test] 1337 | fn find_empty() { 1338 | let m: BurstTrieMap = BurstTrieMap::new(); 1339 | assert!(m.get("5") == None); 1340 | } 1341 | 1342 | #[test] 1343 | fn find_not_found() { 1344 | let mut m = BurstTrieMap::new(); 1345 | assert!(m.insert("1", 2).is_none()); 1346 | assert!(m.insert("5", 3).is_none()); 1347 | assert!(m.insert("9", 3).is_none()); 1348 | assert_eq!(m.get("2"), None); 1349 | } 1350 | 1351 | #[test] 1352 | fn test_len() { 1353 | let mut m = BurstTrieMap::new(); 1354 | assert!(m.insert("3", 6).is_none()); 1355 | assert_eq!(m.len(), 1); 1356 | assert!(m.insert("0", 0).is_none()); 1357 | assert_eq!(m.len(), 2); 1358 | assert!(m.insert("4", 8).is_none()); 1359 | assert_eq!(m.len(), 3); 1360 | assert!(m.remove("3").is_some()); 1361 | assert_eq!(m.len(), 2); 1362 | assert!(!m.remove("5").is_some()); 1363 | assert_eq!(m.len(), 2); 1364 | assert!(m.insert("2", 4).is_none()); 1365 | assert_eq!(m.len(), 3); 1366 | assert!(m.insert("1", 2).is_none()); 1367 | assert_eq!(m.len(), 4); 1368 | } 1369 | 1370 | #[test] 1371 | fn insert_replace() { 1372 | let mut m = BurstTrieMap::new(); 1373 | assert!(m.insert("5", 2).is_none()); 1374 | assert!(m.insert("2", 9).is_none()); 1375 | assert!(!m.insert("2", 11).is_none()); 1376 | assert_eq!(m.get("2").unwrap(), &11); 1377 | } 1378 | 1379 | #[test] 1380 | fn test_swap() { 1381 | let mut m = BurstTrieMap::new(); 1382 | assert_eq!(m.insert("1", 2), None); 1383 | assert_eq!(m.insert("1", 3), Some(2)); 1384 | assert_eq!(m.insert("1", 4), Some(3)); 1385 | } 1386 | 1387 | #[test] 1388 | fn test_pop() { 1389 | let mut m = BurstTrieMap::new(); 1390 | m.insert("1", 2); 1391 | assert_eq!(m.remove("1"), Some(2)); 1392 | assert_eq!(m.remove("1"), None); 1393 | } 1394 | 1395 | #[test] 1396 | fn test_clear() { 1397 | let mut m = BurstTrieMap::new(); 1398 | m.clear(); 1399 | assert!(m.insert("5", 11).is_none()); 1400 | assert!(m.insert("2", -3).is_none()); 1401 | assert!(m.insert("9", 2).is_none()); 1402 | m.clear(); 1403 | assert!(m.get("5").is_none()); 1404 | assert!(m.get("2").is_none()); 1405 | assert!(m.get("9").is_none()); 1406 | assert!(m.is_empty()); 1407 | } 1408 | 1409 | #[test] 1410 | fn test_index() { 1411 | let mut m = BurstTrieMap::new(); 1412 | m.insert("1", 2); 1413 | assert_eq!(m["1"], 2); 1414 | { 1415 | let ref_1 = &mut m["1"]; 1416 | *ref_1 = 3; 1417 | } 1418 | assert_eq!(m["1"], 3); 1419 | } 1420 | } 1421 | 1422 | #[cfg(test)] 1423 | mod bench { 1424 | use test; 1425 | use super::BurstTrieMap; 1426 | use bench_macros::BENCH_SEED; 1427 | 1428 | map_get_rnd_bench!(burst_get_short_1000, 5, 15, 1000, BurstTrieMap); 1429 | map_get_rnd_bench!(burst_get_short_10000, 5, 15, 10000, BurstTrieMap); 1430 | map_get_rnd_bench!(burst_get_short_100000, 5, 15, 100000, BurstTrieMap); 1431 | map_get_rnd_bench!(burst_get_medium_1000, 20, 100, 1000, BurstTrieMap); 1432 | map_get_rnd_bench!(burst_get_medium_10000, 20, 100, 10000, BurstTrieMap); 1433 | map_get_rnd_bench!(burst_get_medium_100000, 20, 100, 100000, BurstTrieMap); 1434 | map_insert_rnd_bench!(burst_insert_short_1000, 5, 15, 1000, BurstTrieMap); 1435 | map_insert_rnd_bench!(burst_insert_short_10000, 5, 15, 10000, BurstTrieMap); 1436 | map_insert_rnd_bench!(burst_insert_short_100000, 5, 15, 100000, BurstTrieMap); 1437 | map_insert_rnd_bench!(burst_insert_medium_1000, 20, 100, 1000, BurstTrieMap); 1438 | map_insert_rnd_bench!(burst_insert_medium_10000, 20, 100, 10000, BurstTrieMap); 1439 | map_insert_rnd_bench!(burst_insert_medium_100000, 20, 100, 100000, BurstTrieMap); 1440 | 1441 | map_get_rnd_bench!(burst_get_prefix_medium_10000, 20, 100, 10000, BurstTrieMap, "https://www."); 1442 | map_get_rnd_bench!(burst_get_prefix_medium_100000, 20, 100, 100000, BurstTrieMap, "https://www."); 1443 | map_insert_rnd_bench!(burst_insert_prefix_medium_10000, 20, 100, 10000, BurstTrieMap, "https://www."); 1444 | map_insert_rnd_bench!(burst_insert_prefix_medium_100000, 20, 100, 100000, BurstTrieMap, "https://www."); 1445 | 1446 | 1447 | map_get_seq_bench!(burst_get_seq_100000, 20, 100, 100000, BurstTrieMap); 1448 | map_insert_seq_bench!(burst_insert_seq_100000, 20, 100, 100000, BurstTrieMap); 1449 | 1450 | // map_iter_bench!(burst_iter_10000, 20, 100, 10000, BurstTrieMap); 1451 | // map_range_bench!(burst_range_10000, 20, 100, 10000, BurstTrieMap); 1452 | 1453 | 1454 | 1455 | use std::collections::BTreeMap; 1456 | map_get_rnd_bench!(btree_get_short_1000, 5, 15, 1000, BTreeMap); 1457 | map_get_rnd_bench!(btree_get_short_10000, 5, 15, 10000, BTreeMap); 1458 | map_get_rnd_bench!(btree_get_short_100000, 5, 15, 100000, BTreeMap); 1459 | map_get_rnd_bench!(btree_get_medium_1000, 20, 100, 1000, BTreeMap); 1460 | map_get_rnd_bench!(btree_get_medium_10000, 20, 100, 10000, BTreeMap); 1461 | map_get_rnd_bench!(btree_get_medium_100000, 20, 100, 100000, BTreeMap); 1462 | map_insert_rnd_bench!(btree_insert_short_1000, 5, 15, 1000, BTreeMap); 1463 | map_insert_rnd_bench!(btree_insert_short_10000, 5, 15, 10000, BTreeMap); 1464 | map_insert_rnd_bench!(btree_insert_short_100000, 5, 15, 100000, BTreeMap); 1465 | map_insert_rnd_bench!(btree_insert_medium_1000, 20, 100, 1000, BTreeMap); 1466 | map_insert_rnd_bench!(btree_insert_medium_10000, 20, 100, 10000, BTreeMap); 1467 | map_insert_rnd_bench!(btree_insert_medium_100000, 20, 100, 100000, BTreeMap); 1468 | 1469 | map_get_rnd_bench!(btree_get_prefix_medium_10000, 20, 100, 10000, BTreeMap, "https://www."); 1470 | map_get_rnd_bench!(btree_get_prefix_medium_100000, 20, 100, 100000, BTreeMap, "https://www."); 1471 | map_insert_rnd_bench!(btree_insert_prefix_medium_10000, 20, 100, 10000, BTreeMap, "https://www."); 1472 | map_insert_rnd_bench!(btree_insert_prefix_medium_100000, 20, 100, 100000, BTreeMap, "https://www."); 1473 | 1474 | map_get_seq_bench!(btree_get_seq_100000, 20, 100, 100000, BTreeMap); 1475 | map_insert_seq_bench!(btree_insert_seq_100000, 20, 100, 100000, BTreeMap); 1476 | 1477 | use std::collections::HashMap; 1478 | map_get_rnd_bench!(hash_get_short_1000, 5, 15, 1000, HashMap); 1479 | map_get_rnd_bench!(hash_get_short_10000, 5, 15, 10000, HashMap); 1480 | map_get_rnd_bench!(hash_get_short_100000, 5, 15, 100000, HashMap); 1481 | map_get_rnd_bench!(hash_get_medium_1000, 20, 100, 1000, HashMap); 1482 | map_get_rnd_bench!(hash_get_medium_10000, 20, 100, 10000, HashMap); 1483 | map_get_rnd_bench!(hash_get_medium_100000, 20, 100, 100000, HashMap); 1484 | map_insert_rnd_bench!(hash_insert_short_1000, 5, 15, 1000, HashMap); 1485 | map_insert_rnd_bench!(hash_insert_short_10000, 5, 15, 10000, HashMap); 1486 | map_insert_rnd_bench!(hash_insert_short_100000, 5, 15, 100000, HashMap); 1487 | map_insert_rnd_bench!(hash_insert_medium_1000, 20, 100, 1000, HashMap); 1488 | map_insert_rnd_bench!(hash_insert_medium_10000, 20, 100, 10000, HashMap); 1489 | map_insert_rnd_bench!(hash_insert_medium_100000, 20, 100, 100000, HashMap); 1490 | 1491 | map_get_rnd_bench!(hash_get_prefix_medium_10000, 20, 100, 10000, HashMap, "https://www."); 1492 | map_get_rnd_bench!(hash_get_prefix_medium_100000, 20, 100, 100000, HashMap, "https://www."); 1493 | map_insert_rnd_bench!(hash_insert_prefix_medium_10000, 20, 100, 10000, HashMap, "https://www."); 1494 | map_insert_rnd_bench!(hash_insert_prefix_medium_100000, 20, 100, 100000, HashMap, "https://www."); 1495 | 1496 | 1497 | 1498 | // map_iter_bench!(btree_iter_10000, 20, 100, 10000, BTreeMap); 1499 | // map_range_bench!(btree_range_10000, 20, 100, 10000, BTreeMap); 1500 | } 1501 | --------------------------------------------------------------------------------