Skip to content

Commit

Permalink
Add problem 2166: Design Bitset
Browse files Browse the repository at this point in the history
  • Loading branch information
EFanZh committed Mar 8, 2024
1 parent 9d4a0ab commit 350f00e
Show file tree
Hide file tree
Showing 3 changed files with 272 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1471,6 +1471,7 @@ pub mod problem_2155_all_divisions_with_the_highest_score_of_a_binary_array;
pub mod problem_2160_minimum_sum_of_four_digit_number_after_splitting_digits;
pub mod problem_2161_partition_array_according_to_given_pivot;
pub mod problem_2165_smallest_value_of_the_rearranged_number;
pub mod problem_2166_design_bitset;

#[cfg(test)]
mod test_utilities;
127 changes: 127 additions & 0 deletions src/problem_2166_design_bitset/dense_storage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// ------------------------------------------------------ snip ------------------------------------------------------ //

pub struct Bitset {
data: Box<[u64]>,
length: usize,
}

impl Bitset {
fn new(size: i32) -> Self {
let length = size as u32 as usize;

Self {
data: vec![0; (length + 63) / 64].into_boxed_slice(),
length,
}
}

fn fix(&mut self, idx: i32) {
let idx = idx as u32 as usize;

self.data[idx / 64] |= 1 << (idx % 64);
}

fn unfix(&mut self, idx: i32) {
let idx = idx as u32 as usize;

self.data[idx / 64] &= !(1 << (idx % 64));
}

fn flip(&mut self) {
for x in &mut self.data[..self.length / 64] {
*x = !*x;
}

let remainder = self.length % 64;

if remainder != 0 {
let mask = (1 << remainder) - 1;
let last = self.data.last_mut().unwrap();

*last = !*last & mask;
}
}

fn all(&self) -> bool {
self.data[..self.length / 64].iter().all(|&x| x == u64::MAX) && {
let remainder = self.length % 64;

remainder == 0 || {
let mask = (1 << remainder) - 1;

*self.data.last().unwrap() == mask
}
}
}

fn one(&self) -> bool {
self.data.iter().any(|&x| x != 0)
}

fn count(&self) -> i32 {
self.data.iter().map(|x| x.count_ones()).sum::<u32>() as _
}

#[allow(clippy::inherent_to_string)] // Expected.
fn to_string(&self) -> String {
let mut result = String::with_capacity(self.length);

for &x in &self.data[..self.length / 64] {
result.extend((0..64).map(|i| char::from(b'0' + u8::from(x & (1 << i) != 0))));
}

let remainder = self.length % 64;

if remainder != 0 {
let x = *self.data.last().unwrap();

result.extend((0..remainder).map(|i| char::from(b'0' + u8::from(x & (1 << i) != 0))));
}

result
}
}

// ------------------------------------------------------ snip ------------------------------------------------------ //

impl super::Bitset for Bitset {
fn new(size: i32) -> Self {
Self::new(size)
}

fn fix(&mut self, idx: i32) {
self.fix(idx);
}

fn unfix(&mut self, idx: i32) {
self.unfix(idx);
}

fn flip(&mut self) {
self.flip();
}

fn all(&self) -> bool {
self.all()
}

fn one(&self) -> bool {
self.one()
}

fn count(&self) -> i32 {
self.count()
}

fn to_string(&self) -> String {
self.to_string()
}
}

#[cfg(test)]
mod tests {
#[test]
fn test_solution() {
super::super::tests::run::<super::Bitset>();
}
}
144 changes: 144 additions & 0 deletions src/problem_2166_design_bitset/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
pub mod dense_storage;

pub trait Bitset {
fn new(size: i32) -> Self;
fn fix(&mut self, idx: i32);
fn unfix(&mut self, idx: i32);
fn flip(&mut self);
fn all(&self) -> bool;
fn one(&self) -> bool;
fn count(&self) -> i32;
fn to_string(&self) -> String;
}

#[cfg(test)]
mod tests {
use super::Bitset;

#[allow(variant_size_differences)] // Expected.
enum Operation {
Fix(i32),
Unfix(i32),
Flip,
All(bool),
One(bool),
Count(i32),
ToString(&'static str),
}

const LONG_TEST_CASE: (i32, &[Operation]) = (
90,
&[
Operation::Unfix(0),
Operation::Unfix(62),
Operation::Count(0),
Operation::One(false),
Operation::ToString(
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
),
Operation::Count(0),
Operation::ToString(
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
),
Operation::Unfix(72),
Operation::Flip,
Operation::ToString(
"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
),
Operation::Flip,
Operation::Fix(11),
Operation::Unfix(80),
Operation::Unfix(80),
Operation::ToString(
"000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000",
),
Operation::Fix(55),
Operation::ToString(
"000000000001000000000000000000000000000000000000000000010000000000000000000000000000000000",
),
Operation::Fix(87),
Operation::Count(3),
Operation::Fix(61),
Operation::Unfix(0),
Operation::Flip,
Operation::Unfix(67),
Operation::Fix(40),
Operation::Flip,
Operation::Unfix(5),
Operation::Count(5),
Operation::Fix(14),
Operation::Count(6),
Operation::All(false),
Operation::All(false),
Operation::Unfix(69),
Operation::Flip,
Operation::All(false),
Operation::Count(84),
Operation::Count(84),
Operation::One(true),
Operation::Unfix(71),
Operation::One(true),
Operation::Count(83),
],
);

pub fn run<S: Bitset>() {
let test_cases = [
(
5,
&[
Operation::Fix(3),
Operation::Fix(1),
Operation::Flip,
Operation::All(false),
Operation::Unfix(0),
Operation::Flip,
Operation::One(true),
Operation::Unfix(0),
Operation::Count(2),
Operation::ToString("01010"),
] as &[_],
),
(
64,
&[
Operation::All(false),
Operation::ToString("0000000000000000000000000000000000000000000000000000000000000000"),
Operation::ToString("0000000000000000000000000000000000000000000000000000000000000000"),
Operation::ToString("0000000000000000000000000000000000000000000000000000000000000000"),
Operation::Count(0),
Operation::Fix(53),
Operation::ToString("0000000000000000000000000000000000000000000000000000010000000000"),
Operation::One(true),
Operation::All(false),
Operation::Count(1),
Operation::All(false),
Operation::Fix(26),
Operation::One(true),
Operation::All(false),
Operation::Count(2),
Operation::ToString("0000000000000000000000000010000000000000000000000000010000000000"),
Operation::Flip,
Operation::ToString("1111111111111111111111111101111111111111111111111111101111111111"),
],
),
LONG_TEST_CASE,
];

for (size, operations) in test_cases {
let mut bitset = S::new(size);

for operation in operations {
match *operation {
Operation::Fix(idx) => bitset.fix(idx),
Operation::Unfix(idx) => bitset.unfix(idx),
Operation::Flip => bitset.flip(),
Operation::All(expected) => assert_eq!(bitset.all(), expected),
Operation::One(expected) => assert_eq!(bitset.one(), expected),
Operation::Count(expected) => assert_eq!(bitset.count(), expected),
Operation::ToString(expected) => assert_eq!(bitset.to_string(), expected),
}
}
}
}
}

0 comments on commit 350f00e

Please sign in to comment.