Skip to content

Commit dd4bff1

Browse files
authored
refactor impls into separate modules (#10)
1 parent 386db52 commit dd4bff1

File tree

6 files changed

+568
-571
lines changed

6 files changed

+568
-571
lines changed

src/bitop.rs

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
use crate::{BST_BITS, BitSliceType, INLINE_SLICE_PARTS, SmolBitSet};
2+
3+
use core::iter;
4+
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign};
5+
6+
macro_rules! impl_bitop {
7+
($($OP:ident :: $op:ident, $OPA:ident :: $opa:ident),+) => {$(
8+
impl $OP<Self> for SmolBitSet {
9+
type Output = Self;
10+
11+
#[inline]
12+
fn $op(self, rhs: Self) -> Self {
13+
let mut lhs = self;
14+
lhs.$opa(rhs);
15+
lhs
16+
}
17+
}
18+
19+
impl $OPA<Self> for SmolBitSet {
20+
#[inline]
21+
fn $opa(&mut self, rhs: Self) {
22+
self.$opa(&rhs);
23+
}
24+
}
25+
26+
impl_bitop!(@ref $OP :: $op, $OPA :: $opa);
27+
)*};
28+
(@ref $OP:ident :: $op:ident, $OPA:ident :: $opa:ident) => {
29+
impl $OP<&Self> for SmolBitSet {
30+
type Output = Self;
31+
32+
#[inline]
33+
fn $op(self, rhs: &Self) -> Self {
34+
let mut lhs = self;
35+
lhs.$opa(rhs);
36+
lhs
37+
}
38+
}
39+
40+
impl $OPA<&Self> for SmolBitSet {
41+
fn $opa(&mut self, rhs: &Self) {
42+
match (self.is_inline(), rhs.is_inline()) {
43+
(true, true) => unsafe {
44+
let lhs = self.get_inline_data_unchecked();
45+
let rhs = rhs.get_inline_data_unchecked();
46+
self.write_inline_data_unchecked(lhs.$op(rhs));
47+
},
48+
(_, false) => {
49+
let rhs_hb = rhs.highest_set_bit();
50+
if rhs_hb > self.highest_set_bit() {
51+
self.ensure_capacity(rhs_hb);
52+
}
53+
54+
let lhs = unsafe { self.as_slice_mut_unchecked() };
55+
let rhs = unsafe { rhs.as_slice_unchecked() };
56+
57+
assert!(lhs.len() >= rhs.len());
58+
59+
// in case lhs > rhs we need to have extra elements
60+
let rhs_iter = rhs.iter().chain(iter::repeat(&0));
61+
62+
for (lhs, rhs) in lhs.iter_mut().zip(rhs_iter) {
63+
(*lhs).$opa(*rhs);
64+
}
65+
}
66+
(false, true) => {
67+
let lhs = unsafe { self.as_slice_mut_unchecked() };
68+
let rhs = unsafe { rhs.get_inline_data_unchecked() };
69+
70+
lhs.iter_mut()
71+
.enumerate()
72+
.take(INLINE_SLICE_PARTS)
73+
.for_each(|(idx, lhs)| {
74+
(*lhs).$opa((rhs >> (idx * BST_BITS)) as BitSliceType);
75+
});
76+
}
77+
}
78+
}
79+
}
80+
};
81+
}
82+
83+
impl_bitop! {
84+
BitOr::bitor, BitOrAssign::bitor_assign,
85+
BitAnd::bitand, BitAndAssign::bitand_assign,
86+
BitXor::bitxor, BitXorAssign::bitxor_assign
87+
}
88+
89+
macro_rules! impl_bitop_prim {
90+
($($OP:ident :: $op:ident, $OPA:ident :: $opa:ident, $t:ty),+) => {$(
91+
impl $OP<$t> for SmolBitSet {
92+
type Output = Self;
93+
94+
#[inline]
95+
fn $op(self, rhs: $t) -> Self {
96+
let mut lhs = self;
97+
lhs.$opa(rhs);
98+
lhs
99+
}
100+
}
101+
102+
impl $OPA<$t> for SmolBitSet {
103+
#[inline]
104+
fn $opa(&mut self, rhs: $t) {
105+
self.$opa(Self::from(rhs))
106+
}
107+
}
108+
109+
impl_bitop_prim!(@ref $OP :: $op, $OPA :: $opa, $t);
110+
)*};
111+
(@ref $OP:ident :: $op:ident, $OPA:ident :: $opa:ident, $t:ty) => {
112+
impl $OP<&$t> for SmolBitSet {
113+
type Output = Self;
114+
115+
#[inline]
116+
fn $op(self, rhs: &$t) -> Self {
117+
self.$op(*rhs)
118+
}
119+
}
120+
121+
impl $OPA<&$t> for SmolBitSet {
122+
#[inline]
123+
fn $opa(&mut self, rhs: &$t) {
124+
self.$opa(*rhs)
125+
}
126+
}
127+
};
128+
($($t:ty),+) => {$(
129+
impl_bitop_prim!{
130+
BitOr::bitor, BitOrAssign::bitor_assign, $t,
131+
BitAnd::bitand, BitAndAssign::bitand_assign, $t,
132+
BitXor::bitxor, BitXorAssign::bitxor_assign, $t
133+
}
134+
)*};
135+
}
136+
137+
impl_bitop_prim!(u8, u16, u32, u64, u128, usize);

