@@ -1480,6 +1480,11 @@ where
1480
1480
}
1481
1481
1482
1482
impl < A > RawTableInner < A > {
1483
+ /// Creates a new empty hash table without allocating any memory.
1484
+ ///
1485
+ /// In effect this returns a table with exactly 1 bucket. However we can
1486
+ /// leave the data pointer dangling since that bucket is never accessed
1487
+ /// due to our load factor forcing us to always have at least 1 free bucket.
1483
1488
#[ inline]
1484
1489
const fn new_in ( alloc : A ) -> Self {
1485
1490
Self {
@@ -1494,6 +1499,18 @@ impl<A> RawTableInner<A> {
1494
1499
}
1495
1500
1496
1501
impl < A : Allocator + Clone > RawTableInner < A > {
1502
+ /// Allocates a new [`RawTableInner`] with the given number of buckets.
1503
+ /// The control bytes and buckets are left uninitialized.
1504
+ ///
1505
+ /// # Safety
1506
+ ///
1507
+ /// The caller of this function must ensure that the `buckets` is power of two
1508
+ /// and also initialize all control bytes of the length `self.bucket_mask + 1 +
1509
+ /// Group::WIDTH` with the [`EMPTY`] bytes.
1510
+ ///
1511
+ /// See also [`Allocator`] API for other safety concerns.
1512
+ ///
1513
+ /// [`Allocator`]: https://doc.rust-lang.org/alloc/alloc/trait.Allocator.html
1497
1514
#[ cfg_attr( feature = "inline-more" , inline) ]
1498
1515
unsafe fn new_uninitialized (
1499
1516
alloc : A ,
@@ -1514,6 +1531,7 @@ impl<A: Allocator + Clone> RawTableInner<A> {
1514
1531
Err ( _) => return Err ( fallibility. alloc_err ( layout) ) ,
1515
1532
} ;
1516
1533
1534
+ // SAFETY: null pointer will be caught in above check
1517
1535
let ctrl = NonNull :: new_unchecked ( ptr. as_ptr ( ) . add ( ctrl_offset) ) ;
1518
1536
Ok ( Self {
1519
1537
ctrl,
@@ -1524,6 +1542,10 @@ impl<A: Allocator + Clone> RawTableInner<A> {
1524
1542
} )
1525
1543
}
1526
1544
1545
+ /// Attempts to allocate a new [`RawTableInner`] with at least enough
1546
+ /// capacity for inserting the given number of elements without reallocating.
1547
+ ///
1548
+ /// All the control bytes are initialized with the [`EMPTY`] bytes.
1527
1549
#[ inline]
1528
1550
fn fallible_with_capacity (
1529
1551
alloc : A ,
@@ -1534,11 +1556,16 @@ impl<A: Allocator + Clone> RawTableInner<A> {
1534
1556
if capacity == 0 {
1535
1557
Ok ( Self :: new_in ( alloc) )
1536
1558
} else {
1559
+ // SAFETY: We checked that we could successfully allocate the new table, and then
1560
+ // initialized all control bytes with the constant `EMPTY` byte.
1537
1561
unsafe {
1538
1562
let buckets =
1539
1563
capacity_to_buckets ( capacity) . ok_or_else ( || fallibility. capacity_overflow ( ) ) ?;
1540
1564
1541
1565
let result = Self :: new_uninitialized ( alloc, table_layout, buckets, fallibility) ?;
1566
+ // SAFETY: We checked that the table is allocated and therefore the table already has
1567
+ // `self.bucket_mask + 1 + Group::WIDTH` number of control bytes (see TableLayout::calculate_layout_for)
1568
+ // so writing `self.num_ctrl_bytes() == bucket_mask + 1 + Group::WIDTH` bytes is safe.
1542
1569
result. ctrl ( 0 ) . write_bytes ( EMPTY , result. num_ctrl_bytes ( ) ) ;
1543
1570
1544
1571
Ok ( result)
0 commit comments