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, }; }