src/cmp.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use crate::SmolBitSet;
2+
3+
use core::cmp;
4+
5+
impl cmp::PartialEq for SmolBitSet {
6+
fn eq(&self, other: &Self) -> bool {
7+
match (self.len(), other.len()) {
8+
(0, 0) => unsafe {
9+
self.get_inline_data_unchecked() == other.get_inline_data_unchecked()
10+
},
11+
(a, b) if a == b => {
12+
let a = unsafe { self.as_slice_unchecked() };
13+
let b = unsafe { other.as_slice_unchecked() };
14+
15+
a == b
16+
}
17+
_ => false,
18+
}
19+
}
20+
}
21+
22+
impl cmp::Eq for SmolBitSet {}
23+
24+
impl cmp::PartialOrd for SmolBitSet {
25+
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
26+
Some(self.cmp(other))
27+
}
28+
}
29+
30+
impl cmp::Ord for SmolBitSet {
31+
fn cmp(&self, other: &Self) -> cmp::Ordering {
32+
match (self.len(), other.len()) {
33+
(0, 0) => unsafe {
34+
self.get_inline_data_unchecked()
35+
.cmp(&other.get_inline_data_unchecked())
36+
},
37+
(0, _) => cmp::Ordering::Less,
38+
(_, 0) => cmp::Ordering::Greater,
39+
(a, b) if a == b => unsafe {
40+
let a = self.as_slice_unchecked();
41+
let b = other.as_slice_unchecked();
42+
43+
for (a, b) in a.iter().zip(b.iter()).rev() {
44+
let cmp = a.cmp(b);
45+
if cmp != cmp::Ordering::Equal {
46+
return cmp;
47+
}
48+
}
49+
50+
cmp::Ordering::Equal
51+
},
52+
(a, b) => a.cmp(&b),
53+
}
54+
}
55+
}

