1
1
use core:: alloc:: Layout ;
2
- use core:: convert:: { TryFrom , TryInto } ;
2
+ use core:: convert:: TryInto ;
3
3
use core:: mem;
4
4
use core:: mem:: { align_of, size_of} ;
5
5
use core:: ptr:: NonNull ;
@@ -13,42 +13,20 @@ pub struct HoleList {
13
13
pub ( crate ) first : Hole , // dummy
14
14
}
15
15
16
- pub struct Cursor {
16
+ pub ( crate ) struct Cursor {
17
17
prev : NonNull < Hole > ,
18
18
hole : NonNull < Hole > ,
19
19
}
20
20
21
- enum Position < ' a > {
22
- BeforeCurrent ,
23
- BetweenCurrentNext {
24
- curr : & ' a Hole ,
25
- next : & ' a Hole ,
26
- } ,
27
- AfterBoth ,
28
- AfterCurrentNoNext ,
29
- }
30
-
31
21
impl Cursor {
32
22
fn next ( mut self ) -> Option < Self > {
33
23
unsafe {
34
- if let Some ( nhole ) = self . hole . as_mut ( ) . next {
35
- Some ( Cursor {
24
+ self . hole . as_mut ( ) . next . map ( |nhole| {
25
+ Cursor {
36
26
prev : self . hole ,
37
27
hole : nhole,
38
- } )
39
- } else {
40
- None
41
- }
42
- }
43
- }
44
-
45
- fn peek_next ( & self ) -> Option < & Hole > {
46
- unsafe {
47
- if let Some ( nhole) = self . hole . as_ref ( ) . next {
48
- Some ( nhole. as_ref ( ) )
49
- } else {
50
- None
51
- }
28
+ }
29
+ } )
52
30
}
53
31
}
54
32
@@ -170,7 +148,6 @@ impl Cursor {
170
148
171
149
// As of now, the old `Hole` is no more. We are about to replace it with one or more of
172
150
// the front padding, the allocation, and the back padding.
173
- drop ( hole) ;
174
151
175
152
match ( front_padding, back_padding) {
176
153
( None , None ) => {
@@ -249,7 +226,7 @@ impl HoleList {
249
226
}
250
227
}
251
228
252
- pub fn cursor ( & mut self ) -> Option < Cursor > {
229
+ pub ( crate ) fn cursor ( & mut self ) -> Option < Cursor > {
253
230
if let Some ( hole) = self . first . next {
254
231
Some ( Cursor {
255
232
hole,
@@ -326,9 +303,7 @@ impl HoleList {
326
303
size = Self :: min_size ( ) ;
327
304
}
328
305
let size = align_up_size ( size, mem:: align_of :: < Hole > ( ) ) ;
329
- let layout = Layout :: from_size_align ( size, layout. align ( ) ) . unwrap ( ) ;
330
-
331
- layout
306
+ Layout :: from_size_align ( size, layout. align ( ) ) . unwrap ( )
332
307
}
333
308
334
309
/// Searches the list for a big enough hole.
@@ -396,35 +371,13 @@ pub(crate) struct Hole {
396
371
pub next : Option < NonNull < Hole > > ,
397
372
}
398
373
399
- impl Hole {
400
- /// Returns basic information about the hole.
401
- fn info ( & mut self ) -> HoleInfo {
402
- HoleInfo {
403
- addr : self as * mut _ as * mut u8 ,
404
- size : self . size ,
405
- }
406
- }
407
-
408
- fn addr_u8 ( & self ) -> * const u8 {
409
- self as * const Hole as * const u8
410
- }
411
- }
412
-
413
374
/// Basic information about a hole.
414
375
#[ derive( Debug , Clone , Copy ) ]
415
376
struct HoleInfo {
416
377
addr : * mut u8 ,
417
378
size : usize ,
418
379
}
419
380
420
- /// The result returned by `split_hole` and `allocate_first_fit`. Contains the address and size of
421
- /// the allocation (in the `info` field), and the front and back padding.
422
- struct Allocation {
423
- info : HoleInfo ,
424
- front_padding : Option < HoleInfo > ,
425
- back_padding : Option < HoleInfo > ,
426
- }
427
-
428
381
unsafe fn make_hole ( addr : * mut u8 , size : usize ) -> NonNull < Hole > {
429
382
let hole_addr = addr. cast :: < Hole > ( ) ;
430
383
debug_assert_eq ! ( addr as usize % align_of:: <Hole >( ) , 0 ) ;
@@ -482,12 +435,11 @@ impl Cursor {
482
435
}
483
436
}
484
437
485
-
486
- // Merge the current node with an IMMEDIATELY FOLLOWING next node
487
- fn try_merge_next_two ( self ) {
438
+ // Merge the current node with up to n following nodes
439
+ fn try_merge_next_n ( self , max : usize ) {
488
440
let Cursor { prev : _, mut hole } = self ;
489
441
490
- for _ in 0 ..2 {
442
+ for _ in 0 ..max {
491
443
// Is there a next node?
492
444
let mut next = if let Some ( next) = unsafe { hole. as_mut ( ) } . next . as_ref ( ) {
493
445
* next
@@ -496,13 +448,12 @@ impl Cursor {
496
448
} ;
497
449
498
450
// Can we directly merge these? e.g. are they touching?
499
- //
500
- // TODO(AJM): Should "touching" also include deltas <= node size?
501
451
let hole_u8 = hole. as_ptr ( ) . cast :: < u8 > ( ) ;
502
452
let hole_sz = unsafe { hole. as_ref ( ) . size } ;
503
453
let next_u8 = next. as_ptr ( ) . cast :: < u8 > ( ) ;
454
+ let end = hole_u8. wrapping_add ( hole_sz) ;
504
455
505
- let touching = hole_u8 . wrapping_add ( hole_sz ) == next_u8;
456
+ let touching = end == next_u8;
506
457
507
458
if touching {
508
459
let next_sz;
@@ -531,56 +482,55 @@ impl Cursor {
531
482
/// Frees the allocation given by `(addr, size)`. It starts at the given hole and walks the list to
532
483
/// find the correct place (the list is sorted by address).
533
484
fn deallocate ( list : & mut HoleList , addr : * mut u8 , size : usize ) {
534
- // Start off by just making this allocation a hole.
485
+ // Start off by just making this allocation a hole where it stands.
486
+ // We'll attempt to merge it with other nodes once we figure out where
487
+ // it should live
535
488
let hole = unsafe { make_hole ( addr, size) } ;
536
489
490
+ // Now, try to get a cursor to the list - this only works if we have at least
491
+ // one non-"dummy" hole in the list
537
492
let cursor = if let Some ( cursor) = list. cursor ( ) {
538
493
cursor
539
494
} else {
540
- // Oh hey, there are no holes at all. That means this just becomes the only hole!
495
+ // Oh hey, there are no "real" holes at all. That means this just
496
+ // becomes the only "real" hole!
541
497
list. first . next = Some ( hole) ;
542
498
return ;
543
499
} ;
544
500
545
501
// First, check if we can just insert this node at the top of the list. If the
546
502
// insertion succeeded, then our cursor now points to the NEW node, behind the
547
503
// previous location the cursor was pointing to.
548
- let cursor = match cursor. try_insert_back ( hole) {
504
+ //
505
+ // Otherwise, our cursor will point at the current non-"dummy" head of the list
506
+ let ( cursor, n) = match cursor. try_insert_back ( hole) {
549
507
Ok ( cursor) => {
550
- // Yup! It lives at the front of the list. Hooray!
551
- cursor
508
+ // Yup! It lives at the front of the list. Hooray! Attempt to merge
509
+ // it with just ONE next node, since it is at the front of the list
510
+ ( cursor, 1 )
552
511
} ,
553
512
Err ( mut cursor) => {
554
513
// Nope. It lives somewhere else. Advance the list until we find its home
555
514
while let Err ( ( ) ) = cursor. try_insert_after ( hole) {
556
515
cursor = cursor. next ( ) . unwrap ( ) ;
557
516
}
558
- cursor
517
+ // Great! We found a home for it, our cursor is now JUST BEFORE the new
518
+ // node we inserted, so we need to try to merge up to twice: One to combine
519
+ // the current node to the new node, then once more to combine the new node
520
+ // with the node after that.
521
+ ( cursor, 2 )
559
522
} ,
560
523
} ;
561
524
562
525
// We now need to merge up to two times to combine the current node with the next
563
526
// two nodes.
564
- cursor. try_merge_next_two ( ) ;
565
- }
566
-
567
-
568
- /// Identity function to ease moving of references.
569
- ///
570
- /// By default, references are reborrowed instead of moved (equivalent to `&mut *reference`). This
571
- /// function forces a move.
572
- ///
573
- /// for more information, see section “id Forces References To Move” in:
574
- /// https://bluss.github.io/rust/fun/2015/10/11/stuff-the-identity-function-does/
575
- fn move_helper < T > ( x : T ) -> T {
576
- x
527
+ cursor. try_merge_next_n ( n) ;
577
528
}
578
529
579
530
#[ cfg( test) ]
580
531
pub mod test {
581
- use super :: * ;
582
532
use core:: alloc:: Layout ;
583
- use std:: mem:: { align_of , size_of , MaybeUninit } ;
533
+ use std:: mem:: MaybeUninit ;
584
534
use std:: prelude:: v1:: * ;
585
535
use crate :: Heap ;
586
536
@@ -612,16 +562,13 @@ pub mod test {
612
562
#[ test]
613
563
fn cursor ( ) {
614
564
let mut heap = new_heap ( ) ;
615
- let curs = heap. holes_mut ( ) . cursor ( ) . unwrap ( ) ;
565
+ let curs = heap. holes . cursor ( ) . unwrap ( ) ;
616
566
// This is the "dummy" node
617
567
assert_eq ! ( curs. previous( ) . size, 0 ) ;
618
568
// This is the "full" heap
619
569
assert_eq ! ( curs. current( ) . size, 1000 ) ;
620
570
// There is no other hole
621
- assert ! ( curs. peek_next( ) . is_none( ) ) ;
622
-
623
- let reqd = Layout :: from_size_align ( 256 , 1 ) . unwrap ( ) ;
624
- let _ = curs. split_current ( reqd) . map_err ( drop) . unwrap ( ) ;
571
+ assert ! ( curs. next( ) . is_none( ) ) ;
625
572
}
626
573
627
574
#[ test]
0 commit comments