diff --git a/src/ext.rs b/src/ext.rs index 14ac938..94387d8 100644 --- a/src/ext.rs +++ b/src/ext.rs @@ -7,8 +7,121 @@ pub use std::{ convert::{ TryFrom, TryInto, }, + borrow::*, }; +/// Add forwarding borrow + deref (+ optional `into_inner()`) impls for a type. +/// +/// # Usage +/// For a mutable forwarding newtype: +/// ``` +/// # use crate::forward_newtype; +/// # use core::borrow::*; +/// +/// /// A mutable buffer newtype over an array. +/// struct Buffer([u8; 16]); +/// forward_newtype!(mut Buffer => [u8], 0); // Generates `Borrow<[u8]>`, `BorrowMut<[u8]>`, `Deref`, and `DerefMut` impls for `Buffer` that return `<&[mut] self.>0` (as specified by `0`.) +/// ``` +/// +/// For an immutable forwarding newtype: +/// ``` +/// # use crate::forward_newtype; +/// # use core::borrow::*; +/// +/// /// A mutable buffer newtype over an array. +/// struct Data([u8; 16]); +/// forward_newtype!(ref Buffer => [u8], 0); // Generates `Borrow<[u8]>` and `Deref` impls for `Buffer` that return `<& self.>0` (as specified by `0`.) Immutable access only is specified by `ref`. +/// ``` +/// +/// ## Consuming into inner +/// To generate an `into_inner(self) -> T` inherent impl for the type, the syntax `forward_newtype!(move [const] Type => Inner, accessor)` can be used. +/// If `const` is passed, then the `into_inner()` function will be a `const fn`, if not, then it won't be. +/// +/// To combine with ref-forwarding accessors, the syntax `forward_newtype!(move [const] {ref/mut} Type => Inner, accessor)` can be used to generate them all; the `Borrow`, `BorrowMut`, `Deref`, `DerefMut` and `pub [const] fn into_inner()`. +/// This is the most likely to be useful. +/// +/// If you need a seperate `into_inner()` impl, you can either not use the `move` declarator, or use the `ref`/`mut` accessor generator in a different statement than the `move` one: +/// ``` +/// # use crate::forward_newtype; +/// # use core::borrow::*; +/// +/// /// A mutable buffer newtype over an array. +/// struct Buffer([u8; 16]); +/// forward_newtype!(mut Buffer => [u8], 0); // Generate a mutable & immutable forwarding ref to a slice of bytes. +/// forward_newtype!(move const Buffer => [u8; 16], 0); // Generate a seperately typed `into_inner()` that returns the sized array. +/// ``` +macro_rules! forward_newtype { + (ref $type:ty => $inner:ty, $($expr:tt)+) => { + impl Borrow<$inner> for $type + { + #[inline] + fn borrow(&self) -> &$inner + { + &self.$($expr)+ + } + } + + impl ::std::ops::Deref for $type { + type Target = $inner; + #[inline] + fn deref(&self) -> &Self::Target { + self.borrow() + } + } + }; + (mut $type:ty => $inner:ty, $($expr:tt)+) => { + forward_newtype!(ref $type => $inner, $($expr)+); + + impl BorrowMut<$inner> for $type + { + #[inline] + fn borrow_mut(&mut self) -> &mut $inner + { + &mut self.$($expr)+ + } + } + + impl ::std::ops::DerefMut for $type { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + self.borrow_mut() + } + } + }; + (move const $type:ty => $inner:ty, $($expr:tt)+) => { + impl $type { + /// Consume into the inner value. + pub const fn into_inner(self) -> $inner { + self.$($expr)+ + } + } + }; + (move $type:ty => $inner:ty, $($expr:tt)+) => { + impl $type { + /// Consume into the inner value. + pub fn into_inner(self) -> $inner { + self.$($expr)+ + } + } + }; + (move const ref $type:ty => $inner:ty, $($expr:tt)+) => { + forward_newtype!(move const $type => $inner, $($expr)+); + forward_newtype!(ref $type => $inner, $($expr)+); + }; + (move ref $type:ty => $inner:ty, $($expr:tt)+) => { + forward_newtype!(move $type => $inner, $($expr)+); + forward_newtype!(ref $type => $inner, $($expr)+); + }; + (move const mut $type:ty => $inner:ty, $($expr:tt)+) => { + forward_newtype!(move const $type => $inner, $($expr)+); + forward_newtype!(mut $type => $inner, $($expr)+); + }; + (move mut $type:ty => $inner:ty, $($expr:tt)+) => { + forward_newtype!(move $type => $inner, $($expr)+); + forward_newtype!(mut $type => $inner, $($expr)+); + }; +} + /// The default bottom type. /// /// To use the `unwrap_infallible()`-like interface, functions that return `-> !` should be changed to `-> Never`. diff --git a/src/part.rs b/src/part.rs index 826898f..87a4ea8 100644 --- a/src/part.rs +++ b/src/part.rs @@ -11,6 +11,65 @@ use std::{ /// TODO: Make this comptime env-var configurable (`option_env!()`) on debug builds. (See `SEARCH_CAP_GROW`.) const CACHELINE_SIZE: usize = std::mem::size_of::>(); +/// A buffer that takes up exactly one cache-line. +/// +/// This type is not `Copy` to ensure copies are made safely. `clone()` is trivial, and to copy explicitly in a const context use `.copied()` +/// +/// # Alignment +/// Note that the buffer is *not* 1-cacheline aligned itself by default. +/// To ensure its alignment, you should use `crossbeam_utils::CachePadded` (or the type-alias `AlignedCachelineBuffer`.) +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[repr(transparent)] +pub struct CachelineBuffer([u8; CACHELINE_SIZE]); + +impl Default for CachelineBuffer +{ + #[inline] + fn default() -> Self + { + Self::new() + } +} + + +/// A buffer that takes up exactly one cache-line, which is itself aligned to 1 cacheline. +pub type AlignedCachelineBuffer = crossbeam_utils::CachePadded; + +impl CachelineBuffer { + /// The size of the buffer (1 cacheline of bytes.) + pub const SIZE: usize = CACHELINE_SIZE; + + /// Create a new, empty buffer. + #[inline] + pub const fn new() -> Self + { + Self([0; Self::SIZE]) + } + + /// Clone this value. + /// + /// This is a `const fn` explicit trivial copy of the data. + #[inline] + pub const fn copied(&self) -> Self + { + Self(self.0) + } + + /// Get a reference to the byte array. + pub const fn as_bytes(&self) -> &[u8; Self::SIZE] + { + &self.0 + } +} + +forward_newtype!(mut CachelineBuffer => [u8], 0); +forward_newtype!(move const CachelineBuffer => [u8; CACHELINE_SIZE], 0); + +const _: () = { + debug_assert!(CachelineBuffer::SIZE > std::mem::size_of::(), "Invalid cacheline-padding size (`CACHELINE_SIZE`)"); + //debug_assert!(CACHELINE_SIZE == 128, "Unexpected `CACHELINE_SIZE`"); +}; + /// Grow capacity exponentially when search fails. /// /// TODO: Make this comptime env-var settable (`option_env!()`) on debug builds. @@ -331,6 +390,8 @@ where S: MidpointFBSearcher #[cfg(test)] mod test { + use super::*; + use std::hint::black_box; //TODO: Add a generic randomised lorem-ipsum-like text data generator & a generic assertion tester that can take a unique `MidpointFBSearcher`. #[test] @@ -360,4 +421,6 @@ mod test { unimplemented!("A pure async parallel searcher has not yet been implemented") } + + //TODO: Benchmarking the searchers' configuration about capacity size, growth and bounding. }