Skip to content

Commit b37dd22

Browse files
authored
implement Eq, Ord, Hash, Debug & Binary (#6)
* impl `Eq` & `Ord` * impl `Hash` * impl `Debug` & `Binary` formatters
1 parent 3d3ea73 commit b37dd22

File tree

1 file changed

+164
-0
lines changed

1 file changed

+164
-0
lines changed

src/lib.rs

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use extern_alloc::string::ToString;
88
#[cfg(not(feature = "std"))]
99
use {
1010
core::convert::Infallible,
11+
core::hash,
1112
core::iter,
1213
core::mem::MaybeUninit,
1314
core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not},
@@ -24,6 +25,7 @@ use {
2425
use {
2526
std::alloc::{self, Layout, handle_alloc_error},
2627
std::convert::Infallible,
28+
std::hash,
2729
std::iter,
2830
std::mem::MaybeUninit,
2931
std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not},
@@ -697,6 +699,86 @@ macro_rules! impl_from {
697699

698700
impl_from!(u8, u16, u32, u64, usize);
699701

702+
impl cmp::PartialEq for SmolBitSet {
703+
fn eq(&self, other: &Self) -> bool {
704+
match (self.len(), other.len()) {
705+
(0, 0) => unsafe {
706+
self.get_inline_data_unchecked() == other.get_inline_data_unchecked()
707+
},
708+
(a, b) if a == b => {
709+
let a = unsafe { self.as_slice_unchecked() };
710+
let b = unsafe { other.as_slice_unchecked() };
711+
712+
a == b
713+
}
714+
_ => false,
715+
}
716+
}
717+
}
718+
719+
impl cmp::Eq for SmolBitSet {}
720+
721+
impl cmp::PartialOrd for SmolBitSet {
722+
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
723+
Some(self.cmp(other))
724+
}
725+
}
726+
727+
impl cmp::Ord for SmolBitSet {
728+
fn cmp(&self, other: &Self) -> cmp::Ordering {
729+
match (self.len(), other.len()) {
730+
(0, 0) => unsafe {
731+
self.get_inline_data_unchecked()
732+
.cmp(&other.get_inline_data_unchecked())
733+
},
734+
(0, _) => cmp::Ordering::Less,
735+
(_, 0) => cmp::Ordering::Greater,
736+
(a, b) if a == b => unsafe {
737+
let a = self.as_slice_unchecked();
738+
let b = other.as_slice_unchecked();
739+
740+
for (a, b) in a.iter().zip(b.iter()).rev() {
741+
let cmp = a.cmp(b);
742+
if cmp != cmp::Ordering::Equal {
743+
return cmp;
744+
}
745+
}
746+
747+
cmp::Ordering::Equal
748+
},
749+
(a, b) => a.cmp(&b),
750+
}
751+
}
752+
}
753+
754+
impl hash::Hash for SmolBitSet {
755+
fn hash<H: hash::Hasher>(&self, state: &mut H) {
756+
if self.is_inline() {
757+
unsafe { self.get_inline_data_unchecked() }.hash(state);
758+
return;
759+
}
760+
761+
let hb = self.highest_set_bit();
762+
let data = unsafe { self.as_slice_unchecked() };
763+
for d in data.iter().take(hb.div_ceil(BST_BITS)) {
764+
d.hash(state);
765+
}
766+
}
767+
}
768+
769+
impl fmt::Debug for SmolBitSet {
770+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
771+
let data = if self.is_inline() {
772+
let d = unsafe { self.get_inline_data_unchecked() };
773+
&[d as BitSliceType, (d >> BST_BITS) as BitSliceType]
774+
} else {
775+
unsafe { self.as_slice_unchecked() }
776+
};
777+
778+
f.debug_list().entries(data).finish()
779+
}
780+
}
781+
700782
impl fmt::Display for SmolBitSet {
701783
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
702784
if self.is_inline() {
@@ -708,6 +790,31 @@ impl fmt::Display for SmolBitSet {
708790
}
709791
}
710792

793+
impl fmt::Binary for SmolBitSet {
794+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
795+
if self.is_inline() {
796+
return fmt::Binary::fmt(&unsafe { self.get_inline_data_unchecked() }, f);
797+
}
798+
799+
let data = unsafe { self.as_slice_unchecked() };
800+
let highest = self.highest_set_bit().saturating_sub(1).div_ceil(BST_BITS);
801+
802+
let mut full_width = false;
803+
for idx in (0..highest).rev() {
804+
let d = data[idx];
805+
806+
if full_width {
807+
write!(f, "{d:0BST_BITS$b}")?;
808+
} else {
809+
full_width = true;
810+
fmt::Binary::fmt(&d, f)?;
811+
}
812+
}
813+
814+
Ok(())
815+
}
816+
}
817+
711818
impl TryFrom<String> for SmolBitSet {
712819
type Error = ();
713820

@@ -931,6 +1038,32 @@ mod tests {
9311038
assert_eq!((!sbs).as_slice(), [!0x0000_1234, !0xC5C5_BEEF]);
9321039
}
9331040

1041+
#[test]
1042+
#[cfg(feature = "std")]
1043+
fn hash() {
1044+
// core does not have a default hasher
1045+
use hash::{DefaultHasher, Hash, Hasher};
1046+
1047+
let a = SmolBitSet::from(0xC5C5_F00Du32);
1048+
let b = SmolBitSet::from(0xC5C5_F00Du32);
1049+
let mut hasher_a = DefaultHasher::new();
1050+
let mut hasher_b = DefaultHasher::new();
1051+
a.hash(&mut hasher_a);
1052+
b.hash(&mut hasher_b);
1053+
assert_eq!(hasher_a.finish(), hasher_b.finish());
1054+
1055+
let mut a = SmolBitSet::from(0xFFC5_C0FF_EE00_BEEF_u64);
1056+
let mut b = SmolBitSet::from(0xFFC5_C0FF_EE00_BEEF_u64);
1057+
a <<= 128u8;
1058+
a >>= 66u8;
1059+
b <<= 128u8 - 66u8;
1060+
let mut hasher_a = DefaultHasher::new();
1061+
let mut hasher_b = DefaultHasher::new();
1062+
a.hash(&mut hasher_a);
1063+
b.hash(&mut hasher_b);
1064+
assert_eq!(hasher_a.finish(), hasher_b.finish());
1065+
}
1066+
9341067
mod from {
9351068
use super::*;
9361069

@@ -1319,4 +1452,35 @@ mod tests {
13191452
}
13201453
}
13211454
}
1455+
1456+
mod cmp {
1457+
use super::*;
1458+
1459+
#[test]
1460+
fn eq() {
1461+
let mut a = SmolBitSet::from(u16::MAX);
1462+
let mut b = SmolBitSet::from(0xFFFFu16);
1463+
assert_eq!(a, b);
1464+
1465+
a <<= 55;
1466+
assert_ne!(a, b);
1467+
1468+
b <<= 55;
1469+
assert_eq!(a, b);
1470+
}
1471+
1472+
#[test]
1473+
fn ord() {
1474+
let mut a = SmolBitSet::from(0xBEEFu16);
1475+
let mut b = SmolBitSet::from(0x00C5_F00Du32);
1476+
assert!(a < b);
1477+
1478+
a <<= 72;
1479+
assert!(a > b);
1480+
assert!(b < a);
1481+
1482+
b <<= 72;
1483+
assert!(a < b);
1484+
}
1485+
}
13221486
}

0 commit comments

Comments
 (0)