Skip to content

Commit 17572d4

Browse files
committed
Auto merge of #148 - cuviper:nonnull, r=Amanieu
Use NonNull for the Bucket pointer `NonNull` has the same variance as `*const`, but also enables niche layout optimizations for things like `Option<Bucket<T>>`.
2 parents eaaa366 + 31e56a0 commit 17572d4

File tree

1 file changed

+26
-17
lines changed

1 file changed

+26
-17
lines changed

src/raw/mod.rs

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,8 @@ fn calculate_layout<T>(buckets: usize) -> Option<(Layout, usize)> {
257257
/// is a ZST, then we instead track the index of the element in the table so
258258
/// that `erase` works properly.
259259
pub struct Bucket<T> {
260-
// Using *const for variance
261-
ptr: *const T,
260+
// Using `NonNull` for variance and niche layout
261+
ptr: NonNull<T>,
262262
}
263263

264264
// This Send impl is needed for rayon support. This is safe since Bucket is
@@ -274,31 +274,44 @@ impl<T> Clone for Bucket<T> {
274274

275275
impl<T> Bucket<T> {
276276
#[cfg_attr(feature = "inline-more", inline)]
277-
unsafe fn from_base_index(base: *const T, index: usize) -> Self {
277+
unsafe fn from_base_index(base: NonNull<T>, index: usize) -> Self {
278278
let ptr = if mem::size_of::<T>() == 0 {
279-
index as *const T
279+
// won't overflow because index must be less than length
280+
(index + 1) as *mut T
280281
} else {
281-
base.add(index)
282+
base.as_ptr().add(index)
282283
};
283-
Self { ptr }
284+
Self {
285+
ptr: NonNull::new_unchecked(ptr),
286+
}
287+
}
288+
#[cfg_attr(feature = "inline-more", inline)]
289+
unsafe fn to_base_index(&self, base: NonNull<T>) -> usize {
290+
if mem::size_of::<T>() == 0 {
291+
self.ptr.as_ptr() as usize - 1
292+
} else {
293+
offset_from(self.ptr.as_ptr(), base.as_ptr())
294+
}
284295
}
285296
#[cfg_attr(feature = "inline-more", inline)]
286297
pub unsafe fn as_ptr(&self) -> *mut T {
287298
if mem::size_of::<T>() == 0 {
288299
// Just return an arbitrary ZST pointer which is properly aligned
289300
mem::align_of::<T>() as *mut T
290301
} else {
291-
self.ptr as *mut T
302+
self.ptr.as_ptr()
292303
}
293304
}
294305
#[cfg_attr(feature = "inline-more", inline)]
295306
unsafe fn add(&self, offset: usize) -> Self {
296307
let ptr = if mem::size_of::<T>() == 0 {
297-
(self.ptr as usize + offset) as *const T
308+
(self.ptr.as_ptr() as usize + offset) as *mut T
298309
} else {
299-
self.ptr.add(offset)
310+
self.ptr.as_ptr().add(offset)
300311
};
301-
Self { ptr }
312+
Self {
313+
ptr: NonNull::new_unchecked(ptr),
314+
}
302315
}
303316
#[cfg_attr(feature = "inline-more", inline)]
304317
pub unsafe fn drop(&self) {
@@ -428,11 +441,7 @@ impl<T> RawTable<T> {
428441
/// Returns the index of a bucket from a `Bucket`.
429442
#[cfg_attr(feature = "inline-more", inline)]
430443
pub unsafe fn bucket_index(&self, bucket: &Bucket<T>) -> usize {
431-
if mem::size_of::<T>() == 0 {
432-
bucket.ptr as usize
433-
} else {
434-
offset_from(bucket.ptr, self.data.as_ptr())
435-
}
444+
bucket.to_base_index(self.data)
436445
}
437446

438447
/// Returns a pointer to a control byte.
@@ -447,7 +456,7 @@ impl<T> RawTable<T> {
447456
pub unsafe fn bucket(&self, index: usize) -> Bucket<T> {
448457
debug_assert_ne!(self.bucket_mask, 0);
449458
debug_assert!(index < self.buckets());
450-
Bucket::from_base_index(self.data.as_ptr(), index)
459+
Bucket::from_base_index(self.data, index)
451460
}
452461

453462
/// Erases an element from the table without dropping it.
@@ -936,7 +945,7 @@ impl<T> RawTable<T> {
936945
/// struct, we have to make the `iter` method unsafe.
937946
#[cfg_attr(feature = "inline-more", inline)]
938947
pub unsafe fn iter(&self) -> RawIter<T> {
939-
let data = Bucket::from_base_index(self.data.as_ptr(), 0);
948+
let data = Bucket::from_base_index(self.data, 0);
940949
RawIter {
941950
iter: RawIterRange::new(self.ctrl.as_ptr(), data, self.buckets()),
942951
items: self.items,

0 commit comments

Comments
 (0)