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