Avoid a few small allocations when decoding

This commit is contained in:
Tony Garnock-Jones 2020-05-22 10:38:34 +02:00
parent 316a772fec
commit d29ec9ffc4
2 changed files with 66 additions and 44 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "preserves" name = "preserves"
version = "0.5.0" version = "0.5.1"
authors = ["Tony Garnock-Jones <tonyg@leastfixedpoint.com>"] authors = ["Tony Garnock-Jones <tonyg@leastfixedpoint.com>"]
edition = "2018" edition = "2018"
description = "Implementation of the Preserves serialization format via serde." description = "Implementation of the Preserves serialization format via serde."

View File

@ -65,6 +65,35 @@ pub struct Decoder<'a, 'b, R: Read, N: NestedValue<D>, D: Domain> {
read_annotations: bool, read_annotations: bool,
} }
struct CountedStream<'de, 'a, 'b, R: Read, N: NestedValue<D>, D: Domain> {
count: usize,
decoder: &'de mut Decoder<'a, 'b, R, N, D>,
}
impl<'de, 'a, 'b, R: Read, N: NestedValue<D>, D: Domain> Iterator for CountedStream<'de, 'a, 'b, R, N, D> {
type Item = Result<N>;
fn next(&mut self) -> Option<Self::Item> {
if self.count == 0 { return None }
self.count -= 1;
Some(self.decoder.next())
}
}
struct DelimitedStream<'de, 'a, 'b, R: Read, N: NestedValue<D>, D: Domain> {
decoder: &'de mut Decoder<'a, 'b, R, N, D>,
}
impl<'de, 'a, 'b, R: Read, N: NestedValue<D>, D: Domain> Iterator for DelimitedStream<'de, 'a, 'b, R, N, D> {
type Item = Result<N>;
fn next(&mut self) -> Option<Self::Item> {
match self.decoder.peekend() {
Err(e) => Some(Err(e)),
Ok(true) => None,
Ok(false) => Some(self.decoder.next()),
}
}
}
fn decodeint(bs: &[u8]) -> BigInt { fn decodeint(bs: &[u8]) -> BigInt {
BigInt::from_signed_bytes_be(bs) BigInt::from_signed_bytes_be(bs)
} }
@ -124,15 +153,14 @@ impl<'a, 'b, R: Read, N: NestedValue<D>, D: Domain> Decoder<'a, 'b, R, N, D> {
Ok(v) Ok(v)
} }
pub fn readbytes(&mut self, n: usize) -> Result<Vec<u8>> { pub fn readbytes(&mut self, bs: &mut [u8]) -> Result<()> {
if *self.buf != PeekState::Empty { if *self.buf != PeekState::Empty {
unreachable!(); unreachable!();
} }
let mut bs = vec![0; n]; match self.read.read_exact(bs) {
match self.read.read_exact(&mut bs) {
Ok(()) => { Ok(()) => {
self.index += n; self.index += bs.len();
Ok(bs) Ok(())
} }
Err(e) => Err(e) =>
if e.kind() == std::io::ErrorKind::UnexpectedEof { if e.kind() == std::io::ErrorKind::UnexpectedEof {
@ -143,15 +171,6 @@ impl<'a, 'b, R: Read, N: NestedValue<D>, D: Domain> Decoder<'a, 'b, R, N, D> {
} }
} }
pub fn readvalues(&mut self, mut count: usize) -> Result<Vec<N>> {
let mut pieces: Vec<N> = Vec::with_capacity(count);
while count > 0 {
pieces.push(self.next()?);
count -= 1;
}
Ok(pieces)
}
pub fn decodeop(b: u8) -> Result<(Op, u8)> { pub fn decodeop(b: u8) -> Result<(Op, u8)> {
Ok((Op::try_from(b >> 4)?, b & 15)) Ok((Op::try_from(b >> 4)?, b & 15))
} }
@ -195,34 +214,37 @@ impl<'a, 'b, R: Read, N: NestedValue<D>, D: Domain> Decoder<'a, 'b, R, N, D> {
}) })
} }
pub fn decodecompound(minor: CompoundMinor, mut pieces: Vec<N>) -> Result<N> { pub fn decodecompound<I: Iterator<Item = Result<N>>>(minor: CompoundMinor, mut pieces: I) ->
Result<N>
{
match minor { match minor {
CompoundMinor::Record => CompoundMinor::Record =>
if pieces.is_empty() { match pieces.next() {
Err(Error::Syntax("Too few elements in encoded record")) None => Err(Error::Syntax("Too few elements in encoded record")),
} else { Some(labelres) => {
let label = pieces.remove(0); let label = labelres?;
Ok(Value::record(label, pieces).wrap()) Ok(Value::record(label, pieces.collect::<Result<Vec<N>>>()?).wrap())
}
}, },
CompoundMinor::Sequence => Ok(Value::Sequence(pieces).wrap()), CompoundMinor::Sequence => {
Ok(Value::Sequence(pieces.collect::<Result<Vec<N>>>()?).wrap())
}
CompoundMinor::Set => { CompoundMinor::Set => {
let mut s = Set::new(); let mut s = Set::new();
while let Some(v) = pieces.pop() { for res in pieces { s.insert(res?); }
s.insert(v);
}
Ok(Value::Set(s).wrap()) Ok(Value::Set(s).wrap())
} }
CompoundMinor::Dictionary => CompoundMinor::Dictionary => {
if pieces.len() % 2 != 0 { let mut d = Map::new();
Err(Error::Syntax("Missing dictionary value")) while let Some(kres) = pieces.next() {
} else { let k = kres?;
let mut d = Map::new(); match pieces.next() {
while let Some(v) = pieces.pop() { Some(vres) => { d.insert(k, vres?); }
let k = pieces.pop().unwrap(); None => return Err(Error::Syntax("Missing dictionary value")),
d.insert(k, v);
} }
Ok(Value::Dictionary(d).wrap()) }
}, Ok(Value::Dictionary(d).wrap())
}
} }
} }
@ -238,11 +260,7 @@ impl<'a, 'b, R: Read, N: NestedValue<D>, D: Domain> Decoder<'a, 'b, R, N, D> {
} }
pub fn valuestream(&mut self, minor: CompoundMinor) -> Result<N> { pub fn valuestream(&mut self, minor: CompoundMinor) -> Result<N> {
let mut pieces: Vec<N> = Vec::new(); Self::decodecompound(minor, DelimitedStream { decoder: self })
while !self.peekend()? {
pieces.push(self.next()?);
}
Self::decodecompound(minor, pieces)
} }
pub fn next(&mut self) -> Result<N> { pub fn next(&mut self) -> Result<N> {
@ -251,11 +269,13 @@ impl<'a, 'b, R: Read, N: NestedValue<D>, D: Domain> Decoder<'a, 'b, R, N, D> {
(Op::Misc(0), 0) => Ok(Value::from(false).wrap()), (Op::Misc(0), 0) => Ok(Value::from(false).wrap()),
(Op::Misc(0), 1) => Ok(Value::from(true).wrap()), (Op::Misc(0), 1) => Ok(Value::from(true).wrap()),
(Op::Misc(0), 2) => { (Op::Misc(0), 2) => {
let bs: &[u8] = &self.readbytes(4)?; let mut bs: [u8; 4] = Default::default();
self.readbytes(&mut bs)?;
Ok(Value::from(f32::from_bits(u32::from_be_bytes(bs.try_into().unwrap()))).wrap()) Ok(Value::from(f32::from_bits(u32::from_be_bytes(bs.try_into().unwrap()))).wrap())
} }
(Op::Misc(0), 3) => { (Op::Misc(0), 3) => {
let bs: &[u8] = &self.readbytes(8)?; let mut bs: [u8; 8] = Default::default();
self.readbytes(&mut bs)?;
Ok(Value::from(f64::from_bits(u64::from_be_bytes(bs.try_into().unwrap()))).wrap()) Ok(Value::from(f64::from_bits(u64::from_be_bytes(bs.try_into().unwrap()))).wrap())
} }
(Op::Misc(0), 5) => { (Op::Misc(0), 5) => {
@ -295,11 +315,13 @@ impl<'a, 'b, R: Read, N: NestedValue<D>, D: Domain> Decoder<'a, 'b, R, N, D> {
(Op::Misc(_), _) => unreachable!(), (Op::Misc(_), _) => unreachable!(),
(Op::Atom(minor), arg) => { (Op::Atom(minor), arg) => {
let count = self.wirelength(arg)?; let count = self.wirelength(arg)?;
Self::decodebinary(minor, self.readbytes(count)?) let mut bs = vec![0; count];
self.readbytes(&mut bs)?;
Self::decodebinary(minor, bs)
} }
(Op::Compound(minor), arg) => { (Op::Compound(minor), arg) => {
let count = self.wirelength(arg)?; let count = self.wirelength(arg)?;
Self::decodecompound(minor, self.readvalues(count)?) Self::decodecompound(minor, CountedStream { count, decoder: self })
} }
(Op::Reserved(3), 15) => continue, (Op::Reserved(3), 15) => continue,
(Op::Reserved(_), _) => Err(InvalidOp.into()), (Op::Reserved(_), _) => Err(InvalidOp.into()),