Add soa crate

This commit is contained in:
Richard Feldman 2024-10-09 22:55:20 -04:00
parent 7df1142455
commit ece46a28d0
No known key found for this signature in database
GPG key ID: 5DE4EE30BB738EDF
7 changed files with 201 additions and 10 deletions

8
Cargo.lock generated
View file

@ -3178,6 +3178,7 @@ dependencies = [
"roc_parse", "roc_parse",
"roc_region", "roc_region",
"roc_serialize", "roc_serialize",
"soa",
"static_assertions", "static_assertions",
"ven_pretty", "ven_pretty",
] ]
@ -3577,6 +3578,13 @@ version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
[[package]]
name = "soa"
version = "0.0.1"
dependencies = [
"pretty_assertions",
]
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.4.9" version = "0.4.9"

View file

@ -22,6 +22,7 @@ members = [
"crates/valgrind", "crates/valgrind",
"crates/tracing", "crates/tracing",
"crates/utils/*", "crates/utils/*",
"crates/soa",
"crates/docs", "crates/docs",
"crates/docs_cli", "crates/docs_cli",
"crates/linker", "crates/linker",
@ -74,6 +75,8 @@ inkwell = { git = "https://github.com/roc-lang/inkwell", branch = "inkwell-llvm-
"llvm16-0", "llvm16-0",
] } ] }
soa = { path = "crates/soa" }
arrayvec = "0.7.2" # update roc_std/Cargo.toml on change arrayvec = "0.7.2" # update roc_std/Cargo.toml on change
backtrace = "0.3.67" backtrace = "0.3.67"
base64-url = "1.4.13" base64-url = "1.4.13"
@ -137,7 +140,10 @@ maplit = "1.0.2"
memmap2 = "0.5.10" memmap2 = "0.5.10"
mimalloc = { version = "0.1.34", default-features = false } mimalloc = { version = "0.1.34", default-features = false }
nonempty = "0.8.1" nonempty = "0.8.1"
object = { version = "0.32.2", default-features = false, features = ["read", "write"] } object = { version = "0.32.2", default-features = false, features = [
"read",
"write",
] }
packed_struct = "0.10.1" packed_struct = "0.10.1"
page_size = "0.5.0" page_size = "0.5.0"
palette = "0.6.1" palette = "0.6.1"

View file

@ -12,7 +12,7 @@ use roc_module::{
use roc_types::{ use roc_types::{
subs::{ subs::{
self, AliasVariables, Descriptor, GetSubsSlice, OptVariable, RecordFields, Subs, SubsIndex, self, AliasVariables, Descriptor, GetSubsSlice, OptVariable, RecordFields, Subs, SubsIndex,
SubsSlice, TupleElems, UnionLambdas, UnionTags, Variable, VariableSubsSlice, SubsSlice, TupleElems, UnionLambdas, UnionTags, Variable, VariableSlice,
}, },
types::{RecordField, Uls}, types::{RecordField, Uls},
}; };
@ -162,7 +162,7 @@ impl<'a> CopyEnv for AcrossSubs<'a> {
fn clone_field_names(&mut self, field_names: SubsSlice<Lowercase>) -> SubsSlice<Lowercase> { fn clone_field_names(&mut self, field_names: SubsSlice<Lowercase>) -> SubsSlice<Lowercase> {
SubsSlice::extend_new( SubsSlice::extend_new(
&mut self.target.field_names, &mut self.target.field_names,
self.source.get_subs_slice(field_names).iter().cloned(), self.source.get_slice(field_names).iter().cloned(),
) )
} }
@ -173,10 +173,7 @@ impl<'a> CopyEnv for AcrossSubs<'a> {
) -> SubsSlice<usize> { ) -> SubsSlice<usize> {
SubsSlice::extend_new( SubsSlice::extend_new(
&mut self.target.tuple_elem_indices, &mut self.target.tuple_elem_indices,
self.source self.source.get_slice(tuple_elem_indices).iter().cloned(),
.get_subs_slice(tuple_elem_indices)
.iter()
.cloned(),
) )
} }
@ -184,7 +181,7 @@ impl<'a> CopyEnv for AcrossSubs<'a> {
fn clone_tag_names(&mut self, tag_names: SubsSlice<TagName>) -> SubsSlice<TagName> { fn clone_tag_names(&mut self, tag_names: SubsSlice<TagName>) -> SubsSlice<TagName> {
SubsSlice::extend_new( SubsSlice::extend_new(
&mut self.target.tag_names, &mut self.target.tag_names,
self.source.get_subs_slice(tag_names).iter().cloned(), self.source.get_slice(tag_names).iter().cloned(),
) )
} }
@ -192,7 +189,7 @@ impl<'a> CopyEnv for AcrossSubs<'a> {
fn clone_lambda_names(&mut self, lambda_names: SubsSlice<Symbol>) -> SubsSlice<Symbol> { fn clone_lambda_names(&mut self, lambda_names: SubsSlice<Symbol>) -> SubsSlice<Symbol> {
SubsSlice::extend_new( SubsSlice::extend_new(
&mut self.target.symbol_names, &mut self.target.symbol_names,
self.source.get_subs_slice(lambda_names).iter().cloned(), self.source.get_slice(lambda_names).iter().cloned(),
) )
} }
@ -203,7 +200,7 @@ impl<'a> CopyEnv for AcrossSubs<'a> {
) -> SubsSlice<RecordField<()>> { ) -> SubsSlice<RecordField<()>> {
SubsSlice::extend_new( SubsSlice::extend_new(
&mut self.target.record_fields, &mut self.target.record_fields,
self.source.get_subs_slice(record_fields).iter().copied(), self.source.get_slice(record_fields).iter().copied(),
) )
} }
} }

