Add conversion and bitfield operations to Block.

This commit is contained in:
yukirij 2023-09-26 17:33:40 -07:00
parent c5429b7e21
commit 57c67cae9e
4 changed files with 231 additions and 75 deletions

View File

@ -4,6 +4,9 @@ use crate::runtime::{
type_inner, type_key, type_inner, type_key,
block_length, block_length,
block_set, block_get, block_set, block_get,
block_set_natural, block_get_natural,
block_set_integer, block_get_integer,
block_set_field, block_get_field,
}; };
use crate::tag; use crate::tag;
use super::block; use super::block;
@ -41,6 +44,21 @@ impl Block {
} }
} }
pub fn set_u64(&self, data:u64)
{
unsafe {block_set_natural(self.addr, data)}
}
pub fn set_i64(&self, data:i64)
{
unsafe {block_set_integer(self.addr, data)}
}
pub fn set_field(&mut self, index:usize, length:usize, data:u64)
{
unsafe { block_set_field(self.addr, index, length, data); }
}
pub fn get(&self) -> Vec<u8> pub fn get(&self) -> Vec<u8>
{ {
let mut result = Vec::<u8>::new(); let mut result = Vec::<u8>::new();
@ -53,6 +71,21 @@ impl Block {
} }
return result; return result;
} }
pub fn get_u64(&self) -> u64
{
unsafe {block_get_natural(self.addr)}
}
pub fn get_i64(&self) -> i64
{
unsafe {block_get_integer(self.addr)}
}
pub fn get_field(&self, index:usize, length:usize) -> u64
{
unsafe {block_get_field(self.addr, index, length)}
}
} }
impl TryFrom<Reference> for Block { impl TryFrom<Reference> for Block {
type Error = (); type Error = ();

View File

@ -549,6 +549,60 @@ extern "C" uint8_t block_get(Reference addr, size_t index)
return 0; return 0;
} }
extern "C" uint64_t block_get_natural(Reference addr)
{
size_t length = type_innerkey(addr.type);
uint8_t* data = reinterpret_cast<uint8_t*>(addr.address);
uint64_t result = 0;
for(size_t i = 0; i < length; ++i) {
result <<= 8;
result |= data[i];
}
return result;
}
extern "C" int64_t block_get_integer(Reference addr)
{
size_t length = type_innerkey(addr.type);
uint8_t* data = reinterpret_cast<uint8_t*>(addr.address);
int64_t result = 0;
for(size_t i = 0; i < length; ++i) {
result <<= 8;
result |= data[i];
}
return result;
}
extern "C" uint64_t block_get_field(Reference addr, size_t index, size_t length)
{
size_t data_length = type_innerkey(addr.type);
size_t byte_start = index >> 3;
size_t bit_offset = index & 0x07;
size_t byte_length = 1 + ((bit_offset + length) >> 3);
size_t byte_end = byte_start + byte_length;
size_t mask_offset = ((8 * byte_length) - (length + bit_offset));
uint64_t mask = ((1 << length) - 1) << mask_offset;
uint64_t bits = 0;
uint8_t* data = reinterpret_cast<uint8_t*>(addr.address);
size_t i = byte_start;
for(; i < data_length && i < byte_end; ++i) {
bits <<= 8;
bits |= data[i];
}
for(; i < byte_end; ++i) {
bits <<= 8;
}
return (bits & mask) >> mask_offset;
}
extern "C" void block_set(Reference addr, size_t index, uint8_t value) extern "C" void block_set(Reference addr, size_t index, uint8_t value)
{ {
size_t length = type_innerkey(addr.type); size_t length = type_innerkey(addr.type);
@ -557,6 +611,63 @@ extern "C" void block_set(Reference addr, size_t index, uint8_t value)
} }
} }
extern "C" void block_set_natural(Reference addr, uint64_t data)
{
size_t length = type_innerkey(addr.type);
uint8_t* dest = reinterpret_cast<uint8_t*>(addr.address);
for(size_t i = length; i > 0; --i) {
dest[i - 1] = data & 0xFF;
data >>= 8;
}
}
extern "C" void block_set_integer(Reference addr, int64_t data)
{
size_t length = type_innerkey(addr.type);
uint8_t* dest = reinterpret_cast<uint8_t*>(addr.address);
for(size_t i = length; i > 0; --i) {
dest[i - 1] = data & 0xFF;
data >>= 8;
}
}
extern "C" void block_set_field(Reference addr, size_t index, size_t length, uint64_t value)
{
size_t data_length = type_innerkey(addr.type);
size_t byte_start = index >> 3;
size_t bit_offset = index & 0x07;
size_t byte_length = 1 + ((bit_offset + length) >> 3);
size_t byte_end = byte_start + byte_length;
size_t mask_offset = ((8 * byte_length) - (length + bit_offset));
uint64_t mask = ((1 << length) - 1) << mask_offset;
uint64_t bits = 0;
uint8_t* data = reinterpret_cast<uint8_t*>(addr.address);
size_t byte_index = byte_start;
for(; byte_index < data_length && byte_index < byte_end; ++byte_index) {
bits <<= 8;
bits |= data[byte_index];
}
for(; byte_index < byte_end; ++byte_index) {
bits <<= 8;
}
bits &= ~mask;
bits |= mask & (value << mask_offset);
for(; byte_index > data_length; --byte_index) {
bits >>= 8;
}
for(; byte_index > byte_start; --byte_index) {
data[byte_index - 1] = bits & 0xFF;
bits >>= 8;
}
}
// Sequence // // Sequence //

