diff options
| author | bors <bors@rust-lang.org> | 2013-08-25 13:36:14 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-08-25 13:36:14 -0700 |
| commit | 491bc3568c87dadaba4d342135bd308961c6e0ef (patch) | |
| tree | d3d99d9c97e2de40a5f16cd0c2ca9feee9cdf891 /src/libextra | |
| parent | 05f1bbba16912f63b562a7847801823872f89ec6 (diff) | |
| parent | 022f188a08b11234b2a5fbce3484d233625371c1 (diff) | |
auto merge of #8745 : brson/rust/metadata, r=cmr
This does two things: 1) stops compressing metadata, 2) stops copying the metadata section, instead holding a reference to the buffer returned by the LLVM section iterator. Not compressing metadata requires something like 7x the storage space, but makes running tests about 9% faster. This has been a time improvement on all platforms I've tested, including windows. I considered leaving compression as an option but it doesn't seem to be worth the complexity since we don't currently have any use cases where we need to save that space. In order to avoid copying the metadata section I had to hack up extra::ebml a bit to support unsafe buffers. We should probably move it into librustc so that it can evolve to support the compiler without worrying about having a crummy interface. r? @graydon
Diffstat (limited to 'src/libextra')
| -rw-r--r-- | src/libextra/ebml.rs | 77 |
1 files changed, 57 insertions, 20 deletions
diff --git a/src/libextra/ebml.rs b/src/libextra/ebml.rs index f66677c21f7..560bcccae80 100644 --- a/src/libextra/ebml.rs +++ b/src/libextra/ebml.rs @@ -12,6 +12,8 @@ use std::str; +use std::cast; +use std::vec; // Simple Extensible Binary Markup Language (ebml) reader and writer on a // cursor model. See the specification here: @@ -30,8 +32,41 @@ struct EbmlState { } #[deriving(Clone)] +pub enum EbmlData { + SafeData(@~[u8]), + UnsafeData(*u8, uint) +} + +impl EbmlData { + #[inline] + pub fn slice<'a>(&'a self, start: uint, end: uint) -> &'a [u8] { + match *self { + SafeData(@ref v) => v.slice(start, end), + UnsafeData(buf, len) => unsafe { + do vec::raw::buf_as_slice(buf, len) |s| { + cast::transmute(s.slice(start, end)) + } + } + } + } + + #[inline] + pub fn as_slice<'a>(&'a self) -> &'a [u8] { + self.slice(0, self.len()) + } + + #[inline] + pub fn len(&self) -> uint { + match *self { + SafeData(@ref v) => v.len(), + UnsafeData(_, len) => len + } + } +} + +#[deriving(Clone)] pub struct Doc { - data: @~[u8], + data: EbmlData, start: uint, end: uint, } @@ -185,24 +220,28 @@ pub mod reader { } pub fn Doc(data: @~[u8]) -> Doc { - Doc { data: data, start: 0u, end: data.len() } + Doc { data: SafeData(data), start: 0u, end: data.len() } + } + + pub fn unsafe_Doc(buf: *u8, len: uint) -> Doc { + Doc { data: UnsafeData(buf, len), start: 0u, end: len } } - pub fn doc_at(data: @~[u8], start: uint) -> TaggedDoc { - let elt_tag = vuint_at(*data, start); - let elt_size = vuint_at(*data, elt_tag.next); + pub fn doc_at(data: &EbmlData, start: uint) -> TaggedDoc { + let elt_tag = vuint_at(data.as_slice(), start); + let elt_size = vuint_at(data.as_slice(), elt_tag.next); let end = elt_size.next + elt_size.val; TaggedDoc { tag: elt_tag.val, - doc: Doc { data: data, start: elt_size.next, end: end } + doc: Doc { data: data.clone(), start: elt_size.next, end: end } } } pub fn maybe_get_doc(d: Doc, tg: uint) -> Option<Doc> { let mut pos = d.start; while pos < d.end { - let elt_tag = vuint_at(*d.data, pos); - let elt_size = vuint_at(*d.data, elt_tag.next); + let elt_tag = vuint_at(d.data.as_slice(), pos); + let elt_size = vuint_at(d.data.as_slice(), elt_tag.next); pos = elt_size.next + elt_size.val; if elt_tag.val == tg { return Some(Doc { data: d.data, start: elt_size.next, @@ -225,8 +264,8 @@ pub mod reader { pub fn docs(d: Doc, it: &fn(uint, Doc) -> bool) -> bool { let mut pos = d.start; while pos < d.end { - let elt_tag = vuint_at(*d.data, pos); - let elt_size = vuint_at(*d.data, elt_tag.next); + let elt_tag = vuint_at(d.data.as_slice(), pos); + let elt_size = vuint_at(d.data.as_slice(), elt_tag.next); pos = elt_size.next + elt_size.val; let doc = Doc { data: d.data, start: elt_size.next, end: pos }; if !it(elt_tag.val, doc) { @@ -239,8 +278,8 @@ pub mod reader { pub fn tagged_docs(d: Doc, tg: uint, it: &fn(Doc) -> bool) -> bool { let mut pos = d.start; while pos < d.end { - let elt_tag = vuint_at(*d.data, pos); - let elt_size = vuint_at(*d.data, elt_tag.next); + let elt_tag = vuint_at(d.data.as_slice(), pos); + let elt_size = vuint_at(d.data.as_slice(), elt_tag.next); pos = elt_size.next + elt_size.val; if elt_tag.val == tg { let doc = Doc { data: d.data, start: elt_size.next, @@ -260,22 +299,22 @@ pub mod reader { pub fn doc_as_u8(d: Doc) -> u8 { assert_eq!(d.end, d.start + 1u); - (*d.data)[d.start] + d.data.as_slice()[d.start] } pub fn doc_as_u16(d: Doc) -> u16 { assert_eq!(d.end, d.start + 2u); - io::u64_from_be_bytes(*d.data, d.start, 2u) as u16 + io::u64_from_be_bytes(d.data.as_slice(), d.start, 2u) as u16 } pub fn doc_as_u32(d: Doc) -> u32 { assert_eq!(d.end, d.start + 4u); - io::u64_from_be_bytes(*d.data, d.start, 4u) as u32 + io::u64_from_be_bytes(d.data.as_slice(), d.start, 4u) as u32 } pub fn doc_as_u64(d: Doc) -> u64 { assert_eq!(d.end, d.start + 8u); - io::u64_from_be_bytes(*d.data, d.start, 8u) + io::u64_from_be_bytes(d.data.as_slice(), d.start, 8u) } pub fn doc_as_i8(d: Doc) -> i8 { doc_as_u8(d) as i8 } @@ -298,8 +337,7 @@ pub mod reader { impl Decoder { fn _check_label(&mut self, lbl: &str) { if self.pos < self.parent.end { - let TaggedDoc { tag: r_tag, doc: r_doc } = - doc_at(self.parent.data, self.pos); + let TaggedDoc { tag: r_tag, doc: r_doc } = doc_at(&self.parent.data, self.pos); if r_tag == (EsLabel as uint) { self.pos = r_doc.end; @@ -316,8 +354,7 @@ pub mod reader { if self.pos >= self.parent.end { fail!("no more documents in current node!"); } - let TaggedDoc { tag: r_tag, doc: r_doc } = - doc_at(self.parent.data, self.pos); + let TaggedDoc { tag: r_tag, doc: r_doc } = doc_at(&self.parent.data, self.pos); debug!("self.parent=%?-%? self.pos=%? r_tag=%? r_doc=%?-%?", self.parent.start, self.parent.end, |
