@@ -2,354 +2,36 @@ pub use self::inner::*;
22
33#[ cfg( feature = "nightly" ) ]
44mod inner {
5- pub use crate :: alloc:: alloc:: { AllocRef , Global } ;
5+ pub use crate :: alloc:: alloc:: { AllocError , AllocRef , Global } ;
66}
77
88#[ cfg( not( feature = "nightly" ) ) ]
99mod inner {
10- use crate :: alloc:: alloc:: { alloc, dealloc, AllocErr , Layout } ;
10+ use crate :: alloc:: alloc:: { alloc, dealloc, Layout } ;
11+ use core:: ptr;
1112 use core:: ptr:: NonNull ;
1213
13- #[ derive( Debug , Copy , Clone ) ]
14- pub enum AllocInit {
15- Uninitialized ,
16- }
17-
18- #[ derive( Debug , Copy , Clone ) ]
19- pub struct MemoryBlock {
20- pub ptr : NonNull < u8 > ,
21- pub size : usize ,
22- }
14+ pub struct AllocError ;
2315
24- /// An implementation of `AllocRef` can allocate, grow, shrink, and deallocate arbitrary blocks of
25- /// data described via [`Layout`][].
26- ///
27- /// `AllocRef` is designed to be implemented on ZSTs, references, or smart pointers because having
28- /// an allocator like `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the
29- /// allocated memory.
30- ///
31- /// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `AllocRef`. If an underlying
32- /// allocator does not support this (like jemalloc) or return a null pointer (such as
33- /// `libc::malloc`), this must be caught by the implementation.
34- ///
35- /// ### Currently allocated memory
36- ///
37- /// Some of the methods require that a memory block be *currently allocated* via an allocator. This
38- /// means that:
39- ///
40- /// * the starting address for that memory block was previously returned by [`alloc`], [`grow`], or
41- /// [`shrink`], and
42- ///
43- /// * the memory block has not been subsequently deallocated, where blocks are either deallocated
44- /// directly by being passed to [`dealloc`] or were changed by being passed to [`grow`] or
45- /// [`shrink`] that returns `Ok`. If `grow` or `shrink` have returned `Err`, the passed pointer
46- /// remains valid.
47- ///
48- /// [`alloc`]: AllocRef::alloc
49- /// [`grow`]: AllocRef::grow
50- /// [`shrink`]: AllocRef::shrink
51- /// [`dealloc`]: AllocRef::dealloc
52- ///
53- /// ### Memory fitting
54- ///
55- /// Some of the methods require that a layout *fit* a memory block. What it means for a layout to
56- /// "fit" a memory block means (or equivalently, for a memory block to "fit" a layout) is that the
57- /// following conditions must hold:
58- ///
59- /// * The block must be allocated with the same alignment as [`layout.align()`], and
60- ///
61- /// * The provided [`layout.size()`] must fall in the range `min ..= max`, where:
62- /// - `min` is the size of the layout most recently used to allocate the block, and
63- /// - `max` is the latest actual size returned from [`alloc`], [`grow`], or [`shrink`].
64- ///
65- /// [`layout.align()`]: Layout::align
66- /// [`layout.size()`]: Layout::size
67- ///
68- /// # Safety
69- ///
70- /// * Memory blocks returned from an allocator must point to valid memory and retain their validity
71- /// until the instance and all of its clones are dropped,
72- ///
73- /// * cloning or moving the allocator must not invalidate memory blocks returned from this
74- /// allocator. A cloned allocator must behave like the same allocator, and
75- ///
76- /// * any pointer to a memory block which is [*currently allocated*] may be passed to any other
77- /// method of the allocator.
78- ///
79- /// [*currently allocated*]: #currently-allocated-memory
80- #[ unstable( feature = "allocator_api" , issue = "32838" ) ]
8116 pub unsafe trait AllocRef {
82- /// Attempts to allocate a block of memory.
83- ///
84- /// On success, returns a [`NonNull<[u8]>`] meeting the size and alignment guarantees of `layout`.
85- ///
86- /// The returned block may have a larger size than specified by `layout.size()`, and may or may
87- /// not have its contents initialized.
88- ///
89- /// [`NonNull<[u8]>`]: NonNull
90- ///
91- /// # Errors
92- ///
93- /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
94- /// allocator's size or alignment constraints.
95- ///
96- /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
97- /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
98- /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
99- ///
100- /// Clients wishing to abort computation in response to an allocation error are encouraged to
101- /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
102- ///
103- /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
104- fn alloc ( & self , layout : Layout ) -> Result < NonNull < [ u8 ] > , AllocErr > ;
105-
106- /// Behaves like `alloc`, but also ensures that the returned memory is zero-initialized.
107- ///
108- /// # Errors
109- ///
110- /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
111- /// allocator's size or alignment constraints.
112- ///
113- /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
114- /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
115- /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
116- ///
117- /// Clients wishing to abort computation in response to an allocation error are encouraged to
118- /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
119- ///
120- /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
121- fn alloc_zeroed ( & self , layout : Layout ) -> Result < NonNull < [ u8 ] > , AllocErr > {
122- let ptr = self . alloc ( layout) ?;
123- // SAFETY: `alloc` returns a valid memory block
124- unsafe { ptr. as_non_null_ptr ( ) . as_ptr ( ) . write_bytes ( 0 , ptr. len ( ) ) }
125- Ok ( ptr)
126- }
127-
128- /// Deallocates the memory referenced by `ptr`.
129- ///
130- /// # Safety
131- ///
132- /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, and
133- /// * `layout` must [*fit*] that block of memory.
134- ///
135- /// [*currently allocated*]: #currently-allocated-memory
136- /// [*fit*]: #memory-fitting
17+ fn alloc ( & self , layout : Layout ) -> Result < NonNull < [ u8 ] > , AllocError > ;
13718 unsafe fn dealloc ( & self , ptr : NonNull < u8 > , layout : Layout ) ;
138-
139- /// Attempts to extend the memory block.
140- ///
141- /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated
142- /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish
143- /// this, the allocator may extend the allocation referenced by `ptr` to fit the new layout.
144- ///
145- /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
146- /// transferred to this allocator. The memory may or may not have been freed, and should be
147- /// considered unusable unless it was transferred back to the caller again via the return value
148- /// of this method.
149- ///
150- /// If this method returns `Err`, then ownership of the memory block has not been transferred to
151- /// this allocator, and the contents of the memory block are unaltered.
152- ///
153- /// [`NonNull<[u8]>`]: NonNull
154- ///
155- /// # Safety
156- ///
157- /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
158- /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.).
159- /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`.
160- ///
161- /// [*currently allocated*]: #currently-allocated-memory
162- /// [*fit*]: #memory-fitting
163- ///
164- /// # Errors
165- ///
166- /// Returns `Err` if the new layout does not meet the allocator's size and alignment
167- /// constraints of the allocator, or if growing otherwise fails.
168- ///
169- /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
170- /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
171- /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
172- ///
173- /// Clients wishing to abort computation in response to an allocation error are encouraged to
174- /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
175- ///
176- /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
177- unsafe fn grow (
178- & self ,
179- ptr : NonNull < u8 > ,
180- old_layout : Layout ,
181- new_layout : Layout ,
182- ) -> Result < NonNull < [ u8 ] > , AllocErr > {
183- debug_assert ! (
184- new_layout. size( ) >= old_layout. size( ) ,
185- "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
186- ) ;
187-
188- let new_ptr = self . alloc ( new_layout) ?;
189-
190- // SAFETY: because `new_layout.size()` must be greater than or equal to
191- // `old_layout.size()`, both the old and new memory allocation are valid for reads and
192- // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet
193- // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is
194- // safe. The safety contract for `dealloc` must be upheld by the caller.
195- unsafe {
196- ptr:: copy_nonoverlapping ( ptr. as_ptr ( ) , new_ptr. as_mut_ptr ( ) , old_layout. size ( ) ) ;
197- self . dealloc ( ptr, old_layout) ;
198- }
199-
200- Ok ( new_ptr)
201- }
202-
203- /// Behaves like `grow`, but also ensures that the new contents are set to zero before being
204- /// returned.
205- ///
206- /// The memory block will contain the following contents after a successful call to
207- /// `grow_zeroed`:
208- /// * Bytes `0..old_layout.size()` are preserved from the original allocation.
209- /// * Bytes `old_layout.size()..old_size` will either be preserved or zeroed, depending on
210- /// the allocator implementation. `old_size` refers to the size of the memory block prior
211- /// to the `grow_zeroed` call, which may be larger than the size that was originally
212- /// requested when it was allocated.
213- /// * Bytes `old_size..new_size` are zeroed. `new_size` refers to the size of the memory
214- /// block returned by the `grow_zeroed` call.
215- ///
216- /// # Safety
217- ///
218- /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
219- /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.).
220- /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`.
221- ///
222- /// [*currently allocated*]: #currently-allocated-memory
223- /// [*fit*]: #memory-fitting
224- ///
225- /// # Errors
226- ///
227- /// Returns `Err` if the new layout does not meet the allocator's size and alignment
228- /// constraints of the allocator, or if growing otherwise fails.
229- ///
230- /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
231- /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
232- /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
233- ///
234- /// Clients wishing to abort computation in response to an allocation error are encouraged to
235- /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
236- ///
237- /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
238- unsafe fn grow_zeroed (
239- & self ,
240- ptr : NonNull < u8 > ,
241- old_layout : Layout ,
242- new_layout : Layout ,
243- ) -> Result < NonNull < [ u8 ] > , AllocErr > {
244- debug_assert ! (
245- new_layout. size( ) >= old_layout. size( ) ,
246- "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
247- ) ;
248-
249- let new_ptr = self . alloc_zeroed ( new_layout) ?;
250-
251- // SAFETY: because `new_layout.size()` must be greater than or equal to
252- // `old_layout.size()`, both the old and new memory allocation are valid for reads and
253- // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet
254- // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is
255- // safe. The safety contract for `dealloc` must be upheld by the caller.
256- unsafe {
257- ptr:: copy_nonoverlapping ( ptr. as_ptr ( ) , new_ptr. as_mut_ptr ( ) , old_layout. size ( ) ) ;
258- self . dealloc ( ptr, old_layout) ;
259- }
260-
261- Ok ( new_ptr)
262- }
263-
264- /// Attempts to shrink the memory block.
265- ///
266- /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated
267- /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish
268- /// this, the allocator may shrink the allocation referenced by `ptr` to fit the new layout.
269- ///
270- /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
271- /// transferred to this allocator. The memory may or may not have been freed, and should be
272- /// considered unusable unless it was transferred back to the caller again via the return value
273- /// of this method.
274- ///
275- /// If this method returns `Err`, then ownership of the memory block has not been transferred to
276- /// this allocator, and the contents of the memory block are unaltered.
277- ///
278- /// [`NonNull<[u8]>`]: NonNull
279- ///
280- /// # Safety
281- ///
282- /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
283- /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.).
284- /// * `new_layout.size()` must be smaller than or equal to `old_layout.size()`.
285- ///
286- /// [*currently allocated*]: #currently-allocated-memory
287- /// [*fit*]: #memory-fitting
288- ///
289- /// # Errors
290- ///
291- /// Returns `Err` if the new layout does not meet the allocator's size and alignment
292- /// constraints of the allocator, or if shrinking otherwise fails.
293- ///
294- /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
295- /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
296- /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
297- ///
298- /// Clients wishing to abort computation in response to an allocation error are encouraged to
299- /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
300- ///
301- /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
302- unsafe fn shrink (
303- & self ,
304- ptr : NonNull < u8 > ,
305- old_layout : Layout ,
306- new_layout : Layout ,
307- ) -> Result < NonNull < [ u8 ] > , AllocErr > {
308- debug_assert ! (
309- new_layout. size( ) <= old_layout. size( ) ,
310- "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
311- ) ;
312-
313- let new_ptr = self . alloc ( new_layout) ?;
314-
315- // SAFETY: because `new_layout.size()` must be lower than or equal to
316- // `old_layout.size()`, both the old and new memory allocation are valid for reads and
317- // writes for `new_layout.size()` bytes. Also, because the old allocation wasn't yet
318- // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is
319- // safe. The safety contract for `dealloc` must be upheld by the caller.
320- unsafe {
321- ptr:: copy_nonoverlapping ( ptr. as_ptr ( ) , new_ptr. as_mut_ptr ( ) , new_layout. size ( ) ) ;
322- self . dealloc ( ptr, old_layout) ;
323- }
324-
325- Ok ( new_ptr)
326- }
327-
328- /// Creates a "by reference" adaptor for this instance of `AllocRef`.
329- ///
330- /// The returned adaptor also implements `AllocRef` and will simply borrow this.
331- #[ inline( always) ]
332- fn by_ref ( & self ) -> & Self {
333- self
334- }
335- }
336-
337- pub trait AllocRef {
338- unsafe fn alloc ( & mut self , layout : Layout , init : AllocInit ) -> Result < MemoryBlock , ( ) > ;
339- unsafe fn dealloc ( & mut self , ptr : NonNull < u8 > , layout : Layout ) ;
34019 }
34120
34221 #[ derive( Copy , Clone ) ]
34322 pub struct Global ;
344- impl AllocRef for Global {
345- unsafe fn alloc ( & mut self , layout : Layout , _init : AllocInit ) -> Result < MemoryBlock , ( ) > {
346- let ptr = NonNull :: new ( alloc ( layout) ) . ok_or ( ( ) ) ?;
347- Ok ( MemoryBlock {
348- ptr,
349- size : layout. size ( ) ,
350- } )
23+ unsafe impl AllocRef for Global {
24+ fn alloc ( & self , layout : Layout ) -> Result < NonNull < [ u8 ] > , AllocError > {
25+ unsafe {
26+ let ptr = alloc ( layout) ;
27+ if ptr. is_null ( ) {
28+ return Err ( AllocError ) ;
29+ }
30+ let slice = ptr:: slice_from_raw_parts_mut ( ptr, layout. size ( ) ) ;
31+ Ok ( NonNull :: new_unchecked ( slice) )
32+ }
35133 }
352- unsafe fn dealloc ( & mut self , ptr : NonNull < u8 > , layout : Layout ) {
34+ unsafe fn dealloc ( & self , ptr : NonNull < u8 > , layout : Layout ) {
35335 dealloc ( ptr. as_ptr ( ) , layout)
35436 }
35537 }
0 commit comments