mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 23:04:49 +00:00
remove allocation in Symbol creation
This commit is contained in:
parent
9cb6261a4d
commit
813b22a106
5 changed files with 43 additions and 17 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -3647,6 +3647,9 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "roc_ident"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"arrayvec 0.7.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roc_linker"
|
||||
|
@ -3702,6 +3705,7 @@ dependencies = [
|
|||
name = "roc_module"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"arrayvec 0.7.2",
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
"roc_collections",
|
||||
|
|
|
@ -4,3 +4,6 @@ version = "0.1.0"
|
|||
authors = ["The Roc Contributors"]
|
||||
license = "UPL-1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
arrayvec = "0.7.2"
|
||||
|
|
|
@ -20,9 +20,6 @@ use std::os::raw::c_char;
|
|||
/// a UTF-8 string). This design works on little-endian targets, but a different
|
||||
/// design for storing length might be necessary on big-endian targets.
|
||||
|
||||
// For big-endian, field order must be swapped!
|
||||
// Otherwise, the discriminant byte will be in the wrong place.
|
||||
#[cfg(target_endian = "little")]
|
||||
#[repr(C)]
|
||||
pub struct IdentStr {
|
||||
elements: *const u8,
|
||||
|
@ -30,6 +27,8 @@ pub struct IdentStr {
|
|||
}
|
||||
|
||||
impl IdentStr {
|
||||
const SMALL_STR_BYTES: usize = std::mem::size_of::<Self>() - 1;
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
let bytes = self.length.to_ne_bytes();
|
||||
let last_byte = bytes[mem::size_of::<usize>() - 1];
|
||||
|
@ -82,22 +81,39 @@ impl IdentStr {
|
|||
(self as *const IdentStr).cast()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
const fn small_str_from_bytes(slice: &[u8]) -> Self {
|
||||
assert!(slice.len() <= Self::SMALL_STR_BYTES);
|
||||
|
||||
let len = slice.len();
|
||||
let mut bytes = [0; mem::size_of::<Self>()];
|
||||
|
||||
// Copy the bytes from the slice into bytes.
|
||||
// while because for/Iterator does not work in const context
|
||||
let mut i = 0;
|
||||
while i < len {
|
||||
bytes[i] = slice[i];
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// Write length and small string bit to last byte of length.
|
||||
bytes[Self::SMALL_STR_BYTES] = u8::MAX - len as u8;
|
||||
|
||||
unsafe { mem::transmute::<[u8; mem::size_of::<Self>()], Self>(bytes) }
|
||||
}
|
||||
|
||||
pub fn from_array_string(
|
||||
array_string: arrayvec::ArrayString<{ Self::SMALL_STR_BYTES }>,
|
||||
) -> Self {
|
||||
Self::small_str_from_bytes(array_string.as_bytes())
|
||||
}
|
||||
|
||||
fn from_str(str: &str) -> Self {
|
||||
let slice = str.as_bytes();
|
||||
let len = slice.len();
|
||||
|
||||
match len.cmp(&mem::size_of::<Self>()) {
|
||||
Ordering::Less => {
|
||||
let mut bytes = [0; mem::size_of::<Self>()];
|
||||
|
||||
// Copy the bytes from the slice into bytes.
|
||||
bytes[..len].copy_from_slice(slice);
|
||||
|
||||
// Write length and small string bit to last byte of length.
|
||||
bytes[mem::size_of::<usize>() * 2 - 1] = u8::MAX - len as u8;
|
||||
|
||||
unsafe { mem::transmute::<[u8; mem::size_of::<Self>()], Self>(bytes) }
|
||||
}
|
||||
Ordering::Less => Self::small_str_from_bytes(slice),
|
||||
Ordering::Equal => {
|
||||
// This fits in a small string, and is exactly long enough to
|
||||
// take up the entire available struct
|
||||
|
|
|
@ -14,3 +14,4 @@ bumpalo = { version = "3.8.0", features = ["collections"] }
|
|||
lazy_static = "1.4.0"
|
||||
static_assertions = "1.1.0"
|
||||
snafu = { version = "0.6.10", features = ["backtraces"] }
|
||||
arrayvec = "0.7.2"
|
||||
|
|
|
@ -634,9 +634,11 @@ impl IdentIds {
|
|||
/// This is used, for example, during canonicalization of an Expr::Closure
|
||||
/// to generate a unique symbol to refer to that closure.
|
||||
pub fn gen_unique(&mut self) -> IdentId {
|
||||
// TODO convert this directly from u32 into IdentStr,
|
||||
// without allocating an extra string along the way like this.
|
||||
let ident = self.next_generated_name.to_string().into();
|
||||
use std::fmt::Write;
|
||||
|
||||
let mut temp: arrayvec::ArrayString<15> = arrayvec::ArrayString::new();
|
||||
write!(temp, "{}", self.next_generated_name).unwrap();
|
||||
let ident = Ident(IdentStr::from_array_string(temp));
|
||||
|
||||
self.next_generated_name += 1;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue