1use crate::ast::{DomainOpError, domains::Int};
2use funcmap::{FuncMap, TryFuncMap};
3use num_traits::Num;
4use polyquine::Quine;
5use serde::{Deserialize, Serialize};
6use std::fmt::Display;
7
8#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, FuncMap, TryFuncMap, Quine)]
9#[path_prefix(conjure_cp::ast)]
10pub enum Range<A = Int> {
11 Single(A),
12 Bounded(A, A),
13 UnboundedL(A),
14 UnboundedR(A),
15 Unbounded,
16}
17
18impl<A> Range<A> {
19 pub fn is_lower_or_upper_bounded(&self) -> bool {
22 match &self {
23 Range::Single(_)
24 | Range::Bounded(_, _)
25 | Range::UnboundedL(_)
26 | Range::UnboundedR(_) => true,
27 Range::Unbounded => false,
28 }
29 }
30
31 pub fn is_unbounded(&self) -> bool {
33 !self.is_lower_or_upper_bounded()
34 }
35
36 pub fn is_finite(&self) -> bool {
38 match &self {
39 Range::Single(_) | Range::Bounded(_, _) => true,
40 Range::Unbounded | Range::UnboundedL(_) | Range::UnboundedR(_) => false,
41 }
42 }
43}
44
45impl<A: Ord> Range<A> {
46 pub fn contains(&self, val: &A) -> bool {
47 match self {
48 Range::Single(x) => x == val,
49 Range::Bounded(x, y) => x <= val && val <= y,
50 Range::UnboundedR(x) => x <= val,
51 Range::UnboundedL(x) => val <= x,
52 Range::Unbounded => true,
53 }
54 }
55
56 pub fn low(&self) -> Option<&A> {
58 match self {
59 Range::Single(a) => Some(a),
60 Range::Bounded(a, _) => Some(a),
61 Range::UnboundedR(a) => Some(a),
62 Range::UnboundedL(_) | Range::Unbounded => None,
63 }
64 }
65
66 pub fn high(&self) -> Option<&A> {
68 match self {
69 Range::Single(a) => Some(a),
70 Range::Bounded(_, a) => Some(a),
71 Range::UnboundedL(a) => Some(a),
72 Range::UnboundedR(_) | Range::Unbounded => None,
73 }
74 }
75}
76
77impl<A: Ord + Clone> Range<A> {
78 pub fn new(lo: Option<A>, hi: Option<A>) -> Range<A> {
80 match (lo, hi) {
81 (None, None) => Range::Unbounded,
82 (Some(l), None) => Range::UnboundedR(l),
83 (None, Some(r)) => Range::UnboundedL(r),
84 (Some(l), Some(r)) => {
85 if l == r {
86 Range::Single(l)
87 } else {
88 let min = Ord::min(&l, &r).clone();
89 let max = Ord::max(l, r);
90 Range::Bounded(min, max)
91 }
92 }
93 }
94 }
95
96 pub fn spanning(rngs: &[Range<A>]) -> Range<A> {
100 if rngs.is_empty() {
101 return Range::Unbounded;
102 }
103
104 let mut lo = rngs[0].low();
105 let mut hi = rngs[0].high();
106 for rng in rngs {
107 lo = match (lo, rng.low()) {
108 (Some(curr), Some(new)) => Some(curr.min(new)),
109 _ => None,
110 };
111 hi = match (hi, rng.high()) {
112 (Some(curr), Some(new)) => Some(curr.max(new)),
113 _ => None,
114 };
115 }
116 Range::new(lo.cloned(), hi.cloned())
117 }
118 pub fn minimal(rngs: &[Range<A>]) -> Result<Range<A>, DomainOpError> {
125 if rngs.is_empty() {
126 return Ok(Range::Unbounded);
127 }
128 let mut lo = rngs[0].low();
129 let mut hi = rngs[0].high();
130 for rng in rngs {
131 lo = match (lo, rng.low()) {
132 (Some(curr), Some(new)) => Some(curr.max(new)),
133 (None, Some(new)) => Some(new),
134 (Some(curr), None) => Some(curr),
135 _ => None,
136 };
137 hi = match (hi, rng.high()) {
138 (Some(curr), Some(new)) => Some(curr.min(new)),
139 (None, Some(new)) => Some(new),
140 (Some(curr), None) => Some(curr),
141 _ => None,
142 };
143 if let (Some(l), Some(h)) = (lo, hi)
144 && l > h
145 {
146 return Err(DomainOpError::ConflictingAttrs);
147 }
148 }
149 Ok(Range::new(lo.cloned(), hi.cloned()))
150 }
151}
152
153impl<A: Num + Ord + Clone> Range<A> {
154 pub fn length(&self) -> Option<A> {
155 match self {
156 Range::Single(_) => Some(A::one()),
157 Range::Bounded(i, j) if i > j => Some(A::zero()),
158 Range::Bounded(i, j) => Some(j.clone() - i.clone() + A::one()),
159 Range::UnboundedR(_) | Range::UnboundedL(_) | Range::Unbounded => None,
160 }
161 }
162
163 pub fn overlaps(&self, other: &Range<A>) -> bool {
170 self.low()
171 .is_none_or(|la| other.high().is_none_or(|rb| la <= rb))
172 && self
173 .high()
174 .is_none_or(|ra| other.low().is_none_or(|lb| ra >= lb))
175 }
176
177 pub fn touches_left(&self, other: &Range<A>) -> bool {
180 self.high().is_some_and(|ra| {
181 let ra = ra.clone() + A::one();
182 other.low().is_some_and(|lb| ra.eq(lb))
183 })
184 }
185
186 pub fn touches_right(&self, other: &Range<A>) -> bool {
189 self.low().is_some_and(|la| {
190 let la = la.clone() - A::one();
191 other.high().is_some_and(|rb| la.eq(rb))
192 })
193 }
194
195 pub fn joins(&self, other: &Range<A>) -> bool {
203 self.touches_left(other) || self.overlaps(other) || self.touches_right(other)
204 }
205
206 pub fn is_before(&self, other: &Range<A>) -> bool {
208 self.high()
209 .is_some_and(|ra| other.low().is_some_and(|lb| ra < &(lb.clone() - A::one())))
210 }
211
212 pub fn is_after(&self, other: &Range<A>) -> bool {
214 self.low()
215 .is_some_and(|la| other.high().is_some_and(|rb| la > &(rb.clone() + A::one())))
216 }
217
218 pub fn join(&self, other: &Range<A>) -> Option<Range<A>> {
220 if self.joins(other) {
221 let lo = Ord::min(self.low(), other.low());
222 let hi = match (self.high(), other.high()) {
223 (Some(a), Some(b)) => Some(Ord::max(a, b)),
224 _ => None,
225 };
226 return Some(Range::new(lo.cloned(), hi.cloned()));
227 }
228 None
229 }
230
231 pub fn squeeze(rngs: &[Range<A>]) -> Vec<Range<A>> {
241 let mut ans = Vec::from(rngs);
242
243 if ans.is_empty() {
244 return ans;
245 }
246
247 loop {
248 let mut merged = false;
249
250 'outer: for i in 0..ans.len() {
252 for j in (i + 1)..ans.len() {
253 if let Some(joined) = ans[i].join(&ans[j]) {
254 ans[i] = joined;
255 ans.remove(j);
257 merged = true;
258 break 'outer;
259 }
260 }
261 }
262
263 if !merged {
265 break;
266 }
267 }
268
269 ans
270 }
271
272 pub fn iter(&self) -> Option<RangeIterator<A>> {
275 match self {
276 Range::Single(val) => Some(RangeIterator::Single(Some(val.clone()))),
277 Range::Bounded(start, end) => Some(RangeIterator::Bounded {
278 current: start.clone(),
279 end: end.clone(),
280 }),
281 Range::UnboundedL(_) | Range::UnboundedR(_) | Range::Unbounded => None,
282 }
283 }
284
285 pub fn values(rngs: &[Range<A>]) -> Option<impl Iterator<Item = A>> {
287 let itrs = rngs
288 .iter()
289 .map(Range::iter)
290 .collect::<Option<Vec<RangeIterator<A>>>>()?;
291 Some(itrs.into_iter().flatten())
292 }
293
294 pub fn is_contiguous(rngs: &[Range<A>]) -> bool {
296 Self::squeeze(rngs).len() <= 1
297 }
298
299 pub fn low_of(rngs: &[Range<A>]) -> Option<&A> {
301 let mut low = rngs.first()?.low()?;
302 for rng in rngs {
303 low = Ord::min(low, rng.low()?);
304 }
305 Some(low)
306 }
307
308 pub fn high_of(rngs: &[Range<A>]) -> Option<&A> {
310 let mut hi = rngs.first()?.high()?;
311 for rng in rngs {
312 hi = Ord::min(hi, rng.low()?);
313 }
314 Some(hi)
315 }
316
317 pub fn total_length(rngs: &[Range<A>]) -> Option<A> {
320 rngs.iter()
321 .try_fold(A::zero(), |acc, r| Some(acc + r.length()?))
322 }
323}
324
325pub enum RangeIterator<A> {
327 Single(Option<A>),
328 Bounded { current: A, end: A },
329}
330
331impl<A: Num + Ord + Clone> Iterator for RangeIterator<A> {
332 type Item = A;
333
334 fn next(&mut self) -> Option<Self::Item> {
335 match self {
336 RangeIterator::Single(val) => val.take(),
337 RangeIterator::Bounded { current, end } => {
338 if current > end {
339 return None;
340 }
341
342 let result = current.clone();
343 *current = current.clone() + A::one();
344
345 Some(result)
346 }
347 }
348 }
349}
350
351impl<A: Display> Display for Range<A> {
352 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
353 match self {
354 Range::Single(i) => write!(f, "{i}"),
355 Range::Bounded(i, j) => write!(f, "{i}..{j}"),
356 Range::UnboundedR(i) => write!(f, "{i}.."),
357 Range::UnboundedL(i) => write!(f, "..{i}"),
358 Range::Unbounded => write!(f, ""),
359 }
360 }
361}
362
363#[allow(unused_imports)]
364mod test {
365 use super::*;
366 use crate::range;
367
368 #[test]
369 pub fn test_range_macros() {
370 assert_eq!(range!(1..3), Range::Bounded(1, 3));
371 assert_eq!(range!(1..), Range::UnboundedR(1));
372 assert_eq!(range!(..3), Range::UnboundedL(3));
373 assert_eq!(range!(1), Range::Single(1));
374 }
375
376 #[test]
377 pub fn test_range_low() {
378 assert_eq!(range!(1..3).low(), Some(&1));
379 assert_eq!(range!(1..).low(), Some(&1));
380 assert_eq!(range!(1).low(), Some(&1));
381 assert_eq!(range!(..3).low(), None);
382 assert_eq!(Range::<Int>::Unbounded.low(), None);
383 }
384
385 #[test]
386 pub fn test_range_high() {
387 assert_eq!(range!(1..3).high(), Some(&3));
388 assert_eq!(range!(1..).high(), None);
389 assert_eq!(range!(1).high(), Some(&1));
390 assert_eq!(range!(..3).high(), Some(&3));
391 assert_eq!(Range::<Int>::Unbounded.high(), None);
392 }
393
394 #[test]
395 pub fn test_range_is_finite() {
396 assert!(range!(1..3).is_finite());
397 assert!(range!(1).is_finite());
398 assert!(!range!(1..).is_finite());
399 assert!(!range!(..3).is_finite());
400 assert!(!Range::<Int>::Unbounded.is_finite());
401 }
402
403 #[test]
404 pub fn test_range_bounded() {
405 assert!(range!(1..3).is_lower_or_upper_bounded());
406 assert!(range!(1).is_lower_or_upper_bounded());
407 assert!(range!(1..).is_lower_or_upper_bounded());
408 assert!(range!(..3).is_lower_or_upper_bounded());
409 assert!(!Range::<Int>::Unbounded.is_lower_or_upper_bounded());
410 }
411
412 #[test]
413 pub fn test_range_length() {
414 assert_eq!(range!(1..3).length(), Some(3));
415 assert_eq!(range!(1).length(), Some(1));
416 assert_eq!(range!(1..).length(), None);
417 assert_eq!(range!(..3).length(), None);
418 assert_eq!(Range::<Int>::Unbounded.length(), None);
419 }
420
421 #[test]
422 pub fn test_range_contains_value() {
423 assert!(range!(1..3).contains(&2));
424 assert!(!range!(1..3).contains(&4));
425 assert!(range!(1).contains(&1));
426 assert!(!range!(1).contains(&2));
427 assert!(Range::Unbounded.contains(&42));
428 }
429
430 #[test]
431 pub fn test_range_overlaps() {
432 assert!(range!(1..3).overlaps(&range!(2..4)));
433 assert!(range!(1..3).overlaps(&range!(3..5)));
434 assert!(!range!(1..3).overlaps(&range!(4..6)));
435 assert!(Range::Unbounded.overlaps(&range!(1..3)));
436 }
437
438 #[test]
439 pub fn test_range_touches_left() {
440 assert!(range!(1..2).touches_left(&range!(3..4)));
441 assert!(range!(1..2).touches_left(&range!(3)));
442 assert!(range!(-5..-4).touches_left(&range!(-3..2)));
443 assert!(!range!(1..2).touches_left(&range!(4..5)));
444 assert!(!range!(1..2).touches_left(&range!(2..3)));
445 assert!(!range!(3..4).touches_left(&range!(1..2)));
446 }
447
448 #[test]
449 pub fn test_range_touches_right() {
450 assert!(range!(3..4).touches_right(&range!(1..2)));
451 assert!(range!(3).touches_right(&range!(1..2)));
452 assert!(range!(0..1).touches_right(&range!(-2..-1)));
453 assert!(!range!(1..2).touches_right(&range!(3..4)));
454 assert!(!range!(2..3).touches_right(&range!(1..2)));
455 assert!(!range!(1..2).touches_right(&range!(1..2)));
456 }
457
458 #[test]
459 pub fn test_range_is_before() {
460 assert!(range!(1..2).is_before(&range!(4..5)));
461 assert!(range!(1..2).is_before(&range!(4..)));
462 assert!(!range!(1..2).is_before(&range!(3..)));
463 assert!(!range!(1..2).is_before(&range!(..4)));
464 assert!(!range!(1..2).is_before(&range!(2..4)));
465 assert!(!range!(3..4).is_before(&range!(1..2)));
466 assert!(!range!(1..2).is_before(&Range::Unbounded));
467 }
468
469 #[test]
470 pub fn test_range_is_after() {
471 assert!(range!(5..6).is_after(&range!(1..2)));
472 assert!(range!(4..5).is_after(&range!(..2)));
473 assert!(!range!(4..5).is_after(&range!(..3)));
474 assert!(!range!(2..3).is_after(&range!(1..2)));
475 assert!(!range!(1..2).is_after(&range!(3..4)));
476 assert!(!range!(1..2).is_after(&Range::Unbounded));
477 }
478
479 #[test]
480 pub fn test_range_squeeze() {
481 let input = vec![range!(2..3), range!(4), range!(..1), range!(6..8)];
482 let squeezed = Range::squeeze(&input);
483 assert_eq!(squeezed, vec![range!(..4), range!(6..8)]);
484 }
485
486 #[test]
487 pub fn test_range_spanning() {
488 assert_eq!(Range::<Int>::spanning(&[]), Range::Unbounded);
489 assert_eq!(Range::spanning(&[range!(1..2), range!(4..5)]), range!(1..5));
490 assert_eq!(
491 Range::spanning(&[range!(..0), range!(2..4)]),
492 Range::UnboundedL(4)
493 );
494 assert_eq!(
495 Range::spanning(&[range!(0), range!(2..3), range!(5..)]),
496 Range::UnboundedR(0)
497 );
498 assert_eq!(
499 Range::spanning(&[range!(..0), range!(2..)]),
500 Range::Unbounded
501 );
502 }
503
504 #[test]
505 pub fn test_range_join() {
506 assert_eq!(range!(1..3).join(&range!(2..4)), Some(range!(1..4)));
507 assert_eq!(range!(1..3).join(&range!(3..4)), Some(range!(1..4)));
508 assert_eq!(range!(1..3).join(&range!(4..5)), Some(range!(1..5)));
509 assert_eq!(range!(..3).join(&range!(4..5)), Some(range!(..5)));
510 assert_eq!(range!(1..3).join(&range!(4..)), Some(range!(1..)));
511 assert_eq!(range!(4..).join(&range!(1..3)), Some(range!(1..)));
512 assert_eq!(range!(..3).join(&range!(4..)), Some(Range::Unbounded));
513 assert_eq!(range!(1..3).join(&range!(5..6)), None);
514 }
515}