Merge pull request #3 from MarcusGrass/no-std-support

master
Avril 1 year ago committed by GitHub
commit 1a3887c560
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -17,10 +17,12 @@ panic = "unwind"
strip=true
[features]
default = ["std"]
std = []
# TODO: maybe add an FFI feature, to allow C projects to use it? idk if that's worth it really...
[dependencies]
serde = {version = "1.0.116", features = ["derive"], optional = true}
serde = {version = "1.0.116", default-features = false, features = ["derive", "alloc"], optional = true}
# TODO: optional smallvec feature: instead of heap-allocating the first page, it can be placed on the stack.

@ -33,7 +33,7 @@ where K: Collapse
/// Replace the held value with another, yielding the old one
pub fn insert(&mut self, value: V) -> V
{
std::mem::replace(&mut self.0.as_mut().unwrap().1, value)
core::mem::replace(&mut self.0.as_mut().unwrap().1, value)
}
/// Remove this entry from the `Map`, yielding the removed value
pub fn remove(self) -> V

@ -2,7 +2,7 @@
use super::*;
/// An iterator over `Page`s
pub struct Pages<'a, K, V>(pub(crate) std::slice::Iter<'a, Page<K,V>>);
pub struct Pages<'a, K, V>(pub(crate) core::slice::Iter<'a, Page<K,V>>);
impl<'a, K, V> Iterator for Pages<'a,K,V>
{
@ -18,7 +18,7 @@ impl<'a, K, V> Iterator for Pages<'a,K,V>
}
/// A mutable iterator over `Page`s
pub struct PagesMut<'a, K, V>(pub(crate) std::slice::IterMut<'a, Page<K,V>>);
pub struct PagesMut<'a, K, V>(pub(crate) core::slice::IterMut<'a, Page<K,V>>);
impl<'a, K, V> Iterator for PagesMut<'a,K,V>
{
@ -34,10 +34,10 @@ impl<'a, K, V> Iterator for PagesMut<'a,K,V>
}
impl<'a, K, V> ExactSizeIterator for PagesMut<'a,K,V>{}
impl<'a, K, V> std::iter::FusedIterator for PagesMut<'a,K,V>{}
impl<'a, K, V> core::iter::FusedIterator for PagesMut<'a,K,V>{}
/// An iterator over elements in a `Page`.
pub struct PageElements<'a, K, V>(pub(crate) std::slice::Iter<'a, Option<(K,V)>>);
pub struct PageElements<'a, K, V>(pub(crate) core::slice::Iter<'a, Option<(K,V)>>);
impl<'a, K, V> Iterator for PageElements<'a,K,V>
{
@ -57,10 +57,10 @@ impl<'a, K, V> Iterator for PageElements<'a,K,V>
(0, self.0.size_hint().1)
}
}
impl<'a, K, V> std::iter::FusedIterator for PageElements<'a,K,V>{}
impl<'a, K, V> core::iter::FusedIterator for PageElements<'a,K,V>{}
/// A mutable iterator over elements in a `Page`.
pub struct PageElementsMut<'a, K, V>(pub(crate) std::slice::IterMut<'a, Option<(K,V)>>);
pub struct PageElementsMut<'a, K, V>(pub(crate) core::slice::IterMut<'a, Option<(K,V)>>);
impl<'a, K, V> Iterator for PageElementsMut<'a,K,V>
{
@ -79,7 +79,7 @@ impl<'a, K, V> Iterator for PageElementsMut<'a,K,V>
(0, self.0.size_hint().1)
}
}
impl<'a, K, V> std::iter::FusedIterator for PageElementsMut<'a,K,V>{}
impl<'a, K, V> core::iter::FusedIterator for PageElementsMut<'a,K,V>{}
/// A consuming iterator over elements in a `Page`.
pub struct IntoPageElements<K,V>(pub(crate) [Option<(K,V)>; MAX], pub(crate) usize);
@ -104,7 +104,7 @@ impl<K,V> Iterator for IntoPageElements<K,V>
(0, Some(self.0.len()))
}
}
impl<K, V> std::iter::FusedIterator for IntoPageElements<K,V>{}
impl<K, V> core::iter::FusedIterator for IntoPageElements<K,V>{}
/// An iterator over entries in a `Map`.
pub struct Iter<'a, K, V>(pub(crate) Option<PageElements<'a,K,V>>, pub(crate) Pages<'a, K,V>);
@ -131,7 +131,7 @@ where K: Collapse
(0, self.1.size_hint().1.map(|x| x * MAX))
}
}
impl<'a, K: Collapse, V> std::iter::FusedIterator for Iter<'a, K,V>{}
impl<'a, K: Collapse, V> core::iter::FusedIterator for Iter<'a, K,V>{}
/// A mutable iterator over entries in a `Map`.
pub struct IterMut<'a, K, V>(pub(crate) Option<PageElementsMut<'a,K,V>>, pub(crate) PagesMut<'a, K,V>);
@ -158,10 +158,10 @@ where K: Collapse
(0, self.1.size_hint().1.map(|x| x * MAX))
}
}
impl<'a, K: Collapse, V> std::iter::FusedIterator for IterMut<'a, K,V>{}
impl<'a, K: Collapse, V> core::iter::FusedIterator for IterMut<'a, K,V>{}
/// A consuming iterator over entries in a `Map`.
pub struct IntoIter<K, V>(pub(crate) Option<IntoPageElements<K,V>>, pub(crate) std::vec::IntoIter<Page<K,V>>);
pub struct IntoIter<K, V>(pub(crate) Option<IntoPageElements<K,V>>, pub(crate) vec::IntoIter<Page<K,V>>);
impl<K, V> Iterator for IntoIter<K,V>
where K: Collapse
@ -187,7 +187,7 @@ where K: Collapse
}
}
impl<K: Collapse, V> std::iter::FusedIterator for IntoIter<K,V>{}
impl<K: Collapse, V> core::iter::FusedIterator for IntoIter<K,V>{}
#[cfg(test)]
mod tests

