diff --git a/benchmarks/compare/canbench_results.yml b/benchmarks/compare/canbench_results.yml
index add6fc9e..bdf415a3 100644
--- a/benchmarks/compare/canbench_results.yml
+++ b/benchmarks/compare/canbench_results.yml
@@ -2,21 +2,21 @@ benches:
read_chunks_btreemap_1:
total:
calls: 1
- instructions: 1219162597
+ instructions: 1219162653
heap_increase: 3233
stable_memory_increase: 1665
scopes: {}
read_chunks_btreemap_1k:
total:
calls: 1
- instructions: 5414908676
+ instructions: 5414908732
heap_increase: 1604
stable_memory_increase: 1665
scopes: {}
read_chunks_btreemap_1m:
total:
calls: 1
- instructions: 133588820086
+ instructions: 133588820142
heap_increase: 1892
stable_memory_increase: 3201
scopes: {}
@@ -44,42 +44,42 @@ benches:
read_chunks_vec_1:
total:
calls: 1
- instructions: 1363286727
+ instructions: 1363286555
heap_increase: 3202
stable_memory_increase: 1665
scopes: {}
read_chunks_vec_1k:
total:
calls: 1
- instructions: 1378054827
- heap_increase: 1602
+ instructions: 1378501974
+ heap_increase: 3200
stable_memory_increase: 1665
scopes: {}
read_chunks_vec_1m:
total:
calls: 1
- instructions: 4584728190
- heap_increase: 1892
+ instructions: 4748969057
+ heap_increase: 3784
stable_memory_increase: 1665
scopes: {}
write_chunks_btreemap_1:
total:
calls: 1
- instructions: 1069803049
+ instructions: 1069803070
heap_increase: 3233
stable_memory_increase: 1665
scopes: {}
write_chunks_btreemap_1k:
total:
calls: 1
- instructions: 4914919689
+ instructions: 4914919710
heap_increase: 1604
stable_memory_increase: 1665
scopes: {}
write_chunks_btreemap_1m:
total:
calls: 1
- instructions: 89822427791
+ instructions: 89822427812
heap_increase: 1892
stable_memory_increase: 3201
scopes: {}
@@ -107,22 +107,22 @@ benches:
write_chunks_vec_1:
total:
calls: 1
- instructions: 1257791168
+ instructions: 1257790996
heap_increase: 3202
stable_memory_increase: 1665
scopes: {}
write_chunks_vec_1k:
total:
calls: 1
- instructions: 1271592530
- heap_increase: 1602
+ instructions: 1272039677
+ heap_increase: 3200
stable_memory_increase: 1665
scopes: {}
write_chunks_vec_1m:
total:
calls: 1
- instructions: 3575186447
- heap_increase: 1892
+ instructions: 3739427314
+ heap_increase: 3784
stable_memory_increase: 1665
scopes: {}
version: 0.1.15
diff --git a/src/storable/tuples.rs b/src/storable/tuples.rs
index 180d5c88..e4d8fc8b 100644
--- a/src/storable/tuples.rs
+++ b/src/storable/tuples.rs
@@ -1,7 +1,7 @@
use crate::storable::{
bounds, bytes_to_store_size, bytes_to_store_size_bounded, Bound, Bounds, Storable,
};
-use std::borrow::{Borrow, Cow};
+use std::borrow::Cow;
impl Storable for (A, B)
where
@@ -11,26 +11,22 @@ where
fn to_bytes(&self) -> Cow<[u8]> {
match Self::BOUND {
Bound::Bounded { max_size, .. } => {
- let mut bytes = vec![0; max_size as usize];
let a_bytes = self.0.to_bytes();
let b_bytes = self.1.to_bytes();
-
let a_bounds = bounds::();
let b_bounds = bounds::();
-
let a_max_size = a_bounds.max_size as usize;
let b_max_size = b_bounds.max_size as usize;
+ let a_size_len = bytes_to_store_size_bounded(&a_bounds) as usize;
+ let b_size_len = bytes_to_store_size_bounded(&b_bounds) as usize;
+ let sizes_offset = a_max_size + b_max_size;
debug_assert!(a_bytes.len() <= a_max_size);
debug_assert!(b_bytes.len() <= b_max_size);
- bytes[0..a_bytes.len()].copy_from_slice(a_bytes.borrow());
- bytes[a_max_size..a_max_size + b_bytes.len()].copy_from_slice(b_bytes.borrow());
-
- let a_size_len = bytes_to_store_size_bounded(&a_bounds) as usize;
- let b_size_len = bytes_to_store_size_bounded(&b_bounds) as usize;
-
- let sizes_offset: usize = a_max_size + b_max_size;
+ let mut bytes = vec![0; max_size as usize];
+ bytes[..a_bytes.len()].copy_from_slice(a_bytes.as_ref());
+ bytes[a_max_size..a_max_size + b_bytes.len()].copy_from_slice(b_bytes.as_ref());
encode_size_of_bound(
&mut bytes[sizes_offset..sizes_offset + a_size_len],
@@ -54,15 +50,14 @@ where
match Self::BOUND {
Bound::Bounded { max_size, .. } => {
assert_eq!(bytes.len(), max_size as usize);
-
let a_bounds = bounds::();
let b_bounds = bounds::();
let a_max_size = a_bounds.max_size as usize;
let b_max_size = b_bounds.max_size as usize;
let sizes_offset = a_max_size + b_max_size;
-
let a_size_len = bytes_to_store_size_bounded(&a_bounds) as usize;
let b_size_len = bytes_to_store_size_bounded(&b_bounds) as usize;
+
let a_len = decode_size_of_bound(
&bytes[sizes_offset..sizes_offset + a_size_len],
&a_bounds,
@@ -72,35 +67,27 @@ where
&b_bounds,
);
- let a = A::from_bytes(Cow::Borrowed(&bytes[0..a_len]));
+ let a = A::from_bytes(Cow::Borrowed(&bytes[..a_len]));
let b = B::from_bytes(Cow::Borrowed(&bytes[a_max_size..a_max_size + b_len]));
-
(a, b)
}
_ => todo!("Deserializing tuples with unbounded types is not yet supported."),
}
}
- const BOUND: Bound = {
- match (A::BOUND, B::BOUND) {
- (Bound::Bounded { .. }, Bound::Bounded { .. }) => {
- let a_bounds = bounds::();
- let b_bounds = bounds::();
-
- let max_size = a_bounds.max_size
+ const BOUND: Bound = match (A::BOUND, B::BOUND) {
+ (Bound::Bounded { .. }, Bound::Bounded { .. }) => {
+ let a_bounds = bounds::();
+ let b_bounds = bounds::();
+ Bound::Bounded {
+ max_size: a_bounds.max_size
+ b_bounds.max_size
+ bytes_to_store_size_bounded(&a_bounds)
- + bytes_to_store_size_bounded(&b_bounds);
-
- let is_fixed_size = a_bounds.is_fixed_size && b_bounds.is_fixed_size;
-
- Bound::Bounded {
- max_size,
- is_fixed_size,
- }
+ + bytes_to_store_size_bounded(&b_bounds),
+ is_fixed_size: a_bounds.is_fixed_size && b_bounds.is_fixed_size,
}
- _ => Bound::Unbounded,
}
+ _ => Bound::Unbounded,
};
}
@@ -113,10 +100,9 @@ fn decode_size_of_bound(src: &[u8], bounds: &Bounds) -> usize {
}
fn encode_size_of_bound(dst: &mut [u8], n: usize, bounds: &Bounds) {
- if bounds.is_fixed_size {
- return;
+ if !bounds.is_fixed_size {
+ encode_size(dst, n, bytes_to_store_size(bounds.max_size as usize));
}
- encode_size(dst, n, bytes_to_store_size(bounds.max_size as usize));
}
/// Decodes size from the beginning of `src` of length `size_len` and returns it.
@@ -129,15 +115,15 @@ fn decode_size(src: &[u8], size_len: usize) -> usize {
}
/// Encodes `size` at the beginning of `dst` of length `bytes_to_store_size` bytes.
-fn encode_size(dst: &mut [u8], size: usize, bytes_to_store_size: usize) {
- match bytes_to_store_size {
- 1 => dst[0] = size as u8,
- 2 => dst[0..2].copy_from_slice(&(size as u16).to_be_bytes()),
- _ => dst[0..4].copy_from_slice(&(size as u32).to_be_bytes()),
- };
+fn encode_size(dst: &mut [u8], size_len: usize, bytes: usize) {
+ match bytes {
+ 1 => dst[0] = size_len as u8,
+ 2 => dst[..2].copy_from_slice(&(size_len as u16).to_be_bytes()),
+ _ => dst[..4].copy_from_slice(&(size_len as u32).to_be_bytes()),
+ }
}
-fn encode_size_lengths(sizes: Vec) -> u8 {
+fn encode_size_lengths(sizes: &[usize]) -> u8 {
assert!(sizes.len() <= 4);
let mut size_lengths_byte: u8 = 0;
@@ -186,16 +172,14 @@ fn decode_size_lengths(mut encoded_bytes_to_store: u8, number_of_encoded_lengths
// The element is assumed to be at the beginning of `dst`.
// Returns the number of bytes written to `dst`.
fn encode_tuple_element(dst: &mut [u8], bytes: &[u8], last: bool) -> usize {
- let mut bytes_written: usize = 0;
- let size = bytes.len();
-
+ let mut offset = 0;
if !last && !T::BOUND.is_fixed_size() {
- encode_size(&mut dst[bytes_written..], size, bytes_to_store_size(size));
- bytes_written += bytes_to_store_size(size);
+ let size_len = bytes_to_store_size(bytes.len());
+ encode_size(&mut dst[offset..], bytes.len(), size_len);
+ offset += size_len;
}
-
- dst[bytes_written..bytes_written + size].copy_from_slice(bytes);
- bytes_written + size
+ dst[offset..offset + bytes.len()].copy_from_slice(bytes);
+ offset + bytes.len()
}
// Decodes an element `T` from a tuple.
@@ -205,12 +189,11 @@ fn encode_tuple_element(dst: &mut [u8], bytes: &[u8], last: bool) -
//
// Returns the element `T` and the number of bytes read from `src`.
fn decode_tuple_element(src: &[u8], size_len: Option, last: bool) -> (T, usize) {
- let mut bytes_read: usize = 0;
-
- let size = if let Some(size_len) = size_len {
- let size = decode_size(&src[bytes_read..], size_len as usize);
- bytes_read += size_len as usize;
- size
+ let mut read = 0;
+ let size = if let Some(len) = size_len {
+ let s = decode_size(&src[read..], len as usize);
+ read += len as usize;
+ s
} else if let Bound::Bounded {
max_size,
is_fixed_size: true,
@@ -222,10 +205,9 @@ fn decode_tuple_element(src: &[u8], size_len: Option, last: boo
assert!(last);
src.len()
};
-
(
- T::from_bytes(Cow::Borrowed(&src[bytes_read..bytes_read + size])),
- bytes_read + size,
+ T::from_bytes(Cow::Borrowed(&src[read..read + size])),
+ read + size,
)
}
@@ -255,104 +237,82 @@ where
B: Storable,
C: Storable,
{
- // Tuple (A, B, C) will be serialized in the following form:
- // If A and B have fixed size
- //
- // Otherwise
- //
+ // Tuple (A, B, C) serialization:
+ // If A and B have fixed size:
+ //
+ // Otherwise:
+ //
fn to_bytes(&self) -> Cow<[u8]> {
let a_bytes = self.0.to_bytes();
- let a_size = a_bytes.len();
-
let b_bytes = self.1.to_bytes();
- let b_size = b_bytes.len();
-
let c_bytes = self.2.to_bytes();
+ let a_size = a_bytes.len();
+ let b_size = b_bytes.len();
let c_size = c_bytes.len();
let sizes_overhead = sizes_overhead::(a_size, b_size);
-
let output_size = a_size + b_size + c_size + sizes_overhead;
-
- let mut bytes_written = 0;
-
let mut bytes = vec![0; output_size];
+ let mut offset = 0;
if sizes_overhead != 0 {
- bytes[bytes_written] = encode_size_lengths(vec![a_size, b_size]);
- bytes_written += 1;
+ bytes[offset] = encode_size_lengths(&[a_size, b_size]);
+ offset += 1;
}
- bytes_written +=
- encode_tuple_element::(&mut bytes[bytes_written..], a_bytes.borrow(), false);
- bytes_written +=
- encode_tuple_element::(&mut bytes[bytes_written..], b_bytes.borrow(), false);
- bytes_written +=
- encode_tuple_element::(&mut bytes[bytes_written..], c_bytes.borrow(), true);
-
- assert_eq!(bytes_written, output_size);
+ offset += encode_tuple_element::(&mut bytes[offset..], a_bytes.as_ref(), false);
+ offset += encode_tuple_element::(&mut bytes[offset..], b_bytes.as_ref(), false);
+ offset += encode_tuple_element::(&mut bytes[offset..], c_bytes.as_ref(), true);
+ debug_assert_eq!(offset, output_size);
Cow::Owned(bytes)
}
#[inline]
fn from_bytes(bytes: Cow<[u8]>) -> Self {
- let mut bytes_read_total = 0;
-
+ let mut offset = 0;
let mut size_lengths = [None, None];
if !(A::BOUND.is_fixed_size() && B::BOUND.is_fixed_size()) {
- let lengths = decode_size_lengths(bytes[bytes_read_total], 2);
- bytes_read_total += 1;
-
+ let lengths = decode_size_lengths(bytes[0], 2);
+ offset += 1;
if !A::BOUND.is_fixed_size() {
size_lengths[0] = Some(lengths[0]);
}
-
if !B::BOUND.is_fixed_size() {
size_lengths[1] = Some(lengths[1]);
}
}
- let (a, bytes_read) =
- decode_tuple_element::(&bytes[bytes_read_total..], size_lengths[0], false);
- bytes_read_total += bytes_read;
-
- let (b, bytes_read) =
- decode_tuple_element::(&bytes[bytes_read_total..], size_lengths[1], false);
- bytes_read_total += bytes_read;
-
- let (c, bytes_read) = decode_tuple_element::(&bytes[bytes_read_total..], None, true);
-
- bytes_read_total += bytes_read;
-
- assert_eq!(bytes_read_total, bytes.len());
+ let (a, read) = decode_tuple_element::(&bytes[offset..], size_lengths[0], false);
+ offset += read;
+ let (b, read) = decode_tuple_element::(&bytes[offset..], size_lengths[1], false);
+ offset += read;
+ let (c, read) = decode_tuple_element::(&bytes[offset..], None, true);
+ offset += read;
+ debug_assert_eq!(offset, bytes.len());
(a, b, c)
}
- const BOUND: Bound = {
- match (A::BOUND, B::BOUND, C::BOUND) {
- (Bound::Bounded { .. }, Bound::Bounded { .. }, Bound::Bounded { .. }) => {
- let a_bounds = bounds::();
- let b_bounds = bounds::();
- let c_bounds = bounds::();
-
- let sizes_overhead =
- sizes_overhead::(a_bounds.max_size as usize, b_bounds.max_size as usize)
- as u32;
-
- Bound::Bounded {
- max_size: a_bounds.max_size
- + b_bounds.max_size
- + c_bounds.max_size
- + sizes_overhead,
- is_fixed_size: a_bounds.is_fixed_size
- && b_bounds.is_fixed_size
- && c_bounds.is_fixed_size,
- }
+ const BOUND: Bound = match (A::BOUND, B::BOUND, C::BOUND) {
+ (Bound::Bounded { .. }, Bound::Bounded { .. }, Bound::Bounded { .. }) => {
+ let a_bounds = bounds::();
+ let b_bounds = bounds::();
+ let c_bounds = bounds::();
+ let sizes_overhead =
+ sizes_overhead::(a_bounds.max_size as usize, b_bounds.max_size as usize)
+ as u32;
+ Bound::Bounded {
+ max_size: a_bounds.max_size
+ + b_bounds.max_size
+ + c_bounds.max_size
+ + sizes_overhead,
+ is_fixed_size: a_bounds.is_fixed_size
+ && b_bounds.is_fixed_size
+ && c_bounds.is_fixed_size,
}
- _ => Bound::Unbounded,
}
+ _ => Bound::Unbounded,
};
}