@@ -54,10 +54,8 @@ pub const CAPACITY: usize = 2 * B - 1;
54
54
/// `NodeHeader` because we do not want unnecessary padding between `len` and the keys.
55
55
/// Crucially, `NodeHeader` can be safely transmuted to different K and V. (This is exploited
56
56
/// by `as_header`.)
57
- /// See `into_key_slice` for an explanation of K2. K2 cannot be safely transmuted around
58
- /// because the size of `NodeHeader` depends on its alignment!
59
57
#[ repr( C ) ]
60
- struct NodeHeader < K , V , K2 = ( ) > {
58
+ struct NodeHeader < K , V > {
61
59
/// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`.
62
60
/// This either points to an actual node or is null.
63
61
parent : * const InternalNode < K , V > ,
@@ -72,9 +70,6 @@ struct NodeHeader<K, V, K2 = ()> {
72
70
/// This next to `parent_idx` to encourage the compiler to join `len` and
73
71
/// `parent_idx` into the same 32-bit word, reducing space overhead.
74
72
len : u16 ,
75
-
76
- /// See `into_key_slice`.
77
- keys_start : [ K2 ; 0 ] ,
78
73
}
79
74
#[ repr( C ) ]
80
75
struct LeafNode < K , V > {
@@ -128,7 +123,7 @@ unsafe impl Sync for NodeHeader<(), ()> {}
128
123
// We use just a header in order to save space, since no operation on an empty tree will
129
124
// ever take a pointer past the first key.
130
125
static EMPTY_ROOT_NODE : NodeHeader < ( ) , ( ) > =
131
- NodeHeader { parent : ptr:: null ( ) , parent_idx : MaybeUninit :: uninit ( ) , len : 0 , keys_start : [ ] } ;
126
+ NodeHeader { parent : ptr:: null ( ) , parent_idx : MaybeUninit :: uninit ( ) , len : 0 } ;
132
127
133
128
/// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden
134
129
/// behind `BoxedNode`s to prevent dropping uninitialized keys and values. Any pointer to an
@@ -390,14 +385,13 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
390
385
}
391
386
392
387
/// Borrows a view into the keys stored in the node.
393
- /// Works on all possible nodes, including the shared root.
394
- pub fn keys ( & self ) -> & [ K ] {
388
+ /// The caller must ensure that the node is not the shared root.
389
+ pub unsafe fn keys ( & self ) -> & [ K ] {
395
390
self . reborrow ( ) . into_key_slice ( )
396
391
}
397
392
398
393
/// Borrows a view into the values stored in the node.
399
394
/// The caller must ensure that the node is not the shared root.
400
- /// This function is not public, so doesn't have to support shared roots like `keys` does.
401
395
fn vals ( & self ) -> & [ V ] {
402
396
self . reborrow ( ) . into_val_slice ( )
403
397
}
@@ -515,7 +509,6 @@ impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
515
509
}
516
510
517
511
/// The caller must ensure that the node is not the shared root.
518
- /// This function is not public, so doesn't have to support shared roots like `keys` does.
519
512
fn keys_mut ( & mut self ) -> & mut [ K ] {
520
513
unsafe { self . reborrow_mut ( ) . into_key_slice_mut ( ) }
521
514
}
@@ -527,48 +520,11 @@ impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
527
520
}
528
521
529
522
impl < ' a , K : ' a , V : ' a , Type > NodeRef < marker:: Immut < ' a > , K , V , Type > {
530
- fn into_key_slice ( self ) -> & ' a [ K ] {
531
- // We have to be careful here because we might be pointing to the shared root.
532
- // In that case, we must not create an `&LeafNode`. We could just return
533
- // an empty slice whenever the length is 0 (this includes the shared root),
534
- // but we want to avoid that run-time check.
535
- // Instead, we create a slice pointing into the node whenever possible.
536
- // We can sometimes do this even for the shared root, as the slice will be
537
- // empty and `NodeHeader` contains an empty `keys_start` array.
538
- // We cannot *always* do this because:
539
- // - `keys_start` is not correctly typed because we want `NodeHeader`'s size to
540
- // not depend on the alignment of `K` (needed because `as_header` should be safe).
541
- // For this reason, `NodeHeader` has this `K2` parameter (that's usually `()`
542
- // and hence just adds a size-0-align-1 field, not affecting layout).
543
- // If the correctly typed header is more highly aligned than the allocated header,
544
- // we cannot transmute safely.
545
- // - Even if we can transmute, the offset of a correctly typed `keys_start` might
546
- // be different and outside the bounds of the allocated header!
547
- // So we do an alignment check and a size check first, that will be evaluated
548
- // at compile-time, and only do any run-time check in the rare case that
549
- // the compile-time checks signal danger.
550
- if ( mem:: align_of :: < NodeHeader < K , V , K > > ( ) > mem:: align_of :: < NodeHeader < K , V > > ( )
551
- || mem:: size_of :: < NodeHeader < K , V , K > > ( ) != mem:: size_of :: < NodeHeader < K , V > > ( ) )
552
- && self . is_shared_root ( )
553
- {
554
- & [ ]
555
- } else {
556
- // If we are a `LeafNode<K, V>`, we can always transmute to
557
- // `NodeHeader<K, V, K>` and `keys_start` always has the same offset
558
- // as the actual `keys`.
559
- // Thanks to the checks above, we know that we can transmute to
560
- // `NodeHeader<K, V, K>` and that `keys_start` will be
561
- // in-bounds of some allocation even if this is the shared root!
562
- // (We might be one-past-the-end, but that is allowed by LLVM.)
563
- // Thus we can use `NodeHeader<K, V, K>`
564
- // to compute the pointer where the keys start.
565
- // This entire hack will become unnecessary once
566
- // <https://github.com/rust-lang/rfcs/pull/2582> lands, then we can just take a raw
567
- // pointer to the `keys` field of `*const InternalNode<K, V>`.
568
- let header = self . as_header ( ) as * const _ as * const NodeHeader < K , V , K > ;
569
- let keys = unsafe { & ( * header) . keys_start as * const _ as * const K } ;
570
- unsafe { slice:: from_raw_parts ( keys, self . len ( ) ) }
571
- }
523
+ /// The caller must ensure that the node is not the shared root.
524
+ unsafe fn into_key_slice ( self ) -> & ' a [ K ] {
525
+ debug_assert ! ( !self . is_shared_root( ) ) ;
526
+ // We cannot be the shared root, so `as_leaf` is okay.
527
+ slice:: from_raw_parts ( MaybeUninit :: first_ptr ( & self . as_leaf ( ) . keys ) , self . len ( ) )
572
528
}
573
529
574
530
/// The caller must ensure that the node is not the shared root.
@@ -578,9 +534,10 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
578
534
unsafe { slice:: from_raw_parts ( MaybeUninit :: first_ptr ( & self . as_leaf ( ) . vals ) , self . len ( ) ) }
579
535
}
580
536
537
+ /// The caller must ensure that the node is not the shared root.
581
538
fn into_slices ( self ) -> ( & ' a [ K ] , & ' a [ V ] ) {
582
539
let k = unsafe { ptr:: read ( & self ) } ;
583
- ( k. into_key_slice ( ) , self . into_val_slice ( ) )
540
+ ( unsafe { k. into_key_slice ( ) } , self . into_val_slice ( ) )
584
541
}
585
542
}
586
543
0 commit comments