superset_map

B-tree-backed map whose keys are distinct supersets.
git clone https://git.philomathiclife.com/repos/superset_map
Log | Files | Refs | README

README.md (5511B)


      1 # `superset_map`
      2 
      3 `superset_map` is a library for `Set`s that have an order defined on them. Its main data structure is
      4 `SupersetMap` which is a specialized version of `BTreeMap` where only supersets are stored. This can be
      5 useful when the keys don't fit well or at all with the concept of `RangeBounds`.
      6 
      7 Nightly Rust is required. Once
      8 [`BTreeMap` cursors are stabilized](https://github.com/rust-lang/rust/issues/107540), stable Rust will work.
      9 
     10 ## Example
     11 
     12 ```rust
     13 use core::{borrow::Borrow, cmp::Ordering};
     14 use superset_map::{zfc::{num_bigint::BigUint, BoundedCardinality, Cardinality, Set}, SetOrd, SupersetSet};
     15 #[derive(Clone, Copy, Eq, PartialEq)]
     16 struct ShortAscii<'a> {
     17     val: &'a [u8],
     18 }
     19 impl<'a> ShortAscii<'a> {
     20     fn new(val: &'a [u8]) -> Option<ShortAscii<'a>> {
     21         (val.len() <= 255 && val.is_ascii()).then_some(Self { val })
     22     }
     23     fn len(self) -> u8 {
     24         self.val.len().try_into().expect("The ShortAscii instance was not constructed properly and contains more than 255 bytes.")
     25     }
     26 }
     27 #[derive(Clone, Copy, Eq, PartialEq)]
     28 enum WildcardAscii<'a> {
     29     Plain(ShortAscii<'a>),
     30     // Represents a ShortAscii<'a> with an implicit wildcard at the end
     31     // meaning it's all ShortAscii<'a>s that begin with the contained ShortAscii<'a>.val.
     32     Wildcard(ShortAscii<'a>),
     33 }
     34 impl<'a> WildcardAscii<'a> {
     35     const fn val(self) -> ShortAscii<'a> {
     36         match self {
     37             WildcardAscii::Plain(s) | WildcardAscii::Wildcard(s) => s,
     38         }
     39     }
     40     const fn is_plain(self) -> bool {
     41         match self {
     42             WildcardAscii::Plain(_) => true,
     43             WildcardAscii::Wildcard(_) => false,
     44         }
     45     }
     46     const fn is_wildcard(self) -> bool {
     47         !self.is_plain()
     48     }
     49 }
     50 impl<'a> PartialOrd<Self> for WildcardAscii<'a> {
     51     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
     52         Some(self.cmp(other))
     53     }
     54 }
     55 impl<'a> Ord for WildcardAscii<'a> {
     56     fn cmp(&self, other: &Self) -> Ordering {
     57         let len = u8::min(self.val().len(), other.val().len()) as usize;
     58         match self.val().val[..len].cmp(&other.val().val[..len]) {
     59             Ordering::Less => Ordering::Less,
     60             Ordering::Equal => {
     61                 if self.is_wildcard() {
     62                     if other.is_wildcard() {
     63                         self.val().len().cmp(&other.val().len()).reverse()
     64                     } else {
     65                         Ordering::Greater
     66                     }
     67                 } else if other.is_wildcard() {
     68                     Ordering::Less
     69                 } else {
     70                     self.val().len().cmp(&other.val().len())
     71                 }
     72             }
     73             Ordering::Greater => Ordering::Greater,
     74         }
     75     }
     76 }
     77 impl<'a> Set for WildcardAscii<'a> {
     78     type Elem = ShortAscii<'a>;
     79     fn bounded_cardinality(&self) -> BoundedCardinality {
     80         BoundedCardinality::new_exact(self.cardinality().unwrap())
     81     }
     82     fn cardinality(&self) -> Option<Cardinality> {
     83         Some(Cardinality::Finite(match *self {
     84             WildcardAscii::Plain(_) => BigUint::new(vec![1]),
     85             // Geometric series.
     86             WildcardAscii::Wildcard(v) => {
     87                 (BigUint::new(vec![128]).pow((u8::MAX - v.len()) as u32 + 1)
     88                     - BigUint::new(vec![1]))
     89                     / BigUint::new(vec![127])
     90             }
     91         }))
     92     }
     93     fn contains<Q>(&self, elem: &Q) -> bool
     94     where
     95         Q: Borrow<Self::Elem> + Eq + ?Sized,
     96     {
     97         match *self {
     98             WildcardAscii::Plain(v) => v == *elem.borrow(),
     99             WildcardAscii::Wildcard(v) => {
    100                 v.len() <= elem.borrow().len() && *v.val == elem.borrow().val[..v.len() as usize]
    101             }
    102         }
    103     }
    104     fn is_proper_subset(&self, val: &Self) -> bool {
    105         val.is_wildcard()
    106             && match val.val().len().cmp(&self.val().len()) {
    107                 Ordering::Less => val.val().val == &self.val().val[..val.val().len() as usize],
    108                 Ordering::Equal => self.is_plain() && self.val() == val.val(),
    109                 Ordering::Greater => false,
    110             }
    111     }
    112     fn is_subset(&self, val: &Self) -> bool {
    113         self == val || self.is_proper_subset(val)
    114     }
    115 }
    116 impl<'a> SetOrd for WildcardAscii<'a> {}
    117 fn main() {
    118     let mut set = SupersetSet::new();
    119     set.insert(WildcardAscii::Plain(ShortAscii::new(b"foo").unwrap()));
    120     set.insert(WildcardAscii::Plain(ShortAscii::new(b"bar").unwrap()));
    121     set.insert(WildcardAscii::Wildcard(ShortAscii::new(b"b").unwrap()));
    122     set.insert(WildcardAscii::Wildcard(ShortAscii::new(b"bar").unwrap()));
    123     let mut iter = set.into_iter();
    124     assert!(iter.next().map_or(false, |s| s
    125         == WildcardAscii::Wildcard(ShortAscii::new(b"b").unwrap())));
    126     assert!(iter.next().map_or(false, |s| s
    127         == WildcardAscii::Plain(ShortAscii::new(b"foo").unwrap())));
    128     assert!(iter.next().is_none());
    129 }
    130 ```
    131 
    132 ## License
    133 
    134 Licensed under either of
    135 
    136 * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0).
    137 * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT).
    138 
    139 at your option.
    140 
    141 ## Contribution
    142 
    143 Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you,
    144 as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
    145 
    146 ### Status
    147 
    148 The crate is only tested on `x86_64-unknown-linux-gnu` and `x86_64-unknown-openbsd` targets, but it should work
    149 on most platforms.