@@ -493,7 +493,7 @@ impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
493
493
494
494
/// Returns a raw ptr to avoid asserting exclusive access to the entire node.
495
495
fn as_leaf_mut ( & mut self ) -> * mut LeafNode < K , V > {
496
- // We are mutable, so we cannot be the root, so accessing this as a leaf is okay.
496
+ // We are mutable, so we cannot be the shared root, so accessing this as a leaf is okay.
497
497
self . node . as_ptr ( )
498
498
}
499
499
@@ -514,33 +514,37 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
514
514
// but we want to avoid that run-time check.
515
515
// Instead, we create a slice pointing into the node whenever possible.
516
516
// We can sometimes do this even for the shared root, as the slice will be
517
- // empty. We cannot *always* do this because if the type is too highly
518
- // aligned, the offset of `keys` in a "full node" might be outside the bounds
519
- // of the header! So we do an alignment check first, that will be
520
- // evaluated at compile-time, and only do any run-time check in the rare case
521
- // that the alignment is very big.
522
- if mem:: align_of :: < K > ( ) > mem:: align_of :: < LeafNode < ( ) , ( ) > > ( ) && self . is_shared_root ( ) {
517
+ // empty and `NodeHeader` contains an empty `keys_start` array.
518
+ // We cannot *always* do this because:
519
+ // - `keys_start` is not correctly typed because we want `NodeHeader`'s size to
520
+ // not depend on the alignment of `K` (needed because `as_header` should be safe).
521
+ // For this reason, `NodeHeader` has this `K2` parameter (that's usually `()`
522
+ // and hence just adds a size-0-align-1 field, not affecting layout).
523
+ // If the correctly typed header is more highly aligned than the allocated header,
524
+ // we cannot transmute safely.
525
+ // - Even if we can transmute, the offset of a correctly typed `keys_start` might
526
+ // be different and outside the bounds of the allocated header!
527
+ // So we do an alignment check and a size check first, that will be evaluated
528
+ // at compile-time, and only do any run-time check in the rare case that
529
+ // the compile-time checks signal danger.
530
+ if ( mem:: align_of :: < NodeHeader < K , V , K > > ( ) > mem:: align_of :: < NodeHeader < K , V > > ( )
531
+ || mem:: size_of :: < NodeHeader < K , V , K > > ( ) != mem:: size_of :: < NodeHeader < K , V > > ( ) )
532
+ && self . is_shared_root ( )
533
+ {
523
534
& [ ]
524
535
} else {
525
- // Thanks to the alignment check above, we know that `keys` will be
536
+ // If we are a `LeafNode<K, V>`, we can always transmute to
537
+ // `NodeHeader<K, V, K>` and `keys_start` always has the same offset
538
+ // as the actual `keys`.
539
+ // Thanks to the checks above, we know that we can transmute to
540
+ // `NodeHeader<K, V, K>` and that `keys_start` will be
526
541
// in-bounds of some allocation even if this is the shared root!
527
542
// (We might be one-past-the-end, but that is allowed by LLVM.)
528
- // Getting the pointer is tricky though. `NodeHeader` does not have a `keys`
529
- // field because we want its size to not depend on the alignment of `K`
530
- // (needed because `as_header` should be safe). We cannot call `as_leaf`
531
- // because we might be the shared root.
532
- // For this reason, `NodeHeader` has this `K2` parameter (that's usually `()`
533
- // and hence just adds a size-0-align-1 field, not affecting layout).
534
- // We know that we can transmute `NodeHeader<K, V, ()>` to `NodeHeader<K, V, K>`
535
- // because we did the alignment check above, and hence `NodeHeader<K, V, K>`
536
- // is not bigger than `NodeHeader<K, V, ()>`! Then we can use `NodeHeader<K, V, K>`
543
+ // Thus we can use `NodeHeader<K, V, K>`
537
544
// to compute the pointer where the keys start.
538
545
// This entire hack will become unnecessary once
539
546
// <https://github.com/rust-lang/rfcs/pull/2582> lands, then we can just take a raw
540
547
// pointer to the `keys` field of `*const InternalNode<K, V>`.
541
-
542
- // This is a non-debug-assert because it can be completely compile-time evaluated.
543
- assert ! ( mem:: size_of:: <NodeHeader <K , V >>( ) == mem:: size_of:: <NodeHeader <K , V , K >>( ) ) ;
544
548
let header = self . as_header ( ) as * const _ as * const NodeHeader < K , V , K > ;
545
549
let keys = unsafe { & ( * header) . keys_start as * const _ as * const K } ;
546
550
unsafe { slice:: from_raw_parts ( keys, self . len ( ) ) }
@@ -549,7 +553,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
549
553
550
554
fn into_val_slice ( self ) -> & ' a [ V ] {
551
555
debug_assert ! ( !self . is_shared_root( ) ) ;
552
- // We cannot be the root, so `as_leaf` is okay
556
+ // We cannot be the shared root, so `as_leaf` is okay
553
557
unsafe { slice:: from_raw_parts ( MaybeUninit :: first_ptr ( & self . as_leaf ( ) . vals ) , self . len ( ) ) }
554
558
}
555
559
@@ -567,9 +571,11 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
567
571
}
568
572
569
573
fn into_key_slice_mut ( mut self ) -> & ' a mut [ K ] {
570
- // Same as for `into_key_slice` above, we try to avoid a run-time check
571
- // (the alignment comparison will usually be performed at compile-time).
572
- if mem:: align_of :: < K > ( ) > mem:: align_of :: < LeafNode < ( ) , ( ) > > ( ) && self . is_shared_root ( ) {
574
+ // Same as for `into_key_slice` above, we try to avoid a run-time check.
575
+ if ( mem:: align_of :: < NodeHeader < K , V , K > > ( ) > mem:: align_of :: < NodeHeader < K , V > > ( )
576
+ || mem:: size_of :: < NodeHeader < K , V , K > > ( ) != mem:: size_of :: < NodeHeader < K , V > > ( ) )
577
+ && self . is_shared_root ( )
578
+ {
573
579
& mut [ ]
574
580
} else {
575
581
unsafe {
0 commit comments