Skip to content

Commit fa2a741

Browse files
Use a more efficient encoding for opaque data in RBML.
1 parent 8975307 commit fa2a741

File tree

12 files changed

+1308
-369
lines changed

12 files changed

+1308
-369
lines changed

src/librbml/leb128.rs

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#[inline]
12+
pub fn write_to_vec(vec: &mut Vec<u8>, position: &mut usize, byte: u8)
13+
{
14+
if *position == vec.len() {
15+
vec.push(byte);
16+
} else {
17+
vec[*position] = byte;
18+
}
19+
20+
*position += 1;
21+
}
22+
23+
pub fn write_unsigned_leb128(out: &mut Vec<u8>,
24+
start_position: usize,
25+
mut value: u64)
26+
-> usize {
27+
let mut position = start_position;
28+
loop
29+
{
30+
let mut byte = (value & 0x7F) as u8;
31+
value >>= 7;
32+
if value != 0 {
33+
byte |= 0x80;
34+
}
35+
36+
write_to_vec(out, &mut position, byte);
37+
38+
if value == 0 {
39+
break;
40+
}
41+
}
42+
43+
return position - start_position;
44+
}
45+
46+
pub fn read_unsigned_leb128(data: &[u8],
47+
start_position: usize)
48+
-> (u64, usize) {
49+
let mut result = 0;
50+
let mut shift = 0;
51+
let mut position = start_position;
52+
loop {
53+
let byte = data[position];
54+
position += 1;
55+
result |= ((byte & 0x7F) as u64) << shift;
56+
if (byte & 0x80) == 0 {
57+
break;
58+
}
59+
shift += 7;
60+
}
61+
62+
(result, position - start_position)
63+
}
64+
65+
66+
pub fn write_signed_leb128(out: &mut Vec<u8>,
67+
start_position: usize,
68+
mut value: i64) -> usize {
69+
let mut position = start_position;
70+
71+
loop {
72+
let mut byte = (value as u8) & 0x7f;
73+
value >>= 7;
74+
let more = !((((value == 0 ) && ((byte & 0x40) == 0)) ||
75+
((value == -1) && ((byte & 0x40) != 0))));
76+
if more {
77+
byte |= 0x80; // Mark this byte to show that more bytes will follow.
78+
}
79+
80+
write_to_vec(out, &mut position, byte);
81+
82+
if !more {
83+
break;
84+
}
85+
}
86+
87+
return position - start_position;
88+
}
89+
90+
pub fn read_signed_leb128(data: &[u8],
91+
start_position: usize)
92+
-> (i64, usize) {
93+
let mut result = 0;
94+
let mut shift = 0;
95+
let mut position = start_position;
96+
let mut byte;
97+
98+
loop {
99+
byte = data[position];
100+
position += 1;
101+
result |= ((byte & 0x7F) as i64) << shift;
102+
shift += 7;
103+
104+
if (byte & 0x80) == 0 {
105+
break;
106+
}
107+
}
108+
109+
if (shift < 64) && ((byte & 0x40) != 0) {
110+
/* sign extend */
111+
result |= -(1i64 << shift);
112+
}
113+
114+
(result, position - start_position)
115+
}
116+
117+
#[test]
118+
fn test_unsigned_leb128() {
119+
let mut stream = Vec::with_capacity(10000);
120+
121+
for x in 0..62 {
122+
let pos = stream.len();
123+
let bytes_written = write_unsigned_leb128(&mut stream, pos, 3 << x);
124+
assert_eq!(stream.len(), pos + bytes_written);
125+
}
126+
127+
let mut position = 0;
128+
for x in 0..62 {
129+
let expected = 3 << x;
130+
let (actual, bytes_read) = read_unsigned_leb128(&stream, position);
131+
assert_eq!(expected, actual);
132+
position += bytes_read;
133+
}
134+
assert_eq!(stream.len(), position);
135+
}
136+
137+
#[test]
138+
fn test_signed_leb128() {
139+
let mut values = Vec::new();
140+
141+
let mut i = -500;
142+
while i < 500 {
143+
values.push(i * 123457i64);
144+
i += 1;
145+
}
146+
147+
let mut stream = Vec::new();
148+
149+
for &x in &values {
150+
let pos = stream.len();
151+
let bytes_written = write_signed_leb128(&mut stream, pos, x);
152+
assert_eq!(stream.len(), pos + bytes_written);
153+
}
154+
155+
let mut pos = 0;
156+
for &x in &values {
157+
let (value, bytes_read) = read_signed_leb128(&mut stream, pos);
158+
pos += bytes_read;
159+
assert_eq!(x, value);
160+
}
161+
assert_eq!(pos, stream.len());
162+
}

