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::machineword::ConstMachineWord;
19use const_num_traits::Nct;
20use const_num_traits::{CheckedAdd, MultipleOf, NextMultipleOf, Zero};
21
22c0nst::c0nst! {
23    c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> MultipleOf for FixedUInt<T, N, Nct> {
24        fn is_multiple_of(self, rhs: Self) -> bool {
25            if <Self as Zero>::is_zero(&rhs) {
26                false
27            } else {
28                <Self as Zero>::is_zero(&(self % rhs))
29            }
30        }
31    }
32
33    c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> NextMultipleOf for FixedUInt<T, N, Nct> {
34        type Output = FixedUInt<T, N, Nct>;
35        fn next_multiple_of(self, rhs: Self) -> Self {
36            match self.checked_next_multiple_of(rhs) {
37                Some(v) => v,
38                None => panic!("next_multiple_of: rhs is zero or result overflows"),
39            }
40        }
41
42        fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
43            if rhs.is_zero() {
44                return None;
45            }
46            let rem = self % rhs;
47            if rem.is_zero() {
48                Some(self)
49            } else {
50                // self + (rhs - rem)
51                let add = rhs - rem;
52                CheckedAdd::checked_add(self, add)
53            }
54        }
55    }
56
57    c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> MultipleOf for &FixedUInt<T, N, Nct> {
58        fn is_multiple_of(self, rhs: Self) -> bool {
59            <FixedUInt<T, N, Nct> as MultipleOf>::is_multiple_of(FixedUInt::from_array(self.array), FixedUInt::from_array(rhs.array))
60        }
61    }
62
63    c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> NextMultipleOf for &FixedUInt<T, N, Nct> {
64        type Output = FixedUInt<T, N, Nct>;
65        fn next_multiple_of(self, rhs: Self) -> FixedUInt<T, N, Nct> {
66            <FixedUInt<T, N, Nct> as NextMultipleOf>::next_multiple_of(FixedUInt::from_array(self.array), FixedUInt::from_array(rhs.array))
67        }
68        fn checked_next_multiple_of(self, rhs: Self) -> Option<FixedUInt<T, N, Nct>> {
69            <FixedUInt<T, N, Nct> as NextMultipleOf>::checked_next_multiple_of(FixedUInt::from_array(self.array), FixedUInt::from_array(rhs.array))
70        }
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77
78    #[test]
79    fn test_is_multiple_of() {
80        type U16 = FixedUInt<u8, 2>;
81
82        assert!(MultipleOf::is_multiple_of(U16::from(0u8), U16::from(5u8)));
83        assert!(MultipleOf::is_multiple_of(U16::from(10u8), U16::from(5u8)));
84        assert!(MultipleOf::is_multiple_of(U16::from(15u8), U16::from(5u8)));
85        assert!(!MultipleOf::is_multiple_of(U16::from(11u8), U16::from(5u8)));
86        assert!(MultipleOf::is_multiple_of(
87            U16::from(100u8),
88            U16::from(10u8)
89        ));
90        assert!(!MultipleOf::is_multiple_of(
91            U16::from(101u8),
92            U16::from(10u8)
93        ));
94
95        // rhs == 0 returns false
96        assert!(!MultipleOf::is_multiple_of(U16::from(10u8), U16::from(0u8)));
97    }
98
99    #[test]
100    fn test_next_multiple_of() {
101        type U16 = FixedUInt<u8, 2>;
102
103        // Already a multiple
104        assert_eq!(
105            NextMultipleOf::next_multiple_of(U16::from(10u8), U16::from(5u8)),
106            U16::from(10u8)
107        );
108        assert_eq!(
109            NextMultipleOf::next_multiple_of(U16::from(0u8), U16::from(5u8)),
110            U16::from(0u8)
111        );
112
113        // Not a multiple
114        assert_eq!(
115            NextMultipleOf::next_multiple_of(U16::from(11u8), U16::from(5u8)),
116            U16::from(15u8)
117        );
118        assert_eq!(
119            NextMultipleOf::next_multiple_of(U16::from(12u8), U16::from(5u8)),
120            U16::from(15u8)
121        );
122        assert_eq!(
123            NextMultipleOf::next_multiple_of(U16::from(14u8), U16::from(5u8)),
124            U16::from(15u8)
125        );
126
127        // Larger values
128        assert_eq!(
129            NextMultipleOf::next_multiple_of(U16::from(101u8), U16::from(10u8)),
130            U16::from(110u8)
131        );
132    }
133
134    #[test]
135    fn test_checked_next_multiple_of() {
136        type U16 = FixedUInt<u8, 2>;
137
138        // Normal cases
139        assert_eq!(
140            NextMultipleOf::checked_next_multiple_of(U16::from(11u8), U16::from(5u8)),
141            Some(U16::from(15u8))
142        );
143
144        // rhs == 0
145        assert_eq!(
146            NextMultipleOf::checked_next_multiple_of(U16::from(10u8), U16::from(0u8)),
147            None
148        );
149
150        // Already a multiple (no overflow)
151        let large = U16::from(65530u16);
152        assert_eq!(
153            NextMultipleOf::checked_next_multiple_of(large, U16::from(10u8)),
154            Some(large)
155        ); // 65530 % 10 = 0, so returns itself
156
157        // Overflow case
158        let large2 = U16::from(65531u16);
159        assert_eq!(
160            NextMultipleOf::checked_next_multiple_of(large2, U16::from(10u8)),
161            None
162        ); // 65531 + 9 = 65540 > 65535, overflow
163    }
164
165    c0nst::c0nst! {
166        pub c0nst fn const_is_multiple_of<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
167            a: &FixedUInt<T, N, Nct>,
168            b: &FixedUInt<T, N, Nct>,
169        ) -> bool {
170            MultipleOf::is_multiple_of(*a, *b)
171        }
172
173        pub c0nst fn const_next_multiple_of<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
174            a: FixedUInt<T, N, Nct>,
175            b: FixedUInt<T, N, Nct>,
176        ) -> FixedUInt<T, N, Nct> {
177            NextMultipleOf::next_multiple_of(a, b)
178        }
179    }
180
181    #[test]
182    fn test_const_multiple() {
183        type U16 = FixedUInt<u8, 2>;
184
185        assert!(const_is_multiple_of(&U16::from(10u8), &U16::from(5u8)));
186        assert_eq!(
187            const_next_multiple_of(U16::from(11u8), U16::from(5u8)),
188            U16::from(15u8)
189        );
190
191        #[cfg(feature = "nightly")]
192        {
193            const TEN: U16 = FixedUInt::from_array([10, 0]);
194            const FIVE: U16 = FixedUInt::from_array([5, 0]);
195            const IS_MULT: bool = const_is_multiple_of(&TEN, &FIVE);
196            assert!(IS_MULT);
197
198            const ELEVEN: U16 = FixedUInt::from_array([11, 0]);
199            const NEXT: U16 = const_next_multiple_of(ELEVEN, FIVE);
200            assert_eq!(NEXT, FixedUInt::from_array([15, 0]));
201        }
202    }
203}