//! Provides maps to associate custom data to graph vertices and edges. //! //! [`EntityMap`] provides a copy-on-write, [`Vec`]-backed map to associate data to either all //! vertices or all edges in a graph. use std::ops::{Index, IndexMut}; /// A map to associate custom data to graph vertices or edges. /// /// This map uses raw entity indices to associate homogenous custom data of type `T` to graph /// vertices or edges. The implementation uses a [`Vec`], allocating contiguous slots for the data, /// which means that the provided index conversion function should map entities to contiguous /// indices, or indices with relatively few gaps. /// /// Data allocation happens as copy-on-write, i.e. the backing [`Vec`] is only resized if a value is /// written beyond current capacity, but the `default` value can transparently be read. No bound or /// validity checks are performed by the map on the provided entity handles. /// /// Use [`GraphTopology::vertex_map`] or [`GraphTopology::edge_map`] to obtain an `EntityMap` for /// vertices or edges, respectively. pub struct EntityMap { data: Vec, default: T, to_index: fn(E) -> usize, } impl EntityMap { /// Creates a new map with the given `default` value, an index conversion function `to_index`, /// and an initial `capacity`. pub fn new(default: T, to_index: fn(E) -> usize, capacity: usize) -> Self { Self { data: vec![default.clone(); capacity], default, to_index, } } /// Returns the total number of data entries the map can write without reallocating. Reads /// beyond `capacity` are valid and return the default value. pub fn capacity(&self) -> usize { self.data.capacity() } /// Expands the internal data storage capacity of the map to `capacity`, Does nothing if /// capacity is already sufficient. /// /// Use this before writing data for new graph entities to avoid incremental growth on the first /// write to each new entity. pub fn expand(&mut self, capacity: usize) { if capacity > self.data.len() { self.data.resize(capacity, self.default.clone()); } } } impl Index for EntityMap { type Output = T; fn index(&self, e: E) -> &T { let i = (self.to_index)(e); if i < self.data.len() { &self.data[i] } else { &self.default } } } impl IndexMut for EntityMap { fn index_mut(&mut self, e: E) -> &mut T { let i = (self.to_index)(e); if i >= self.data.len() { self.data.resize(i + 1, self.default.clone()); } &mut self.data[i] } }