Rename Alloc to AllocRef

This commit is contained in:
Tim Diekmann 2020-01-23 01:49:29 +01:00
parent c2d141df59
commit 7ca25db816
No known key found for this signature in database
GPG Key ID: D393760BF8145B42
16 changed files with 60 additions and 45 deletions

View File

@ -9,7 +9,7 @@ The tracking issue for this feature is [#32838]
Sometimes you want the memory for one collection to use a different Sometimes you want the memory for one collection to use a different
allocator than the memory for another collection. In this case, allocator than the memory for another collection. In this case,
replacing the global allocator is not a workable option. Instead, replacing the global allocator is not a workable option. Instead,
you need to pass in an instance of an `Alloc` to each collection you need to pass in an instance of an `AllocRef` to each collection
for which you want a custom allocator. for which you want a custom allocator.
TBD TBD

View File

@ -31,14 +31,14 @@ extern "Rust" {
/// The global memory allocator. /// The global memory allocator.
/// ///
/// This type implements the [`Alloc`] trait by forwarding calls /// This type implements the [`AllocRef`] trait by forwarding calls
/// to the allocator registered with the `#[global_allocator]` attribute /// to the allocator registered with the `#[global_allocator]` attribute
/// if there is one, or the `std` crates default. /// if there is one, or the `std` crates default.
/// ///
/// Note: while this type is unstable, the functionality it provides can be /// Note: while this type is unstable, the functionality it provides can be
/// accessed through the [free functions in `alloc`](index.html#functions). /// accessed through the [free functions in `alloc`](index.html#functions).
/// ///
/// [`Alloc`]: trait.Alloc.html /// [`AllocRef`]: trait.AllocRef.html
#[unstable(feature = "allocator_api", issue = "32838")] #[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Copy, Clone, Default, Debug)] #[derive(Copy, Clone, Default, Debug)]
pub struct Global; pub struct Global;
@ -50,14 +50,14 @@ pub struct Global;
/// if there is one, or the `std` crates default. /// if there is one, or the `std` crates default.
/// ///
/// This function is expected to be deprecated in favor of the `alloc` method /// This function is expected to be deprecated in favor of the `alloc` method
/// of the [`Global`] type when it and the [`Alloc`] trait become stable. /// of the [`Global`] type when it and the [`AllocRef`] trait become stable.
/// ///
/// # Safety /// # Safety
/// ///
/// See [`GlobalAlloc::alloc`]. /// See [`GlobalAlloc::alloc`].
/// ///
/// [`Global`]: struct.Global.html /// [`Global`]: struct.Global.html
/// [`Alloc`]: trait.Alloc.html /// [`AllocRef`]: trait.AllocRef.html
/// [`GlobalAlloc::alloc`]: trait.GlobalAlloc.html#tymethod.alloc /// [`GlobalAlloc::alloc`]: trait.GlobalAlloc.html#tymethod.alloc
/// ///
/// # Examples /// # Examples
@ -88,14 +88,14 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 {
/// if there is one, or the `std` crates default. /// if there is one, or the `std` crates default.
/// ///
/// This function is expected to be deprecated in favor of the `dealloc` method /// This function is expected to be deprecated in favor of the `dealloc` method
/// of the [`Global`] type when it and the [`Alloc`] trait become stable. /// of the [`Global`] type when it and the [`AllocRef`] trait become stable.
/// ///
/// # Safety /// # Safety
/// ///
/// See [`GlobalAlloc::dealloc`]. /// See [`GlobalAlloc::dealloc`].
/// ///
/// [`Global`]: struct.Global.html /// [`Global`]: struct.Global.html
/// [`Alloc`]: trait.Alloc.html /// [`AllocRef`]: trait.AllocRef.html
/// [`GlobalAlloc::dealloc`]: trait.GlobalAlloc.html#tymethod.dealloc /// [`GlobalAlloc::dealloc`]: trait.GlobalAlloc.html#tymethod.dealloc
#[stable(feature = "global_alloc", since = "1.28.0")] #[stable(feature = "global_alloc", since = "1.28.0")]
#[inline] #[inline]
@ -110,14 +110,14 @@ pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
/// if there is one, or the `std` crates default. /// if there is one, or the `std` crates default.
/// ///
/// This function is expected to be deprecated in favor of the `realloc` method /// This function is expected to be deprecated in favor of the `realloc` method
/// of the [`Global`] type when it and the [`Alloc`] trait become stable. /// of the [`Global`] type when it and the [`AllocRef`] trait become stable.
/// ///
/// # Safety /// # Safety
/// ///
/// See [`GlobalAlloc::realloc`]. /// See [`GlobalAlloc::realloc`].
/// ///
/// [`Global`]: struct.Global.html /// [`Global`]: struct.Global.html
/// [`Alloc`]: trait.Alloc.html /// [`AllocRef`]: trait.AllocRef.html
/// [`GlobalAlloc::realloc`]: trait.GlobalAlloc.html#method.realloc /// [`GlobalAlloc::realloc`]: trait.GlobalAlloc.html#method.realloc
#[stable(feature = "global_alloc", since = "1.28.0")] #[stable(feature = "global_alloc", since = "1.28.0")]
#[inline] #[inline]
@ -132,14 +132,14 @@ pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8
/// if there is one, or the `std` crates default. /// if there is one, or the `std` crates default.
/// ///
/// This function is expected to be deprecated in favor of the `alloc_zeroed` method /// This function is expected to be deprecated in favor of the `alloc_zeroed` method
/// of the [`Global`] type when it and the [`Alloc`] trait become stable. /// of the [`Global`] type when it and the [`AllocRef`] trait become stable.
/// ///
/// # Safety /// # Safety
/// ///
/// See [`GlobalAlloc::alloc_zeroed`]. /// See [`GlobalAlloc::alloc_zeroed`].
/// ///
/// [`Global`]: struct.Global.html /// [`Global`]: struct.Global.html
/// [`Alloc`]: trait.Alloc.html /// [`AllocRef`]: trait.AllocRef.html
/// [`GlobalAlloc::alloc_zeroed`]: trait.GlobalAlloc.html#method.alloc_zeroed /// [`GlobalAlloc::alloc_zeroed`]: trait.GlobalAlloc.html#method.alloc_zeroed
/// ///
/// # Examples /// # Examples
@ -163,7 +163,7 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
} }
#[unstable(feature = "allocator_api", issue = "32838")] #[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl Alloc for Global { unsafe impl AllocRef for Global {
#[inline] #[inline]
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> { unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
NonNull::new(alloc(layout)).ok_or(AllocErr) NonNull::new(alloc(layout)).ok_or(AllocErr)

View File

@ -145,7 +145,7 @@ use core::ptr::{self, NonNull, Unique};
use core::slice; use core::slice;
use core::task::{Context, Poll}; use core::task::{Context, Poll};
use crate::alloc::{self, Alloc, Global}; use crate::alloc::{self, AllocRef, Global};
use crate::raw_vec::RawVec; use crate::raw_vec::RawVec;
use crate::str::from_boxed_utf8_unchecked; use crate::str::from_boxed_utf8_unchecked;
use crate::vec::Vec; use crate::vec::Vec;

View File

@ -36,7 +36,7 @@ use core::mem::{self, MaybeUninit};
use core::ptr::{self, NonNull, Unique}; use core::ptr::{self, NonNull, Unique};
use core::slice; use core::slice;
use crate::alloc::{Alloc, Global, Layout}; use crate::alloc::{AllocRef, Global, Layout};
use crate::boxed::Box; use crate::boxed::Box;
const B: usize = 6; const B: usize = 6;

View File

@ -7,7 +7,7 @@ use core::ops::Drop;
use core::ptr::{self, NonNull, Unique}; use core::ptr::{self, NonNull, Unique};
use core::slice; use core::slice;
use crate::alloc::{handle_alloc_error, Alloc, AllocErr, Global, Layout}; use crate::alloc::{handle_alloc_error, AllocErr, AllocRef, Global, Layout};
use crate::boxed::Box; use crate::boxed::Box;
use crate::collections::TryReserveError::{self, *}; use crate::collections::TryReserveError::{self, *};
@ -42,13 +42,13 @@ mod tests;
/// field. This allows zero-sized types to not be special-cased by consumers of /// field. This allows zero-sized types to not be special-cased by consumers of
/// this type. /// this type.
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
pub struct RawVec<T, A: Alloc = Global> { pub struct RawVec<T, A: AllocRef = Global> {
ptr: Unique<T>, ptr: Unique<T>,
cap: usize, cap: usize,
a: A, a: A,
} }
impl<T, A: Alloc> RawVec<T, A> { impl<T, A: AllocRef> RawVec<T, A> {
/// Like `new`, but parameterized over the choice of allocator for /// Like `new`, but parameterized over the choice of allocator for
/// the returned `RawVec`. /// the returned `RawVec`.
pub const fn new_in(a: A) -> Self { pub const fn new_in(a: A) -> Self {
@ -147,7 +147,7 @@ impl<T> RawVec<T, Global> {
} }
} }
impl<T, A: Alloc> RawVec<T, A> { impl<T, A: AllocRef> RawVec<T, A> {
/// Reconstitutes a `RawVec` from a pointer, capacity, and allocator. /// Reconstitutes a `RawVec` from a pointer, capacity, and allocator.
/// ///
/// # Undefined Behavior /// # Undefined Behavior
@ -182,7 +182,7 @@ impl<T> RawVec<T, Global> {
} }
} }
impl<T, A: Alloc> RawVec<T, A> { impl<T, A: AllocRef> RawVec<T, A> {
/// Gets a raw pointer to the start of the allocation. Note that this is /// Gets a raw pointer to the start of the allocation. Note that this is
/// `Unique::empty()` if `capacity == 0` or `T` is zero-sized. In the former case, you must /// `Unique::empty()` if `capacity == 0` or `T` is zero-sized. In the former case, you must
/// be careful. /// be careful.
@ -622,7 +622,7 @@ enum ReserveStrategy {
use ReserveStrategy::*; use ReserveStrategy::*;
impl<T, A: Alloc> RawVec<T, A> { impl<T, A: AllocRef> RawVec<T, A> {
fn reserve_internal( fn reserve_internal(
&mut self, &mut self,
used_capacity: usize, used_capacity: usize,
@ -700,7 +700,7 @@ impl<T> RawVec<T, Global> {
} }
} }
impl<T, A: Alloc> RawVec<T, A> { impl<T, A: AllocRef> RawVec<T, A> {
/// Frees the memory owned by the `RawVec` *without* trying to drop its contents. /// Frees the memory owned by the `RawVec` *without* trying to drop its contents.
pub unsafe fn dealloc_buffer(&mut self) { pub unsafe fn dealloc_buffer(&mut self) {
let elem_size = mem::size_of::<T>(); let elem_size = mem::size_of::<T>();
@ -712,7 +712,7 @@ impl<T, A: Alloc> RawVec<T, A> {
} }
} }
unsafe impl<#[may_dangle] T, A: Alloc> Drop for RawVec<T, A> { unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec<T, A> {
/// Frees the memory owned by the `RawVec` *without* trying to drop its contents. /// Frees the memory owned by the `RawVec` *without* trying to drop its contents.
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {

View File

@ -19,7 +19,7 @@ fn allocator_param() {
struct BoundedAlloc { struct BoundedAlloc {
fuel: usize, fuel: usize,
} }
unsafe impl Alloc for BoundedAlloc { unsafe impl AllocRef for BoundedAlloc {
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> { unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
let size = layout.size(); let size = layout.size();
if size > self.fuel { if size > self.fuel {

View File

@ -252,7 +252,7 @@ use core::ptr::{self, NonNull};
use core::slice::{self, from_raw_parts_mut}; use core::slice::{self, from_raw_parts_mut};
use core::usize; use core::usize;
use crate::alloc::{box_free, handle_alloc_error, Alloc, Global, Layout}; use crate::alloc::{box_free, handle_alloc_error, AllocRef, Global, Layout};
use crate::string::String; use crate::string::String;
use crate::vec::Vec; use crate::vec::Vec;

View File

@ -25,7 +25,7 @@ use core::sync::atomic;
use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
use core::{isize, usize}; use core::{isize, usize};
use crate::alloc::{box_free, handle_alloc_error, Alloc, Global, Layout}; use crate::alloc::{box_free, handle_alloc_error, AllocRef, Global, Layout};
use crate::boxed::Box; use crate::boxed::Box;
use crate::rc::is_dangling; use crate::rc::is_dangling;
use crate::string::String; use crate::string::String;

View File

@ -1,4 +1,4 @@
use std::alloc::{Alloc, Global, Layout, System}; use std::alloc::{AllocRef, Global, Layout, System};
/// Issue #45955 and #62251. /// Issue #45955 and #62251.
#[test] #[test]
@ -11,7 +11,7 @@ fn std_heap_overaligned_request() {
check_overalign_requests(Global) check_overalign_requests(Global)
} }
fn check_overalign_requests<T: Alloc>(mut allocator: T) { fn check_overalign_requests<T: AllocRef>(mut allocator: T) {
for &align in &[4, 8, 16, 32] { for &align in &[4, 8, 16, 32] {
// less than and bigger than `MIN_ALIGN` // less than and bigger than `MIN_ALIGN`
for &size in &[align / 2, align - 1] { for &size in &[align / 2, align - 1] {

View File

@ -31,7 +31,7 @@ const fn size_align<T>() -> (usize, usize) {
/// ///
/// (Note however that layouts are *not* required to have positive /// (Note however that layouts are *not* required to have positive
/// size, even though many allocators require that all memory /// size, even though many allocators require that all memory
/// requests have positive size. A caller to the `Alloc::alloc` /// requests have positive size. A caller to the `AllocRef::alloc`
/// method must either ensure that conditions like this are met, or /// method must either ensure that conditions like this are met, or
/// use specific allocators with looser requirements.) /// use specific allocators with looser requirements.)
#[stable(feature = "alloc_layout", since = "1.28.0")] #[stable(feature = "alloc_layout", since = "1.28.0")]
@ -364,8 +364,8 @@ impl fmt::Display for AllocErr {
/// [`shrink_in_place`] were unable to reuse the given memory block for /// [`shrink_in_place`] were unable to reuse the given memory block for
/// a requested layout. /// a requested layout.
/// ///
/// [`grow_in_place`]: ./trait.Alloc.html#method.grow_in_place /// [`grow_in_place`]: ./trait.AllocRef.html#method.grow_in_place
/// [`shrink_in_place`]: ./trait.Alloc.html#method.shrink_in_place /// [`shrink_in_place`]: ./trait.AllocRef.html#method.shrink_in_place
#[unstable(feature = "allocator_api", issue = "32838")] #[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
pub struct CannotReallocInPlace; pub struct CannotReallocInPlace;
@ -580,9 +580,14 @@ pub unsafe trait GlobalAlloc {
} }
} }
/// An implementation of `Alloc` can allocate, reallocate, and /// An implementation of `AllocRef` can allocate, reallocate, and
/// deallocate arbitrary blocks of data described via `Layout`. /// deallocate arbitrary blocks of data described via `Layout`.
/// ///
/// `AllocRef` is designed to be implemented on ZSTs, references, or
/// smart pointers because having an allocator like `MyAlloc([u8; N])`
/// cannot be moved, without updating the pointers to the allocated
/// memory.
///
/// Some of the methods require that a memory block be *currently /// Some of the methods require that a memory block be *currently
/// allocated* via an allocator. This means that: /// allocated* via an allocator. This means that:
/// ///
@ -598,7 +603,7 @@ pub unsafe trait GlobalAlloc {
/// passed to a reallocation method (see above) that returns `Ok`. /// passed to a reallocation method (see above) that returns `Ok`.
/// ///
/// A note regarding zero-sized types and zero-sized layouts: many /// A note regarding zero-sized types and zero-sized layouts: many
/// methods in the `Alloc` trait state that allocation requests /// methods in the `AllocRef` trait state that allocation requests
/// must be non-zero size, or else undefined behavior can result. /// must be non-zero size, or else undefined behavior can result.
/// ///
/// * However, some higher-level allocation methods (`alloc_one`, /// * However, some higher-level allocation methods (`alloc_one`,
@ -606,7 +611,7 @@ pub unsafe trait GlobalAlloc {
/// optionally support them: it is left up to the implementor /// optionally support them: it is left up to the implementor
/// whether to return `Err`, or to return `Ok` with some pointer. /// whether to return `Err`, or to return `Ok` with some pointer.
/// ///
/// * If an `Alloc` implementation chooses to return `Ok` in this /// * If an `AllocRef` implementation chooses to return `Ok` in this
/// case (i.e., the pointer denotes a zero-sized inaccessible block) /// case (i.e., the pointer denotes a zero-sized inaccessible block)
/// then that returned pointer must be considered "currently /// then that returned pointer must be considered "currently
/// allocated". On such an allocator, *all* methods that take /// allocated". On such an allocator, *all* methods that take
@ -646,13 +651,16 @@ pub unsafe trait GlobalAlloc {
/// ///
/// # Safety /// # Safety
/// ///
/// The `Alloc` trait is an `unsafe` trait for a number of reasons, and /// The `AllocRef` trait is an `unsafe` trait for a number of reasons, and
/// implementors must ensure that they adhere to these contracts: /// implementors must ensure that they adhere to these contracts:
/// ///
/// * Pointers returned from allocation functions must point to valid memory and /// * Pointers returned from allocation functions must point to valid memory and
/// retain their validity until at least the instance of `Alloc` is dropped /// retain their validity until at least one instance of `AllocRef` is dropped
/// itself. /// itself.
/// ///
/// * Cloning or moving the allocator must not invalidate pointers returned
/// from this allocator. Cloning must return a reference to the same allocator.
///
/// * `Layout` queries and calculations in general must be correct. Callers of /// * `Layout` queries and calculations in general must be correct. Callers of
/// this trait are allowed to rely on the contracts defined on each method, /// this trait are allowed to rely on the contracts defined on each method,
/// and implementors must ensure such contracts remain true. /// and implementors must ensure such contracts remain true.
@ -660,7 +668,7 @@ pub unsafe trait GlobalAlloc {
/// Note that this list may get tweaked over time as clarifications are made in /// Note that this list may get tweaked over time as clarifications are made in
/// the future. /// the future.
#[unstable(feature = "allocator_api", issue = "32838")] #[unstable(feature = "allocator_api", issue = "32838")]
pub unsafe trait Alloc { pub unsafe trait AllocRef {
// (Note: some existing allocators have unspecified but well-defined // (Note: some existing allocators have unspecified but well-defined
// behavior in response to a zero size allocation request ; // behavior in response to a zero size allocation request ;
// e.g., in C, `malloc` of 0 will either return a null pointer or a // e.g., in C, `malloc` of 0 will either return a null pointer or a
@ -1042,7 +1050,7 @@ pub unsafe trait Alloc {
/// must be considered "currently allocated" and must be /// must be considered "currently allocated" and must be
/// acceptable input to methods such as `realloc` or `dealloc`, /// acceptable input to methods such as `realloc` or `dealloc`,
/// *even if* `T` is a zero-sized type. In other words, if your /// *even if* `T` is a zero-sized type. In other words, if your
/// `Alloc` implementation overrides this method in a manner /// `AllocRef` implementation overrides this method in a manner
/// that can return a zero-sized `ptr`, then all reallocation and /// that can return a zero-sized `ptr`, then all reallocation and
/// deallocation methods need to be similarly overridden to accept /// deallocation methods need to be similarly overridden to accept
/// such values as input. /// such values as input.
@ -1106,7 +1114,7 @@ pub unsafe trait Alloc {
/// must be considered "currently allocated" and must be /// must be considered "currently allocated" and must be
/// acceptable input to methods such as `realloc` or `dealloc`, /// acceptable input to methods such as `realloc` or `dealloc`,
/// *even if* `T` is a zero-sized type. In other words, if your /// *even if* `T` is a zero-sized type. In other words, if your
/// `Alloc` implementation overrides this method in a manner /// `AllocRef` implementation overrides this method in a manner
/// that can return a zero-sized `ptr`, then all reallocation and /// that can return a zero-sized `ptr`, then all reallocation and
/// deallocation methods need to be similarly overridden to accept /// deallocation methods need to be similarly overridden to accept
/// such values as input. /// such values as input.
@ -1219,3 +1227,10 @@ pub unsafe trait Alloc {
} }
} }
} }
// In order to rename `Alloc` to `AllocRef`, some submoduleshas to be updated as well. The CI fails
// if either of the submodules fails to compile. The submodules have their own CI depending on a
// specific Rust version, which don't have `AllocRef` yet. This alias is used to make the submodules
// compile and pass the CI.
#[unstable(feature = "allocator_api", issue = "32838")]
pub use self::AllocRef as Alloc;

View File

@ -133,9 +133,9 @@ pub use alloc_crate::alloc::*;
#[derive(Debug, Default, Copy, Clone)] #[derive(Debug, Default, Copy, Clone)]
pub struct System; pub struct System;
// The Alloc impl just forwards to the GlobalAlloc impl, which is in `std::sys::*::alloc`. // The AllocRef impl just forwards to the GlobalAlloc impl, which is in `std::sys::*::alloc`.
#[unstable(feature = "allocator_api", issue = "32838")] #[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl Alloc for System { unsafe impl AllocRef for System {
#[inline] #[inline]
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> { unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr)

View File

@ -4,7 +4,7 @@
#![feature(allocator_api, nonnull)] #![feature(allocator_api, nonnull)]
use std::alloc::{Alloc, Global, Layout, handle_alloc_error}; use std::alloc::{AllocRef, Global, Layout, handle_alloc_error};
fn main() { fn main() {
unsafe { unsafe {

View File

@ -7,7 +7,7 @@
extern crate helper; extern crate helper;
use std::alloc::{self, Global, Alloc, System, Layout}; use std::alloc::{self, Global, AllocRef, System, Layout};
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
static HITS: AtomicUsize = AtomicUsize::new(0); static HITS: AtomicUsize = AtomicUsize::new(0);

View File

@ -9,7 +9,7 @@
extern crate custom; extern crate custom;
extern crate helper; extern crate helper;
use std::alloc::{Global, Alloc, System, Layout}; use std::alloc::{Global, AllocRef, System, Layout};
use std::sync::atomic::{Ordering, AtomicUsize}; use std::sync::atomic::{Ordering, AtomicUsize};
#[global_allocator] #[global_allocator]

View File

@ -6,7 +6,7 @@
#![feature(allocator_api)] #![feature(allocator_api)]
use std::alloc::{Global, Alloc, Layout, handle_alloc_error}; use std::alloc::{Global, AllocRef, Layout, handle_alloc_error};
use std::ptr::{self, NonNull}; use std::ptr::{self, NonNull};
fn main() { fn main() {

View File

@ -6,7 +6,7 @@
#![feature(allocator_api)] #![feature(allocator_api)]
use std::alloc::{Alloc, Global, Layout, handle_alloc_error}; use std::alloc::{AllocRef, Global, Layout, handle_alloc_error};
use std::ptr::NonNull; use std::ptr::NonNull;
struct arena(()); struct arena(());