intrusivesplaytree

An intrusive, allocation-free [splay tree] implementation.

Travis CI Build Status

Splay trees are self-adjusting, meaning that operating on an element (for example, doing a find or an insert) rebalances the tree in such a way that the element becomes the root. This means that subsequent operations on that element are O(1) as long as no other element is operated on in the meantime.

Implementation and Goals

Constraints

Example

This example defines a Monster type, where each of its instances live within two intrusive trees: one ordering monsters by their name, and the other ordering them by their health.

```rust

[macro_use]

extern crate intrusivesplaytree; extern crate typed_arena;

use intrusivesplaytree::SplayTree;

use std::cmp::Ordering; use std::marker::PhantomData;

// We have a monster type, and we want to query monsters by both name and // health.

[derive(Debug)]

struct Monster<'a> { name: String, health: u64,

// An intrusive node so we can put monsters in a tree to query by name.
by_name_node: intrusive_splay_tree::Node<'a>,

// Another intrusive node so we can put monsters in a second tree (at
// the same time!) and query them by health.
by_health_node: intrusive_splay_tree::Node<'a>,

}

// Define a type for trees where monsters are ordered by name. struct MonstersByName;

// Implement IntrusiveNode for the MonstersByName tree, where the // element type is Monster and the field in Monster that has this tree's // intrusive node is by_name. implintrusivenode! { impl<'a> IntrusiveNode<'a> for MonstersByName where type Elem = Monster<'a>, node = bynamenode; }

// Define how to order Monsters within the MonstersByName tree by // implementing TreeOrd. impl<'a> intrusivesplaytree::TreeOrd<'a, MonstersByName> for Monster<'a> { fn tree_cmp(&self, rhs: &Monster<'a>) -> Ordering { self.name.cmp(&rhs.name) } }

// And do all the same things for trees where monsters are ordered by health... struct MonstersByHealth; implintrusivenode! { impl<'a> IntrusiveNode<'a> for MonstersByHealth where type Elem = Monster<'a>, node = byhealthnode; } impl<'a> intrusivesplaytree::TreeOrd<'a, MonstersByHealth> for Monster<'a> { fn tree_cmp(&self, rhs: &Monster<'a>) -> Ordering { self.health.cmp(&rhs.health) } }

// We can also implement TreeOrd for other types, so that we can query the // tree by these types. For example, we want to query the MonstersByHealth // tree by some u64 health value, and we want to query the MonstersByName // tree by some &str name value.

impl<'a> intrusivesplaytree::TreeOrd<'a, MonstersByHealth> for u64 { fn tree_cmp(&self, rhs: &Monster<'a>) -> Ordering { self.cmp(&rhs.health) } }

impl<'a> intrusivesplaytree::TreeOrd<'a, MonstersByName> for str { fn tree_cmp(&self, rhs: &Monster<'a>) -> Ordering { self.cmp(&rhs.name) } }

impl<'a> Monster<'a> { /// The Monster constructor allocates Monsters in a typed arena, and /// inserts the new Monster in both trees. pub fn new( arena: &'a typedarena::Arena>, name: String, health: u64, bynametree: &mut SplayTree<'a, MonstersByName>, byhealthtree: &mut SplayTree<'a, MonstersByHealth> ) -> &'a Monster<'a> { let monster = arena.alloc(Monster { name, health, bynamenode: Default::default(), byhealth_node: Default::default(), });

    by_name_tree.insert(monster);
    by_health_tree.insert(monster);

    monster
}

}

fn main() { // The arena that the monsters will live within. let mut arena = typed_arena::Arena::new();

// The splay trees ordered by name and health respectively.
let mut by_name_tree = SplayTree::default();
let mut by_health_tree = SplayTree::default();

// Now let's create some monsters, inserting them into the trees!

Monster::new(
    &arena,
    "Frankenstein's Monster".into(),
    99,
    &mut by_name_tree,
    &mut by_health_tree,
);

Monster::new(
    &arena,
    "Godzilla".into(),
    2000,
    &mut by_name_tree,
    &mut by_health_tree,
);

Monster::new(
    &arena,
    "Vegeta".into(),
    9001,
    &mut by_name_tree,
    &mut by_health_tree,
);

// Query the `MonstersByName` tree by a name.

let godzilla = by_name_tree.find("Godzilla").unwrap();
assert_eq!(godzilla.name, "Godzilla");

assert!(by_name_tree.find("Gill-Man").is_none());

// Query the `MonstersByHealth` tree by a health.

let vegeta = by_health_tree.find(&9001).unwrap();
assert_eq!(vegeta.name, "Vegeta");

assert!(by_health_tree.find(&0).is_none());

} ```

License: MPL-2.0