Skip to main content

fixed_bigint/fixeduint/
multiple_impl.rs

1// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Multiple-of operations for FixedUInt.
16
17use super::{FixedUInt, MachineWord};
18use crate::const_numtraits::{ConstCheckedAdd, ConstMultiple, ConstZero};
19use crate::machineword::ConstMachineWord;
20use crate::personality::Nct;
21
22c0nst::c0nst! {
23    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst ConstMultiple for FixedUInt<T, N, Nct> {
24        fn is_multiple_of(&self, rhs: &Self) -> bool {
25            if rhs.is_zero() {
26                false
27            } else {
28                (*self % *rhs).is_zero()
29            }
30        }
31
32        fn next_multiple_of(self, rhs: Self) -> Self {
33            match self.checked_next_multiple_of(rhs) {
34                Some(v) => v,
35                None => panic!("next_multiple_of: rhs is zero or result overflows"),
36            }
37        }
38
39        fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
40            if rhs.is_zero() {
41                return None;
42            }
43            let rem = self % rhs;
44            if rem.is_zero() {
45                Some(self)
46            } else {
47                // self + (rhs - rem)
48                let add = rhs - rem;
49                ConstCheckedAdd::checked_add(&self, &add)
50            }
51        }
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58
59    #[test]
60    fn test_is_multiple_of() {
61        type U16 = FixedUInt<u8, 2>;
62
63        assert!(ConstMultiple::is_multiple_of(
64            &U16::from(0u8),
65            &U16::from(5u8)
66        ));
67        assert!(ConstMultiple::is_multiple_of(
68            &U16::from(10u8),
69            &U16::from(5u8)
70        ));
71        assert!(ConstMultiple::is_multiple_of(
72            &U16::from(15u8),
73            &U16::from(5u8)
74        ));
75        assert!(!ConstMultiple::is_multiple_of(
76            &U16::from(11u8),
77            &U16::from(5u8)
78        ));
79        assert!(ConstMultiple::is_multiple_of(
80            &U16::from(100u8),
81            &U16::from(10u8)
82        ));
83        assert!(!ConstMultiple::is_multiple_of(
84            &U16::from(101u8),
85            &U16::from(10u8)
86        ));
87
88        // rhs == 0 returns false
89        assert!(!ConstMultiple::is_multiple_of(
90            &U16::from(10u8),
91            &U16::from(0u8)
92        ));
93    }
94
95    #[test]
96    fn test_next_multiple_of() {
97        type U16 = FixedUInt<u8, 2>;
98
99        // Already a multiple
100        assert_eq!(
101            ConstMultiple::next_multiple_of(U16::from(10u8), U16::from(5u8)),
102            U16::from(10u8)
103        );
104        assert_eq!(
105            ConstMultiple::next_multiple_of(U16::from(0u8), U16::from(5u8)),
106            U16::from(0u8)
107        );
108
109        // Not a multiple
110        assert_eq!(
111            ConstMultiple::next_multiple_of(U16::from(11u8), U16::from(5u8)),
112            U16::from(15u8)
113        );
114        assert_eq!(
115            ConstMultiple::next_multiple_of(U16::from(12u8), U16::from(5u8)),
116            U16::from(15u8)
117        );
118        assert_eq!(
119            ConstMultiple::next_multiple_of(U16::from(14u8), U16::from(5u8)),
120            U16::from(15u8)
121        );
122
123        // Larger values
124        assert_eq!(
125            ConstMultiple::next_multiple_of(U16::from(101u8), U16::from(10u8)),
126            U16::from(110u8)
127        );
128    }
129
130    #[test]
131    fn test_checked_next_multiple_of() {
132        type U16 = FixedUInt<u8, 2>;
133
134        // Normal cases
135        assert_eq!(
136            ConstMultiple::checked_next_multiple_of(U16::from(11u8), U16::from(5u8)),
137            Some(U16::from(15u8))
138        );
139
140        // rhs == 0
141        assert_eq!(
142            ConstMultiple::checked_next_multiple_of(U16::from(10u8), U16::from(0u8)),
143            None
144        );
145
146        // Already a multiple (no overflow)
147        let large = U16::from(65530u16);
148        assert_eq!(
149            ConstMultiple::checked_next_multiple_of(large, U16::from(10u8)),
150            Some(large)
151        ); // 65530 % 10 = 0, so returns itself
152
153        // Overflow case
154        let large2 = U16::from(65531u16);
155        assert_eq!(
156            ConstMultiple::checked_next_multiple_of(large2, U16::from(10u8)),
157            None
158        ); // 65531 + 9 = 65540 > 65535, overflow
159    }
160
161    c0nst::c0nst! {
162        pub c0nst fn const_is_multiple_of<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
163            a: &FixedUInt<T, N, Nct>,
164            b: &FixedUInt<T, N, Nct>,
165        ) -> bool {
166            ConstMultiple::is_multiple_of(a, b)
167        }
168
169        pub c0nst fn const_next_multiple_of<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
170            a: FixedUInt<T, N, Nct>,
171            b: FixedUInt<T, N, Nct>,
172        ) -> FixedUInt<T, N, Nct> {
173            ConstMultiple::next_multiple_of(a, b)
174        }
175    }
176
177    #[test]
178    fn test_const_multiple() {
179        type U16 = FixedUInt<u8, 2>;
180
181        assert!(const_is_multiple_of(&U16::from(10u8), &U16::from(5u8)));
182        assert_eq!(
183            const_next_multiple_of(U16::from(11u8), U16::from(5u8)),
184            U16::from(15u8)
185        );
186
187        #[cfg(feature = "nightly")]
188        {
189            const TEN: U16 = FixedUInt::from_array([10, 0]);
190            const FIVE: U16 = FixedUInt::from_array([5, 0]);
191            const IS_MULT: bool = const_is_multiple_of(&TEN, &FIVE);
192            assert!(IS_MULT);
193
194            const ELEVEN: U16 = FixedUInt::from_array([11, 0]);
195            const NEXT: U16 = const_next_multiple_of(ELEVEN, FIVE);
196            assert_eq!(NEXT, FixedUInt::from_array([15, 0]));
197        }
198    }
199}