1use oxidd_core::util::{AllocResult, Borrowed, EdgeDropGuard};
2use oxidd_core::Manager;
3
4type UnaryOp<M, R> = fn(&M, R, Borrowed<<M as Manager>::Edge>) -> AllocResult<<M as Manager>::Edge>;
5
6type BinaryOp<M, R> = fn(
7 &M,
8 R,
9 Borrowed<<M as Manager>::Edge>,
10 Borrowed<<M as Manager>::Edge>,
11) -> AllocResult<<M as Manager>::Edge>;
12
13type TernaryOp<M, R> = fn(
14 &M,
15 R,
16 Borrowed<<M as Manager>::Edge>,
17 Borrowed<<M as Manager>::Edge>,
18 Borrowed<<M as Manager>::Edge>,
19) -> AllocResult<<M as Manager>::Edge>;
20
21type SubstOp<M, R> = fn(
22 &M,
23 R,
24 Borrowed<<M as Manager>::Edge>,
25 &[<M as Manager>::Edge],
26 u32,
27) -> AllocResult<<M as Manager>::Edge>;
28
29pub trait Recursor<M: Manager>: Copy {
30 fn unary<'a>(
31 self,
32 op: UnaryOp<M, Self>,
33 manager: &'a M,
34 a: Borrowed<M::Edge>,
35 b: Borrowed<M::Edge>,
36 ) -> AllocResult<(EdgeDropGuard<'a, M>, EdgeDropGuard<'a, M>)>;
37
38 fn binary<'a>(
39 self,
40 op: BinaryOp<M, Self>,
41 manager: &'a M,
42 a: (Borrowed<M::Edge>, Borrowed<M::Edge>),
43 b: (Borrowed<M::Edge>, Borrowed<M::Edge>),
44 ) -> AllocResult<(EdgeDropGuard<'a, M>, EdgeDropGuard<'a, M>)>;
45
46 #[allow(clippy::type_complexity)]
47 fn ternary<'a>(
48 self,
49 op: TernaryOp<M, Self>,
50 manager: &'a M,
51 a: (Borrowed<M::Edge>, Borrowed<M::Edge>, Borrowed<M::Edge>),
52 b: (Borrowed<M::Edge>, Borrowed<M::Edge>, Borrowed<M::Edge>),
53 ) -> AllocResult<(EdgeDropGuard<'a, M>, EdgeDropGuard<'a, M>)>;
54
55 fn subst<'a>(
56 self,
57 op: SubstOp<M, Self>,
58 manager: &'a M,
59 a: (Borrowed<M::Edge>, &[M::Edge], u32),
60 b: (Borrowed<M::Edge>, &[M::Edge], u32),
61 ) -> AllocResult<(EdgeDropGuard<'a, M>, EdgeDropGuard<'a, M>)>;
62
63 fn should_switch_to_sequential(self) -> bool;
71}
72
73#[derive(Clone, Copy)]
74pub struct SequentialRecursor;
75
76impl<M: Manager> Recursor<M> for SequentialRecursor {
77 #[inline(always)]
78 fn unary<'a>(
79 self,
80 op: UnaryOp<M, Self>,
81 manager: &'a M,
82 a: Borrowed<M::Edge>,
83 b: Borrowed<M::Edge>,
84 ) -> AllocResult<(EdgeDropGuard<'a, M>, EdgeDropGuard<'a, M>)> {
85 let ra = EdgeDropGuard::new(manager, op(manager, self, a)?);
86 let rb = EdgeDropGuard::new(manager, op(manager, self, b)?);
87 Ok((ra, rb))
88 }
89
90 #[inline(always)]
91 fn binary<'a>(
92 self,
93 op: BinaryOp<M, Self>,
94 manager: &'a M,
95 a: (Borrowed<M::Edge>, Borrowed<M::Edge>),
96 b: (Borrowed<M::Edge>, Borrowed<M::Edge>),
97 ) -> AllocResult<(EdgeDropGuard<'a, M>, EdgeDropGuard<'a, M>)> {
98 let ra = EdgeDropGuard::new(manager, op(manager, self, a.0, a.1)?);
99 let rb = EdgeDropGuard::new(manager, op(manager, self, b.0, b.1)?);
100 Ok((ra, rb))
101 }
102
103 #[inline(always)]
104 fn ternary<'a>(
105 self,
106 op: TernaryOp<M, Self>,
107 manager: &'a M,
108 a: (Borrowed<M::Edge>, Borrowed<M::Edge>, Borrowed<M::Edge>),
109 b: (Borrowed<M::Edge>, Borrowed<M::Edge>, Borrowed<M::Edge>),
110 ) -> AllocResult<(EdgeDropGuard<'a, M>, EdgeDropGuard<'a, M>)> {
111 let ra = EdgeDropGuard::new(manager, op(manager, self, a.0, a.1, a.2)?);
112 let rb = EdgeDropGuard::new(manager, op(manager, self, b.0, b.1, b.2)?);
113 Ok((ra, rb))
114 }
115
116 #[inline(always)]
117 fn subst<'a>(
118 self,
119 op: SubstOp<M, Self>,
120 manager: &'a M,
121 a: (Borrowed<M::Edge>, &[M::Edge], u32),
122 b: (Borrowed<M::Edge>, &[M::Edge], u32),
123 ) -> AllocResult<(EdgeDropGuard<'a, M>, EdgeDropGuard<'a, M>)> {
124 let ra = EdgeDropGuard::new(manager, op(manager, self, a.0, a.1, a.2)?);
125 let rb = EdgeDropGuard::new(manager, op(manager, self, b.0, b.1, a.2)?);
126 Ok((ra, rb))
127 }
128
129 #[inline(always)]
130 fn should_switch_to_sequential(self) -> bool {
131 false }
133}
134
135#[cfg(feature = "multi-threading")]
136pub mod mt {
137 use super::*;
138 use oxidd_core::WorkerPool;
139
140 #[derive(Clone, Copy)]
141 pub struct ParallelRecursor {
142 remaining_depth: u32,
143 }
144
145 impl ParallelRecursor {
146 pub fn new<M: oxidd_core::HasWorkers>(manager: &M) -> Self {
147 Self {
148 remaining_depth: manager.workers().split_depth(),
149 }
150 }
151 }
152
153 impl<M> Recursor<M> for ParallelRecursor
154 where
155 M: Manager + oxidd_core::HasWorkers,
156 M::Edge: Send + Sync,
157 {
158 fn unary<'a>(
159 mut self,
160 op: UnaryOp<M, Self>,
161 manager: &'a M,
162 a: Borrowed<M::Edge>,
163 b: Borrowed<M::Edge>,
164 ) -> AllocResult<(EdgeDropGuard<'a, M>, EdgeDropGuard<'a, M>)> {
165 self.remaining_depth -= 1;
166 let (ra, rb) = manager.workers().join(
167 move || {
168 let edge = op(manager, self, a)?;
169 Ok(EdgeDropGuard::new(manager, edge))
170 },
171 move || {
172 let edge = op(manager, self, b)?;
173 Ok(EdgeDropGuard::new(manager, edge))
174 },
175 );
176 Ok((ra?, rb?))
177 }
178
179 fn binary<'a>(
180 mut self,
181 op: BinaryOp<M, Self>,
182 manager: &'a M,
183 a: (Borrowed<M::Edge>, Borrowed<M::Edge>),
184 b: (Borrowed<M::Edge>, Borrowed<M::Edge>),
185 ) -> AllocResult<(EdgeDropGuard<'a, M>, EdgeDropGuard<'a, M>)> {
186 self.remaining_depth -= 1;
187 let (ra, rb) = manager.workers().join(
188 move || {
189 let edge = op(manager, self, a.0, a.1)?;
190 Ok(EdgeDropGuard::new(manager, edge))
191 },
192 move || {
193 let edge = op(manager, self, b.0, b.1)?;
194 Ok(EdgeDropGuard::new(manager, edge))
195 },
196 );
197 Ok((ra?, rb?))
198 }
199
200 fn ternary<'a>(
201 mut self,
202 op: TernaryOp<M, Self>,
203 manager: &'a M,
204 a: (Borrowed<M::Edge>, Borrowed<M::Edge>, Borrowed<M::Edge>),
205 b: (Borrowed<M::Edge>, Borrowed<M::Edge>, Borrowed<M::Edge>),
206 ) -> AllocResult<(EdgeDropGuard<'a, M>, EdgeDropGuard<'a, M>)> {
207 self.remaining_depth -= 1;
208 let (ra, rb) = manager.workers().join(
209 move || {
210 let edge = op(manager, self, a.0, a.1, a.2)?;
211 Ok(EdgeDropGuard::new(manager, edge))
212 },
213 move || {
214 let edge = op(manager, self, b.0, b.1, b.2)?;
215 Ok(EdgeDropGuard::new(manager, edge))
216 },
217 );
218 Ok((ra?, rb?))
219 }
220
221 fn subst<'a>(
222 mut self,
223 op: SubstOp<M, Self>,
224 manager: &'a M,
225 a: (Borrowed<M::Edge>, &[M::Edge], u32),
226 b: (Borrowed<M::Edge>, &[M::Edge], u32),
227 ) -> AllocResult<(EdgeDropGuard<'a, M>, EdgeDropGuard<'a, M>)> {
228 self.remaining_depth -= 1;
229 let (ra, rb) = manager.workers().join(
230 move || {
231 let edge = op(manager, self, a.0, a.1, a.2)?;
232 Ok(EdgeDropGuard::new(manager, edge))
233 },
234 move || {
235 let edge = op(manager, self, b.0, b.1, b.2)?;
236 Ok(EdgeDropGuard::new(manager, edge))
237 },
238 );
239 Ok((ra?, rb?))
240 }
241
242 #[inline(always)]
243 fn should_switch_to_sequential(self) -> bool {
244 self.remaining_depth == 0
245 }
246 }
247}