about summary refs log tree commit diff
path: root/src/libsyntax/ptr.rs
diff options
context:
space:
mode:
authorkennytm <kennytm@gmail.com>2018-12-01 01:05:56 +0800
committerkennytm <kennytm@gmail.com>2018-12-01 02:03:41 +0800
commitce00a8dd4d795f47a38a207af861a2cffcee7256 (patch)
tree2a6bc7612cd2b92a7766bc2d227617734106464b /src/libsyntax/ptr.rs
parentf7c407eb8bc9413d9d1449eeda9710715ad255a2 (diff)
parent6674db48872c1b84fe3ac3feb94b8d3e0ee82b24 (diff)
downloadrust-ce00a8dd4d795f47a38a207af861a2cffcee7256.tar.gz
rust-ce00a8dd4d795f47a38a207af861a2cffcee7256.zip
Rollup merge of #56268 - nnethercote:fold_opt_expr-recycle, r=petrochenkov
Reuse the `P` in `InvocationCollector::fold_{,opt_}expr`.

This requires adding a new method, `P::filter_map`.

This commit reduces instruction counts for various benchmarks by up to
0.7%.
Diffstat (limited to 'src/libsyntax/ptr.rs')
-rw-r--r--src/libsyntax/ptr.rs28
1 files changed, 25 insertions, 3 deletions
diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs
index bb47d9b535b..9fbc64758da 100644
--- a/src/libsyntax/ptr.rs
+++ b/src/libsyntax/ptr.rs
@@ -72,7 +72,7 @@ impl<T: 'static> P<T> {
         *self.ptr
     }
 
-    /// Transform the inner value, consuming `self` and producing a new `P<T>`.
+    /// Produce a new `P<T>` from `self` without reallocating.
     pub fn map<F>(mut self, f: F) -> P<T> where
         F: FnOnce(T) -> T,
     {
@@ -88,8 +88,30 @@ impl<T: 'static> P<T> {
             ptr::write(p, f(ptr::read(p)));
 
             // Recreate self from the raw pointer.
-            P {
-                ptr: Box::from_raw(p)
+            P { ptr: Box::from_raw(p) }
+        }
+    }
+
+    /// Optionally produce a new `P<T>` from `self` without reallocating.
+    pub fn filter_map<F>(mut self, f: F) -> Option<P<T>> where
+        F: FnOnce(T) -> Option<T>,
+    {
+        let p: *mut T = &mut *self.ptr;
+
+        // Leak self in case of panic.
+        // FIXME(eddyb) Use some sort of "free guard" that
+        // only deallocates, without dropping the pointee,
+        // in case the call the `f` below ends in a panic.
+        mem::forget(self);
+
+        unsafe {
+            if let Some(v) = f(ptr::read(p)) {
+                ptr::write(p, v);
+
+                // Recreate self from the raw pointer.
+                Some(P { ptr: Box::from_raw(p) })
+            } else {
+                None
             }
         }
     }