about summary refs log tree commit diff
path: root/src/liballoc
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-10-15 09:32:06 -0700
committerGitHub <noreply@github.com>2016-10-15 09:32:06 -0700
commit5bfe10740168eb8213101c827302b4c45b1b5b74 (patch)
tree87a212efaa05f0461b26e463fdeabb8718b0c8c3 /src/liballoc
parent8e05e7ee3c19a5594b79d67c8390cef78970be7c (diff)
parent348c3fb0851c155f06768e54c44990d39b6eb142 (diff)
Auto merge of #37132 - petrochenkov:intern, r=alexcrichton
Get rid of double indirection in string interner
Diffstat (limited to 'src/liballoc')
-rw-r--r--src/liballoc/rc.rs28
1 files changed, 27 insertions, 1 deletions
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index 699f777138d..740d13c4762 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -230,13 +230,14 @@ use core::hash::{Hash, Hasher};
 use core::intrinsics::{abort, assume};
 use core::marker;
 use core::marker::Unsize;
-use core::mem::{self, align_of_val, forget, size_of_val, uninitialized};
+use core::mem::{self, align_of_val, forget, size_of, size_of_val, uninitialized};
 use core::ops::Deref;
 use core::ops::CoerceUnsized;
 use core::ptr::{self, Shared};
 use core::convert::From;
 
 use heap::deallocate;
+use raw_vec::RawVec;
 
 struct RcBox<T: ?Sized> {
     strong: Cell<usize>,
@@ -365,6 +366,31 @@ impl<T> Rc<T> {
     }
 }
 
+impl Rc<str> {
+    /// Constructs a new `Rc<str>` from a string slice.
+    #[doc(hidden)]
+    #[unstable(feature = "rustc_private",
+               reason = "for internal use in rustc",
+               issue = "0")]
+    pub fn __from_str(value: &str) -> Rc<str> {
+        unsafe {
+            // Allocate enough space for `RcBox<str>`.
+            let aligned_len = 2 + (value.len() + size_of::<usize>() - 1) / size_of::<usize>();
+            let vec = RawVec::<usize>::with_capacity(aligned_len);
+            let ptr = vec.ptr();
+            forget(vec);
+            // Initialize fields of `RcBox<str>`.
+            *ptr.offset(0) = 1; // strong: Cell::new(1)
+            *ptr.offset(1) = 1; // weak: Cell::new(1)
+            ptr::copy_nonoverlapping(value.as_ptr(), ptr.offset(2) as *mut u8, value.len());
+            // Combine the allocation address and the string length into a fat pointer to `RcBox`.
+            let rcbox_ptr: *mut RcBox<str> = mem::transmute([ptr as usize, value.len()]);
+            assert!(aligned_len * size_of::<usize>() == size_of_val(&*rcbox_ptr));
+            Rc { ptr: Shared::new(rcbox_ptr) }
+        }
+    }
+}
+
 impl<T: ?Sized> Rc<T> {
     /// Creates a new [`Weak`][weak] pointer to this value.
     ///