interval/
ops.rs

1// Copyright 2015 Pierre Talbot (IRCAM)
2
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! Interval and bound specific operations.
10
11use gcollections::kind::*;
12use num_integer::Integer;
13use num_traits::{Unsigned};
14use num_traits::Bounded as NumBounded;
15
16pub trait Hull<RHS = Self>
17{
18  type Output;
19  fn hull(&self, rhs: &RHS) -> Self::Output;
20}
21
22pub trait Range : Collection
23{
24  fn new(lb: Self::Item, ub: Self::Item) -> Self;
25}
26
27pub trait Whole
28{
29  fn whole() -> Self;
30}
31
32/// Limit of a bound for which the distance between `min_value()` and `max_value()` can be represented in the type `Output`.
33pub trait Width : Ord + Clone
34{
35  type Output: Unsigned + Integer + Clone;
36
37  fn max_value() -> Self;
38  fn min_value() -> Self;
39  /// The result might be infinite depending on the underlying type (think about floating types).
40  fn width(lower: &Self, upper: &Self) -> Self::Output;
41}
42
43macro_rules! unsigned_width_impl
44{
45  ( $( $t: ty ),* ) =>
46  {$(
47    impl Width for $t
48    {
49      type Output = $t;
50
51      fn max_value() -> $t {
52        <$t as NumBounded>::max_value() - 1
53      }
54
55      fn min_value() -> $t {
56        <$t as NumBounded>::min_value()
57      }
58
59      fn width(lower: &$t, upper: &$t) -> $t {
60        let lower = *lower;
61        let upper = *upper;
62        debug_assert!(upper <= <$t as Width>::max_value(),
63          "Width cannot be represented because the value exceeds the maximum value allowed.");
64        debug_assert!(lower <= upper);
65        upper - lower + 1
66      }
67    }
68  )*}
69}
70
71macro_rules! signed_width_impl
72{
73  ( $( $t: ty, $u: ty ),* ) =>
74  {$(
75    impl Width for $t
76    {
77      type Output = $u;
78
79      fn max_value() -> $t {
80        <$t as NumBounded>::max_value()
81      }
82
83      fn min_value() -> $t {
84        <$t as NumBounded>::min_value() + 1
85      }
86
87      fn width(lower: &$t, upper: &$t) -> $u {
88        let lower = *lower;
89        let upper = *upper;
90        debug_assert!(lower >= <$t as Width>::min_value(),
91          "Width cannot be represented because the value exceeds the minimum value allowed.");
92        debug_assert!(lower <= upper);
93        let size =
94          // Special case for width that could not be computed within the signed int (it could overflow).
95          if lower < 0 && upper > 0 {
96            (-lower as $u) + (upper as $u)
97          } else {
98            (upper - lower) as $u
99          };
100        size + 1
101      }
102    }
103  )*}
104}
105
106unsigned_width_impl!(u8,u16,u32,u64,usize);
107signed_width_impl!(i8,u8,i16,u16,i32,u32,i64,u64,isize,usize);
108
109#[allow(non_upper_case_globals)]
110#[cfg(test)]
111mod tests {
112  use super::*;
113  use gcollections::ops::*;
114  use crate::interval::*;
115
116  #[test]
117  fn strict_shrink_left() {
118    let empty: Interval<u32> = Interval::empty();
119    let i0_10: Interval<u32> = Interval::new(0, 10);
120    let i2_10: Interval<u32> = Interval::new(2, 10);
121
122    let ub = u32::max_value();
123    assert_eq!(i0_10.strict_shrink_left(ub), empty);
124    assert_eq!(i0_10.strict_shrink_left(10u32), empty);
125    assert_eq!(i0_10.strict_shrink_left(1u32), i2_10);
126  }
127
128  #[test]
129  fn strict_shrink_right() {
130    let empty: Interval<u32> = Interval::empty();
131    let i0_10: Interval<u32> = Interval::new(0, 10);
132    let i0_8: Interval<u32> = Interval::new(0, 8);
133
134    let lb = u32::min_value();
135    assert_eq!(i0_10.strict_shrink_right(lb), empty);
136    assert_eq!(i0_10.strict_shrink_right(0u32), empty);
137    assert_eq!(i0_10.strict_shrink_right(9u32), i0_8);
138  }
139}