Skip to content

Commit 134d42b

Browse files
committed
optimize the fixed32 and fixed64 encoding
1 parent 4e8b38b commit 134d42b

File tree

2 files changed

+60
-2
lines changed

2 files changed

+60
-2
lines changed

protobuf/src/coded_output_stream/mod.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ impl<'a> CodedOutputStream<'a> {
265265
pub fn write_raw_varint32(&mut self, value: u32) -> crate::Result<()> {
266266
if self.buffer.unfilled_len() >= 5 {
267267
// fast path
268+
// SAFETY: we've just checked that there's enough space in the buffer.
268269
unsafe {
269270
let len = encode_varint32(value, self.buffer.unfilled());
270271
self.buffer.advance(len);
@@ -284,6 +285,7 @@ impl<'a> CodedOutputStream<'a> {
284285
pub fn write_raw_varint64(&mut self, value: u64) -> crate::Result<()> {
285286
if self.buffer.unfilled_len() >= MAX_VARINT_ENCODED_LEN {
286287
// fast path
288+
// SAFETY: we've just checked that there's enough space in the buffer.
287289
unsafe {
288290
let len = encode_varint64(value, self.buffer.unfilled());
289291
self.buffer.advance(len);
@@ -301,12 +303,38 @@ impl<'a> CodedOutputStream<'a> {
301303

302304
/// Write 32-bit integer little endian
303305
pub fn write_raw_little_endian32(&mut self, value: u32) -> crate::Result<()> {
304-
self.write_raw_bytes(&value.to_le_bytes())
306+
if self.buffer.unfilled_len() >= 4 {
307+
// fast path
308+
// SAFETY: we've just checked that there's enough space in the buffer.
309+
unsafe {
310+
let buf = self.buffer.unfilled();
311+
let bytes = value.to_le_bytes();
312+
ptr::copy_nonoverlapping(bytes.as_ptr(), buf.as_mut_ptr() as *mut u8, 4);
313+
self.buffer.advance(4);
314+
};
315+
Ok(())
316+
} else {
317+
// slow path
318+
self.write_raw_bytes(&value.to_le_bytes())
319+
}
305320
}
306321

307322
/// Write 64-bit integer little endian
308323
pub fn write_raw_little_endian64(&mut self, value: u64) -> crate::Result<()> {
309-
self.write_raw_bytes(&value.to_le_bytes())
324+
if self.buffer.unfilled_len() >= 8 {
325+
// fast path
326+
// SAFETY: we've just checked that there's enough space in the buffer.
327+
unsafe {
328+
let buf = self.buffer.unfilled();
329+
let bytes = value.to_le_bytes();
330+
ptr::copy_nonoverlapping(bytes.as_ptr(), buf.as_mut_ptr() as *mut u8, 8);
331+
self.buffer.advance(8);
332+
};
333+
Ok(())
334+
} else {
335+
// slow path
336+
self.write_raw_bytes(&value.to_le_bytes())
337+
}
310338
}
311339

312340
/// Write `float`

test-crates/perftest/misc/benches/coded_output_stream.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,33 @@ fn bench_write_raw_varint_32(b: &mut Bencher) {
6363
v.len()
6464
})
6565
}
66+
67+
#[bench]
68+
fn bench_write_raw_fixed32(b: &mut Bencher) {
69+
let mut v = Vec::with_capacity(10_000);
70+
b.iter(|| {
71+
v.clear();
72+
{
73+
let mut os = CodedOutputStream::new(&mut v);
74+
for i in 0..1000 {
75+
os.write_fixed32_no_tag(i * 139 % 1000).unwrap();
76+
}
77+
}
78+
v.len()
79+
})
80+
}
81+
82+
#[bench]
83+
fn bench_write_raw_fixed64(b: &mut Bencher) {
84+
let mut v = Vec::with_capacity(10_000);
85+
b.iter(|| {
86+
v.clear();
87+
{
88+
let mut os = CodedOutputStream::new(&mut v);
89+
for i in 0..1000 {
90+
os.write_fixed64_no_tag(i * 12345678 % 100000000).unwrap();
91+
}
92+
}
93+
v.len()
94+
})
95+
}

0 commit comments

Comments
 (0)