@ -26,16 +26,19 @@
//!
//! ### When not to use
//! Generally don't use this if your key would have a lot of collisions being represents in 8 bits, otherwise it might be a faster alternative to hash-based maps. You should check yourself before sticking with this crate instead of `std`'s vectorised map implementations.
#![cfg_attr(any(not(test), not(feature = "std")), no_std)]
#![cfg_attr(nightly, feature(test))]
#![cfg_attr(nightly, feature(drain_filter))]
#![cfg_attr(nightly, feature(never_type))]
#[cfg(nightly)] extern crate test;
#[cfg(all(nightly, test))] extern crate test;
extern crate alloc;
const MAX: usize = 256;
use std::borrow::Borrow;
use alloc::vec;
use alloc::vec::Vec;
use core::borrow::Borrow;
pub mod iter;
use iter::*;
@ -138,7 +141,7 @@ where K: Collapse
/// This is a count that iterates over all slots, if possible store it in a temporary instead of re-calling it many times.
pub fn len(&self) -> usize
{
self.0.iter().map(Option::as_ref).filter_map(std::convert::identity).count()
self.0.iter().map(Option::as_ref).filter_map(core::convert::identity).count()
}
/// An iterator over all entries currently in this page
@ -166,11 +169,11 @@ where K: Collapse
fn replace(&mut self, k: K, v: V) -> Option<(K,V)>
{
std::mem::replace(&mut self.0[usize::from(k.collapse())], Some((k,v)))
core::mem::replace(&mut self.0[usize::from(k.collapse())], Some((k,v)))
}
}
impl<K: Collapse, V> std::iter::FromIterator<(K, V)> for Map<K,V>
impl<K: Collapse, V> core::iter::FromIterator<(K, V)> for Map<K,V>
{
fn from_iter<I: IntoIterator<Item=(K, V)>>(iter: I) -> Self
{
@ -210,10 +213,50 @@ where K: Collapse
/// A small hashtable-like map with byte sized key indecies.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature="serde", derive(serde::Serialize, serde::Deserialize))]
// TODO: Replace with `SmallVec<[Page<TKey, TValue>; 1]>` when feature that adds `smallvec` is enabled (this will allocate the first page on the stack, and the rest on the heap.
pub struct Map<TKey, TValue>(Vec<Page<TKey,TValue>>);
#[cfg(feature = "serde")]
struct MapVisitor<TKey, TValue> {
_pd: core::marker::PhantomData<(TKey, TValue)>,
}
#[cfg(feature = "serde")]
impl<'de, TKey, TValue> serde::de::Deserialize<'de> for Map<TKey, TValue> where TKey: Collapse + serde::Deserialize<'de>, TValue: serde::Deserialize<'de> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
deserializer.deserialize_map(MapVisitor { _pd: core::marker::PhantomData::default() })
}
}
/// Just taken from [serde.rs' examples](https://serde.rs/deserialize-map.html)
#[cfg(feature = "serde")]
impl<'de, TKey, TValue> serde::de::Visitor<'de> for MapVisitor<TKey, TValue> where TKey: Collapse + serde::Deserialize<'de>, TValue: serde::Deserialize<'de> {
type Value = Map<TKey, TValue>;
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
formatter.write_str("A map")
}
fn visit_map<A>(self, mut access: A) -> Result<Self::Value, A::Error> where A: serde::de::MapAccess<'de> {
let mut map = Map::with_capacity(access.size_hint().unwrap_or(1));
while let Some((key, value)) = access.next_entry()? {
map.insert(key, value);
}
Ok(map)
}
}
#[cfg(feature = "serde")]
impl<TKey, TValue> serde::Serialize for Map<TKey, TValue> where TKey: Collapse + serde::Serialize, TValue: serde::Serialize {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
let mut m = serializer.serialize_map(Some(self.len()))?;
for (k, v) in self.iter() {
m.serialize_entry(k, v)?;
}
m.end()
}
}
impl<K,V> Map<K,V>
{
/// Returns the currently allocated size of the map in bytes (including currently unused reserved space.)
@ -221,8 +264,8 @@ impl<K,V> Map<K,V>
#[allow(dead_code)] // Used in test cases, but compiler still warns about it
pub(crate) fn internal_size_bytes(&self) -> usize
{
self.0.capacity() * std::mem::size_of::<Page<K,V>>()
//self.0.iter().map(std::mem::size_of_val).sum::<usize>()
self.0.capacity() * core::mem::size_of::<Page<K,V>>()
//self.0.iter().map(core::mem::size_of_val).sum::<usize>()
}
}
@ -432,7 +475,7 @@ where K: Collapse
{
match page.search_mut(&key) {
Some((ref ok, ov)) if ok.eq(&key) => {
return Some(std::mem::replace(ov, value));
return Some(core::mem::replace(ov, value));
},
empty @ None => {
return empty.replace((key, value))
@ -484,7 +527,7 @@ impl<K: Collapse, V> IntoIterator for Map<K,V>
}
}
impl<K: Collapse, V> std::iter::Extend<(K,V)> for Map<K,V>
impl<K: Collapse, V> core::iter::Extend<(K,V)> for Map<K,V>
{
fn extend<T: IntoIterator<Item = (K,V)>>(&mut self, iter: T) {
// we can probably optimise this better, right?
@ -495,8 +538,10 @@ impl<K: Collapse, V> std::iter::Extend<(K,V)> for Map<K,V>
}
}
use std::hash::{Hash, Hasher,};
use std::ops::{Index, IndexMut};
use core::hash::{Hash, Hasher,};
use core::ops::{Index, IndexMut};
#[cfg(feature = "serde")]
use serde::ser::SerializeMap;
impl<T: ?Sized + Hash + Eq> Collapse for T
{

@ -1,6 +1,6 @@
//! Because we can't #derive big arrays on stable smh
use super::*;
use std::{
use core::{
fmt::{self, Debug,},
hash,
};
@ -49,7 +49,7 @@ impl<K: hash::Hash, V: hash::Hash> hash::Hash for Page<K,V> {
#[cfg(feature="serde")]
const _: () = {
use serde::*;
use std::marker::PhantomData;
use core::marker::PhantomData;
impl<K,V> serde::Serialize for Page<K,V>
where K:Serialize, V: Serialize
@ -93,7 +93,7 @@ const _: () = {
Ok(Page(elems))
} else {
use serde::de::Error;
Err(A::Error::custom(format!("Expected {} elemts, got {}", MAX, i)))
Err(A::Error::custom(alloc::format!("Expected {} elemts, got {}", MAX, i)))
}
}
}

@ -6,7 +6,7 @@
//!
//! If/when Rust gets specialisation, this will be unneeded.
use super::*;
use std::num::*;
use core::num::*;
/// Sealed trait allowing for wrapping primitive types with a more efficient implemntation for the `Collapse` trait.
/// This should not be used for much directly, instead use the newtype shim `Primitive<T>`.

@ -12,12 +12,12 @@ 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>;
pub type NonZeroByteSet = Set<core::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>;
pub type NonZeroI8Set = Set<core::num::NonZeroI8>;
/// A set of non-zero unsigned 8-bit integers.
///

Loading…
Cancel
Save