diff options
| author | metamuffin <metamuffin@disroot.org> | 2026-01-06 23:43:05 +0100 |
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2026-01-06 23:43:05 +0100 |
| commit | f932d4de439c6472d34ed4bbf530fca13b84d73a (patch) | |
| tree | b64f28fc6bdf40a38ed6e08cc7ce4602d3a4c537 | |
| parent | ffa6b5c4ae2cdd3e07426ed0330f3f66e90ee57b (diff) | |
| download | jellything-f932d4de439c6472d34ed4bbf530fca13b84d73a.tar jellything-f932d4de439c6472d34ed4bbf530fca13b84d73a.tar.bz2 jellything-f932d4de439c6472d34ed4bbf530fca13b84d73a.tar.zst | |
object insert
| -rw-r--r-- | common/object/src/buffer.rs | 15 | ||||
| -rw-r--r-- | common/object/src/lib.rs | 78 | ||||
| -rw-r--r-- | common/object/src/tests.rs | 10 | ||||
| -rw-r--r-- | database/src/table.rs | 11 |
4 files changed, 106 insertions, 8 deletions
diff --git a/common/object/src/buffer.rs b/common/object/src/buffer.rs index dbde833..2f9d066 100644 --- a/common/object/src/buffer.rs +++ b/common/object/src/buffer.rs @@ -24,8 +24,9 @@ impl ObjectBuffer { let mut temp = Vec::new(); for (tag, val) in fields { tags.push(tag.0); + let off = (values.len() as u32) << 2; if val.is_aligned() { - offsets.push((values.len() as u32) << 2); + offsets.push(off); val.store_aligned(&mut values); } else { temp.clear(); @@ -35,7 +36,7 @@ impl ObjectBuffer { pad += 1; temp.push(0); } - offsets.push(((values.len() as u32) << 2) | pad); + offsets.push(off | pad); values.extend(bytemuck::cast_slice(&temp)); // ok bc. temp length is a whole number of dwords } } @@ -60,3 +61,13 @@ impl From<Vec<u8>> for ObjectBuffer { })) } } + +#[inline] +pub(super) fn pad_vec(temp: &mut Vec<u8>) -> u32 { + let mut pad = 0; + while temp.len() % 4 != 0 { + pad += 1; + temp.push(0); + } + pad +} diff --git a/common/object/src/lib.rs b/common/object/src/lib.rs index 522b6c1..540ce1c 100644 --- a/common/object/src/lib.rs +++ b/common/object/src/lib.rs @@ -47,6 +47,13 @@ impl<'a> Object<'a> { .is_some_and(|&x| x == tag.0) .then_some(first) } + #[inline] + fn offset(&self, i: usize) -> usize { + self.offsets + .get(i) + .map(|&v| v >> 2) + .unwrap_or(self.values.len() as u32) as usize + } fn get_aligned(&self, index: usize) -> Option<&[u32]> { let start_raw = self.offsets[index]; let end_raw = self @@ -86,6 +93,12 @@ impl<'a> Object<'a> { pub fn get<'b: 'a, T: Value<'b>>(&'b self, tag: TypedTag<T>) -> Option<T> { self.get_typed(self.find_field(tag.0)?) } + pub fn keys<'b: 'a, T>(&'b self) -> ObjectIter<'b> { + ObjectIter { + object: self, + index: 0, + } + } pub fn iter<'b: 'a, T>(&'b self, tag: TypedTag<T>) -> FieldIter<'b, T> { FieldIter { object: self, @@ -94,6 +107,71 @@ impl<'a> Object<'a> { ty: PhantomData, } } + pub fn insert<T: ValueStore>(&self, tag: TypedTag<T>, value: T) -> ObjectBuffer { + self.insert_multi(tag, &[value]) + } + pub fn insert_multi<T: ValueStore>(&self, tag: TypedTag<T>, values: &[T]) -> ObjectBuffer { + let prefix = self.tags.partition_point(|&x| x < tag.0.0); + let suffix = self.tags.partition_point(|&x| x <= tag.0.0); + let values_prefix = self.offset(prefix + 1); + let values_suffix = self.offset(suffix + 1); + + let mut buf = Vec::new(); + let cut_size = suffix - prefix; + buf.push((self.tags.len() - cut_size + values.len()) as u32); + + buf.extend(&self.tags[..prefix]); + buf.extend(values.iter().map(|_| tag.0.0)); + buf.extend(&self.tags[suffix..]); + + buf.extend(&self.offsets[..prefix]); + let new_offs = buf.len(); + buf.extend(values.iter().map(|_| 0)); // placeholder + let suffix_offs = buf.len(); + buf.extend(&self.offsets[suffix..]); // need offsetting later + let suffix_end = buf.len(); + + let values_start = buf.len() as u32; + buf.extend(&self.values[..values_prefix]); + let mut temp = Vec::new(); + let values_new = buf.len(); + for (i, val) in values.iter().enumerate() { + let off = (buf.len() as u32 - values_start) << 2; + if val.is_aligned() { + buf[new_offs + i] = off; + val.store_aligned(&mut buf); + } else { + temp.clear(); + val.store_unaligned(&mut temp); + let pad = pad_vec(&mut temp); + buf[new_offs + i] = off | pad; + buf.extend(bytemuck::cast_slice(&temp)); + } + } + let insert_size = (buf.len() - values_new) as u32; + buf[suffix_offs..suffix_end] + .iter_mut() + .for_each(|e| *e += insert_size << 2); + buf.extend(&self.values[values_suffix..]); + + ObjectBuffer(buf) + } +} + +pub struct ObjectIter<'a> { + object: &'a Object<'a>, + index: usize, +} +impl Iterator for ObjectIter<'_> { + type Item = Tag; + fn next(&mut self) -> Option<Self::Item> { + if self.index >= self.object.tags.len() { + return None; + } else { + self.index += 1; + Some(Tag(self.object.tags[self.index - 1])) + } + } } pub struct FieldIter<'a, T> { diff --git a/common/object/src/tests.rs b/common/object/src/tests.rs index 143782c..181b46f 100644 --- a/common/object/src/tests.rs +++ b/common/object/src/tests.rs @@ -49,3 +49,13 @@ fn vec_align_test() { } assert_eq!(c, 10_000, "correctly aligned vecs by system allocator") } + +#[test] +fn insert() { + let bob = test_object(); + let edward = bob.as_object().insert(NAME, "Edward"); + + let edward = edward.as_object(); + eprintln!("{edward:#?}"); + assert_eq!(edward.get(NAME), Some("Edward")); +} diff --git a/database/src/table.rs b/database/src/table.rs index 42e03a3..16b9ed5 100644 --- a/database/src/table.rs +++ b/database/src/table.rs @@ -4,14 +4,12 @@ Copyright (C) 2026 metamuffin <metamuffin.org> */ -use std::sync::Arc; - use crate::{ backends::{ReadTransaction, WriteTransaction}, indices::Index, }; use anyhow::Result; -use jellycommon::jellyobject::{Object, ObjectBuffer}; +use jellycommon::jellyobject::ObjectBuffer; pub type TableNum = u64; pub type RowNum = u64; @@ -33,7 +31,7 @@ impl Table { key.extend(row.to_be_bytes()); key } - pub fn insert(&self, db: &mut dyn WriteTransaction, entry: T) -> Result<RowNum> { + pub fn insert(&self, db: &mut dyn WriteTransaction, entry: ObjectBuffer) -> Result<RowNum> { let mut id_counter = db .get(&self.id.to_be_bytes())? .map(|k| k.as_slice().try_into().map(RowNum::from_be_bytes).ok()) @@ -43,10 +41,11 @@ impl Table { id_counter += 1; db.set(&self.id.to_be_bytes(), &id_counter.to_be_bytes())?; - db.set(&self.key(row), &serde_json::to_vec(&entry)?)?; + db.set(&self.key(row), bytemuck::cast_slice(entry.0.as_slice()))?; + let ob = entry.as_object(); for idx in &self.indices { - idx.add(db, row, &entry)?; + idx.add(db, row, ob)?; } Ok(id_counter) |