malachite_base/unions/exhaustive.rs
1// Copyright © 2025 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::unions::Union2;
10
11/// Defines exhaustive union generators.
12///
13/// Malachite provides [`lex_union2s`] and [`exhaustive_union2s`], but you can also define
14/// `lex_union3s`, `lex_union4s`, and so on, and `exhaustive_union3s`, `exhaustive_union4s`, and so
15/// on, in your program using the code below. The documentation for [`lex_union2s`] and
16/// [`exhaustive_union2s`] describes these other functions as well.
17///
18/// See usage examples [here](self#lex_union2s) and [here](self#exhaustive_union2s).
19///
20/// ```
21/// use malachite_base::unions::UnionFromStrError;
22/// use malachite_base::{exhaustive_unions, union_struct};
23/// use std::fmt::{self, Display, Formatter};
24/// use std::str::FromStr;
25///
26/// union_struct!(
27/// (pub(crate)),
28/// Union3,
29/// Union3<T, T, T>,
30/// [A, A, 'A', a],
31/// [B, B, 'B', b],
32/// [C, C, 'C', c]
33/// );
34/// union_struct!(
35/// (pub(crate)),
36/// Union4,
37/// Union4<T, T, T, T>,
38/// [A, A, 'A', a],
39/// [B, B, 'B', b],
40/// [C, C, 'C', c],
41/// [D, D, 'D', d]
42/// );
43/// union_struct!(
44/// (pub(crate)),
45/// Union5,
46/// Union5<T, T, T, T, T>,
47/// [A, A, 'A', a],
48/// [B, B, 'B', b],
49/// [C, C, 'C', c],
50/// [D, D, 'D', d],
51/// [E, E, 'E', e]
52/// );
53/// union_struct!(
54/// (pub(crate)),
55/// Union6,
56/// Union6<T, T, T, T, T, T>,
57/// [A, A, 'A', a],
58/// [B, B, 'B', b],
59/// [C, C, 'C', c],
60/// [D, D, 'D', d],
61/// [E, E, 'E', e],
62/// [F, F, 'F', f]
63/// );
64/// union_struct!(
65/// (pub(crate)),
66/// Union7,
67/// Union7<T, T, T, T, T, T, T>,
68/// [A, A, 'A', a],
69/// [B, B, 'B', b],
70/// [C, C, 'C', c],
71/// [D, D, 'D', d],
72/// [E, E, 'E', e],
73/// [F, F, 'F', f],
74/// [G, G, 'G', g]
75/// );
76/// union_struct!(
77/// (pub(crate)),
78/// Union8,
79/// Union8<T, T, T, T, T, T, T, T>,
80/// [A, A, 'A', a],
81/// [B, B, 'B', b],
82/// [C, C, 'C', c],
83/// [D, D, 'D', d],
84/// [E, E, 'E', e],
85/// [F, F, 'F', f],
86/// [G, G, 'G', g],
87/// [H, H, 'H', h]
88/// );
89///
90/// exhaustive_unions!(
91/// (pub(crate)),
92/// Union3,
93/// LexUnion3s,
94/// ExhaustiveUnion3s,
95/// lex_union3s,
96/// exhaustive_union3s,
97/// 3,
98/// [0, X, I, A, xs, xs_done],
99/// [1, Y, J, B, ys, ys_done],
100/// [2, Z, K, C, zs, zs_done]
101/// );
102/// exhaustive_unions!(
103/// (pub(crate)),
104/// Union4,
105/// LexUnion4s,
106/// ExhaustiveUnion4s,
107/// lex_union4s,
108/// exhaustive_union4s,
109/// 4,
110/// [0, X, I, A, xs, xs_done],
111/// [1, Y, J, B, ys, ys_done],
112/// [2, Z, K, C, zs, zs_done],
113/// [3, W, L, D, ws, ws_done]
114/// );
115/// exhaustive_unions!(
116/// (pub(crate)),
117/// Union5,
118/// LexUnion5s,
119/// ExhaustiveUnion5s,
120/// lex_union5s,
121/// exhaustive_union5s,
122/// 5,
123/// [0, X, I, A, xs, xs_done],
124/// [1, Y, J, B, ys, ys_done],
125/// [2, Z, K, C, zs, zs_done],
126/// [3, W, L, D, ws, ws_done],
127/// [4, V, M, E, vs, vs_done]
128/// );
129/// exhaustive_unions!(
130/// (pub(crate)),
131/// Union6,
132/// LexUnion6s,
133/// ExhaustiveUnion6s,
134/// lex_union6s,
135/// exhaustive_union6s,
136/// 6,
137/// [0, X, I, A, xs, xs_done],
138/// [1, Y, J, B, ys, ys_done],
139/// [2, Z, K, C, zs, zs_done],
140/// [3, W, L, D, ws, ws_done],
141/// [4, V, M, E, vs, vs_done],
142/// [5, U, N, F, us, us_done]
143/// );
144/// exhaustive_unions!(
145/// (pub(crate)),
146/// Union7,
147/// LexUnion7s,
148/// ExhaustiveUnion7s,
149/// lex_union7s,
150/// exhaustive_union7s,
151/// 7,
152/// [0, X, I, A, xs, xs_done],
153/// [1, Y, J, B, ys, ys_done],
154/// [2, Z, K, C, zs, zs_done],
155/// [3, W, L, D, ws, ws_done],
156/// [4, V, M, E, vs, vs_done],
157/// [5, U, N, F, us, us_done],
158/// [6, T, O, G, ts, ts_done]
159/// );
160/// exhaustive_unions!(
161/// (pub(crate)),
162/// Union8,
163/// LexUnion8s,
164/// ExhaustiveUnion8s,
165/// lex_union8s,
166/// exhaustive_union8s,
167/// 8,
168/// [0, X, I, A, xs, xs_done],
169/// [1, Y, J, B, ys, ys_done],
170/// [2, Z, K, C, zs, zs_done],
171/// [3, W, L, D, ws, ws_done],
172/// [4, V, M, E, vs, vs_done],
173/// [5, U, N, F, us, us_done],
174/// [6, T, O, G, ts, ts_done],
175/// [7, S, P, H, ss, ss_done]
176/// );
177/// ```
178#[macro_export]
179macro_rules! exhaustive_unions {
180 (
181 ($($vis:tt)*),
182 $union: ident,
183 $lex_struct: ident,
184 $exhaustive_struct: ident,
185 $lex_fn: ident,
186 $exhaustive_fn: ident,
187 $n: expr,
188 $([$i: expr, $t: ident, $it: ident, $variant: ident, $xs: ident, $xs_done:ident]),*
189 ) => {
190 /// This documentation applies not only to `LexUnion2s`, but also to `LexUnion3s`,
191 /// `LexUnion4s`, and so on. See [`exhaustive_unions`] for more information.
192 ///
193 /// Generates all $n$-unions with elements from $n$ iterators, in lexicographic order.
194 ///
195 /// The order is lexicographic with respect to the order of the element iterators. All of
196 /// the first variant's elements are generated first, followed by the second variant's
197 /// elements, and so on.
198 #[allow(dead_code)]
199 #[derive(Clone, Debug)]
200 $($vis)* struct $lex_struct<$($t, $it: Iterator<Item=$t>),*> {
201 i: u64,
202 $($xs: $it,)*
203 }
204
205 impl<$($t, $it: Iterator<Item=$t>),*> Iterator for $lex_struct<$($t, $it),*> {
206 type Item = $union<$($t),*>;
207
208 fn next(&mut self) -> Option<Self::Item> {
209 loop {
210 match self.i {
211 $(
212 $i => {
213 let next = self.$xs.next().map($union::$variant);
214 if next.is_some() {
215 return next;
216 }
217 },
218 )*
219 _ => return None,
220 }
221 self.i += 1;
222 }
223 }
224 }
225
226 /// This documentation applies not only to `lex_union2s`, but also to `lex_union3s`,
227 /// `lex_union4s`, and so on. See [`exhaustive_unions`] for more information.
228 ///
229 /// Generates all $n$-unions with elements from $n$ iterators, in lexicographic order.
230 ///
231 /// The order is lexicographic with respect to the order of the element iterators. All of
232 /// the first variant's elements are generated first, followed by the second variant's
233 /// elements, and so on. This means that all of the iterators, except possibly the last one,
234 /// must be finite. For functions that support multiple infinite element iterators, try
235 /// `exhaustive_union[n]s`.
236 ///
237 /// If the last iterator is finite, the output length is the sum of the lengths of all the
238 /// input iterators. If the last iterator is infinite, the output is also infinite.
239 ///
240 /// If all of the input iterators are empty, the output is also empty.
241 ///
242 /// # Examples
243 /// See [here](self#lex_union2s).
244 #[allow(dead_code)]
245 #[inline]
246 $($vis)* const fn $lex_fn<$($t, $it: Iterator<Item=$t>),*>($($xs: $it),*) ->
247 $lex_struct<$($t, $it),*> {
248 $lex_struct {
249 i: 0,
250 $($xs,)*
251 }
252 }
253
254 /// This documentation applies not only to `ExhaustiveUnion2s`, but also to
255 /// `ExhaustiveUnion3s`, `ExhaustiveUnion4s`, and so on. See [`exhaustive_unions`] for more
256 /// information.
257 ///
258 /// Generates all $n$-unions with elements from $n$ iterators.
259 #[allow(dead_code)]
260 #[derive(Clone, Debug)]
261 $($vis)* struct $exhaustive_struct<$($t, $it: Iterator<Item=$t>),*> {
262 done: bool,
263 i: u64,
264 $(
265 $xs: $it,
266 $xs_done: bool,
267 )*
268 }
269
270 impl<$($t, $it: Iterator<Item=$t>),*> Iterator for $exhaustive_struct<$($t, $it),*> {
271 type Item = $union<$($t),*>;
272
273 fn next(&mut self) -> Option<Self::Item> {
274 if self.done {
275 None
276 } else {
277 let original_i = self.i;
278 loop {
279 let mut next = None;
280 match self.i {
281 $(
282 $i => if !self.$xs_done {
283 next = self.$xs.next().map($union::$variant);
284 self.$xs_done = next.is_none();
285 },
286 )*
287 _ => unreachable!(),
288 }
289 self.i += 1;
290 if self.i == $n {
291 self.i = 0;
292 }
293 if next.is_some() {
294 return next;
295 }
296 if self.i == original_i {
297 self.done = true;
298 return None;
299 }
300 }
301 }
302 }
303 }
304
305 /// This documentation applies not only to `exhaustive_union2s`, but also to
306 /// `exhaustive_union3s`, `exhaustive_union4s`, and so on. See [`exhaustive_unions`] for
307 /// more information.
308 ///
309 /// Generates all $n$-unions with elements from $n$ iterators.
310 ///
311 /// The input iterators are advanced in a round-robin fashion. First an element from the
312 /// first variant's iterator is selected, followed by an element from the second variant's
313 /// iterator, and so on until an element has been selected from each iterator. Then another
314 /// element from the first iterator is selected, etc. Iterators that have been exhausted are
315 /// skipped. [`exhaustive_union2s`] behaves just like
316 /// [`Itertools::interleave`]([`itertools::Itertools::interleave`]).
317 ///
318 /// If all input iterators are finite, the output length is the sum of the lengths of the
319 /// iterators. If any iterator is infinite, the output is also infinite.
320 ///
321 /// If all of the input iterators are empty, the output is also empty.
322 ///
323 /// # Examples
324 /// See [here](self#exhaustive_union2s).
325 #[allow(dead_code)]
326 #[inline]
327 $($vis)* const fn $exhaustive_fn<$($t, $it: Iterator<Item=$t>),*>($($xs: $it),*) ->
328 $exhaustive_struct<$($t, $it),*> {
329 $exhaustive_struct {
330 done: false,
331 i: 0,
332 $(
333 $xs,
334 $xs_done: false,
335 )*
336 }
337 }
338 }
339}
340
341exhaustive_unions!(
342 (pub),
343 Union2,
344 LexUnion2s,
345 ExhaustiveUnion2s,
346 lex_union2s,
347 exhaustive_union2s,
348 2,
349 [0, X, I, A, xs, xs_done],
350 [1, Y, J, B, ys, ys_done]
351);