flate: return CVec<u8> rather than copying into a new vector.

This trades an O(n) allocation + memcpy for a O(1) proc allocation (for
the destructor). Most users only need &[u8] anyway (all of the users in
the main repo), and so this offers large gains.
This commit is contained in:
Huon Wilson 2014-02-21 19:28:44 +11:00
parent 768b96e8b1
commit 06e3e63c90
7 changed files with 40 additions and 28 deletions

View File

@ -65,7 +65,7 @@ DEPS_rustc := syntax native:rustllvm flate arena serialize sync getopts \
collections time extra
DEPS_rustdoc := rustc native:sundown serialize sync getopts collections \
test time
DEPS_flate := std native:miniz
DEPS_flate := std extra native:miniz
DEPS_arena := std collections
DEPS_glob := std
DEPS_serialize := std

View File

@ -35,7 +35,9 @@
* if necessary.
*/
use std::cast;
use std::ptr;
use std::raw;
/**
* The type representing a foreign chunk of memory
@ -111,6 +113,20 @@ impl <T> CVec<T> {
}
}
/// View the stored data as a slice.
pub fn as_slice<'a>(&'a self) -> &'a [T] {
unsafe {
cast::transmute(raw::Slice { data: self.base as *T, len: self.len })
}
}
/// View the stored data as a mutable slice.
pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
unsafe {
cast::transmute(raw::Slice { data: self.base as *T, len: self.len })
}
}
/**
* Retrieves an element at a given index
*

View File

@ -20,9 +20,10 @@ Simple compression
#[license = "MIT/ASL2"];
#[allow(missing_doc)];
extern crate extra;
use std::libc::{c_void, size_t, c_int};
use std::libc;
use std::vec;
use extra::c_vec::CVec;
pub mod rustrt {
use std::libc::{c_int, c_void, size_t};
@ -33,13 +34,13 @@ pub mod rustrt {
src_buf_len: size_t,
pout_len: *mut size_t,
flags: c_int)
-> *c_void;
-> *mut c_void;
pub fn tinfl_decompress_mem_to_heap(psrc_buf: *c_void,
src_buf_len: size_t,
pout_len: *mut size_t,
flags: c_int)
-> *c_void;
-> *mut c_void;
}
}
@ -47,49 +48,43 @@ static LZ_NORM : c_int = 0x80; // LZ with 128 probes, "normal"
static TINFL_FLAG_PARSE_ZLIB_HEADER : c_int = 0x1; // parse zlib header and adler32 checksum
static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum
fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> CVec<u8> {
unsafe {
let mut outsz : size_t = 0;
let res = rustrt::tdefl_compress_mem_to_heap(bytes.as_ptr() as *c_void,
bytes.len() as size_t,
&mut outsz,
flags);
assert!(res as int != 0);
let out = vec::raw::from_buf_raw(res as *u8,
outsz as uint);
libc::free(res as *mut c_void);
out
assert!(!res.is_null());
CVec::new_with_dtor(res as *mut u8, outsz as uint, proc() libc::free(res))
}
}
pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] {
pub fn deflate_bytes(bytes: &[u8]) -> CVec<u8> {
deflate_bytes_internal(bytes, LZ_NORM)
}
pub fn deflate_bytes_zlib(bytes: &[u8]) -> ~[u8] {
pub fn deflate_bytes_zlib(bytes: &[u8]) -> CVec<u8> {
deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER)
}
fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> CVec<u8> {
unsafe {
let mut outsz : size_t = 0;
let res = rustrt::tinfl_decompress_mem_to_heap(bytes.as_ptr() as *c_void,
bytes.len() as size_t,
&mut outsz,
flags);
assert!(res as int != 0);
let out = vec::raw::from_buf_raw(res as *u8,
outsz as uint);
libc::free(res as *mut c_void);
out
assert!(!res.is_null());
CVec::new_with_dtor(res as *mut u8, outsz as uint, proc() libc::free(res))
}
}
pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] {
pub fn inflate_bytes(bytes: &[u8]) -> CVec<u8> {
inflate_bytes_internal(bytes, 0)
}
pub fn inflate_bytes_zlib(bytes: &[u8]) -> ~[u8] {
pub fn inflate_bytes_zlib(bytes: &[u8]) -> CVec<u8> {
inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER)
}
@ -115,11 +110,11 @@ mod tests {
debug!("de/inflate of {} bytes of random word-sequences",
input.len());
let cmp = deflate_bytes(input);
let out = inflate_bytes(cmp);
let out = inflate_bytes(cmp.as_slice());
debug!("{} bytes deflated to {} ({:.1f}% size)",
input.len(), cmp.len(),
100.0 * ((cmp.len() as f64) / (input.len() as f64)));
assert_eq!(input, out);
assert_eq!(input.as_slice(), out.as_slice());
}
}
@ -127,7 +122,7 @@ mod tests {
fn test_zlib_flate() {
let bytes = ~[1, 2, 3, 4, 5];
let deflated = deflate_bytes(bytes);
let inflated = inflate_bytes(deflated);
assert_eq!(inflated, bytes);
let inflated = inflate_bytes(deflated.as_slice());
assert_eq!(inflated.as_slice(), bytes.as_slice());
}
}

View File

@ -944,7 +944,7 @@ fn link_rlib(sess: Session,
// into the archive.
let bc = obj_filename.with_extension("bc");
match fs::File::open(&bc).read_to_end().and_then(|data| {
fs::File::create(&bc).write(flate::deflate_bytes(data))
fs::File::create(&bc).write(flate::deflate_bytes(data).as_slice())
}) {
Ok(()) => {}
Err(e) => {

View File

@ -58,7 +58,7 @@ pub fn run(sess: session::Session, llmod: ModuleRef,
let bc = bc.expect("missing bytecode in archive!");
let bc = time(sess.time_passes(), format!("inflate {}.bc", name), (), |_|
flate::inflate_bytes(bc));
let ptr = bc.as_ptr();
let ptr = bc.as_slice().as_ptr();
debug!("linking {}", name);
time(sess.time_passes(), format!("ll link {}", name), (), |()| unsafe {
if !llvm::LLVMRustLinkInExternalBitcode(llmod,

View File

@ -18,6 +18,7 @@ use metadata::loader;
use std::cell::RefCell;
use collections::HashMap;
use extra::c_vec::CVec;
use syntax::ast;
use syntax::parse::token::IdentInterner;
@ -28,7 +29,7 @@ use syntax::parse::token::IdentInterner;
pub type cnum_map = @RefCell<HashMap<ast::CrateNum, ast::CrateNum>>;
pub enum MetadataBlob {
MetadataVec(~[u8]),
MetadataVec(CVec<u8>),
MetadataArchive(loader::ArchiveMetadata),
}

View File

@ -2569,7 +2569,7 @@ pub fn write_metadata(cx: &CrateContext, krate: &ast::Crate) -> ~[u8] {
let encode_parms = crate_ctxt_to_encode_parms(cx, encode_inlined_item);
let metadata = encoder::encode_metadata(encode_parms, krate);
let compressed = encoder::metadata_encoding_version +
flate::deflate_bytes(metadata);
flate::deflate_bytes(metadata).as_slice();
let llmeta = C_bytes(compressed);
let llconst = C_struct([llmeta], false);
let name = format!("rust_metadata_{}_{}_{}", cx.link_meta.crateid.name,