13
crates/soa/Cargo.toml Normal file
View file

@ -0,0 +1,13 @@
[package]
name = "soa"
description = "Struct-of-Array helpers"
authors.workspace = true
edition.workspace = true
license.workspace = true
version.workspace = true
[dependencies]
pretty_assertions.workspace = true
[dev-dependencies]

5
crates/soa/src/lib.rs Normal file
View file

@ -0,0 +1,5 @@
mod soa_index;
mod soa_slice;
pub use soa_index::*;
pub use soa_slice::*;

View file

@ -0,0 +1,50 @@
use core::fmt;
use crate::soa_slice::Slice;
/// An index into an array of values, based
/// on an offset into the array rather than a pointer.
///
/// Unlike a Rust pointer, this is a u32 offset
/// rather than usize.
pub struct Index<T> {
pub index: u32,
pub(crate) _marker: core::marker::PhantomData<T>,
}
impl<T> fmt::Debug for Index<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Index<{}>({})", core::any::type_name::<T>(), self.index)
}
}
// derive of copy and clone does not play well with PhantomData
impl<T> Copy for Index<T> {}
impl<T> Clone for Index<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Index<T> {
pub const fn new(start: u32) -> Self {
Self {
index: start,
_marker: core::marker::PhantomData,
}
}
pub fn push_new(vector: &mut Vec<T>, value: T) -> Self {
let index = Self::new(vector.len() as _);
vector.push(value);
index
}
pub const fn as_slice(self) -> Slice<T> {
Slice::new(self.index, 1)
}
}

112
crates/soa/src/soa_slice.rs Normal file
View file

@ -0,0 +1,112 @@
use core::fmt;
use core::iter::Map;
use crate::soa_index::Index;
/// A slice into an array of values, based
/// on an offset into the array rather than a pointer.
///
/// Unlike a Rust slice, this is a u32 offset
/// rather than a pointer, and the length is u16.
pub struct Slice<T> {
pub start: u32,
pub length: u16,
_marker: core::marker::PhantomData<T>,
}
impl<T> fmt::Debug for Slice<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Slice {{ start: {}, length: {} }}",
self.start, self.length
)
}
}
// derive of copy and clone does not play well with PhantomData
impl<T> Copy for Slice<T> {}
impl<T> Clone for Slice<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Default for Slice<T> {
fn default() -> Self {
Self::empty()
}
}
impl<T> Slice<T> {
pub fn empty() -> Self {
Self {
start: 0,
length: 0,
_marker: Default::default(),
}
}
pub fn get_slice<'a>(&self, slice: &'a [T]) -> &'a [T] {
&slice[self.indices()]
}
pub fn get_slice_mut<'a>(&self, slice: &'a mut [T]) -> &'a mut [T] {
&mut slice[self.indices()]
}
#[inline(always)]
pub fn indices(&self) -> core::ops::Range<usize> {
self.start as usize..(self.start as usize + self.length as usize)
}
pub const fn len(&self) -> usize {
self.length as usize
}
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
pub const fn new(start: u32, length: u16) -> Self {
Self {
start,
length,
_marker: std::marker::PhantomData,
}
}
pub fn extend_new(vec: &mut Vec<T>, it: impl IntoIterator<Item = T>) -> Self {
let start = vec.len();
vec.extend(it);
let end = vec.len();
Self::new(start as u32, (end - start) as u16)
}
}
impl<T> IntoIterator for Slice<T> {
type Item = Index<T>;
#[allow(clippy::type_complexity)]
type IntoIter = Map<core::ops::Range<u32>, fn(u32) -> Self::Item>;
fn into_iter(self) -> Self::IntoIter {
(self.start..(self.start + self.length as u32)).map(u32_to_index)
}
}
fn u32_to_index<T>(i: u32) -> Index<T> {
Index {
index: i,
_marker: core::marker::PhantomData,
}
}
pub trait GetSlice<T> {
fn get_slice(&self, slice: Slice<T>) -> &[T];
}