-
Notifications
You must be signed in to change notification settings - Fork 13.3k
User-defined placement-box #18233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
User-defined placement-box #18233
Changes from all commits
93e590a
53865bc
040cf98
452ecab
731e9ba
b293984
3b47ea4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,13 +10,17 @@ | |
|
||
//! A unique pointer type. | ||
|
||
use heap; | ||
|
||
use core::any::{Any, AnyRefExt}; | ||
use core::clone::Clone; | ||
use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering}; | ||
use core::default::Default; | ||
use core::fmt; | ||
use core::intrinsics; | ||
use core::kinds::Sized; | ||
use core::mem; | ||
use core::ops::{Drop, Placer, PlacementAgent}; | ||
use core::option::Option; | ||
use core::raw::TraitObject; | ||
use core::result::{Ok, Err, Result}; | ||
|
@@ -36,22 +40,91 @@ use core::result::{Ok, Err, Result}; | |
/// ``` | ||
#[lang = "exchange_heap"] | ||
#[experimental = "may be renamed; uncertain about custom allocator design"] | ||
pub static HEAP: () = (); | ||
pub const HEAP: ExchangeHeapSingleton = | ||
ExchangeHeapSingleton { _force_singleton: () }; | ||
|
||
/// This the singleton type used solely for `boxed::HEAP`. | ||
pub struct ExchangeHeapSingleton { _force_singleton: () } | ||
|
||
/// A type that represents a uniquely-owned value. | ||
#[lang = "owned_box"] | ||
#[unstable = "custom allocators will add an additional type parameter (with default)"] | ||
pub struct Box<T>(*mut T); | ||
pub struct Box<Sized? T>(*mut T); | ||
|
||
/// `IntermediateBox` represents uninitialized backing storage for `Box`. | ||
/// | ||
/// FIXME (pnkfelix): Ideally we would just reuse `Box<T>` instead of | ||
/// introducing a separate `IntermediateBox<T>`; but then you hit | ||
/// issues when you e.g. attempt to destructure an instance of `Box`, | ||
/// since it is a lang item and so it gets special handling by the | ||
/// compiler. Easier just to make this parallel type for now. | ||
/// | ||
/// FIXME (pnkfelix): Currently the `box` protocol only supports | ||
/// creating instances of sized types. This IntermediateBox is | ||
/// designed to be forward-compatible with a future protocol that | ||
/// supports creating instances of unsized types; that is why the type | ||
/// parameter has the `Sized?` generalization marker, and is also why | ||
/// this carries an explicit size. However, it probably does not need | ||
/// to carry the explicit alignment; that is just a work-around for | ||
/// the fact that the `align_of` intrinsic currently requires the | ||
/// input type to be Sized (which I do not think is strictly | ||
/// necessary). | ||
pub struct IntermediateBox<Sized? T>{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this is public, we'll be committing to the continued existence of this type, at least. I'm ok with this but cc @aturon. We'll probably want to bikeshed the name :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Of course there's no way to avoid having this be public, at least not without private trait methods at the very least...) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In particular I expect we want to reuse the "agent" term There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On Thu, Nov 06, 2014 at 07:48:41AM -0800, Felix S Klock II wrote:
Yes. And I think that's ok. |
||
ptr: *mut u8, | ||
size: uint, | ||
align: uint, | ||
} | ||
|
||
impl<T> Placer<T, Box<T>, IntermediateBox<T>> for ExchangeHeapSingleton { | ||
fn make_place(&mut self) -> IntermediateBox<T> { | ||
let size = mem::size_of::<T>(); | ||
let align = mem::align_of::<T>(); | ||
|
||
let p = if size == 0 { | ||
heap::EMPTY as *mut u8 | ||
} else { | ||
unsafe { | ||
heap::allocate(size, align) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. heap::allocate() can return null on failure, we should check for this and panic |
||
} | ||
}; | ||
|
||
IntermediateBox { ptr: p, size: size, align: align } | ||
} | ||
} | ||
|
||
impl<Sized? T> PlacementAgent<T, Box<T>> for IntermediateBox<T> { | ||
unsafe fn pointer(&self) -> *mut T { | ||
self.ptr as *mut T | ||
} | ||
unsafe fn finalize(self) -> Box<T> { | ||
let p = self.ptr as *mut T; | ||
mem::forget(self); | ||
mem::transmute(p) | ||
} | ||
} | ||
|
||
#[unsafe_destructor] | ||
impl<Sized? T> Drop for IntermediateBox<T> { | ||
fn drop(&mut self) { | ||
if self.size > 0 { | ||
unsafe { | ||
heap::deallocate(self.ptr as *mut u8, self.size, self.align) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why the cast here? seems unnecessary. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (agreed, that was probably an artifact of an earlier version of the |
||
} | ||
} | ||
} | ||
} | ||
|
||
impl<T: Default> Default for Box<T> { | ||
fn default() -> Box<T> { box Default::default() } | ||
fn default() -> Box<T> { | ||
box (HEAP) { let t : T = Default::default(); t } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does it not work to just right There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the type-inference applied to the desugaring might reject that, but I'll double check. |
||
} | ||
} | ||
|
||
#[unstable] | ||
impl<T: Clone> Clone for Box<T> { | ||
/// Returns a copy of the owned box. | ||
#[inline] | ||
fn clone(&self) -> Box<T> { box {(**self).clone()} } | ||
fn clone(&self) -> Box<T> { box (HEAP) {(**self).clone()} } | ||
|
||
/// Performs copy-assignment from `source` by reusing the existing allocation. | ||
#[inline] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -901,3 +901,67 @@ def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12) | |
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13) | ||
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14) | ||
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15) | ||
|
||
/// Interface to user-implementations of `box (<placer_expr>) <value_expr>`. | ||
/// | ||
/// `box (P) V` effectively expands into: | ||
/// `{ let b = P.make_place(); let v = V; unsafe { b.pointer() = v; b.finalize() } }` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only question is whether There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I switched Can you refresh my memory as to which matter of temporary lifetimes you were referring to here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (oh, maybe that was about the "vector should be tied up" note below... which may indeed go away with the revisions to take the placer by value in |
||
pub trait Placer<Sized? Data, Owner, Interim: PlacementAgent<Data, Owner>> { | ||
/// Allocates a place for the data to live, returning an | ||
/// intermediate agent to negotiate ownership. | ||
fn make_place(&mut self) -> Interim; | ||
} | ||
|
||
/// Some free functions called by expansions of `box <value_expr>` and | ||
/// `box (<place>) <value_expr>`. | ||
pub mod placer { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a way for us to mark these macro-artifacts as unstable? cc @aturon There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This may be a moot point now that UFCS support has landed. |
||
use kinds::Sized; | ||
use ops::{Placer, PlacementAgent}; | ||
|
||
/// The first argument, `<place>` in `box (<place>) <value>`, must | ||
/// implement `Placer`. | ||
pub fn parenthesized_input_to_box_must_be_placer<'a, Sized? Data, Owner, A, P>(p: &'a mut P) -> &'a mut P | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ...with UFCS, I suspect we don't need this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you're right; I had thought we would need e.g. |
||
where A:PlacementAgent<Data, Owner>, | ||
P:Placer<Data, Owner, A>+Sized { | ||
p | ||
} | ||
|
||
/// Work-around for lack of UFCS: the `box (<place>) <value>` | ||
/// syntax expands into calls to the three free functions below in | ||
/// order to avoid requiring (or expanding into) declarations like | ||
/// `use std::ops::Placer;` and `use std::ops::PlacementAgent;` | ||
|
||
/// Calls `p.make_place()` as work-around for lack of UFCS. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have UFCS now There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So I imagine we can remove |
||
pub fn make_place<Sized? Data, Owner, A, P>(p: &mut P) -> A | ||
where A:PlacementAgent<Data, Owner>, | ||
P:Placer<Data, Owner, A> { | ||
p.make_place() | ||
} | ||
|
||
/// Calls `a.pointer()` as work-around for lack of UFCS. | ||
pub unsafe fn pointer<Sized? Data, Owner, A>(a: &A) -> *mut Data | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also |
||
where A:PlacementAgent<Data, Owner> { | ||
a.pointer() | ||
} | ||
|
||
/// Calls `a.finalize()` as work-around for lack of UFCS. | ||
pub unsafe fn finalize<Sized? Data, Owner, A>(a: A) -> Owner | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And |
||
where A:PlacementAgent<Data, Owner> { | ||
a.finalize() | ||
} | ||
} | ||
|
||
/// Helper trait for expansion of `box (P) V`. | ||
/// | ||
/// We force all implementers to implement `Drop`, since in the majority of | ||
/// cases, leaving out a user-defined drop is a bug for these values. | ||
/// | ||
/// See also `Placer`. | ||
pub trait PlacementAgent<Sized? Data, Owner> : Drop { | ||
/// Returns a pointer to the offset in the place where the data lives. | ||
unsafe fn pointer(&self) -> *mut Data; | ||
|
||
/// Converts this intermediate agent into owning pointer for the data, | ||
/// forgetting self in the process. | ||
unsafe fn finalize(self) -> Owner; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -501,7 +501,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> { | |
} | ||
|
||
ast::ExprBox(ref place, ref base) => { | ||
self.consume_expr(&**place); | ||
place.as_ref().map(|e|self.consume_expr(&**e)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The expr There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i was just blindly doing a mechanical transformation here. (But now I think we've further revised the protocol so that |
||
self.consume_expr(&**base); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The term exchange heap really shouldn't be used. It's not how dynamic allocation works in Rust. It's wrong to refer to this as
HEAP
at all. TheBox<T>
type represents a dynamic allocation from the same allocator as other types likeVec<T>
andRc<T>
. Rust doesn't draw any distinction between memory on a "heap" and other memory mappings.