@@ -7,6 +7,7 @@ use core::{
77 mem:: { self , ManuallyDrop , MaybeUninit } ,
88 ops:: { Deref , DerefMut , Index , IndexMut } ,
99 ptr,
10+ ptr:: NonNull ,
1011 slice:: SliceIndex ,
1112} ;
1213
@@ -51,7 +52,7 @@ union AlignedHeader<H, T> {
5152/// All of the data, like our header `OurHeaderType { a: 2 }`, the length of the vector: `2`,
5253/// and the contents of the vector `['x', 'z']` resides on the other side of the pointer.
5354pub struct HeaderVec < H , T > {
54- ptr : * mut AlignedHeader < H , T > ,
55+ ptr : NonNull < AlignedHeader < H , T > > ,
5556}
5657
5758impl < H , T > HeaderVec < H , T > {
@@ -64,10 +65,10 @@ impl<H, T> HeaderVec<H, T> {
6465 let layout = Self :: layout ( capacity) ;
6566 let ptr = unsafe { alloc:: alloc:: alloc ( layout) } as * mut AlignedHeader < H , T > ;
6667
67- // Handle out-of-memory.
68- if ptr . is_null ( ) {
68+ let Some ( ptr ) = NonNull :: new ( ptr ) else {
69+ // Handle out-of-memory.
6970 alloc:: alloc:: handle_alloc_error ( layout) ;
70- }
71+ } ;
7172
7273 // Create self.
7374 let mut this = Self { ptr } ;
@@ -172,14 +173,14 @@ impl<H, T> HeaderVec<H, T> {
172173 /// This is useful to check if two nodes are the same. Use it with [`HeaderVec::is`].
173174 #[ inline( always) ]
174175 pub fn ptr ( & self ) -> * const ( ) {
175- self . ptr as * const ( )
176+ self . ptr . as_ptr ( ) as * const ( )
176177 }
177178
178179 /// This is used to check if this is the `HeaderVec` that corresponds to the given pointer.
179180 /// This is useful for updating weak references after [`HeaderVec::push`] returns the pointer.
180181 #[ inline( always) ]
181182 pub fn is ( & self , ptr : * const ( ) ) -> bool {
182- self . ptr as * const ( ) == ptr
183+ self . ptr . as_ptr ( ) as * const ( ) == ptr
183184 }
184185
185186 /// Create a (dangerous) weak reference to the `HeaderVec`. This is useful to be able
@@ -254,8 +255,8 @@ impl<H, T> HeaderVec<H, T> {
254255 self . shrink_to ( len)
255256 }
256257
257- /// Resize the vector to have at least room for `additional` more elements.
258- /// does exact resizing if `exact` is true.
258+ /// Resize the vector to least `requested_capacity` elements.
259+ /// Does exact resizing if `exact` is true.
259260 ///
260261 /// Returns `Some(*const ())` if the memory was moved to a new location.
261262 ///
@@ -264,7 +265,8 @@ impl<H, T> HeaderVec<H, T> {
264265 /// `requested_capacity` must be greater or equal than `self.len()`
265266 #[ cold]
266267 unsafe fn resize_cold ( & mut self , requested_capacity : usize , exact : bool ) -> Option < * const ( ) > {
267- // For efficiency we do only a debug_assert here
268+ // For efficiency we do only a debug_assert here, this is a internal unsafe function
269+ // it's contract should be already enforced by the caller which is under our control
268270 debug_assert ! (
269271 self . len_exact( ) <= requested_capacity,
270272 "requested capacity is less than current length"
@@ -299,19 +301,21 @@ impl<H, T> HeaderVec<H, T> {
299301 // Reallocate the pointer.
300302 let ptr = unsafe {
301303 alloc:: alloc:: realloc (
302- self . ptr as * mut u8 ,
304+ self . ptr . as_ptr ( ) as * mut u8 ,
303305 Self :: layout ( old_capacity) ,
304306 Self :: elems_to_mem_bytes ( new_capacity) ,
305307 ) as * mut AlignedHeader < H , T >
306308 } ;
307- // Handle out-of-memory.
308- if ptr. is_null ( ) {
309+
310+ let Some ( ptr) = NonNull :: new ( ptr) else {
311+ // Handle out-of-memory.
309312 alloc:: alloc:: handle_alloc_error ( Self :: layout ( new_capacity) ) ;
310- }
313+ } ;
314+
311315 // Check if the new pointer is different than the old one.
312316 let previous_pointer = if ptr != self . ptr {
313317 // Give the user the old pointer so they can update everything.
314- Some ( self . ptr as * const ( ) )
318+ Some ( self . ptr ( ) )
315319 } else {
316320 None
317321 } ;
@@ -413,7 +417,7 @@ impl<H, T> HeaderVec<H, T> {
413417 const fn offset ( ) -> usize {
414418 // The first location, in units of size_of::<T>(), that is after the header
415419 // It's the end of the header, rounded up to the nearest size_of::<T>()
416- mem:: size_of :: < AlignedHeader < H , T > > ( ) / mem:: size_of :: < T > ( )
420+ ( mem:: size_of :: < AlignedHeader < H , T > > ( ) - 1 ) / mem:: size_of :: < T > ( ) + 1
417421 }
418422
419423 /// Compute the number of elements (in units of T) to allocate for a given capacity.
@@ -441,13 +445,13 @@ impl<H, T> HeaderVec<H, T> {
441445 /// Gets the pointer to the start of the slice.
442446 #[ inline( always) ]
443447 fn start_ptr ( & self ) -> * const T {
444- unsafe { ( self . ptr as * const T ) . add ( Self :: offset ( ) ) }
448+ unsafe { ( self . ptr . as_ptr ( ) as * const T ) . add ( Self :: offset ( ) ) }
445449 }
446450
447451 /// Gets the pointer to the start of the slice.
448452 #[ inline( always) ]
449453 fn start_ptr_mut ( & mut self ) -> * mut T {
450- unsafe { ( self . ptr as * mut T ) . add ( Self :: offset ( ) ) }
454+ unsafe { ( self . ptr . as_ptr ( ) as * mut T ) . add ( Self :: offset ( ) ) }
451455 }
452456
453457 /// Gets the pointer to the end of the slice. This returns a mutable pointer to
@@ -460,13 +464,13 @@ impl<H, T> HeaderVec<H, T> {
460464 #[ inline( always) ]
461465 fn header ( & self ) -> & HeaderVecHeader < H > {
462466 // The beginning of the memory is always the header.
463- unsafe { & * ( self . ptr as * const HeaderVecHeader < H > ) }
467+ unsafe { & * ( self . ptr . as_ptr ( ) as * const HeaderVecHeader < H > ) }
464468 }
465469
466470 #[ inline( always) ]
467471 fn header_mut ( & mut self ) -> & mut HeaderVecHeader < H > {
468472 // The beginning of the memory is always the header.
469- unsafe { & mut * ( self . ptr as * mut HeaderVecHeader < H > ) }
473+ unsafe { & mut * ( self . ptr . as_ptr ( ) as * mut HeaderVecHeader < H > ) }
470474 }
471475}
472476
@@ -494,8 +498,52 @@ impl<H, T: Clone> HeaderVec<H, T> {
494498
495499#[ cfg( feature = "atomic_append" ) ]
496500/// The atomic append API is only enabled when the `atomic_append` feature flag is set (which
497- /// is the default).
501+ /// is the default). The [`push_atomic()`] or [`extend_from_slice_atomic()`] methods then
502+ /// become available and some internals using atomic operations.
503+ ///
504+ /// This API implements interior-mutable appending to a shared `HeaderVec`. To other threads
505+ /// the appended elements are either not seen or all seen at once. Without additional
506+ /// synchronization these appends are racy but memory safe. The intention behind this API is to
507+ /// provide facilities for building other container abstractions the benefit from the shared
508+ /// non blocking nature while being unaffected from the racy semantics or provide synchronization
509+ /// on their own (Eg: reference counted data, interners, streaming parsers, etc). Since the
510+ /// `HeaderVec` is a shared object and we have only a `&self`, it can not be reallocated and moved,
511+ /// therefore appending can only be done within the reserved capacity.
512+ ///
513+ /// # Safety
514+ ///
515+ /// Only one single thread must try to [`push_atomic()`] or [`extend_from_slice_atomic()`] the
516+ /// `HeaderVec` at at time using the atomic append API's. The actual implementations of this
517+ /// restriction is left to the caller. This can be done by mutexes or guard objects. Or
518+ /// simply by staying single threaded or ensuring somehow else that there is only a single
519+ /// thread using the atomic_appending API.
498520impl < H , T > HeaderVec < H , T > {
521+ /// Atomically adds an item to the end of the list without reallocation.
522+ ///
523+ /// # Errors
524+ ///
525+ /// If the vector is full, the item is returned.
526+ ///
527+ /// # Safety
528+ ///
529+ /// There must be only one thread calling this method at any time. Synchronization has to
530+ /// be provided by the user.
531+ pub unsafe fn push_atomic ( & self , item : T ) -> Result < ( ) , T > {
532+ // relaxed is good enough here because this should be the only thread calling this method.
533+ let len = self . len_atomic_relaxed ( ) ;
534+ if len < self . capacity ( ) {
535+ unsafe {
536+ core:: ptr:: write ( self . end_ptr_atomic_mut ( ) , item) ;
537+ } ;
538+ let len_again = self . len_atomic_add_release ( 1 ) ;
539+ // in debug builds we check for races, the chance to catch these are still pretty minimal
540+ debug_assert_eq ! ( len_again, len, "len was updated by another thread" ) ;
541+ Ok ( ( ) )
542+ } else {
543+ Err ( item)
544+ }
545+ }
546+
499547 /// Get the length of the vector with `Ordering::Acquire`. This ensures that the length is
500548 /// properly synchronized after it got atomically updated.
501549 #[ inline( always) ]
@@ -521,48 +569,12 @@ impl<H, T> HeaderVec<H, T> {
521569 self . header ( ) . len . fetch_add ( n, Ordering :: Release )
522570 }
523571
524- #[ inline( always) ]
525- pub fn is_empty_atomic_acquire ( & self ) -> bool {
526- self . len_atomic_acquire ( ) == 0
527- }
528-
529- #[ inline( always) ]
530- pub fn as_slice_atomic_acquire ( & self ) -> & [ T ] {
531- unsafe { core:: slice:: from_raw_parts ( self . start_ptr ( ) , self . len_atomic_acquire ( ) ) }
532- }
533-
534572 /// Gets the pointer to the end of the slice. This returns a mutable pointer to
535573 /// uninitialized memory behind the last element.
536574 #[ inline( always) ]
537575 fn end_ptr_atomic_mut ( & self ) -> * mut T {
538576 unsafe { self . start_ptr ( ) . add ( self . len_atomic_acquire ( ) ) as * mut T }
539577 }
540-
541- /// Atomically adds an item to the end of the list without reallocation.
542- ///
543- /// # Errors
544- ///
545- /// If the vector is full, the item is returned.
546- ///
547- /// # Safety
548- ///
549- /// There must be only one thread calling this method at any time. Synchronization has to
550- /// be provided by the user.
551- pub unsafe fn push_atomic ( & self , item : T ) -> Result < ( ) , T > {
552- // relaxed is good enough here because this should be the only thread calling this method.
553- let len = self . len_atomic_relaxed ( ) ;
554- if len < self . capacity ( ) {
555- unsafe {
556- core:: ptr:: write ( self . end_ptr_atomic_mut ( ) , item) ;
557- } ;
558- let len_again = self . len_atomic_add_release ( 1 ) ;
559- // in debug builds we check for races, the chance to catch these are still pretty minimal
560- debug_assert_eq ! ( len_again, len, "len was updated by another thread" ) ;
561- Ok ( ( ) )
562- } else {
563- Err ( item)
564- }
565- }
566578}
567579
568580#[ cfg( feature = "atomic_append" ) ]
@@ -607,7 +619,7 @@ impl<H, T> Drop for HeaderVec<H, T> {
607619 for ix in 0 ..self . len_exact ( ) {
608620 ptr:: drop_in_place ( self . start_ptr_mut ( ) . add ( ix) ) ;
609621 }
610- alloc:: alloc:: dealloc ( self . ptr as * mut u8 , Self :: layout ( self . capacity ( ) ) ) ;
622+ alloc:: alloc:: dealloc ( self . ptr . as_ptr ( ) as * mut u8 , Self :: layout ( self . capacity ( ) ) ) ;
611623 }
612624 }
613625}
0 commit comments