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 | |
17 | use core::cmp; |
18 | use core::fmt; |
19 | use core::mem; |
20 | use core::ptr::{self, NonNull}; |
21 | use core::usize; |
22 | |
23 | pub use core::alloc::{Layout, LayoutErr}; |
24 | |
25 | fn new_layout_err() -> LayoutErr { |
26 | Layout::from_size_align(size:1, align:3).unwrap_err() |
27 | } |
28 | |
29 | pub fn handle_alloc_error(layout: Layout) -> ! { |
30 | panic!("encountered allocation error: {:?}" , layout) |
31 | } |
32 | |
33 | pub 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 | |
39 | impl 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)] |
95 | pub struct Excess(pub NonNull<u8>, pub usize); |
96 | |
97 | fn 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)] |
107 | pub struct AllocErr; |
108 | |
109 | // (we need this for downstream impl of trait Error) |
110 | // #[unstable(feature = "allocator_api", issue = "32838")] |
111 | impl 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)] |
122 | pub struct CannotReallocInPlace; |
123 | |
124 | // #[unstable(feature = "allocator_api", issue = "32838")] |
125 | impl 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")] |
133 | impl 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")] |
219 | pub 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 | |