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::Bounded as NumBounded;
14use num_traits::Unsigned;
15
16/// Calculates a new range covering both ranges.
17pub trait Hull<RHS = Self> {
18    type Output;
19    fn hull(&self, rhs: &RHS) -> Self::Output;
20}
21
22/// Generates a new object with lower and upper bounds.
23pub trait Range: Collection {
24    fn new(lb: Self::Item, ub: Self::Item) -> Self;
25}
26
27/// Generates the largest bound that can be represented by the type.
28pub trait Whole {
29    fn whole() -> Self;
30}
31
32/// Limits 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    type Output: Unsigned + Integer + Clone;
35
36    /// Smallest value representable by the range.
37    fn min_value() -> Self;
38    /// Largest value representable by the range.
39    fn max_value() -> Self;
40    /// The result might be infinite depending on the underlying type, for example floating types.
41    fn width(lower: &Self, upper: &Self) -> Self::Output;
42}
43
44macro_rules! unsigned_width_impl
45{
46  ( $( $t: ty ),* ) =>
47  {$(
48    impl Width for $t
49    {
50      type Output = $t;
51
52      fn max_value() -> $t {
53        <$t as NumBounded>::max_value() - 1
54      }
55
56      fn min_value() -> $t {
57        <$t as NumBounded>::min_value()
58      }
59
60      fn width(lower: &$t, upper: &$t) -> $t {
61        let lower = *lower;
62        let upper = *upper;
63        debug_assert!(upper <= <$t as Width>::max_value(),
64          "Width cannot be represented because the value exceeds the maximum value allowed.");
65        debug_assert!(lower <= upper);
66        upper - lower + 1
67      }
68    }
69  )*}
70}
71
72macro_rules! signed_width_impl
73{
74  ( $( $t: ty, $u: ty ),* ) =>
75  {$(
76    impl Width for $t
77    {
78      type Output = $u;
79
80      fn max_value() -> $t {
81        <$t as NumBounded>::max_value()
82      }
83
84      fn min_value() -> $t {
85        <$t as NumBounded>::min_value() + 1
86      }
87
88      fn width(lower: &$t, upper: &$t) -> $u {
89        let lower = *lower;
90        let upper = *upper;
91        debug_assert!(lower >= <$t as Width>::min_value(),
92          "Width cannot be represented because the value exceeds the minimum value allowed.");
93        debug_assert!(lower <= upper);
94        let size =
95          // Special case for width that could not be computed within the signed int (it could overflow).
96          if lower < 0 && upper > 0 {
97            (-lower as $u) + (upper as $u)
98          } else {
99            (upper - lower) as $u
100          };
101        size + 1
102      }
103    }
104  )*}
105}
106
107unsigned_width_impl!(u8, u16, u32, u64, usize);
108signed_width_impl!(i8, u8, i16, u16, i32, u32, i64, u64, isize, usize);
109
110#[allow(non_upper_case_globals)]
111#[cfg(test)]
112mod tests {
113    use super::*;
114    use crate::interval::*;
115    use gcollections::ops::*;
116
117    #[test]
118    fn strict_shrink_left() {
119        let empty: Interval<u32> = Interval::empty();
120        let i0_10: Interval<u32> = Interval::new(0, 10);
121        let i2_10: Interval<u32> = Interval::new(2, 10);
122
123        let ub = u32::max_value();
124        assert_eq!(i0_10.strict_shrink_left(ub), empty);
125        assert_eq!(i0_10.strict_shrink_left(10u32), empty);
126        assert_eq!(i0_10.strict_shrink_left(1u32), i2_10);
127    }
128
129    #[test]
130    fn strict_shrink_right() {
131        let empty: Interval<u32> = Interval::empty();
132        let i0_10: Interval<u32> = Interval::new(0, 10);
133        let i0_8: Interval<u32> = Interval::new(0, 8);
134
135        let lb = u32::min_value();
136        assert_eq!(i0_10.strict_shrink_right(lb), empty);
137        assert_eq!(i0_10.strict_shrink_right(0u32), empty);
138        assert_eq!(i0_10.strict_shrink_right(9u32), i0_8);
139    }
140}