use std::cell::Cell;
use std::marker::PhantomData;
use std::ptr;
use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
use crate::comparator::Comparator;
const BLOCK_SIZE: usize = 4096;
struct Arena {
alloc_ptr: *mut u8,
alloc_bytes_remaining: usize,
blocks: Vec<Box<[u8]>>,
}
unsafe impl Send for Arena {}
impl Arena {
fn new() -> Self {
Self {
alloc_ptr: ptr::null_mut(),
alloc_bytes_remaining: 0,
blocks: Vec::new(),
}
}
fn allocate_aligned(&mut self, bytes: usize, align: usize) -> *mut u8 {
debug_assert!(align.is_power_of_two());
let current_mod = (self.alloc_ptr as usize) & (align - 1);
let slop = if current_mod == 0 {
0
} else {
align - current_mod
};
let needed = bytes + slop;
if needed <= self.alloc_bytes_remaining {
unsafe {
let result = self.alloc_ptr.add(slop);
self.alloc_ptr = self.alloc_ptr.add(needed);
self.alloc_bytes_remaining -= needed;
result
}
} else {
self.allocate_fallback(bytes)
}
}
#[cold]
fn allocate_fallback(&mut self, bytes: usize) -> *mut u8 {
if bytes > BLOCK_SIZE / 4 {
self.allocate_new_block(bytes)
} else {
let new_block = self.allocate_new_block(BLOCK_SIZE);
unsafe {
self.alloc_ptr = new_block.add(bytes);
self.alloc_bytes_remaining = BLOCK_SIZE - bytes;
}
new_block
}
}
#[cold]
fn allocate_new_block(&mut self, size: usize) -> *mut u8 {
let v = vec![0; size];
let mut block = v.into_boxed_slice();
let ptr = block.as_mut_ptr();
self.blocks.push(block);
ptr
}
}
fn arena_alloc_slice_copy(arena: &mut Arena, src: &[u8]) -> *const [u8] {
if src.is_empty() {
return ptr::slice_from_raw_parts(ptr::null::<u8>(), 0);
}
let dst = arena.allocate_aligned(src.len(), 1);
unsafe {
ptr::copy_nonoverlapping(src.as_ptr(), dst, src.len());
}
ptr::slice_from_raw_parts(dst as *const u8, src.len())
}
fn arena_alloc_slice_fill_with<T>(
arena: &mut Arena,
count: usize,
mut init: impl FnMut() -> T,
) -> *mut [T] {
if count == 0 {
return ptr::slice_from_raw_parts_mut(ptr::null_mut::<T>(), 0);
}
let layout = std::alloc::Layout::array::<T>(count)
.expect("arena_alloc_slice_fill_with: layout overflow");
let raw = arena.allocate_aligned(layout.size(), layout.align()) as *mut T;
for i in 0..count {
unsafe {
ptr::write(raw.add(i), init());
}
}
ptr::slice_from_raw_parts_mut(raw, count)
}
fn arena_alloc<T>(arena: &mut Arena, value: T) -> *mut T {
let layout = std::alloc::Layout::new::<T>();
let raw = arena.allocate_aligned(layout.size(), layout.align()) as *mut T;
unsafe {
ptr::write(raw, value);
}
raw
}
pub const MAX_HEIGHT: usize = 12;
pub const BRANCHING: u32 = 4;
pub(crate) struct Node {
key: *const [u8],
next: *mut [AtomicPtr<Node>],
}
impl Node {
unsafe fn key(&self) -> &[u8] {
&*self.key
}
unsafe fn next_at(&self, level: usize) -> *mut Node {
(&*self.next)[level].load(Ordering::Acquire)
}
unsafe fn set_next(&self, level: usize, ptr: *mut Node) {
(&*self.next)[level].store(ptr, Ordering::Release);
}
unsafe fn next_at_no_barrier(&self, level: usize) -> *mut Node {
(&*self.next)[level].load(Ordering::Relaxed)
}
unsafe fn set_next_no_barrier(&self, level: usize, ptr: *mut Node) {
(&*self.next)[level].store(ptr, Ordering::Relaxed);
}
}
fn allocate_node_in(arena: &mut Arena, key: &[u8], height: usize) -> *mut Node {
let key_ptr = arena_alloc_slice_copy(arena, key);
allocate_node_for_key(arena, key_ptr, height)
}
fn allocate_node_for_key(arena: &mut Arena, key: *const [u8], height: usize) -> *mut Node {
let next = arena_alloc_slice_fill_with(arena, height, || AtomicPtr::new(ptr::null_mut()));
arena_alloc(arena, Node { key, next })
}
pub struct SkipList<C: Comparator> {
arena: Arena,
head: *mut Node,
comparator: C,
height: AtomicUsize,
rng_state: Cell<u32>,
}
unsafe impl<C: Comparator + Send> Send for SkipList<C> {}
unsafe impl<C: Comparator + Sync> Sync for SkipList<C> {}
impl<C: Comparator> SkipList<C> {
pub fn new(comparator: C) -> Self {
let mut arena = Arena::new();
let head = allocate_node_in(&mut arena, &[], MAX_HEIGHT);
Self {
arena,
head,
comparator,
height: AtomicUsize::new(1),
rng_state: Cell::new(0xdead_beef & 0x7fff_ffff),
}
}
pub fn reserve(&mut self, additional: usize) {
let _ = additional;
}
pub fn insert(&mut self, key: Vec<u8>) {
let key_ptr = arena_alloc_slice_copy(&mut self.arena, &key);
self.insert_key_ptr(key_ptr);
}
pub fn insert_with<F>(&mut self, len: usize, fill: F)
where
F: FnOnce(&mut [u8]),
{
let (raw, key_slice): (*const u8, &mut [u8]) = if len == 0 {
(ptr::null::<u8>(), &mut [])
} else {
let raw = self.arena.allocate_aligned(len, 1);
let slice = unsafe { std::slice::from_raw_parts_mut(raw, len) };
(raw as *const u8, slice)
};
fill(key_slice);
let key_ptr = ptr::slice_from_raw_parts(raw, len);
self.insert_key_ptr(key_ptr);
}
fn insert_key_ptr(&mut self, key_ptr: *const [u8]) {
let key = unsafe { &*key_ptr };
let mut prev: [*mut Node; MAX_HEIGHT] = [ptr::null_mut(); MAX_HEIGHT];
let existing = self.find_greater_or_equal(key, Some(&mut prev));
debug_assert!(
existing.is_null()
|| self
.comparator
.compare(unsafe { (*existing).key() }, key)
.is_ne(),
"SkipList::insert called with duplicate key"
);
let height = self.random_height();
let current_height = self.height.load(Ordering::Acquire);
if height > current_height {
for slot in prev.iter_mut().take(height).skip(current_height) {
*slot = self.head;
}
self.height.store(height, Ordering::Release);
}
let node_ptr = allocate_node_for_key(&mut self.arena, key_ptr, height);
unsafe {
for (i, prev_ptr) in prev.iter().copied().enumerate().take(height) {
let prev_node = &*prev_ptr;
(*node_ptr).set_next_no_barrier(i, prev_node.next_at_no_barrier(i));
prev_node.set_next(i, node_ptr);
}
}
}
pub fn contains(&self, key: &[u8]) -> bool {
let n = self.find_greater_or_equal(key, None);
!n.is_null() && unsafe { self.comparator.compare((*n).key(), key).is_eq() }
}
pub fn iter(&self) -> SkipListIter<'_, C> {
SkipListIter {
list: self,
node: ptr::null_mut(),
}
}
pub(crate) fn cursor(&self) -> SkipListCursor<C> {
SkipListCursor {
list: self as *const SkipList<C>,
node: ptr::null_mut(),
_marker: PhantomData,
}
}
fn find_greater_or_equal(
&self,
key: &[u8],
mut prev: Option<&mut [*mut Node; MAX_HEIGHT]>,
) -> *mut Node {
let mut x = self.head;
let mut level = self.height.load(Ordering::Acquire) - 1;
loop {
let next = unsafe { (*x).next_at(level) };
if !next.is_null()
&& self
.comparator
.compare(unsafe { (*next).key() }, key)
.is_lt()
{
x = next;
} else {
if let Some(prev) = prev.as_deref_mut() {
prev[level] = x;
}
if level == 0 {
return next;
}
level -= 1;
}
}
}
fn find_less_than(&self, key: &[u8]) -> *mut Node {
let mut x = self.head;
let mut level = self.height.load(Ordering::Acquire) - 1;
loop {
let next = unsafe { (*x).next_at(level) };
if !next.is_null()
&& self
.comparator
.compare(unsafe { (*next).key() }, key)
.is_lt()
{
x = next;
} else {
if level == 0 {
return x;
}
level -= 1;
}
}
}
fn find_last(&self) -> *mut Node {
let mut x = self.head;
let mut level = self.height.load(Ordering::Acquire) - 1;
loop {
let next = unsafe { (*x).next_at(level) };
if next.is_null() {
if level == 0 {
return x;
}
level -= 1;
} else {
x = next;
}
}
}
fn random_height(&self) -> usize {
let mut height = 1usize;
while height < MAX_HEIGHT && self.random_next().is_multiple_of(BRANCHING) {
height += 1;
}
height
}
fn random_next(&self) -> u32 {
const M: u32 = 2_147_483_647;
const A: u64 = 16_807;
let product = u64::from(self.rng_state.get()) * A;
let mut seed = ((product >> 31) + (product & u64::from(M))) as u32;
if seed > M {
seed -= M;
}
self.rng_state.set(seed);
seed
}
}
pub(crate) struct SkipListCursor<C: Comparator> {
list: *const SkipList<C>,
node: *mut Node,
_marker: PhantomData<C>,
}
impl<C: Comparator> SkipListCursor<C> {
fn list(&self) -> &SkipList<C> {
unsafe { &*self.list }
}
pub fn valid(&self) -> bool {
!self.node.is_null()
}
pub fn key(&self) -> &[u8] {
assert!(self.valid());
unsafe { (*self.node).key() }
}
pub fn seek_to_first(&mut self) {
self.node = unsafe { (*self.list().head).next_at(0) };
}
pub fn seek_to_last(&mut self) {
let list = self.list();
let last = list.find_last();
self.node = if ptr::eq(last, list.head) {
ptr::null_mut()
} else {
last
};
}
pub fn seek(&mut self, target: &[u8]) {
self.node = self.list().find_greater_or_equal(target, None);
}
pub fn next(&mut self) {
assert!(self.valid());
self.node = unsafe { (*self.node).next_at(0) };
}
pub fn prev(&mut self) {
assert!(self.valid());
let key = unsafe { (*self.node).key().to_vec() };
let list = self.list();
let candidate = list.find_less_than(&key);
self.node = if ptr::eq(candidate, list.head) {
ptr::null_mut()
} else {
candidate
};
}
}
pub struct SkipListIter<'a, C: Comparator> {
list: &'a SkipList<C>,
node: *mut Node,
}
impl<'a, C: Comparator> SkipListIter<'a, C> {
pub fn valid(&self) -> bool {
!self.node.is_null()
}
pub fn key(&self) -> &[u8] {
assert!(self.valid());
unsafe { (*self.node).key() }
}
pub fn seek_to_first(&mut self) {
self.node = unsafe { (*self.list.head).next_at(0) };
}
pub fn seek_to_last(&mut self) {
let last = self.list.find_last();
self.node = if ptr::eq(last, self.list.head) {
ptr::null_mut()
} else {
last
};
}
pub fn seek(&mut self, target: &[u8]) {
self.node = self.list.find_greater_or_equal(target, None);
}
pub fn next(&mut self) {
assert!(self.valid());
self.node = unsafe { (*self.node).next_at(0) };
}
pub fn prev(&mut self) {
assert!(self.valid());
let key = unsafe { (*self.node).key().to_vec() };
let candidate = self.list.find_less_than(&key);
self.node = if ptr::eq(candidate, self.list.head) {
ptr::null_mut()
} else {
candidate
};
}
}