Skip to content

Commit 3ff4ad0

Browse files
Allow Relation<T> to be joined with Variable<(T, S)>
This case occurred in `Polonius`, where we had to create a separate `Relation<(T, ())>` to make things work. Implementing this required a change to the interface of `JoinInput`, since we are not allowed to assume that a `Relation<T>` and a `Relation<(T, ())>` are layout compatible. Now, `stable` takes a callback instead of returning a slice directly.
1 parent 5bda2f0 commit 3ff4ad0

File tree

1 file changed

+33
-17
lines changed

1 file changed

+33
-17
lines changed

src/join.rs

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ pub(crate) fn join_into<'me, Key: Ord, Val1: Ord, Val2: Ord, Result: Ord>(
2525

2626
let mut closure = |k: &Key, v1: &Val1, v2: &Val2| results.push(logic(k, v1, v2));
2727

28-
for batch2 in input2.stable().iter() {
28+
input2.for_each_stable_set(|batch2| {
2929
join_helper(&recent1, &batch2, &mut closure);
30-
}
30+
});
3131

32-
for batch1 in input1.stable().iter() {
32+
input1.for_each_stable_set(|batch1| {
3333
join_helper(&batch1, &recent2, &mut closure);
34-
}
34+
});
3535

3636
join_helper(&recent1, &recent2, &mut closure);
3737
}
@@ -141,40 +141,56 @@ pub trait JoinInput<'me, Tuple: Ord>: Copy {
141141
/// empty slice.)
142142
type RecentTuples: Deref<Target = [Tuple]>;
143143

144-
/// If we are on iteration N of the loop, these are the tuples
145-
/// added on iteration N - 2 or before. (For a `Relation`, this is
146-
/// just `self`.)
147-
type StableTuples: Deref<Target = [Relation<Tuple>]>;
148-
149144
/// Get the set of recent tuples.
150145
fn recent(self) -> Self::RecentTuples;
151146

152-
/// Get the set of stable tuples.
153-
fn stable(self) -> Self::StableTuples;
147+
/// Call a function for each set of stable tuples.
148+
fn for_each_stable_set(self, f: impl FnMut(&[Tuple]));
154149
}
155150

156151
impl<'me, Tuple: Ord> JoinInput<'me, Tuple> for &'me Variable<Tuple> {
157152
type RecentTuples = Ref<'me, [Tuple]>;
158-
type StableTuples = Ref<'me, [Relation<Tuple>]>;
159153

160154
fn recent(self) -> Self::RecentTuples {
161155
Ref::map(self.recent.borrow(), |r| &r.elements[..])
162156
}
163157

164-
fn stable(self) -> Self::StableTuples {
165-
Ref::map(self.stable.borrow(), |v| &v[..])
158+
fn for_each_stable_set(self, mut f: impl FnMut(&[Tuple])) {
159+
for stable in self.stable.borrow().iter() {
160+
f(stable)
161+
}
166162
}
167163
}
168164

169165
impl<'me, Tuple: Ord> JoinInput<'me, Tuple> for &'me Relation<Tuple> {
170166
type RecentTuples = &'me [Tuple];
171-
type StableTuples = &'me [Relation<Tuple>];
172167

173168
fn recent(self) -> Self::RecentTuples {
174169
&[]
175170
}
176171

177-
fn stable(self) -> Self::StableTuples {
178-
std::slice::from_ref(self)
172+
fn for_each_stable_set(self, mut f: impl FnMut(&[Tuple])) {
173+
f(&self.elements)
174+
}
175+
}
176+
177+
impl<'me, Tuple: Ord> JoinInput<'me, (Tuple, ())> for &'me Relation<Tuple> {
178+
type RecentTuples = &'me [(Tuple, ())];
179+
180+
fn recent(self) -> Self::RecentTuples {
181+
&[]
182+
}
183+
184+
fn for_each_stable_set(self, mut f: impl FnMut(&[(Tuple, ())])) {
185+
use std::mem;
186+
assert_eq!(mem::size_of::<(Tuple, ())>(), mem::size_of::<Tuple>());
187+
assert_eq!(mem::align_of::<(Tuple, ())>(), mem::align_of::<Tuple>());
188+
189+
// SAFETY: https://rust-lang.github.io/unsafe-code-guidelines/layout/structs-and-tuples.html#structs-with-1-zst-fields
190+
// guarantees that `T` is layout compatible with `(T, ())`, since `()` is a 1-ZST.
191+
let elements: &'me [Tuple] = self.elements.as_slice();
192+
let elements: &'me [(Tuple, ())] = unsafe { std::mem::transmute(elements) };
193+
194+
f(elements)
179195
}
180196
}

0 commit comments

Comments
 (0)