Skip to content

Commit b61d9c2

Browse files
committed
Fix nightly feature
1 parent 9370f0f commit b61d9c2

File tree

2 files changed

+17
-335
lines changed

2 files changed

+17
-335
lines changed

src/raw/alloc.rs

Lines changed: 16 additions & 334 deletions
Original file line numberDiff line numberDiff line change
@@ -2,354 +2,36 @@ pub use self::inner::*;
22

33
#[cfg(feature = "nightly")]
44
mod 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"))]
99
mod 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
}

src/raw/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ impl<T, A: AllocRef + Clone> RawTable<T, A> {
424424
/// The control bytes are left uninitialized.
425425
#[cfg_attr(feature = "inline-more", inline)]
426426
unsafe fn new_uninitialized(
427-
mut alloc: A,
427+
alloc: A,
428428
buckets: usize,
429429
fallability: Fallibility,
430430
) -> Result<Self, TryReserveError> {

0 commit comments

Comments
 (0)