Skip to content

Commit ddf0dd8

Browse files
authored
Add an owned iterator: IntoOnes (#103)
1 parent c6f976a commit ddf0dd8

1 file changed

Lines changed: 171 additions & 1 deletion

File tree

src/lib.rs

Lines changed: 171 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@
1818
#[cfg(not(feature = "std"))]
1919
extern crate alloc;
2020
#[cfg(not(feature = "std"))]
21-
use alloc::{vec, vec::Vec};
21+
use alloc::{
22+
vec,
23+
vec::{IntoIter, Vec},
24+
};
25+
#[cfg(feature = "std")]
26+
use std::vec::IntoIter;
2227

2328
#[cfg(not(feature = "std"))]
2429
use core as std;
@@ -517,6 +522,32 @@ impl FixedBitSet {
517522
}
518523
}
519524

525+
/// Iterates over all enabled bits.
526+
///
527+
/// Iterator element is the index of the `1` bit, type `usize`.
528+
/// Unlike `ones`, this function consumes the `FixedBitset`.
529+
pub fn into_ones(mut self) -> IntoOnes {
530+
if self.data.len() == 0 {
531+
IntoOnes {
532+
bitset_front: 0,
533+
bitset_back: 0,
534+
block_idx_front: 0,
535+
block_idx_back: 0,
536+
remaining_blocks: self.data.into_iter(),
537+
}
538+
} else {
539+
let first_block = self.data.remove(0);
540+
let last_block = self.data.pop().unwrap_or(0);
541+
IntoOnes {
542+
bitset_front: first_block,
543+
bitset_back: last_block,
544+
block_idx_front: 0,
545+
block_idx_back: (1 + self.data.len()) * BITS,
546+
remaining_blocks: self.data.into_iter(),
547+
}
548+
}
549+
}
550+
520551
/// Iterates over all disabled bits.
521552
///
522553
/// Iterator element is the index of the `0` bit, type `usize`.
@@ -1058,6 +1089,116 @@ impl FromIterator<usize> for FixedBitSet {
10581089
}
10591090
}
10601091

1092+
pub struct IntoOnes {
1093+
bitset_front: Block,
1094+
bitset_back: Block,
1095+
block_idx_front: usize,
1096+
block_idx_back: usize,
1097+
remaining_blocks: IntoIter<Block>,
1098+
}
1099+
1100+
impl IntoOnes {
1101+
#[inline]
1102+
pub fn last_positive_bit_and_unset(n: &mut Block) -> usize {
1103+
// Find the last set bit using x & -x
1104+
let last_bit = *n & n.wrapping_neg();
1105+
1106+
// Find the position of the last set bit
1107+
let position = last_bit.trailing_zeros();
1108+
1109+
// Unset the last set bit
1110+
*n &= *n - 1;
1111+
1112+
position as usize
1113+
}
1114+
1115+
#[inline]
1116+
fn first_positive_bit_and_unset(n: &mut Block) -> usize {
1117+
/* Identify the first non zero bit */
1118+
let bit_idx = n.leading_zeros();
1119+
1120+
/* set that bit to zero */
1121+
let mask = !((1 as Block) << (BITS as u32 - bit_idx - 1));
1122+
n.bitand_assign(mask);
1123+
1124+
bit_idx as usize
1125+
}
1126+
}
1127+
1128+
impl DoubleEndedIterator for IntoOnes {
1129+
fn next_back(&mut self) -> Option<Self::Item> {
1130+
while self.bitset_back == 0 {
1131+
match self.remaining_blocks.next_back() {
1132+
None => {
1133+
if self.bitset_front != 0 {
1134+
self.bitset_back = 0;
1135+
self.block_idx_back = self.block_idx_front;
1136+
return Some(
1137+
self.block_idx_front + BITS
1138+
- Self::first_positive_bit_and_unset(&mut self.bitset_front)
1139+
- 1,
1140+
);
1141+
} else {
1142+
return None;
1143+
}
1144+
}
1145+
Some(next_block) => {
1146+
self.bitset_back = next_block;
1147+
self.block_idx_back -= BITS;
1148+
}
1149+
};
1150+
}
1151+
1152+
Some(
1153+
self.block_idx_back - Self::first_positive_bit_and_unset(&mut self.bitset_back) + BITS
1154+
- 1,
1155+
)
1156+
}
1157+
}
1158+
1159+
impl Iterator for IntoOnes {
1160+
type Item = usize; // the bit position of the '1'
1161+
1162+
#[inline]
1163+
fn next(&mut self) -> Option<Self::Item> {
1164+
while self.bitset_front == 0 {
1165+
match self.remaining_blocks.next() {
1166+
Some(next_block) => {
1167+
self.bitset_front = next_block;
1168+
self.block_idx_front += BITS;
1169+
}
1170+
None => {
1171+
if self.bitset_back != 0 {
1172+
// not needed for iteration, but for size_hint
1173+
self.block_idx_front = self.block_idx_back;
1174+
self.bitset_front = 0;
1175+
1176+
return Some(
1177+
self.block_idx_back
1178+
+ Self::last_positive_bit_and_unset(&mut self.bitset_back),
1179+
);
1180+
} else {
1181+
return None;
1182+
}
1183+
}
1184+
};
1185+
}
1186+
1187+
Some(self.block_idx_front + Self::last_positive_bit_and_unset(&mut self.bitset_front))
1188+
}
1189+
1190+
#[inline]
1191+
fn size_hint(&self) -> (usize, Option<usize>) {
1192+
(
1193+
0,
1194+
(Some(self.block_idx_back - self.block_idx_front + 2 * BITS)),
1195+
)
1196+
}
1197+
}
1198+
1199+
// Ones will continue to return None once it first returns None.
1200+
impl<'a> FusedIterator for IntoOnes {}
1201+
10611202
impl<'a> BitAnd for &'a FixedBitSet {
10621203
type Output = FixedBitSet;
10631204
fn bitand(self, other: &FixedBitSet) -> FixedBitSet {
@@ -1376,6 +1517,35 @@ mod tests {
13761517
assert_eq!(known_result, ones_alternating);
13771518
}
13781519

1520+
#[test]
1521+
fn into_ones() {
1522+
fn create() -> FixedBitSet {
1523+
let mut fb = FixedBitSet::with_capacity(100);
1524+
fb.set(11, true);
1525+
fb.set(12, true);
1526+
fb.set(7, true);
1527+
fb.set(35, true);
1528+
fb.set(40, true);
1529+
fb.set(77, true);
1530+
fb.set(95, true);
1531+
fb.set(50, true);
1532+
fb.set(99, true);
1533+
fb
1534+
}
1535+
1536+
let ones: Vec<_> = create().into_ones().collect();
1537+
let ones_rev: Vec<_> = create().into_ones().rev().collect();
1538+
let ones_alternating: Vec<_> = create().into_ones().alternate().collect();
1539+
1540+
let mut known_result = vec![7, 11, 12, 35, 40, 50, 77, 95, 99];
1541+
1542+
assert_eq!(known_result, ones);
1543+
known_result.reverse();
1544+
assert_eq!(known_result, ones_rev);
1545+
let known_result: Vec<_> = known_result.into_iter().rev().alternate().collect();
1546+
assert_eq!(known_result, ones_alternating);
1547+
}
1548+
13791549
#[test]
13801550
fn size_hint() {
13811551
for s in 0..1000 {

0 commit comments

Comments
 (0)