Skip to content

Bit is the loneliest number that you'll ever do, Two can be as bad as one -- it's the loneliest number, shifted one.

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE_APACHE
MIT
LICENSE_MIT
Notifications You must be signed in to change notification settings

cubicle-jockey/cj_bitmask_vec

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

85 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cj_bitmask_vec

Rust Dependency Review Crate API

BitmaskVec is a vector that pairs bitmasks with T. Bitmasks u8 through u128 are supported.

Items can be added with or without supplying bitmasks. The bitmask will default to zero if not supplied.

Filtering iterator using bitmasks:

// filtering by bitmask
fn main() {
    use cj_bitmask_vec::prelude::*;

    let mut v = BitmaskVec::<u8, i32>::new();
    // Bitmasks hold whatever meaning the developer gives them.
    // In this example any u8 is a valid bitmask.
    //                (bitmask)  (T)      
    v.push_with_mask(0b00000000, 100);
    v.push_with_mask(0b00000010, 101);
    v.push_with_mask(0b00000011, 102);
    v.push_with_mask(0b00000100, 103);
    v.push_with_mask(0b00000110, 104);
    v.push(105);  // <- the bitmask will default to zero
    // or an easier way to add items   
    v += (0b00000000, 106);
    v += (0b00010000, 107);
    v += (0b00100000, 108);
    v += (0b00000100, 109);
    v += (0b10000001, 110);
    v += (0b00000001, 111);
    v += (0b00000000, 112);
    v += 113; // <- bitmask will default to zero

    assert_eq!(v[6], 106);

    // here we're going to iterate over all items that have bitmask bit 1 set
    let mut count = 0;
    let mut iter = v.iter_with_mask();
    //                                (mask with bit 1 set)
    //                                               V
    while let Some(pair) = iter.filter_mask(&0b00000010) {
        // only items 101, 102, and 104 in the Vec above have
        // bitmask bit 1 set.
        assert!([101, 102, 104].contains(&pair.item));
        count += 1;
    }
    assert_eq!(count, 3);
}

Iterating over T:

fn main() {
    use cj_bitmask_vec::prelude::*;

    let mut v = BitmaskVec::<u8, i32>::new();
    v.push_with_mask(0b00000000, 100);
    v.push_with_mask(0b00000010, 101);
    v.push_with_mask(0b00000010, 102);
    v.push_with_mask(0b00000110, 103);
    v.push_with_mask(0b00000001, 104);
    v.push_with_mask(0b00000001, 105);
    v.push_with_mask(0b00000000, 106);

    let mut total = 0;
    // iter excludes the bitmask
    for x in v.iter() {
        total += x;
    }
    assert_eq!(total, 721);
}

Iterating over T and bitmask:

fn main() {
    use cj_bitmask_vec::prelude::*;
    use cj_common::prelude::CjMatchesMask;

    let mut v = BitmaskVec::<u8, i32>::new();
    v.push_with_mask(0b00000000, 100);
    v.push_with_mask(0b00000010, 101);
    v.push_with_mask(0b00000010, 102);
    v.push_with_mask(0b00000110, 103);
    v.push_with_mask(0b00000001, 104);
    v.push_with_mask(0b00000001, 105);
    v.push_with_mask(0b00000000, 106);

    let mut total = 0;
    for x in v.iter_with_mask() {
        if x.matches_mask(&0b00000010) {
            total += x.item;
        }
    }
    assert_eq!(total, 306);
}

Mutably iterating over T:

fn main() {
    use cj_bitmask_vec::prelude::*;

    let mut v = BitmaskVec::<u8, i32>::new();
    v.push_with_mask(0b00000000, 100);
    v.push_with_mask(0b00000010, 101);
    v.push_with_mask(0b00000010, 102);
    v.push_with_mask(0b00000100, 103);
    v.push_with_mask(0b00000011, 104);
    v.push_with_mask(0b00000001, 105);
    v.push_with_mask(0b00000000, 106);

    let mut total = 0;
    // iter_mut excludes the bitmask
    let x = v.iter_mut();
    for z in x {
        // here we modify T
        total += *z;
        *z *= 2;
    }

    // verify the changes from above
    let mut total_2 = 0;
    let x = v.iter();
    for z in x {
        total_2 += *z;
    }

    assert_eq!(total_2, total * 2);
}

