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