1#![warn(clippy::pedantic)]
7#![allow(clippy::unreadable_literal)]
8#![no_std]
9
10mod tests;
11
12extern crate alloc;
13use alloc::boxed::Box;
14
15pub trait IntLog {
27 fn log10(self) -> usize;
41
42 fn log2(self) -> usize;
56
57 fn checked_log10(self) -> Option<usize>;
68
69 fn checked_log2(self) -> Option<usize>;
80}
81
82macro_rules! forward_ref_intlog {
86 ($imp:ident for $( $t:ty ),+) => {$(
87 impl $imp for $t {
88 #[inline]
89 fn log10(self) -> usize {
90 $imp::log10(*self)
91 }
92 #[inline]
93 fn log2(self) -> usize {
94 $imp::log2(*self)
95 }
96 #[inline]
97 fn checked_log10(self) -> Option<usize> {
98 $imp::checked_log10(*self)
99 }
100 #[inline]
101 fn checked_log2(self) -> Option<usize> {
102 $imp::checked_log2(*self)
103 }
104 }
105 )+}
106}
107
108macro_rules! impl_unsigned_log {
110 ($SelfT: ty, $Msb: expr, $ApproxMul: expr, $ApproxShr: expr, $Table: ident) => {
111 impl IntLog for $SelfT {
112 #[inline]
113 fn log10(self) -> usize {
114 let y = ($ApproxMul * ($Msb - self.leading_zeros() as usize)) >> $ApproxShr;
115 y + (($Table[y + 1] as $SelfT).wrapping_sub(self) >> $Msb) as usize
116 }
117
118 #[inline]
119 fn log2(self) -> usize {
120 $Msb - self.leading_zeros() as usize
121 }
122
123 #[inline]
124 fn checked_log10(self) -> Option<usize> {
125 if self > 0 { Some(self.log10()) } else { None }
126 }
127
128 #[inline]
129 fn checked_log2(self) -> Option<usize> {
130 if self > 0 { Some(self.log2()) } else { None }
131 }
132 }
133
134 forward_ref_intlog!(IntLog for &$SelfT, &mut $SelfT, Box<$SelfT>);
135 }
136}
137
138macro_rules! impl_signed_log {
140 ($SelfT: ty, $UnsignedT: ty) => {
141 impl IntLog for $SelfT {
142 #[inline]
143 fn log10(self) -> usize {
144 <$UnsignedT>::log10(self as $UnsignedT)
145 }
146
147 #[inline]
148 fn log2(self) -> usize {
149 <$UnsignedT>::log2(self as $UnsignedT)
150 }
151
152 #[inline]
153 fn checked_log10(self) -> Option<usize> {
154 if self > 0 { Some(<$UnsignedT>::log10(self as $UnsignedT)) } else { None }
155 }
156
157 #[inline]
158 fn checked_log2(self) -> Option<usize> {
159 if self > 0 { Some(<$UnsignedT>::log2(self as $UnsignedT)) } else { None }
160 }
161 }
162
163 forward_ref_intlog!(IntLog for &$SelfT, &mut $SelfT, Box<$SelfT>);
164 }
165}
166
167const LOG10_U8_TABLE: [u8; 4] = [0, 9, 99, u8::MAX];
169
170impl_unsigned_log! { u8, 7, 19, 6, LOG10_U8_TABLE }
171impl_signed_log! { i8, u8 }
172
173const LOG10_U16_TABLE: [u16; 6] = [0, 9, 99, 999, 9999, u16::MAX];
174
175impl_unsigned_log! { u16, 15, 18, 6, LOG10_U16_TABLE }
176impl_signed_log! { i16, u16 }
177#[cfg(target_pointer_width = "16")]
178impl_unsigned_log! { usize, 15, 18, 6, LOG10_U16_TABLE }
179#[cfg(target_pointer_width = "16")]
180impl_signed_log! { isize, u16 }
181
182const LOG10_U32_TABLE: [u32; 11] = [0, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, u32::MAX];
183
184impl_unsigned_log! { u32, 31, 19, 6, LOG10_U32_TABLE }
185impl_signed_log! { i32, u32 }
186#[cfg(target_pointer_width = "32")]
187impl_unsigned_log! { usize, 31, 19, 6, LOG10_U32_TABLE }
188#[cfg(target_pointer_width = "32")]
189impl_signed_log! { isize, u32 }
190
191const LOG10_U64_TABLE: [u64; 20] = [0, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999,
192 9999999999, 99999999999, 999999999999, 9999999999999, 99999999999999, 999999999999999,
193 9999999999999999, 99999999999999999, 999999999999999999, 9999999999999999999];
194
195impl_unsigned_log! { u64, 63, 19, 6, LOG10_U64_TABLE }
196impl_signed_log! { i64, u64 }
197#[cfg(target_pointer_width = "64")]
198impl_unsigned_log! { usize, 63, 19, 6, LOG10_U64_TABLE }
199#[cfg(target_pointer_width = "64")]
200impl_signed_log! { isize, u64 }
201
202const LOG10_U128_TABLE: [u128; 40] = [0, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999,
203 9999999999, 99999999999, 999999999999, 9999999999999, 99999999999999, 999999999999999,
204 9999999999999999, 99999999999999999, 999999999999999999, 9999999999999999999, 99999999999999999999,
205 999999999999999999999, 9999999999999999999999, 99999999999999999999999, 999999999999999999999999,
206 9999999999999999999999999, 99999999999999999999999999, 999999999999999999999999999, 9999999999999999999999999999,
207 99999999999999999999999999999, 999999999999999999999999999999, 9999999999999999999999999999999,
208 99999999999999999999999999999999, 999999999999999999999999999999999, 9999999999999999999999999999999999,
209 99999999999999999999999999999999999, 999999999999999999999999999999999999, 9999999999999999999999999999999999999,
210 99999999999999999999999999999999999999, u128::MAX];
211
212impl_unsigned_log! { u128, 127, 77, 8, LOG10_U128_TABLE }
213impl_signed_log! { i128, u128 }
214
215