Mutably iterating over T and bitmask:

fn main() {
    use cj_bitmask_vec::prelude::*;
    use cj_common::prelude::{Bitflag, CjMatchesMask};

    let mut v = BitmaskVec::<u8, i32>::new();
    v.push_with_mask(0b00000000, 100);
    v.push_with_mask(0b00000010, 101);
    v.push_with_mask(0b00000010, 102);
    v.push_with_mask(0b00000100, 103);
    v.push_with_mask(0b00000011, 104);
    v.push_with_mask(0b00000001, 105);
    v.push_with_mask(0b00000000, 106);

    let mut total = 0;
    let x = v.iter_with_mask_mut();
    for z in x {
        total += z.item;
        // here we modify T
        z.item *= 2;

        // here we modify the 8th bit of the bitmask.
        // - Note that set_bit() only modifies a single bit,
        //   leaving the rest of the bitmask unchanged.
        z.bitmask.set_bit(7, true);
    }

    // verify the changes from above
    let mut total_2 = 0;
    let x = v.iter_with_mask();
    for z in x {
        total_2 += z.item;
        // test that the 8th bit is now set.
        assert!(z.matches_mask(&0b10000000));
    }
    // test that T was modified
    assert_eq!(total_2, total * 2);
}

Filtering Methods

BitmaskVec provides convenient filtering methods that return iterators over items matching specific bitmasks:

filtered() - Filter items only

Returns an iterator over items (T) that match the given bitmask:

fn main() {
    use cj_bitmask_vec::prelude::*;

    let mut tasks = BitmaskVec::<u8, String>::new();
    
    const ACTIVE: u8 = 0b00000001;
    const INACTIVE: u8 = 0b00000010;
    const COMPLETED: u8 = 0b00000100;
    
    tasks.push_with_mask(ACTIVE, "Write documentation".to_string());
    tasks.push_with_mask(INACTIVE, "Review code".to_string());
    tasks.push_with_mask(ACTIVE, "Run tests".to_string());
    tasks.push_with_mask(COMPLETED, "Deploy to production".to_string());
    
    // Get all active tasks
    let active_tasks: Vec<&String> = tasks.filtered(&ACTIVE).collect();
    assert_eq!(active_tasks.len(), 2);
    println!("Active tasks: {:?}", active_tasks);
}

filtered_mut() - Filter and modify items

Returns a mutable iterator over items (T) that match the given bitmask:

fn main() {
    use cj_bitmask_vec::prelude::*;

    let mut scores = BitmaskVec::<u8, i32>::new();
    
    const BONUS_ELIGIBLE: u8 = 0b00000001;
    const REGULAR: u8 = 0b00000010;
    
    scores.push_with_mask(BONUS_ELIGIBLE, 85);
    scores.push_with_mask(REGULAR, 75);
    scores.push_with_mask(BONUS_ELIGIBLE, 92);
    scores.push_with_mask(REGULAR, 68);
    
    // Apply bonus to eligible scores
    for score in scores.filtered_mut(&BONUS_ELIGIBLE) {
        *score += 10; // Add 10 point bonus
    }
    
    assert_eq!(scores[0], 95); // 85 + 10
    assert_eq!(scores[1], 75); // unchanged
    assert_eq!(scores[2], 102); // 92 + 10
    assert_eq!(scores[3], 68); // unchanged
}

filtered_with_mask() - Filter with access to bitmasks

Returns an iterator over BitmaskItem objects that match the given bitmask:

