Struct corundum::boxed::Pbox [−][src]
Expand description
A pointer type for persistent heap allocation.
If Pbox
is mutable, the underlying data can mutate after taking a log.
It is necessary because compound types containing a Pbox
may provide
interior mutability (via PCell
or PRefCell
) though which the
Pbox
become mutably available. The log taken for interior mutability works
only on the pointer value and does not include the referent object. Therefore,
Pbox
provides a logging mechanism to provide mutable dereferencing.
Examples
Create a boxed object in the persistent memory
use corundum::default::*; type P = BuddyAlloc; let _p = P::open_no_root("foo.pool", O_CF).unwrap(); transaction(|j| { let five = Pbox::new(5, j); assert_eq!(*five, 5); }).unwrap();
Examples
Move a value from the stack to the persistent memory by creating a Pbox
:
transaction(|j| { let val: u8 = 5; let boxed: Pbox<u8> = Pbox::new(val, j); }).unwrap();
Move a value from a Pbox
back to the stack by dereferencing:
transaction(|j| { let boxed: Pbox<u8> = Pbox::new(5, j); let val: u8 = *boxed; }).unwrap();
Creating a recursive data structure:
#[derive(Debug)] enum List<T: PSafe> { Cons(T, Pbox<List<T>>), Nil, } transaction(|j| { let list: List<i32> = List::Cons(1, Pbox::new(List::Cons(2, Pbox::new(List::Nil, j)), j)); println!("{:?}", list); }).unwrap();
This will print Cons(1, Cons(2, Nil))
.
Recursive structures must be boxed, because if the definition of Cons
looked like this:
Cons(T, List<T>),
It wouldn’t work. This is because the size of a List
depends on how many
elements are in the list, and so we don’t know how much memory to allocate
for a Cons
. By introducing a Pbox<T>
, which has a defined size, we know
how big Cons
needs to be.
Implementations
Allocates memory on the persistent heap and then places x
into it.
This doesn’t actually allocate if T
is zero-sized.
Examples
Heap::transaction(|j| { let five = Pbox::new(5, j); }).unwrap();
Constructs a new Pbox with uninitialized contents.
Examples
P::transaction(|j| { let mut five = Pbox::<u32>::new_uninit(j); let five = unsafe { // Deferred initialization: five.as_mut_ptr().write(5); five.assume_init() }; assert_eq!(*five, 5) }).unwrap()
Constructs a new Pbox
with uninitialized contents, with the memory
being filled with 0
bytes.
See MaybeUninit::zeroed
for examples of correct and incorrect usage
of this method.
Examples
P::transaction(|j| { let zero = Pbox::<u32>::new_zeroed(j); let zero = unsafe { zero.assume_init() }; assert_eq!(*zero, 0) }).unwrap()
Converts to Pbox<T, A>
.
Safety
As with MaybeUninit::assume_init
,
it is up to the caller to guarantee that the value
really is in an initialized state.
Calling this when the content is not yet fully initialized
causes immediate undefined behavior.
Initializes boxed data with value
in-place if it is None
This function should not be called from a transaction as it updates data without taking high-level logs. If transaction is unsuccessful, there is no way to recover data. However, it is safe to use it outside a transaction because it uses low-level logs to provide safety for a single update without drop. A dynamic check at the beginning makes sure of that.
Examples
use corundum::default::*; type P = BuddyAlloc; let root = P::open::<Option<Pbox<i32>>>("foo.pool", O_CF).unwrap(); Pbox::initialize(&*root, 25); let value = **root.as_ref().unwrap(); assert_eq!(value, 25);
Constructs a box from a raw pointer.
After calling this function, the raw pointer is owned by the
resulting Pbox
. Specifically, the Pbox
destructor will call
the destructor of T
and free the allocated memory. For this
to be safe, the memory must have been allocated in accordance
with the memory layout used by Pbox
.
Safety
This function is unsafe because improper use may lead to memory problems. For example, a double-free may occur if the function is called twice on the same raw pointer.
Consumes the Pbox
, returning a wrapped raw pointer.
The pointer will be properly aligned and non-null.
After calling this function, the caller is responsible for the
memory previously managed by the Pbox
. In particular, the
caller should properly destroy T
and release the memory, taking
into account the [memory layout] used by Pbox
. The easiest way to
do this is to convert the raw pointer back into a Pbox
with the
Pbox::from_raw
function, allowing the Pbox
destructor to perform
the cleanup.
Note: this is an associated function, which means that you have
to call it as Pbox::into_raw(b)
instead of b.into_raw()
. This
is so that there is no conflict with a method on the inner type.
Consumes the Pbox
, returning the wrapped pointer as NonNull<T>
.
After calling this function, the caller is responsible for the
memory previously managed by the Pbox
. In particular, the
caller should properly destroy T
and release the memory. The
easiest way to do so is to convert the NonNull<T>
pointer
into a raw pointer and back into a Pbox
with the Pbox::from_raw
function.
Note: this is an associated function, which means that you have
to call it as Pbox::into_raw_non_null(b)
instead of b.into_raw_non_null()
. This
is so that there is no conflict with a method on the inner type.
Consumes and leaks the Pbox
, returning a mutable reference,
&'a mut T
. Note that the type T
must outlive the chosen lifetime
'a
. If the type has only static references, or none at all, then this
may be chosen to be 'static
.
This function is mainly useful for data that lives for the remainder of
the program’s life. Dropping the returned reference will cause a memory
leak. If this is not acceptable, the reference should first be wrapped
with the Pbox::from_raw
function producing a Pbox
. This Pbox
can
then be dropped which will properly destroy T
and release the
allocated memory.
Note: this is an associated function, which means that you have
to call it as Pbox::leak(b)
instead of b.leak()
. This
is so that there is no conflict with a method on the inner type.
Safety
This function is considered unsafe in persistent memory programming because memory leak is permanent and undesirable.
Examples
Simple usage:
Heap::transaction(|j| unsafe { let x = Pbox::new(41, j); let static_ref: &'static mut usize = Pbox::leak(x); *static_ref += 1; assert_eq!(*static_ref, 42); }).unwrap();
Converts a Pbox<T, A>
into a Pin<Pbox<T, A>>
This conversion does not allocate on the heap and happens in place.
This is also available via From
.
Trait Implementations
Writes a single u128
into this hasher.
Writes a single usize
into this hasher.
Writes a single i128
into this hasher.
Writes a single isize
into this hasher.
Returns a new box with a pclone()
of this box’s contents.
Examples
use corundum::clone::PClone; Heap::transaction(|j| { let x = Pbox::new(5, j); let y = x.pclone(j); // The value is the same assert_eq!(x, y); // But they are unique objects assert_ne!(&*x as *const i32, &*y as *const i32); }).unwrap();
Performs copy-assignment from source
. Read more
This method returns an ordering between self
and other
values if one exists. Read more
This method tests less than (for self
and other
) and is used by the <
operator. Read more
This method tests less than or equal to (for self
and other
) and is used by the <=
operator. Read more
This method tests greater than or equal to (for self
and other
) and is used by the >=
operator. Read more