View File

@ -67,7 +67,13 @@ extern "C" Type::Significant significant_get(Reference addr);
// Block // // Block //
extern "C" size_t block_length(Reference addr); extern "C" size_t block_length(Reference addr);
extern "C" uint8_t block_get(Reference addr, size_t index); extern "C" uint8_t block_get(Reference addr, size_t index);
extern "C" uint64_t block_get_natural(Reference addr);
extern "C" int64_t block_get_integer(Reference addr);
extern "C" uint64_t block_get_field(Reference addr, size_t index, size_t length);
extern "C" void block_set(Reference addr, size_t index, uint8_t value); extern "C" void block_set(Reference addr, size_t index, uint8_t value);
extern "C" void block_set_natural(Reference addr, uint64_t data);
extern "C" void block_set_integer(Reference addr, int64_t data);
extern "C" void block_set_field(Reference addr, size_t index, size_t length, uint64_t value);
// Sequence // // Sequence //
extern "C" size_t sequence_capacity(Reference addr); extern "C" size_t sequence_capacity(Reference addr);

View File

@ -83,8 +83,14 @@ extern "C" {
pub fn significant_get(addr:Reference) -> f64; pub fn significant_get(addr:Reference) -> f64;
pub fn block_length(addr:Reference) -> usize; pub fn block_length(addr:Reference) -> usize;
pub fn block_set(addr:Reference, index:usize, data:u8);
pub fn block_get(addr:Reference, index:usize) -> u8; pub fn block_get(addr:Reference, index:usize) -> u8;
pub fn block_get_natural(addr:Reference) -> u64;
pub fn block_get_integer(addr:Reference) -> i64;
pub fn block_get_field(addr:Reference, index:usize, length:usize) -> u64;
pub fn block_set(addr:Reference, index:usize, data:u8);
pub fn block_set_natural(addr:Reference, data:u64);
pub fn block_set_integer(addr:Reference, data:i64);
pub fn block_set_field(addr:Reference, index:usize, length:usize, data:u64);
pub fn sequence_capacity(addr:Reference) -> usize; pub fn sequence_capacity(addr:Reference) -> usize;
pub fn sequence_length(addr:Reference) -> usize; pub fn sequence_length(addr:Reference) -> usize;