@@ -1072,6 +1072,11 @@ where
1072
1072
}
1073
1073
1074
1074
impl < A > RawTableInner < A > {
1075
+ /// Creates a new empty hash table without allocating any memory.
1076
+ ///
1077
+ /// In effect this returns a table with exactly 1 bucket. However we can
1078
+ /// leave the data pointer dangling since that bucket is never written to
1079
+ /// due to our load factor forcing us to always have at least 1 free bucket.
1075
1080
#[ inline]
1076
1081
const fn new_in ( alloc : A ) -> Self {
1077
1082
Self {
@@ -1086,6 +1091,18 @@ impl<A> RawTableInner<A> {
1086
1091
}
1087
1092
1088
1093
impl < A : Allocator + Clone > RawTableInner < A > {
1094
+ /// Allocates a new [`RawTableInner`] with the given number of buckets.
1095
+ /// The control bytes are left uninitialized.
1096
+ ///
1097
+ /// # Safety
1098
+ ///
1099
+ /// The caller of this function must ensure that the `buckets` is power of two
1100
+ /// and also initialize all control bytes of the length `self.bucket_mask + 1 +
1101
+ /// Group::WIDTH` with the [`EMPTY`] bytes.
1102
+ ///
1103
+ /// See also [`Allocator`] API for other safety concerns.
1104
+ ///
1105
+ /// [`Allocator`]: https://doc.rust-lang.org/alloc/alloc/trait.Allocator.html
1089
1106
#[ cfg_attr( feature = "inline-more" , inline) ]
1090
1107
unsafe fn new_uninitialized (
1091
1108
alloc : A ,
@@ -1106,6 +1123,7 @@ impl<A: Allocator + Clone> RawTableInner<A> {
1106
1123
Err ( _) => return Err ( fallibility. alloc_err ( layout) ) ,
1107
1124
} ;
1108
1125
1126
+ // SAFETY: null pointer will be caught in above check
1109
1127
let ctrl = NonNull :: new_unchecked ( ptr. as_ptr ( ) . add ( ctrl_offset) ) ;
1110
1128
Ok ( Self {
1111
1129
ctrl,
@@ -1116,6 +1134,10 @@ impl<A: Allocator + Clone> RawTableInner<A> {
1116
1134
} )
1117
1135
}
1118
1136
1137
+ /// Attempts to allocate a new [`RawTableInner`] with at least enough
1138
+ /// capacity for inserting the given number of elements without reallocating.
1139
+ ///
1140
+ /// All the control bytes are initialized with the [`EMPTY`] bytes.
1119
1141
#[ inline]
1120
1142
fn fallible_with_capacity (
1121
1143
alloc : A ,
@@ -1126,11 +1148,16 @@ impl<A: Allocator + Clone> RawTableInner<A> {
1126
1148
if capacity == 0 {
1127
1149
Ok ( Self :: new_in ( alloc) )
1128
1150
} else {
1151
+ // SAFETY: We checked that we could successfully allocate the new table, and then
1152
+ // initialized all control bytes with the constant `EMPTY` byte.
1129
1153
unsafe {
1130
1154
let buckets =
1131
1155
capacity_to_buckets ( capacity) . ok_or_else ( || fallibility. capacity_overflow ( ) ) ?;
1132
1156
1133
1157
let result = Self :: new_uninitialized ( alloc, table_layout, buckets, fallibility) ?;
1158
+ // SAFETY: We checked that the table is allocated and therefore the table already has
1159
+ // `self.bucket_mask + 1 + Group::WIDTH` number of control bytes (see TableLayout::calculate_layout_for)
1160
+ // so writing `self.num_ctrl_bytes() == bucket_mask + 1 + Group::WIDTH` bytes is safe.
1134
1161
result. ctrl ( 0 ) . write_bytes ( EMPTY , result. num_ctrl_bytes ( ) ) ;
1135
1162
1136
1163
Ok ( result)
0 commit comments