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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
use std::fmt::{Debug,Formatter};
use std::collections::{HashSet,BTreeSet};

/// Set-like data structure for storing u8 elements. Cannot contains values >= 64.
#[derive(Copy,Clone,Serialize,Deserialize,Eq,PartialEq)]
pub struct LilBitSet {
    bits : u64,
}

impl LilBitSet {
    const VALUE_LIMIT : u8 = 63;

    #[inline]
    fn mask() -> u64 { ::std::u64::MAX }
    #[inline]

    /// Creates a new, empty `LilBitSet`.
    pub fn new() -> LilBitSet { LilBitSet {bits : 0} }
    #[inline]
    /// Returns the largest u8 values that IS permitted to be inserted.
    pub fn largest_allowed() -> u8 { Self::VALUE_LIMIT } 
    #[inline]
    /// Constructs a LilBitSet from a `u64`. The indices of positive
    /// bits refers to the presence of a u8 in the set. ie '...1010'
    /// binary for 10 will represent the set {1,3}.
    pub fn new_from_raw(raw: u64) -> Self { LilBitSet {bits: raw} }
    #[inline]
    /// Inverse of `new_from_raw`
    pub fn into_raw(self) -> u64 { self.bits }

    /// Included only as it is a common function for the HashSet. Here it simply
    /// wraps `contains`.
    /// # Panics
    /// panics when element > Self::largest_allowed().
    pub fn get(&self, element: u8) -> Option<u8> {
        if self.contains(element) {
            Some(element)
        } else {
            None
        }
    }

    #[inline]
    /// Returns true IFF the given `u8` is in the set.
    /// # Panics
    /// panics when element > Self::largest_allowed().
    pub fn contains(&self, element : u8) -> bool {
        Self::check_element_is_ok(element);
        ! self.is_empty() //checking this is lightning fast
        && ((1 << element) & self.bits) > 0
    }

    #[inline]
    /// Returns true IFF the set is empty (contains no values).
    pub fn is_empty(&self) -> bool { self.bits == 0 }

    /// Of course this set is not unqiue in its finite value-space for set elements.
    /// However, as there is the additional restriction of x <= Self::largest_allowed()
    /// for any element x, the UNIVERSE of missing elements can be useful
    pub fn universe() -> LilBitSet {
        LilBitSet { bits: Self::mask() }
    }

    #[inline]
    fn check_element_is_ok(element: u8) {
        if element > Self::VALUE_LIMIT {
            panic!("LilBitSet incapable of handling a u8 of that size!");
        }
    }

    /// Attempts to insert the given `u8` into the set. Returns `true` IFF successful.
    /// # Panics
    /// panics when element > Self::largest_allowed().
    pub fn insert(&mut self, element: u8) -> bool {
        Self::check_element_is_ok(element);
        let had = self.contains(element);
        self.bits |= 1 << element;
        !had
    }

    /// Attempts to remove a given `u8` from the set. Returns `true` IFF successful.
    /// # Panics
    /// panics when element >= Self::largest_allowed().
    pub fn remove(&mut self, element: u8) -> bool {
        Self::check_element_is_ok(element);
        let had = self.contains(element);
        self.bits &= Self::mask() - (1 << element);
        had
    }

    /// Returns the set union of this, and the given `LilBitSet`.
    pub fn union(&self, other: &Self) -> Self {
        LilBitSet { bits: self.bits | other.bits }
    }

    /// Returns the set itersection of this, and the given `LilBitSet`.
    pub fn itersection(&self, other: &Self) -> Self {
        LilBitSet { bits: self.bits & other.bits }
    }

    /// Returns the set cardinality (number of elements of the set).
    pub fn len(&self) -> usize {
        self.into_iter().count()
    }

    /// Returns the set symmetric difference of this, and the given `LilBitSet`.
    pub fn symmetric_difference(&self, other: &Self) -> Self {
        LilBitSet { bits: self.bits ^ other.bits }
    }

    /// Relying on `Self::universe()`, this function can be useful in reasoning
    /// over _missing_ elements in a more convenient way
    pub fn complement(&self) -> LilBitSet {
        LilBitSet { bits: Self::mask() - self.bits }
    }

}

impl Into<HashSet<u8>> for LilBitSet {
    fn into(self) -> HashSet<u8> { self.into_iter().collect() }
}
impl Into<BTreeSet<u8>> for LilBitSet {
    fn into(self) -> BTreeSet<u8> { self.into_iter().collect() }
}

impl Into<LilBitSet> for HashSet<u8> {
    fn into(self) -> LilBitSet { self.into_iter().collect() }
}
impl Into<LilBitSet> for BTreeSet<u8> {
    fn into(self) -> LilBitSet { self.into_iter().collect() }
}


impl Debug for LilBitSet {
    fn fmt(&self, f: &mut Formatter) -> Result<(), ::std::fmt::Error> {
        let mut first = true;
        write!(f, "{{")?;
        for value in 0..64 {
            if self.contains(value) {
                if !first {
                    write!(f, ",")?;
                } else {
                    first = false;
                }
                write!(f, "{:?}", value)?;
            }
        }
        write!(f, "}}")
    }
}

impl IntoIterator for LilBitSet {
    type Item = u8;
    type IntoIter = IntoIter;

    fn into_iter(self) -> Self::IntoIter {
        IntoIter { bit_set: self, index: 0 }
    }
}


/// Iterator over elements inside a `LilBitSet`.
pub struct IntoIter {
    bit_set : LilBitSet,
    index : u8,
}

impl Iterator for IntoIter {
    type Item = u8;
    fn next(&mut self) -> Option<u8> {
        while self.index <= LilBitSet::VALUE_LIMIT {
            self.index += 1;
            if self.bit_set.contains(self.index-1) {
                return Some(self.index-1)
            }
        }
        None
    }
}

impl ::std::iter::FromIterator<u8> for LilBitSet {
    fn from_iter<I: IntoIterator<Item=u8>>(iter: I) -> Self {
        let mut lilbitset = LilBitSet::new();
        for i in iter {
            lilbitset.insert(i);
        }
        lilbitset
    }
}

impl<'a> ::std::iter::FromIterator<&'a u8> for LilBitSet {
    fn from_iter<I: IntoIterator<Item=&'a u8>>(iter: I) -> Self {
        let mut lilbitset = LilBitSet::new();
        for i in iter {
            lilbitset.insert(*i);
        }
        lilbitset
    }
}

#[macro_export]
/// This code is adapted from github.com/bluss/maplit (MIT license)
macro_rules! lilbits {
    (@single $($x:tt)*) => (());
    (@count $($rest:expr),*) => (<[()]>::len(&[$(lilbits!(@single $rest)),*]));

    ($($key:expr,)+) => { lilbits!($($key),+) };
    ($($key:expr),*) => {
        {
            let _cap = lilbits!(@count $($key),*);
            let mut _set = LilBitSet::new();
            $(
                let _ = _set.insert($key);
            )*
            _set
        }
    };
}