Revert "Do some checked SoA stuff"

This reverts commit c79d7745f6eb345fd50a7cb4a2a7dd6fb6f8f1fc.
This commit is contained in:
Richard Feldman 2024-10-11 13:27:28 -04:00
parent a8d3280b02
commit b2ea0b842c
No known key found for this signature in database
GPG key ID: DAC334802F365236
19 changed files with 432 additions and 764 deletions

1
Cargo.lock generated
View file

@ -2900,7 +2900,6 @@ dependencies = [
"roc_error_macros", "roc_error_macros",
"roc_module", "roc_module",
"roc_region", "roc_region",
"soa",
"tempfile", "tempfile",
] ]

View file

@ -5,12 +5,12 @@ use std::sync::Arc;
use crate::abilities::SpecializationId; use crate::abilities::SpecializationId;
use crate::exhaustive::{ExhaustiveContext, SketchedRows}; use crate::exhaustive::{ExhaustiveContext, SketchedRows};
use crate::expected::{Expected, PExpected}; use crate::expected::{Expected, PExpected};
use roc_collections::soa::{EitherIndex, Index, Slice};
use roc_module::ident::TagName; use roc_module::ident::TagName;
use roc_module::symbol::{ModuleId, Symbol}; use roc_module::symbol::{ModuleId, Symbol};
use roc_region::all::{Loc, Region}; use roc_region::all::{Loc, Region};
use roc_types::subs::{ExhaustiveMark, IllegalCycleMark, Variable}; use roc_types::subs::{ExhaustiveMark, IllegalCycleMark, Variable};
use roc_types::types::{Category, PatternCategory, TypeTag, Types}; use roc_types::types::{Category, PatternCategory, TypeTag, Types};
use soa::{EitherIndex, Index, Slice};
pub struct Constraints { pub struct Constraints {
pub constraints: Vec<Constraint>, pub constraints: Vec<Constraint>,
@ -131,36 +131,36 @@ impl Constraints {
} }
} }
pub const EMPTY_RECORD: Index<Cell<Index<TypeTag>>> = unsafe_index(0); pub const EMPTY_RECORD: Index<Cell<Index<TypeTag>>> = Index::new(0);
pub const EMPTY_TAG_UNION: Index<Cell<Index<TypeTag>>> = unsafe_index(1); pub const EMPTY_TAG_UNION: Index<Cell<Index<TypeTag>>> = Index::new(1);
pub const STR: Index<Cell<Index<TypeTag>>> = unsafe_index(2); pub const STR: Index<Cell<Index<TypeTag>>> = Index::new(2);
pub const CATEGORY_RECORD: Index<Category> = unsafe_index(0); pub const CATEGORY_RECORD: Index<Category> = Index::new(0);
pub const CATEGORY_FOREIGNCALL: Index<Category> = unsafe_index(1); pub const CATEGORY_FOREIGNCALL: Index<Category> = Index::new(1);
pub const CATEGORY_OPAQUEARG: Index<Category> = unsafe_index(2); pub const CATEGORY_OPAQUEARG: Index<Category> = Index::new(2);
pub const CATEGORY_LAMBDA: Index<Category> = unsafe_index(3); pub const CATEGORY_LAMBDA: Index<Category> = Index::new(3);
pub const CATEGORY_CLOSURESIZE: Index<Category> = unsafe_index(4); pub const CATEGORY_CLOSURESIZE: Index<Category> = Index::new(4);
pub const CATEGORY_STRINTERPOLATION: Index<Category> = unsafe_index(5); pub const CATEGORY_STRINTERPOLATION: Index<Category> = Index::new(5);
pub const CATEGORY_IF: Index<Category> = unsafe_index(6); pub const CATEGORY_IF: Index<Category> = Index::new(6);
pub const CATEGORY_WHEN: Index<Category> = unsafe_index(7); pub const CATEGORY_WHEN: Index<Category> = Index::new(7);
pub const CATEGORY_FLOAT: Index<Category> = unsafe_index(8); pub const CATEGORY_FLOAT: Index<Category> = Index::new(8);
pub const CATEGORY_INT: Index<Category> = unsafe_index(9); pub const CATEGORY_INT: Index<Category> = Index::new(9);
pub const CATEGORY_NUM: Index<Category> = unsafe_index(10); pub const CATEGORY_NUM: Index<Category> = Index::new(10);
pub const CATEGORY_LIST: Index<Category> = unsafe_index(11); pub const CATEGORY_LIST: Index<Category> = Index::new(11);
pub const CATEGORY_STR: Index<Category> = unsafe_index(12); pub const CATEGORY_STR: Index<Category> = Index::new(12);
pub const CATEGORY_CHARACTER: Index<Category> = unsafe_index(13); pub const CATEGORY_CHARACTER: Index<Category> = Index::new(13);
pub const PCATEGORY_RECORD: Index<PatternCategory> = unsafe_index(0); pub const PCATEGORY_RECORD: Index<PatternCategory> = Index::new(0);
pub const PCATEGORY_EMPTYRECORD: Index<PatternCategory> = unsafe_index(1); pub const PCATEGORY_EMPTYRECORD: Index<PatternCategory> = Index::new(1);
pub const PCATEGORY_PATTERNGUARD: Index<PatternCategory> = unsafe_index(2); pub const PCATEGORY_PATTERNGUARD: Index<PatternCategory> = Index::new(2);
pub const PCATEGORY_PATTERNDEFAULT: Index<PatternCategory> = unsafe_index(3); pub const PCATEGORY_PATTERNDEFAULT: Index<PatternCategory> = Index::new(3);
pub const PCATEGORY_SET: Index<PatternCategory> = unsafe_index(4); pub const PCATEGORY_SET: Index<PatternCategory> = Index::new(4);
pub const PCATEGORY_MAP: Index<PatternCategory> = unsafe_index(5); pub const PCATEGORY_MAP: Index<PatternCategory> = Index::new(5);
pub const PCATEGORY_STR: Index<PatternCategory> = unsafe_index(6); pub const PCATEGORY_STR: Index<PatternCategory> = Index::new(6);
pub const PCATEGORY_NUM: Index<PatternCategory> = unsafe_index(7); pub const PCATEGORY_NUM: Index<PatternCategory> = Index::new(7);
pub const PCATEGORY_INT: Index<PatternCategory> = unsafe_index(8); pub const PCATEGORY_INT: Index<PatternCategory> = Index::new(8);
pub const PCATEGORY_FLOAT: Index<PatternCategory> = unsafe_index(9); pub const PCATEGORY_FLOAT: Index<PatternCategory> = Index::new(9);
pub const PCATEGORY_CHARACTER: Index<PatternCategory> = unsafe_index(10); pub const PCATEGORY_CHARACTER: Index<PatternCategory> = Index::new(10);
#[inline(always)] #[inline(always)]
pub fn push_type(&mut self, types: &Types, typ: Index<TypeTag>) -> TypeOrVar { pub fn push_type(&mut self, types: &Types, typ: Index<TypeTag>) -> TypeOrVar {
@ -199,7 +199,7 @@ impl Constraints {
const fn push_type_variable(var: Variable) -> TypeOrVar { const fn push_type_variable(var: Variable) -> TypeOrVar {
// that's right, we use the variable's integer value as the index // that's right, we use the variable's integer value as the index
// that way, we don't need to push anything onto a vector // that way, we don't need to push anything onto a vector
let index: Index<Variable> = Index::new(var.index(), self.type_slices.as_slice()); let index: Index<Variable> = Index::new(var.index());
EitherIndex::from_right(index) EitherIndex::from_right(index)
} }
@ -337,16 +337,7 @@ impl Constraints {
category: PatternCategory, category: PatternCategory,
region: Region, region: Region,
) -> Constraint { ) -> Constraint {
let category_index = { let category_index = Index::push_new(&mut self.pattern_categories, category);
let index = Index::new(
self.pattern_categories.len() as u32,
self.pattern_categories.as_slice(),
);
self.pattern_categories.push(category);
index
};
let includes_tag = IncludesTag { let includes_tag = IncludesTag {
type_index, type_index,
@ -356,16 +347,7 @@ impl Constraints {
region, region,
}; };
let includes_tag_index = { let includes_tag_index = Index::push_new(&mut self.includes_tags, includes_tag);
let index = Index::new(
self.includes_tags.len() as u32,
self.includes_tags.as_slice(),
);
self.includes_tags.push(includes_tag);
index
};
Constraint::IncludesTag(includes_tag_index) Constraint::IncludesTag(includes_tag_index)
} }
@ -378,7 +360,7 @@ impl Constraints {
self.variables.extend(it); self.variables.extend(it);
let length = self.variables.len() - start; let length = self.variables.len() - start;
Slice::new(start as u32, length as u16, self.variables.as_slice()) Slice::new(start as _, length as _)
} }
fn def_types_slice<I>(&mut self, it: I) -> DefTypes fn def_types_slice<I>(&mut self, it: I) -> DefTypes
@ -405,8 +387,8 @@ impl Constraints {
} }
DefTypes { DefTypes {
types: Slice::new(types_start as u32, length as u16, &self.type_slices), types: Slice::new(types_start as _, length as _),
loc_symbols: Slice::new(loc_symbols_start as u32, length as u16, &self.loc_symbols), loc_symbols: Slice::new(loc_symbols_start as _, length as _),
} }
} }
@ -417,7 +399,7 @@ impl Constraints {
where where
I: IntoIterator<Item = Variable>, I: IntoIterator<Item = Variable>,
{ {
let defs_and_ret_constraint = Index::new(self.constraints.len() as u32, &self.constraints); let defs_and_ret_constraint = Index::new(self.constraints.len() as _);
self.constraints.push(defs_constraint); self.constraints.push(defs_constraint);
self.constraints.push(Constraint::True); self.constraints.push(Constraint::True);
@ -433,7 +415,7 @@ impl Constraints {
generalizable: Generalizable(false), generalizable: Generalizable(false),
}; };
let let_index = Index::new(self.let_constraints.len() as u32, &self.let_constraints); let let_index = Index::new(self.let_constraints.len() as _);
self.let_constraints.push(let_contraint); self.let_constraints.push(let_contraint);
Constraint::Let(let_index, Slice::default()) Constraint::Let(let_index, Slice::default())
@ -448,7 +430,7 @@ impl Constraints {
{ {
let defs_constraint = self.and_constraint(defs_constraint); let defs_constraint = self.and_constraint(defs_constraint);
let defs_and_ret_constraint = Index::new(self.constraints.len() as u32, &self.constraints); let defs_and_ret_constraint = Index::new(self.constraints.len() as _);
self.constraints.push(defs_constraint); self.constraints.push(defs_constraint);
self.constraints.push(Constraint::True); self.constraints.push(Constraint::True);
@ -460,7 +442,7 @@ impl Constraints {
generalizable: Generalizable(false), generalizable: Generalizable(false),
}; };
let let_index = Index::new(self.let_constraints.len() as u32, &self.let_constraints); let let_index = Index::new(self.let_constraints.len() as _);
self.let_constraints.push(let_contraint); self.let_constraints.push(let_contraint);
Constraint::Let(let_index, Slice::default()) Constraint::Let(let_index, Slice::default())
@ -483,7 +465,7 @@ impl Constraints {
I3::IntoIter: ExactSizeIterator, I3::IntoIter: ExactSizeIterator,
{ {
// defs and ret constraint are stored consequtively, so we only need to store one index // defs and ret constraint are stored consequtively, so we only need to store one index
let defs_and_ret_constraint = Index::new(self.constraints.len() as u32, &self.constraints); let defs_and_ret_constraint = Index::new(self.constraints.len() as _);
self.constraints.push(defs_constraint); self.constraints.push(defs_constraint);
self.constraints.push(ret_constraint); self.constraints.push(ret_constraint);
@ -496,7 +478,7 @@ impl Constraints {
generalizable, generalizable,
}; };
let let_index = Index::new(self.let_constraints.len() as u32, &self.let_constraints); let let_index = Index::new(self.let_constraints.len() as _);
self.let_constraints.push(let_constraint); self.let_constraints.push(let_constraint);
Constraint::Let(let_index, Slice::default()) Constraint::Let(let_index, Slice::default())
@ -532,7 +514,7 @@ impl Constraints {
I3::IntoIter: ExactSizeIterator, I3::IntoIter: ExactSizeIterator,
{ {
// defs and ret constraint are stored consequtively, so we only need to store one index // defs and ret constraint are stored consequtively, so we only need to store one index
let defs_and_ret_constraint = Index::new(self.constraints.len() as u32, &self.constraints); let defs_and_ret_constraint = Index::new(self.constraints.len() as _);
self.constraints.push(Constraint::True); self.constraints.push(Constraint::True);
self.constraints.push(module_constraint); self.constraints.push(module_constraint);
@ -547,7 +529,7 @@ impl Constraints {
generalizable: Generalizable(true), generalizable: Generalizable(true),
}; };
let let_index = Index::new(self.let_constraints.len() as u32, &self.let_constraints); let let_index = Index::new(self.let_constraints.len() as _);
self.let_constraints.push(let_contraint); self.let_constraints.push(let_contraint);
let pool_slice = self.variable_slice(pool_variables.iter().copied()); let pool_slice = self.variable_slice(pool_variables.iter().copied());
@ -568,9 +550,12 @@ impl Constraints {
1 => it.next().unwrap(), 1 => it.next().unwrap(),
_ => { _ => {
let start = self.constraints.len() as u32; let start = self.constraints.len() as u32;
self.constraints.extend(it); self.constraints.extend(it);
let end = self.constraints.len() as u32; let end = self.constraints.len() as u32;
let slice = Slice::new(start, (end - start) as u16, &self.constraints);
let slice = Slice::new(start, (end - start) as u16);
Constraint::And(slice) Constraint::And(slice)
} }
@ -590,9 +575,8 @@ impl Constraints {
match constraint { match constraint {
Constraint::SaveTheEnvironment => true, Constraint::SaveTheEnvironment => true,
Constraint::Let(index, _) => { Constraint::Let(index, _) => {
let let_constraint = index.get_in(&self.let_constraints); let let_constraint = &self.let_constraints[index.index()];
unsafe {
let offset = let_constraint.defs_and_ret_constraint.index(); let offset = let_constraint.defs_and_ret_constraint.index();
let defs_constraint = &self.constraints[offset]; let defs_constraint = &self.constraints[offset];
let ret_constraint = &self.constraints[offset + 1]; let ret_constraint = &self.constraints[offset + 1];
@ -600,9 +584,8 @@ impl Constraints {
self.contains_save_the_environment(defs_constraint) self.contains_save_the_environment(defs_constraint)
|| self.contains_save_the_environment(ret_constraint) || self.contains_save_the_environment(ret_constraint)
} }
}
Constraint::And(slice) => { Constraint::And(slice) => {
let constraints = slice.get_slice(&self.constraints); let constraints = &self.constraints[slice.indices()];
constraints constraints
.iter() .iter()
@ -684,11 +667,7 @@ impl Constraints {
// we add a dummy symbol to these regions, so we can store the data in the loc_symbols vec // we add a dummy symbol to these regions, so we can store the data in the loc_symbols vec
let it = expr_regions.into_iter().map(|r| (Symbol::ATTR_ATTR, r)); let it = expr_regions.into_iter().map(|r| (Symbol::ATTR_ATTR, r));
let expr_regions = Slice::extend_new(&mut self.loc_symbols, it); let expr_regions = Slice::extend_new(&mut self.loc_symbols, it);
let expr_regions = Slice::new( let expr_regions = Slice::new(expr_regions.start() as _, expr_regions.len() as _);
expr_regions.start() as u32,
expr_regions.len() as u16,
&expr_regions,
);
let cycle = Cycle { let cycle = Cycle {
def_names, def_names,
@ -725,7 +704,7 @@ impl std::ops::Index<ExpectedTypeIndex> for Constraints {
type Output = Expected<TypeOrVar>; type Output = Expected<TypeOrVar>;
fn index(&self, index: ExpectedTypeIndex) -> &Self::Output { fn index(&self, index: ExpectedTypeIndex) -> &Self::Output {
index.get_in(&self.expectations) &self.expectations[index.index()]
} }
} }
@ -733,7 +712,7 @@ impl std::ops::Index<PExpectedTypeIndex> for Constraints {
type Output = PExpected<TypeOrVar>; type Output = PExpected<TypeOrVar>;
fn index(&self, index: PExpectedTypeIndex) -> &Self::Output { fn index(&self, index: PExpectedTypeIndex) -> &Self::Output {
index.get_in(&self.pattern_expectations) &self.pattern_expectations[index.index()]
} }
} }
@ -903,7 +882,3 @@ impl std::fmt::Debug for Constraint {
} }
} }
} }
const fn unsafe_index<T, U>(index: u32) -> Index<T, U> {
unsafe { Index::new_unchecked(index) }
}

View file

@ -12,6 +12,7 @@ use crate::pattern::{canonicalize_pattern, BindingsFromPattern, Pattern, PermitS
use crate::procedure::{QualifiedReference, References}; use crate::procedure::{QualifiedReference, References};
use crate::scope::{Scope, SymbolLookup}; use crate::scope::{Scope, SymbolLookup};
use crate::traverse::{walk_expr, Visitor}; use crate::traverse::{walk_expr, Visitor};
use roc_collections::soa::Index;
use roc_collections::{SendMap, VecMap, VecSet}; use roc_collections::{SendMap, VecMap, VecSet};
use roc_error_macros::internal_error; use roc_error_macros::internal_error;
use roc_module::called_via::CalledVia; use roc_module::called_via::CalledVia;
@ -26,7 +27,6 @@ use roc_region::all::{Loc, Region};
use roc_types::num::SingleQuoteBound; use roc_types::num::SingleQuoteBound;
use roc_types::subs::{ExhaustiveMark, IllegalCycleMark, RedundantMark, VarStore, Variable}; use roc_types::subs::{ExhaustiveMark, IllegalCycleMark, RedundantMark, VarStore, Variable};
use roc_types::types::{Alias, Category, IndexOrField, LambdaSet, OptAbleVar, Type}; use roc_types::types::{Alias, Category, IndexOrField, LambdaSet, OptAbleVar, Type};
use soa::Index;
use std::fmt::{Debug, Display}; use std::fmt::{Debug, Display};
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;

View file

@ -7,6 +7,7 @@ pub mod all;
mod reference_matrix; mod reference_matrix;
mod small_string_interner; mod small_string_interner;
mod small_vec; mod small_vec;
pub mod soa;
mod vec_map; mod vec_map;
mod vec_set; mod vec_set;

View file

@ -0,0 +1,193 @@
use std::usize;
/// DEPRECATED - use crates/soa instead!
pub struct Index<T> {
index: u32,
_marker: std::marker::PhantomData<T>,
}
impl<T> Eq for Index<T> {}
impl<T> PartialEq for Index<T> {
fn eq(&self, other: &Self) -> bool {
self.index == other.index
}
}
impl<T> std::hash::Hash for Index<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.index.hash(state);
}
}
impl<T> Clone for Index<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for Index<T> {}
impl<T> std::fmt::Debug for Index<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Index({})", self.index)
}
}
impl<T> Index<T> {
pub const fn new(index: u32) -> Self {
Self {
index,
_marker: std::marker::PhantomData,
}
}
pub const fn index(self) -> usize {
self.index as usize
}
pub fn push_new(vector: &mut Vec<T>, value: T) -> Index<T> {
let index = Self::new(vector.len() as _);
vector.push(value);
index
}
pub const fn as_slice(self) -> Slice<T> {
Slice::new(self.index, 1)
}
}
#[derive(PartialEq, Eq)]
pub struct Slice<T> {
length: u16,
start: u32,
_marker: std::marker::PhantomData<T>,
}
impl<T> Clone for Slice<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for Slice<T> {}
impl<T> std::fmt::Debug for Slice<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Slice(start = {}, length = {})", self.start, self.length)
}
}
impl<T> Default for Slice<T> {
fn default() -> Self {
Self::empty()
}
}
impl<T> Slice<T> {
pub const fn empty() -> Self {
Self::new(0, 0)
}
pub const fn new(start: u32, length: u16) -> Self {
Self {
start,
length,
_marker: std::marker::PhantomData,
}
}
pub fn extend_new<I>(vector: &mut Vec<T>, values: I) -> Slice<T>
where
I: IntoIterator<Item = T>,
{
let start = vector.len() as u32;
vector.extend(values);
let end = vector.len() as u32;
Self::new(start, (end - start) as u16)
}
pub const fn len(&self) -> usize {
self.length as _
}
pub const fn start(&self) -> usize {
self.start as _
}
pub const fn is_empty(&self) -> bool {
self.length == 0
}
pub const fn indices(&self) -> std::ops::Range<usize> {
self.start as usize..(self.start as usize + self.length as usize)
}
pub fn into_iter(&self) -> impl Iterator<Item = Index<T>> {
self.indices().map(|i| Index::new(i as _))
}
pub const fn at(&self, i: usize) -> Index<T> {
Index::new(self.start + i as u32)
}
}
#[derive(PartialEq, Eq)]
pub struct EitherIndex<T, U> {
index: u32,
_marker: std::marker::PhantomData<(T, U)>,
}
impl<T, U> Clone for EitherIndex<T, U> {
fn clone(&self) -> Self {
*self
}
}
impl<T, U> Copy for EitherIndex<T, U> {}
impl<T, U> std::fmt::Debug for EitherIndex<T, U> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Index({})", self.index)
}
}
impl<T, U> EitherIndex<T, U> {
const MASK: u32 = 1 << 31;
pub const fn from_left(input: Index<T>) -> Self {
assert!(input.index & Self::MASK == 0);
Self {
index: input.index,
_marker: std::marker::PhantomData,
}
}
pub const fn from_right(input: Index<U>) -> Self {
assert!(input.index & Self::MASK == 0);
Self {
index: input.index | Self::MASK,
_marker: std::marker::PhantomData,
}
}
pub const fn split(self) -> Result<Index<T>, Index<U>> {
if self.index & Self::MASK == 0 {
Ok(Index::new(self.index))
} else {
Err(Index::new(self.index ^ Self::MASK))
}
}
pub fn decrement_index(&mut self) {
self.index = self.index.saturating_sub(1);
}
}

View file

@ -22,6 +22,7 @@ use roc_can::expr::{
use roc_can::pattern::Pattern; use roc_can::pattern::Pattern;
use roc_can::traverse::symbols_introduced_from_pattern; use roc_can::traverse::symbols_introduced_from_pattern;
use roc_collections::all::{HumanIndex, MutMap, SendMap}; use roc_collections::all::{HumanIndex, MutMap, SendMap};
use roc_collections::soa::{Index, Slice};
use roc_collections::VecMap; use roc_collections::VecMap;
use roc_module::ident::Lowercase; use roc_module::ident::Lowercase;
use roc_module::symbol::{ModuleId, Symbol}; use roc_module::symbol::{ModuleId, Symbol};
@ -32,7 +33,6 @@ use roc_types::types::{
AliasKind, AnnotationSource, Category, IndexOrField, OptAbleType, PReason, Reason, RecordField, AliasKind, AnnotationSource, Category, IndexOrField, OptAbleType, PReason, Reason, RecordField,
TypeExtension, TypeTag, Types, TypeExtension, TypeTag, Types,
}; };
use soa::{Index, Slice};
/// This is for constraining Defs /// This is for constraining Defs
#[derive(Default, Debug)] #[derive(Default, Debug)]

View file

@ -5,6 +5,7 @@ use roc_can::expected::{Expected, PExpected};
use roc_can::pattern::Pattern::{self, *}; use roc_can::pattern::Pattern::{self, *};
use roc_can::pattern::{DestructType, ListPatterns, RecordDestruct, TupleDestruct}; use roc_can::pattern::{DestructType, ListPatterns, RecordDestruct, TupleDestruct};
use roc_collections::all::{HumanIndex, SendMap}; use roc_collections::all::{HumanIndex, SendMap};
use roc_collections::soa::Index;
use roc_collections::VecMap; use roc_collections::VecMap;
use roc_module::ident::Lowercase; use roc_module::ident::Lowercase;
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
@ -14,7 +15,6 @@ use roc_types::types::{
AliasKind, AliasShared, Category, OptAbleType, PReason, PatternCategory, Reason, RecordField, AliasKind, AliasShared, Category, OptAbleType, PReason, PatternCategory, Reason, RecordField,
Type, TypeExtension, TypeTag, Types, Type, TypeExtension, TypeTag, Types,
}; };
use soa::Index;
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct PatternState { pub struct PatternState {

View file

@ -19,8 +19,6 @@ roc_error_macros = { path = "../../error_macros" }
bumpalo.workspace = true bumpalo.workspace = true
encode_unicode.workspace = true encode_unicode.workspace = true
soa.workspace = true
[dev-dependencies] [dev-dependencies]
criterion.workspace = true criterion.workspace = true
indoc.workspace = true indoc.workspace = true

View file

@ -8,11 +8,11 @@ use crate::ident::Accessor;
use crate::parser::ESingleQuote; use crate::parser::ESingleQuote;
use bumpalo::collections::{String, Vec}; use bumpalo::collections::{String, Vec};
use bumpalo::Bump; use bumpalo::Bump;
use roc_collections::soa::{EitherIndex, Index, Slice};
use roc_error_macros::internal_error; use roc_error_macros::internal_error;
use roc_module::called_via::{BinOp, CalledVia, UnaryOp}; use roc_module::called_via::{BinOp, CalledVia, UnaryOp};
use roc_module::ident::QualifiedModuleName; use roc_module::ident::QualifiedModuleName;
use roc_region::all::{Loc, Position, Region}; use roc_region::all::{Loc, Position, Region};
use soa::{EitherIndex, Index, Slice};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct FullAst<'a> { pub struct FullAst<'a> {
@ -623,7 +623,7 @@ pub fn is_expr_suffixed(expr: &Expr) -> bool {
Expr::Defs(defs, expr) => { Expr::Defs(defs, expr) => {
let any_defs_suffixed = defs.tags.iter().any(|tag| match tag.split() { let any_defs_suffixed = defs.tags.iter().any(|tag| match tag.split() {
Ok(_) => false, Ok(_) => false,
Err(value_index) => match value_index.get_in(&defs.value_defs) { Err(value_index) => match defs.value_defs[value_index.index()] {
ValueDef::Body(_, loc_expr) => is_expr_suffixed(&loc_expr.value), ValueDef::Body(_, loc_expr) => is_expr_suffixed(&loc_expr.value),
ValueDef::AnnotatedBody { body_expr, .. } => is_expr_suffixed(&body_expr.value), ValueDef::AnnotatedBody { body_expr, .. } => is_expr_suffixed(&body_expr.value),
_ => false, _ => false,
@ -1025,7 +1025,7 @@ impl<'a, 'b> Iterator for RecursiveValueDefIter<'a, 'b> {
match self.current.tags.get(self.index) { match self.current.tags.get(self.index) {
Some(tag) => { Some(tag) => {
if let Err(def_index) = tag.split() { if let Err(def_index) = tag.split() {
let def = def_index.get_in(&self.current.value_defs); let def = &self.current.value_defs[def_index.index()];
let region = &self.current.regions[self.index]; let region = &self.current.regions[self.index];
match def { match def {
@ -1195,8 +1195,8 @@ impl<'a> Defs<'a> {
pub fn defs(&self) -> impl Iterator<Item = Result<&TypeDef<'a>, &ValueDef<'a>>> { pub fn defs(&self) -> impl Iterator<Item = Result<&TypeDef<'a>, &ValueDef<'a>>> {
self.tags.iter().map(|tag| match tag.split() { self.tags.iter().map(|tag| match tag.split() {
Ok(type_index) => Ok(type_index.get_in(&self.type_defs)), Ok(type_index) => Ok(&self.type_defs[type_index.index()]),
Err(value_index) => Err(value_index.get_in(&self.value_defs)), Err(value_index) => Err(&self.value_defs[value_index.index()]),
}) })
} }
@ -1207,13 +1207,10 @@ impl<'a> Defs<'a> {
.iter() .iter()
.enumerate() .enumerate()
.map(|(i, tag)| match tag.split() { .map(|(i, tag)| match tag.split() {
Ok(type_index) => Ok(Loc::at( Ok(type_index) => Ok(Loc::at(self.regions[i], self.type_defs[type_index.index()])),
self.regions[i],
*type_index.get_in(&self.type_defs),
)),
Err(value_index) => Err(Loc::at( Err(value_index) => Err(Loc::at(
self.regions[i], self.regions[i],
*value_index.get_in(&self.value_defs), self.value_defs[value_index.index()],
)), )),
}) })
} }
@ -1224,14 +1221,14 @@ impl<'a> Defs<'a> {
.enumerate() .enumerate()
.filter_map(|(tag_index, tag)| match tag.split() { .filter_map(|(tag_index, tag)| match tag.split() {
Ok(_) => None, Ok(_) => None,
Err(value_index) => Some((tag_index, value_index.get_in(&self.value_defs))), Err(value_index) => Some((tag_index, &self.value_defs[value_index.index()])),
}) })
} }
pub fn last(&self) -> Option<Result<&TypeDef<'a>, &ValueDef<'a>>> { pub fn last(&self) -> Option<Result<&TypeDef<'a>, &ValueDef<'a>>> {
self.tags.last().map(|tag| match tag.split() { self.tags.last().map(|tag| match tag.split() {
Ok(type_index) => Ok(type_index.get_in(&self.type_defs)), Ok(type_index) => Ok(&self.type_defs[type_index.index()]),
Err(value_index) => Err(value_index.get_in(&self.value_defs)), Err(value_index) => Err(&self.value_defs[value_index.index()]),
}) })
} }
@ -1243,7 +1240,7 @@ impl<'a> Defs<'a> {
.rev() .rev()
.find_map(|(tag_index, tag)| match tag.split() { .find_map(|(tag_index, tag)| match tag.split() {
Ok(_) => None, Ok(_) => None,
Err(value_index) => match *value_index.get_in(&self.value_defs) { Err(value_index) => match self.value_defs[value_index.index()] {
ValueDef::Body( ValueDef::Body(
Loc { Loc {
value: Pattern::RecordDestructure(collection), value: Pattern::RecordDestructure(collection),
@ -1273,7 +1270,7 @@ impl<'a> Defs<'a> {
{ {
Ok(type_index) => { Ok(type_index) => {
// remove from vec // remove from vec
unsafe { self.type_defs.remove(type_index.index()) }; self.type_defs.remove(type_index.index());
// update all of the remaining indexes in type_defs // update all of the remaining indexes in type_defs
for (current_tag_index, tag) in self.tags.iter_mut().enumerate() { for (current_tag_index, tag) in self.tags.iter_mut().enumerate() {
@ -1285,7 +1282,7 @@ impl<'a> Defs<'a> {
} }
Err(value_index) => { Err(value_index) => {
// remove from vec // remove from vec
unsafe { self.value_defs.remove(value_index.index()) }; self.value_defs.remove(value_index.index());
// update all of the remaining indexes in value_defs // update all of the remaining indexes in value_defs
for (current_tag_index, tag) in self.tags.iter_mut().enumerate() { for (current_tag_index, tag) in self.tags.iter_mut().enumerate() {
@ -1314,17 +1311,11 @@ impl<'a> Defs<'a> {
self.regions.push(region); self.regions.push(region);
self.space_before.push({ let before = Slice::extend_new(&mut self.spaces, spaces_before.iter().copied());
let start = self.spaces.len() as u32; self.space_before.push(before);
self.spaces.extend(spaces_before.iter().copied());
Slice::new(start, spaces_before.len() as u16, &self.spaces)
});
self.space_after.push({ let after = Slice::extend_new(&mut self.spaces, spaces_after.iter().copied());
let start = self.spaces.len() as u32; self.space_after.push(after);
self.spaces.extend(spaces_after.iter().copied());
Slice::new(start, spaces_after.len() as u16, &self.spaces)
});
} }
pub fn push_value_def( pub fn push_value_def(
@ -1334,11 +1325,7 @@ impl<'a> Defs<'a> {
spaces_before: &[CommentOrNewline<'a>], spaces_before: &[CommentOrNewline<'a>],
spaces_after: &[CommentOrNewline<'a>], spaces_after: &[CommentOrNewline<'a>],
) { ) {
let value_def_index = { let value_def_index = Index::push_new(&mut self.value_defs, value_def);
let index = Index::new(self.value_defs.len() as u32, &self.value_defs);
self.value_defs.push(value_def);
index
};
let tag = EitherIndex::from_right(value_def_index); let tag = EitherIndex::from_right(value_def_index);
self.push_def_help(tag, region, spaces_before, spaces_after) self.push_def_help(tag, region, spaces_before, spaces_after)
} }
@ -1360,7 +1347,7 @@ impl<'a> Defs<'a> {
} }
Err(value_index) => { Err(value_index) => {
self.regions[tag_index] = region; self.regions[tag_index] = region;
*value_index.get_in_mut(&mut self.value_defs) = value_def; self.value_defs[value_index.index()] = value_def;
} }
} }
} }
@ -1372,11 +1359,7 @@ impl<'a> Defs<'a> {
spaces_before: &[CommentOrNewline<'a>], spaces_before: &[CommentOrNewline<'a>],
spaces_after: &[CommentOrNewline<'a>], spaces_after: &[CommentOrNewline<'a>],
) { ) {
let type_def_index = { let type_def_index = Index::push_new(&mut self.type_defs, type_def);
let index = Index::new(self.type_defs.len() as u32, &self.type_defs);
self.type_defs.push(type_def);
index
};
let tag = EitherIndex::from_left(type_def_index); let tag = EitherIndex::from_left(type_def_index);
self.push_def_help(tag, region, spaces_before, spaces_after) self.push_def_help(tag, region, spaces_before, spaces_after)
} }
@ -1390,13 +1373,13 @@ impl<'a> Defs<'a> {
for (tag_index, tag) in self.tags.iter().enumerate() { for (tag_index, tag) in self.tags.iter().enumerate() {
let region = self.regions[tag_index]; let region = self.regions[tag_index];
let space_before = unsafe { let space_before = {
let start = self.space_before[tag_index].start(); let start = self.space_before[tag_index].start();
let len = self.space_before[tag_index].len(); let len = self.space_before[tag_index].len();
&self.spaces[start..(start + len)] &self.spaces[start..(start + len)]
}; };
let space_after = unsafe { let space_after = {
let start = self.space_after[tag_index].start(); let start = self.space_after[tag_index].start();
let len = self.space_after[tag_index].len(); let len = self.space_after[tag_index].len();
@ -1405,28 +1388,18 @@ impl<'a> Defs<'a> {
match tag.split() { match tag.split() {
Ok(type_def_index) => { Ok(type_def_index) => {
let type_def = *type_def_index.get_in(&self.type_defs); let type_def = self.type_defs[type_def_index.index()];
match tag_index.cmp(&target) { match tag_index.cmp(&target) {
std::cmp::Ordering::Less => { std::cmp::Ordering::Less => {
// before // before
let type_def_index = { let type_def_index = Index::push_new(&mut before.type_defs, type_def);
let index =
Index::new(before.type_defs.len() as u32, &before.type_defs);
before.type_defs.push(type_def);
index
};
let tag = EitherIndex::from_left(type_def_index); let tag = EitherIndex::from_left(type_def_index);
before.push_def_help(tag, region, space_before, space_after); before.push_def_help(tag, region, space_before, space_after);
} }
std::cmp::Ordering::Greater => { std::cmp::Ordering::Greater => {
// after // after
let type_def_index = { let type_def_index = Index::push_new(&mut after.type_defs, type_def);
let index =
Index::new(after.type_defs.len() as u32, &after.type_defs);
after.type_defs.push(type_def);
index
};
let tag = EitherIndex::from_left(type_def_index); let tag = EitherIndex::from_left(type_def_index);
after.push_def_help(tag, region, space_before, space_after); after.push_def_help(tag, region, space_before, space_after);
} }
@ -1436,28 +1409,20 @@ impl<'a> Defs<'a> {
} }
} }
Err(value_def_index) => { Err(value_def_index) => {
let value_def = *value_def_index.get_in(&self.value_defs); let value_def = self.value_defs[value_def_index.index()];
match tag_index.cmp(&target) { match tag_index.cmp(&target) {
std::cmp::Ordering::Less => { std::cmp::Ordering::Less => {
// before // before
let new_value_def_index = { let new_value_def_index =
let index = Index::push_new(&mut before.value_defs, value_def);
Index::new(before.value_defs.len() as u32, &before.value_defs);
before.value_defs.push(value_def);
index
};
let tag = EitherIndex::from_right(new_value_def_index); let tag = EitherIndex::from_right(new_value_def_index);
before.push_def_help(tag, region, space_before, space_after); before.push_def_help(tag, region, space_before, space_after);
} }
std::cmp::Ordering::Greater => { std::cmp::Ordering::Greater => {
// after // after
let new_value_def_index = { let new_value_def_index =
let index = Index::push_new(&mut after.value_defs, value_def);
Index::new(after.value_defs.len() as u32, &after.value_defs);
after.value_defs.push(value_def);
index
};
let tag = EitherIndex::from_right(new_value_def_index); let tag = EitherIndex::from_right(new_value_def_index);
after.push_def_help(tag, region, space_before, space_after); after.push_def_help(tag, region, space_before, space_after);
} }

View file

@ -28,10 +28,10 @@ use crate::type_annotation;
use crate::{header, keyword}; use crate::{header, keyword};
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
use bumpalo::Bump; use bumpalo::Bump;
use roc_collections::soa::Slice;
use roc_error_macros::internal_error; use roc_error_macros::internal_error;
use roc_module::called_via::{BinOp, CalledVia, UnaryOp}; use roc_module::called_via::{BinOp, CalledVia, UnaryOp};
use roc_region::all::{Loc, Position, Region}; use roc_region::all::{Loc, Position, Region};
use soa::Slice;
use crate::parser::Progress::{self, *}; use crate::parser::Progress::{self, *};
@ -2286,11 +2286,7 @@ pub fn parse_top_level_defs<'a>(
} }
if output.tags.len() > existing_len { if output.tags.len() > existing_len {
let after = { let after = Slice::extend_new(&mut output.spaces, last_space.iter().copied());
let start = output.spaces.len() as u32;
output.spaces.extend(last_space.iter().copied());
Slice::new(start, last_space.len() as u16, &output.spaces)
};
let last = output.tags.len() - 1; let last = output.tags.len() - 1;
debug_assert!(output.space_after[last].is_empty() || after.is_empty()); debug_assert!(output.space_after[last].is_empty() || after.is_empty());
output.space_after[last] = after; output.space_after[last] = after;

View file

@ -2,7 +2,6 @@ use bumpalo::collections::{String, Vec};
use bumpalo::Bump; use bumpalo::Bump;
use roc_module::called_via::{BinOp, UnaryOp}; use roc_module::called_via::{BinOp, UnaryOp};
use roc_region::all::{Loc, Position, Region}; use roc_region::all::{Loc, Position, Region};
use soa::Slice;
use crate::{ use crate::{
ast::{ ast::{
@ -723,8 +722,8 @@ impl<'a> Normalize<'a> for Expr<'a> {
Expr::Crash => Expr::Crash, Expr::Crash => Expr::Crash,
Expr::Defs(a, b) => { Expr::Defs(a, b) => {
let mut defs = a.clone(); let mut defs = a.clone();
defs.space_before = vec![Slice::empty(&defs.spaces); defs.len()]; defs.space_before = vec![Default::default(); defs.len()];
defs.space_after = vec![Slice::empty(&defs.spaces); defs.len()]; defs.space_after = vec![Default::default(); defs.len()];
defs.regions = vec![Region::zero(); defs.len()]; defs.regions = vec![Region::zero(); defs.len()];
defs.spaces.clear(); defs.spaces.clear();

View file

@ -1,6 +1,7 @@
use std::cell::RefCell; use std::cell::RefCell;
use roc_can::{abilities::AbilitiesStore, constraint::TypeOrVar, expected::Expected}; use roc_can::{abilities::AbilitiesStore, constraint::TypeOrVar, expected::Expected};
use roc_collections::soa::{Index, Slice};
use roc_error_macros::internal_error; use roc_error_macros::internal_error;
use roc_module::{ident::TagName, symbol::Symbol}; use roc_module::{ident::TagName, symbol::Symbol};
use roc_region::all::Loc; use roc_region::all::Loc;
@ -18,7 +19,6 @@ use roc_types::{
}, },
}; };
use roc_unify::unify::{unify, Unified}; use roc_unify::unify::{unify, Unified};
use soa::{Index, Slice};
use crate::{ use crate::{
ability::{AbilityImplError, ObligationCache}, ability::{AbilityImplError, ObligationCache},

View file

@ -152,7 +152,7 @@ fn find_names_needed(
// User-defined names are already taken. // User-defined names are already taken.
// We must not accidentally generate names that collide with them! // We must not accidentally generate names that collide with them!
let name = name_index.get_in(&subs.field_names).clone(); let name = subs.field_names[name_index.index as usize].clone();
match names_taken.get(&name) { match names_taken.get(&name) {
Some(var) if *var == root => {} Some(var) if *var == root => {}
Some(_) => { Some(_) => {
@ -680,24 +680,24 @@ fn write_content<'a>(
match subs.get_content_without_compacting(var) { match subs.get_content_without_compacting(var) {
FlexVar(Some(name_index)) => { FlexVar(Some(name_index)) => {
let name = name_index.get_in(&subs.field_names); let name = &subs.field_names[name_index.index as usize];
buf.push_str(name.as_str()) buf.push_str(name.as_str())
} }
FlexVar(None) => buf.push_str(WILDCARD), FlexVar(None) => buf.push_str(WILDCARD),
RigidVar(name_index) => { RigidVar(name_index) => {
let name = name_index.get_in(&subs.field_names); let name = &subs.field_names[name_index.index as usize];
buf.push_str(name.as_str()) buf.push_str(name.as_str())
} }
FlexAbleVar(opt_name_index, abilities) => { FlexAbleVar(opt_name_index, abilities) => {
let name = opt_name_index let name = opt_name_index
.map(|name_index| name_index.get_in(&subs.field_names).as_str()) .map(|name_index| subs.field_names[name_index.index as usize].as_str())
.unwrap_or(WILDCARD); .unwrap_or(WILDCARD);
let abilities = AbilitySet::from_iter(subs.get_subs_slice(*abilities).iter().copied()); let abilities = AbilitySet::from_iter(subs.get_subs_slice(*abilities).iter().copied());
ctx.able_variables.push((name, abilities)); ctx.able_variables.push((name, abilities));
buf.push_str(name); buf.push_str(name);
} }
RigidAbleVar(name_index, abilities) => { RigidAbleVar(name_index, abilities) => {
let name = name_index.get_in(&subs.field_names).as_str(); let name = subs.field_names[name_index.index as usize].as_str();
let abilities = AbilitySet::from_iter(subs.get_subs_slice(*abilities).iter().copied()); let abilities = AbilitySet::from_iter(subs.get_subs_slice(*abilities).iter().copied());
ctx.able_variables.push((name, abilities)); ctx.able_variables.push((name, abilities));
buf.push_str(name); buf.push_str(name);
@ -713,7 +713,7 @@ fn write_content<'a>(
ctx.recursion_structs_to_expand.insert(structure_root); ctx.recursion_structs_to_expand.insert(structure_root);
} else { } else {
let name = name_index.get_in(&subs.field_names); let name = &subs.field_names[name_index.index as usize];
buf.push_str(name.as_str()) buf.push_str(name.as_str())
} }
} }

View file

@ -15,37 +15,9 @@ use std::iter::{once, Iterator};
// if your changes cause this number to go down, great! // if your changes cause this number to go down, great!
// please change it to the lower number. // please change it to the lower number.
// if it went up, maybe check that the change is really required. // if it went up, maybe check that the change is really required
roc_error_macros::assert_sizeof_all!( roc_error_macros::assert_sizeof_all!(Descriptor, 5 * 8 + 4);
Descriptor, roc_error_macros::assert_sizeof_all!(FlatType, 3 * 8 + 4);
5 * 8 + 4 + {
// extra bytes in debug builds for extra Index/Slice array pointer storage for verification
#[cfg(debug_assertions)]
{
20
}
#[cfg(not(debug_assertions))]
{
0
}
}
);
roc_error_macros::assert_sizeof_all!(
FlatType,
3 * 8 + 4 + {
// extra bytes in debug builds for extra Index/Slice array pointer storage for verification
#[cfg(debug_assertions)]
{
12
}
#[cfg(not(debug_assertions))]
{
0
}
}
);
roc_error_macros::assert_sizeof_all!(UnionTags, 12); roc_error_macros::assert_sizeof_all!(UnionTags, 12);
roc_error_macros::assert_sizeof_all!(RecordFields, 2 * 8); roc_error_macros::assert_sizeof_all!(RecordFields, 2 * 8);
@ -297,7 +269,7 @@ impl Subs {
let mut lowercases = Vec::with_capacity(length); let mut lowercases = Vec::with_capacity(length);
for subs_slice in slices { for subs_slice in slices {
let bytes = subs_slice.get_slice(&string_slice); let bytes = &string_slice[subs_slice.indices()];
offset += bytes.len(); offset += bytes.len();
let string = unsafe { std::str::from_utf8_unchecked(bytes) }; let string = unsafe { std::str::from_utf8_unchecked(bytes) };
@ -315,7 +287,7 @@ impl Subs {
let mut tag_names = Vec::with_capacity(length); let mut tag_names = Vec::with_capacity(length);
for SerializedTagName(subs_slice) in slices { for SerializedTagName(subs_slice) in slices {
let bytes = subs_slice.get_slice(&string_slice); let bytes = &string_slice[subs_slice.indices()];
offset += bytes.len(); offset += bytes.len();
let string = unsafe { std::str::from_utf8_unchecked(bytes) }; let string = unsafe { std::str::from_utf8_unchecked(bytes) };
@ -441,10 +413,10 @@ impl Default for Subs {
} }
/// A slice into the Vec<T> of subs /// A slice into the Vec<T> of subs
pub type SubsSlice<T> = Slice<T>; pub type SubsSlice<T> = Slice<Subs, T>;
/// An index into the Vec<T> of subs /// An index into the Vec<T> of subs
pub type SubsIndex<T> = Index<T>; pub type SubsIndex<T> = Index<Subs, T>;
// make `subs[some_index]` work. The types/trait resolution make sure we get the // make `subs[some_index]` work. The types/trait resolution make sure we get the
// element from the right vector // element from the right vector
@ -453,13 +425,13 @@ impl std::ops::Index<SubsIndex<Variable>> for Subs {
type Output = Variable; type Output = Variable;
fn index(&self, index: SubsIndex<Variable>) -> &Self::Output { fn index(&self, index: SubsIndex<Variable>) -> &Self::Output {
index.get_in(&self.variables) &self.variables[index.index as usize]
} }
} }
impl std::ops::IndexMut<SubsIndex<Variable>> for Subs { impl std::ops::IndexMut<SubsIndex<Variable>> for Subs {
fn index_mut(&mut self, index: SubsIndex<Variable>) -> &mut Self::Output { fn index_mut(&mut self, index: SubsIndex<Variable>) -> &mut Self::Output {
index.get_in_mut(&mut self.variables) &mut self.variables[index.index as usize]
} }
} }
@ -467,7 +439,7 @@ impl std::ops::Index<SubsIndex<Lowercase>> for Subs {
type Output = Lowercase; type Output = Lowercase;
fn index(&self, index: SubsIndex<Lowercase>) -> &Self::Output { fn index(&self, index: SubsIndex<Lowercase>) -> &Self::Output {
index.get_in(&self.field_names) &self.field_names[index.index as usize]
} }
} }
@ -475,7 +447,7 @@ impl std::ops::Index<SubsIndex<usize>> for Subs {
type Output = usize; type Output = usize;
fn index(&self, index: SubsIndex<usize>) -> &Self::Output { fn index(&self, index: SubsIndex<usize>) -> &Self::Output {
index.get_in(&self.tuple_elem_indices) &self.tuple_elem_indices[index.index as usize]
} }
} }
@ -483,13 +455,13 @@ impl std::ops::Index<SubsIndex<TagName>> for Subs {
type Output = TagName; type Output = TagName;
fn index(&self, index: SubsIndex<TagName>) -> &Self::Output { fn index(&self, index: SubsIndex<TagName>) -> &Self::Output {
index.get_in(&self.tag_names) &self.tag_names[index.index as usize]
} }
} }
impl std::ops::IndexMut<SubsIndex<TagName>> for Subs { impl std::ops::IndexMut<SubsIndex<TagName>> for Subs {
fn index_mut(&mut self, index: SubsIndex<TagName>) -> &mut Self::Output { fn index_mut(&mut self, index: SubsIndex<TagName>) -> &mut Self::Output {
index.get_in_mut(&mut self.tag_names) &mut self.tag_names[index.index as usize]
} }
} }
@ -497,13 +469,13 @@ impl std::ops::Index<SubsIndex<Symbol>> for Subs {
type Output = Symbol; type Output = Symbol;
fn index(&self, index: SubsIndex<Symbol>) -> &Self::Output { fn index(&self, index: SubsIndex<Symbol>) -> &Self::Output {
index.get_in(&self.symbol_names) &self.symbol_names[index.index as usize]
} }
} }
impl std::ops::IndexMut<SubsIndex<Symbol>> for Subs { impl std::ops::IndexMut<SubsIndex<Symbol>> for Subs {
fn index_mut(&mut self, index: SubsIndex<Symbol>) -> &mut Self::Output { fn index_mut(&mut self, index: SubsIndex<Symbol>) -> &mut Self::Output {
index.get_in_mut(&mut self.symbol_names) &mut self.symbol_names[index.index as usize]
} }
} }
@ -511,19 +483,19 @@ impl std::ops::Index<SubsIndex<Uls>> for Subs {
type Output = Uls; type Output = Uls;
fn index(&self, index: SubsIndex<Uls>) -> &Self::Output { fn index(&self, index: SubsIndex<Uls>) -> &Self::Output {
index.get_in(&self.unspecialized_lambda_sets) &self.unspecialized_lambda_sets[index.index as usize]
} }
} }
impl std::ops::IndexMut<SubsIndex<Uls>> for Subs { impl std::ops::IndexMut<SubsIndex<Uls>> for Subs {
fn index_mut(&mut self, index: SubsIndex<Uls>) -> &mut Self::Output { fn index_mut(&mut self, index: SubsIndex<Uls>) -> &mut Self::Output {
index.get_in_mut(&mut self.unspecialized_lambda_sets) &mut self.unspecialized_lambda_sets[index.index as usize]
} }
} }
impl std::ops::IndexMut<SubsIndex<Lowercase>> for Subs { impl std::ops::IndexMut<SubsIndex<Lowercase>> for Subs {
fn index_mut(&mut self, index: SubsIndex<Lowercase>) -> &mut Self::Output { fn index_mut(&mut self, index: SubsIndex<Lowercase>) -> &mut Self::Output {
index.get_in_mut(&mut self.field_names) &mut self.field_names[index.index as usize]
} }
} }
@ -531,13 +503,13 @@ impl std::ops::Index<SubsIndex<RecordField<()>>> for Subs {
type Output = RecordField<()>; type Output = RecordField<()>;
fn index(&self, index: SubsIndex<RecordField<()>>) -> &Self::Output { fn index(&self, index: SubsIndex<RecordField<()>>) -> &Self::Output {
index.get_in(&self.record_fields) &self.record_fields[index.index as usize]
} }
} }
impl std::ops::IndexMut<SubsIndex<RecordField<()>>> for Subs { impl std::ops::IndexMut<SubsIndex<RecordField<()>>> for Subs {
fn index_mut(&mut self, index: SubsIndex<RecordField<()>>) -> &mut Self::Output { fn index_mut(&mut self, index: SubsIndex<RecordField<()>>) -> &mut Self::Output {
index.get_in_mut(&mut self.record_fields) &mut self.record_fields[index.index as usize]
} }
} }
@ -545,13 +517,13 @@ impl std::ops::Index<SubsIndex<VariableSubsSlice>> for Subs {
type Output = VariableSubsSlice; type Output = VariableSubsSlice;
fn index(&self, index: SubsIndex<VariableSubsSlice>) -> &Self::Output { fn index(&self, index: SubsIndex<VariableSubsSlice>) -> &Self::Output {
index.get_in(&self.variable_slices) &self.variable_slices[index.index as usize]
} }
} }
impl std::ops::IndexMut<SubsIndex<VariableSubsSlice>> for Subs { impl std::ops::IndexMut<SubsIndex<VariableSubsSlice>> for Subs {
fn index_mut(&mut self, index: SubsIndex<VariableSubsSlice>) -> &mut Self::Output { fn index_mut(&mut self, index: SubsIndex<VariableSubsSlice>) -> &mut Self::Output {
index.get_in_mut(&mut self.variable_slices) &mut self.variable_slices[index.index as usize]
} }
} }
@ -1520,41 +1492,33 @@ pub struct SubsSnapshot {
uls_of_var_snapshot: UlsOfVarSnapshot, uls_of_var_snapshot: UlsOfVarSnapshot,
} }
fn unchecked_slice<T>(start: u32, len: u16) -> SubsSlice<T> {
unsafe { SubsSlice::new_unchecked(start, len) }
}
fn unchecked_index<T>(index: u32) -> SubsIndex<T> {
unsafe { SubsIndex::new_unchecked(index) }
}
impl Subs { impl Subs {
// IFTTT INIT-TagNames // IFTTT INIT-TagNames
pub const RESULT_TAG_NAMES: SubsSlice<TagName> = unchecked_slice(0, 2); pub const RESULT_TAG_NAMES: SubsSlice<TagName> = SubsSlice::new(0, 2);
pub const TAG_NAME_ERR: SubsIndex<TagName> = unchecked_index(0); pub const TAG_NAME_ERR: SubsIndex<TagName> = SubsIndex::new(0);
pub const TAG_NAME_OK: SubsIndex<TagName> = unchecked_index(1); pub const TAG_NAME_OK: SubsIndex<TagName> = SubsIndex::new(1);
pub const TAG_NAME_INVALID_NUM_STR: SubsIndex<TagName> = unchecked_index(2); pub const TAG_NAME_INVALID_NUM_STR: SubsIndex<TagName> = SubsIndex::new(2);
pub const TAG_NAME_BAD_UTF_8: SubsIndex<TagName> = unchecked_index(3); pub const TAG_NAME_BAD_UTF_8: SubsIndex<TagName> = SubsIndex::new(3);
pub const TAG_NAME_OUT_OF_BOUNDS: SubsIndex<TagName> = unchecked_index(4); pub const TAG_NAME_OUT_OF_BOUNDS: SubsIndex<TagName> = SubsIndex::new(4);
// END INIT-TagNames // END INIT-TagNames
// IFTTT INIT-VariableSubsSlice // IFTTT INIT-VariableSubsSlice
pub const STR_SLICE: VariableSubsSlice = unchecked_slice(0, 1); pub const STR_SLICE: VariableSubsSlice = SubsSlice::new(0, 1);
// END INIT-VariableSubsSlice // END INIT-VariableSubsSlice
// IFTTT INIT-SymbolSubsSlice // IFTTT INIT-SymbolSubsSlice
#[rustfmt::skip] #[rustfmt::skip]
pub const AB_ENCODING: SubsSlice<Symbol> = unchecked_slice(0, 1); pub const AB_ENCODING: SubsSlice<Symbol> = SubsSlice::new(0, 1);
#[rustfmt::skip] #[rustfmt::skip]
pub const AB_DECODING: SubsSlice<Symbol> = unchecked_slice(1, 1); pub const AB_DECODING: SubsSlice<Symbol> = SubsSlice::new(1, 1);
#[rustfmt::skip] #[rustfmt::skip]
pub const AB_HASHER: SubsSlice<Symbol> = unchecked_slice(2, 1); pub const AB_HASHER: SubsSlice<Symbol> = SubsSlice::new(2, 1);
#[rustfmt::skip] #[rustfmt::skip]
pub const AB_HASH: SubsSlice<Symbol> = unchecked_slice(3, 1); pub const AB_HASH: SubsSlice<Symbol> = SubsSlice::new(3, 1);
#[rustfmt::skip] #[rustfmt::skip]
pub const AB_EQ: SubsSlice<Symbol> = unchecked_slice(4, 1); pub const AB_EQ: SubsSlice<Symbol> = SubsSlice::new(4, 1);
#[rustfmt::skip] #[rustfmt::skip]
pub const AB_INSPECT: SubsSlice<Symbol> = unchecked_slice(5, 1); pub const AB_INSPECT: SubsSlice<Symbol> = SubsSlice::new(5, 1);
// END INIT-SymbolSubsSlice // END INIT-SymbolSubsSlice
pub fn new() -> Self { pub fn new() -> Self {
@ -1684,7 +1648,7 @@ impl Subs {
self.variables self.variables
.extend(std::iter::repeat(Variable::NULL).take(length)); .extend(std::iter::repeat(Variable::NULL).take(length));
Slice::new(start, length as u16, &self.variables) Slice::new(start, length as u16)
} }
pub fn insert_into_vars<I>(&mut self, input: I) -> VariableSubsSlice pub fn insert_into_vars<I>(&mut self, input: I) -> VariableSubsSlice
@ -1697,7 +1661,7 @@ impl Subs {
let length = (self.variables.len() as u32 - start) as u16; let length = (self.variables.len() as u32 - start) as u16;
Slice::new(start, length as u16, &self.variables) Slice::new(start, length)
} }
pub fn reserve_variable_slices(&mut self, length: usize) -> SubsSlice<VariableSubsSlice> { pub fn reserve_variable_slices(&mut self, length: usize) -> SubsSlice<VariableSubsSlice> {
@ -1710,7 +1674,7 @@ impl Subs {
self.variable_slices.push(value); self.variable_slices.push(value);
} }
Slice::new(start, length as u16, &self.variable_slices) Slice::new(start, length as u16)
} }
pub fn reserve_tag_names(&mut self, length: usize) -> SubsSlice<TagName> { pub fn reserve_tag_names(&mut self, length: usize) -> SubsSlice<TagName> {
@ -1719,7 +1683,7 @@ impl Subs {
self.tag_names self.tag_names
.extend(std::iter::repeat(TagName(Uppercase::default())).take(length)); .extend(std::iter::repeat(TagName(Uppercase::default())).take(length));
Slice::new(start, length as u16, &self.tag_names) Slice::new(start, length as u16)
} }
pub fn reserve_uls_slice(&mut self, length: usize) -> SubsSlice<Uls> { pub fn reserve_uls_slice(&mut self, length: usize) -> SubsSlice<Uls> {
@ -1728,7 +1692,7 @@ impl Subs {
self.unspecialized_lambda_sets self.unspecialized_lambda_sets
.extend(std::iter::repeat(Uls(Variable::NULL, Symbol::UNDERSCORE, 0)).take(length)); .extend(std::iter::repeat(Uls(Variable::NULL, Symbol::UNDERSCORE, 0)).take(length));
Slice::new(start, length as u16, &self.unspecialized_lambda_sets) Slice::new(start, length as u16)
} }
#[inline(always)] #[inline(always)]
@ -2245,53 +2209,11 @@ impl From<Content> for Descriptor {
} }
} }
roc_error_macros::assert_sizeof_all!( roc_error_macros::assert_sizeof_all!(Content, 4 * 8);
Content,
4 * 8 + {
// extra bytes in debug builds for extra Index/Slice array pointer storage for verification
#[cfg(debug_assertions)]
{
16
}
#[cfg(not(debug_assertions))]
{
0
}
}
);
roc_error_macros::assert_sizeof_all!((Symbol, AliasVariables, Variable), 8 + 12 + 4); roc_error_macros::assert_sizeof_all!((Symbol, AliasVariables, Variable), 8 + 12 + 4);
roc_error_macros::assert_sizeof_all!(AliasVariables, 12); roc_error_macros::assert_sizeof_all!(AliasVariables, 12);
roc_error_macros::assert_sizeof_all!( roc_error_macros::assert_sizeof_all!(FlatType, 3 * 8 + 4);
FlatType, roc_error_macros::assert_sizeof_all!(LambdaSet, 3 * 8 + 4);
3 * 8 + 4 + {
// extra bytes in debug builds for extra Index/Slice array pointer storage for verification
#[cfg(debug_assertions)]
{
12
}
#[cfg(not(debug_assertions))]
{
0
}
}
);
roc_error_macros::assert_sizeof_all!(
LambdaSet,
3 * 8 + 4 + {
// extra bytes in debug builds for extra Index/Slice array pointer storage for verification
#[cfg(debug_assertions)]
{
12
}
#[cfg(not(debug_assertions))]
{
0
}
}
);
roc_error_macros::assert_sizeof_aarch64!((Variable, Option<Lowercase>), 4 * 8); roc_error_macros::assert_sizeof_aarch64!((Variable, Option<Lowercase>), 4 * 8);
roc_error_macros::assert_sizeof_wasm!((Variable, Option<Lowercase>), 4 * 4); roc_error_macros::assert_sizeof_wasm!((Variable, Option<Lowercase>), 4 * 4);
@ -2390,16 +2312,16 @@ pub struct AliasVariables {
impl AliasVariables { impl AliasVariables {
pub const fn all_variables(&self) -> VariableSubsSlice { pub const fn all_variables(&self) -> VariableSubsSlice {
unsafe { SubsSlice::new_unchecked(self.variables_start, self.all_variables_len) } SubsSlice::new(self.variables_start, self.all_variables_len)
} }
pub const fn type_variables(&self) -> VariableSubsSlice { pub const fn type_variables(&self) -> VariableSubsSlice {
unsafe { SubsSlice::new_unchecked(self.variables_start, self.type_variables_len) } SubsSlice::new(self.variables_start, self.type_variables_len)
} }
pub const fn lambda_set_variables(&self) -> VariableSubsSlice { pub const fn lambda_set_variables(&self) -> VariableSubsSlice {
let start = self.variables_start + self.type_variables_len as u32; let start = self.variables_start + self.type_variables_len as u32;
unsafe { SubsSlice::new_unchecked(start, self.lambda_set_variables_len) } SubsSlice::new(start, self.lambda_set_variables_len)
} }
pub const fn infer_ext_in_output_variables(&self) -> VariableSubsSlice { pub const fn infer_ext_in_output_variables(&self) -> VariableSubsSlice {
@ -2407,7 +2329,7 @@ impl AliasVariables {
self.type_variables_len as u32 + self.lambda_set_variables_len as u32; self.type_variables_len as u32 + self.lambda_set_variables_len as u32;
let start = self.variables_start + infer_ext_vars_offset; let start = self.variables_start + infer_ext_vars_offset;
let infer_ext_vars_len = self.all_variables_len - infer_ext_vars_offset as u16; let infer_ext_vars_len = self.all_variables_len - infer_ext_vars_offset as u16;
unsafe { SubsSlice::new_unchecked(start, infer_ext_vars_len) } SubsSlice::new(start, infer_ext_vars_len)
} }
pub const fn len(&self) -> usize { pub const fn len(&self) -> usize {
@ -2724,7 +2646,7 @@ where
} }
let slice = subs.variable_slices[self.values_start as usize]; let slice = subs.variable_slices[self.values_start as usize];
slice.len() == 1 slice.length == 1
} }
pub fn from_tag_name_index(index: SubsIndex<L>) -> Self { pub fn from_tag_name_index(index: SubsIndex<L>) -> Self {
@ -2743,8 +2665,8 @@ where
Self { Self {
length: labels.len() as u16, length: labels.len() as u16,
labels_start: labels.start(), labels_start: labels.start,
values_start: variables.start(), values_start: variables.start,
_marker: Default::default(), _marker: Default::default(),
} }
} }
@ -3072,25 +2994,24 @@ impl RecordFields {
} }
pub const fn variables(&self) -> SubsSlice<Variable> { pub const fn variables(&self) -> SubsSlice<Variable> {
unsafe { SubsSlice::new_unchecked(self.variables_start, self.length) } SubsSlice::new(self.variables_start, self.length)
} }
pub const fn field_names(&self) -> SubsSlice<Lowercase> { pub const fn field_names(&self) -> SubsSlice<Lowercase> {
unsafe { SubsSlice::new_unchecked(self.field_names_start, self.length) } SubsSlice::new(self.field_names_start, self.length)
} }
pub const fn record_fields(&self) -> SubsSlice<RecordField<()>> { pub const fn record_fields(&self) -> SubsSlice<RecordField<()>> {
unsafe { SubsSlice::new_unchecked(self.field_types_start, self.length) } SubsSlice::new(self.field_types_start, self.length)
} }
pub fn iter_variables(&self) -> impl Iterator<Item = SubsIndex<Variable>> { pub fn iter_variables(&self) -> impl Iterator<Item = SubsIndex<Variable>> {
let slice = unsafe { SubsSlice::new_unchecked(self.variables_start, self.length) }; let slice = SubsSlice::new(self.variables_start, self.length);
slice.into_iter() slice.into_iter()
} }
pub fn has_only_optional_fields(&self, subs: &Subs) -> bool { pub fn has_only_optional_fields(&self, subs: &Subs) -> bool {
let slice: SubsSlice<RecordField<()>> = let slice: SubsSlice<RecordField<()>> = SubsSlice::new(self.field_types_start, self.length);
unsafe { SubsSlice::new_unchecked(self.field_types_start, self.length) };
subs.get_subs_slice(slice) subs.get_subs_slice(slice)
.iter() .iter()
@ -3223,15 +3144,7 @@ impl RecordFields {
let it = range1.into_iter().zip(range2).zip(range3); let it = range1.into_iter().zip(range2).zip(range3);
unsafe { it.map(|((i1, i2), i3)| (SubsIndex::new(i1), SubsIndex::new(i2), SubsIndex::new(i3)))
it.map(|((i1, i2), i3)| {
(
SubsIndex::new_unchecked(i1),
SubsIndex::new_unchecked(i2),
SubsIndex::new_unchecked(i3),
)
})
}
} }
} }
@ -3292,15 +3205,15 @@ impl TupleElems {
} }
pub const fn variables(&self) -> SubsSlice<Variable> { pub const fn variables(&self) -> SubsSlice<Variable> {
unsafe { SubsSlice::new_unchecked(self.variables_start, self.length) } SubsSlice::new(self.variables_start, self.length)
} }
pub const fn elem_indices(&self) -> SubsSlice<usize> { pub const fn elem_indices(&self) -> SubsSlice<usize> {
unsafe { SubsSlice::new_unchecked(self.elem_index_start, self.length) } SubsSlice::new(self.elem_index_start, self.length)
} }
pub fn iter_variables(&self) -> impl Iterator<Item = SubsIndex<Variable>> { pub fn iter_variables(&self) -> impl Iterator<Item = SubsIndex<Variable>> {
let slice = unsafe { SubsSlice::new_unchecked(self.variables_start, self.length) }; let slice = SubsSlice::new(self.variables_start, self.length);
slice.into_iter() slice.into_iter()
} }
@ -3312,7 +3225,7 @@ impl TupleElems {
let it = range1.into_iter().zip(range2); let it = range1.into_iter().zip(range2);
unsafe { it.map(|(i1, i2)| (SubsIndex::new_unchecked(i1), SubsIndex::new_unchecked(i2))) } it.map(|(i1, i2)| (SubsIndex::new(i1), SubsIndex::new(i2)))
} }
pub fn insert_into_subs<I>(subs: &mut Subs, input: I) -> Self pub fn insert_into_subs<I>(subs: &mut Subs, input: I) -> Self

View file

@ -5,6 +5,7 @@ use crate::subs::{
VariableSubsSlice, VariableSubsSlice,
}; };
use roc_collections::all::{HumanIndex, ImMap, ImSet, MutMap, MutSet, SendMap}; use roc_collections::all::{HumanIndex, ImMap, ImSet, MutMap, MutSet, SendMap};
use roc_collections::soa::{Index, Slice};
use roc_collections::VecMap; use roc_collections::VecMap;
use roc_error_macros::internal_error; use roc_error_macros::internal_error;
use roc_module::called_via::CalledVia; use roc_module::called_via::CalledVia;
@ -12,7 +13,6 @@ use roc_module::ident::{ForeignSymbol, Lowercase, TagName};
use roc_module::low_level::LowLevel; use roc_module::low_level::LowLevel;
use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_module::symbol::{Interns, ModuleId, Symbol};
use roc_region::all::{Loc, Region}; use roc_region::all::{Loc, Region};
use soa::{Index, Slice};
use std::fmt; use std::fmt;
use std::fmt::Write; use std::fmt::Write;
use std::path::PathBuf; use std::path::PathBuf;
@ -486,17 +486,17 @@ impl Default for Types {
} }
impl Types { impl Types {
pub const EMPTY_RECORD: Index<TypeTag> = unsafe { Index::new_unchecked(0) }; pub const EMPTY_RECORD: Index<TypeTag> = Index::new(0);
const EMPTY_RECORD_TAG: TypeTag = TypeTag::Variable(Variable::EMPTY_RECORD); const EMPTY_RECORD_TAG: TypeTag = TypeTag::Variable(Variable::EMPTY_RECORD);
const EMPTY_RECORD_ARGS: Slice<TypeTag> = unsafe { Slice::empty_unchecked() }; const EMPTY_RECORD_ARGS: Slice<TypeTag> = Slice::empty();
pub const EMPTY_TAG_UNION: Index<TypeTag> = unsafe { Index::new_unchecked(1) }; pub const EMPTY_TAG_UNION: Index<TypeTag> = Index::new(1);
const EMPTY_TAG_UNION_TAG: TypeTag = TypeTag::Variable(Variable::EMPTY_TAG_UNION); const EMPTY_TAG_UNION_TAG: TypeTag = TypeTag::Variable(Variable::EMPTY_TAG_UNION);
const EMPTY_TAG_UNION_ARGS: Slice<TypeTag> = unsafe { Slice::empty_unchecked() }; const EMPTY_TAG_UNION_ARGS: Slice<TypeTag> = Slice::empty();
pub const STR: Index<TypeTag> = unsafe { Index::new_unchecked(1) }; pub const STR: Index<TypeTag> = Index::new(2);
const STR_TAG: TypeTag = TypeTag::Variable(Variable::STR); const STR_TAG: TypeTag = TypeTag::Variable(Variable::STR);
const STR_ARGS: Slice<TypeTag> = unsafe { Slice::empty_unchecked() }; const STR_ARGS: Slice<TypeTag> = Slice::empty();
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@ -1280,8 +1280,8 @@ mod debug_types {
}; };
use super::{TypeTag, Types}; use super::{TypeTag, Types};
use roc_collections::soa::{Index, Slice};
use roc_module::ident::TagName; use roc_module::ident::TagName;
use soa::{Index, Slice};
use ven_pretty::{text, Arena, DocAllocator, DocBuilder}; use ven_pretty::{text, Arena, DocAllocator, DocBuilder};
pub struct DebugTag<'a>(pub &'a Types, pub Index<TypeTag>); pub struct DebugTag<'a>(pub &'a Types, pub Index<TypeTag>);
@ -4558,7 +4558,3 @@ mod test {
} }
} }
} }
const fn unsafe_index<T>(index: u32) -> Index<T> {
unsafe { Index::new_unchecked(index) }
}

View file

@ -1,96 +0,0 @@
use core::{
fmt::{self, Formatter},
marker::PhantomData,
ptr::NonNull,
};
use crate::soa_index::Index;
#[derive(PartialEq, Eq)]
pub struct EitherIndex<T, U> {
index: u32,
_marker: PhantomData<(T, U)>,
#[cfg(debug_assertions)]
pub(crate) array_start: Result<Option<NonNull<T>>, Option<NonNull<U>>>,
}
impl<T, U> Clone for EitherIndex<T, U> {
fn clone(&self) -> Self {
*self
}
}
impl<T, U> Copy for EitherIndex<T, U> {}
impl<T, U> fmt::Debug for EitherIndex<T, U> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Index({})", self.index)
}
}
impl<T, U> EitherIndex<T, U> {
const MASK: u32 = 1 << 31;
pub const fn from_left(input: Index<T>) -> Self {
assert!(input.index & Self::MASK == 0);
Self {
index: input.index,
_marker: PhantomData,
#[cfg(debug_assertions)]
array_start: Ok(input.array_start),
}
}
pub const fn from_right(input: Index<U>) -> Self {
assert!(input.index & Self::MASK == 0);
Self {
index: input.index | Self::MASK,
_marker: std::marker::PhantomData,
#[cfg(debug_assertions)]
array_start: Err(input.array_start),
}
}
pub const fn split(self) -> Result<Index<T>, Index<U>> {
if self.index & Self::MASK == 0 {
Ok(Index {
index: self.index,
_marker: PhantomData,
#[cfg(debug_assertions)]
array_start: {
match self.array_start {
Ok(array) => array,
Err(_) => {
panic!("Tried to split an EitherIndex that was created with from_right, but ended up with a mask that indicates it was created with from_left");
}
}
},
})
} else {
Err(Index {
index: self.index ^ Self::MASK,
_marker: PhantomData,
#[cfg(debug_assertions)]
array_start: {
match self.array_start {
Err(array) => array,
Ok(_) => {
panic!("Tried to split an EitherIndex that was created with from_left, but ended up with a mask that indicates it was created with from_right");
}
}
},
})
}
}
pub fn decrement_index(&mut self) {
self.index = self.index.saturating_sub(1);
}
}

View file

@ -1,9 +1,5 @@
#![cfg_attr(not(any(debug_assertions, test)), no_std)]
mod either_index;
mod soa_index; mod soa_index;
mod soa_slice; mod soa_slice;
pub use either_index::*;
pub use soa_index::*; pub use soa_index::*;
pub use soa_slice::*; pub use soa_slice::*;

View file

@ -1,11 +1,4 @@
use core::{ use core::fmt;
any,
cmp::Ordering,
fmt::{self, Formatter},
hash::{Hash, Hasher},
marker::PhantomData,
ptr::NonNull,
};
use crate::soa_slice::Slice; use crate::soa_slice::Slice;
@ -14,174 +7,50 @@ use crate::soa_slice::Slice;
/// ///
/// Unlike a Rust pointer, this is a u32 offset /// Unlike a Rust pointer, this is a u32 offset
/// rather than usize. /// rather than usize.
pub struct Index<T> { pub struct Index<Array, Elem> {
pub(crate) index: u32, pub index: u32,
pub(crate) _marker: PhantomData<T>, pub(crate) _marker: core::marker::PhantomData<(Array, Elem)>,
#[cfg(debug_assertions)]
pub(crate) array_start: Option<NonNull<T>>,
} }
impl<T> PartialEq for Index<T> { impl<Array, Elem> fmt::Debug for Index<Array, Elem> {
fn eq(&self, other: &Self) -> bool { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[cfg(debug_assertions)] write!(
self.verify_array(other.array_start.map(NonNull::as_ptr), ".eq()"); f,
"Index<{}, {}>({})",
self.index == other.index core::any::type_name::<Array>(),
} core::any::type_name::<Elem>(),
} self.index
)
impl<T> Eq for Index<T> {}
impl<T> PartialOrd for Index<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
#[cfg(debug_assertions)]
self.verify_array(other.array_start.map(NonNull::as_ptr), ".partial_cmp()");
Some(self.cmp(other))
}
}
impl<T> Ord for Index<T> {
fn cmp(&self, other: &Self) -> Ordering {
#[cfg(debug_assertions)]
self.verify_array(other.array_start.map(NonNull::as_ptr), ".cmp()");
self.index.cmp(&other.index)
}
}
impl<T> fmt::Debug for Index<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Index<{}>({})", any::type_name::<T>(), self.index)
} }
} }
// derive of copy and clone does not play well with PhantomData // derive of copy and clone does not play well with PhantomData
impl<T> Copy for Index<T> {} impl<Array, Elem> Copy for Index<Array, Elem> {}
impl<T> Clone for Index<T> { impl<Array, Elem> Clone for Index<Array, Elem> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
*self *self
} }
} }
impl<T> Hash for Index<T> { impl<Array, Elem> Index<Array, Elem> {
fn hash<H: Hasher>(&self, state: &mut H) { pub const fn new(start: u32) -> Self {
self.index.hash(state);
}
}
impl<T> Index<T> {
pub const fn new(
start: u32,
_array: &[T], // only used in debug builds
) -> Self {
Self { Self {
index: start, index: start,
_marker: PhantomData, _marker: core::marker::PhantomData,
#[cfg(debug_assertions)]
array_start: Some(
// Safety: this is safe beccause references are never to null pointers.
// Once NonNull::new is const on stable Rust, use that instead. Docs to check for const-ness:
// https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.new
unsafe { NonNull::new_unchecked(_array.as_ptr() as *mut T) },
),
} }
} }
/// Create a new index that isn't associated with any particular array. pub fn push_new(vector: &mut Vec<Elem>, value: Elem) -> Self {
/// This is marked as unsafe because it omits the runtime checks (in debug builds) let index = Self::new(vector.len() as _);
/// which verify in debug builds that indices are dereferened into the original array.
pub const unsafe fn new_unchecked(start: u32) -> Self {
Self {
index: start,
_marker: PhantomData,
#[cfg(debug_assertions)] vector.push(value);
array_start: None,
} index
} }
pub const fn as_slice(self) -> Slice<T> { pub const fn as_slice(self) -> Slice<Array, Elem> {
Slice { Slice::new(self.index, 1)
start: self.index,
length: 1,
_marker: PhantomData,
#[cfg(debug_assertions)]
array_start: self.array_start,
}
}
/// Given the original slice this indexes into, return the equivalent of slice.get_unchecked(index)
/// (except that in debug build it actually does do a bounds check, and panics if it's out of bounds,
/// but that should never happen since this is an Index into a known slice - basically, a reference).
pub fn get_in(self, slice: &[T]) -> &T {
#[cfg(debug_assertions)]
{
self.verify_array(Some(slice.as_ptr() as *mut T), "get_in");
slice.get(self.index as usize).expect("Accessing an Index in its original slice went out of bounds. This should never happen!")
}
#[cfg(not(debug_assertions))]
unsafe {
slice.get_unchecked(self.index as usize)
}
}
/// Given the original slice this indexes into, return the equivalent of slice.get_unchecked_mut(index)
/// (except that in debug build it actually does do a bounds check, and panics if it's out of bounds,
/// but that should never happen since this is an Index into a known slice - basically, a reference).
pub fn get_in_mut(self, slice: &mut [T]) -> &mut T {
#[cfg(debug_assertions)]
{
self.verify_array(Some(slice.as_ptr() as *mut T), "get_in");
slice.get_mut(self.index as usize).expect("Accessing an Index in its original slice went out of bounds. This should never happen!")
}
#[cfg(not(debug_assertions))]
unsafe {
slice.get_unchecked_mut(self.index as usize)
}
}
/// This is unsafe because it doesn't verify that the index being returned is being used with the original
/// slice it was created with. Self::get_in is the safe alternative to this.
pub const unsafe fn index(self) -> usize {
self.index as usize
}
#[cfg(debug_assertions)]
fn verify_array(&self, other: Option<*mut T>, operation: &'static str) {
match (self.array_start, other) {
(Some(array_start), Some(other_array_start))
if other_array_start != array_start.as_ptr() =>
{
panic!(
"Tried to {} an index from one array to the index of a different array!",
operation
);
}
_ => {
// Either one of them was None, meaning this is unchecked, or they point to the same memory - as expected!
}
}
}
}
impl<'a, T> core::ops::Index<Index<T>> for [T] {
type Output = T;
fn index(&self, index: Index<T>) -> &Self::Output {
index.get_in(self)
}
}
impl<'a, T> core::ops::IndexMut<Index<T>> for [T] {
fn index_mut(&mut self, index: Index<T>) -> &mut Self::Output {
index.get_in_mut(self)
} }
} }

View file

@ -1,4 +1,5 @@
use core::{fmt, marker::PhantomData, ops::Range, ptr::NonNull}; use core::fmt;
use core::iter::Map;
use crate::soa_index::Index; use crate::soa_index::Index;
@ -7,22 +8,19 @@ use crate::soa_index::Index;
/// ///
/// Unlike a Rust slice, this is a u32 offset /// Unlike a Rust slice, this is a u32 offset
/// rather than a pointer, and the length is u16. /// rather than a pointer, and the length is u16.
#[derive(PartialEq, Eq, PartialOrd, Ord)] pub struct Slice<Array, Elem> {
pub struct Slice<T> { pub start: u32,
pub(crate) start: u32, pub length: u16,
pub(crate) length: u16, _marker: core::marker::PhantomData<(Array, Elem)>,
pub(crate) _marker: core::marker::PhantomData<T>,
#[cfg(debug_assertions)]
pub(crate) array_start: Option<NonNull<T>>,
} }
impl<T> fmt::Debug for Slice<T> { impl<T, U> fmt::Debug for Slice<T, U> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!( write!(
f, f,
"Slice<{}> {{ start: {}, length: {} }}", "Slice<{}, {}> {{ start: {}, length: {} }}",
core::any::type_name::<T>(), core::any::type_name::<T>(),
core::any::type_name::<U>(),
self.start, self.start,
self.length self.length
) )
@ -31,89 +29,42 @@ impl<T> fmt::Debug for Slice<T> {
// derive of copy and clone does not play well with PhantomData // derive of copy and clone does not play well with PhantomData
impl<T> Copy for Slice<T> {} impl<T, U> Copy for Slice<T, U> {}
impl<T> Clone for Slice<T> { impl<T, U> Clone for Slice<T, U> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
*self *self
} }
} }
impl<T> Slice<T> { impl<T, U> Default for Slice<T, U> {
pub fn empty(_array: &[T]) -> Self { fn default() -> Self {
Self::empty()
}
}
impl<Array, Elem> Slice<Array, Elem> {
pub fn empty() -> Self {
Self { Self {
start: 0, start: 0,
length: 0, length: 0,
_marker: Default::default(), _marker: Default::default(),
#[cfg(debug_assertions)]
array_start: NonNull::new(_array.as_ptr() as *mut T),
} }
} }
/// Create an empty slice that isn't associated with any particular array. pub fn get_slice<'a>(&self, slice: &'a [Elem]) -> &'a [Elem] {
/// This is marked as unsafe because it omits the runtime checks (in debug builds) &slice[self.indices()]
/// which verify that indices made from this slice are compared with other
/// indices into the original array.
pub unsafe fn empty_unchecked() -> Self {
Self {
start: 0,
length: 0,
_marker: Default::default(),
#[cfg(debug_assertions)]
array_start: None,
}
} }
/// This is unsafe because it doesn't verify that the start index being returned is being used with the original pub fn get_slice_mut<'a>(&self, slice: &'a mut [Elem]) -> &'a mut [Elem] {
/// slice it was created with. Self::get_in is the safe alternative to this. &mut slice[self.indices()]
pub const unsafe fn start(self) -> usize {
self.start as usize
} }
pub fn get_slice<'a>(&self, slice: &'a [T]) -> &'a [T] {
&slice[self.as_range()]
}
pub fn get_slice_mut<'a>(&self, slice: &'a mut [T]) -> &'a mut [T] {
&mut slice[self.as_range()]
}
/// This is unsafe because it doesn't verify that the start index being returned is being used with the original
/// slice it was created with. Self::get_in is the safe alternative to this.
#[inline(always)] #[inline(always)]
pub unsafe fn indices(&self) -> Range<usize> { pub fn indices(&self) -> core::ops::Range<usize> {
self.as_range()
}
/// Given the original &[T] that this Slice<T> was based on,
/// return the &[T] representation of this Slice<T>.
#[inline(always)]
pub fn slice_from<'a>(&self, original: &'a [T]) -> &'a [T] {
#[cfg(debug_assertions)]
self.verify_array(Some(original.as_ptr() as *mut T), "slice_from");
&original[self.as_range()]
}
/// The pub version of this is indices() and it's marked as unsafe. This one isn't marked as unsafe,
/// for internal convenience.
#[inline(always)]
fn as_range(&self) -> Range<usize> {
self.start as usize..(self.start as usize + self.length as usize) self.start as usize..(self.start as usize + self.length as usize)
} }
/// Given the original &mut [T] that this Slice<T> was based on,
/// return the &mut [T] representation of this Slice<T>.
#[inline(always)]
pub fn slice_from_mut<'a>(&self, original: &'a mut [T]) -> &'a mut [T] {
#[cfg(debug_assertions)]
self.verify_array(Some(original.as_ptr() as *mut T), "slice_from");
&mut original[self.start as usize..(self.start as usize + self.length as usize)]
}
pub const fn len(&self) -> usize { pub const fn len(&self) -> usize {
self.length as usize self.length as usize
} }
@ -122,130 +73,43 @@ impl<T> Slice<T> {
self.len() == 0 self.len() == 0
} }
pub fn at_start(&self, array: &[T]) -> Index<T> { pub const fn new(start: u32, length: u16) -> Self {
self.at(0, array)
}
pub fn at(&self, i: usize, _array: &[T]) -> Index<T> {
#[cfg(debug_assertions)]
{
if !self.matches_stored_array(_array) {
panic!("Tried to call .at() on a slice passing an array that was different from the array it was created with!");
}
}
Index {
index: self.start + i as u32,
_marker: PhantomData,
#[cfg(debug_assertions)]
array_start: self.array_start,
}
}
#[cfg(debug_assertions)]
fn matches_stored_array(&self, other_array: &[T]) -> bool {
match self.array_start {
Some(self_array) => other_array.as_ptr() == self_array.as_ptr(),
None => true,
}
}
pub const fn new(start: u32, length: u16, _array: &[T]) -> Self {
Self { Self {
start, start,
length, length,
_marker: PhantomData, _marker: std::marker::PhantomData,
#[cfg(debug_assertions)]
array_start: Some(
// Safety: this is safe beccause references are never to null pointers.
// Once NonNull::new is const on stable Rust, use that instead. Docs to check for const-ness:
// https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.new
unsafe { NonNull::new_unchecked(_array.as_ptr() as *mut T) },
),
} }
} }
/// Create a new slice that isn't associated with any particular array. pub fn extend_new(vec: &mut Vec<Elem>, it: impl IntoIterator<Item = Elem>) -> Self {
/// This is marked as unsafe because it omits the runtime checks (in debug builds) let start = vec.len();
/// which verify in debug builds that indices made from this slice are compared with other
/// indices into the original array.
pub const unsafe fn new_unchecked(start: u32, length: u16) -> Self {
Self {
start,
length,
_marker: PhantomData,
#[cfg(debug_assertions)] vec.extend(it);
array_start: None,
}
}
#[cfg(debug_assertions)] let end = vec.len();
fn verify_array(&self, other: Option<*mut T>, operation: &'static str) {
match (self.array_start, other) { Self::new(start as u32, (end - start) as u16)
(Some(array_start), Some(other_array_start))
if other_array_start != array_start.as_ptr() =>
{
panic!(
"Tried to {} an index from one array to the index of a different array!",
operation
);
}
_ => {
// Either one of them was None, meaning this is unchecked, or they point to the same memory - as expected!
}
}
} }
} }
impl<T> IntoIterator for Slice<T> { impl<Array, Elem> IntoIterator for Slice<Array, Elem> {
type Item = Index<T>; type Item = Index<Array, Elem>;
type IntoIter = SliceIterator<T>;
#[allow(clippy::type_complexity)]
type IntoIter = Map<core::ops::Range<u32>, fn(u32) -> Self::Item>;
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
SliceIterator { (self.start..(self.start + self.length as u32)).map(u32_to_index)
slice: self,
current: self.start,
}
} }
} }
pub struct SliceIterator<T> { fn u32_to_index<T, U>(i: u32) -> Index<T, U> {
slice: Slice<T>, Index {
current: u32, index: i,
} _marker: core::marker::PhantomData,
impl<T> Iterator for SliceIterator<T> {
type Item = Index<T>;
fn next(&mut self) -> Option<Self::Item> {
if self.current < self.slice.start + self.slice.length as u32 {
let index = Index {
index: self.current,
_marker: PhantomData,
#[cfg(debug_assertions)]
array_start: self.slice.array_start,
};
self.current += 1;
Some(index)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = (self.slice.start + self.slice.length as u32 - self.current) as usize;
(remaining, Some(remaining))
} }
} }
impl<T> ExactSizeIterator for SliceIterator<T> {} pub trait GetSlice<Array, Elem> {
fn get_slice(&self, slice: Slice<Array, Elem>) -> &[Elem];
pub trait GetSlice<T> {
fn get_slice(&self, slice: Slice<T>) -> &[T];
} }