Skip to content

Commit 59dda18

Browse files
committed
Remove internal buffering in CodedOutputStream
This commit removes the internal buffering in CodedOutputStream. The protobuf library should rely on the application to provide a buffered Write implementation, if it so desires. By buffering internally, the protobuf library forces double buffering in situations where the application is already buffering. Additionally, it forces awkward resource lifetime issues as discussed in stepancheg#147. Removing the internal buffering simplifies the internals of CodedOutputStream and improves performance on the rust-protobuf-perftest write tests. Before: test1: write: 86 ns per iter test_repeated_bool: write: 91 ns per iter test_repeated_packed_int32: write: 127 ns per iter test_repeated_messages: write: 224 ns per iter test_optional_messages: write: 202 ns per iter test_strings: write: 136 ns per iter test_small_bytearrays: write: 1098 ns per iter test_large_bytearrays: write: 119221 ns per iter After: test1: write: 55 ns per iter test_repeated_bool: write: 66 ns per iter test_repeated_packed_int32: write: 122 ns per iter test_repeated_messages: write: 248 ns per iter test_optional_messages: write: 207 ns per iter test_strings: write: 118 ns per iter test_small_bytearrays: write: 1064 ns per iter test_large_bytearrays: write: 109567 ns per iter
1 parent 668cbcd commit 59dda18

File tree

1 file changed

+5
-49
lines changed

1 file changed

+5
-49
lines changed

src/lib/stream.rs

Lines changed: 5 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -702,71 +702,27 @@ impl<'a> WithCodedInputStream for &'a [u8] {
702702
}
703703
}
704704

705-
706705
pub struct CodedOutputStream<'a> {
707-
buffer: Box<[u8]>,
708-
// within buffer
709-
position: u32,
710-
writer: Option<&'a mut (Write + 'a)>,
706+
writer: &'a mut Write,
711707
}
712708

713709
impl<'a> CodedOutputStream<'a> {
714710
pub fn new(writer: &'a mut Write) -> CodedOutputStream<'a> {
715-
let buffer_len = 4096;
716-
let mut buffer = Vec::with_capacity(buffer_len);
717-
unsafe { buffer.set_len(buffer_len); }
718711
CodedOutputStream {
719-
buffer: buffer.into_boxed_slice(),
720-
position: 0,
721-
writer: Some(writer),
712+
writer: writer,
722713
}
723714
}
724715

725-
fn refresh_buffer(&mut self) -> ProtobufResult<()> {
726-
match self.writer {
727-
Some(ref mut writer) => {
728-
try!(writer.write_all(&self.buffer[0..self.position as usize])
729-
.map_err(|e| ProtobufError::IoError(e)));
730-
},
731-
None => panic!()
732-
};
733-
self.position = 0;
734-
Ok(())
735-
}
736-
737716
pub fn flush(&mut self) -> ProtobufResult<()> {
738-
if self.writer.is_some() {
739-
try!(self.refresh_buffer());
740-
}
741-
Ok(())
717+
self.writer.flush().map_err(ProtobufError::IoError)
742718
}
743719

744720
pub fn write_raw_byte(&mut self, byte: u8) -> ProtobufResult<()> {
745-
if self.position as usize == self.buffer.len() {
746-
try!(self.refresh_buffer());
747-
}
748-
self.buffer[self.position as usize] = byte;
749-
self.position += 1;
750-
Ok(())
721+
self.writer.write_all(&[byte]).map_err(ProtobufError::IoError)
751722
}
752723

753724
pub fn write_raw_bytes(&mut self, bytes: &[u8]) -> ProtobufResult<()> {
754-
if bytes.len() <= self.buffer.len() - self.position as usize {
755-
// TODO: use `copy_from_slice` as soon as rust 1.9 released
756-
unsafe {
757-
let dest = &mut self.buffer[self.position as usize..];
758-
ptr::copy_nonoverlapping(bytes.as_ptr(), dest.as_mut_ptr(), bytes.len());
759-
self.position += bytes.len() as u32;
760-
return Ok(());
761-
}
762-
}
763-
764-
try!(self.refresh_buffer());
765-
match self.writer {
766-
Some(ref mut writer) => try!(writer.write_all(bytes).map_err(|e| ProtobufError::IoError(e))),
767-
None => panic!()
768-
};
769-
Ok(())
725+
self.writer.write_all(bytes).map_err(ProtobufError::IoError)
770726
}
771727

772728
pub fn write_tag(&mut self, field_number: u32, wire_type: wire_format::WireType) -> ProtobufResult<()> {

0 commit comments

Comments
 (0)