mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 15:21:12 +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]]
|
[[package]]
|
||||||
name = "roc_ident"
|
name = "roc_ident"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"arrayvec 0.7.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "roc_linker"
|
name = "roc_linker"
|
||||||
|
@ -3702,6 +3705,7 @@ dependencies = [
|
||||||
name = "roc_module"
|
name = "roc_module"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"arrayvec 0.7.2",
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
|
|
|
@ -4,3 +4,6 @@ version = "0.1.0"
|
||||||
authors = ["The Roc Contributors"]
|
authors = ["The Roc Contributors"]
|
||||||
license = "UPL-1.0"
|
license = "UPL-1.0"
|
||||||
edition = "2018"
|
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
|
/// 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.
|
/// 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)]
|
#[repr(C)]
|
||||||
pub struct IdentStr {
|
pub struct IdentStr {
|
||||||
elements: *const u8,
|
elements: *const u8,
|
||||||
|
@ -30,6 +27,8 @@ pub struct IdentStr {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IdentStr {
|
impl IdentStr {
|
||||||
|
const SMALL_STR_BYTES: usize = std::mem::size_of::<Self>() - 1;
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
let bytes = self.length.to_ne_bytes();
|
let bytes = self.length.to_ne_bytes();
|
||||||
let last_byte = bytes[mem::size_of::<usize>() - 1];
|
let last_byte = bytes[mem::size_of::<usize>() - 1];
|
||||||
|
@ -82,22 +81,39 @@ impl IdentStr {
|
||||||
(self as *const IdentStr).cast()
|
(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 {
|
fn from_str(str: &str) -> Self {
|
||||||
let slice = str.as_bytes();
|
let slice = str.as_bytes();
|
||||||
let len = slice.len();
|
let len = slice.len();
|
||||||
|
|
||||||
match len.cmp(&mem::size_of::<Self>()) {
|
match len.cmp(&mem::size_of::<Self>()) {
|
||||||
Ordering::Less => {
|
Ordering::Less => Self::small_str_from_bytes(slice),
|
||||||
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::Equal => {
|
Ordering::Equal => {
|
||||||
// This fits in a small string, and is exactly long enough to
|
// This fits in a small string, and is exactly long enough to
|
||||||
// take up the entire available struct
|
// take up the entire available struct
|
||||||
|
|
|
@ -14,3 +14,4 @@ bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
static_assertions = "1.1.0"
|
static_assertions = "1.1.0"
|
||||||
snafu = { version = "0.6.10", features = ["backtraces"] }
|
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
|
/// This is used, for example, during canonicalization of an Expr::Closure
|
||||||
/// to generate a unique symbol to refer to that closure.
|
/// to generate a unique symbol to refer to that closure.
|
||||||
pub fn gen_unique(&mut self) -> IdentId {
|
pub fn gen_unique(&mut self) -> IdentId {
|
||||||
// TODO convert this directly from u32 into IdentStr,
|
use std::fmt::Write;
|
||||||
// without allocating an extra string along the way like this.
|
|
||||||
let ident = self.next_generated_name.to_string().into();
|
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;
|
self.next_generated_name += 1;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue