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

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;
@ -7,22 +8,19 @@ use crate::soa_index::Index;
///
/// Unlike a Rust slice, this is a u32 offset
/// rather than a pointer, and the length is u16.
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub struct Slice<T> {
pub(crate) start: u32,
pub(crate) length: u16,
pub(crate) _marker: core::marker::PhantomData<T>,
#[cfg(debug_assertions)]
pub(crate) array_start: Option<NonNull<T>>,
pub struct Slice<Array, Elem> {
pub start: u32,
pub length: u16,
_marker: core::marker::PhantomData<(Array, Elem)>,
}
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 {
write!(
f,
"Slice<{}> {{ start: {}, length: {} }}",
"Slice<{}, {}> {{ start: {}, length: {} }}",
core::any::type_name::<T>(),
core::any::type_name::<U>(),
self.start,
self.length
)
@ -31,89 +29,42 @@ impl<T> fmt::Debug for Slice<T> {
// 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 {
*self
}
}
impl<T> Slice<T> {
pub fn empty(_array: &[T]) -> Self {
impl<T, U> Default for Slice<T, U> {
fn default() -> Self {
Self::empty()
}
}
impl<Array, Elem> Slice<Array, Elem> {
pub fn empty() -> Self {
Self {
start: 0,
length: 0,
_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.
/// This is marked as unsafe because it omits the runtime checks (in debug builds)
/// 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,
}
pub fn get_slice<'a>(&self, slice: &'a [Elem]) -> &'a [Elem] {
&slice[self.indices()]
}
/// 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.
pub const unsafe fn start(self) -> usize {
self.start as usize
pub fn get_slice_mut<'a>(&self, slice: &'a mut [Elem]) -> &'a mut [Elem] {
&mut slice[self.indices()]
}
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)]
pub unsafe fn indices(&self) -> 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> {
pub fn indices(&self) -> core::ops::Range<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 {
self.length as usize
}
@ -122,130 +73,43 @@ impl<T> Slice<T> {
self.len() == 0
}
pub fn at_start(&self, array: &[T]) -> Index<T> {
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 {
pub const fn new(start: u32, length: u16) -> Self {
Self {
start,
length,
_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) },
),
_marker: std::marker::PhantomData,
}
}
/// Create a new slice that isn't associated with any particular array.
/// This is marked as unsafe because it omits the runtime checks (in debug builds)
/// 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,
pub fn extend_new(vec: &mut Vec<Elem>, it: impl IntoIterator<Item = Elem>) -> Self {
let start = vec.len();
#[cfg(debug_assertions)]
array_start: None,
}
}
vec.extend(it);
#[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!
}
}
let end = vec.len();
Self::new(start as u32, (end - start) as u16)
}
}
impl<T> IntoIterator for Slice<T> {
type Item = Index<T>;
type IntoIter = SliceIterator<T>;
impl<Array, Elem> IntoIterator for Slice<Array, Elem> {
type Item = Index<Array, Elem>;
#[allow(clippy::type_complexity)]
type IntoIter = Map<core::ops::Range<u32>, fn(u32) -> Self::Item>;
fn into_iter(self) -> Self::IntoIter {
SliceIterator {
slice: self,
current: self.start,
}
(self.start..(self.start + self.length as u32)).map(u32_to_index)
}
}
pub struct SliceIterator<T> {
slice: Slice<T>,
current: u32,
}
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))
fn u32_to_index<T, U>(i: u32) -> Index<T, U> {
Index {
index: i,
_marker: core::marker::PhantomData,
}
}
impl<T> ExactSizeIterator for SliceIterator<T> {}
pub trait GetSlice<T> {
fn get_slice(&self, slice: Slice<T>) -> &[T];
pub trait GetSlice<Array, Elem> {
fn get_slice(&self, slice: Slice<Array, Elem>) -> &[Elem];
}