1use super::{FixedUInt, MachineWord};
18use crate::machineword::ConstMachineWord;
19use const_num_traits::Nct;
20use const_num_traits::{Ilog, Ilog2, Ilog10, PrimBits, Zero};
21
22c0nst::c0nst! {
23 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> Ilog2 for FixedUInt<T, N, Nct> {
24 fn ilog2(self) -> u32 {
25 match <Self as Ilog2>::checked_ilog2(self) {
26 Some(v) => v,
27 None => panic!("ilog2: argument is zero"),
28 }
29 }
30
31 fn checked_ilog2(self) -> Option<u32> {
32 if <Self as Zero>::is_zero(&self) {
33 return None;
34 }
35 let leading = PrimBits::leading_zeros(self);
37 Some(Self::BIT_SIZE as u32 - 1 - leading)
38 }
39 }
40
41 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> Ilog10 for FixedUInt<T, N, Nct> {
42 fn ilog10(self) -> u32 {
43 match <Self as Ilog10>::checked_ilog10(self) {
44 Some(v) => v,
45 None => panic!("ilog10: argument is zero"),
46 }
47 }
48
49 fn checked_ilog10(self) -> Option<u32> {
50 if <Self as Zero>::is_zero(&self) {
51 return None;
52 }
53 let ten: Self = core::convert::From::from(10u8);
55 let mut n = self;
56 let mut count = 0u32;
57 while n >= ten {
58 n /= ten;
59 count += 1;
60 }
61 Some(count)
62 }
63 }
64
65 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> Ilog for FixedUInt<T, N, Nct> {
66 fn ilog(self, base: Self) -> u32 {
67 match <Self as Ilog>::checked_ilog(self, base) {
68 Some(v) => v,
69 None => panic!("ilog: argument is zero or base is less than 2"),
70 }
71 }
72
73 fn checked_ilog(self, base: Self) -> Option<u32> {
74 if <Self as Zero>::is_zero(&self) {
75 return None;
76 }
77 let two: Self = core::convert::From::from(2u8);
78 if base < two {
79 return None;
80 }
81 if base == two {
84 return <Self as Ilog2>::checked_ilog2(self);
85 }
86 let ten: Self = core::convert::From::from(10u8);
87 if base == ten {
88 return <Self as Ilog10>::checked_ilog10(self);
89 }
90 let mut n = self;
92 let mut count = 0u32;
93 while n >= base {
94 n /= base;
95 count += 1;
96 }
97 Some(count)
98 }
99 }
100
101 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> Ilog2 for &FixedUInt<T, N, Nct> {
102 fn ilog2(self) -> u32 {
103 <FixedUInt<T, N, Nct> as Ilog2>::ilog2(FixedUInt::from_array(self.array))
104 }
105 fn checked_ilog2(self) -> Option<u32> {
106 <FixedUInt<T, N, Nct> as Ilog2>::checked_ilog2(FixedUInt::from_array(self.array))
107 }
108 }
109
110 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> Ilog10 for &FixedUInt<T, N, Nct> {
111 fn ilog10(self) -> u32 {
112 <FixedUInt<T, N, Nct> as Ilog10>::ilog10(FixedUInt::from_array(self.array))
113 }
114 fn checked_ilog10(self) -> Option<u32> {
115 <FixedUInt<T, N, Nct> as Ilog10>::checked_ilog10(FixedUInt::from_array(self.array))
116 }
117 }
118
119 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> Ilog for &FixedUInt<T, N, Nct> {
120 fn ilog(self, base: Self) -> u32 {
121 <FixedUInt<T, N, Nct> as Ilog>::ilog(FixedUInt::from_array(self.array), FixedUInt::from_array(base.array))
122 }
123 fn checked_ilog(self, base: Self) -> Option<u32> {
124 <FixedUInt<T, N, Nct> as Ilog>::checked_ilog(FixedUInt::from_array(self.array), FixedUInt::from_array(base.array))
125 }
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 #[test]
134 fn test_ilog2() {
135 type U16 = FixedUInt<u8, 2>;
136
137 assert_eq!(Ilog2::ilog2(U16::from(1u8)), 0);
138 assert_eq!(Ilog2::ilog2(U16::from(2u8)), 1);
139 assert_eq!(Ilog2::ilog2(U16::from(3u8)), 1);
140 assert_eq!(Ilog2::ilog2(U16::from(4u8)), 2);
141 assert_eq!(Ilog2::ilog2(U16::from(7u8)), 2);
142 assert_eq!(Ilog2::ilog2(U16::from(8u8)), 3);
143 assert_eq!(Ilog2::ilog2(U16::from(255u8)), 7);
144 assert_eq!(Ilog2::ilog2(U16::from(256u16)), 8);
145 assert_eq!(Ilog2::ilog2(U16::from(32768u16)), 15);
146 }
147
148 #[test]
149 fn test_ilog10() {
150 type U16 = FixedUInt<u8, 2>;
151
152 assert_eq!(Ilog10::ilog10(U16::from(1u8)), 0);
153 assert_eq!(Ilog10::ilog10(U16::from(9u8)), 0);
154 assert_eq!(Ilog10::ilog10(U16::from(10u8)), 1);
155 assert_eq!(Ilog10::ilog10(U16::from(99u8)), 1);
156 assert_eq!(Ilog10::ilog10(U16::from(100u8)), 2);
157 assert_eq!(Ilog10::ilog10(U16::from(999u16)), 2);
158 assert_eq!(Ilog10::ilog10(U16::from(1000u16)), 3);
159 assert_eq!(Ilog10::ilog10(U16::from(9999u16)), 3);
160 assert_eq!(Ilog10::ilog10(U16::from(10000u16)), 4);
161 }
162
163 #[test]
164 fn test_ilog() {
165 type U16 = FixedUInt<u8, 2>;
166
167 assert_eq!(Ilog::ilog(U16::from(8u8), U16::from(2u8)), 3);
169 assert_eq!(Ilog::ilog(U16::from(9u8), U16::from(2u8)), 3);
170
171 assert_eq!(Ilog::ilog(U16::from(1u8), U16::from(3u8)), 0);
173 assert_eq!(Ilog::ilog(U16::from(3u8), U16::from(3u8)), 1);
174 assert_eq!(Ilog::ilog(U16::from(8u8), U16::from(3u8)), 1);
175 assert_eq!(Ilog::ilog(U16::from(9u8), U16::from(3u8)), 2);
176 assert_eq!(Ilog::ilog(U16::from(27u8), U16::from(3u8)), 3);
177
178 assert_eq!(Ilog::ilog(U16::from(255u8), U16::from(16u8)), 1);
180 assert_eq!(Ilog::ilog(U16::from(256u16), U16::from(16u8)), 2);
181 }
182
183 #[test]
184 fn test_checked_ilog2() {
185 type U16 = FixedUInt<u8, 2>;
186
187 assert_eq!(Ilog2::checked_ilog2(U16::from(0u8)), None);
188 assert_eq!(Ilog2::checked_ilog2(U16::from(1u8)), Some(0));
189 assert_eq!(Ilog2::checked_ilog2(U16::from(8u8)), Some(3));
190 }
191
192 #[test]
193 fn test_checked_ilog10() {
194 type U16 = FixedUInt<u8, 2>;
195
196 assert_eq!(Ilog10::checked_ilog10(U16::from(0u8)), None);
197 assert_eq!(Ilog10::checked_ilog10(U16::from(1u8)), Some(0));
198 assert_eq!(Ilog10::checked_ilog10(U16::from(100u8)), Some(2));
199 }
200
201 #[test]
202 fn test_checked_ilog() {
203 type U16 = FixedUInt<u8, 2>;
204
205 assert_eq!(Ilog::checked_ilog(U16::from(0u8), U16::from(2u8)), None);
207 assert_eq!(Ilog::checked_ilog(U16::from(10u8), U16::from(0u8)), None);
209 assert_eq!(Ilog::checked_ilog(U16::from(10u8), U16::from(1u8)), None);
210 assert_eq!(Ilog::checked_ilog(U16::from(8u8), U16::from(2u8)), Some(3));
212 }
213
214 c0nst::c0nst! {
215 pub c0nst fn const_ilog2<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
216 v: FixedUInt<T, N, Nct>,
217 ) -> u32 {
218 Ilog2::ilog2(v)
219 }
220
221 pub c0nst fn const_ilog10<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
222 v: FixedUInt<T, N, Nct>,
223 ) -> u32 {
224 Ilog10::ilog10(v)
225 }
226 }
227
228 #[test]
229 fn test_const_ilog() {
230 type U16 = FixedUInt<u8, 2>;
231
232 assert_eq!(const_ilog2(U16::from(8u8)), 3);
233 assert_eq!(const_ilog10(U16::from(100u8)), 2);
234
235 #[cfg(feature = "nightly")]
236 {
237 const EIGHT: U16 = FixedUInt::from_array([8, 0]);
238 const HUNDRED: U16 = FixedUInt::from_array([100, 0]);
239 const LOG2_RESULT: u32 = const_ilog2(EIGHT);
240 const LOG10_RESULT: u32 = const_ilog10(HUNDRED);
241 assert_eq!(LOG2_RESULT, 3);
242 assert_eq!(LOG10_RESULT, 2);
243 }
244 }
245}