From 4eb2851cf998bec7bc161da73f33c4b7d323c967 Mon Sep 17 00:00:00 2001 From: Sayan Nandan Date: Mon, 24 Apr 2023 22:27:07 -0700 Subject: [PATCH] Improve word impls --- server/src/engine/core/index/key.rs | 26 +- server/src/engine/core/model/cell.rs | 37 +- server/src/engine/data/lit.rs | 22 +- server/src/engine/data/spec.rs | 24 +- server/src/engine/mem/mod.rs | 4 +- .../src/engine/mem/{tests.rs => tests/mod.rs} | 1 + server/src/engine/mem/tests/word.rs | 145 +++++ server/src/engine/mem/word.rs | 511 +++++++++--------- 8 files changed, 453 insertions(+), 317 deletions(-) rename server/src/engine/mem/{tests.rs => tests/mod.rs} (99%) create mode 100644 server/src/engine/mem/tests/word.rs diff --git a/server/src/engine/core/index/key.rs b/server/src/engine/core/index/key.rs index dcc16f02..4090c380 100644 --- a/server/src/engine/core/index/key.rs +++ b/server/src/engine/core/index/key.rs @@ -35,7 +35,7 @@ use { tag::{DataTag, TagUnique}, }, idx::meta::Comparable, - mem::{self, NativeDword, SystemDword}, + mem::{self, DwordQN, SpecialPaddedWord, WordIO}, }, core::{ fmt, @@ -47,12 +47,12 @@ use { pub struct PrimaryIndexKey { tag: TagUnique, - data: NativeDword, + data: SpecialPaddedWord, } impl PrimaryIndexKey { pub unsafe fn read_uint(&self) -> u64 { - self.data.load_qw() + self.data.load() } pub fn uint(&self) -> Option { (self.tag == TagUnique::UnsignedInt).then_some(unsafe { @@ -61,7 +61,7 @@ impl PrimaryIndexKey { }) } pub unsafe fn read_sint(&self) -> i64 { - self.data.load_qw() as _ + self.data.load() } pub fn sint(&self) -> Option { (self.tag == TagUnique::SignedInt).then_some(unsafe { @@ -105,16 +105,16 @@ impl PrimaryIndexKey { debug_assert!(Self::check(&dc)); let tag = dc.tag().tag_unique(); let dc = ManuallyDrop::new(dc); - let dword = unsafe { + let (a, b) = unsafe { // UNSAFE(@ohsayan): this doesn't do anything "bad" by itself. needs the construction to be broken for it to do something silly dc.as_raw() } - .load_double(); + .dwordqn_load_qw_nw(); Self { tag, data: unsafe { - // UNSAFE(@ohsayan): Perfectly safe since we're tranforming it and THIS will not by itself crash anything - core::mem::transmute(dword) + // UNSAFE(@ohsayan): loaded above, writing here + SpecialPaddedWord::new(a, b) }, } } @@ -126,12 +126,12 @@ impl PrimaryIndexKey { } /// ## Safety /// If you mess up construction, everything will fall apart - pub unsafe fn new(tag: TagUnique, data: NativeDword) -> Self { + pub unsafe fn new(tag: TagUnique, data: SpecialPaddedWord) -> Self { Self { tag, data } } fn __compute_vdata_offset(&self) -> [usize; 2] { - let [len, data] = self.data.load_double(); - let actual_len = len * (self.tag >= TagUnique::Bin) as usize; + let (len, data) = self.data.dwordqn_load_qw_nw(); + let actual_len = (len as usize) * (self.tag >= TagUnique::Bin) as usize; [data, actual_len] } fn virtual_block(&self) -> &[u8] { @@ -164,7 +164,7 @@ impl Drop for PrimaryIndexKey { impl PartialEq for PrimaryIndexKey { fn eq(&self, other: &Self) -> bool { - let [data_1, data_2] = [self.data.load_double()[0], other.data.load_double()[0]]; + let [data_1, data_2]: [u64; 2] = [self.data.load(), other.data.load()]; ((self.tag == other.tag) & (data_1 == data_2)) && self.virtual_block() == other.virtual_block() } @@ -282,6 +282,8 @@ fn check_pk_extremes() { let d1 = PrimaryIndexKey::try_from_dc(Datacell::new_uint(u64::MAX)).unwrap(); let d2 = PrimaryIndexKey::try_from_dc(Datacell::from(LitIR::UnsignedInt(u64::MAX))).unwrap(); assert_eq!(d1, d2); + assert_eq!(d1.uint().unwrap(), u64::MAX); + assert_eq!(d2.uint().unwrap(), u64::MAX); assert_eq!( test_utils::hash_rs(&state, &d1), test_utils::hash_rs(&state, &d2) diff --git a/server/src/engine/core/model/cell.rs b/server/src/engine/core/model/cell.rs index f46e1b83..effd8cfc 100644 --- a/server/src/engine/core/model/cell.rs +++ b/server/src/engine/core/model/cell.rs @@ -32,7 +32,7 @@ use { spec::{Dataspec1D, DataspecMeta1D}, tag::{CUTag, DataTag, TagClass}, }, - mem::{NativeQword, SystemDword, SystemTword, WordRW}, + mem::{DwordNN, DwordQN, NativeQword, WordIO}, }, core::{fmt, mem, mem::ManuallyDrop, slice, str}, parking_lot::RwLock, @@ -49,7 +49,7 @@ impl Datacell { pub fn new_bool(b: bool) -> Self { unsafe { // UNSAFE(@ohsayan): Correct because we are initializing Self with the correct tag - Self::new(CUTag::BOOL, DataRaw::word(SystemDword::store(b))) + Self::new(CUTag::BOOL, DataRaw::word(WordIO::store(b))) } } pub unsafe fn read_bool(&self) -> bool { @@ -68,7 +68,7 @@ impl Datacell { pub fn new_uint(u: u64) -> Self { unsafe { // UNSAFE(@ohsayan): Correct because we are initializing Self with the correct tag - Self::new(CUTag::UINT, DataRaw::word(SystemDword::store(u))) + Self::new(CUTag::UINT, DataRaw::word(WordIO::store(u))) } } pub unsafe fn read_uint(&self) -> u64 { @@ -87,7 +87,7 @@ impl Datacell { pub fn new_sint(u: i64) -> Self { unsafe { // UNSAFE(@ohsayan): Correct because we are initializing Self with the correct tag - Self::new(CUTag::SINT, DataRaw::word(SystemDword::store(u))) + Self::new(CUTag::SINT, DataRaw::word(WordIO::store(u))) } } pub unsafe fn read_sint(&self) -> i64 { @@ -106,7 +106,7 @@ impl Datacell { pub fn new_float(f: f64) -> Self { unsafe { // UNSAFE(@ohsayan): Correct because we are initializing Self with the correct tag - Self::new(CUTag::FLOAT, DataRaw::word(SystemDword::store(f))) + Self::new(CUTag::FLOAT, DataRaw::word(WordIO::store(f))) } } pub unsafe fn read_float(&self) -> f64 { @@ -128,7 +128,7 @@ impl Datacell { // UNSAFE(@ohsayan): Correct because we are initializing Self with the correct tag Self::new( CUTag::BIN, - DataRaw::word(SystemDword::store((md.len(), md.as_mut_ptr()))), + DataRaw::word(WordIO::store((md.len(), md.as_mut_ptr()))), ) } } @@ -152,7 +152,7 @@ impl Datacell { // UNSAFE(@ohsayan): Correct because we are initializing Self with the correct tag Self::new( CUTag::STR, - DataRaw::word(SystemDword::store((md.len(), md.as_mut_ptr()))), + DataRaw::word(WordIO::store((md.len(), md.as_mut_ptr()))), ) } } @@ -213,12 +213,10 @@ impl<'a> From> for Datacell { match l.kind().tag_class() { tag if tag < TagClass::Bin => unsafe { // UNSAFE(@ohsayan): Correct because we are using the same tag, and in this case the type doesn't need any advanced construction - let data = l.data().load_qw(); - let ptr = l.data().load_double()[1]; Datacell::new( CUTag::from(l.kind()), // DO NOT RELY ON the payload's bit pattern; it's padded - DataRaw::word(SystemTword::store_qw_nw(data, ptr as usize)), + DataRaw::word(l.data().dword_promote()), ) }, TagClass::Bin | TagClass::Str => unsafe { @@ -226,7 +224,7 @@ impl<'a> From> for Datacell { let mut bin = ManuallyDrop::new(l.read_bin_uck().to_owned().into_boxed_slice()); Datacell::new( CUTag::from(l.kind()), - DataRaw::word(SystemDword::store((bin.len(), bin.as_mut_ptr()))), + DataRaw::word(WordIO::store((bin.len(), bin.as_mut_ptr()))), ) }, _ => unsafe { @@ -270,7 +268,11 @@ impl Datacell { pub fn null() -> Self { unsafe { // UNSAFE(@ohsayan): This is a hack. It's safe because we set init to false - Self::_new(CUTag::BOOL, DataRaw::word(NativeQword::store_qw(0)), false) + Self::_new( + CUTag::BOOL, + DataRaw::word(NativeQword::dwordnn_store_qw(0)), + false, + ) } } pub fn is_null(&self) -> bool { @@ -286,8 +288,11 @@ impl Datacell { None } } - unsafe fn load_word<'a, T: WordRW = T>>(&'a self) -> T { - self.data.word.dword_ld() + unsafe fn load_word<'a, T>(&'a self) -> T + where + NativeQword: WordIO, + { + self.data.word.load() } unsafe fn _new(tag: CUTag, data: DataRaw, init: bool) -> Self { Self { init, tag, data } @@ -400,7 +405,7 @@ impl Clone for Datacell { // UNSAFE(@ohsayan): we have checked that the cell is initialized (uninit will not satisfy this class), and we have checked its class let mut block = ManuallyDrop::new(self.read_bin().to_owned().into_boxed_slice()); DataRaw { - word: ManuallyDrop::new(SystemDword::store((block.len(), block.as_mut_ptr()))), + word: ManuallyDrop::new(WordIO::store((block.len(), block.as_mut_ptr()))), } }, TagClass::List => unsafe { @@ -411,7 +416,7 @@ impl Clone for Datacell { } }, _ => unsafe { - // UNSAFE(@ohsayan): we have checked that the cell is initialized (uninit will not satisfy this class), and we have checked its class + // UNSAFE(@ohsayan): we have checked that the cell is a stack class DataRaw { word: ManuallyDrop::new(mem::transmute_copy(&self.data.word)), } diff --git a/server/src/engine/data/lit.rs b/server/src/engine/data/lit.rs index 038a8531..0ef9e035 100644 --- a/server/src/engine/data/lit.rs +++ b/server/src/engine/data/lit.rs @@ -29,7 +29,7 @@ use { spec::{Dataspec1D, DataspecMeta1D, DataspecMethods1D, DataspecRaw1D}, tag::{DataTag, FullTag, TagUnique}, }, - crate::engine::mem::{SpecialPaddedWord, SystemDword}, + crate::engine::mem::{DwordQN, SpecialPaddedWord, WordIO}, core::{ fmt, hash::{Hash, Hasher}, @@ -93,16 +93,16 @@ unsafe impl<'a> DataspecRaw1D for Lit<'a> { const HEAP_STR: bool = true; const HEAP_BIN: bool = false; unsafe fn drop_str(&mut self) { - let [len, ptr] = self.data().load_double(); - drop(String::from_raw_parts(ptr as *mut u8, len, len)); + let (len, ptr) = self.data().load(); + drop(String::from_raw_parts(ptr, len, len)); } unsafe fn drop_bin(&mut self) {} unsafe fn clone_str(s: &str) -> Self::Target { let new_string = ManuallyDrop::new(s.to_owned().into_boxed_str()); - SystemDword::store((new_string.len(), new_string.as_ptr())) + WordIO::store((new_string.len(), new_string.as_ptr())) } unsafe fn clone_bin(b: &[u8]) -> Self::Target { - SystemDword::store((b.len(), b.as_ptr())) + WordIO::store((b.len(), b.as_ptr())) } } @@ -114,7 +114,7 @@ unsafe impl<'a> DataspecRaw1D for Lit<'a> { unsafe impl<'a> Dataspec1D for Lit<'a> { fn Str(s: Box) -> Self { let md = ManuallyDrop::new(s); - Self::new(FullTag::STR, SystemDword::store((md.len(), md.as_ptr()))) + Self::new(FullTag::STR, WordIO::store((md.len(), md.as_ptr()))) } } @@ -184,8 +184,8 @@ pub struct LitIR<'a> { impl<'a> LitIR<'a> { pub fn __vdata(&self) -> &[u8] { - let [vlen, data] = self.data().load_double(); - let len = vlen * (self.kind().tag_unique() >= TagUnique::Bin) as usize; + let (vlen, data) = self.data().dwordqn_load_qw_nw(); + let len = vlen as usize * (self.kind().tag_unique() >= TagUnique::Bin) as usize; unsafe { // UNSAFE(@ohsayan): either because of static or lt slice::from_raw_parts(data as *const u8, len) @@ -237,10 +237,10 @@ unsafe impl<'a> DataspecRaw1D for LitIR<'a> { unsafe fn drop_str(&mut self) {} unsafe fn drop_bin(&mut self) {} unsafe fn clone_str(s: &str) -> Self::Target { - SystemDword::store((s.len(), s.as_ptr())) + WordIO::store((s.len(), s.as_ptr())) } unsafe fn clone_bin(b: &[u8]) -> Self::Target { - SystemDword::store((b.len(), b.as_ptr())) + WordIO::store((b.len(), b.as_ptr())) } } @@ -250,7 +250,7 @@ unsafe impl<'a> DataspecRaw1D for LitIR<'a> { */ unsafe impl<'a> Dataspec1D for LitIR<'a> { fn Str(s: Self::StringItem) -> Self { - Self::new(FullTag::STR, SystemDword::store((s.len(), s.as_ptr()))) + Self::new(FullTag::STR, WordIO::store((s.len(), s.as_ptr()))) } } diff --git a/server/src/engine/data/spec.rs b/server/src/engine/data/spec.rs index 40f71d39..9a9e71c2 100644 --- a/server/src/engine/data/spec.rs +++ b/server/src/engine/data/spec.rs @@ -31,7 +31,7 @@ use { super::tag::{DataTag, TagClass}, - crate::engine::mem::SystemDword, + crate::engine::mem::{DwordQN, WordIO}, core::{fmt, mem, slice}, }; @@ -45,7 +45,7 @@ pub trait DataspecMeta1D: Sized { // assoc type Tag: DataTag; /// The target must be able to store (atleast) a native dword - type Target: SystemDword; + type Target: DwordQN; /// The string item. This helps us remain correct with the dtors type StringItem; // fn @@ -86,27 +86,27 @@ pub unsafe trait Dataspec1D: DataspecMeta1D + DataspecRaw1D { /// Store a new bool. This function is always safe to call #[allow(non_snake_case)] fn Bool(b: bool) -> Self { - Self::new(Self::Tag::BOOL, SystemDword::store(b)) + Self::new(Self::Tag::BOOL, WordIO::store(b)) } /// Store a new uint. This function is always safe to call #[allow(non_snake_case)] fn UnsignedInt(u: u64) -> Self { - Self::new(Self::Tag::UINT, SystemDword::store(u)) + Self::new(Self::Tag::UINT, WordIO::store(u)) } /// Store a new sint. This function is always safe to call #[allow(non_snake_case)] fn SignedInt(s: i64) -> Self { - Self::new(Self::Tag::SINT, SystemDword::store(s)) + Self::new(Self::Tag::SINT, WordIO::store(s)) } /// Store a new float. This function is always safe to call #[allow(non_snake_case)] fn Float(f: f64) -> Self { - Self::new(Self::Tag::FLOAT, SystemDword::store(f.to_bits())) + Self::new(Self::Tag::FLOAT, WordIO::store(f.to_bits())) } /// Store a new binary. This function is always safe to call #[allow(non_snake_case)] fn Bin(b: &[u8]) -> Self { - Self::new(Self::Tag::BIN, SystemDword::store((b.len(), b.as_ptr()))) + Self::new(Self::Tag::BIN, WordIO::store((b.len(), b.as_ptr()))) } /// Store a new string. Now, I won't talk about this one's safety because it depends on the implementor @@ -117,7 +117,7 @@ pub unsafe trait Dataspec1D: DataspecMeta1D + DataspecRaw1D { // bool /// Load a bool (this is unsafe for logical verity) unsafe fn read_bool_uck(&self) -> bool { - self.data().dword_ld() + self.data().load() } /// Load a bool fn read_bool_try(&self) -> Option { @@ -135,7 +135,7 @@ pub unsafe trait Dataspec1D: DataspecMeta1D + DataspecRaw1D { // uint /// Load a uint (this is unsafe for logical verity) unsafe fn read_uint_uck(&self) -> u64 { - self.data().dword_ld() + self.data().load() } /// Load a uint fn read_uint_try(&self) -> Option { @@ -156,7 +156,7 @@ pub unsafe trait Dataspec1D: DataspecMeta1D + DataspecRaw1D { // sint /// Load a sint (unsafe for logical verity) unsafe fn read_sint_uck(&self) -> i64 { - self.data().dword_ld() + self.data().load() } /// Load a sint fn read_sint_try(&self) -> Option { @@ -172,7 +172,7 @@ pub unsafe trait Dataspec1D: DataspecMeta1D + DataspecRaw1D { // float /// Load a float (unsafe for logical verity) unsafe fn read_float_uck(&self) -> f64 { - self.data().dword_ld() + self.data().load() } /// Load a float fn read_float_try(&self) -> Option { @@ -190,7 +190,7 @@ pub unsafe trait Dataspec1D: DataspecMeta1D + DataspecRaw1D { /// ## Safety /// Are you a binary? Did you store it correctly? Are you a victim of segfaults? unsafe fn read_bin_uck(&self) -> &[u8] { - let (l, p) = self.data().dword_ld(); + let (l, p) = self.data().load(); slice::from_raw_parts(p, l) } /// Load a bin diff --git a/server/src/engine/mem/mod.rs b/server/src/engine/mem/mod.rs index fa83aeda..d99940e0 100644 --- a/server/src/engine/mem/mod.rs +++ b/server/src/engine/mem/mod.rs @@ -35,7 +35,7 @@ mod tests; pub use astr::AStr; pub use uarray::UArray; pub use vinline::VInline; -pub use word::{SystemDword, SystemQword, SystemTword, WordRW}; +pub use word::{DwordNN, DwordQN, QwordNNNN, TwordNNN, WordIO}; // imports use std::alloc::{self, Layout}; @@ -58,7 +58,7 @@ pub struct SpecialPaddedWord { } impl SpecialPaddedWord { - const fn new(a: u64, b: usize) -> Self { + pub const unsafe fn new(a: u64, b: usize) -> Self { Self { a, b } } } diff --git a/server/src/engine/mem/tests.rs b/server/src/engine/mem/tests/mod.rs similarity index 99% rename from server/src/engine/mem/tests.rs rename to server/src/engine/mem/tests/mod.rs index 60221b86..efe152a8 100644 --- a/server/src/engine/mem/tests.rs +++ b/server/src/engine/mem/tests/mod.rs @@ -25,6 +25,7 @@ */ use super::*; +mod word; mod vinline { use super::VInline; diff --git a/server/src/engine/mem/tests/word.rs b/server/src/engine/mem/tests/word.rs new file mode 100644 index 00000000..d6efed52 --- /dev/null +++ b/server/src/engine/mem/tests/word.rs @@ -0,0 +1,145 @@ +/* + * Created on Mon Apr 24 2023 + * + * This file is a part of Skytable + * Skytable (formerly known as TerrabaseDB or Skybase) is a free and open-source + * NoSQL database written by Sayan Nandan ("the Author") with the + * vision to provide flexibility in data modelling without compromising + * on performance, queryability or scalability. + * + * Copyright (c) 2023, Sayan Nandan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * +*/ + +use { + crate::engine::mem::{ + word::{DwordQN, QwordNNNN, TwordNNN, WordIO, ZERO_BLOCK}, + NativeDword, NativeQword, NativeTword, SpecialPaddedWord, + }, + core::{slice, str}, +}; + +fn wordld>(w: &W, x: T) -> (T, T) { + (w.load(), x) +} + +macro_rules! assert_wordeq { + ($a:expr, $b:expr) => {{ + let (a, b) = wordld(&$a, $b); + assert_eq!(a, b); + }}; +} + +macro_rules! assert_wordeq_minmax { + ($word:ty => $($ty:ty),* $(,)?; with $extramin:ident, $extramax:ident) => {{ + $( + let x = <$word>::store(<$ty>::MIN); assert_wordeq!(x, <$ty>::MIN); + $extramin(&x); + let x = <$word>::store(<$ty>::MAX); assert_wordeq!(x, <$ty>::MAX); + $extramax(&x); + )* + }}; +} + +fn check_primitives(extramin: impl Fn(&W), extramax: impl Fn(&W)) +where + W: WordIO + + WordIO + + WordIO + + WordIO + + WordIO + + WordIO + + WordIO + + WordIO + + WordIO + + WordIO + + WordIO + + WordIO<(usize, usize)> + + WordIO<(usize, *mut u8)> + + WordIO<(usize, *const u8)>, +{ + assert_wordeq_minmax!(W => u8, u16, u32, u64, i8, i16, i32, i64, f32, f64; with extramin, extramax); + // bool + let x = W::store(false); + assert_wordeq!(x, false); + extramin(&x); + let x = W::store(true); + assert_wordeq!(x, true); + extramax(&x); + // str + let str = "hello, world"; + let x = W::store((str.len(), str.as_ptr())); + unsafe { + let (len, ptr) = x.load(); + assert_eq!( + str, + str::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) + ); + } + // string (mut) + let mut string = String::from("hello, world"); + let x = W::store((string.len(), string.as_mut_ptr())); + unsafe { + let (len, ptr) = x.load(); + assert_eq!( + string, + str::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) + ); + } +} + +#[test] +fn dwordnn_all() { + check_primitives::(|_| {}, |_| {}); +} + +#[test] +fn dwordqn_all() { + check_primitives::( + |minword| { + let (_a, b) = minword.dwordqn_load_qw_nw(); + assert_eq!(b, ZERO_BLOCK.as_ptr() as usize); + }, + |maxword| { + let (_a, b) = maxword.dwordqn_load_qw_nw(); + assert_eq!(b, ZERO_BLOCK.as_ptr() as usize); + }, + ); +} + +#[test] +fn twordnnn_all() { + check_primitives::(|_| {}, |_| {}); +} + +#[test] +fn qwordnnn_all() { + check_primitives::(|_| {}, |_| {}); +} + +#[test] +fn dwordqn_promotions() { + let x = SpecialPaddedWord::store(u64::MAX); + let y: NativeTword = x.dword_promote(); + let (uint, usize) = y.dwordqn_load_qw_nw(); + assert_eq!(uint, u64::MAX); + assert_eq!(usize, ZERO_BLOCK.as_ptr() as usize); + let z: NativeQword = y.tword_promote(); + let (uint, usize_1, usize_2) = z.qwordnnnn_load_qw_nw_nw(); + assert_eq!(uint, u64::MAX); + assert_eq!(usize_1, ZERO_BLOCK.as_ptr() as usize); + assert_eq!(usize_2, 0); +} diff --git a/server/src/engine/mem/word.rs b/server/src/engine/mem/word.rs index 5cd7cb72..035236ba 100644 --- a/server/src/engine/mem/word.rs +++ b/server/src/engine/mem/word.rs @@ -24,9 +24,12 @@ * */ -use super::{NativeDword, NativeQword, NativeTword, SpecialPaddedWord}; +use { + super::{NativeDword, NativeQword, NativeTword, SpecialPaddedWord}, + core::mem::size_of, +}; -static ZERO_BLOCK: [u8; 0] = []; +pub static ZERO_BLOCK: [u8; 0] = []; #[cfg(target_pointer_width = "32")] fn quadsplit(q: u64) -> [usize; 2] { @@ -43,353 +46,333 @@ fn quadmerge(v: [usize; 2]) -> u64 { } } -/// Native quad pointer stack (must also be usable as a double and triple pointer stack. see [`SystemTword`] and [`SystemDword`]) -pub trait SystemQword: SystemTword { - fn store_full(a: usize, b: usize, c: usize, d: usize) -> Self; - fn load_quad(&self) -> [usize; 4]; - fn store<'a, T>(v: T) -> Self - where - T: WordRW, - { - WordRW::store(v) - } - fn qword_ld<'a, T>(&'a self) -> T - where - T: WordRW = T>, - { - ::load(self) +pub trait WordIO { + fn store(v: T) -> Self; + fn load(&self) -> T; +} + +/* + dword + --- + kinds: NN (word * 2), QN (qword, word) + promotions: QN -> NNN +*/ + +pub trait DwordNN: Sized { + const DWORDNN_FROM_UPPER: bool = size_of::() > size_of::<[usize; 2]>(); + fn dwordnn_store_native_full(a: usize, b: usize) -> Self; + fn dwordnn_store_qw(a: u64) -> Self { + debug_assert!(!Self::DWORDNN_FROM_UPPER, "NEED TO OVERRIDE STORE"); + #[cfg(target_pointer_width = "32")] + { + let [a, b] = quadsplit(a); + Self::dwordnn_store_native_full(a, b) + } + #[cfg(target_pointer_width = "64")] + { + Self::dwordnn_store_native_full(a as usize, 0) + } + } + fn dwordnn_load_native_full(&self) -> [usize; 2]; + fn dwordnn_load_qw(&self) -> u64 { + debug_assert!(!Self::DWORDNN_FROM_UPPER, "NEED TO OVERRIDE LOAD"); + #[cfg(target_pointer_width = "32")] + { + quadmerge(self.dwordnn_load_native_full()) + } + #[cfg(target_pointer_width = "64")] + { + self.dwordnn_load_native_full()[0] as u64 + } } } -/// Native tripe pointer stack (must also be usable as a double pointer stack, see [`SystemDword`]) -pub trait SystemTword: SystemDword { - /// Store a quad and a native word - fn store_qw_nw(a: u64, b: usize) -> Self; - /// Load a quad and a native word - fn load_qw_nw(&self) -> (u64, usize); - fn store_full(a: usize, b: usize, c: usize) -> Self; - fn load_triple(&self) -> [usize; 3]; - fn store<'a, T>(v: T) -> Self - where - T: WordRW, - { - WordRW::store(v) - } - fn tword_ld<'a, T>(&'a self) -> T - where - T: WordRW = T>, - { - ::load(self) +pub trait DwordQN: Sized { + const DWORDQN_FROM_UPPER: bool = size_of::() > size_of::<(u64, usize)>(); + fn dwordqn_store_qw_nw(a: u64, b: usize) -> Self; + fn dwordqn_load_qw_nw(&self) -> (u64, usize); + // overrides + fn overridable_dwordnn_store_qw(a: u64) -> Self { + Self::dwordqn_store_qw_nw(a, 0) + } + // promotions + fn dword_promote(&self) -> W { + let (a, b) = self.dwordqn_load_qw_nw(); + ::dwordqn_store_qw_nw(a, b) } } -/// Native double pointer stack -pub trait SystemDword: Sized { - fn store_qw(u: u64) -> Self; - fn store_fat(a: usize, b: usize) -> Self; - fn load_qw(&self) -> u64; - fn load_double(&self) -> [usize; 2]; - fn store<'a, T>(v: T) -> Self - where - T: WordRW, - { - WordRW::store(v) - } - fn dword_ld<'a, T>(&'a self) -> T - where - T: WordRW = T>, - { - ::load(self) +/* + dword: blanket impls +*/ + +impl DwordNN for T { + fn dwordnn_store_native_full(a: usize, b: usize) -> Self { + Self::dwordqn_store_qw_nw(a as u64, b) + } + fn dwordnn_store_qw(a: u64) -> Self { + Self::overridable_dwordnn_store_qw(a) + } + fn dwordnn_load_native_full(&self) -> [usize; 2] { + let (a, b) = self.dwordqn_load_qw_nw(); + debug_assert!(a <= usize::MAX as u64, "overflowed with: `{}`", a); + [a as usize, b] + } + fn dwordnn_load_qw(&self) -> u64 { + DwordQN::dwordqn_load_qw_nw(self).0 } } -impl SystemDword for SpecialPaddedWord { - fn store_qw(u: u64) -> Self { - Self::new(u, ZERO_BLOCK.as_ptr() as usize) +/* + dword: impls +*/ + +impl DwordNN for NativeDword { + fn dwordnn_store_native_full(a: usize, b: usize) -> Self { + Self([a, b]) } - fn store_fat(a: usize, b: usize) -> Self { - Self::new(a as u64, b) + fn dwordnn_load_native_full(&self) -> [usize; 2] { + self.0 } - fn load_qw(&self) -> u64 { - self.a +} + +impl DwordQN for SpecialPaddedWord { + fn dwordqn_store_qw_nw(a: u64, b: usize) -> Self { + unsafe { + // UNSAFE(@ohsayan): valid construction + Self::new(a, b) + } + } + fn dwordqn_load_qw_nw(&self) -> (u64, usize) { + (self.a, self.b) + } + // overrides + fn overridable_dwordnn_store_qw(a: u64) -> Self { + unsafe { + // UNSAFE(@ohsayan): valid construction + Self::new(a, ZERO_BLOCK.as_ptr() as usize) + } } - fn load_double(&self) -> [usize; 2] { - [self.a as usize, self.b] +} + +/* + tword + --- + kinds: NNN (word * 3) + promotions: NNN -> NNNN +*/ + +pub trait TwordNNN: Sized { + const TWORDNNN_FROM_UPPER: bool = size_of::() > size_of::<[usize; 3]>(); + fn twordnnn_store_native_full(a: usize, b: usize, c: usize) -> Self; + fn twordnnn_load_native_full(&self) -> [usize; 3]; + // promotions + fn tword_promote(&self) -> W { + let [a, b, c] = self.twordnnn_load_native_full(); + ::twordnnn_store_native_full(a, b, c) } } -impl SystemDword for NativeDword { - #[inline(always)] - fn store_qw(u: u64) -> Self { - let x; +/* + tword: blanket impls +*/ + +impl DwordQN for T { + fn dwordqn_store_qw_nw(a: u64, b: usize) -> Self { #[cfg(target_pointer_width = "32")] { - x = quadsplit(u); + let [qw_1, qw_2] = quadsplit(a); + Self::twordnnn_store_native_full(qw_1, qw_2, b) } #[cfg(target_pointer_width = "64")] { - x = [u as usize, 0] + Self::twordnnn_store_native_full(a as usize, b, 0) } - Self(x) - } - #[inline(always)] - fn store_fat(a: usize, b: usize) -> Self { - Self([a, b]) } - #[inline(always)] - fn load_qw(&self) -> u64 { - let x; + fn dwordqn_load_qw_nw(&self) -> (u64, usize) { #[cfg(target_pointer_width = "32")] { - x = quadmerge(self.0); + let [w1, w2, b] = self.twordnnn_load_native_full(); + (quadmerge([w1, w2]), b) } #[cfg(target_pointer_width = "64")] { - x = self.0[0] as _; + let [a, b, _] = self.twordnnn_load_native_full(); + (a as u64, b) } - x - } - #[inline(always)] - fn load_double(&self) -> [usize; 2] { - self.0 } } -impl SystemTword for NativeTword { - #[inline(always)] - fn store_full(a: usize, b: usize, c: usize) -> Self { +/* + tword: impls +*/ + +impl TwordNNN for NativeTword { + fn twordnnn_store_native_full(a: usize, b: usize, c: usize) -> Self { Self([a, b, c]) } - #[inline(always)] - fn load_triple(&self) -> [usize; 3] { + fn twordnnn_load_native_full(&self) -> [usize; 3] { self.0 } - #[inline(always)] - fn store_qw_nw(a: u64, b: usize) -> Self { - let ret; +} + +/* + qword + --- + kinds: NNNN (word * 4) + promotions: N/A +*/ + +pub trait QwordNNNN: Sized { + const QWORDNNNN_FROM_UPPER: bool = size_of::() > size_of::<[usize; 4]>(); + fn qwordnnnn_store_native_full(a: usize, b: usize, c: usize, d: usize) -> Self; + fn qwordnnnn_store_qw_qw(a: u64, b: u64) -> Self { #[cfg(target_pointer_width = "32")] { - let [qw_1, qw_2] = quadsplit(a); - ret = [qw_1, qw_2, b]; + let [qw1_a, qw1_b] = quadsplit(a); + let [qw2_a, qw2_b] = quadsplit(b); + Self::qwordnnnn_store_native_full(qw1_a, qw1_b, qw2_a, qw2_b) } #[cfg(target_pointer_width = "64")] { - ret = [a as usize, b, 0]; + Self::qwordnnnn_store_native_full(a as usize, b as usize, 0, 0) } - Self(ret) } - #[inline(always)] - fn load_qw_nw(&self) -> (u64, usize) { - let ret; + fn qwordnnnn_store_qw_nw_nw(a: u64, b: usize, c: usize) -> Self { #[cfg(target_pointer_width = "32")] { - let qw = quadmerge([self.0[0], self.0[1]]); - let nw = self.0[2]; - ret = (qw, nw); + let [qw_a, qw_b] = quadsplit(a); + Self::qwordnnnn_store_native_full(qw_a, qw_b, b, c) } #[cfg(target_pointer_width = "64")] { - ret = (self.0[0] as u64, self.0[1]); + Self::qwordnnnn_store_native_full(a as usize, b, c, 0) } - ret } -} - -impl SystemDword for NativeTword { - #[inline(always)] - fn store_qw(u: u64) -> Self { - let x; + fn qwordnnnn_load_native_full(&self) -> [usize; 4]; + fn qwordnnnn_load_qw_qw(&self) -> [u64; 2] { + let [a, b, c, d] = self.qwordnnnn_load_native_full(); #[cfg(target_pointer_width = "32")] { - let [a, b]: [usize; 2] = quadsplit(u); - x = [a, b, 0]; + [quadmerge([a, b]), quadmerge([c, d])] } #[cfg(target_pointer_width = "64")] { - x = [u as _, 0, 0]; + let _ = (c, d); + [a as u64, b as u64] } - Self(x) } - #[inline(always)] - fn store_fat(a: usize, b: usize) -> Self { - Self([a, b, 0]) - } - #[inline(always)] - fn load_qw(&self) -> u64 { - let x; + fn qwordnnnn_load_qw_nw_nw(&self) -> (u64, usize, usize) { + let [a, b, c, d] = self.qwordnnnn_load_native_full(); #[cfg(target_pointer_width = "32")] { - x = quadmerge([self.0[0], self.0[1]]); + (quadmerge([a, b]), c, d) } #[cfg(target_pointer_width = "64")] { - x = self.0[0] as _; + let _ = d; + (a as u64, b, c) } - x } - #[inline(always)] - fn load_double(&self) -> [usize; 2] { - [self.0[0], self.0[1]] +} + +/* + qword: blanket impls +*/ + +impl TwordNNN for T { + fn twordnnn_store_native_full(a: usize, b: usize, c: usize) -> Self { + Self::qwordnnnn_store_native_full(a, b, c, 0) + } + fn twordnnn_load_native_full(&self) -> [usize; 3] { + let [a, b, c, _] = self.qwordnnnn_load_native_full(); + [a, b, c] } } -impl SystemQword for NativeQword { - fn store_full(a: usize, b: usize, c: usize, d: usize) -> Self { +/* + qword: impls +*/ + +impl QwordNNNN for NativeQword { + fn qwordnnnn_store_native_full(a: usize, b: usize, c: usize, d: usize) -> Self { Self([a, b, c, d]) } - fn load_quad(&self) -> [usize; 4] { + fn qwordnnnn_load_native_full(&self) -> [usize; 4] { self.0 } } -impl SystemTword for NativeQword { - fn store_full(a: usize, b: usize, c: usize) -> Self { - Self([a, b, c, 0]) +/* + impls: WordIO +*/ + +macro_rules! impl_numeric_io { + ($trait:ident => { $($ty:ty),* $(,)? }) => { + $(impl WordIO<$ty> for T { + fn store(v: $ty) -> Self { Self::dwordnn_store_qw(v as _) } + fn load(&self) -> $ty { self.dwordnn_load_qw() as _ } + })* } - fn load_triple(&self) -> [usize; 3] { - [self.0[0], self.0[1], self.0[2]] +} + +impl_numeric_io!(DwordNN => { u8, u16, u32, u64, i8, i16, i32, i64 }); + +impl WordIO for T { + fn store(v: bool) -> Self { + Self::dwordnn_store_qw(v as _) } - /// Store a quadword and a native word - fn store_qw_nw(a: u64, b: usize) -> Self { - let ret; - #[cfg(target_pointer_width = "32")] - { - let [qw_1, qw_2] = quadsplit(a); - ret = [qw_1, qw_2, b, 0]; - } - #[cfg(target_pointer_width = "64")] - { - ret = [a as usize, b, 0, 0]; - } - Self(ret) - } - #[inline(always)] - fn load_qw_nw(&self) -> (u64, usize) { - let ret; - #[cfg(target_pointer_width = "32")] - { - let qw = quadmerge([self.0[0], self.0[1]]); - let nw = self.0[2]; - ret = (qw, nw); - } - #[cfg(target_pointer_width = "64")] - { - ret = (self.0[0] as u64, self.0[1]); - } - ret + fn load(&self) -> bool { + self.dwordnn_load_qw() == 1 } } -impl SystemDword for NativeQword { - fn store_qw(u: u64) -> Self { - let ret; - #[cfg(target_pointer_width = "32")] - { - let [a, b] = quadsplit(u); - ret = ::store_full(a, b, 0, 0); - } - #[cfg(target_pointer_width = "64")] - { - ret = ::store_full(u as _, 0, 0, 0); - } - ret - } - fn store_fat(a: usize, b: usize) -> Self { - ::store_full(a, b, 0, 0) +macro_rules! impl_float_io { + ($($float:ty),* $(,)?) => { + $(impl WordIO<$float> for T { + fn store(v: $float) -> Self { Self::dwordnn_store_qw(v.to_bits() as u64) } + fn load(&self) -> $float { <$float>::from_bits(self.dwordnn_load_qw() as _) } + })* } - fn load_qw(&self) -> u64 { - let ret; - #[cfg(target_pointer_width = "32")] - { - ret = quadmerge([self.0[0], self.0[1]]); - } - #[cfg(target_pointer_width = "64")] - { - ret = self.0[0] as _; - } - ret +} + +impl_float_io!(f32, f64); + +impl WordIO<(usize, usize)> for T { + fn store((a, b): (usize, usize)) -> Self { + Self::dwordnn_store_native_full(a, b) } - fn load_double(&self) -> [usize; 2] { - [self.0[0], self.0[1]] + fn load(&self) -> (usize, usize) { + let [a, b] = self.dwordnn_load_native_full(); + (a, b) } } -pub trait WordRW { - type Target<'a> - where - W: 'a; - fn store(self) -> W; - fn load<'a>(word: &'a W) -> Self::Target<'a>; +impl WordIO<[usize; 2]> for T { + fn store([a, b]: [usize; 2]) -> Self { + Self::dwordnn_store_native_full(a, b) + } + fn load(&self) -> [usize; 2] { + self.dwordnn_load_native_full() + } } -macro_rules! impl_wordrw { - ($($ty:ty as $minword:ident => { type Target<'a> = $target:ty; |$selfname:ident| $store:expr; |$wordarg:ident| $load:expr;})*) => { - $(impl WordRW for $ty { type Target<'a> = $target where W: 'a; fn store($selfname: Self) -> W { $store } fn load<'a>($wordarg: &'a W) -> Self::Target<'a> { $load } })* - }; - ($($ty:ty as $minword:ident => { |$selfname:ident| $store:expr; |$wordarg:ident| $load:expr;})*) => { impl_wordrw!($($ty as $minword => { type Target<'a> = $ty; |$selfname| $store; |$wordarg| $load;})*); }; +impl WordIO<(usize, *mut u8)> for T { + fn store((a, b): (usize, *mut u8)) -> Self { + Self::dwordnn_store_native_full(a, b as usize) + } + fn load(&self) -> (usize, *mut u8) { + let [a, b] = self.dwordnn_load_native_full(); + (a, b as *mut u8) + } } -impl_wordrw! { - bool as SystemDword => { - |self| SystemDword::store_qw(self as _); - |word| SystemDword::load_qw(word) == 1; - } - u8 as SystemDword => { - |self| SystemDword::store_qw(self as _); - |word| SystemDword::load_qw(word) as u8; - } - u16 as SystemDword => { - |self| SystemDword::store_qw(self as _); - |word| SystemDword::load_qw(word) as u16; - } - u32 as SystemDword => { - |self| SystemDword::store_qw(self as _); - |word| SystemDword::load_qw(word) as u32; - } - u64 as SystemDword => { - |self| SystemDword::store_qw(self); - |word| SystemDword::load_qw(word); - } - i8 as SystemDword => { - |self| SystemDword::store_qw(self as _); - |word| SystemDword::load_qw(word) as i8; - } - i16 as SystemDword => { - |self| SystemDword::store_qw(self as _); - |word| SystemDword::load_qw(word) as i16; - } - i32 as SystemDword => { - |self| SystemDword::store_qw(self as _); - |word| SystemDword::load_qw(word) as i32; - } - i64 as SystemDword => { - |self| SystemDword::store_qw(self as _); - |word| SystemDword::load_qw(word) as i64; - } - f32 as SystemDword => { - |self| SystemDword::store_qw(self.to_bits() as u64); - |word| f32::from_bits(SystemDword::load_qw(word) as u32); - } - f64 as SystemDword => { - |self| SystemDword::store_qw(self.to_bits()); - |word| f64::from_bits(SystemDword::load_qw(word)); - } - [usize; 2] as SystemDword => { - |self| SystemDword::store_fat(self[0], self[1]); - |word| SystemDword::load_double(word); - } - (usize, *mut u8) as SystemDword => { - |self| SystemDword::store_fat(self.0, self.1 as usize); - |word| { - let [a, b] = word.load_double(); - (a, b as *mut u8) - }; - } - (usize, *const u8) as SystemDword => { - |self| SystemDword::store_fat(self.0, self.1 as usize); - |word| { - let [a, b] = word.load_double(); - (a, b as *const u8) - }; +impl WordIO<(usize, *const u8)> for T { + fn store((a, b): (usize, *const u8)) -> Self { + Self::dwordnn_store_native_full(a, b as usize) + } + fn load(&self) -> (usize, *const u8) { + let [a, b] = self.dwordnn_load_native_full(); + (a, b as *const u8) } }