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 let mut n = self;
83 let mut count = 0u32;
84 while n >= base {
85 n /= base;
86 count += 1;
87 }
88 Some(count)
89 }
90 }
91
92 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> Ilog2 for &FixedUInt<T, N, Nct> {
93 fn ilog2(self) -> u32 {
94 <FixedUInt<T, N, Nct> as Ilog2>::ilog2(*self)
95 }
96 fn checked_ilog2(self) -> Option<u32> {
97 <FixedUInt<T, N, Nct> as Ilog2>::checked_ilog2(*self)
98 }
99 }
100
101 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> Ilog10 for &FixedUInt<T, N, Nct> {
102 fn ilog10(self) -> u32 {
103 <FixedUInt<T, N, Nct> as Ilog10>::ilog10(*self)
104 }
105 fn checked_ilog10(self) -> Option<u32> {
106 <FixedUInt<T, N, Nct> as Ilog10>::checked_ilog10(*self)
107 }
108 }
109
110 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> Ilog for &FixedUInt<T, N, Nct> {
111 fn ilog(self, base: Self) -> u32 {
112 <FixedUInt<T, N, Nct> as Ilog>::ilog(*self, *base)
113 }
114 fn checked_ilog(self, base: Self) -> Option<u32> {
115 <FixedUInt<T, N, Nct> as Ilog>::checked_ilog(*self, *base)
116 }
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 #[test]
125 fn test_ilog2() {
126 type U16 = FixedUInt<u8, 2>;
127
128 assert_eq!(Ilog2::ilog2(U16::from(1u8)), 0);
129 assert_eq!(Ilog2::ilog2(U16::from(2u8)), 1);
130 assert_eq!(Ilog2::ilog2(U16::from(3u8)), 1);
131 assert_eq!(Ilog2::ilog2(U16::from(4u8)), 2);
132 assert_eq!(Ilog2::ilog2(U16::from(7u8)), 2);
133 assert_eq!(Ilog2::ilog2(U16::from(8u8)), 3);
134 assert_eq!(Ilog2::ilog2(U16::from(255u8)), 7);
135 assert_eq!(Ilog2::ilog2(U16::from(256u16)), 8);
136 assert_eq!(Ilog2::ilog2(U16::from(32768u16)), 15);
137 }
138
139 #[test]
140 fn test_ilog10() {
141 type U16 = FixedUInt<u8, 2>;
142
143 assert_eq!(Ilog10::ilog10(U16::from(1u8)), 0);
144 assert_eq!(Ilog10::ilog10(U16::from(9u8)), 0);
145 assert_eq!(Ilog10::ilog10(U16::from(10u8)), 1);
146 assert_eq!(Ilog10::ilog10(U16::from(99u8)), 1);
147 assert_eq!(Ilog10::ilog10(U16::from(100u8)), 2);
148 assert_eq!(Ilog10::ilog10(U16::from(999u16)), 2);
149 assert_eq!(Ilog10::ilog10(U16::from(1000u16)), 3);
150 assert_eq!(Ilog10::ilog10(U16::from(9999u16)), 3);
151 assert_eq!(Ilog10::ilog10(U16::from(10000u16)), 4);
152 }
153
154 #[test]
155 fn test_ilog() {
156 type U16 = FixedUInt<u8, 2>;
157
158 assert_eq!(Ilog::ilog(U16::from(8u8), U16::from(2u8)), 3);
160 assert_eq!(Ilog::ilog(U16::from(9u8), U16::from(2u8)), 3);
161
162 assert_eq!(Ilog::ilog(U16::from(1u8), U16::from(3u8)), 0);
164 assert_eq!(Ilog::ilog(U16::from(3u8), U16::from(3u8)), 1);
165 assert_eq!(Ilog::ilog(U16::from(8u8), U16::from(3u8)), 1);
166 assert_eq!(Ilog::ilog(U16::from(9u8), U16::from(3u8)), 2);
167 assert_eq!(Ilog::ilog(U16::from(27u8), U16::from(3u8)), 3);
168
169 assert_eq!(Ilog::ilog(U16::from(255u8), U16::from(16u8)), 1);
171 assert_eq!(Ilog::ilog(U16::from(256u16), U16::from(16u8)), 2);
172 }
173
174 #[test]
175 fn test_checked_ilog2() {
176 type U16 = FixedUInt<u8, 2>;
177
178 assert_eq!(Ilog2::checked_ilog2(U16::from(0u8)), None);
179 assert_eq!(Ilog2::checked_ilog2(U16::from(1u8)), Some(0));
180 assert_eq!(Ilog2::checked_ilog2(U16::from(8u8)), Some(3));
181 }
182
183 #[test]
184 fn test_checked_ilog10() {
185 type U16 = FixedUInt<u8, 2>;
186
187 assert_eq!(Ilog10::checked_ilog10(U16::from(0u8)), None);
188 assert_eq!(Ilog10::checked_ilog10(U16::from(1u8)), Some(0));
189 assert_eq!(Ilog10::checked_ilog10(U16::from(100u8)), Some(2));
190 }
191
192 #[test]
193 fn test_checked_ilog() {
194 type U16 = FixedUInt<u8, 2>;
195
196 assert_eq!(Ilog::checked_ilog(U16::from(0u8), U16::from(2u8)), None);
198 assert_eq!(Ilog::checked_ilog(U16::from(10u8), U16::from(0u8)), None);
200 assert_eq!(Ilog::checked_ilog(U16::from(10u8), U16::from(1u8)), None);
201 assert_eq!(Ilog::checked_ilog(U16::from(8u8), U16::from(2u8)), Some(3));
203 }
204
205 c0nst::c0nst! {
206 pub c0nst fn const_ilog2<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
207 v: FixedUInt<T, N, Nct>,
208 ) -> u32 {
209 Ilog2::ilog2(v)
210 }
211
212 pub c0nst fn const_ilog10<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
213 v: FixedUInt<T, N, Nct>,
214 ) -> u32 {
215 Ilog10::ilog10(v)
216 }
217 }
218
219 #[test]
220 fn test_const_ilog() {
221 type U16 = FixedUInt<u8, 2>;
222
223 assert_eq!(const_ilog2(U16::from(8u8)), 3);
224 assert_eq!(const_ilog10(U16::from(100u8)), 2);
225
226 #[cfg(feature = "nightly")]
227 {
228 const EIGHT: U16 = FixedUInt::from_array([8, 0]);
229 const HUNDRED: U16 = FixedUInt::from_array([100, 0]);
230 const LOG2_RESULT: u32 = const_ilog2(EIGHT);
231 const LOG10_RESULT: u32 = const_ilog10(HUNDRED);
232 assert_eq!(LOG2_RESULT, 3);
233 assert_eq!(LOG10_RESULT, 2);
234 }
235 }
236}