Skip to content

Commit

Permalink
Split (#11)
Browse files Browse the repository at this point in the history
* split

* value

* Rc

* split fail

* ptr_subset

* ptr_subset()

* fmt

* number
  • Loading branch information
sergey-shandar authored Nov 20, 2023
1 parent 90358fc commit 3a04e5d
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 93 deletions.
30 changes: 18 additions & 12 deletions src/bit_subset64.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::const_assert::const_assert;
use std::marker::PhantomData;

use crate::{const_assert::const_assert, container::Clean, ptr_subset::PtrSubset};

/// A bit subset of `u64`.
///
Expand Down Expand Up @@ -75,15 +77,19 @@ impl BitSubset64 {
BitSubset64::from_tag_and_union(self.tag | b.tag, self.union() & b.union())
}
#[inline(always)]
pub const fn split(self, i: u8) -> (BitSubset64, BitSubset64) {
let i_mask = 1 << i;
const_assert(i_mask & self.mask == 0);
let mask = self.mask | i_mask;
pub const fn split(self, m: u64) -> (BitSubset64, BitSubset64) {
const_assert(m != 0);
const_assert(m & self.mask == 0);
let mask = self.mask | m;
(
BitSubset64::from_tag_and_mask(self.tag, mask),
BitSubset64::from_tag_and_mask(self.tag | i_mask, mask),
BitSubset64::from_tag_and_mask(self.tag | m, mask),
)
}
#[inline(always)]
pub const fn ptr_subset<T: Clean>(self) -> PtrSubset<T> {
PtrSubset(self, PhantomData)
}
}

#[cfg(test)]
Expand All @@ -99,7 +105,7 @@ mod test {
const _: () = const_assert(A.has(0b010));
const _: () = const_assert(A.has(0b011));

const AS: (BitSubset64, BitSubset64) = A.split(0);
const AS: (BitSubset64, BitSubset64) = A.split(1);
const _: () = const_assert(AS.0.tag == 0b010);
const _: () = const_assert(AS.0.superposition() == 0);
const _: () = const_assert(AS.1.tag == 0b011);
Expand All @@ -121,10 +127,10 @@ mod test {
const _: () = const_assert(UBC.tag == 0b000100);
const _: () = const_assert(UBC.union() == 0b011111);

const UBCS: (BitSubset64, BitSubset64) = UBC.split(3);
const _: () = const_assert(UBCS.0.superposition() == 0b010011);
const _: () = const_assert(UBCS.0.tag == 0b000100);
const _: () = const_assert(UBCS.1.tag == 0b001100);
const _UBCS: (BitSubset64, BitSubset64) = UBC.split(0b1000);
const _: () = const_assert(_UBCS.0.superposition() == 0b010011);
const _: () = const_assert(_UBCS.0.tag == 0b000100);
const _: () = const_assert(_UBCS.1.tag == 0b001100);

#[test]
fn test_ubc() {
Expand All @@ -142,7 +148,7 @@ mod test {
#[test]
#[should_panic]
fn test_split_fail() {
UBC.split(2);
UBC.split(0b100);
}

const D: BitSubset64 = BitSubset64::from_tag_and_union(0b00110, 0b00111);
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
mod bit_subset64;
mod const_assert;
mod container;
mod number;
mod object;
mod ptr_subset;
mod string16;
mod value;
17 changes: 17 additions & 0 deletions src/number.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// compatible with `f64`
pub const INFINITY: u64 = 0x7FF0_0000_0000_0000;
pub const NAN: u64 = 0x7FF8_0000_0000_0000;
pub const NEG_INFINITY: u64 = 0xFFF0_0000_0000_0000;

#[cfg(test)]
mod test {
use super::*;

#[test]
fn test_nan() {
assert_eq!(f64::INFINITY.to_bits(), INFINITY);
assert_ne!(f64::NAN, f64::NAN);
assert_eq!(f64::NAN.to_bits(), NAN);
assert_eq!(f64::NEG_INFINITY.to_bits(), NEG_INFINITY);
}
}
20 changes: 20 additions & 0 deletions src/ptr_subset.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use std::marker::PhantomData;

use crate::{
bit_subset64::BitSubset64,
container::{Clean, Container},
};

pub struct PtrSubset<T: Clean>(pub BitSubset64, pub PhantomData<T>);

impl<T: Clean> PtrSubset<T> {
pub fn update<const ADD: bool>(&self, v: u64) {
let v = v & self.0.superposition();
if v == 0 {
return;
}
unsafe {
Container::update::<ADD>(v as *mut Container<T>);
}
}
}
98 changes: 17 additions & 81 deletions src/value.rs
Original file line number Diff line number Diff line change
@@ -1,89 +1,34 @@
use std::marker::PhantomData;

use crate::{
bit_subset64::BitSubset64,
container::{Clean, Container},
object::Object,
string16::String16,
};
use crate::{bit_subset64::BitSubset64, object::Object, ptr_subset::PtrSubset, string16::String16};

#[derive(Debug)]
#[repr(transparent)]
struct Value(u64);

// compatible with `f64`
const INFINITY: u64 = 0x7FF0_0000_0000_0000;
const NAN: u64 = 0x7FF8_0000_0000_0000;
const NEG_INFINITY: u64 = 0xFFF0_0000_0000_0000;
pub struct Value(u64);

//

const EXTENSION_MASK: u64 = 0xFFF8_0000_0000_0000;

const fn extension(tag: u64, sup: u64) -> BitSubset64 {
BitSubset64::from_tag_and_superposition(EXTENSION_MASK | tag, sup)
}

struct PtrSubset<T: Clean>(BitSubset64, PhantomData<T>);

impl<T: Clean> PtrSubset<T> {
const fn new(tag: u64) -> Self {
Self(
extension(
tag | 0x1_0000_0000_0000,
0x0000_FFFF_FFFF_FFFF, // 48-bits. We can reduce it to 45-bits by removing the first alignment bits.
),
PhantomData,
)
}
fn update<const ADD: bool>(&self, v: u64) {
let v = v & self.0.superposition();
if v == 0 {
return;
}
unsafe {
Container::update::<ADD>(v as *mut Container<T>);
}
}
}

// an object pointer
const EXTENSION: BitSubset64 = BitSubset64::from_tag(0xFFF8_0000_0000_0000);

const OBJ_PTR: PtrSubset<Object> = PtrSubset::new(0);
const EXTENSION_SPLIT: (BitSubset64, BitSubset64) = EXTENSION.split(0x0004_0000_0000_0000);

// a string index
const BOOL: BitSubset64 = EXTENSION_SPLIT.0;
const PTR: BitSubset64 = EXTENSION_SPLIT.1;

const STR_INDEX: BitSubset64 = extension(0x2_0000_0000_0000, 0xFFFF_FFFF);
const PTR_SPLIT: (BitSubset64, BitSubset64) = PTR.split(0x0002_0000_0000_0000);

// a pointer to a string

const STR_PTR: PtrSubset<String16> = PtrSubset::new(STR_INDEX.tag);

// all strings

const STR: BitSubset64 = STR_INDEX.or_unchecked(STR_PTR.0);

// all pointers

const PTR: BitSubset64 = OBJ_PTR.0.or(STR_PTR.0);

// bool

const BOOL: BitSubset64 = extension(0, 1);
const STRING: PtrSubset<String16> = PTR_SPLIT.0.ptr_subset();
const STRING_TAG: u64 = STRING.0.tag;
const OBJECT: PtrSubset<Object> = PTR_SPLIT.1.ptr_subset();
const OBJECT_TAG: u64 = OBJECT.0.tag;

const FALSE: u64 = BOOL.tag;
const TRUE: u64 = BOOL.union();

// all extensions

const EXTENSION: BitSubset64 = PTR.or_unchecked(STR_INDEX).or_unchecked(BOOL);
const TRUE: u64 = BOOL.tag | 1;

fn update<const ADD: bool>(v: u64) {
if PTR.has(v) {
if STR_PTR.0.has(v) {
STR_PTR.update::<ADD>(v);
if STRING.0.has(v) {
STRING.update::<ADD>(v);
} else {
OBJ_PTR.update::<ADD>(v);
OBJECT.update::<ADD>(v);
}
}
}
Expand All @@ -106,22 +51,13 @@ mod test {
use std::rc::Rc;

use super::*;
use crate::const_assert::const_assert;
use crate::{const_assert::const_assert, number::NAN};

const _: () = const_assert(BOOL.has(FALSE));
const _: () = const_assert(BOOL.has(TRUE));
const _: () = const_assert(!BOOL.has(0));
const _: () = const_assert(!BOOL.has(NAN));
const _: () = const_assert(BOOL.has(EXTENSION_MASK));
const _: () = const_assert(!BOOL.has(EXTENSION_MASK | 2));

#[test]
fn test_nan() {
assert_eq!(f64::INFINITY.to_bits(), INFINITY);
assert_ne!(f64::NAN, f64::NAN);
assert_eq!(f64::NAN.to_bits(), NAN);
assert_eq!(f64::NEG_INFINITY.to_bits(), NEG_INFINITY);
}
const _: () = const_assert(BOOL.has(EXTENSION.mask));

#[test]
fn test_unsized() {
Expand Down

0 comments on commit 3a04e5d

Please sign in to comment.