bitstring/bit_string.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
use core::cmp::{
min,
Ordering,
};
/// A bit string with variable (but possibly limited) length.
///
/// The length limit might depend on the current string; that is why
/// writing a bit might truncate the string (but not the bit that was
/// just modified). "Writing" a bit also includes writing without
/// actually changing it.
///
/// This special case is needed to handle variants with different
/// (maximum) lengths: a small prefix indicates the variant, then
/// follows the actual data of the variant.
///
/// As an example one might want to combine IPv4 and IPv6 cidr
/// representations into one `BitString` type; the empty bit string
/// would represent `0.0.0.0/0` + `::/0`.
///
/// Apart from this special case writing a bit must not modify any other
/// bits or change the length.
///
/// The required `Eq` implementation must match comparing two bitstrings
/// by their bits (up to their length); i.e. `BitString`s must not carry
/// additional data apart from the bits (and mustn't compare unused
/// bits in the storage if their value isn't fixed).
#[allow(clippy::len_without_is_empty)]
pub trait BitString: Eq {
/// Get the `ndx`th bit.
///
/// # Panics
///
/// Should panic if `ndx >= self.len()`.
fn get(&self, ndx: usize) -> bool;
/// Set the `ndx`th bit to `bit`.
///
/// Might clip the length to `ndx+1`.
///
/// # Panics
///
/// Should panic if `ndx >= self.len()`.
fn set(&mut self, ndx: usize, bit: bool);
/// Flips the `ndx`th bit.
///
/// # Panics
///
/// Should panic if `ndx >= self.len()`.
fn flip(&mut self, ndx: usize);
/// Current length of the bit string in bits.
#[allow(clippy::len_without_is_empty)]
fn len(&self) -> usize;
/// Set current length to `len`.
///
/// Does nothing if `len <= self.len()`.
///
/// If necessary should also zero the underlying storage if `Eq`
/// needs it to work properly.
fn clip(&mut self, len: usize);
/// Append a bit.
///
/// # Panics
///
/// Might panic if underlying storage can only store a limited
/// number of bits.
fn append(&mut self, bit: bool);
/// Create a new zero-length bit string.
///
/// Underlying storage should be zeroed if `Eq` needs it to work
/// properly.
fn null() -> Self;
/// Length of the longest shared prefix of two bit strings.
fn shared_prefix_len(&self, other: &Self) -> usize {
let max_len = min(self.len(), other.len());
for i in 0..max_len {
if self.get(i) != other.get(i) {
return i;
}
}
max_len
}
/// Longest shared prefix of two bit strings.
fn shared_prefix(&self, other: &Self) -> Self
where
Self: Clone,
{
let mut a = self.clone();
a.clip(self.shared_prefix_len(other));
a
}
/// Partial ordering on bit strings.
///
/// Formal definition:
///
/// ```text
/// `a < b` iff `a != b` and `b` is a prefix of `a`
/// ```
///
/// If you view a bit string as a set including all bit strings
/// starting with it, this is the subset relation.
fn subset_cmp(&self, other: &Self) -> Option<Ordering> {
let spl = self.shared_prefix_len(other);
if spl == self.len() {
// self is a prefix of other
if spl == other.len() {
Some(Ordering::Equal)
} else {
Some(Ordering::Greater)
}
} else if spl == other.len() {
// other is a prefix of self
Some(Ordering::Less)
} else {
// neither is a prefix of the other one
None
}
}
/// Lexicographic ordering on bit strings.
///
/// Formal definition:
///
/// ```text
/// `a < b` iff `a != b` and (
/// `b` is a prefix of `a`
/// or `a[s] < b[s]`
/// where s is the smallest index with `a[s] != b[s]`)
/// ```
///
/// Or, if you define `_|_ < false < true`:
///
/// ```text
/// `a < b` iff `a[s] < b[s]`
/// where s is the smallest index with `a[s] != b[s]`
/// ```
fn lexicographic_cmp(&self, other: &Self) -> Ordering {
let spl = self.shared_prefix_len(other);
if spl == self.len() {
// self is a prefix of other
if spl == other.len() {
Ordering::Equal
} else {
// self is shorter than other
Ordering::Less
}
} else if spl == other.len() {
// other is a prefix of self and shorter
Ordering::Greater
} else {
// both are at least one bit longer than the shared prefix,
// and they differ in that bit (otherwise shared prefix
// would be longer)
if self.get(spl) {
Ordering::Greater
} else {
Ordering::Less
}
}
}
}