2014-04-02 20:06:55 -07:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 16:48:01 -08:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
2014-08-04 22:48:39 +12:00
|
|
|
|
2014-01-06 17:03:30 -08:00
|
|
|
//! The arena, a fast but limited type of allocator.
|
|
|
|
//!
|
|
|
|
//! Arenas are a type of allocator that destroy the objects within, all at
|
|
|
|
//! once, once the arena itself is destroyed. They do not support deallocation
|
|
|
|
//! of individual objects while the arena itself is still alive. The benefit
|
|
|
|
//! of an arena is very fast allocation; just a pointer bump.
|
2014-04-04 07:57:39 -04:00
|
|
|
//!
|
2014-08-04 22:48:39 +12:00
|
|
|
//! This crate has two arenas implemented: `TypedArena`, which is a simpler
|
|
|
|
//! arena but can only hold objects of a single type, and `Arena`, which is a
|
|
|
|
//! more complex, slower arena which can hold objects of any type.
|
2012-08-21 15:32:30 -07:00
|
|
|
|
2014-07-01 07:12:04 -07:00
|
|
|
#![crate_name = "arena"]
|
2014-06-17 22:13:36 -07:00
|
|
|
#![experimental]
|
2014-03-21 18:05:05 -07:00
|
|
|
#![crate_type = "rlib"]
|
|
|
|
#![crate_type = "dylib"]
|
|
|
|
#![license = "MIT/ASL2"]
|
|
|
|
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
|
|
|
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
2014-10-09 10:47:22 -07:00
|
|
|
html_root_url = "http://doc.rust-lang.org/nightly/")]
|
2014-06-17 16:00:04 -07:00
|
|
|
|
|
|
|
#![feature(unsafe_destructor)]
|
2014-03-21 18:05:05 -07:00
|
|
|
#![allow(missing_doc)]
|
2014-03-27 15:13:16 -07:00
|
|
|
|
2013-12-30 17:32:53 -08:00
|
|
|
use std::cell::{Cell, RefCell};
|
2014-02-06 02:34:33 -05:00
|
|
|
use std::cmp;
|
2014-05-05 18:56:44 -07:00
|
|
|
use std::intrinsics::{TyDesc, get_tydesc};
|
|
|
|
use std::intrinsics;
|
|
|
|
use std::mem;
|
Replaces the free-standing functions in f32, &c.
The free-standing functions in f32, f64, i8, i16, i32, i64, u8, u16,
u32, u64, float, int, and uint are replaced with generic functions in
num instead.
If you were previously using any of those functions, just replace them
with the corresponding function with the same name in num.
Note: If you were using a function that corresponds to an operator, use
the operator instead.
2013-07-08 18:05:17 +02:00
|
|
|
use std::num;
|
2014-05-29 17:40:18 -07:00
|
|
|
use std::ptr;
|
2014-02-01 15:53:11 +11:00
|
|
|
use std::rc::Rc;
|
2014-09-05 09:08:30 -04:00
|
|
|
use std::rt::heap::{allocate, deallocate};
|
2013-03-05 12:21:02 -08:00
|
|
|
|
2012-08-21 15:32:30 -07:00
|
|
|
// The way arena uses arrays is really deeply awful. The arrays are
|
|
|
|
// allocated, and have capacities reserved, but the fill for the array
|
|
|
|
// will always stay at 0.
|
2014-05-29 17:45:07 -07:00
|
|
|
#[deriving(Clone, PartialEq)]
|
2013-01-22 08:44:24 -08:00
|
|
|
struct Chunk {
|
2014-09-05 09:08:30 -04:00
|
|
|
data: Rc<RefCell<Vec<u8>>>,
|
2013-12-30 17:32:53 -08:00
|
|
|
fill: Cell<uint>,
|
2014-03-27 00:01:11 +01:00
|
|
|
is_copy: Cell<bool>,
|
2013-01-22 08:44:24 -08:00
|
|
|
}
|
2014-09-05 09:08:30 -04:00
|
|
|
|
2014-02-01 15:53:11 +11:00
|
|
|
impl Chunk {
|
|
|
|
fn capacity(&self) -> uint {
|
2014-03-20 15:05:56 -07:00
|
|
|
self.data.borrow().capacity()
|
2014-02-01 15:53:11 +11:00
|
|
|
}
|
|
|
|
|
2014-06-25 12:47:34 -07:00
|
|
|
unsafe fn as_ptr(&self) -> *const u8 {
|
2014-03-20 15:05:56 -07:00
|
|
|
self.data.borrow().as_ptr()
|
2014-02-01 15:53:11 +11:00
|
|
|
}
|
|
|
|
}
|
2012-07-11 15:00:40 -07:00
|
|
|
|
2014-04-04 07:57:39 -04:00
|
|
|
/// A slower reflection-based arena that can allocate objects of any type.
|
|
|
|
///
|
2014-08-04 22:48:39 +12:00
|
|
|
/// This arena uses `Vec<u8>` as a backing store to allocate objects from. For
|
2014-04-04 07:57:39 -04:00
|
|
|
/// each allocated object, the arena stores a pointer to the type descriptor
|
2014-08-04 22:48:39 +12:00
|
|
|
/// followed by the object (potentially with alignment padding after each
|
|
|
|
/// element). When the arena is destroyed, it iterates through all of its
|
2014-04-04 07:57:39 -04:00
|
|
|
/// chunks, and uses the tydesc information to trace through the objects,
|
2014-08-04 22:48:39 +12:00
|
|
|
/// calling the destructors on them. One subtle point that needs to be
|
2014-04-04 07:57:39 -04:00
|
|
|
/// addressed is how to handle failures while running the user provided
|
|
|
|
/// initializer function. It is important to not run the destructor on
|
|
|
|
/// uninitialized objects, but how to detect them is somewhat subtle. Since
|
2014-08-04 22:48:39 +12:00
|
|
|
/// `alloc()` can be invoked recursively, it is not sufficient to simply exclude
|
2014-04-04 07:57:39 -04:00
|
|
|
/// the most recent object. To solve this without requiring extra space, we
|
|
|
|
/// use the low order bit of the tydesc pointer to encode whether the object
|
|
|
|
/// it describes has been fully initialized.
|
|
|
|
///
|
2014-08-04 22:48:39 +12:00
|
|
|
/// As an optimization, objects with destructors are stored in different chunks
|
|
|
|
/// than objects without destructors. This reduces overhead when initializing
|
|
|
|
/// plain-old-data (`Copy` types) and means we don't need to waste time running
|
|
|
|
/// their destructors.
|
2012-09-28 16:24:57 -07:00
|
|
|
pub struct Arena {
|
2013-05-03 15:57:18 -07:00
|
|
|
// The head is separated out from the list as a unbenchmarked
|
2014-04-04 07:57:39 -04:00
|
|
|
// microoptimization, to avoid needing to case on the list to access the
|
|
|
|
// head.
|
2014-06-10 00:29:36 -03:00
|
|
|
head: RefCell<Chunk>,
|
|
|
|
copy_head: RefCell<Chunk>,
|
2014-03-27 15:13:16 -07:00
|
|
|
chunks: RefCell<Vec<Chunk>>,
|
2012-11-13 21:38:18 -05:00
|
|
|
}
|
|
|
|
|
2013-08-05 17:43:40 +09:00
|
|
|
impl Arena {
|
2014-08-04 22:48:39 +12:00
|
|
|
/// Allocates a new Arena with 32 bytes preallocated.
|
2013-08-05 17:43:40 +09:00
|
|
|
pub fn new() -> Arena {
|
|
|
|
Arena::new_with_size(32u)
|
|
|
|
}
|
|
|
|
|
2014-08-04 22:48:39 +12:00
|
|
|
/// Allocates a new Arena with `initial_size` bytes preallocated.
|
2013-08-05 17:43:40 +09:00
|
|
|
pub fn new_with_size(initial_size: uint) -> Arena {
|
|
|
|
Arena {
|
2014-06-10 00:29:36 -03:00
|
|
|
head: RefCell::new(chunk(initial_size, false)),
|
|
|
|
copy_head: RefCell::new(chunk(initial_size, true)),
|
2014-03-18 21:31:40 -07:00
|
|
|
chunks: RefCell::new(Vec::new()),
|
2012-08-21 15:32:30 -07:00
|
|
|
}
|
|
|
|
}
|
2012-07-11 15:00:40 -07:00
|
|
|
}
|
2012-03-20 19:06:04 -07:00
|
|
|
|
2014-03-27 00:01:11 +01:00
|
|
|
fn chunk(size: uint, is_copy: bool) -> Chunk {
|
2013-01-22 08:44:24 -08:00
|
|
|
Chunk {
|
2014-03-05 15:28:08 -08:00
|
|
|
data: Rc::new(RefCell::new(Vec::with_capacity(size))),
|
2013-12-30 17:32:53 -08:00
|
|
|
fill: Cell::new(0u),
|
2014-03-27 00:01:11 +01:00
|
|
|
is_copy: Cell::new(is_copy),
|
2013-01-22 08:44:24 -08:00
|
|
|
}
|
2012-03-20 19:06:04 -07:00
|
|
|
}
|
|
|
|
|
2013-08-05 17:43:40 +09:00
|
|
|
#[unsafe_destructor]
|
|
|
|
impl Drop for Arena {
|
2013-09-16 21:18:07 -04:00
|
|
|
fn drop(&mut self) {
|
2013-08-05 17:43:40 +09:00
|
|
|
unsafe {
|
2014-06-10 00:29:36 -03:00
|
|
|
destroy_chunk(&*self.head.borrow());
|
2014-03-18 21:31:40 -07:00
|
|
|
for chunk in self.chunks.borrow().iter() {
|
2014-03-27 00:01:11 +01:00
|
|
|
if !chunk.is_copy.get() {
|
2013-08-05 17:43:40 +09:00
|
|
|
destroy_chunk(chunk);
|
|
|
|
}
|
2014-02-24 22:18:19 -04:00
|
|
|
}
|
2013-08-05 17:43:40 +09:00
|
|
|
}
|
2013-01-22 08:44:24 -08:00
|
|
|
}
|
2012-03-20 19:06:04 -07:00
|
|
|
}
|
|
|
|
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2014-01-06 17:03:30 -08:00
|
|
|
fn round_up(base: uint, align: uint) -> uint {
|
|
|
|
(base.checked_add(&(align - 1))).unwrap() & !(&(align - 1))
|
2012-08-21 15:32:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Walk down a chunk, running the destructors for any objects stored
|
|
|
|
// in it.
|
2012-09-19 18:14:30 -07:00
|
|
|
unsafe fn destroy_chunk(chunk: &Chunk) {
|
2012-08-21 15:32:30 -07:00
|
|
|
let mut idx = 0;
|
2014-02-01 15:53:11 +11:00
|
|
|
let buf = chunk.as_ptr();
|
2013-12-30 17:32:53 -08:00
|
|
|
let fill = chunk.fill.get();
|
2012-08-21 15:32:30 -07:00
|
|
|
|
|
|
|
while idx < fill {
|
2014-06-25 12:47:34 -07:00
|
|
|
let tydesc_data: *const uint = mem::transmute(buf.offset(idx as int));
|
2012-08-21 15:32:30 -07:00
|
|
|
let (tydesc, is_done) = un_bitpack_tydesc_ptr(*tydesc_data);
|
2013-06-04 21:43:41 -07:00
|
|
|
let (size, align) = ((*tydesc).size, (*tydesc).align);
|
2012-08-21 15:32:30 -07:00
|
|
|
|
2014-06-25 12:47:34 -07:00
|
|
|
let after_tydesc = idx + mem::size_of::<*const TyDesc>();
|
2012-08-21 15:32:30 -07:00
|
|
|
|
2014-01-06 17:03:30 -08:00
|
|
|
let start = round_up(after_tydesc, align);
|
2012-08-21 15:32:30 -07:00
|
|
|
|
2013-10-21 13:08:31 -07:00
|
|
|
//debug!("freeing object: idx = {}, size = {}, align = {}, done = {}",
|
2012-08-21 15:32:30 -07:00
|
|
|
// start, size, align, is_done);
|
|
|
|
if is_done {
|
2014-06-25 12:47:34 -07:00
|
|
|
((*tydesc).drop_glue)(buf.offset(start as int) as *const i8);
|
2012-08-21 15:32:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Find where the next tydesc lives
|
2014-06-25 12:47:34 -07:00
|
|
|
idx = round_up(start + size, mem::align_of::<*const TyDesc>());
|
2012-08-21 15:32:30 -07:00
|
|
|
}
|
2012-08-02 16:00:45 -07:00
|
|
|
}
|
|
|
|
|
2012-08-21 15:32:30 -07:00
|
|
|
// We encode whether the object a tydesc describes has been
|
|
|
|
// initialized in the arena in the low bit of the tydesc pointer. This
|
|
|
|
// is necessary in order to properly do cleanup if a failure occurs
|
|
|
|
// during an initializer.
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2014-06-25 12:47:34 -07:00
|
|
|
fn bitpack_tydesc_ptr(p: *const TyDesc, is_done: bool) -> uint {
|
2014-02-21 23:56:09 +11:00
|
|
|
p as uint | (is_done as uint)
|
2012-08-21 15:32:30 -07:00
|
|
|
}
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2014-06-25 12:47:34 -07:00
|
|
|
fn un_bitpack_tydesc_ptr(p: uint) -> (*const TyDesc, bool) {
|
|
|
|
((p & !1) as *const TyDesc, p & 1 == 1)
|
2012-08-21 15:32:30 -07:00
|
|
|
}
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
impl Arena {
|
2014-02-01 15:53:11 +11:00
|
|
|
fn chunk_size(&self) -> uint {
|
2014-06-10 00:29:36 -03:00
|
|
|
self.copy_head.borrow().capacity()
|
2014-02-01 15:53:11 +11:00
|
|
|
}
|
2014-06-10 00:29:36 -03:00
|
|
|
|
2012-10-05 14:58:42 -07:00
|
|
|
// Functions for the POD part of the arena
|
2014-06-25 12:47:34 -07:00
|
|
|
fn alloc_copy_grow(&self, n_bytes: uint, align: uint) -> *const u8 {
|
2012-10-05 14:58:42 -07:00
|
|
|
// Allocate a new chunk.
|
2014-02-06 02:34:33 -05:00
|
|
|
let new_min_chunk_size = cmp::max(n_bytes, self.chunk_size());
|
2014-06-10 00:29:36 -03:00
|
|
|
self.chunks.borrow_mut().push(self.copy_head.borrow().clone());
|
|
|
|
|
|
|
|
*self.copy_head.borrow_mut() =
|
2014-01-30 16:35:17 +11:00
|
|
|
chunk(num::next_power_of_two(new_min_chunk_size + 1u), true);
|
2012-10-05 14:58:42 -07:00
|
|
|
|
2014-03-27 00:01:11 +01:00
|
|
|
return self.alloc_copy_inner(n_bytes, align);
|
2012-10-05 14:58:42 -07:00
|
|
|
}
|
|
|
|
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2014-06-25 12:47:34 -07:00
|
|
|
fn alloc_copy_inner(&self, n_bytes: uint, align: uint) -> *const u8 {
|
2014-06-10 00:29:36 -03:00
|
|
|
let start = round_up(self.copy_head.borrow().fill.get(), align);
|
|
|
|
|
|
|
|
let end = start + n_bytes;
|
|
|
|
if end > self.chunk_size() {
|
|
|
|
return self.alloc_copy_grow(n_bytes, align);
|
|
|
|
}
|
2012-10-05 14:58:42 -07:00
|
|
|
|
2014-06-10 00:29:36 -03:00
|
|
|
let copy_head = self.copy_head.borrow();
|
|
|
|
copy_head.fill.set(end);
|
2012-10-05 14:58:42 -07:00
|
|
|
|
2014-06-10 00:29:36 -03:00
|
|
|
unsafe {
|
|
|
|
copy_head.as_ptr().offset(start as int)
|
2012-10-05 14:58:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2014-07-31 07:56:39 +09:00
|
|
|
fn alloc_copy<T>(&self, op: || -> T) -> &T {
|
2012-10-05 14:58:42 -07:00
|
|
|
unsafe {
|
2014-05-17 00:56:00 -07:00
|
|
|
let ptr = self.alloc_copy_inner(mem::size_of::<T>(),
|
|
|
|
mem::min_align_of::<T>());
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 10:34:51 -07:00
|
|
|
let ptr = ptr as *mut T;
|
2014-05-29 17:40:18 -07:00
|
|
|
ptr::write(&mut (*ptr), op());
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 10:34:51 -07:00
|
|
|
return &*ptr;
|
2012-10-05 14:58:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Functions for the non-POD part of the arena
|
2014-06-25 12:47:34 -07:00
|
|
|
fn alloc_noncopy_grow(&self, n_bytes: uint,
|
|
|
|
align: uint) -> (*const u8, *const u8) {
|
2012-10-05 14:58:42 -07:00
|
|
|
// Allocate a new chunk.
|
2014-02-06 02:34:33 -05:00
|
|
|
let new_min_chunk_size = cmp::max(n_bytes, self.chunk_size());
|
2014-06-10 00:29:36 -03:00
|
|
|
self.chunks.borrow_mut().push(self.head.borrow().clone());
|
|
|
|
|
|
|
|
*self.head.borrow_mut() =
|
2014-01-30 16:35:17 +11:00
|
|
|
chunk(num::next_power_of_two(new_min_chunk_size + 1u), false);
|
2012-10-05 14:58:42 -07:00
|
|
|
|
2014-03-27 00:01:11 +01:00
|
|
|
return self.alloc_noncopy_inner(n_bytes, align);
|
2012-10-05 14:58:42 -07:00
|
|
|
}
|
|
|
|
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2014-06-25 12:47:34 -07:00
|
|
|
fn alloc_noncopy_inner(&self, n_bytes: uint,
|
|
|
|
align: uint) -> (*const u8, *const u8) {
|
2014-06-10 00:29:36 -03:00
|
|
|
// Be careful to not maintain any `head` borrows active, because
|
|
|
|
// `alloc_noncopy_grow` borrows it mutably.
|
|
|
|
let (start, end, tydesc_start, head_capacity) = {
|
|
|
|
let head = self.head.borrow();
|
|
|
|
let fill = head.fill.get();
|
|
|
|
|
|
|
|
let tydesc_start = fill;
|
2014-06-25 12:47:34 -07:00
|
|
|
let after_tydesc = fill + mem::size_of::<*const TyDesc>();
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 10:34:51 -07:00
|
|
|
let start = round_up(after_tydesc, align);
|
|
|
|
let end = start + n_bytes;
|
2013-04-29 15:23:04 -07:00
|
|
|
|
2014-06-10 00:29:36 -03:00
|
|
|
(start, end, tydesc_start, head.capacity())
|
|
|
|
};
|
2013-06-25 19:19:38 -07:00
|
|
|
|
2014-06-10 00:29:36 -03:00
|
|
|
if end > head_capacity {
|
|
|
|
return self.alloc_noncopy_grow(n_bytes, align);
|
|
|
|
}
|
2012-10-05 14:58:42 -07:00
|
|
|
|
2014-06-10 00:29:36 -03:00
|
|
|
let head = self.head.borrow();
|
2014-06-25 12:47:34 -07:00
|
|
|
head.fill.set(round_up(end, mem::align_of::<*const TyDesc>()));
|
2012-10-05 14:58:42 -07:00
|
|
|
|
2014-06-10 00:29:36 -03:00
|
|
|
unsafe {
|
|
|
|
let buf = head.as_ptr();
|
2014-02-10 16:50:42 -05:00
|
|
|
return (buf.offset(tydesc_start as int), buf.offset(start as int));
|
2012-10-05 14:58:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2014-07-31 07:56:39 +09:00
|
|
|
fn alloc_noncopy<T>(&self, op: || -> T) -> &T {
|
2012-10-05 14:58:42 -07:00
|
|
|
unsafe {
|
2013-06-20 11:39:49 +02:00
|
|
|
let tydesc = get_tydesc::<T>();
|
2012-10-05 14:58:42 -07:00
|
|
|
let (ty_ptr, ptr) =
|
2014-05-17 00:56:00 -07:00
|
|
|
self.alloc_noncopy_inner(mem::size_of::<T>(),
|
|
|
|
mem::min_align_of::<T>());
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 10:34:51 -07:00
|
|
|
let ty_ptr = ty_ptr as *mut uint;
|
|
|
|
let ptr = ptr as *mut T;
|
2012-10-05 14:58:42 -07:00
|
|
|
// Write in our tydesc along with a bit indicating that it
|
|
|
|
// has *not* been initialized yet.
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 10:34:51 -07:00
|
|
|
*ty_ptr = mem::transmute(tydesc);
|
2012-10-05 14:58:42 -07:00
|
|
|
// Actually initialize it
|
2014-05-29 17:40:18 -07:00
|
|
|
ptr::write(&mut(*ptr), op());
|
2012-10-05 14:58:42 -07:00
|
|
|
// Now that we are done, update the tydesc to indicate that
|
|
|
|
// the object is there.
|
|
|
|
*ty_ptr = bitpack_tydesc_ptr(tydesc, true);
|
|
|
|
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 10:34:51 -07:00
|
|
|
return &*ptr;
|
2012-10-05 14:58:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-04 22:48:39 +12:00
|
|
|
/// Allocates a new item in the arena, using `op` to initialize the value,
|
|
|
|
/// and returns a reference to it.
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2014-07-31 07:56:39 +09:00
|
|
|
pub fn alloc<T>(&self, op: || -> T) -> &T {
|
2013-04-10 13:14:06 -07:00
|
|
|
unsafe {
|
2013-06-16 17:50:16 +02:00
|
|
|
if intrinsics::needs_drop::<T>() {
|
2014-06-10 00:29:36 -03:00
|
|
|
self.alloc_noncopy(op)
|
2013-06-16 17:50:16 +02:00
|
|
|
} else {
|
2014-06-10 00:29:36 -03:00
|
|
|
self.alloc_copy(op)
|
2013-04-10 13:14:06 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-10-05 14:58:42 -07:00
|
|
|
}
|
2012-03-20 19:06:04 -07:00
|
|
|
|
2012-08-21 15:32:30 -07:00
|
|
|
#[test]
|
|
|
|
fn test_arena_destructors() {
|
2013-08-05 17:43:40 +09:00
|
|
|
let arena = Arena::new();
|
2013-08-03 12:45:23 -04:00
|
|
|
for i in range(0u, 10) {
|
2012-08-21 15:32:30 -07:00
|
|
|
// Arena allocate something with drop glue to make sure it
|
|
|
|
// doesn't leak.
|
2014-04-02 20:06:55 -07:00
|
|
|
arena.alloc(|| Rc::new(i));
|
2012-08-21 15:32:30 -07:00
|
|
|
// Allocate something with funny size and alignment, to keep
|
|
|
|
// things interesting.
|
2013-11-20 15:46:49 -08:00
|
|
|
arena.alloc(|| [0u8, 1u8, 2u8]);
|
2012-08-21 15:32:30 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-09 23:54:52 -03:00
|
|
|
#[test]
|
|
|
|
fn test_arena_alloc_nested() {
|
|
|
|
struct Inner { value: uint }
|
|
|
|
struct Outer<'a> { inner: &'a Inner }
|
|
|
|
|
|
|
|
let arena = Arena::new();
|
|
|
|
|
|
|
|
let result = arena.alloc(|| Outer {
|
|
|
|
inner: arena.alloc(|| Inner { value: 10 })
|
|
|
|
});
|
|
|
|
|
|
|
|
assert_eq!(result.inner.value, 10);
|
|
|
|
}
|
|
|
|
|
2013-04-29 15:23:04 -07:00
|
|
|
#[test]
|
|
|
|
#[should_fail]
|
2012-08-21 15:32:30 -07:00
|
|
|
fn test_arena_destructors_fail() {
|
2013-08-05 17:43:40 +09:00
|
|
|
let arena = Arena::new();
|
2012-08-21 15:32:30 -07:00
|
|
|
// Put some stuff in the arena.
|
2013-08-03 12:45:23 -04:00
|
|
|
for i in range(0u, 10) {
|
2012-08-21 15:32:30 -07:00
|
|
|
// Arena allocate something with drop glue to make sure it
|
|
|
|
// doesn't leak.
|
2014-04-02 20:06:55 -07:00
|
|
|
arena.alloc(|| { Rc::new(i) });
|
2012-08-21 15:32:30 -07:00
|
|
|
// Allocate something with funny size and alignment, to keep
|
|
|
|
// things interesting.
|
2013-11-21 19:20:48 -08:00
|
|
|
arena.alloc(|| { [0u8, 1u8, 2u8] });
|
2012-08-21 15:32:30 -07:00
|
|
|
}
|
|
|
|
// Now, fail while allocating
|
2014-04-02 20:06:55 -07:00
|
|
|
arena.alloc::<Rc<int>>(|| {
|
2012-08-21 15:32:30 -07:00
|
|
|
// Now fail.
|
2013-10-21 13:08:31 -07:00
|
|
|
fail!();
|
2013-11-21 19:20:48 -08:00
|
|
|
});
|
2012-08-21 15:32:30 -07:00
|
|
|
}
|
2014-01-06 17:03:30 -08:00
|
|
|
|
2014-04-04 07:57:39 -04:00
|
|
|
/// A faster arena that can hold objects of only one type.
|
2014-01-06 17:03:30 -08:00
|
|
|
///
|
|
|
|
/// Safety note: Modifying objects in the arena that have already had their
|
|
|
|
/// `drop` destructors run can cause leaks, because the destructor will not
|
|
|
|
/// run again for these objects.
|
|
|
|
pub struct TypedArena<T> {
|
|
|
|
/// A pointer to the next object to be allocated.
|
2014-06-25 12:47:34 -07:00
|
|
|
ptr: Cell<*const T>,
|
2014-01-06 17:03:30 -08:00
|
|
|
|
|
|
|
/// A pointer to the end of the allocated area. When this pointer is
|
|
|
|
/// reached, a new chunk is allocated.
|
2014-06-25 12:47:34 -07:00
|
|
|
end: Cell<*const T>,
|
2014-01-06 17:03:30 -08:00
|
|
|
|
|
|
|
/// A pointer to the first arena segment.
|
2014-09-05 09:08:30 -04:00
|
|
|
first: RefCell<*mut TypedArenaChunk<T>>,
|
2014-01-06 17:03:30 -08:00
|
|
|
}
|
|
|
|
|
2014-02-21 07:25:17 -05:00
|
|
|
struct TypedArenaChunk<T> {
|
2014-01-06 17:03:30 -08:00
|
|
|
/// Pointer to the next arena segment.
|
2014-09-05 09:08:30 -04:00
|
|
|
next: *mut TypedArenaChunk<T>,
|
2014-01-06 17:03:30 -08:00
|
|
|
|
|
|
|
/// The number of elements that this chunk can hold.
|
|
|
|
capacity: uint,
|
|
|
|
|
|
|
|
// Objects follow here, suitably aligned.
|
|
|
|
}
|
|
|
|
|
2014-09-05 09:08:30 -04:00
|
|
|
fn calculate_size<T>(capacity: uint) -> uint {
|
|
|
|
let mut size = mem::size_of::<TypedArenaChunk<T>>();
|
|
|
|
size = round_up(size, mem::min_align_of::<T>());
|
|
|
|
let elem_size = mem::size_of::<T>();
|
|
|
|
let elems_size = elem_size.checked_mul(&capacity).unwrap();
|
|
|
|
size = size.checked_add(&elems_size).unwrap();
|
|
|
|
size
|
|
|
|
}
|
|
|
|
|
2014-02-21 07:25:17 -05:00
|
|
|
impl<T> TypedArenaChunk<T> {
|
2014-01-06 17:03:30 -08:00
|
|
|
#[inline]
|
2014-09-05 09:08:30 -04:00
|
|
|
unsafe fn new(next: *mut TypedArenaChunk<T>, capacity: uint)
|
|
|
|
-> *mut TypedArenaChunk<T> {
|
|
|
|
let size = calculate_size::<T>(capacity);
|
|
|
|
let chunk = allocate(size, mem::min_align_of::<TypedArenaChunk<T>>())
|
|
|
|
as *mut TypedArenaChunk<T>;
|
|
|
|
(*chunk).next = next;
|
|
|
|
(*chunk).capacity = capacity;
|
2014-04-25 21:24:51 -04:00
|
|
|
chunk
|
|
|
|
}
|
|
|
|
|
2014-01-06 17:03:30 -08:00
|
|
|
/// Destroys this arena chunk. If the type descriptor is supplied, the
|
|
|
|
/// drop glue is called; otherwise, drop glue is not called.
|
|
|
|
#[inline]
|
2014-02-21 07:25:17 -05:00
|
|
|
unsafe fn destroy(&mut self, len: uint) {
|
2014-01-06 17:03:30 -08:00
|
|
|
// Destroy all the allocated objects.
|
2014-02-21 07:25:17 -05:00
|
|
|
if intrinsics::needs_drop::<T>() {
|
|
|
|
let mut start = self.start();
|
|
|
|
for _ in range(0, len) {
|
2014-06-25 12:47:34 -07:00
|
|
|
ptr::read(start as *const T); // run the destructor on the pointer
|
2014-02-21 07:25:17 -05:00
|
|
|
start = start.offset(mem::size_of::<T>() as int)
|
2014-01-06 17:03:30 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Destroy the next chunk.
|
2014-09-05 09:08:30 -04:00
|
|
|
let next = self.next;
|
|
|
|
let size = calculate_size::<T>(self.capacity);
|
|
|
|
deallocate(self as *mut TypedArenaChunk<T> as *mut u8, size,
|
|
|
|
mem::min_align_of::<TypedArenaChunk<T>>());
|
|
|
|
if next.is_not_null() {
|
|
|
|
let capacity = (*next).capacity;
|
|
|
|
(*next).destroy(capacity);
|
2014-01-06 17:03:30 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a pointer to the first allocated object.
|
|
|
|
#[inline]
|
2014-06-25 12:47:34 -07:00
|
|
|
fn start(&self) -> *const u8 {
|
|
|
|
let this: *const TypedArenaChunk<T> = self;
|
2014-01-06 17:03:30 -08:00
|
|
|
unsafe {
|
2014-05-17 00:56:00 -07:00
|
|
|
mem::transmute(round_up(this.offset(1) as uint,
|
|
|
|
mem::min_align_of::<T>()))
|
2014-01-06 17:03:30 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a pointer to the end of the allocated space.
|
|
|
|
#[inline]
|
2014-06-25 12:47:34 -07:00
|
|
|
fn end(&self) -> *const u8 {
|
2014-01-06 17:03:30 -08:00
|
|
|
unsafe {
|
2014-02-21 07:25:17 -05:00
|
|
|
let size = mem::size_of::<T>().checked_mul(&self.capacity).unwrap();
|
|
|
|
self.start().offset(size as int)
|
2014-01-06 17:03:30 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> TypedArena<T> {
|
2014-08-04 22:48:39 +12:00
|
|
|
/// Creates a new `TypedArena` with preallocated space for eight objects.
|
2014-01-06 17:03:30 -08:00
|
|
|
#[inline]
|
|
|
|
pub fn new() -> TypedArena<T> {
|
|
|
|
TypedArena::with_capacity(8)
|
|
|
|
}
|
|
|
|
|
2014-08-04 22:48:39 +12:00
|
|
|
/// Creates a new `TypedArena` with preallocated space for the given number of
|
2014-01-06 17:03:30 -08:00
|
|
|
/// objects.
|
|
|
|
#[inline]
|
|
|
|
pub fn with_capacity(capacity: uint) -> TypedArena<T> {
|
2014-09-05 09:08:30 -04:00
|
|
|
unsafe {
|
2014-09-14 20:27:36 -07:00
|
|
|
let chunk = TypedArenaChunk::<T>::new(ptr::null_mut(), capacity);
|
2014-09-05 09:08:30 -04:00
|
|
|
TypedArena {
|
|
|
|
ptr: Cell::new((*chunk).start() as *const T),
|
|
|
|
end: Cell::new((*chunk).end() as *const T),
|
|
|
|
first: RefCell::new(chunk),
|
|
|
|
}
|
2014-01-06 17:03:30 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-04 22:48:39 +12:00
|
|
|
/// Allocates an object in the `TypedArena`, returning a reference to it.
|
2014-01-06 17:03:30 -08:00
|
|
|
#[inline]
|
2014-07-31 07:56:39 +09:00
|
|
|
pub fn alloc(&self, object: T) -> &T {
|
2014-06-10 00:41:44 -03:00
|
|
|
if self.ptr == self.end {
|
|
|
|
self.grow()
|
|
|
|
}
|
2014-01-06 17:03:30 -08:00
|
|
|
|
2014-07-31 07:56:39 +09:00
|
|
|
let ptr: &T = unsafe {
|
|
|
|
let ptr: &mut T = mem::transmute(self.ptr);
|
2014-05-29 17:40:18 -07:00
|
|
|
ptr::write(ptr, object);
|
2014-06-10 00:41:44 -03:00
|
|
|
self.ptr.set(self.ptr.get().offset(1));
|
2014-01-06 17:03:30 -08:00
|
|
|
ptr
|
2014-06-10 00:41:44 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
ptr
|
2014-01-06 17:03:30 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Grows the arena.
|
|
|
|
#[inline(never)]
|
2014-06-10 00:41:44 -03:00
|
|
|
fn grow(&self) {
|
2014-09-05 09:08:30 -04:00
|
|
|
unsafe {
|
|
|
|
let chunk = *self.first.borrow_mut();
|
|
|
|
let new_capacity = (*chunk).capacity.checked_mul(&2).unwrap();
|
|
|
|
let chunk = TypedArenaChunk::<T>::new(chunk, new_capacity);
|
|
|
|
self.ptr.set((*chunk).start() as *const T);
|
|
|
|
self.end.set((*chunk).end() as *const T);
|
|
|
|
*self.first.borrow_mut() = chunk
|
|
|
|
}
|
2014-01-06 17:03:30 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[unsafe_destructor]
|
|
|
|
impl<T> Drop for TypedArena<T> {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
2014-09-05 09:08:30 -04:00
|
|
|
// Determine how much was filled.
|
|
|
|
let start = self.first.borrow().as_ref().unwrap().start() as uint;
|
|
|
|
let end = self.ptr.get() as uint;
|
|
|
|
let diff = (end - start) / mem::size_of::<T>();
|
|
|
|
|
|
|
|
// Pass that to the `destroy` method.
|
|
|
|
(**self.first.borrow_mut()).destroy(diff)
|
2014-01-06 17:03:30 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
2014-02-14 09:49:11 +08:00
|
|
|
mod tests {
|
|
|
|
extern crate test;
|
2014-04-01 09:16:35 +08:00
|
|
|
use self::test::Bencher;
|
2014-01-06 17:03:30 -08:00
|
|
|
use super::{Arena, TypedArena};
|
|
|
|
|
2014-09-09 11:32:58 +02:00
|
|
|
#[allow(dead_code)]
|
2014-01-06 17:03:30 -08:00
|
|
|
struct Point {
|
|
|
|
x: int,
|
|
|
|
y: int,
|
|
|
|
z: int,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2014-03-27 00:01:11 +01:00
|
|
|
pub fn test_copy() {
|
2014-01-06 17:03:30 -08:00
|
|
|
let arena = TypedArena::new();
|
2014-04-21 17:58:52 -04:00
|
|
|
for _ in range(0u, 100000) {
|
2014-01-06 17:03:30 -08:00
|
|
|
arena.alloc(Point {
|
|
|
|
x: 1,
|
|
|
|
y: 2,
|
|
|
|
z: 3,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[bench]
|
2014-04-01 09:16:35 +08:00
|
|
|
pub fn bench_copy(b: &mut Bencher) {
|
2014-01-06 17:03:30 -08:00
|
|
|
let arena = TypedArena::new();
|
2014-04-01 09:16:35 +08:00
|
|
|
b.iter(|| {
|
2014-01-06 17:03:30 -08:00
|
|
|
arena.alloc(Point {
|
|
|
|
x: 1,
|
|
|
|
y: 2,
|
|
|
|
z: 3,
|
2014-02-08 21:32:09 +11:00
|
|
|
})
|
2014-01-06 17:03:30 -08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[bench]
|
2014-04-01 09:16:35 +08:00
|
|
|
pub fn bench_copy_nonarena(b: &mut Bencher) {
|
|
|
|
b.iter(|| {
|
2014-04-25 01:08:02 -07:00
|
|
|
box Point {
|
2014-01-06 17:03:30 -08:00
|
|
|
x: 1,
|
|
|
|
y: 2,
|
|
|
|
z: 3,
|
2014-02-08 21:32:09 +11:00
|
|
|
}
|
2014-01-06 17:03:30 -08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[bench]
|
2014-04-01 09:16:35 +08:00
|
|
|
pub fn bench_copy_old_arena(b: &mut Bencher) {
|
2014-01-06 17:03:30 -08:00
|
|
|
let arena = Arena::new();
|
2014-04-01 09:16:35 +08:00
|
|
|
b.iter(|| {
|
2014-01-06 17:03:30 -08:00
|
|
|
arena.alloc(|| {
|
|
|
|
Point {
|
|
|
|
x: 1,
|
|
|
|
y: 2,
|
|
|
|
z: 3,
|
|
|
|
}
|
2014-02-08 21:32:09 +11:00
|
|
|
})
|
2014-01-06 17:03:30 -08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2014-09-09 11:32:58 +02:00
|
|
|
#[allow(dead_code)]
|
2014-03-27 00:01:11 +01:00
|
|
|
struct Noncopy {
|
2014-05-22 16:57:53 -07:00
|
|
|
string: String,
|
2014-08-20 23:41:02 -04:00
|
|
|
array: Vec<int>,
|
2014-01-06 17:03:30 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2014-03-27 00:01:11 +01:00
|
|
|
pub fn test_noncopy() {
|
2014-01-06 17:03:30 -08:00
|
|
|
let arena = TypedArena::new();
|
2014-04-21 17:58:52 -04:00
|
|
|
for _ in range(0u, 100000) {
|
2014-03-27 00:01:11 +01:00
|
|
|
arena.alloc(Noncopy {
|
2014-05-25 03:17:19 -07:00
|
|
|
string: "hello world".to_string(),
|
2014-03-05 15:28:08 -08:00
|
|
|
array: vec!( 1, 2, 3, 4, 5 ),
|
2014-01-06 17:03:30 -08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[bench]
|
2014-04-01 09:16:35 +08:00
|
|
|
pub fn bench_noncopy(b: &mut Bencher) {
|
2014-01-06 17:03:30 -08:00
|
|
|
let arena = TypedArena::new();
|
2014-04-01 09:16:35 +08:00
|
|
|
b.iter(|| {
|
2014-03-27 00:01:11 +01:00
|
|
|
arena.alloc(Noncopy {
|
2014-05-25 03:17:19 -07:00
|
|
|
string: "hello world".to_string(),
|
2014-03-05 15:28:08 -08:00
|
|
|
array: vec!( 1, 2, 3, 4, 5 ),
|
2014-02-08 21:32:09 +11:00
|
|
|
})
|
2014-01-06 17:03:30 -08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[bench]
|
2014-04-01 09:16:35 +08:00
|
|
|
pub fn bench_noncopy_nonarena(b: &mut Bencher) {
|
|
|
|
b.iter(|| {
|
2014-04-25 01:08:02 -07:00
|
|
|
box Noncopy {
|
2014-05-25 03:17:19 -07:00
|
|
|
string: "hello world".to_string(),
|
2014-03-05 15:28:08 -08:00
|
|
|
array: vec!( 1, 2, 3, 4, 5 ),
|
2014-02-08 21:32:09 +11:00
|
|
|
}
|
2014-01-06 17:03:30 -08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[bench]
|
2014-04-01 09:16:35 +08:00
|
|
|
pub fn bench_noncopy_old_arena(b: &mut Bencher) {
|
2014-01-06 17:03:30 -08:00
|
|
|
let arena = Arena::new();
|
2014-04-01 09:16:35 +08:00
|
|
|
b.iter(|| {
|
2014-03-27 00:01:11 +01:00
|
|
|
arena.alloc(|| Noncopy {
|
2014-05-25 03:17:19 -07:00
|
|
|
string: "hello world".to_string(),
|
2014-03-05 15:28:08 -08:00
|
|
|
array: vec!( 1, 2, 3, 4, 5 ),
|
2014-02-08 21:32:09 +11:00
|
|
|
})
|
2014-01-06 17:03:30 -08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|