YA6A53B5DH4CTM4QO6RMERXQ6I3H3LAZ4V4Q2TBCG44GILTWMG3AC
use super::MutPage;
const N_LEVELS: usize = 7;
pub const SKIPLIST_ROOT: u16 = 8;
const RIGHT_CHILD_OFFSET_U64: isize = 1;
pub const FIRST_BINDING_SIZE: u16 = SKIPLIST_ROOT + 16;
#[derive(Debug, Copy, Clone)]
pub struct SkipCursor {
pub levels: [u16; N_LEVELS],
pub started: bool,
}
impl SkipCursor {
pub fn new() -> Self {
SkipCursor {
levels: [SKIPLIST_ROOT; N_LEVELS],
started: false,
}
}
pub fn reset(&mut self) {
for i in self.levels.iter_mut() {
*i = SKIPLIST_ROOT
}
self.started = false
}
}
/// Sets the cursor to the last position strictly smaller than
/// (key, value). If the key (and possibly value) was found, the
/// corresponding value is returned.
pub(crate) fn set_cursor(
page: &MutPage,
curs: &mut SkipCursor,
key: u64,
) -> Option<u64> {
let mut level = N_LEVELS - 1;
loop {
let result = set_cursor_at_level(page, &mut curs.levels[level], level, key);
if level == 0 {
return result;
}
level -= 1;
curs.levels[level] = curs.levels[level + 1]
}
}
/// Moves the cursor at level `level`, until the final position is
/// either immediately before NIL, or the largest position
/// strictly smaller than (key, value). If (key, value) was found,
/// it is returned.
fn set_cursor_at_level(
page: &MutPage,
position: &mut u16,
level: usize,
key: u64,
) -> Option<u64> {
loop {
let next_position = next_at_level(page, *position, level);
if next_position == 0 {
return None;
}
let (k, v) = unsafe { read_key_value(page, next_position) };
if k == key {
return Some(v)
} else if k < key {
debug_assert!(*position != next_position);
*position = next_position
} else {
return None
}
}
}
unsafe fn set_level(p: *mut u8, level: usize, value: u16) {
debug_assert!(level < N_LEVELS);
debug_assert_eq!(value & 7, 0); // Check that value is multiple of 8.
debug_assert_eq!((p as usize) & 7, 0); // Check that the conversion to *mut u64 is valid.
let p = p as *mut u64;
let mut levels = u64::from_le(*p);
// All values are 8-bytes aligned, we don't need to store the 3 extra 0s.
let value = (value >> 3) as u64;
// Set the value at that level to 0.
levels &= !(0x1ff << (9 * level));
// Replace with current value.
levels |= value << (9 * level);
*p = levels.to_le()
}
/// This function panics if there's enough space on the page.
#[doc(hidden)]
pub(crate) fn skiplist_insert_after_cursor(
page: &mut MutPage,
r: &mut u8,
cursor: &mut SkipCursor,
key: u64,
value: u64,
right_child: u64,
) {
// First allocate the key and value.
let off = page.alloc(32);
debug_assert_ne!(off, 0);
page.reset_pointers(off);
unsafe {
*(page.p.offset(off as isize + 16) as *mut u64) = key;
*(page.p.offset(off as isize + 24) as *mut u64) = value;
}
set_right_child(page, off, right_child);
// Now insert in the base list.
let mut g = *r;
*r += 1;
for l in 0..N_LEVELS {
unsafe {
debug_assert_ne!(off, next_at_level(page, cursor.levels[l], l));
debug_assert_ne!(off, cursor.levels[l]);
set_level(
page.p.offset(off as isize),
l,
next_at_level(page, cursor.levels[l], l),
);
set_level(page.p.offset(cursor.levels[l] as isize), l, off);
}
cursor.levels[l] = off;
if g & 1 == 0 {
break;
}
g >>= 1
}
}
#[doc(hidden)]
pub(crate) fn set_right_child(page: &MutPage, off: u16, r: u64) {
if off >= 4096 {
panic!("{} < 4096", off);
}
unsafe {
*((page.offset(off as isize) as *mut u64).offset(RIGHT_CHILD_OFFSET_U64)) = r.to_le();
}
}
impl MutPage {
fn reset_pointers(&mut self, offset: u16) {
// Initialize the list pointers.
unsafe {
let p: *mut u8 = self.p.offset(offset as isize);
std::ptr::write_bytes(p, 0, 8);
}
}
}
// All bindings are 8-bytes aligned. There are 7 layers, each
// encoding 9 bits, which are then multiplied by 8 to get the
// position on the page.
pub(crate) fn next_at_level(p: &MutPage, off: u16, level: usize) -> u16 {
unsafe {
debug_assert!(level < N_LEVELS);
let levels = u64::from_le(*(p.offset(off as isize) as *const u64));
(((levels >> (9 * level)) & 0x1ff) as u16) << 3
}
}
pub(crate) unsafe fn read_key_value(
p: &MutPage,
off: u16,
) -> (u64, u64) {
assert!(off < 4096);
(*(p.offset(off as isize + 16) as *mut u64),
*(p.offset(off as isize + 24) as *mut u64))
}
impl MutPage {
pub fn init_skiplist_page(&mut self) {
self.reset_pointers(SKIPLIST_ROOT);
// Initialize the page metadata.
self.set_first_free(FIRST_BINDING_SIZE); // first free spot.
self.set_size(FIRST_BINDING_SIZE); // occupied size on page.
unsafe {
*((self.offset(SKIPLIST_ROOT as isize) as *mut u64).offset(RIGHT_CHILD_OFFSET_U64)) = 0;
}
}
}
mod skiplist;
fn main() {
let mut page = [0u8; 4096];
let mut total_put = std::time::Duration::from_secs(0);
let mut total_lookup = std::time::Duration::from_secs(0);
for _ in 0..1_000_000 {
let mut p = MutPage {
p: page.as_mut_ptr()
};
unsafe {
p.init();
let now = std::time::SystemTime::now();
for i in 0..170 {
p.put(i * i, i * i * i, 0);
}
total_put += now.elapsed().unwrap();
let now = std::time::SystemTime::now();
for i in 0..170 {
p.lookup(i * i);
}
total_lookup += now.elapsed().unwrap();
}
}
println!("{:?} {:?}", total_put, total_lookup);
let mut total_put = std::time::Duration::from_secs(0);
let mut total_lookup = std::time::Duration::from_secs(0);
for _ in 0..1_000_000 {
let mut p = MutPage {
p: page.as_mut_ptr()
};
unsafe {
p.init();
for i in 0..170 {
let now = std::time::SystemTime::now();
p.put_ord(i * i, i * i * i, 0);
total_put += now.elapsed().unwrap();
}
let now = std::time::SystemTime::now();
for i in 0..170 {
p.lookup_ord(i * i);
}
total_lookup += now.elapsed().unwrap();
}
}
println!("{:?} {:?}", total_put, total_lookup);
let mut rng = 0;
let mut total_put = std::time::Duration::from_secs(0);
let mut total_lookup = std::time::Duration::from_secs(0);
for _ in 0..1_000_000 {
let mut p = MutPage {
p: page.as_mut_ptr()
};
p.init_skiplist_page();
let mut c = skiplist::SkipCursor::new();
let now = std::time::SystemTime::now();
for i in 0..100 {
c.reset();
skiplist::set_cursor(&p, &mut c, i * i);
skiplist::skiplist_insert_after_cursor(&mut p, &mut rng, &mut c, i*i, i*i*i, 0);
}
total_put += now.elapsed().unwrap();
let now = std::time::SystemTime::now();
for i in 0..100 {
c.reset();
skiplist::set_cursor(&p, &mut c, i * i);
}
total_lookup += now.elapsed().unwrap();
}
println!("{:?} {:?}", total_put, total_lookup);
}
struct MutPage {
p: *mut u8,
}
impl MutPage {
pub unsafe fn init(&mut self) {
let p = self.p as *mut u64;
*(p.offset(1)) = 0;
self.set_size(16);
self.set_first_free(16);
}
pub fn size(&self) -> u16 {
unsafe {
u16::from_le(*(self.p as *mut u16).offset(2))
}
}
pub fn set_size(&self, n: u16) {
unsafe {
*(self.p as *mut u16).offset(2) = n.to_le()
}
}
pub fn set_first_free(&self, n: u16) {
unsafe {
*(self.p as *mut u16).offset(3) = n.to_le()
}
}
pub fn first_free(&self) -> u16 {
unsafe {
u16::from_le(*(self.p as *mut u16).offset(3))
}
}
pub unsafe fn put(&mut self, k0: u64, v0: u64, rr: u64) {
let rn0 = u64::from_le(*self.offset(8));
let mut n0 = (rn0 & 0xfff) as isize;
let mut i = n0;
n0 = 8;
while i != 0 {
let k = u64::from_le(*self.offset(i + 8));
if k0 < k {
let rn = u64::from_le(*self.offset(i));
let n = (rn & 0xfff) as isize;
n0 = i;
i = n
} else if k0 == k {
return
} else {
// Insérer ici.
let off = self.alloc(24);
let r0 = *self.offset(n0) & !0xfff;
*self.offset(n0) = r0 | (off as u64);
*self.offset(off as isize) = rr | (i as u64);
*self.offset(off as isize + 8) = k0.to_le();
*self.offset(off as isize + 16) = v0.to_le();
return
}
}
let off = self.alloc(24);
let r0 = *self.offset(n0) & !0xfff;
*self.offset(n0) = r0 | (off as u64);
*self.offset(off as isize) = rr.to_le();
*self.offset(off as isize + 8) = k0.to_le();
*self.offset(off as isize + 16) = v0.to_le();
}
unsafe fn offset(&self, i: isize) -> *mut u64 {
self.p.offset(i) as *mut u64
}
pub fn alloc(&mut self, n: u16) -> u16 {
self.set_size(self.size() + n);
let result = self.first_free();
assert!(result + n <= 4096);
self.set_first_free(result + n);
result
}
pub unsafe fn lookup(&self, k0: u64) -> Option<u64> {
let rn0 = u64::from_le(*self.offset(8));
let mut i = (rn0 & 0xfff) as isize;
while i != 0 {
let k = u64::from_le(*self.offset(i + 8));
if k0 < k {
let rn = u64::from_le(*self.offset(i));
let n = (rn & 0xfff) as isize;
i = n
} else if k0 == k {
return Some(u64::from_le(*self.offset(i + 16)))
} else {
return None
}
}
None
}
}
impl MutPage {
pub unsafe fn lookup_ord_(&mut self, k0: u64) -> u16 {
let mut a = 16;
let mut b = self.size();
assert!(b <= 4096);
while a < b {
let mid = (a + b) / 2 - 16;
let mid = 16 + mid - (mid % 24);
let k = *(self.p.offset(mid as isize) as *mut u64);
if k < k0 {
if a == mid {
break
}
a = mid
} else {
b = mid
}
}
a
}
pub unsafe fn lookup_ord(&mut self, k0: u64) -> Option<u64> {
let off = self.lookup_ord_(k0) as isize;
let k = *(self.p.offset(off) as *mut u64);
if k == k0 {
Some(*(self.p.offset(off + 8) as *mut u64))
} else {
None
}
}
pub unsafe fn put_ord(&mut self, k0: u64, v0: u64, _rr: u64) {
let size = self.size();
let off = self.lookup_ord_(k0);
if size > off {
std::ptr::copy(self.p.offset(off as isize), self.p.offset(off as isize + 24), (size - off) as usize);
}
*self.offset(off as isize + 8) = k0.to_le();
*self.offset(off as isize + 16) = v0.to_le();
self.set_size(size + 24);
}
}
[package]
name = "sanakirja2"
version = "0.1.0"
authors = ["pe"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]