You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
71 lines
2.5 KiB
71 lines
2.5 KiB
//! Space-efficient small maps and sets
|
|
//!
|
|
//! To make an entirely space efficient `Map` (i.e. size of each page is 256 bytes, there is never more than 1 page), the following must be true:
|
|
//!
|
|
//! * The key must be 8 bits wide and subject to the *null pointer optimisation*
|
|
//! * The value must be a ZST.
|
|
//!
|
|
//! This leaves pretty much only `std::num::NonZeroU8` and `std::num::NonZeroI8` as entirely space-efficient key candidates.
|
|
//! The restriction on values also means the only entirely space-efficient smallmaps are sets, enable to encode only if a key is present, with no extra information. (See `std::collections::HashSet`).
|
|
use super::*;
|
|
|
|
/// A set of only non-zero bytes.
|
|
///
|
|
/// This type is entirely space efficient and will only ever allocate `256` bytes of memory.
|
|
pub type NonZeroByteSet = Set<std::num::NonZeroU8>;
|
|
|
|
/// A set of non-zero signed 8-bit integers.
|
|
///
|
|
/// This type is entirely space efficient and will only ever allocate `256` bytes of memory.
|
|
pub type NonZeroI8Set = Set<std::num::NonZeroI8>;
|
|
|
|
/// A set of non-zero unsigned 8-bit integers.
|
|
///
|
|
/// This type is entirely space efficient and will only ever allocate `256` bytes of memory.
|
|
pub type NonZeroU8Set = NonZeroByteSet;
|
|
|
|
#[cfg(test)]
|
|
mod tests
|
|
{
|
|
use super::*;
|
|
|
|
/// Returns the currently allocated space of `map`.
|
|
pub fn space_of<K, V>(map: &Map<K,V>) -> usize
|
|
{
|
|
map.internal_size_bytes()
|
|
}
|
|
|
|
/// Check the allocation size of types in this module
|
|
mod allocsz {
|
|
use super::*;
|
|
|
|
/// Assert the allocated space (in bytes) of `map` is equal to `expected`.
|
|
pub fn assert_space_of<T, K, V>(map: T, expected: usize)
|
|
where T: std::borrow::Borrow<Map<K,V>>
|
|
{
|
|
let sz = space_of(map.borrow());
|
|
assert_eq!(sz, expected, "unexpected full allocated size of type {}: expected {expected}, got {sz}.", std::any::type_name::<Map<K,V>>());
|
|
}
|
|
|
|
/// Create a test that asserts the allocation size of a type is equal to a specific number of bytes
|
|
///
|
|
/// # Usage
|
|
/// ```
|
|
/// # use super::*;
|
|
/// size_test!(non_zero_byte_set, NonZeroByteSet, 256); // Creates a test function, named `non_zero_byte_set`, that asserts the type `NonZeroByteSet` allocates exactly 256 bytes.
|
|
/// ```
|
|
macro_rules! size_test {
|
|
($name:ident, $type:ty, $num:expr) => {
|
|
#[test]
|
|
fn $name() {
|
|
assert_space_of(<$type>::new(), $num);
|
|
}
|
|
}
|
|
}
|
|
|
|
size_test!(non_zero_byte_set, NonZeroByteSet, 256);
|
|
size_test!(non_zero_u8_set, NonZeroU8Set, 256);
|
|
size_test!(non_zero_i8_set, NonZeroI8Set, 256);
|
|
}
|
|
}
|