Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
al8n committed May 20, 2024
1 parent 71b1585 commit d24fd62
Show file tree
Hide file tree
Showing 8 changed files with 749 additions and 223 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
## 0.10.0

- Remove `SkipSet`
- Add `insert`, `get_or_insert` and `get_or_insert_with` methods
- Add `insert`, `insert_with`, `insert_with_value`, `get_or_insert`, `get_or_insert` and `get_or_insert_with_value` methods
- Add `compare_remove` and `get_or_remove` methods
- Add `Entry` and `VersionedEntry`
- Add discard states tracker and `discarded` method to let users know how many bytes in ARENA are discarded.
- Do not panic when users do not fully fill `VacantValue`
- Rename `OccupiedValue` to `VacantBuffer` and do not panic when users do not fully fill `VacantBuffer`
- Add `tracing`

## 0.9.0
Expand Down
38 changes: 36 additions & 2 deletions src/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,41 @@ impl Arena {
}

#[cfg(not(feature = "unaligned"))]
pub(super) fn alloc_value<T>(&self, size: u32) -> Result<u32, ArenaError> {
pub(super) fn alloc_key(&self, size: u16) -> Result<(u32, u16), ArenaError> {
let size = size as u64;
let header = self.header();
let mut current_allocated = header.allocated.load(Ordering::Acquire);
if current_allocated + size > self.cap as u64 {
return Err(ArenaError);
}

loop {
let want = current_allocated + size;
match header.allocated.compare_exchange_weak(
current_allocated,
want,
Ordering::SeqCst,
Ordering::Acquire,
) {
Ok(current) => {
// Return the aligned offset.
#[cfg(feature = "tracing")]
tracing::trace!("ARENA allocates {} bytes for a key", size);
return Ok((current as u32, size as u16));
}
Err(x) => {
if x + size > self.cap as u64 {
return Err(ArenaError);
}

current_allocated = x;
}
}
}
}

#[cfg(not(feature = "unaligned"))]
pub(super) fn alloc_value<T>(&self, size: u32) -> Result<(u32, u32), ArenaError> {
let padded = Self::pad_value_and_trailer::<T>(size);
let header = self.header();
let mut current_allocated = header.allocated.load(Ordering::Acquire);
Expand All @@ -476,7 +510,7 @@ impl Arena {
let value_offset = (allocated as u32 - size) & !(mem::align_of::<T>() as u32 - 1);
#[cfg(feature = "tracing")]
tracing::trace!("ARENA allocates {} bytes for a value", padded);
return Ok(value_offset);
return Ok((value_offset, padded as u32));
}
Err(x) => {
if x + padded > self.cap as u64 {
Expand Down
153 changes: 3 additions & 150 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ use align8vp::Pointer;
/// A map implementation based on skiplist
pub mod map;

mod types;
pub use types::*;

#[cfg(all(feature = "memmap", not(target_family = "wasm")))]
mod options;
#[cfg(all(feature = "memmap", not(target_family = "wasm")))]
Expand Down Expand Up @@ -140,156 +143,6 @@ impl Comparator for Descend {
}
}

/// Returns when the bytes are too large to be written to the occupied value.
#[derive(Debug, Default, Clone, Copy)]
pub struct TooLarge {
remaining: usize,
write: usize,
}

impl core::fmt::Display for TooLarge {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"VacantValue does not have enough space (remaining {}, want {})",
self.remaining, self.write
)
}
}

#[cfg(feature = "std")]
impl std::error::Error for TooLarge {}

/// An occupied value in the skiplist.
#[must_use = "occupied value must be fully filled with bytes."]
#[derive(Debug)]
pub struct VacantValue<'a> {
value: &'a mut [u8],
len: usize,
cap: usize,
}

impl<'a> VacantValue<'a> {
/// Write bytes to the occupied value.
pub fn write(&mut self, bytes: &[u8]) -> Result<(), TooLarge> {
let len = bytes.len();
let remaining = self.cap - self.len;
if len > remaining {
return Err(TooLarge {
remaining,
write: len,
});
}

self.value[self.len..self.len + len].copy_from_slice(bytes);
self.len += len;
Ok(())
}

/// Returns the capacity of the occupied value.
#[inline]
pub const fn capacity(&self) -> usize {
self.cap
}

/// Returns the length of the occupied value.
#[inline]
pub const fn len(&self) -> usize {
self.len
}

/// Returns `true` if the occupied value is empty.
#[inline]
pub const fn is_empty(&self) -> bool {
self.len == 0
}

/// Returns the remaining space of the occupied value.
#[inline]
pub const fn remaining(&self) -> usize {
self.cap - self.len
}

#[inline]
fn new(cap: usize, value: &'a mut [u8]) -> Self {
Self { value, len: 0, cap }
}
}

impl<'a> core::ops::Deref for VacantValue<'a> {
type Target = [u8];

fn deref(&self) -> &Self::Target {
&self.value[..self.len]
}
}

impl<'a> core::ops::DerefMut for VacantValue<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.value[..self.len]
}
}

impl<'a> PartialEq<[u8]> for VacantValue<'a> {
fn eq(&self, other: &[u8]) -> bool {
self.value[..self.len].eq(other)
}
}

impl<'a> PartialEq<VacantValue<'a>> for [u8] {
fn eq(&self, other: &VacantValue<'a>) -> bool {
self.eq(&other.value[..other.len])
}
}

impl<'a> PartialEq<[u8]> for &VacantValue<'a> {
fn eq(&self, other: &[u8]) -> bool {
self.value[..self.len].eq(other)
}
}

impl<'a> PartialEq<&VacantValue<'a>> for [u8] {
fn eq(&self, other: &&VacantValue<'a>) -> bool {
self.eq(&other.value[..other.len])
}
}

impl<'a, const N: usize> PartialEq<[u8; N]> for VacantValue<'a> {
fn eq(&self, other: &[u8; N]) -> bool {
self.value[..self.len].eq(other.as_slice())
}
}

impl<'a, const N: usize> PartialEq<VacantValue<'a>> for [u8; N] {
fn eq(&self, other: &VacantValue<'a>) -> bool {
self.as_slice().eq(&other.value[..other.len])
}
}

impl<'a, const N: usize> PartialEq<&VacantValue<'a>> for [u8; N] {
fn eq(&self, other: &&VacantValue<'a>) -> bool {
self.as_slice().eq(&other.value[..other.len])
}
}

impl<'a, const N: usize> PartialEq<[u8; N]> for &VacantValue<'a> {
fn eq(&self, other: &[u8; N]) -> bool {
self.value[..self.len].eq(other.as_slice())
}
}

impl<'a, const N: usize> PartialEq<&mut VacantValue<'a>> for [u8; N] {
fn eq(&self, other: &&mut VacantValue<'a>) -> bool {
self.as_slice().eq(&other.value[..other.len])
}
}

impl<'a, const N: usize> PartialEq<[u8; N]> for &mut VacantValue<'a> {
fn eq(&self, other: &[u8; N]) -> bool {
self.value[..self.len].eq(other.as_slice())
}
}

/// A trait for extra information that can be stored with entry in the skiplist.
///
/// # Safety
Expand Down
Loading

0 comments on commit d24fd62

Please sign in to comment.