@@ -2,354 +2,36 @@ pub use self::inner::*;
2
2
3
3
#[ cfg( feature = "nightly" ) ]
4
4
mod inner {
5
- pub use crate :: alloc:: alloc:: { AllocRef , Global } ;
5
+ pub use crate :: alloc:: alloc:: { AllocError , AllocRef , Global } ;
6
6
}
7
7
8
8
#[ cfg( not( feature = "nightly" ) ) ]
9
9
mod inner {
10
- use crate :: alloc:: alloc:: { alloc, dealloc, AllocErr , Layout } ;
10
+ use crate :: alloc:: alloc:: { alloc, dealloc, Layout } ;
11
+ use core:: ptr;
11
12
use core:: ptr:: NonNull ;
12
13
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 ;
23
15
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" ) ]
81
16
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 > ;
137
18
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 ) ;
340
19
}
341
20
342
21
#[ derive( Copy , Clone ) ]
343
22
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
+ }
351
33
}
352
- unsafe fn dealloc ( & mut self , ptr : NonNull < u8 > , layout : Layout ) {
34
+ unsafe fn dealloc ( & self , ptr : NonNull < u8 > , layout : Layout ) {
353
35
dealloc ( ptr. as_ptr ( ) , layout)
354
36
}
355
37
}
0 commit comments