src/librbml/lib.rs

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,17 @@
128128
#![cfg_attr(test, feature(test))]
129129

130130
extern crate serialize;
131+
132+
#[cfg(test)]
133+
extern crate serialize as rustc_serialize; // Used by RustcEncodable
134+
131135
#[macro_use] extern crate log;
132136

133137
#[cfg(test)] extern crate test;
134138

139+
pub mod opaque;
140+
pub mod leb128;
141+
135142
pub use self::EbmlEncoderTag::*;
136143
pub use self::Error::*;
137144

@@ -241,6 +248,7 @@ pub mod reader {
241248

242249
use serialize;
243250

251+
use super::opaque;
244252
use super::{ ApplicationError, EsVec, EsMap, EsEnum, EsSub8, EsSub32,
245253
EsVecElt, EsMapKey, EsU64, EsU32, EsU16, EsU8, EsI64,
246254
EsI32, EsI16, EsI8, EsBool, EsF64, EsF32, EsChar, EsStr, EsMapVal,
@@ -621,18 +629,16 @@ pub mod reader {
621629
}
622630

623631
pub fn read_opaque<R, F>(&mut self, op: F) -> DecodeResult<R> where
624-
F: FnOnce(&mut Decoder, Doc) -> DecodeResult<R>,
632+
F: FnOnce(&mut opaque::Decoder, Doc) -> DecodeResult<R>,
625633
{
626634
let doc = try!(self.next_doc(EsOpaque));
627635

628-
let (old_parent, old_pos) = (self.parent, self.pos);
629-
self.parent = doc;
630-
self.pos = doc.start;
631-
632-
let result = try!(op(self, doc));
636+
let result = {
637+
let mut opaque_decoder = opaque::Decoder::new(doc.data,
638+
doc.start);
639+
try!(op(&mut opaque_decoder, doc))
640+
};
633641

634-
self.parent = old_parent;
635-
self.pos = old_pos;
636642
Ok(result)
637643
}
638644

@@ -877,6 +883,7 @@ pub mod writer {
877883
use std::io::prelude::*;
878884
use std::io::{self, SeekFrom, Cursor};
879885

886+
use super::opaque;
880887
use super::{ EsVec, EsMap, EsEnum, EsSub8, EsSub32, EsVecElt, EsMapKey,
881888
EsU64, EsU32, EsU16, EsU8, EsI64, EsI32, EsI16, EsI8,
882889
EsBool, EsF64, EsF32, EsChar, EsStr, EsMapVal,
@@ -1120,10 +1127,16 @@ pub mod writer {
11201127
}
11211128

11221129
pub fn emit_opaque<F>(&mut self, f: F) -> EncodeResult where
1123-
F: FnOnce(&mut Encoder) -> EncodeResult,
1130+
F: FnOnce(&mut opaque::Encoder) -> EncodeResult,
11241131
{
11251132
try!(self.start_tag(EsOpaque as usize));
1126-
try!(f(self));
1133+
1134+
{
1135+
let mut opaque_encoder = opaque::Encoder::new(self.writer);
1136+
try!(f(&mut opaque_encoder));
1137+
}
1138+
1139+
self.mark_stable_position();
11271140
self.end_tag()
11281141
}
11291142
}

0 commit comments

Comments
 (0)