I am trying to build a tree-like data structure using the Node
representation:
use std::cmp::Ordering;
use std::fmt::Debug;
use std::sync::Arc;
const BRANCH_FACTOR: usize = 32;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
enum Node<T> {
Branch {
children: [Option<Arc<Node<T>>>; BRANCH_FACTOR],
len: usize,
},
RelaxedBranch {
children: [Option<Arc<Node<T>>>; BRANCH_FACTOR],
sizes: [Option<usize>; BRANCH_FACTOR],
len: usize,
},
Leaf {
elements: [Option<T>; BRANCH_FACTOR],
len: usize,
},
}
playground
The RelaxedBranch
variant of the enum will be used rarely, sometimes not at all. Since the size of enums in Rust is defined by the size of the largest variant, RelaxedBranch
increases overall the memory footprint of Node
drastically. The large size of this enum causes a 20% performance hit, which is not acceptable in my case.
As an alternative to enums, I have decided to try trait objects:
use std::cmp::Ordering;
use std::fmt::Debug;
use std::sync::Arc;
const BRANCH_FACTOR: usize = 32;
trait Node<T>: Debug + Clone + PartialEq + Eq + PartialOrd + Ord {}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
struct Branch<T> {
children: [Option<Arc<Node<T>>>; BRANCH_FACTOR],
len: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
struct RelaxedBranch<T> {
children: [Option<Arc<Node<T>>>; BRANCH_FACTOR],
len: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
struct Leaf<T> {
elements: [Option<T>; BRANCH_FACTOR],
len: usize,
}
impl<T> Node<T> for Branch<T> {}
impl<T> Node<T> for RelaxedBranch<T> {}
impl<T> Node<T> for Leaf<T> {}
playground
I have quickly discovered something called trait object safety :) This doesn't allow traits used for trait objects to return objects of the Self
type, which is my case due to inheritance from Clone
.
How can I represent a tree node without having the overhead of enums?
See Question&Answers more detail:
os