@@ -562,6 +562,65 @@ impl<T: ?Sized + Pointable> Atomic<T> {
562
562
} )
563
563
}
564
564
565
+ /// Fetches the pointer, and then applies a function to it that returns a new value.
566
+ /// Returns a `Result` of `Ok(previous_value)` if the function returned `Some`, else `Err(_)`.
567
+ ///
568
+ /// Note that the given function may be called multiple times if the value has been changed by
569
+ /// other threads in the meantime, as long as the function returns `Some(_)`, but the function
570
+ /// will have been applied only once to the stored value.
571
+ ///
572
+ /// `fetch_update` takes two [`Ordering`] arguments to describe the memory
573
+ /// ordering of this operation. The first describes the required ordering for
574
+ /// when the operation finally succeeds while the second describes the
575
+ /// required ordering for loads. These correspond to the success and failure
576
+ /// orderings of [`Atomic::compare_exchange`] respectively.
577
+ ///
578
+ /// Using [`Acquire`] as success ordering makes the store part of this
579
+ /// operation [`Relaxed`], and using [`Release`] makes the final successful
580
+ /// load [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`],
581
+ /// [`Acquire`] or [`Relaxed`] and must be equivalent to or weaker than the
582
+ /// success ordering.
583
+ ///
584
+ /// [`Relaxed`]: Ordering::Relaxed
585
+ /// [`Acquire`]: Ordering::Acquire
586
+ /// [`Release`]: Ordering::Release
587
+ /// [`SeqCst`]: Ordering::SeqCst
588
+ ///
589
+ /// # Examples
590
+ ///
591
+ /// ```
592
+ /// use crossbeam_epoch::{self as epoch, Atomic};
593
+ /// use std::sync::atomic::Ordering::SeqCst;
594
+ ///
595
+ /// let a = Atomic::new(1234);
596
+ /// let guard = &epoch::pin();
597
+ ///
598
+ /// let res1 = a.fetch_update(SeqCst, SeqCst, guard, |x| Some(x.with_tag(1)));
599
+ /// assert!(res1.is_ok());
600
+ ///
601
+ /// let res2 = a.fetch_update(SeqCst, SeqCst, guard, |x| None);
602
+ /// assert!(res2.is_err());
603
+ /// ```
604
+ pub fn fetch_update < ' g , F > (
605
+ & self ,
606
+ set_order : Ordering ,
607
+ fail_order : Ordering ,
608
+ guard : & ' g Guard ,
609
+ mut func : F ,
610
+ ) -> Result < Shared < ' g , T > , Shared < ' g , T > >
611
+ where
612
+ F : FnMut ( Shared < ' g , T > ) -> Option < Shared < ' g , T > > ,
613
+ {
614
+ let mut prev = self . load ( fail_order, guard) ;
615
+ while let Some ( next) = func ( prev) {
616
+ match self . compare_exchange_weak ( prev, next, set_order, fail_order, guard) {
617
+ Ok ( shared) => return Ok ( shared) ,
618
+ Err ( next_prev) => prev = next_prev. current ,
619
+ }
620
+ }
621
+ Err ( prev)
622
+ }
623
+
565
624
/// Stores the pointer `new` (either `Shared` or `Owned`) into the atomic pointer if the current
566
625
/// value is the same as `current`. The tag is also taken into account, so two pointers to the
567
626
/// same object, but with different tags, will not be considered equal.
0 commit comments