use std::{cell::RefCell, marker::PhantomData};
#[doc(hidden)]
#[cfg(feature = "serde")]
pub use serde;
pub trait Key: Clone + Copy + From<DefaultKey> + Into<DefaultKey> {
fn index(self) -> usize;
}
#[derive(Clone, Copy, Debug)]
pub struct DefaultKey {
chunk_idx: u32,
value_idx: u32,
}
impl DefaultKey {
fn new(chunk_idx: usize, value_idx: usize) -> Self {
Self {
chunk_idx: u32::try_from(chunk_idx)
.expect("Overflow in chunk number. Too many chunks."),
value_idx: u32::try_from(value_idx)
.expect("Overflow in index number. Too many values."),
}
}
fn chunk_idx(self) -> usize {
self.chunk_idx as usize
}
fn value_idx(self) -> usize {
self.value_idx as usize
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for DefaultKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.value_idx.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for DefaultKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let value_idx = u32::deserialize(deserializer)?;
Ok(Self {
chunk_idx: 0,
value_idx,
})
}
}
impl Key for DefaultKey {
fn index(self) -> usize {
self.value_idx()
}
}
impl std::fmt::Display for DefaultKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.value_idx.fmt(f)
}
}
impl std::hash::Hash for DefaultKey {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.value_idx.hash(state);
}
}
impl PartialEq for DefaultKey {
fn eq(&self, other: &Self) -> bool {
self.value_idx == other.value_idx
}
}
impl Eq for DefaultKey {}
impl PartialOrd for DefaultKey {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.value_idx.partial_cmp(&other.value_idx)
}
}
impl Ord for DefaultKey {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.value_idx.cmp(&other.value_idx)
}
}
#[macro_export]
macro_rules! new_key_types {
($(#[$meta:meta])* $vis:vis struct $name:ident; $($other:tt)*) => {
$(#[$meta])*
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[repr(transparent)]
$vis struct $name($crate::DefaultKey);
const _: () = {
#[automatically_derived]
impl ::std::convert::From<$crate::DefaultKey> for $name {
fn from(key: $crate::DefaultKey) -> Self {
Self(key)
}
}
#[automatically_derived]
impl ::std::convert::From<$name> for $crate::DefaultKey {
fn from(key: $name) -> Self {
key.0
}
}
#[automatically_derived]
impl $crate::Key for $name {
fn index(self) -> usize {
self.0.index()
}
}
$crate::private_key_type_impl_serde!($name);
};
$crate::new_key_types!($($other)*);
};
() => {}
}
#[macro_export]
#[doc(hidden)]
#[cfg(not(feature = "serde"))]
macro_rules! private_key_type_impl_serde {
($name:ident) => {};
}
#[macro_export]
#[doc(hidden)]
#[cfg(feature = "serde")]
macro_rules! private_key_type_impl_serde {
($name:ident) => {
impl $crate::serde::Serialize for $name {
fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
where
S: $crate::serde::Serializer,
{
use $crate::serde::Serialize;
self.0.serialize(serializer)
}
}
impl<'de> $crate::serde::Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: $crate::serde::Deserializer<'de>,
{
use $crate::serde::Deserialize;
$crate::DefaultKey::deserialize(deserializer).map($name)
}
}
};
}
pub const DEFAULT_CAPACITY: usize = 32;
const NORMAL_PAGE_SIZE: usize = 4096;
const HUGE_PAGE_SIZE: usize = 2 * 1024 * 1024;
#[derive(Clone, Debug)]
struct Chunk<T> {
start: usize,
storage: Vec<T>,
}
impl<T> Chunk<T> {
fn new(start: usize, capacity: usize) -> Self {
Self {
start,
storage: Vec::with_capacity(capacity),
}
}
}
#[derive(Clone, Debug)]
struct StackoInner<T> {
chunks: Vec<Chunk<T>>,
}
#[derive(Clone, Debug)]
pub struct Stacko<T, K: Key = DefaultKey> {
inner: RefCell<StackoInner<T>>,
_phantom_key: PhantomData<K>,
}
impl<T, K: Key> Stacko<T, K> {
#[must_use]
pub fn new() -> Self {
Self::with_capacity(DEFAULT_CAPACITY)
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
let page_capacity = NORMAL_PAGE_SIZE / std::mem::size_of::<T>();
let capacity = std::cmp::max(page_capacity, capacity);
Self {
inner: RefCell::new(StackoInner {
chunks: vec![Chunk::new(0, capacity)],
}),
_phantom_key: PhantomData,
}
}
pub fn push(&self, value: T) -> (K, &T) {
self.try_push(value).unwrap_or_else(|value| {
self.grow(1);
match self.try_push(value) {
Ok(result) => result,
Err(_) => unreachable!("There should be space because we just grew the `Stacko`."),
}
})
}
pub fn try_push(&self, value: T) -> Result<(K, &T), T> {
let mut inner = self.inner.borrow_mut();
let chunk_idx = inner.chunks.len() - 1;
let active = inner
.chunks
.last_mut()
.expect("There should be at least one chunk in the `Stacko`.");
let offset = active.storage.len();
if offset < active.storage.capacity() {
active.storage.push(value);
debug_assert!(offset < active.storage.len());
let reference = unsafe { &*active.storage.as_ptr().add(offset) };
let value_idx = active.start + offset;
Ok((K::from(DefaultKey::new(chunk_idx, value_idx)), reference))
} else {
Err(value)
}
}
pub fn len(&self) -> usize {
let inner = self.inner.borrow();
let active = inner
.chunks
.last()
.expect("There should be at least one chunk in the Stacko.");
(active.start as usize) + active.storage.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get(&self, key: K) -> Option<&T> {
let key: DefaultKey = key.into();
self.raw_get(key.chunk_idx(), key.value_idx())
.or_else(|| self.get_slow(key))
}
#[cold]
fn get_slow(&self, key: DefaultKey) -> Option<&T> {
let key: DefaultKey = self.key_from_index(key.index())?.into();
self.raw_get(key.chunk_idx(), key.value_idx())
}
pub fn get_mut(&mut self, key: K) -> Option<&mut T> {
let key: DefaultKey = key.into();
unsafe {
self.raw_get_mut(key.chunk_idx(), key.value_idx())
.or_else(|| self.get_mut_slow(key))
}
}
#[cold]
unsafe fn get_mut_slow(&self, key: DefaultKey) -> Option<&mut T> {
let key: DefaultKey = self.key_from_index(key.index())?.into();
self.raw_get_mut(key.chunk_idx(), key.value_idx())
}
pub fn key_from_index(&self, index: usize) -> Option<K> {
let inner = self.inner.borrow();
let chunk_idx = inner
.chunks
.binary_search_by_key(&index, |chunk| chunk.start)
.unwrap_or_else(|idx| idx - 1);
let chunk = &inner.chunks[chunk_idx];
if index - chunk.start < chunk.storage.len() {
Some(K::from(DefaultKey::new(chunk_idx, index)))
} else {
None
}
}
pub fn into_vec(self) -> Vec<T> {
let mut result = Vec::with_capacity(self.len());
let inner = self.inner.into_inner();
for mut chunk in inner.chunks {
result.append(&mut chunk.storage);
}
result
}
pub fn iter(&self) -> Iter<T, K> {
Iter {
stacko: self,
chunk_idx: 0,
value_idx: 0,
}
}
#[cold]
fn grow(&self, additional: usize) {
let mut inner = self.inner.borrow_mut();
let active = inner
.chunks
.last()
.expect("There should be at least one chunk in the Stacko.");
debug_assert!(
active.storage.len() == active.storage.capacity(),
"The active chunk is not full yet?"
);
let start = active.start + active.storage.len();
let capacity = std::cmp::max(
additional,
std::cmp::min(
active.storage.capacity() * 2,
HUGE_PAGE_SIZE / std::mem::size_of::<T>(),
),
);
inner.chunks.push(Chunk::new(start, capacity));
}
fn raw_get(&self, chunk: usize, index: usize) -> Option<&T> {
self.inner.borrow().chunks.get(chunk).and_then(|chunk| {
let offset = index - (chunk.start as usize);
if offset < chunk.storage.len() {
Some(unsafe { &*chunk.storage.as_ptr().add(offset) })
} else {
None
}
})
}
unsafe fn raw_get_mut(&self, chunk: usize, index: usize) -> Option<&mut T> {
self.inner
.borrow_mut()
.chunks
.get_mut(chunk)
.and_then(|chunk| {
let offset = index - (chunk.start as usize);
if offset < chunk.storage.len() {
Some(&mut *(chunk.storage.as_mut_ptr().add(offset)))
} else {
None
}
})
}
}
impl<T, K: Key> From<Stacko<T, K>> for Vec<T> {
fn from(stacko: Stacko<T, K>) -> Self {
stacko.into_vec()
}
}
impl<T, K: Key> From<Vec<T>> for Stacko<T, K> {
fn from(chunk: Vec<T>) -> Self {
Self {
inner: RefCell::new(StackoInner {
chunks: vec![Chunk {
start: 0,
storage: chunk,
}],
}),
_phantom_key: PhantomData,
}
}
}
impl<T, K: Key> Default for Stacko<T, K> {
fn default() -> Self {
Self::new()
}
}
impl<'p, T, K: Key> IntoIterator for &'p Stacko<T, K> {
type Item = (K, &'p T);
type IntoIter = Iter<'p, T, K>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<T, K: Key> IntoIterator for Stacko<T, K> {
type Item = (K, T);
type IntoIter = IntoIter<T, K>;
fn into_iter(self) -> Self::IntoIter {
IntoIter {
chunks: self.inner.into_inner().chunks.into_iter(),
active: None,
chunk_idx: 0,
value_idx: 0,
_phantom_key: PhantomData,
}
}
}
impl<T, K: Key> FromIterator<T> for Stacko<T, K> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let iter = iter.into_iter();
let (lower_bound, upper_bound) = iter.size_hint();
let capacity = upper_bound.unwrap_or(lower_bound);
let stacko = Stacko::with_capacity(capacity);
for value in iter {
stacko.push(value);
}
stacko
}
}
impl<T, K: Key> std::ops::Index<K> for Stacko<T, K> {
type Output = T;
fn index(&self, key: K) -> &Self::Output {
self.get(key)
.expect("No value has been stored for the given key.")
}
}
impl<T, K: Key> std::ops::IndexMut<K> for Stacko<T, K> {
fn index_mut(&mut self, key: K) -> &mut Self::Output {
self.get_mut(key)
.expect("No value has been stored for the given key.")
}
}
#[cfg(feature = "serde")]
impl<T: serde::Serialize, K: Key> serde::Serialize for Stacko<T, K> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeSeq;
let mut seq = serializer.serialize_seq(Some(self.len()))?;
for (_, value) in self.iter() {
seq.serialize_element(value)?;
}
seq.end()
}
}
#[cfg(feature = "serde")]
impl<'de, T: serde::Deserialize<'de>, K: Key> serde::Deserialize<'de> for Stacko<T, K> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(Vec::deserialize(deserializer)?.into())
}
}
pub struct IntoIter<T, K: Key> {
chunks: std::vec::IntoIter<Chunk<T>>,
active: Option<std::vec::IntoIter<T>>,
chunk_idx: usize,
value_idx: usize,
_phantom_key: PhantomData<K>,
}
impl<T, K: Key> Iterator for IntoIter<T, K> {
type Item = (K, T);
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(chunk) = &mut self.active {
if let Some(value) = chunk.next() {
let result = Some((
K::from(DefaultKey::new(self.chunk_idx, self.value_idx)),
value,
));
self.value_idx += 1;
break result;
}
self.active = None;
self.chunk_idx += 1;
}
if let Some(chunk) = self.chunks.next() {
self.active = Some(chunk.storage.into_iter());
} else {
break None;
}
}
}
}
pub struct Iter<'p, T, K: Key> {
stacko: &'p Stacko<T, K>,
chunk_idx: usize,
value_idx: usize,
}
impl<'p, T, K: Key> Iterator for Iter<'p, T, K> {
type Item = (K, &'p T);
fn next(&mut self) -> Option<Self::Item> {
loop {
let inner = self.stacko.inner.borrow();
if self.chunk_idx >= inner.chunks.len() {
break None;
}
if let Some(value) = self.stacko.raw_get(self.chunk_idx, self.value_idx) {
let result = Some((
K::from(DefaultKey::new(self.chunk_idx, self.value_idx)),
value,
));
self.value_idx += 1;
break result;
}
self.chunk_idx += 1;
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.stacko.len(), None)
}
fn count(self) -> usize {
self.stacko.len() - self.value_idx
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn test_many() {
let stacko = Stacko::<usize>::new();
let values = (0..10_000)
.map(|value| stacko.push(value))
.collect::<Vec<_>>();
for (expected, (key, _)) in values.iter().enumerate() {
assert_eq!(stacko[*key], expected)
}
for (expected, (key, value_ref)) in stacko.iter().enumerate() {
assert_eq!(key.index(), expected);
assert_eq!(*value_ref, expected);
assert_eq!(stacko[key], expected);
}
}
}