From 21b95b936c43a7c25b3432eaec4cd3520e6872f9 Mon Sep 17 00:00:00 2001 From: yukirij Date: Wed, 23 Aug 2023 17:21:40 -0700 Subject: [PATCH] Add Sparse, update README, remove risky methods, fix bugs. --- README.md | 73 +++- src/encoding/mod.rs | 96 ++++- src/interface/array.rs | 11 - src/interface/block.rs | 11 - src/interface/boolean.rs | 11 - src/interface/builder.rs | 1 + src/interface/integer.rs | 11 - src/interface/list.rs | 11 - src/interface/mod.rs | 6 +- src/interface/natural.rs | 11 - src/interface/record.rs | 16 +- src/interface/schema.rs | 11 - src/interface/sequence.rs | 11 - .../{signfiicant.rs => signficant.rs} | 11 - src/interface/sparse.rs | 92 ++++ src/interface/varying.rs | 11 - src/lib.rs | 55 ++- src/runtime/lib.cc | 393 ++++++++++++++---- src/runtime/lib.h | 13 +- src/runtime/mod.rs | 18 + src/runtime/nametree.h | 3 +- src/runtime/rawlist.cc | 2 +- src/runtime/rawlist.h | 2 +- src/runtime/sparselist.h | 2 +- src/runtime/type.h | 22 +- src/tag.rs | 2 +- 26 files changed, 649 insertions(+), 257 deletions(-) rename src/interface/{signfiicant.rs => signficant.rs} (82%) create mode 100644 src/interface/sparse.rs diff --git a/README.md b/README.md index fb3c141..df6c1dd 100644 --- a/README.md +++ b/README.md @@ -234,19 +234,6 @@ match Integer::from(list.at(0)) { ``` --- -`with(value) -> Self` - -``` -let b = Boolean::with(true); -``` ---- - -`detatch()` - -Prevents an allocated object from being dropped when the interface goes out of scope. - ---- - `*Dereference -> Reference` ``` @@ -372,7 +359,7 @@ Stores a constant-magnitude number with whole and decimal components. ## Significant Stores a fixed-precision, variable-magnitude number. -> Encode not implemented. +> Encode/decode not implemented. `get() -> f64` @@ -486,7 +473,7 @@ Reallocates the sequeunce to have capacity not less than the specified size. ## Array -Constant-sized, ordered collection of items. +Constant-sized, indexed collection of items. `new(length:usize, type_id:usize) -> Array` @@ -520,7 +507,7 @@ Returns the type identifier of the contents. ## List -Variable-sized, ordered collection of items. +Variable-sized, indexed collection of items. `new(type_id:usize) -> List` @@ -577,9 +564,63 @@ Removes all elements from the list. --- +## Sparse +List of discontinuous indicies. + +`length() -> usize` + +Returns the number of elements in the collection. + +--- + +`at(index:usize) -> Reference` + +Returns a reference to the item at the specified index. + +--- + +`has(key:usize) -> bool` + +Returns whether the specified key is assigned. + +--- + +`get(key:usize) -> Reference` + +Returns a reference to the item at the specified key. + +--- + +`set(key:usize, source:Reference)` + +Adds or updates an element at the specified key. + +--- + +`unset(key:usize)` + +Removes an element from the collection. + +--- + +`clear()` + +Removes all elements from the collection. + +--- + +`indexof(index:usize) -> usize` + +Returns the key of the element at the specified index. + +--- + + ## Schema Definition of an abstract structure composed of named items. +> Encode/decode not implemented. + `with(members:Vec<(&str, usize)>) -> Schema` Produces a schema with the provided member assignments. diff --git a/src/encoding/mod.rs b/src/encoding/mod.rs index e0ce6f3..380609d 100644 --- a/src/encoding/mod.rs +++ b/src/encoding/mod.rs @@ -1,8 +1,9 @@ use crate::{ + runtime, runtime::{ Reference, kind_hasinner, type_hasinner, type_inner, type_outer, - type_key, type_innerkey, + type_key, type_innerkey, SparseHeader, }, tag, Type, @@ -84,6 +85,29 @@ pub fn encode_data(addr:Reference) -> Vec } } } + tag::SPARSE => { + let data = crate::Sparse::from(addr).unwrap(); + + let header_length = unsafe {runtime::sparse_header_length(addr)}; + + result.append(&mut util::pack_natural(header_length as u64)); + + for i in 0..header_length { + let header = unsafe {runtime::sparse_header_data(addr, i)}; + result.append(&mut util::pack_natural(header.start as u64)); + result.append(&mut util::pack_natural(header.length as u64)); + result.append(&mut util::pack_natural(header.index as u64)); + } + + for i in 0..data.length() { + if unsafe {type_innerkey(addr.class)} == tag::VARYING { + result.append(&mut encode(data.at(i))); + } + else { + result.append(&mut encode_data(data.at(i))); + } + } + } tag::RECORD => { let data = Record::from(addr).unwrap(); for i in 0..data.length() { @@ -171,6 +195,76 @@ pub fn decode_data(data:&Vec, type_id:usize, index:&mut usize) -> Result { + let length = unsafe {type_innerkey(type_id)}; + let inner = unsafe {type_inner(type_inner(type_id))}; + + let mut result = Array::new(length, inner); + for i in 0..length { + match if unsafe {type_key(inner)} == tag::VARYING { + decode(data, index) + } else { + decode_data(data, inner, index) + } { + Ok(data) => { result.set(i, data.get()); } + Err(_) => { return Err(()); } + } + } + + return Ok(Type::Array(result)); + } + tag::LIST => { + let inner = unsafe {type_inner(type_id)}; + let length = util::unpack_natural(data, index) as usize; + + let mut result = List::new(inner); + result.reserve(length); + + for _ in 0..length { + match if unsafe {type_key(inner)} == tag::VARYING { + decode(data, index) + } else { + decode_data(data, inner, index) + } { + Ok(data) => { result.append(data.get()); } + Err(_) => { return Err(()); } + } + } + + return Ok(Type::List(result)); + } + tag::SPARSE => { + let inner = unsafe {type_inner(type_id)}; + let mut result = crate::Sparse::new(inner); + + let header_length = util::unpack_natural(data, index) as usize; + let mut headers = Vec::::with_capacity(header_length); + + for _ in 0..header_length { + headers.push(runtime::SparseHeader { + start:util::unpack_natural(data, index) as usize, + length:util::unpack_natural(data, index) as usize, + index:util::unpack_natural(data, index) as usize, + }); + } + + for header in headers { + for i in 0..header.length { + match if unsafe {type_key(inner)} == tag::VARYING { + decode(data, index) + } else { + decode_data(data, inner, index) + } { + Ok(data) => { + result.set(header.start + i, data.get()); + } + Err(_) => { return Err(()); } + } + } + } + + return Ok(Type::Sparse(result)); + } tag::RECORD => { return match Record::new(unsafe {type_innerkey(type_id)}) { Ok(mut value) => { diff --git a/src/interface/array.rs b/src/interface/array.rs index 729712c..4ea1064 100644 --- a/src/interface/array.rs +++ b/src/interface/array.rs @@ -53,17 +53,6 @@ impl Array { return obj; } - pub fn detach(&mut self) - { - self.managed = false; - } - - pub fn release(mut self) - { - self.detach(); - unsafe { release(self.addr); } - } - pub fn length(&self) -> usize { unsafe {array_length(self.addr)} diff --git a/src/interface/block.rs b/src/interface/block.rs index 5bb41d4..2053ba6 100644 --- a/src/interface/block.rs +++ b/src/interface/block.rs @@ -37,17 +37,6 @@ impl Block { obj.set(data); return obj; } - - pub fn detach(&mut self) - { - self.managed = false; - } - - pub fn release(mut self) - { - self.detach(); - unsafe { release(self.addr); } - } pub fn size(&self) -> usize { diff --git a/src/interface/boolean.rs b/src/interface/boolean.rs index fbf57e1..c9b29e2 100644 --- a/src/interface/boolean.rs +++ b/src/interface/boolean.rs @@ -37,17 +37,6 @@ impl Boolean { return obj; } - pub fn detach(&mut self) - { - self.managed = false; - } - - pub fn release(mut self) - { - self.detach(); - unsafe { release(self.addr); } - } - pub fn set(&mut self, value:bool) { unsafe { bool_set(self.addr, value) }; diff --git a/src/interface/builder.rs b/src/interface/builder.rs index 431dea4..4c868e1 100644 --- a/src/interface/builder.rs +++ b/src/interface/builder.rs @@ -28,6 +28,7 @@ pub fn array(size:usize, type_id:usize) -> usize { } pub fn list(type_id:usize) -> usize { unsafe { runtime::type_outer(type_id, tag::LIST) } } +pub fn sparse(type_id:usize) -> usize { unsafe { runtime::type_outer(type_id, tag::SPARSE) } } pub fn record(schema_id:usize) -> usize { unsafe { diff --git a/src/interface/integer.rs b/src/interface/integer.rs index 31ddfd8..f5605bb 100644 --- a/src/interface/integer.rs +++ b/src/interface/integer.rs @@ -36,17 +36,6 @@ impl Integer { obj.set(value); return obj; } - - pub fn detach(&mut self) - { - self.managed = false; - } - - pub fn release(mut self) - { - self.detach(); - unsafe { release(self.addr); } - } pub fn set(&mut self, value:i64) { diff --git a/src/interface/list.rs b/src/interface/list.rs index 9e18545..fa54c46 100644 --- a/src/interface/list.rs +++ b/src/interface/list.rs @@ -44,17 +44,6 @@ impl List { return obj; } - pub fn detach(&mut self) - { - self.managed = false; - } - - pub fn release(mut self) - { - self.detach(); - unsafe { release(self.addr); } - } - pub fn capacity(&self) -> usize { unsafe {list_capacity(self.addr)} diff --git a/src/interface/mod.rs b/src/interface/mod.rs index d216692..6da38fe 100644 --- a/src/interface/mod.rs +++ b/src/interface/mod.rs @@ -8,11 +8,12 @@ mod varying; pub use varying::Varying; mod boolean; pub use boolean::Boolean; mod natural; pub use natural::Natural; mod integer; pub use integer::Integer; -mod signfiicant; pub use signfiicant::Significant; +mod signficant; pub use signficant::Significant; mod block; pub use block::Block; mod sequence; pub use sequence::Sequence; mod array; pub use array::Array; mod list; pub use list::List; +mod sparse; pub use sparse::Sparse; mod schema; pub use schema::Schema; mod record; pub use record::Record; @@ -26,6 +27,7 @@ pub enum Type { Sequence(Sequence), Array(Array), List(List), + Sparse(Sparse), Record(Record), Schema(Schema), } @@ -42,6 +44,7 @@ impl Type { tag::SEQUENCE => Type::Sequence(Sequence::from(addr).unwrap()), tag::ARRAY => Type::Array(Array::from(addr).unwrap()), tag::LIST => Type::List(List::from(addr).unwrap()), + tag::SPARSE => Type::Sparse(Sparse::from(addr).unwrap()), tag::RECORD => Type::Record(Record::from(addr).unwrap()), _ => Type::Null, } @@ -58,6 +61,7 @@ impl Type { Type::Sequence(obj) => **obj, Type::Array(obj) => **obj, Type::List(obj) => **obj, + Type::Sparse(obj) => **obj, Type::Record(obj) => **obj, _ => Reference::null(), } diff --git a/src/interface/natural.rs b/src/interface/natural.rs index ad2554e..007cb51 100644 --- a/src/interface/natural.rs +++ b/src/interface/natural.rs @@ -37,17 +37,6 @@ impl Natural { return obj; } - pub fn detach(&mut self) - { - self.managed = false; - } - - pub fn release(mut self) - { - self.detach(); - unsafe { release(self.addr); } - } - pub fn set(&mut self, value:u64) { unsafe { natural_set(self.addr, value) }; diff --git a/src/interface/record.rs b/src/interface/record.rs index 8b6378c..96ed0e0 100644 --- a/src/interface/record.rs +++ b/src/interface/record.rs @@ -63,18 +63,7 @@ impl Record { Err(_) => Err(()) } } - - pub fn detach(&mut self) - { - self.managed = false; - } - - pub fn release(mut self) - { - self.detach(); - unsafe { release(self.addr); } - } - + pub fn length(&self) -> usize { unsafe {record_length(self.addr)} @@ -116,8 +105,7 @@ impl Record { let result = unsafe {record_indexof(self.addr, key_index)}; if result != self.length() { Some(result) - } - else { + } else { None } } diff --git a/src/interface/schema.rs b/src/interface/schema.rs index 6982a79..0052722 100644 --- a/src/interface/schema.rs +++ b/src/interface/schema.rs @@ -44,17 +44,6 @@ impl Schema { } return obj; } - - pub fn detach(&mut self) - { - self.managed = false; - } - - pub fn release(mut self) - { - self.detach(); - unsafe { release(self.addr); } - } pub fn length(&self) -> usize { diff --git a/src/interface/sequence.rs b/src/interface/sequence.rs index 9a2484f..1a9e02f 100644 --- a/src/interface/sequence.rs +++ b/src/interface/sequence.rs @@ -47,17 +47,6 @@ impl Sequence { return obj; } - pub fn detach(&mut self) - { - self.managed = false; - } - - pub fn release(mut self) - { - self.detach(); - unsafe { release(self.addr); } - } - pub fn capacity(&self) -> usize { unsafe {sequence_capacity(self.addr)} diff --git a/src/interface/signfiicant.rs b/src/interface/signficant.rs similarity index 82% rename from src/interface/signfiicant.rs rename to src/interface/signficant.rs index 3db0c0a..53068d1 100644 --- a/src/interface/signfiicant.rs +++ b/src/interface/signficant.rs @@ -36,17 +36,6 @@ impl Significant { obj.set(value); return obj; } - - pub fn detach(&mut self) - { - self.managed = false; - } - - pub fn release(mut self) - { - self.detach(); - unsafe { release(self.addr); } - } pub fn set(&mut self, value:f64) { diff --git a/src/interface/sparse.rs b/src/interface/sparse.rs new file mode 100644 index 0000000..613eda6 --- /dev/null +++ b/src/interface/sparse.rs @@ -0,0 +1,92 @@ +use crate::runtime::{ + Reference, + acquire, release, + type_key, + sparse_length, + sparse_at, sparse_get, + sparse_clear, + sparse_set, sparse_unset, + sparse_indexof, +}; +use crate::tag; +use super::sparse; + +pub struct Sparse { + managed:bool, + addr:Reference, +} +impl Sparse { + pub fn new(class:usize) -> Self + { + Self { + managed:true, + addr:unsafe {acquire(sparse(class))}, + } + } + + pub fn from(addr:Reference) -> Result + { + return if(unsafe {type_key(addr.class)} == tag::SPARSE) { + Ok(Self { managed:false, addr:addr }) + } + else { + Err(()) + } + } + + /* pub fn with(class:usize, data:Vec) -> Self + { + let mut obj = Self::new(class); + for item in data { + obj.insert(obj.length(), item); + } + return obj; + } */ + + pub fn length(&self) -> usize + { + unsafe {sparse_length(self.addr)} + } + + pub fn at(&self, index:usize) -> Reference + { + unsafe {sparse_at(self.addr, index)} + } + + pub fn has(&self, key:usize) -> bool + { + unsafe {sparse_get(self.addr, key)}.address != 0 + } + + pub fn get(&self, key:usize) -> Reference + { + unsafe {sparse_get(self.addr, key)} + } + + pub fn clear(&mut self) + { + unsafe{sparse_clear(self.addr)}; + } + + pub fn set(&mut self, key:usize, source:Reference) + { + unsafe{sparse_set(self.addr, key, source)}; + } + + pub fn unset(&mut self, key:usize) + { + unsafe{sparse_unset(self.addr, key)}; + } + + pub fn indexof(&self, index:usize) -> usize + { + unsafe{sparse_indexof(self.addr, index)} + } +} +impl std::ops::Deref for Sparse { + type Target = Reference; + fn deref(&self) -> &Self::Target { return &self.addr; } +} +impl Drop for Sparse { + fn drop(&mut self) { if self.managed { unsafe {release(self.addr)}; } } +} diff --git a/src/interface/varying.rs b/src/interface/varying.rs index 91ff12d..010e51c 100644 --- a/src/interface/varying.rs +++ b/src/interface/varying.rs @@ -38,17 +38,6 @@ impl Varying { return obj; } - pub fn detach(&mut self) - { - self.managed = false; - } - - pub fn release(mut self) - { - self.detach(); - unsafe { release(self.addr); } - } - pub fn is_null(&self) -> bool { (unsafe {varying_get(self.addr)}).address == 0 diff --git a/src/lib.rs b/src/lib.rs index f111045..f0b9ed1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,24 +7,53 @@ mod interface; pub use interface::*; mod encoding; pub use encoding::*; pub fn test() { - let mut data = Varying::new(); - data.set(*Natural::with(79)); + use std::fs::File; + use std::io::prelude::*; + const MAGAZINE :usize = 0x100; + const MAGAZINE_ROW :usize = 0x101; + + // define schema "Magazine Row" + Schema::with(vec![ + ("Content", natural()), + ("Quantity", natural()), + ]).bind(MAGAZINE_ROW); + + // define schema "Magazine" + Schema::with(vec![ + ("Capacity", natural()), + ("Quantity", natural()), + ("Content", list(record(MAGAZINE_ROW))), + ]).bind(MAGAZINE); + + // create record "Magazine" + let data = Record::with(MAGAZINE, vec![ + ("Capacity", *Natural::with(30)), + ("Quantity", *Natural::with(25)), + ("Content", *List::with(record(MAGAZINE_ROW), vec![ + *Record::with(MAGAZINE_ROW, vec![ + ("Content", *Natural::with(15)), + ("Quantity", *Natural::with(5)), + ]).unwrap(), + *Record::with(MAGAZINE_ROW, vec![ + ("Content", *Natural::with(16)), + ("Quantity", *Natural::with(20)), + ]).unwrap(), + ])), + ]).unwrap(); + + // encode record let out = encode(*data); + + // write encoding to file + let mut file = File::create("dat.szn").unwrap(); + file.write_all(&out).ok(); + + // print hex series of encoding print!("[{}]: ", out.len()); for byte in &out { print!("{:02x} ", *byte); - } println!("\n"); - - match decode(&out, &mut 0) { - Ok(ty) => match ty { - Type::Varying(data) => { - println!("Ok: {}", Natural::from(data.get()).unwrap().get()); - } - _ => { println!("Other"); } - }, - Err(_) => { println!("Failure"); } - } + } println!(""); } #[cfg(test)] diff --git a/src/runtime/lib.cc b/src/runtime/lib.cc index 6317c43..df820f1 100644 --- a/src/runtime/lib.cc +++ b/src/runtime/lib.cc @@ -55,6 +55,7 @@ extern "C" size_t type_size(size_t type_id) } case Type::Tag::List: + case Type::Tag::Sparse: case Type::Tag::Record: { size_t innerkey = type_innerkey(type_id); @@ -64,6 +65,7 @@ extern "C" size_t type_size(size_t type_id) else { switch(type) { case Type::Tag::List: return sizeof(Type::List); + case Type::Tag::Sparse: return sizeof(Type::Sparse); case Type::Tag::Record: { auto binding = DB_SCHEMA.get(type_innerkey(type_id)); if(binding != nullptr) { @@ -88,23 +90,25 @@ size_t type_alignment(size_t type_id) switch(type) { case Type::Tag::Null: return 0; - case Type::Tag::Varying: return sizeof(size_t); + case Type::Tag::Boolean: return sizeof(Type::Boolean); case Type::Tag::Natural: return sizeof(Type::Natural); case Type::Tag::Integer: return sizeof(Type::Integer); case Type::Tag::Significant: return sizeof(Type::Significant); case Type::Tag::Block: return sizeof(uint8_t); - case Type::Tag::Sequence: return sizeof(size_t); - case Type::Tag::Array: return type_inner(type_id); - case Type::Tag::List: return sizeof(size_t); + case Type::Tag::Array: return type_alignment(type_inner(type_id)); + + case Type::Tag::Varying: + case Type::Tag::Sequence: + case Type::Tag::List: + case Type::Tag::Sparse: + case Type::Tag::Schema: + return sizeof(size_t); + case Type::Tag::Record: { auto binding = DB_SCHEMA.get(type_innerkey(type_id)); - if(binding != nullptr) { - return binding->alignment; - } + return (binding != nullptr)? binding->alignment : 0; } - case Type::Tag::Schema: return sizeof(size_t); - default: return 0; } } return 0; @@ -117,6 +121,7 @@ extern "C" size_t kind_hasinner(size_t kind) return 2; case Type::Tag::Block: case Type::Tag::List: + case Type::Tag::Sparse: case Type::Tag::Record: return 1; } @@ -192,25 +197,19 @@ void drop(Reference addr) if(addr.address != nullptr) { switch(type_key(addr.type)) { case Type::Tag::Varying: { - auto& var = *reinterpret_cast(addr.address); - if(var.address != nullptr) { - drop(var); - } - var.type = 0; - var.address = nullptr; + varying_clear(addr); } break; case Type::Tag::Sequence: { - auto& seq = *reinterpret_cast(addr.address); - rawlist_clear(seq.data); + sequence_clear(addr); } break; case Type::Tag::List: { - Type::List& list = *reinterpret_cast(addr.address); - for(size_t i = 0; i < list.data.length; ++i) { - drop(list_cell(addr, i)); - } - rawlist_clear(list.data); + list_clear(addr); + } break; + + case Type::Tag::Sparse: { + sparse_clear(addr); } break; case Type::Tag::Record: { @@ -303,6 +302,27 @@ extern "C" bool copy(Reference dst, Reference src) } } break; + case Type::Tag::Sparse: { + auto& src_list = *reinterpret_cast(source.address); + auto& dst_list = *reinterpret_cast(destination.address); + + rawlist_reserve(dst_list.header, sizeof(Type::SparseHeader), src_list.header.capacity); + dst_list.header.length = src_list.header.length; + + for(size_t i = 0; i < src_list.header.length; ++i) { + Type::SparseHeader& src_header = *reinterpret_cast(rawlist_cell(src_list.header, sizeof(Type::SparseHeader), i)); + Type::SparseHeader& dst_header = *reinterpret_cast(rawlist_cell(dst_list.header, sizeof(Type::SparseHeader), i)); + dst_header = src_header; + } + + rawlist_reserve(dst_list.data, type_size(type_inner(source.type)), src_list.data.capacity); + dst_list.data.length = src_list.data.length; + + for(size_t i = 0; i < src_list.data.length; ++i) { + copy(list_at(destination, i), list_at(source, i)); + } + } break; + case Type::Tag::Record: { size_t schema_id = type_innerkey(source.type); auto binding = DB_SCHEMA.get(schema_id); @@ -439,9 +459,9 @@ extern "C" void varying_clear(Reference addr) if(var.address != nullptr) { drop(var); free(var.address); - var.type = 0; - var.address = nullptr; } + var.type = 0; + var.address = nullptr; } @@ -669,33 +689,13 @@ extern "C" Reference list_at(Reference addr, size_t index) return result; } -/*extern "C" Reference list_first(Reference addr) -{ - Reference result {0}; - if(type_key(addr.type) == Type::Tag::List) { - auto& list = (*reinterpret_cast(addr.address)); - if(list.length > 0) { - result = list_at(addr, 0); - } - } - return result; -}*/ - -/*extern "C" Reference list_last(Reference addr) -{ - Reference result {0}; - if(type_key(addr.type) == Type::Tag::List) { - auto& list = (*reinterpret_cast(addr.address)); - if(list.length > 0) { - result = list_at(addr, list.length - 1); - } - } - return result; -}*/ - extern "C" void list_clear(Reference addr) { - drop(addr); + Type::List& list = *reinterpret_cast(addr.address); + for(size_t i = 0; i < list.data.length; ++i) { + drop(list_cell(addr, i)); + } + rawlist_clear(list.data); } extern "C" void list_insert(Reference addr, size_t index, Reference source) @@ -706,13 +706,15 @@ extern "C" void list_insert(Reference addr, size_t index, Reference source) if(index > list.data.length) { index = list.data.length; } - void* cell = rawlist_insert(list.data, offset, index); + Reference cell {0}; + cell.type = inner; + cell.address = rawlist_insert(list.data, offset, index); if(type_key(inner) == Type::Tag::Varying) { - varying_set(list_cell(addr, index), source); + varying_set(cell, source); } else { - copy(list_cell(addr, index), source); + copy(cell, source); } } @@ -723,16 +725,15 @@ extern "C" void list_prepend(Reference addr, Reference source) extern "C" void list_append(Reference addr, Reference source) { - auto& list = (*reinterpret_cast(addr.address)); + auto& list = *reinterpret_cast(addr.address); list_insert(addr, list.data.length, source); } extern "C" void list_update(Reference addr, size_t index, Reference source) { - auto& list = (*reinterpret_cast(addr.address)); + auto& list = *reinterpret_cast(addr.address); if(index < list.data.length) { size_t inner = type_inner(addr.type); - size_t offset = type_size(inner); if(type_key(inner) == Type::Tag::Varying) { varying_set(list_cell(addr, index), source); @@ -743,25 +744,9 @@ extern "C" void list_update(Reference addr, size_t index, Reference source) } } -/*extern "C" void list_truncate(Reference addr, size_t maximum) -{ - if(type_key(addr.type) == Type::Tag::List) { - //auto& list = (*reinterpret_cast(addr.address)); - - } -}*/ - -/*extern "C" void list_shift(Reference addr) -{ - if(type_key(addr.type) == Type::Tag::List) { - //auto& list = (*reinterpret_cast(addr.address)); - - } -}*/ - extern "C" void list_remove(Reference addr, size_t index) { - auto& list = (*reinterpret_cast(addr.address)); + auto& list = *reinterpret_cast(addr.address); size_t inner = type_inner(addr.type); size_t offset = type_size(inner); if(index < list.data.length) { @@ -772,20 +757,265 @@ extern "C" void list_remove(Reference addr, size_t index) extern "C" void list_reserve(Reference addr, size_t capacity) { - auto& list = (*reinterpret_cast(addr.address)); + auto& list = *reinterpret_cast(addr.address); size_t inner = type_inner(addr.type); size_t offset = type_size(inner); rawlist_reserve(list.data, offset, capacity); } -/*extern "C" void list_resize(Reference addr, size_t length) + +// Sparse // + +extern "C" size_t sparse_header_length(Reference addr) { - if(type_key(addr.type) == Type::Tag::List) { - //auto& list = (*reinterpret_cast(addr.address)); - + auto& list = *reinterpret_cast(addr.address); + return list.header.length; +} + +extern "C" Type::SparseHeader sparse_header_data(Reference addr, size_t index) +{ + auto& list = *reinterpret_cast(addr.address); + Type::SparseHeader header {0}; + + if(index < list.header.length) { + header = *reinterpret_cast(rawlist_cell(list.header, sizeof(Type::SparseHeader), index)); } -}*/ + + return header; +} + +extern "C" size_t sparse_length(Reference addr) +{ + auto& list = *reinterpret_cast(addr.address); + return list.data.length; +} + +extern "C" void sparse_clear(Reference addr) +{ + auto& list = *reinterpret_cast(addr.address); + size_t inner = type_inner(addr.type); + + Reference ref {0}; + ref.type = inner; + + for(size_t i = 0; i < list.data.length; ++i) { + ref.address = rawlist_cell(list.data, type_size(inner), i); + drop(ref); + } + + rawlist_clear(list.data); + rawlist_clear(list.header); +} + +extern "C" Reference sparse_at(Reference addr, size_t index) +{ + Reference result {0}; + auto& list = *reinterpret_cast(addr.address); + size_t inner = type_inner(addr.type); + + if(index < list.data.length) { + auto cell = rawlist_cell(list.data, type_size(inner), index); + if(cell != nullptr) { + result.type = inner; + result.address = cell; + } + + if(type_key(inner) == Type::Tag::Varying) { + result = varying_get(result); + } + } + + return result; +} + +extern "C" Reference sparse_get(Reference addr, size_t index) +{ + Reference result {0}; + auto& list = *reinterpret_cast(addr.address); + size_t inner = type_inner(addr.type); + + size_t bound_lower = 0; + size_t bound_upper = list.header.length; + size_t header_index = 0; + Type::SparseHeader* header = nullptr; + + while(bound_lower != bound_upper) { + header_index = bound_lower + ((bound_upper - bound_lower) / 2); + header = reinterpret_cast(rawlist_cell(list.header, sizeof(Type::SparseHeader), header_index)); + + if(index >= header->start && index < (header->start + header->length)) { + break; + } + else if(index < header->start) { + bound_upper = header_index; + } + else { + bound_lower = header_index + 1; + } + + header = nullptr; + } + + if(header != nullptr) { + result.type = inner; + size_t data_index = header->index + (index - header->start); + result.address = rawlist_cell(list.data, type_size(inner), data_index); + + if(type_key(result.type) == Type::Tag::Varying) { + result = varying_get(result); + } + } + + return result; +} + +extern "C" void sparse_set(Reference addr, size_t index, Reference source) +{ + auto& list = *reinterpret_cast(addr.address); + size_t inner = type_inner(addr.type); + + size_t header_index = 0; + Type::SparseHeader* header = nullptr; + for(; header_index < list.header.length; ++header_index) { + header = reinterpret_cast(rawlist_cell(list.header, sizeof(Type::SparseHeader), header_index)); + if(index <= (header->start + header->length)) { + break; + } + } + + Type::SparseHeader header_new; + + Reference new_data {0}; + new_data.type = inner; + + if(header_index == list.header.length) { + // append header to end + header_new.start = index; + header_new.length = 1; + header_new.index = list.data.length; + + new_data.address = rawlist_insert(list.data, type_size(inner), list.data.length); + copy(new_data, source); + + auto& h_cell = *reinterpret_cast(rawlist_insert(list.header, sizeof(Type::SparseHeader), list.header.length)); + h_cell = header_new; + } else { + if(index < header->start) { + // insert header before current + header_new.start = index; + header_new.length = 1; + header_new.index = header->index; + + new_data.address = rawlist_insert(list.data, type_size(inner), header->index); + copy(new_data, source); + + header = reinterpret_cast(rawlist_insert(list.header, sizeof(Type::SparseHeader), header_index)); + *header = header_new; + + for(size_t i = header_index + 1; i < list.header.length; ++i) { + auto hcell = reinterpret_cast(rawlist_cell(list.header, sizeof(Type::SparseHeader), i)); + hcell->index++; + } + } else { + size_t offset = index - header->start; + if(offset < header->length) { + // update existing value + new_data.address = rawlist_cell(list.data, type_size(inner), header->index + offset); + drop(new_data); + copy(new_data, source); + } else { + // append value to current + new_data.address = rawlist_insert(list.data, type_size(inner), header->index + offset); + copy(new_data, source); + header->length++; + + for(size_t i = header_index + 1; i < list.header.length; ++i) { + auto hcell = reinterpret_cast(rawlist_cell(list.header, sizeof(Type::SparseHeader), i)); + hcell->index++; + } + } + } + + // join headers if ranges intersect + if(header_index + 1 < list.header.length) { + auto next_header = reinterpret_cast(rawlist_cell(list.header, sizeof(Type::SparseHeader), header_index + 1)); + if(next_header->start == header->start + header->length) { + header->length += next_header->length; + rawlist_remove(list.header, sizeof(Type::SparseHeader), header_index + 1); + } + } + } +} + +extern "C" void sparse_unset(Reference addr, size_t index) +{ + auto& list = *reinterpret_cast(addr.address); + size_t inner = type_inner(addr.type); + + size_t header_index = 0; + Type::SparseHeader* header = nullptr; + for(; header_index < list.header.length; ++header_index) { + header = reinterpret_cast(rawlist_cell(list.header, sizeof(Type::SparseHeader), header_index)); + if(index <= (header->start + header->length)) { + break; + } + } + + Type::SparseHeader header_new; + + Reference cell {0}; + cell.type = inner; + + if(header_index < list.header.length && index >= header->start) { + size_t offset = index - header->start; + size_t data_index = header->index + offset; + if(offset == 0) { + // shift start of range + header->start++; + } else if(offset < header->length - 1) { + // split header at index + header_new.start = index + 1; + header_new.length = header->length - offset - 1; + header_new.index = header->index + offset + 1; + header->length = offset + 1; + + auto header_insert = reinterpret_cast(rawlist_insert(list.header, sizeof(Type::SparseHeader), header_index + 1)); + *header_insert = header_new; + } + + cell.address = rawlist_cell(list.data, type_size(inner), data_index); + drop(cell); + rawlist_remove(list.data, type_size(inner), data_index); + header->length--; + + for(size_t i = header_index + 1; i < list.header.length; ++i) { + auto hcell = reinterpret_cast(rawlist_cell(list.header, sizeof(Type::SparseHeader), i)); + hcell->index--; + } + + if(header->length == 0) { + rawlist_remove(list.header, sizeof(Type::SparseHeader), header_index); + } + } +} + +extern "C" size_t sparse_indexof(Reference addr, size_t index) +{ + auto& list = *reinterpret_cast(addr.address); + + for(size_t i = 0; i < list.header.length; ++i) { + auto hcell = reinterpret_cast(rawlist_cell(list.header, sizeof(Type::SparseHeader), i)); + + if(index < hcell->length) { + return hcell->start + index; + } else { + index -= hcell->length; + } + } + + return 0; +} // Record // @@ -833,7 +1063,8 @@ extern "C" Reference record_at(Reference addr, size_t index) extern "C" void record_update(Reference addr, size_t index, Reference source) { Reference destination {0}; - auto binding = DB_SCHEMA.get(type_innerkey(addr.type)); + size_t schid = type_innerkey(addr.type); + auto binding = DB_SCHEMA.get(schid); if(binding != nullptr) { if(index < binding->data.size()) { destination.type = binding->data[index].type; @@ -960,7 +1191,7 @@ extern "C" void schema_map(Reference addr, size_t key, size_t index) extern "C" void schema_unmap(Reference addr, size_t key) { auto& object = (*reinterpret_cast(addr.address)); - for(size_t i; i < object.map.length; i++) { + for(size_t i; i < object.map.length; ++i) { auto cell = reinterpret_cast(rawlist_cell(object.map, sizeof(Type::Schema::Mapping), i)); if(cell != nullptr) { if(cell->key == key) { @@ -1036,7 +1267,7 @@ extern "C" size_t schema_bind(Reference addr, size_t id) printf(" Align: %zu\n", binding.alignment); printf(" Data:\n"); for(size_t i = 0; i < binding.data.size(); ++i) { - printf(" - %zu {%#x} (%zu)\n", + printf(" - %zu:%#x +%zu\n", binding.data[i].type, type_key(binding.data[i].type), binding.data[i].offset diff --git a/src/runtime/lib.h b/src/runtime/lib.h index afe58d3..be299ae 100644 --- a/src/runtime/lib.h +++ b/src/runtime/lib.h @@ -69,7 +69,7 @@ extern "C" size_t block_length(Reference addr); extern "C" uint8_t block_get(Reference addr, size_t index); extern "C" void block_set(Reference addr, size_t index, uint8_t value); -// String // +// Sequence // extern "C" size_t sequence_capacity(Reference addr); extern "C" size_t sequence_length(Reference addr); extern "C" uint8_t sequence_get(Reference addr, size_t index); @@ -102,6 +102,17 @@ extern "C" void list_remove(Reference addr, size_t index); extern "C" void list_reserve(Reference addr, size_t capacity); //extern "C" void list_resize(Reference addr, size_t length); +// Sparse // +extern "C" size_t sparse_header_length(Reference addr); +extern "C" Type::SparseHeader sparse_header_data(Reference addr, size_t index); +extern "C" size_t sparse_length(Reference addr); +extern "C" void sparse_clear(Reference addr); +extern "C" Reference sparse_at(Reference addr, size_t index); +extern "C" Reference sparse_get(Reference addr, size_t index); +extern "C" void sparse_set(Reference addr, size_t index, Reference source); +extern "C" void sparse_unset(Reference addr, size_t index); +extern "C" size_t sparse_indexof(Reference addr, size_t index); + // Record // extern "C" size_t record_length(Reference addr); extern "C" size_t record_type(Reference addr, size_t index); diff --git a/src/runtime/mod.rs b/src/runtime/mod.rs index f7689d2..146c09e 100644 --- a/src/runtime/mod.rs +++ b/src/runtime/mod.rs @@ -28,6 +28,14 @@ pub struct Str { pub length:usize, } +#[repr(C)] +#[derive(Clone, Copy)] +pub struct SparseHeader { + pub start:usize, + pub length:usize, + pub index:usize, +} + extern "C" { pub fn test(); @@ -101,6 +109,16 @@ extern "C" { //pub fn list_find(addr:Reference, target:Reference, start:usize) -> usize; //pub fn list_count(addr:Reference, target:Reference, start:usize) -> usize; + pub fn sparse_header_length(addr:Reference) -> usize; + pub fn sparse_header_data(addr:Reference, index:usize) -> SparseHeader; + pub fn sparse_length(addr:Reference) -> usize; + pub fn sparse_clear(addr:Reference); + pub fn sparse_get(addr:Reference, index:usize) -> Reference; + pub fn sparse_at(addr:Reference, index:usize) -> Reference; + pub fn sparse_set(addr:Reference, index:usize, source:Reference); + pub fn sparse_unset(addr:Reference, index:usize); + pub fn sparse_indexof(addr:Reference, index:usize) -> usize; + pub fn record_length(addr:Reference) -> usize; pub fn record_type(addr:Reference, index:usize) -> usize; pub fn record_at(addr:Reference, index:usize) -> Reference; diff --git a/src/runtime/nametree.h b/src/runtime/nametree.h index 825c85c..47544e1 100644 --- a/src/runtime/nametree.h +++ b/src/runtime/nametree.h @@ -83,8 +83,8 @@ size_t NameTree::indexof(const std::string& key) // create branching node if value is not prefix if(index != key.length()) { m_nodes.push_back(Node(key.substr(index), intermediate_index)); + m_nodes[intermediate_index].children.push_back(m_nodes.size() - 1); } - return m_nodes.size() - 1; } } @@ -97,7 +97,6 @@ size_t NameTree::indexof(const std::string& key) return m_nodes.size() - 1; } } - return current; } diff --git a/src/runtime/rawlist.cc b/src/runtime/rawlist.cc index af87f11..3c73938 100644 --- a/src/runtime/rawlist.cc +++ b/src/runtime/rawlist.cc @@ -1,6 +1,6 @@ #include "rawlist.h" -void* rawlist_insert(RawList& list, size_t offset, size_t index) +uint8_t* rawlist_insert(RawList& list, size_t offset, size_t index) { if(list.length == list.capacity) { rawlist_reserve(list, offset, (list.capacity == 0) + list.capacity * 2); } if(index > list.length) { index = list.length; } diff --git a/src/runtime/rawlist.h b/src/runtime/rawlist.h index 4c73476..fcb4c81 100644 --- a/src/runtime/rawlist.h +++ b/src/runtime/rawlist.h @@ -11,7 +11,7 @@ struct RawList { uint8_t* data; }; -void* rawlist_insert(RawList& list, size_t offset, size_t index); +uint8_t* rawlist_insert(RawList& list, size_t offset, size_t index); void rawlist_remove(RawList& list, size_t offset, size_t index); inline uint8_t* rawlist_cell(RawList& list, size_t offset, size_t index); void rawlist_reserve(RawList& list, size_t offset, size_t capacity); diff --git a/src/runtime/sparselist.h b/src/runtime/sparselist.h index 69dd024..c3b1759 100644 --- a/src/runtime/sparselist.h +++ b/src/runtime/sparselist.h @@ -14,7 +14,7 @@ public: size_t length() const { - + m_data.size(); } void set(size_t index, const T& value) diff --git a/src/runtime/type.h b/src/runtime/type.h index cfea37f..0e49183 100644 --- a/src/runtime/type.h +++ b/src/runtime/type.h @@ -23,7 +23,7 @@ namespace Tag { Sequence = 0x1f, Array = 0x22, List = 0x23, - //Sparse = 0x24, + Sparse = 0x24, Record = 0x7e, Schema = 0x7f, }; @@ -42,21 +42,15 @@ struct List { RawList data; }; +extern "C" struct SparseHeader { + size_t start; + size_t length; + size_t index; +}; + struct Sparse { - struct Header { - size_t start; - size_t length; - size_t index; - - Header() { - start = 0; - length = 0; - index = 0; - } - }; - - RawList data; RawList header; + RawList data; }; struct Schema { diff --git a/src/tag.rs b/src/tag.rs index 6ae084e..4b42ad4 100644 --- a/src/tag.rs +++ b/src/tag.rs @@ -16,7 +16,7 @@ pub const SEQUENCE :usize = 0x1f; //pub const SET :usize = 0x21; pub const ARRAY :usize = 0x22; pub const LIST :usize = 0x23; -//pub const SPARSE :usize = 0x24; +pub const SPARSE :usize = 0x24; //pub const TRIE :usize = 0x25; //pub const MAP :usize = 0x26; //pub const TREE :usize = 0x27;