1use std::collections::hash_map::Entry;
4use std::collections::HashMap;
5use std::hash::Hash;
6
7use sophia_api::term::TTerm;
8use sophia_term::*;
9
10pub mod reexport {
12 pub use sophia_api::graph::MgResult;
13 pub use sophia_api::triple::stream::{StreamResult, TripleSource};
14 pub use sophia_api::triple::Triple;
15}
16
17pub trait IndexedGraph {
26 type Index: Copy + Eq + Hash;
28
29 type TermData: TermData + 'static;
31
32 fn with_capacity(capacity: usize) -> Self;
34
35 fn shrink_to_fit(&mut self);
37
38 fn get_index<T>(&self, t: &T) -> Option<Self::Index>
40 where
41 T: TTerm + ?Sized;
42
43 fn get_term(&self, i: Self::Index) -> Option<&Term<Self::TermData>>;
45
46 fn insert_indexed<TS, TP, TO>(&mut self, s: &TS, p: &TP, o: &TO) -> Option<[Self::Index; 3]>
49 where
50 TS: TTerm + ?Sized,
51 TP: TTerm + ?Sized,
52 TO: TTerm + ?Sized;
53 fn remove_indexed<TS, TP, TO>(&mut self, s: &TS, p: &TP, o: &TO) -> Option<[Self::Index; 3]>
56 where
57 TS: TTerm + ?Sized,
58 TP: TTerm + ?Sized,
59 TO: TTerm + ?Sized;
60}
61
62#[macro_export]
65macro_rules! impl_collectible_graph_for_indexed_graph {
66 ($indexed_mutable_graph: ty) => {
67 impl CollectibleGraph for $indexed_mutable_graph {
68 impl_collectible_graph_for_indexed_graph!();
69 }
70 };
71 () => {
72 fn from_triple_source<TS: $crate::graph::reexport::TripleSource>(
73 mut triples: TS,
74 ) -> $crate::graph::reexport::StreamResult<Self, TS::Error, Self::Error> {
75 use $crate::graph::reexport::Triple;
76 let (tmin, tmax) = triples.size_hint_triples();
77 let cap = tmax.unwrap_or(tmin);
78 let mut g = Self::with_capacity(cap);
79 triples
80 .try_for_each_triple(|t| -> Result<(), Self::Error> {
81 g.insert_indexed(t.s(), t.p(), t.o());
82 Ok(())
83 })
84 .map(|_| g)
85 }
86 };
87}
88
89#[macro_export]
92macro_rules! impl_mutable_graph_for_indexed_graph {
93 ($indexed_mutable_graph: ty) => {
94 impl MutableGraph for $indexed_mutable_graph {
95 impl_mutable_graph_for_indexed_graph!();
96 }
97 };
98 () => {
99 type MutationError = std::convert::Infallible;
100
101 fn insert<TS_, TP_, TO_>(
102 &mut self,
103 s: &TS_,
104 p: &TP_,
105 o: &TO_,
106 ) -> $crate::graph::reexport::MgResult<Self, bool>
107 where
108 TS_: sophia_api::term::TTerm + ?Sized,
109 TP_: sophia_api::term::TTerm + ?Sized,
110 TO_: sophia_api::term::TTerm + ?Sized,
111 {
112 Ok(self.insert_indexed(s, p, o).is_some())
113 }
114 fn remove<TS_, TP_, TO_>(
115 &mut self,
116 s: &TS_,
117 p: &TP_,
118 o: &TO_,
119 ) -> $crate::graph::reexport::MgResult<Self, bool>
120 where
121 TS_: sophia_api::term::TTerm + ?Sized,
122 TP_: sophia_api::term::TTerm + ?Sized,
123 TO_: sophia_api::term::TTerm + ?Sized,
124 {
125 Ok(self.remove_indexed(s, p, o).is_some())
126 }
127 };
128}
129
130pub fn insert_in_index<K, W>(hm: &mut HashMap<K, Vec<W>>, k: K, w: W) -> bool
139where
140 K: Eq + Hash,
141 W: Copy + Eq,
142{
143 let mut ret = false;
144 hm.entry(k)
145 .or_insert_with(|| {
146 ret = true;
147 Vec::new()
148 })
149 .push(w);
150 ret
151}
152
153pub fn remove_from_index<K, W>(hm: &mut HashMap<K, Vec<W>>, k: K, w: W) -> bool
167where
168 K: Eq + Hash,
169 W: Copy + Eq,
170{
171 match hm.entry(k) {
172 Entry::Occupied(mut e) => {
173 {
174 let ws = e.get_mut();
175 if ws.len() > 1 {
176 let wi = ws
177 .iter()
178 .enumerate()
179 .filter_map(|(i, w2)| if *w2 == w { Some(i) } else { None })
180 .next()
181 .unwrap();
182 ws.swap_remove(wi);
183 return false;
184 }
185 }
186 e.remove_entry();
187 true
188 }
189 Entry::Vacant(_) => unreachable!(),
190 }
191}
192
193#[cfg(test)]
194mod test {
195 }