1// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11#![allow(unstable_name_collisions)]
12#![allow(dead_code)]
13#![allow(deprecated)]
14
15//! Memory allocation APIs
16
17use core::cmp;
18use core::fmt;
19use core::mem;
20use core::ptr::{self, NonNull};
21use core::usize;
22
23pub use core::alloc::{Layout, LayoutErr};
24
25fn new_layout_err() -> LayoutErr {
26 Layout::from_size_align(size:1, align:3).unwrap_err()
27}
28
29pub fn handle_alloc_error(layout: Layout) -> ! {
30 panic!("encountered allocation error: {:?}", layout)
31}
32
33pub trait UnstableLayoutMethods {
34 fn padding_needed_for(&self, align: usize) -> usize;
35 fn repeat(&self, n: usize) -> Result<(Layout, usize), LayoutErr>;
36 fn array<T>(n: usize) -> Result<Layout, LayoutErr>;
37}
38
39impl UnstableLayoutMethods for Layout {
40 fn padding_needed_for(&self, align: usize) -> usize {
41 let len = self.size();
42
43 // Rounded up value is:
44 // len_rounded_up = (len + align - 1) & !(align - 1);
45 // and then we return the padding difference: `len_rounded_up - len`.
46 //
47 // We use modular arithmetic throughout:
48 //
49 // 1. align is guaranteed to be > 0, so align - 1 is always
50 // valid.
51 //
52 // 2. `len + align - 1` can overflow by at most `align - 1`,
53 // so the &-mask with `!(align - 1)` will ensure that in the
54 // case of overflow, `len_rounded_up` will itself be 0.
55 // Thus the returned padding, when added to `len`, yields 0,
56 // which trivially satisfies the alignment `align`.
57 //
58 // (Of course, attempts to allocate blocks of memory whose
59 // size and padding overflow in the above manner should cause
60 // the allocator to yield an error anyway.)
61
62 let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
63 len_rounded_up.wrapping_sub(len)
64 }
65
66 fn repeat(&self, n: usize) -> Result<(Layout, usize), LayoutErr> {
67 let padded_size = self
68 .size()
69 .checked_add(self.padding_needed_for(self.align()))
70 .ok_or_else(new_layout_err)?;
71 let alloc_size = padded_size.checked_mul(n).ok_or_else(new_layout_err)?;
72
73 unsafe {
74 // self.align is already known to be valid and alloc_size has been
75 // padded already.
76 Ok((
77 Layout::from_size_align_unchecked(alloc_size, self.align()),
78 padded_size,
79 ))
80 }
81 }
82
83 fn array<T>(n: usize) -> Result<Layout, LayoutErr> {
84 Layout::new::<T>().repeat(n).map(|(k, offs)| {
85 debug_assert!(offs == mem::size_of::<T>());
86 k
87 })
88 }
89}
90
91/// Represents the combination of a starting address and
92/// a total capacity of the returned block.
93// #[unstable(feature = "allocator_api", issue = "32838")]
94#[derive(Debug)]
95pub struct Excess(pub NonNull<u8>, pub usize);
96
97fn size_align<T>() -> (usize, usize) {
98 (mem::size_of::<T>(), mem::align_of::<T>())
99}
100
101/// The `AllocErr` error indicates an allocation failure
102/// that may be due to resource exhaustion or to
103/// something wrong when combining the given input arguments with this
104/// allocator.
105// #[unstable(feature = "allocator_api", issue = "32838")]
106#[derive(Clone, PartialEq, Eq, Debug)]
107pub struct AllocErr;
108
109// (we need this for downstream impl of trait Error)
110// #[unstable(feature = "allocator_api", issue = "32838")]
111impl fmt::Display for AllocErr {
112 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
113 f.write_str(data:"memory allocation failed")
114 }
115}
116
117/// The `CannotReallocInPlace` error is used when `grow_in_place` or
118/// `shrink_in_place` were unable to reuse the given memory block for
119/// a requested layout.
120// #[unstable(feature = "allocator_api", issue = "32838")]
121#[derive(Clone, PartialEq, Eq, Debug)]
122pub struct CannotReallocInPlace;
123
124// #[unstable(feature = "allocator_api", issue = "32838")]
125impl CannotReallocInPlace {
126 pub fn description(&self) -> &str {
127 "cannot reallocate allocator's memory in place"
128 }
129}
130
131// (we need this for downstream impl of trait Error)
132// #[unstable(feature = "allocator_api", issue = "32838")]
133impl fmt::Display for CannotReallocInPlace {
134 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135 write!(f, "{}", self.description())
136 }
137}
138
139/// An implementation of `Alloc` can allocate, reallocate, and
140/// deallocate arbitrary blocks of data described via `Layout`.
141///
142/// Some of the methods require that a memory block be *currently
143/// allocated* via an allocator. This means that:
144///
145/// * the starting address for that memory block was previously
146/// returned by a previous call to an allocation method (`alloc`,
147/// `alloc_zeroed`, `alloc_excess`, `alloc_one`, `alloc_array`) or
148/// reallocation method (`realloc`, `realloc_excess`, or
149/// `realloc_array`), and
150///
151/// * the memory block has not been subsequently deallocated, where
152/// blocks are deallocated either by being passed to a deallocation
153/// method (`dealloc`, `dealloc_one`, `dealloc_array`) or by being
154/// passed to a reallocation method (see above) that returns `Ok`.
155///
156/// A note regarding zero-sized types and zero-sized layouts: many
157/// methods in the `Alloc` trait state that allocation requests
158/// must be non-zero size, or else undefined behavior can result.
159///
160/// * However, some higher-level allocation methods (`alloc_one`,
161/// `alloc_array`) are well-defined on zero-sized types and can
162/// optionally support them: it is left up to the implementor
163/// whether to return `Err`, or to return `Ok` with some pointer.
164///
165/// * If an `Alloc` implementation chooses to return `Ok` in this
166/// case (i.e. the pointer denotes a zero-sized inaccessible block)
167/// then that returned pointer must be considered "currently
168/// allocated". On such an allocator, *all* methods that take
169/// currently-allocated pointers as inputs must accept these
170/// zero-sized pointers, *without* causing undefined behavior.
171///
172/// * In other words, if a zero-sized pointer can flow out of an
173/// allocator, then that allocator must likewise accept that pointer
174/// flowing back into its deallocation and reallocation methods.
175///
176/// Some of the methods require that a layout *fit* a memory block.
177/// What it means for a layout to "fit" a memory block means (or
178/// equivalently, for a memory block to "fit" a layout) is that the
179/// following two conditions must hold:
180///
181/// 1. The block's starting address must be aligned to `layout.align()`.
182///
183/// 2. The block's size must fall in the range `[use_min, use_max]`, where:
184///
185/// * `use_min` is `self.usable_size(layout).0`, and
186///
187/// * `use_max` is the capacity that was (or would have been)
188/// returned when (if) the block was allocated via a call to
189/// `alloc_excess` or `realloc_excess`.
190///
191/// Note that:
192///
193/// * the size of the layout most recently used to allocate the block
194/// is guaranteed to be in the range `[use_min, use_max]`, and
195///
196/// * a lower-bound on `use_max` can be safely approximated by a call to
197/// `usable_size`.
198///
199/// * if a layout `k` fits a memory block (denoted by `ptr`)
200/// currently allocated via an allocator `a`, then it is legal to
201/// use that layout to deallocate it, i.e. `a.dealloc(ptr, k);`.
202///
203/// # Unsafety
204///
205/// The `Alloc` trait is an `unsafe` trait for a number of reasons, and
206/// implementors must ensure that they adhere to these contracts:
207///
208/// * Pointers returned from allocation functions must point to valid memory and
209/// retain their validity until at least the instance of `Alloc` is dropped
210/// itself.
211///
212/// * `Layout` queries and calculations in general must be correct. Callers of
213/// this trait are allowed to rely on the contracts defined on each method,
214/// and implementors must ensure such contracts remain true.
215///
216/// Note that this list may get tweaked over time as clarifications are made in
217/// the future.
218// #[unstable(feature = "allocator_api", issue = "32838")]
219pub unsafe trait Alloc {
220 // (Note: some existing allocators have unspecified but well-defined
221 // behavior in response to a zero size allocation request ;
222 // e.g. in C, `malloc` of 0 will either return a null pointer or a
223 // unique pointer, but will not have arbitrary undefined
224 // behavior.
225 // However in jemalloc for example,
226 // `mallocx(0)` is documented as undefined behavior.)
227
228 /// Returns a pointer meeting the size and alignment guarantees of
229 /// `layout`.
230 ///
231 /// If this method returns an `Ok(addr)`, then the `addr` returned
232 /// will be non-null address pointing to a block of storage
233 /// suitable for holding an instance of `layout`.
234 ///
235 /// The returned block of storage may or may not have its contents
236 /// initialized. (Extension subtraits might restrict this
237 /// behavior, e.g. to ensure initialization to particular sets of
238 /// bit patterns.)
239 ///
240 /// # Safety
241 ///
242 /// This function is unsafe because undefined behavior can result
243 /// if the caller does not ensure that `layout` has non-zero size.
244 ///
245 /// (Extension subtraits might provide more specific bounds on
246 /// behavior, e.g. guarantee a sentinel address or a null pointer
247 /// in response to a zero-size allocation request.)
248 ///
249 /// # Errors
250 ///
251 /// Returning `Err` indicates that either memory is exhausted or
252 /// `layout` does not meet allocator's size or alignment
253 /// constraints.
254 ///
255 /// Implementations are encouraged to return `Err` on memory
256 /// exhaustion rather than panicking or aborting, but this is not
257 /// a strict requirement. (Specifically: it is *legal* to
258 /// implement this trait atop an underlying native allocation
259 /// library that aborts on memory exhaustion.)
260 ///
261 /// Clients wishing to abort computation in response to an
262 /// allocation error are encouraged to call the [`handle_alloc_error`] function,
263 /// rather than directly invoking `panic!` or similar.
264 ///
265 /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
266 unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr>;
267
268 /// Deallocate the memory referenced by `ptr`.
269 ///
270 /// # Safety
271 ///
272 /// This function is unsafe because undefined behavior can result
273 /// if the caller does not ensure all of the following:
274 ///
275 /// * `ptr` must denote a block of memory currently allocated via
276 /// this allocator,
277 ///
278 /// * `layout` must *fit* that block of memory,
279 ///
280 /// * In addition to fitting the block of memory `layout`, the
281 /// alignment of the `layout` must match the alignment used
282 /// to allocate that block of memory.
283 unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout);
284
285 // == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS ==
286 // usable_size
287
288 /// Returns bounds on the guaranteed usable size of a successful
289 /// allocation created with the specified `layout`.
290 ///
291 /// In particular, if one has a memory block allocated via a given
292 /// allocator `a` and layout `k` where `a.usable_size(k)` returns
293 /// `(l, u)`, then one can pass that block to `a.dealloc()` with a
294 /// layout in the size range [l, u].
295 ///
296 /// (All implementors of `usable_size` must ensure that
297 /// `l <= k.size() <= u`)
298 ///
299 /// Both the lower- and upper-bounds (`l` and `u` respectively)
300 /// are provided, because an allocator based on size classes could
301 /// misbehave if one attempts to deallocate a block without
302 /// providing a correct value for its size (i.e., one within the
303 /// range `[l, u]`).
304 ///
305 /// Clients who wish to make use of excess capacity are encouraged
306 /// to use the `alloc_excess` and `realloc_excess` instead, as
307 /// this method is constrained to report conservative values that
308 /// serve as valid bounds for *all possible* allocation method
309 /// calls.
310 ///
311 /// However, for clients that do not wish to track the capacity
312 /// returned by `alloc_excess` locally, this method is likely to
313 /// produce useful results.
314 #[inline]
315 fn usable_size(&self, layout: &Layout) -> (usize, usize) {
316 (layout.size(), layout.size())
317 }
318
319 // == METHODS FOR MEMORY REUSE ==
320 // realloc. alloc_excess, realloc_excess
321
322 /// Returns a pointer suitable for holding data described by
323 /// a new layout with `layout`’s alignment and a size given
324 /// by `new_size`. To
325 /// accomplish this, this may extend or shrink the allocation
326 /// referenced by `ptr` to fit the new layout.
327 ///
328 /// If this returns `Ok`, then ownership of the memory block
329 /// referenced by `ptr` has been transferred to this
330 /// allocator. The memory may or may not have been freed, and
331 /// should be considered unusable (unless of course it was
332 /// transferred back to the caller again via the return value of
333 /// this method).
334 ///
335 /// If this method returns `Err`, then ownership of the memory
336 /// block has not been transferred to this allocator, and the
337 /// contents of the memory block are unaltered.
338 ///
339 /// # Safety
340 ///
341 /// This function is unsafe because undefined behavior can result
342 /// if the caller does not ensure all of the following:
343 ///
344 /// * `ptr` must be currently allocated via this allocator,
345 ///
346 /// * `layout` must *fit* the `ptr` (see above). (The `new_size`
347 /// argument need not fit it.)
348 ///
349 /// * `new_size` must be greater than zero.
350 ///
351 /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`,
352 /// must not overflow (i.e. the rounded value must be less than `usize::MAX`).
353 ///
354 /// (Extension subtraits might provide more specific bounds on
355 /// behavior, e.g. guarantee a sentinel address or a null pointer
356 /// in response to a zero-size allocation request.)
357 ///
358 /// # Errors
359 ///
360 /// Returns `Err` only if the new layout
361 /// does not meet the allocator's size
362 /// and alignment constraints of the allocator, or if reallocation
363 /// otherwise fails.
364 ///
365 /// Implementations are encouraged to return `Err` on memory
366 /// exhaustion rather than panicking or aborting, but this is not
367 /// a strict requirement. (Specifically: it is *legal* to
368 /// implement this trait atop an underlying native allocation
369 /// library that aborts on memory exhaustion.)
370 ///
371 /// Clients wishing to abort computation in response to a
372 /// reallocation error are encouraged to call the [`handle_alloc_error`] function,
373 /// rather than directly invoking `panic!` or similar.
374 ///
375 /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
376 unsafe fn realloc(
377 &mut self,
378 ptr: NonNull<u8>,
379 layout: Layout,
380 new_size: usize,
381 ) -> Result<NonNull<u8>, AllocErr> {
382 let old_size = layout.size();
383
384 if new_size >= old_size {
385 if let Ok(()) = self.grow_in_place(ptr, layout, new_size) {
386 return Ok(ptr);
387 }
388 } else if new_size < old_size {
389 if let Ok(()) = self.shrink_in_place(ptr, layout, new_size) {
390 return Ok(ptr);
391 }
392 }
393
394 // otherwise, fall back on alloc + copy + dealloc.
395 let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
396 let result = self.alloc(new_layout);
397 if let Ok(new_ptr) = result {
398 ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr(), cmp::min(old_size, new_size));
399 self.dealloc(ptr, layout);
400 }
401 result
402 }
403
404 /// Behaves like `alloc`, but also ensures that the contents
405 /// are set to zero before being returned.
406 ///
407 /// # Safety
408 ///
409 /// This function is unsafe for the same reasons that `alloc` is.
410 ///
411 /// # Errors
412 ///
413 /// Returning `Err` indicates that either memory is exhausted or
414 /// `layout` does not meet allocator's size or alignment
415 /// constraints, just as in `alloc`.
416 ///
417 /// Clients wishing to abort computation in response to an
418 /// allocation error are encouraged to call the [`handle_alloc_error`] function,
419 /// rather than directly invoking `panic!` or similar.
420 ///
421 /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
422 unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
423 let size = layout.size();
424 let p = self.alloc(layout);
425 if let Ok(p) = p {
426 ptr::write_bytes(p.as_ptr(), 0, size);
427 }
428 p
429 }
430
431 /// Behaves like `alloc`, but also returns the whole size of
432 /// the returned block. For some `layout` inputs, like arrays, this
433 /// may include extra storage usable for additional data.
434 ///
435 /// # Safety
436 ///
437 /// This function is unsafe for the same reasons that `alloc` is.
438 ///
439 /// # Errors
440 ///
441 /// Returning `Err` indicates that either memory is exhausted or
442 /// `layout` does not meet allocator's size or alignment
443 /// constraints, just as in `alloc`.
444 ///
445 /// Clients wishing to abort computation in response to an
446 /// allocation error are encouraged to call the [`handle_alloc_error`] function,
447 /// rather than directly invoking `panic!` or similar.
448 ///
449 /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
450 unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
451 let usable_size = self.usable_size(&layout);
452 self.alloc(layout).map(|p| Excess(p, usable_size.1))
453 }
454
455 /// Behaves like `realloc`, but also returns the whole size of
456 /// the returned block. For some `layout` inputs, like arrays, this
457 /// may include extra storage usable for additional data.
458 ///
459 /// # Safety
460 ///
461 /// This function is unsafe for the same reasons that `realloc` is.
462 ///
463 /// # Errors
464 ///
465 /// Returning `Err` indicates that either memory is exhausted or
466 /// `layout` does not meet allocator's size or alignment
467 /// constraints, just as in `realloc`.
468 ///
469 /// Clients wishing to abort computation in response to a
470 /// reallocation error are encouraged to call the [`handle_alloc_error`] function,
471 /// rather than directly invoking `panic!` or similar.
472 ///
473 /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
474 unsafe fn realloc_excess(
475 &mut self,
476 ptr: NonNull<u8>,
477 layout: Layout,
478 new_size: usize,
479 ) -> Result<Excess, AllocErr> {
480 let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
481 let usable_size = self.usable_size(&new_layout);
482 self.realloc(ptr, layout, new_size)
483 .map(|p| Excess(p, usable_size.1))
484 }
485
486 /// Attempts to extend the allocation referenced by `ptr` to fit `new_size`.
487 ///
488 /// If this returns `Ok`, then the allocator has asserted that the
489 /// memory block referenced by `ptr` now fits `new_size`, and thus can
490 /// be used to carry data of a layout of that size and same alignment as
491 /// `layout`. (The allocator is allowed to
492 /// expend effort to accomplish this, such as extending the memory block to
493 /// include successor blocks, or virtual memory tricks.)
494 ///
495 /// Regardless of what this method returns, ownership of the
496 /// memory block referenced by `ptr` has not been transferred, and
497 /// the contents of the memory block are unaltered.
498 ///
499 /// # Safety
500 ///
501 /// This function is unsafe because undefined behavior can result
502 /// if the caller does not ensure all of the following:
503 ///
504 /// * `ptr` must be currently allocated via this allocator,
505 ///
506 /// * `layout` must *fit* the `ptr` (see above); note the
507 /// `new_size` argument need not fit it,
508 ///
509 /// * `new_size` must not be less than `layout.size()`,
510 ///
511 /// # Errors
512 ///
513 /// Returns `Err(CannotReallocInPlace)` when the allocator is
514 /// unable to assert that the memory block referenced by `ptr`
515 /// could fit `layout`.
516 ///
517 /// Note that one cannot pass `CannotReallocInPlace` to the `handle_alloc_error`
518 /// function; clients are expected either to be able to recover from
519 /// `grow_in_place` failures without aborting, or to fall back on
520 /// another reallocation method before resorting to an abort.
521 unsafe fn grow_in_place(
522 &mut self,
523 ptr: NonNull<u8>,
524 layout: Layout,
525 new_size: usize,
526 ) -> Result<(), CannotReallocInPlace> {
527 let _ = ptr; // this default implementation doesn't care about the actual address.
528 debug_assert!(new_size >= layout.size());
529 let (_l, u) = self.usable_size(&layout);
530 // _l <= layout.size() [guaranteed by usable_size()]
531 // layout.size() <= new_layout.size() [required by this method]
532 if new_size <= u {
533 Ok(())
534 } else {
535 Err(CannotReallocInPlace)
536 }
537 }
538
539 /// Attempts to shrink the allocation referenced by `ptr` to fit `new_size`.
540 ///
541 /// If this returns `Ok`, then the allocator has asserted that the
542 /// memory block referenced by `ptr` now fits `new_size`, and
543 /// thus can only be used to carry data of that smaller
544 /// layout. (The allocator is allowed to take advantage of this,
545 /// carving off portions of the block for reuse elsewhere.) The
546 /// truncated contents of the block within the smaller layout are
547 /// unaltered, and ownership of block has not been transferred.
548 ///
549 /// If this returns `Err`, then the memory block is considered to
550 /// still represent the original (larger) `layout`. None of the
551 /// block has been carved off for reuse elsewhere, ownership of
552 /// the memory block has not been transferred, and the contents of
553 /// the memory block are unaltered.
554 ///
555 /// # Safety
556 ///
557 /// This function is unsafe because undefined behavior can result
558 /// if the caller does not ensure all of the following:
559 ///
560 /// * `ptr` must be currently allocated via this allocator,
561 ///
562 /// * `layout` must *fit* the `ptr` (see above); note the
563 /// `new_size` argument need not fit it,
564 ///
565 /// * `new_size` must not be greater than `layout.size()`
566 /// (and must be greater than zero),
567 ///
568 /// # Errors
569 ///
570 /// Returns `Err(CannotReallocInPlace)` when the allocator is
571 /// unable to assert that the memory block referenced by `ptr`
572 /// could fit `layout`.
573 ///
574 /// Note that one cannot pass `CannotReallocInPlace` to the `handle_alloc_error`
575 /// function; clients are expected either to be able to recover from
576 /// `shrink_in_place` failures without aborting, or to fall back
577 /// on another reallocation method before resorting to an abort.
578 unsafe fn shrink_in_place(
579 &mut self,
580 ptr: NonNull<u8>,
581 layout: Layout,
582 new_size: usize,
583 ) -> Result<(), CannotReallocInPlace> {
584 let _ = ptr; // this default implementation doesn't care about the actual address.
585 debug_assert!(new_size <= layout.size());
586 let (l, _u) = self.usable_size(&layout);
587 // layout.size() <= _u [guaranteed by usable_size()]
588 // new_layout.size() <= layout.size() [required by this method]
589 if l <= new_size {
590 Ok(())
591 } else {
592 Err(CannotReallocInPlace)
593 }
594 }
595
596 // == COMMON USAGE PATTERNS ==
597 // alloc_one, dealloc_one, alloc_array, realloc_array. dealloc_array
598
599 /// Allocates a block suitable for holding an instance of `T`.
600 ///
601 /// Captures a common usage pattern for allocators.
602 ///
603 /// The returned block is suitable for passing to the
604 /// `alloc`/`realloc` methods of this allocator.
605 ///
606 /// Note to implementors: If this returns `Ok(ptr)`, then `ptr`
607 /// must be considered "currently allocated" and must be
608 /// acceptable input to methods such as `realloc` or `dealloc`,
609 /// *even if* `T` is a zero-sized type. In other words, if your
610 /// `Alloc` implementation overrides this method in a manner
611 /// that can return a zero-sized `ptr`, then all reallocation and
612 /// deallocation methods need to be similarly overridden to accept
613 /// such values as input.
614 ///
615 /// # Errors
616 ///
617 /// Returning `Err` indicates that either memory is exhausted or
618 /// `T` does not meet allocator's size or alignment constraints.
619 ///
620 /// For zero-sized `T`, may return either of `Ok` or `Err`, but
621 /// will *not* yield undefined behavior.
622 ///
623 /// Clients wishing to abort computation in response to an
624 /// allocation error are encouraged to call the [`handle_alloc_error`] function,
625 /// rather than directly invoking `panic!` or similar.
626 ///
627 /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
628 fn alloc_one<T>(&mut self) -> Result<NonNull<T>, AllocErr>
629 where
630 Self: Sized,
631 {
632 let k = Layout::new::<T>();
633 if k.size() > 0 {
634 unsafe { self.alloc(k).map(|p| p.cast()) }
635 } else {
636 Err(AllocErr)
637 }
638 }
639
640 /// Deallocates a block suitable for holding an instance of `T`.
641 ///
642 /// The given block must have been produced by this allocator,
643 /// and must be suitable for storing a `T` (in terms of alignment
644 /// as well as minimum and maximum size); otherwise yields
645 /// undefined behavior.
646 ///
647 /// Captures a common usage pattern for allocators.
648 ///
649 /// # Safety
650 ///
651 /// This function is unsafe because undefined behavior can result
652 /// if the caller does not ensure both:
653 ///
654 /// * `ptr` must denote a block of memory currently allocated via this allocator
655 ///
656 /// * the layout of `T` must *fit* that block of memory.
657 unsafe fn dealloc_one<T>(&mut self, ptr: NonNull<T>)
658 where
659 Self: Sized,
660 {
661 let k = Layout::new::<T>();
662 if k.size() > 0 {
663 self.dealloc(ptr.cast(), k);
664 }
665 }
666
667 /// Allocates a block suitable for holding `n` instances of `T`.
668 ///
669 /// Captures a common usage pattern for allocators.
670 ///
671 /// The returned block is suitable for passing to the
672 /// `alloc`/`realloc` methods of this allocator.
673 ///
674 /// Note to implementors: If this returns `Ok(ptr)`, then `ptr`
675 /// must be considered "currently allocated" and must be
676 /// acceptable input to methods such as `realloc` or `dealloc`,
677 /// *even if* `T` is a zero-sized type. In other words, if your
678 /// `Alloc` implementation overrides this method in a manner
679 /// that can return a zero-sized `ptr`, then all reallocation and
680 /// deallocation methods need to be similarly overridden to accept
681 /// such values as input.
682 ///
683 /// # Errors
684 ///
685 /// Returning `Err` indicates that either memory is exhausted or
686 /// `[T; n]` does not meet allocator's size or alignment
687 /// constraints.
688 ///
689 /// For zero-sized `T` or `n == 0`, may return either of `Ok` or
690 /// `Err`, but will *not* yield undefined behavior.
691 ///
692 /// Always returns `Err` on arithmetic overflow.
693 ///
694 /// Clients wishing to abort computation in response to an
695 /// allocation error are encouraged to call the [`handle_alloc_error`] function,
696 /// rather than directly invoking `panic!` or similar.
697 ///
698 /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
699 fn alloc_array<T>(&mut self, n: usize) -> Result<NonNull<T>, AllocErr>
700 where
701 Self: Sized,
702 {
703 match Layout::array::<T>(n) {
704 Ok(layout) if layout.size() > 0 => unsafe { self.alloc(layout).map(|p| p.cast()) },
705 _ => Err(AllocErr),
706 }
707 }
708
709 /// Reallocates a block previously suitable for holding `n_old`
710 /// instances of `T`, returning a block suitable for holding
711 /// `n_new` instances of `T`.
712 ///
713 /// Captures a common usage pattern for allocators.
714 ///
715 /// The returned block is suitable for passing to the
716 /// `alloc`/`realloc` methods of this allocator.
717 ///
718 /// # Safety
719 ///
720 /// This function is unsafe because undefined behavior can result
721 /// if the caller does not ensure all of the following:
722 ///
723 /// * `ptr` must be currently allocated via this allocator,
724 ///
725 /// * the layout of `[T; n_old]` must *fit* that block of memory.
726 ///
727 /// # Errors
728 ///
729 /// Returning `Err` indicates that either memory is exhausted or
730 /// `[T; n_new]` does not meet allocator's size or alignment
731 /// constraints.
732 ///
733 /// For zero-sized `T` or `n_new == 0`, may return either of `Ok` or
734 /// `Err`, but will *not* yield undefined behavior.
735 ///
736 /// Always returns `Err` on arithmetic overflow.
737 ///
738 /// Clients wishing to abort computation in response to a
739 /// reallocation error are encouraged to call the [`handle_alloc_error`] function,
740 /// rather than directly invoking `panic!` or similar.
741 ///
742 /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
743 unsafe fn realloc_array<T>(
744 &mut self,
745 ptr: NonNull<T>,
746 n_old: usize,
747 n_new: usize,
748 ) -> Result<NonNull<T>, AllocErr>
749 where
750 Self: Sized,
751 {
752 match (Layout::array::<T>(n_old), Layout::array::<T>(n_new)) {
753 (Ok(ref k_old), Ok(ref k_new)) if k_old.size() > 0 && k_new.size() > 0 => {
754 debug_assert!(k_old.align() == k_new.align());
755 self.realloc(ptr.cast(), *k_old, k_new.size())
756 .map(NonNull::cast)
757 }
758 _ => Err(AllocErr),
759 }
760 }
761
762 /// Deallocates a block suitable for holding `n` instances of `T`.
763 ///
764 /// Captures a common usage pattern for allocators.
765 ///
766 /// # Safety
767 ///
768 /// This function is unsafe because undefined behavior can result
769 /// if the caller does not ensure both:
770 ///
771 /// * `ptr` must denote a block of memory currently allocated via this allocator
772 ///
773 /// * the layout of `[T; n]` must *fit* that block of memory.
774 ///
775 /// # Errors
776 ///
777 /// Returning `Err` indicates that either `[T; n]` or the given
778 /// memory block does not meet allocator's size or alignment
779 /// constraints.
780 ///
781 /// Always returns `Err` on arithmetic overflow.
782 unsafe fn dealloc_array<T>(&mut self, ptr: NonNull<T>, n: usize) -> Result<(), AllocErr>
783 where
784 Self: Sized,
785 {
786 match Layout::array::<T>(n) {
787 Ok(k) if k.size() > 0 => {
788 self.dealloc(ptr.cast(), k);
789 Ok(())
790 }
791 _ => Err(AllocErr),
792 }
793 }
794}
795