From 83751efd734999fc11316a66317250ca53e76726 Mon Sep 17 00:00:00 2001 From: superwhiskers Date: Wed, 27 Aug 2025 14:41:19 -0500 Subject: initial expression implementation Change-Id: I6a6a69640c133bce112891bba09033b08e7c0dec --- crates/core/src/hive/group.rs | 24 ++++++++++-- crates/core/src/hive/mod.rs | 82 ++++++++++++++++++++++++++++++++++++++- crates/core/src/hive/skipfield.rs | 17 +++++--- 3 files changed, 114 insertions(+), 9 deletions(-) (limited to 'crates/core/src/hive') diff --git a/crates/core/src/hive/group.rs b/crates/core/src/hive/group.rs index 32d070e..9217897 100644 --- a/crates/core/src/hive/group.rs +++ b/crates/core/src/hive/group.rs @@ -1,4 +1,4 @@ -//! An implementation of the individual memory blocks that make up a [`Hive`]. +//! An implementation of the individual memory blocks that make up a hive. use core::{ mem::{self, ManuallyDrop}, @@ -27,6 +27,7 @@ where /// implementation. #[repr(C, packed)] #[derive(Copy, Clone)] +#[cfg_attr(feature = "core-fmt", derive(Debug))] pub struct FreeList where Sk: skipfield::SkipfieldType, @@ -39,6 +40,7 @@ where } /// A doubly-linked `Group` of `T` with a skipfield type of `Sk`. +#[cfg_attr(feature = "core-fmt", derive(Debug))] pub struct Group where Sk: skipfield::SkipfieldType, @@ -74,7 +76,7 @@ where /// Pointer to the previous [`Group`] with erased elements. pub previous_with_erasures: Option>>, - /// Number assigned to this group in the [`Hive`]. + /// Number assigned to this group. pub number: usize, } @@ -98,7 +100,23 @@ const fn compute_element_allocation_size() -> usize { } else { t_align } + } else if sk2_size > t_size { + sk2_size } else { - if sk2_size > t_size { sk2_size } else { t_size } + t_size + } +} + +#[cfg(all(test, feature = "core-error"))] +mod test { + use super::*; + + #[test] + fn validate_element_allocation_size() { + assert_eq!( + Group::::ELEMENT_ALLOCATION_SIZE, + 4, + "element allocation size with T = u32, Sk = u8 is 4" + ); } } diff --git a/crates/core/src/hive/mod.rs b/crates/core/src/hive/mod.rs index 17568e3..ad14725 100644 --- a/crates/core/src/hive/mod.rs +++ b/crates/core/src/hive/mod.rs @@ -12,6 +12,7 @@ // parameters into a separate struct to reduce the amount of code // generated, akin to what the standard library does with `RawVec` and // `RawVecInner` +//TODO: try_reserve_exact, reserve_exact use alloc::alloc::{Allocator, Global, Layout}; use core::{cmp, mem, ptr::NonNull}; @@ -26,6 +27,7 @@ pub mod group; pub mod skipfield; /// An implementation of a bucket array using a skipfield. +#[cfg_attr(feature = "core-fmt", derive(Debug))] pub struct Hive where Sk: skipfield::SkipfieldType, @@ -127,6 +129,14 @@ where cmp::min(Sk::from_usize(adaptive_size), max_capacity), ); + //NOTE: anything that calls `panic` indirectly or does anything that + // touches standard output requires core::fmt :skull: + #[cfg(feature = "core-fmt")] + debug_assert!( + max_capacity >= min_capacity, + "maximum capacity bound is greater than or equal to the minimum capacity bound" + ); + (min_capacity, max_capacity) } @@ -161,6 +171,9 @@ where /// exceeds `isize::MAX` bytes. #[cfg(feature = "core-fmt")] pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + //PANIC: this is acceptable as the panic is mentioned above and it is + // used to assert an invariant. + #[allow(clippy::expect_used)] Self::try_with_capacity_in(capacity, alloc) .expect("allocation should not fail") } @@ -181,6 +194,73 @@ where capacity: usize, alloc: A, ) -> Result { + let mut hive = Self::new_in(alloc); + hive.try_reserve(capacity)?; + Ok(hive) + } + + /// Reserves capacity for at least `additional` more elements to be + /// inserted in the given `Hive`. + /// + /// The collection may reserve more space to avoid future allocations. + /// After calling `reserve`, the capacity will be greater than or equal to + /// `self.len() + additional`. Does nothing if the capacity is already + /// sufficient. + /// + /// # Panics + /// + /// Panics if the allocator reports allocation failure or if the new + /// capacity exceeds `isize::MAX` bytes. + #[cfg(feature = "core-fmt")] + pub fn reserve(&mut self, additional: usize) { + todo!() + } + + /// Reserves capacity for at least `additional` more elements to be + /// inserted in the given `Hive`. + /// + /// The collection may reserve more space to avoid future allocations. + /// After calling `reserve`, the capacity will be greater than or equal to + /// `self.len() + additional`. Does nothing if the capacity is already + /// sufficient. + /// + /// # Errors + /// + /// Returns an error if the allocator reports allocation failure or if the + /// new capacity exceeds `isize::MAX` bytes. + pub fn try_reserve(&mut self, additional: usize) -> Result<(), Error> { + todo!() + } + + /// Checks if the container needs to grow to accommodate `additional` more + /// elements + #[inline] + fn needs_to_grow(&self, additional: usize) -> bool { + additional > self.capacity.wrapping_sub(self.size) + } + + /// Grow the `Hive` by the given amount, leaving room for more + /// elements than necessary. + /// + /// # Errors + /// + /// Returns an error if the allocator reports allocation failure or if the + /// new capacity exceeds `isize::MAX` bytes. + fn grow_amortized(&mut self, additional: usize) -> Result<(), Error> { + #[cfg(feature = "core-fmt")] + debug_assert!( + additional > 0, + "at least space enough for one element will be added" + ); + + if mem::size_of::() == 0 { + //NOTE: akin to raw_vec in alloc, if we get here with a zero + // sized type, since the capacity is definitionally full when + // it is holding one, the hive would necessarily + // be overfull + return Err(Error::CapacityOverflow); + } + todo!() } } @@ -202,7 +282,7 @@ pub enum Error { /// Allocation size exceeded `isize::MAX`. CapacityOverflow, - /// An unspecified allocation error occurred. + /// Unspecified allocation error. /// /// The layout used during allocation is provided for troubleshooting /// where that is possible. Ideally, future revisions of the diff --git a/crates/core/src/hive/skipfield.rs b/crates/core/src/hive/skipfield.rs index 0fb2ab4..16a3dcb 100644 --- a/crates/core/src/hive/skipfield.rs +++ b/crates/core/src/hive/skipfield.rs @@ -4,7 +4,10 @@ //! types may be used by implementing this trait on them; the trait is not //! sealed. -use core::ops::{Add, AddAssign, Sub, SubAssign}; +use core::{ + cmp, + ops::{Add, AddAssign, Sub, SubAssign}, +}; /// Trait describing integral types in a generic way suitable for use as the /// element type of a skipfield. @@ -21,9 +24,13 @@ pub trait SkipfieldType: const ONE: Self; /// Conversion method from `usize` using `as` or an equivalent + /// + /// Caps the value of the input by the maximum of `Self`. fn from_usize(u: usize) -> Self; /// Conversion method from `isize` using `as` or an equivalent + /// + /// Caps the value of the input by the maximum of `Self`. fn from_isize(i: isize) -> Self; } @@ -34,12 +41,12 @@ impl SkipfieldType for u16 { #[inline(always)] fn from_usize(u: usize) -> Self { - u as u16 + cmp::min(u, Self::MAXIMUM as usize) as u16 } #[inline(always)] fn from_isize(i: isize) -> Self { - i as u16 + cmp::min(i, Self::MAXIMUM as isize) as u16 } } @@ -50,11 +57,11 @@ impl SkipfieldType for u8 { #[inline(always)] fn from_usize(u: usize) -> Self { - u as u8 + cmp::min(u, Self::MAXIMUM as usize) as u8 } #[inline(always)] fn from_isize(i: isize) -> Self { - i as u8 + cmp::min(i, Self::MAXIMUM as isize) as u8 } } -- cgit 1.4.1-2-gfad0