Begin refactor for less allocation

This commit is contained in:
Paul Hauner 2019-05-06 08:47:49 +10:00
parent acf854f558
commit daf6912d18
No known key found for this signature in database
GPG Key ID: 303E4494BB28068C
6 changed files with 82 additions and 68 deletions

View File

@ -1,4 +1,4 @@
//! Encode and decode a list 10,000 times. //! Encode and decode a list many times.
//! //!
//! Useful for `cargo flamegraph`. //! Useful for `cargo flamegraph`.
@ -7,7 +7,7 @@ use ssz::{Decodable, Encodable};
fn main() { fn main() {
let vec: Vec<u64> = vec![4242; 8196]; let vec: Vec<u64> = vec![4242; 8196];
let output: Vec<Vec<u64>> = (0..10_000) let output: Vec<Vec<u64>> = (0..40_000)
.into_iter() .into_iter()
.map(|_| Vec::from_ssz_bytes(&vec.as_ssz_bytes()).unwrap()) .map(|_| Vec::from_ssz_bytes(&vec.as_ssz_bytes()).unwrap())
.collect(); .collect();

View File

@ -1,4 +1,4 @@
use ssz::{Decodable, DecodeError, Encodable, SszDecoderBuilder, SszStream}; use ssz::{encode_length, Decodable, DecodeError, Encodable, SszDecoderBuilder, SszStream};
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Foo { pub struct Foo {
@ -12,14 +12,23 @@ impl Encodable for Foo {
<u16 as Encodable>::is_ssz_fixed_len() && <Vec<u16> as Encodable>::is_ssz_fixed_len() <u16 as Encodable>::is_ssz_fixed_len() && <Vec<u16> as Encodable>::is_ssz_fixed_len()
} }
fn as_ssz_bytes(&self) -> Vec<u8> { fn ssz_append(&self, buf: &mut Vec<u8>) {
let mut stream = SszStream::new(); let offset = <u16 as Encodable>::ssz_fixed_len()
+ <Vec<u16> as Encodable>::ssz_fixed_len()
+ <u16 as Encodable>::ssz_fixed_len();
stream.append(&self.a); let mut fixed = Vec::with_capacity(offset);
stream.append(&self.b); let mut variable = vec![];
stream.append(&self.c);
stream.drain() if <u16 as Encodable>::is_ssz_fixed_len() {
self.a.ssz_append(&mut fixed);
} else {
fixed.append(encode_length())
}
if <Vec<u16> as Encodable>::is_ssz_fixed_len() {
self.a.ssz_append(&mut fixed);
}
} }
} }

View File

@ -3,10 +3,10 @@ use super::*;
mod impls; mod impls;
pub trait Encodable { pub trait Encodable {
fn as_ssz_bytes(&self) -> Vec<u8>;
fn is_ssz_fixed_len() -> bool; fn is_ssz_fixed_len() -> bool;
fn ssz_append(&self, buf: &mut Vec<u8>);
/// The number of bytes this object occupies in the fixed-length portion of the SSZ bytes. /// The number of bytes this object occupies in the fixed-length portion of the SSZ bytes.
/// ///
/// By default, this is set to `BYTES_PER_LENGTH_OFFSET` which is suitable for variable length /// By default, this is set to `BYTES_PER_LENGTH_OFFSET` which is suitable for variable length
@ -15,6 +15,14 @@ pub trait Encodable {
fn ssz_fixed_len() -> usize { fn ssz_fixed_len() -> usize {
BYTES_PER_LENGTH_OFFSET BYTES_PER_LENGTH_OFFSET
} }
fn as_ssz_bytes(&self) -> Vec<u8> {
let mut buf = vec![];
self.ssz_append(&mut buf);
buf
}
} }
pub struct VariableLengths { pub struct VariableLengths {
@ -40,11 +48,13 @@ impl SszStream {
} }
} }
/*
/// Append some item to the stream. /// Append some item to the stream.
pub fn append<T: Encodable>(&mut self, item: &T) { pub fn append<T: Encodable>(&mut self, item: &T) {
let mut bytes = item.as_ssz_bytes(); let mut bytes = item.as_ssz_bytes();
if T::is_ssz_fixed_len() { if T::is_ssz_fixed_len() {
self.app
self.fixed_bytes.append(&mut bytes); self.fixed_bytes.append(&mut bytes);
} else { } else {
self.variable_lengths.push(VariableLengths { self.variable_lengths.push(VariableLengths {
@ -57,6 +67,32 @@ impl SszStream {
self.variable_bytes.append(&mut bytes); self.variable_bytes.append(&mut bytes);
} }
} }
*/
pub fn reserve<T: Encodable>(&mut self, additional: usize) {
if T::is_ssz_fixed_len() {
self.fixed_bytes.reserve(additional * T::ssz_fixed_len());
} else {
self.fixed_bytes
.reserve(additional * BYTES_PER_LENGTH_OFFSET);
self.variable_lengths.reserve(additional);
}
}
pub fn append_fixed_bytes(&mut self, bytes: &[u8]) {
self.fixed_bytes.extend_from_slice(bytes)
}
pub fn append_variable_bytes(&mut self, bytes: &[u8]) {
self.variable_lengths.push(VariableLengths {
fixed_bytes_position: self.fixed_bytes.len(),
variable_bytes_length: bytes.len(),
});
self.fixed_bytes
.append(&mut vec![0; BYTES_PER_LENGTH_OFFSET]);
self.variable_bytes.extend_from_slice(bytes);
}
/// Update the offsets (if any) in the fixed-length bytes to correctly point to the values in /// Update the offsets (if any) in the fixed-length bytes to correctly point to the values in
/// the variable length part. /// the variable length part.

View File

@ -12,8 +12,8 @@ macro_rules! impl_encodable_for_uint {
$bit_size / 8 $bit_size / 8
} }
fn as_ssz_bytes(&self) -> Vec<u8> { fn ssz_append(&self, buf: &mut Vec<u8>) {
self.to_le_bytes().to_vec() buf.extend_from_slice(&self.to_le_bytes());
} }
} }
}; };
@ -30,16 +30,24 @@ impl<T: Encodable> Encodable for Vec<T> {
false false
} }
fn as_ssz_bytes(&self) -> Vec<u8> { fn ssz_append(&self, buf: &mut Vec<u8>) {
if T::is_ssz_fixed_len() { if T::is_ssz_fixed_len() {
let mut bytes = Vec::with_capacity(T::ssz_fixed_len() * self.len()); buf.reserve(T::ssz_fixed_len() * self.len());
for item in self { for item in self {
bytes.append(&mut item.as_ssz_bytes()); item.ssz_append(buf);
} }
bytes
} else { } else {
/*
for item in self {
let mut substream = SszStream::new();
item.ssz_append(&mut substream);
s.append_variable_bytes(&substream.drain());
}
*/
let mut offset = self.len() * BYTES_PER_LENGTH_OFFSET; let mut offset = self.len() * BYTES_PER_LENGTH_OFFSET;
let mut fixed = Vec::with_capacity(offset); let mut fixed = Vec::with_capacity(offset);
let mut variable = vec![]; let mut variable = vec![];
@ -51,9 +59,8 @@ impl<T: Encodable> Encodable for Vec<T> {
variable.append(&mut bytes); variable.append(&mut bytes);
} }
fixed.append(&mut variable); buf.append(&mut fixed);
buf.append(&mut variable);
fixed
} }
} }
} }
@ -64,8 +71,8 @@ impl Encodable for bool {
Some(8) Some(8)
} }
fn as_ssz_bytes(&self) -> Vec<u8> { fn ssz_append(&self, s: &mut SszStream) {
(*self as u8).to_le_bytes().to_vec() s.append_fixed_bytes(&(self as u8).to_le_bytes());
} }
} }
@ -94,48 +101,6 @@ macro_rules! impl_encodable_for_u8_array {
} }
impl_encodable_for_u8_array!(4); impl_encodable_for_u8_array!(4);
macro_rules! impl_encodable_for_u8_array {
($len: expr) => {
impl Encodable for [u8; $len] {
fn ssz_append(&self, s: &mut SszStream) {
let bytes: Vec<u8> = self.iter().cloned().collect();
s.append_encoded_raw(&bytes);
}
}
};
}
impl_encodable_for_u8_array!(4);
impl Encodable for bool {
fn ssz_append(&self, s: &mut SszStream) {
let byte = if *self { 0b0000_0001 } else { 0b0000_0000 };
s.append_encoded_raw(&[byte]);
}
}
impl Encodable for H256 {
fn ssz_append(&self, s: &mut SszStream) {
s.append_encoded_raw(self.as_bytes());
}
}
impl Encodable for Address {
fn ssz_append(&self, s: &mut SszStream) {
s.append_encoded_raw(self.as_bytes());
}
}
impl<T> Encodable for Vec<T>
where
T: Encodable,
{
fn ssz_append(&self, s: &mut SszStream) {
s.append_vec(&self);
}
}
*/ */
#[cfg(test)] #[cfg(test)]

View File

@ -27,9 +27,11 @@ pub fn ssz_encode<T>(val: &T) -> Vec<u8>
where where
T: Encodable, T: Encodable,
{ {
let mut ssz_stream = SszStream::new(); let mut buf = vec![];
ssz_stream.append(val);
ssz_stream.drain() val.ssz_append(&mut buf);
buf
} }
/* /*

View File

@ -1,6 +1,7 @@
use ssz::{Decodable, Encodable}; use ssz::{Decodable, Encodable};
use ssz_derive::{Decode, Encode}; use ssz_derive::{Decode, Encode};
/*
fn round_trip<T: Encodable + Decodable + std::fmt::Debug + PartialEq>(items: Vec<T>) { fn round_trip<T: Encodable + Decodable + std::fmt::Debug + PartialEq>(items: Vec<T>) {
for item in items { for item in items {
let encoded = &item.as_ssz_bytes(); let encoded = &item.as_ssz_bytes();
@ -157,3 +158,4 @@ fn vec_of_variable_len_struct() {
round_trip(items); round_trip(items);
} }
*/