src/fmt.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
use crate::{BST_BITS, BitSliceType, SmolBitSet};
2+
3+
#[cfg(feature = "std")]
4+
use std::fmt;
5+
6+
#[cfg(not(feature = "std"))]
7+
use core::fmt;
8+
9+
use fmt::{Binary, Debug, Display, Formatter, LowerHex, Octal, Result, UpperHex};
10+
11+
impl Debug for SmolBitSet {
12+
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
13+
let data = if self.is_inline() {
14+
let d = unsafe { self.get_inline_data_unchecked() };
15+
&[d as BitSliceType, (d >> BST_BITS) as BitSliceType]
16+
} else {
17+
unsafe { self.as_slice_unchecked() }
18+
};
19+
20+
f.debug_list().entries(data).finish()
21+
}
22+
}
23+
24+
impl Display for SmolBitSet {
25+
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
26+
if self.is_inline() {
27+
return write!(f, "{}", unsafe { self.get_inline_data_unchecked() });
28+
}
29+
30+
let tmp = num_bigint::BigUint::from_slice(unsafe { self.as_slice_unchecked() });
31+
write!(f, "{tmp}")
32+
}
33+
}
34+
35+
macro_rules! impl_format {
36+
($($kind:ident $format:literal $variants:literal),+) => {$(
37+
impl $kind for SmolBitSet {
38+
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
39+
if self.is_inline() {
40+
return $kind::fmt(&unsafe { self.get_inline_data_unchecked() }, f);
41+
}
42+
43+
let data = unsafe { self.as_slice_unchecked() };
44+
let highest = self.highest_set_bit().saturating_sub(1).div_ceil(BST_BITS);
45+
46+
let mut full_width = false;
47+
for idx in (0..highest).rev() {
48+
const PADDING: usize = BST_BITS / ($variants as u8).ilog2() as usize;
49+
50+
let d = data[idx];
51+
52+
if full_width {
53+
write!(f, concat!("{d:0PADDING$", $format, "}"), d = d, PADDING = PADDING)?;
54+
} else {
55+
full_width = true;
56+
$kind::fmt(&d, f)?;
57+
}
58+
}
59+
60+
Ok(())
61+
}
62+
}
63+
)*};
64+
}
65+
66+
impl_format!(
67+
Binary 'b' 2,
68+
Octal 'o' 8,
69+
LowerHex 'x' 16,
70+
UpperHex 'X' 16
71+
);

src/from.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
use crate::{BST_BITS, BitSliceType, SmolBitSet};
2+
3+
use core::str::FromStr;
4+
5+
#[cfg(not(feature = "std"))]
6+
use extern_alloc::string::String;
7+
8+
macro_rules! impl_from {
9+
($($t:ty),+) => {$(
10+
impl From<$t> for SmolBitSet {
11+
fn from(value: $t) -> Self {
12+
let mut sbs = SmolBitSet::new();
13+
sbs.ensure_capacity(highest_set_bit!($t, value));
14+
15+
if sbs.is_inline() {
16+
unsafe { sbs.write_inline_data_unchecked(value as usize) };
17+
} else {
18+
const T_BITS: usize = <$t>::BITS as usize;
19+
const STEPS: usize = T_BITS.div_ceil(BST_BITS);
20+
21+
let data = unsafe { sbs.as_slice_mut_unchecked() };
22+
23+
for i in 0..STEPS {
24+
data[i] = (value >> (i * BST_BITS)) as BitSliceType;
25+
}
26+
}
27+
28+
sbs
29+
}
30+
}
31+
32+
impl_from!(@ref $t);
33+
)*};
34+
(@ref $t:ty) => {
35+
impl From<&$t> for SmolBitSet {
36+
#[inline]
37+
fn from(value: &$t) -> Self {
38+
Self::from(*value)
39+
}
40+
}
41+
}
42+
}
43+
44+
impl_from!(u8, u16, u32, u64, u128, usize);
45+
46+
impl TryFrom<String> for SmolBitSet {
47+
type Error = ();
48+
49+
#[inline]
50+
fn try_from(value: String) -> Result<Self, Self::Error> {
51+
Self::from_str(value.as_str())
52+
}
53+
}
54+
55+
impl FromStr for SmolBitSet {
56+
type Err = ();
57+
58+
fn from_str(s: &str) -> Result<Self, Self::Err> {
59+
let tmp = num_bigint::BigUint::from_str(s).map_err(|_| ())?;
60+
61+
let mut sbs = Self::new();
62+
sbs.ensure_capacity(tmp.bits() as usize);
63+
64+
let digits = tmp.to_u32_digits();
65+
let digit_count = digits.len();
66+
if sbs.is_inline() {
67+
match digit_count {
68+
0 => {}
69+
1 => unsafe { sbs.write_inline_data_unchecked(digits[0] as usize) },
70+
2 => unsafe {
71+
sbs.write_inline_data_unchecked(
72+
(digits[0] as usize) | ((digits[1] as usize) << BST_BITS),
73+
);
74+
},
75+
_ => unreachable!("Too many digits for inline data"),
76+
}
77+
} else {
78+
assert!(sbs.len() >= digit_count);
79+
80+
let data = unsafe { sbs.as_slice_mut_unchecked() };
81+
data[0..digit_count].copy_from_slice(&digits);
82+
}
83+
84+
Ok(sbs)
85+
}
86+
}

0 commit comments

Comments
 (0)