Ditch AppendOnlyGraph, which was broken and unfixable.

This commit is contained in:
Stu Black 2019-07-23 01:11:59 -04:00
parent 154e49c9f0
commit 01497be3e8

View File

@ -4,15 +4,9 @@ pub mod nav;
pub mod search;
pub mod view;
use std::cell::UnsafeCell;
use std::error::Error;
use std::fmt;
use std::hash::Hash;
use std::ops::Deref;
use base::{EdgeId, RawEdge, RawVertex, VertexId};
use mutators::{MutEdge, MutNode};
use nav::{Edge, Node};
use symbol_map::indexing::{Indexing, Insertion};
use symbol_map::SymbolId;
@ -108,9 +102,9 @@ where
/// Gets a node handle for the given game state.
///
/// If `state` does not correspond to a known game state, returns `None`.
pub fn find_node<'s>(&'s self, state: &T) -> Option<Node<'s, T, S, A>> {
pub fn find_node<'s>(&'s self, state: &T) -> Option<nav::Node<'s, T, S, A>> {
match self.state_ids.get(state) {
Some(symbol) => Some(Node::new(self, *symbol.id())),
Some(symbol) => Some(nav::Node::new(self, *symbol.id())),
None => None,
}
}
@ -118,9 +112,9 @@ where
/// Gets a mutable node handle for the given game state.
///
/// If `state` does not correspond to a known game state, returns `None`.
pub fn find_node_mut<'s>(&'s mut self, state: &T) -> Option<MutNode<'s, T, S, A>> {
pub fn find_node_mut<'s>(&'s mut self, state: &T) -> Option<mutators::MutNode<'s, T, S, A>> {
match self.state_ids.get(state).map(|s| s.id().clone()) {
Some(id) => Some(MutNode::new(self, id)),
Some(id) => Some(mutators::MutNode::new(self, id)),
None => None,
}
}
@ -132,7 +126,7 @@ where
/// ignoring the `data` parameter. As a result, this method is guaranteed to
/// return a handle for a root vertex only when `state` is a novel game
/// state.
pub fn add_node<'s>(&'s mut self, state: T, data: S) -> MutNode<'s, T, S, A> {
pub fn add_node<'s>(&'s mut self, state: T, data: S) -> mutators::MutNode<'s, T, S, A> {
let node_id = match self.state_ids.get_or_insert(state).map(|s| s.id().clone()) {
Insertion::Present(id) => id,
Insertion::New(id) => {
@ -140,7 +134,7 @@ where
id
}
};
MutNode::new(self, node_id)
mutators::MutNode::new(self, node_id)
}
/// Adds an edge from the vertex with state data `source` to the vertex with
@ -157,15 +151,15 @@ where
dest: T,
dest_data: G,
edge_data: A,
) -> MutEdge<'s, T, S, A>
) -> mutators::MutEdge<'s, T, S, A>
where
F: for<'b> FnOnce(Node<'b, T, S, A>) -> S,
G: for<'b> FnOnce(Node<'b, T, S, A>) -> S,
F: for<'b> FnOnce(nav::Node<'b, T, S, A>) -> S,
G: for<'b> FnOnce(nav::Node<'b, T, S, A>) -> S,
{
let source_id = match self.state_ids.get_or_insert(source).map(|s| s.id().clone()) {
Insertion::Present(id) => id,
Insertion::New(id) => {
let data = source_data(Node::new(self, id));
let data = source_data(nav::Node::new(self, id));
self.add_raw_vertex(data);
id
}
@ -173,13 +167,13 @@ where
let dest_id = match self.state_ids.get_or_insert(dest).map(|s| s.id().clone()) {
Insertion::Present(id) => id,
Insertion::New(id) => {
let data = dest_data(Node::new(self, id));
let data = dest_data(nav::Node::new(self, id));
self.add_raw_vertex(data);
id
}
};
let edge_id = self.add_raw_edge(edge_data, source_id, dest_id);
MutEdge::new(self, edge_id)
mutators::MutEdge::new(self, edge_id)
}
/// Returns the number of vertices in the graph.
@ -195,119 +189,6 @@ where
}
}
/// Allows both read-only references into a `Graph` and operations that modify
/// the graph but do not invalidate family of types defined in the `nav`
/// module.
///
/// All methods on `Graph` that take a `&self` parameter may also be called on
/// an `AppendOnlyGraph`. The `add_node` and `add_edge` methods may also be
/// called, because they do not invalidate `Node`, `Edge`, or other such smart
/// pointers into the underlying graph. Unlike the analogous methods on `Graph`,
/// these methods return a read-only view of the graph topology, instead of
/// granting read-write access.
///
/// For example:
///
/// ```rust
/// # use search_graph::{AppendOnlyGraph, Graph};
/// # use search_graph::nav::{Node, Edge};
/// # fn main() {
/// let appendable: AppendOnlyGraph<u32, String, f32> = Graph::new().into();
/// let root1 = appendable.append_node(0, "data1".to_string());
/// // If appendable were a Graph, we could not call append_node while root1 is alive.
/// let root2 = appendable.append_node(1, "data2".to_string());
/// assert_eq!("data1", appendable.find_node(&0).unwrap().get_data());
/// assert!(root1.is_leaf());
/// let edge = appendable.append_edge(root1.clone(), root2.clone(), 3.3).unwrap();
/// assert_eq!(*edge.get_source().get_label(), 0);
/// assert_eq!(*edge.get_target().get_label(), 1);
/// assert!(!root1.is_leaf());
/// # }
/// ```
pub struct AppendOnlyGraph<T, S, A>
where
T: Hash + Eq + Clone,
{
graph: UnsafeCell<Graph<T, S, A>>,
}
#[derive(Debug)]
pub enum AppendEdgeError {
GraphMismatch,
}
impl fmt::Display for AppendEdgeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl Error for AppendEdgeError {
fn description(&self) -> &'static str {
match *self {
AppendEdgeError::GraphMismatch => {
"Underlying graph mismatch (cannot create an edge between vertices in two different graphs)"
}
}
}
}
impl<T, S, A> AppendOnlyGraph<T, S, A>
where
T: Hash + Eq + Clone,
{
pub fn append_node<'s>(&'s self, state: T, data: S) -> Node<'s, T, S, A> {
let graph: &mut Graph<T, S, A> = unsafe { &mut *self.graph.get() };
graph.add_node(state, data).to_node()
}
pub fn append_edge<'s, 'a>(
&'s self,
source: Node<'a, T, S, A>,
target: Node<'a, T, S, A>,
edge_data: A,
) -> Result<Edge<'s, T, S, A>, AppendEdgeError> {
if std::ptr::eq(source.graph, target.graph) {
let graph: &mut Graph<T, S, A> = unsafe { &mut *self.graph.get() };
let id = graph.add_raw_edge(edge_data, source.id, target.id);
Ok(Edge { graph, id })
} else {
Err(AppendEdgeError::GraphMismatch)
}
}
}
impl<T, S, A> Deref for AppendOnlyGraph<T, S, A>
where
T: Hash + Eq + Clone,
{
type Target = Graph<T, S, A>;
fn deref(&self) -> &Graph<T, S, A> {
unsafe { &*self.graph.get() }
}
}
impl<T, S, A> From<AppendOnlyGraph<T, S, A>> for Graph<T, S, A>
where
T: Hash + Eq + Clone,
{
fn from(graph: AppendOnlyGraph<T, S, A>) -> Self {
graph.graph.into_inner()
}
}
impl<T, S, A> From<Graph<T, S, A>> for AppendOnlyGraph<T, S, A>
where
T: Hash + Eq + Clone,
{
fn from(graph: Graph<T, S, A>) -> Self {
AppendOnlyGraph {
graph: UnsafeCell::new(graph),
}
}
}
#[cfg(test)]
mod test {
use crossbeam_utils::thread;