fn main() {
    use cj_bitmask_vec::prelude::*;

    let mut tasks = BitmaskVec::<u8, String>::new();
    
    const URGENT: u8 = 0b00000001;
    const NORMAL: u8 = 0b00000010;
    const LOW: u8 = 0b00000100;
    const ARCHIVED: u8 = 0b00001000;
    
    tasks.push_with_mask(URGENT, "Fix critical bug".to_string());
    tasks.push_with_mask(NORMAL, "Update documentation".to_string());
    tasks.push_with_mask(URGENT | LOW, "Refactor old code".to_string());
    tasks.push_with_mask(URGENT | ARCHIVED, "Legacy system issue".to_string());
    
    // Process urgent tasks and check their additional flags
    for task_item in tasks.filtered_with_mask(&URGENT) {
        println!("Urgent task: {}", task_item.item);
        if task_item.matches_mask(&ARCHIVED) {
            println!("  -> This is an archived urgent task");
        }
        if task_item.matches_mask(&LOW) {
            println!("  -> This urgent task also has low priority");
        }
    }
}

filtered_with_mask_mut() - Filter and modify items with bitmasks

Returns a mutable iterator over BitmaskItem objects that match the given bitmask:

fn main() {
    use cj_bitmask_vec::prelude::*;

    let mut tasks = BitmaskVec::<u8, String>::new();
    
    const PENDING: u8 = 0b00000001;
    const PROCESSING: u8 = 0b00000010;
    const COMPLETED: u8 = 0b00000100;
    
    tasks.push_with_mask(PENDING, "Task A".to_string());
    tasks.push_with_mask(PENDING, "Task B".to_string());
    tasks.push_with_mask(COMPLETED, "Task C".to_string());
    
    // Start processing all pending tasks
    for task_item in tasks.filtered_with_mask_mut(&PENDING) {
        // Update the task status
        task_item.set_mask(PROCESSING);
        // Modify the task name to show progress
        task_item.item.push_str(" (in progress)");
    }
    
    // Verify the changes
    assert_eq!(tasks[0], "Task A (in progress)");
    assert_eq!(tasks[1], "Task B (in progress)");
    assert_eq!(tasks[2], "Task C"); // unchanged
}

Benchmarks

This crate includes comprehensive benchmarks to measure the performance of various BitmaskVec operations. The benchmarks cover:

  • Basic Operations: new(), with_capacity(), push(), push_with_mask()
  • Indexing Operations: Index access, pop(), pop_with_mask()
  • Iteration Operations: iter(), iter_with_mask(), iter_mut(), iter_with_mask_mut()
  • Filtering Operations: filter_mask(), mask matching during iteration
  • Collection Operations: append(), clear(), resize(), resize_with_mask()
  • Different Bitmask Types: Performance comparison across u8, u16, u32, and u64 bitmasks

Running Benchmarks

To run the benchmarks:

cargo bench

This will run all benchmarks and generate detailed performance reports. The benchmarks test with different data sizes (100, 1000, and 10000 elements) to show how performance scales.

Benchmark Results

The benchmarks will generate HTML reports (if you have gnuplot installed) in the target/criterion/ directory, providing detailed performance analysis including:

  • Timing measurements with statistical analysis
  • Performance comparisons across different input sizes
  • Regression detection across benchmark runs
  • Detailed plots and charts (with gnuplot)

Changelog

Version 1.2.0

  • Added filtered() method for filtering items by bitmask
  • Added filtered_mut() method for mutable filtering of items by bitmask
  • Added filtered_with_mask() method for filtering with access to both items and bitmasks
  • Added filtered_with_mask_mut() method for mutable filtering with access to both items and bitmasks
  • Enhanced documentation with comprehensive examples for all filtering methods
  • Added benchmarks for all new filtering methods

About

Bit is the loneliest number that you'll ever do, Two can be as bad as one -- it's the loneliest number, shifted one.

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE_APACHE
MIT
LICENSE_MIT

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •  

Languages