From cb0916caeb7a6fb5e7ad58c646c08c34f506def0 Mon Sep 17 00:00:00 2001 From: Al Liu Date: Tue, 18 Jun 2024 23:12:00 +0800 Subject: [PATCH] use `u5` and `u27` in public API --- Cargo.toml | 3 ++- src/lib.rs | 2 ++ src/map.rs | 28 +++++++++++------------- src/map/api.rs | 26 +++++++++++----------- src/map/tests.rs | 6 +++--- src/options.rs | 56 +++++++++++++++++++++++++++--------------------- 6 files changed, 65 insertions(+), 56 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3e179469..74215c2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "skl" -version = "0.11.1" +version = "0.11.2" edition = "2021" rust-version = "1.56.0" repository = "https://github.com/al8n/skl" @@ -46,6 +46,7 @@ getrandom = { version = "0.2", features = ["js"] } either = { version = "1", default-features = false } rand = { version = "0.8", default-features = false, features = ["getrandom"] } rarena-allocator = { version = "0.1", default-features = false } +ux2 = { version = "0.8", default-features = false, features = ["32"] } tracing = { version = "0.1", optional = true } diff --git a/src/lib.rs b/src/lib.rs index bfd82d8d..2e2adc60 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,6 +34,8 @@ pub use rarena_allocator::{Arena, Error as ArenaError}; pub use map::{AllVersionsIter, SkipMap}; +pub use ux2::{u27, u5}; + const MAX_HEIGHT: usize = 32; #[cfg(feature = "std")] diff --git a/src/map.rs b/src/map.rs index 5eb9e3d3..a0d7d428 100644 --- a/src/map.rs +++ b/src/map.rs @@ -610,7 +610,7 @@ impl Drop for SkipMap { impl SkipMap { fn new_in(arena: Arena, cmp: C, opts: Options) -> Result { - let data_offset = Self::check_capacity(&arena, opts.max_height())?; + let data_offset = Self::check_capacity(&arena, opts.max_height().into())?; if arena.read_only() { let (meta, head, tail) = Self::get_pointers(&arena); @@ -640,14 +640,15 @@ impl SkipMap { } }; - let head = Self::allocate_full_node(&arena, opts.max_height())?; - let tail = Self::allocate_full_node(&arena, opts.max_height())?; + let max_height: u8 = opts.max_height().into(); + let head = Self::allocate_full_node(&arena, max_height)?; + let tail = Self::allocate_full_node(&arena, max_height)?; // Safety: // We will always allocate enough space for the head node and the tail node. unsafe { // Link all head/tail levels together. - for i in 0..(opts.max_height() as usize) { + for i in 0..(max_height as usize) { let head_link = head.tower(&arena, i); let tail_link = tail.tower(&arena, i); head_link.next_offset.store(tail.offset, Ordering::Relaxed); @@ -1085,17 +1086,14 @@ impl SkipMap { } #[inline] - const fn check_node_size( - &self, - height: u32, - key_size: u32, - mut value_size: u32, - ) -> Result<(), Error> { - if height < 1 || height > self.opts.max_height() as u32 { + fn check_node_size(&self, height: u32, key_size: u32, mut value_size: u32) -> Result<(), Error> { + let max_height: u32 = self.opts.max_height().into(); + if height < 1 || height > max_height { panic!("height cannot be less than one or greater than the max height"); } - if key_size > self.opts.max_key_size() { + let max_key_size: u32 = self.opts.max_key_size().into(); + if key_size > max_key_size { return Err(Error::KeyTooLarge(key_size as u64)); } @@ -1156,7 +1154,7 @@ impl SkipMap { value_size: u32, f: impl FnOnce(&mut VacantBuffer<'a>) -> Result<(), E>, ) -> Result<(NodePtr, u32, Deallocator), Either> { - let height = super::random_height(self.opts.max_height()); + let height = super::random_height(self.opts.max_height().into()); let (nd, deallocator) = match key { Key::Occupied(key) => self.allocate_entry_node( height, @@ -1700,12 +1698,12 @@ impl SkipMap { fn fetch_vacant_key<'a, 'b: 'a, E>( &'a self, - key_size: u16, + key_size: u32, key: impl FnOnce(&mut VacantBuffer<'a>) -> Result<(), E>, ) -> Result, Either> { let (key_offset, key_size) = self .arena - .alloc_bytes(key_size as u32) + .alloc_bytes(key_size) .map(|mut b| { b.detach(); (b.offset(), b.capacity()) diff --git a/src/map/api.rs b/src/map/api.rs index cf61cb49..3f704400 100644 --- a/src/map/api.rs +++ b/src/map/api.rs @@ -1,4 +1,5 @@ use rarena_allocator::ArenaOptions; +use ux2::u27; use super::*; @@ -389,14 +390,15 @@ impl SkipMap { self.meta = meta; - let head = Self::allocate_full_node(&self.arena, self.opts.max_height())?; - let tail = Self::allocate_full_node(&self.arena, self.opts.max_height())?; + let max_height: u8 = self.opts.max_height().into(); + let head = Self::allocate_full_node(&self.arena, max_height)?; + let tail = Self::allocate_full_node(&self.arena, max_height)?; // Safety: // We will always allocate enough space for the head node and the tail node. unsafe { // Link all head/tail levels together. - for i in 0..(self.opts.max_height() as usize) { + for i in 0..(max_height as usize) { let head_link = head.tower(&self.arena, i); let tail_link = tail.tower(&self.arena, i); head_link.next_offset.store(tail.offset, Ordering::Relaxed); @@ -737,12 +739,12 @@ impl SkipMap { pub fn insert_with<'a, E>( &'a self, trailer: T, - key_size: u16, + key_size: u27, key: impl FnOnce(&mut VacantBuffer<'a>) -> Result<(), E>, val_size: u32, val: impl FnOnce(&mut VacantBuffer<'a>) -> Result<(), E> + Copy, ) -> Result>, Either> { - let vk = self.fetch_vacant_key(key_size, key)?; + let vk = self.fetch_vacant_key(u32::from(key_size), key)?; self .update( @@ -815,12 +817,12 @@ impl SkipMap { pub fn get_or_insert_with<'a, E>( &'a self, trailer: T, - key_size: u16, + key_size: u27, key: impl FnOnce(&mut VacantBuffer<'a>) -> Result<(), E>, val_size: u32, val: impl FnOnce(&mut VacantBuffer<'a>) -> Result<(), E> + Copy, ) -> Result>, Either> { - let vk = self.fetch_vacant_key(key_size, key)?; + let vk = self.fetch_vacant_key(u32::from(key_size), key)?; self .update( @@ -976,15 +978,15 @@ impl SkipMap { pub fn get_or_remove_with<'a, 'b: 'a, E>( &'a self, trailer: T, - key_size: u16, + key_size: u27, key: impl FnOnce(&mut VacantBuffer<'a>) -> Result<(), E>, ) -> Result>, Either> { - let vk = self.fetch_vacant_key(key_size, key)?; - + let vk = self.fetch_vacant_key(u32::from(key_size), key)?; + let key = Key::RemoveVacant(vk); self .update( trailer, - Key::RemoveVacant(vk), + key, 0, noop::, Ordering::Relaxed, @@ -995,8 +997,6 @@ impl SkipMap { .map(|res| match res { Either::Left(old) => match old { Some(old) => { - self.arena.increase_discarded(key_size as u32); - if old.is_removed() { None } else { diff --git a/src/map/tests.rs b/src/map/tests.rs index cd4848e9..3750f3a7 100644 --- a/src/map/tests.rs +++ b/src/map/tests.rs @@ -2440,7 +2440,7 @@ fn get_or_insert_with(l: SkipMap) { l.get_or_insert_with::<()>( 1, - 5, + u27::new(5), |key| { key.write(b"alice").unwrap(); Ok(()) @@ -2695,7 +2695,7 @@ fn insert_with(l: SkipMap) { l.insert_with::<()>( 1, - 5, + u27::new(5), |key| { key.write(b"alice").unwrap(); Ok(()) @@ -2730,7 +2730,7 @@ fn insert_with(l: SkipMap) { let old = l .insert_with::<()>( 1, - 5, + u27::new(5), |key| { key.write(b"alice").unwrap(); Ok(()) diff --git a/src/options.rs b/src/options.rs index bb1b2fee..6ebe4714 100644 --- a/src/options.rs +++ b/src/options.rs @@ -4,14 +4,14 @@ pub use rarena_allocator::{MmapOptions, OpenOptions}; pub use rarena_allocator::Freelist; -const U27_MAX: u32 = (1 << 27) - 1; +use ux2::{u27, u5}; /// Options for `SkipMap`. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Options { max_value_size: u32, - max_key_size: u32, - max_height: u8, + max_key_size: u27, + max_height: u5, magic_version: u16, capacity: u32, unify: bool, @@ -31,8 +31,8 @@ impl Options { pub const fn new() -> Self { Self { max_value_size: u32::MAX, - max_key_size: U27_MAX, - max_height: 20, + max_key_size: u27::MAX, + max_height: u5::new(20), capacity: 1024, unify: false, magic_version: 0, @@ -127,13 +127,13 @@ impl Options { /// # Example /// /// ``` - /// use skl::Options; + /// use skl::{Options, u27}; /// /// let options = Options::new().with_max_key_size(1024); /// ``` #[inline] - pub const fn with_max_key_size(mut self, size: u32) -> Self { - self.max_key_size = if size > U27_MAX { U27_MAX } else { size }; + pub const fn with_max_key_size(mut self, size: u27) -> Self { + self.max_key_size = size; self } @@ -146,17 +146,11 @@ impl Options { /// ``` /// use skl::Options; /// - /// let options = Options::new().with_max_height(20); + /// let options = Options::new().with_max_height(u5::new(20)); /// ``` #[inline] - pub const fn with_max_height(mut self, height: u8) -> Self { - self.max_height = if height == 0 { - 1 - } else if height > 31 { - 31 - } else { - height - }; + pub const fn with_max_height(mut self, height: u5) -> Self { + self.max_height = height; self } @@ -186,7 +180,7 @@ impl Options { /// ``` /// use skl::Options; /// - /// let options = Options::new().with_max_value_size(1024); + /// let options = Options::new().with_max_value_size(u27::new(1024)); /// ``` #[inline] pub const fn max_value_size(&self) -> u32 { @@ -194,26 +188,40 @@ impl Options { } /// Returns the maximum size of the key. + /// + /// The maximum size of the key is `u27::MAX`. + /// + /// Default is `u27::MAX`. + /// + /// # Example + /// + /// ``` + /// use skl::{Options, u27}; + /// + /// let options = Options::new().with_max_key_size(u27::new(1024)); + /// + /// assert_eq!(options.max_key_size(), u27::new(1024)); + /// ``` #[inline] - pub const fn max_key_size(&self) -> u32 { + pub const fn max_key_size(&self) -> u27 { self.max_key_size } /// Returns the maximum height. /// - /// Default is `20`. The maximum height is `31`. The minimum height is `1`. + /// Default is `20`. The maximum height is `u5::MAX`. The minimum height is `1`. /// /// # Example /// /// ``` - /// use skl::Options; + /// use skl::{Options, u5}; /// - /// let options = Options::new().with_max_height(20); + /// let options = Options::new().with_max_height(u5::new(5)); /// - /// assert_eq!(options.max_height(), 20); + /// assert_eq!(options.max_height(), u5::new(5)); /// ``` #[inline] - pub const fn max_height(&self) -> u8 { + pub const fn max_height(&self) -> u5 { self.max_height }