Skip to content

Commit b77f690

Browse files
frankmcsherrynikomatsakis
authored andcommitted
first hop
1 parent 4d1e089 commit b77f690

File tree

2 files changed

+318
-0
lines changed

2 files changed

+318
-0
lines changed

src/leapfrog.rs

Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
//! Join functionality.
2+
3+
use super::{Variable, Relation};
4+
5+
/// Performs leapfrog join using a list of leapers.
6+
pub fn leapfrog_into<'a, Tuple: Ord, Val: Ord+'a, Result: Ord>(
7+
source: &Variable<Tuple>,
8+
leapers: &mut [&mut LeapFrog<'a, Tuple, Val>],
9+
output: &Variable<Result>,
10+
mut logic: impl FnMut(&Tuple, &Val)->Result) {
11+
12+
let mut result = Vec::new();
13+
14+
for tuple in source.recent.borrow().iter() {
15+
16+
for leaper in leapers.iter_mut() {
17+
leaper.seek_prefix(tuple);
18+
}
19+
20+
while !leapers.iter().any(|l| l.is_empty()) {
21+
// for leaper in leapers.iter() { println!("{:?}, {:?}", leaper.peek_val().is_some(), leaper.is_empty()); }
22+
let val = leapers.iter_mut().flat_map(|l| l.peek_val()).max().expect("No maximum found");
23+
let mut present = true;
24+
for leaper in leapers.iter_mut() {
25+
if !leaper.seek_val(&val) { present = false; }
26+
}
27+
if present {
28+
result.push(logic(&tuple, &val));
29+
}
30+
}
31+
32+
}
33+
34+
output.insert(result.into());
35+
}
36+
37+
/// Methods to support leapfrog navigation.
38+
pub trait LeapFrog<'a,Tuple,Val> {
39+
/// Sets the cursor for a specific key.
40+
fn seek_prefix(&mut self, prefix: &Tuple);
41+
/// Seeks a specific key and value pair.
42+
///
43+
/// This method positions the cursor just after `val`,
44+
/// under the assumption that we will not seek for the
45+
/// same value immediately afterwards.
46+
fn seek_val(&mut self, val: &Val) -> bool;
47+
/// Proposes a next value.
48+
///
49+
/// It is not mandatory that this method return a value,
50+
/// but we will only observe extensions in the union of
51+
/// peeked values. This allows antijoin implementations
52+
/// to implement this interface, as long as at least one
53+
/// normal join participates.
54+
fn peek_val(&self) -> Option<&'a Val>;
55+
/// Indicates no further values available.
56+
fn is_empty(&self) -> bool;
57+
}
58+
59+
/// Extension method for relations.
60+
pub trait Leaper<Key: Ord, Val: Ord> {
61+
/// Extend with `Val` using the elements of the relation.
62+
fn extend_with<'a, Tuple: Ord, Func: Fn(&Tuple)->Key>(&'a self, key_func: Func) -> extend_with::ExtendWith<'a, Key, Val, Tuple, Func> where Key: 'a, Val: 'a;
63+
/// Extend with `Val` using the complement of the relation.
64+
fn extend_anti<'a, Tuple: Ord, Func: Fn(&Tuple)->Key>(&'a self, key_func: Func) -> extend_anti::ExtendAnti<'a, Key, Val, Tuple, Func> where Key: 'a, Val: 'a;
65+
/// Extend with any value if tuple is present in relation.
66+
fn filter_with<'a, Tuple: Ord, Func: Fn(&Tuple)->(Key,Val)>(&'a self, key_func: Func) -> filter_with::FilterWith<'a, Key, Val, Tuple, Func> where Key: 'a, Val: 'a;
67+
/// Extend with any value if tuple is absent from relation.
68+
fn filter_anti<'a, Tuple: Ord, Func: Fn(&Tuple)->(Key,Val)>(&'a self, key_func: Func) -> filter_anti::FilterAnti<'a, Key, Val, Tuple, Func> where Key: 'a, Val: 'a;
69+
}
70+
71+
impl<Key: Ord, Val: Ord> Leaper<Key, Val> for Relation<(Key, Val)> {
72+
fn extend_with<'a, Tuple: Ord, Func: Fn(&Tuple)->Key>(&'a self, key_func: Func) -> extend_with::ExtendWith<'a, Key, Val, Tuple, Func> where Key: 'a, Val: 'a {
73+
extend_with::ExtendWith::from(self, key_func)
74+
}
75+
fn extend_anti<'a, Tuple: Ord, Func: Fn(&Tuple)->Key>(&'a self, key_func: Func) -> extend_anti::ExtendAnti<'a, Key, Val, Tuple, Func> where Key: 'a, Val: 'a {
76+
extend_anti::ExtendAnti::from(self, key_func)
77+
}
78+
fn filter_with<'a, Tuple: Ord, Func: Fn(&Tuple)->(Key,Val)>(&'a self, key_func: Func) -> filter_with::FilterWith<'a, Key, Val, Tuple, Func> where Key: 'a, Val: 'a {
79+
filter_with::FilterWith::from(self, key_func)
80+
}
81+
fn filter_anti<'a, Tuple: Ord, Func: Fn(&Tuple)->(Key,Val)>(&'a self, key_func: Func) -> filter_anti::FilterAnti<'a, Key, Val, Tuple, Func> where Key: 'a, Val: 'a {
82+
filter_anti::FilterAnti::from(self, key_func)
83+
}
84+
}
85+
86+
mod extend_with {
87+
88+
use super::{Relation, LeapFrog, gallop};
89+
90+
/// Wraps a Relation<Tuple> as a leaper.
91+
pub struct ExtendWith<'a, Key: Ord+'a, Val: Ord+'a, Tuple: Ord, Func: Fn(&Tuple)->Key> {
92+
relation: &'a Relation<(Key, Val)>,
93+
start: usize,
94+
end: usize,
95+
key_func: Func,
96+
phantom: ::std::marker::PhantomData<Tuple>,
97+
}
98+
99+
impl<'a, Key: Ord+'a, Val: Ord+'a, Tuple: Ord, Func: Fn(&Tuple)->Key> ExtendWith<'a, Key, Val, Tuple, Func> {
100+
/// Constructs a ExtendWith from a relation and key and value function.
101+
pub fn from(relation: &'a Relation<(Key, Val)>, key_func: Func) -> Self {
102+
ExtendWith {
103+
relation,
104+
start: 0,
105+
end: 0,
106+
key_func,
107+
phantom: ::std::marker::PhantomData,
108+
}
109+
}
110+
}
111+
112+
impl<'a, Key: Ord, Val: Ord+'a, Tuple: Ord, Func: Fn(&Tuple)->Key> LeapFrog<'a, Tuple,Val> for ExtendWith<'a, Key, Val, Tuple, Func> {
113+
fn seek_prefix(&mut self, tuple: &Tuple) {
114+
let key = (self.key_func)(tuple);
115+
let slice1 = gallop(&self.relation[..], |x| &x.0 < &key);
116+
let slice2 = gallop(slice1, |x| &x.0 <= &key);
117+
self.start = self.relation.len() - slice1.len();
118+
self.end = self.relation.len() - slice2.len();
119+
assert!(self.start <= self.end);
120+
}
121+
fn seek_val(&mut self, val: &Val) -> bool {
122+
assert!(self.start <= self.end);
123+
// Attempt to position the cursor at (key, val).
124+
if !self.is_empty() {
125+
let slice = gallop(&self.relation[self.start .. self.end], |x| &x.1 < val);
126+
self.start = self.end - slice.len();
127+
}
128+
// If the cursor is positioned at something that yields `val`, then success.
129+
if self.peek_val() == Some(val) {
130+
self.start += 1;
131+
true
132+
}
133+
else {
134+
false
135+
}
136+
}
137+
fn peek_val(&self) -> Option<&'a Val> {
138+
assert!(self.start <= self.end);
139+
if self.start < self.end {
140+
Some(&self.relation[self.start].1)
141+
}
142+
else {
143+
None
144+
}
145+
}
146+
fn is_empty(&self) -> bool {
147+
assert!(self.start <= self.end);
148+
self.start == self.end
149+
}
150+
}
151+
}
152+
153+
mod extend_anti {
154+
155+
use super::{Relation, LeapFrog, gallop};
156+
157+
/// Wraps a Relation<Tuple> as a leaper.
158+
pub struct ExtendAnti<'a, Key: Ord+'a, Val: Ord+'a, Tuple: Ord, Func: Fn(&Tuple)->Key> {
159+
relation: &'a Relation<(Key, Val)>,
160+
start: usize,
161+
end: usize,
162+
key_func: Func,
163+
phantom: ::std::marker::PhantomData<Tuple>,
164+
}
165+
166+
impl<'a, Key: Ord+'a, Val: Ord+'a, Tuple: Ord, Func: Fn(&Tuple)->Key> ExtendAnti<'a, Key, Val, Tuple, Func> {
167+
/// Constructs a ExtendWith from a relation and key and value function.
168+
pub fn from(relation: &'a Relation<(Key, Val)>, key_func: Func) -> Self {
169+
ExtendAnti {
170+
relation,
171+
start: 0,
172+
end: 0,
173+
key_func,
174+
phantom: ::std::marker::PhantomData,
175+
}
176+
}
177+
}
178+
179+
impl<'a, Key: Ord, Val: Ord+'a, Tuple: Ord, Func: Fn(&Tuple)->Key> LeapFrog<'a, Tuple,Val> for ExtendAnti<'a, Key, Val, Tuple, Func> {
180+
fn seek_prefix(&mut self, tuple: &Tuple) {
181+
let key = (self.key_func)(tuple);
182+
let slice1 = gallop(&self.relation[..], |x| &x.0 < &key);
183+
let slice2 = gallop(slice1, |x| &x.0 <= &key);
184+
self.start = self.relation.len() - slice1.len();
185+
self.end = self.relation.len() - slice2.len();
186+
assert!(self.start <= self.end);
187+
}
188+
fn seek_val(&mut self, val: &Val) -> bool {
189+
assert!(self.start <= self.end);
190+
// Attempt to position the cursor at (key, val).
191+
if !self.is_empty() {
192+
let slice = gallop(&self.relation[self.start .. self.end], |x| &x.1 < val);
193+
self.start = self.end - slice.len();
194+
}
195+
// If the cursor is positioned at something that yields `val`, then success.
196+
if self.start < self.end && &self.relation[self.start].1 == val {
197+
self.start += 1;
198+
false
199+
}
200+
else {
201+
true
202+
}
203+
}
204+
fn peek_val(&self) -> Option<&'a Val> {
205+
None
206+
}
207+
fn is_empty(&self) -> bool {
208+
false
209+
}
210+
}
211+
}
212+
213+
mod filter_with {
214+
215+
use super::{Relation, LeapFrog};
216+
217+
/// Wraps a Relation<Tuple> as a leaper.
218+
pub struct FilterWith<'a, Key: Ord+'a, Val: Ord+'a, Tuple: Ord, Func: Fn(&Tuple)->(Key,Val)> {
219+
relation: &'a Relation<(Key, Val)>,
220+
key_func: Func,
221+
found: bool,
222+
phantom: ::std::marker::PhantomData<Tuple>,
223+
}
224+
225+
impl<'a, Key: Ord+'a, Val: Ord+'a, Tuple: Ord, Func: Fn(&Tuple)->(Key,Val)> FilterWith<'a, Key, Val, Tuple, Func> {
226+
/// Constructs a ExtendWith from a relation and key and value function.
227+
pub fn from(relation: &'a Relation<(Key, Val)>, key_func: Func) -> Self {
228+
FilterWith {
229+
relation,
230+
key_func,
231+
found: false,
232+
phantom: ::std::marker::PhantomData,
233+
}
234+
}
235+
}
236+
237+
impl<'a, Key: Ord, Val: Ord+'a, Val2, Tuple: Ord, Func: Fn(&Tuple)->(Key,Val)> LeapFrog<'a,Tuple,Val2> for FilterWith<'a, Key, Val, Tuple, Func> {
238+
fn seek_prefix(&mut self, tuple: &Tuple) {
239+
let key_val = (self.key_func)(tuple);
240+
self.found = self.relation.binary_search(&key_val).is_ok();
241+
}
242+
fn seek_val(&mut self, _val: &Val2) -> bool {
243+
self.found
244+
}
245+
fn peek_val(&self) -> Option<&'a Val2> {
246+
None
247+
}
248+
fn is_empty(&self) -> bool {
249+
!self.found
250+
}
251+
}
252+
}
253+
254+
mod filter_anti {
255+
256+
use super::{Relation, LeapFrog};
257+
258+
/// Wraps a Relation<Tuple> as a leaper.
259+
pub struct FilterAnti<'a, Key: Ord+'a, Val: Ord+'a, Tuple: Ord, Func: Fn(&Tuple)->(Key,Val)> {
260+
relation: &'a Relation<(Key, Val)>,
261+
key_func: Func,
262+
found: bool,
263+
phantom: ::std::marker::PhantomData<Tuple>,
264+
}
265+
266+
impl<'a, Key: Ord+'a, Val: Ord+'a, Tuple: Ord, Func: Fn(&Tuple)->(Key,Val)> FilterAnti<'a, Key, Val, Tuple, Func> {
267+
/// Constructs a ExtendWith from a relation and key and value function.
268+
pub fn from(relation: &'a Relation<(Key, Val)>, key_func: Func) -> Self {
269+
FilterAnti {
270+
relation,
271+
key_func,
272+
found: false,
273+
phantom: ::std::marker::PhantomData,
274+
}
275+
}
276+
}
277+
278+
impl<'a, Key: Ord, Val: Ord+'a, Val2, Tuple: Ord, Func: Fn(&Tuple)->(Key,Val)> LeapFrog<'a,Tuple,Val2> for FilterAnti<'a, Key, Val, Tuple, Func> {
279+
fn seek_prefix(&mut self, tuple: &Tuple) {
280+
let key_val = (self.key_func)(tuple);
281+
self.found = self.relation.binary_search(&key_val).is_ok();
282+
}
283+
fn seek_val(&mut self, _val: &Val2) -> bool {
284+
!self.found
285+
}
286+
fn peek_val(&self) -> Option<&'a Val2> {
287+
None
288+
}
289+
fn is_empty(&self) -> bool {
290+
self.found
291+
}
292+
}
293+
}
294+
295+
296+
fn gallop<T>(mut slice: &[T], mut cmp: impl FnMut(&T)->bool) -> &[T] {
297+
// if empty slice, or already >= element, return
298+
if slice.len() > 0 && cmp(&slice[0]) {
299+
let mut step = 1;
300+
while step < slice.len() && cmp(&slice[step]) {
301+
slice = &slice[step..];
302+
step = step << 1;
303+
}
304+
305+
step = step >> 1;
306+
while step > 0 {
307+
if step < slice.len() && cmp(&slice[step]) {
308+
slice = &slice[step..];
309+
}
310+
step = step >> 1;
311+
}
312+
313+
slice = &slice[1..]; // advance one, as we always stayed < value
314+
}
315+
316+
return slice;
317+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use std::cmp::Ordering;
1717

1818
mod map;
1919
mod join;
20+
pub mod leapfrog;
2021

2122
/// A static, ordered list of key-value pairs.
2223
///

0 commit comments

Comments
 (0)