From 7284f8f04c99641bdcbfcf313f5a2bae4d1eaaea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Angelats=20i=20Ribera?= Date: Sat, 22 Aug 2020 01:32:38 +0200 Subject: [PATCH] Make the generated vector-like object use a single length Most methods are not implemented --- soa-derive-internal/src/input.rs | 4 + soa-derive-internal/src/iter.rs | 279 +++++++--------------- soa-derive-internal/src/lib.rs | 1 + soa-derive-internal/src/slice.rs | 394 +++++++++++++++---------------- soa-derive-internal/src/vec.rs | 265 +++++++++++---------- tests/particles/mod.rs | 2 +- tests/vec.rs | 74 ++---- 7 files changed, 445 insertions(+), 574 deletions(-) diff --git a/soa-derive-internal/src/input.rs b/soa-derive-internal/src/input.rs index 752da0e..bb35e20 100644 --- a/soa-derive-internal/src/input.rs +++ b/soa-derive-internal/src/input.rs @@ -81,6 +81,10 @@ impl Input { Ident::new(&format!("{}Vec", self.name), Span::call_site()) } + pub fn vec_fields_name(&self) -> Ident { + Ident::new(&format!("{}VecFields", self.name), Span::call_site()) + } + pub fn slice_name(&self) -> Ident { Ident::new(&format!("{}Slice", self.name), Span::call_site()) } diff --git a/soa-derive-internal/src/iter.rs b/soa-derive-internal/src/iter.rs index 4fb7bf6..857cf5d 100644 --- a/soa-derive-internal/src/iter.rs +++ b/soa-derive-internal/src/iter.rs @@ -15,243 +15,138 @@ pub fn derive(input: &Input) -> TokenStream { let ref_name = &input.ref_name(); let ref_mut_name = &input.ref_mut_name(); - let ref_doc_url = format!("[`{0}`](struct.{0}.html)", ref_name); - let ref_mut_doc_url = format!("[`{0}`](struct.{0}.html)", ref_mut_name); - let fields_names = &input.fields.iter() - .map(|field| field.ident.clone().unwrap()) - .collect::>(); - let first_field = &fields_names[0]; + let fields_names = input.fields.iter() + .map(|field| field.ident.clone().unwrap()) + .collect::>(); + let fields_names_1 = &fields_names; + let fields_names_2 = &fields_names; - let fields_types = &input.fields.iter() - .map(|field| &field.ty) - .collect::>(); - let first_field_type = &fields_types[0]; - - let mut iter_type = quote!{ - slice::Iter<'a, #first_field_type> - }; - let mut iter_pat = quote!{ - #first_field - }; - let mut create_iter = quote!{ - self.#first_field.iter() - }; - - let mut iter_mut_type = quote!{ - slice::IterMut<'a, #first_field_type> - }; - let mut create_iter_mut = quote!{ - self.#first_field.iter_mut() - }; - - if fields_types.len() > 1 { - for field in &input.fields[1..] { - let field_name = &field.ident; - let field_type = &field.ty; - - iter_pat = quote!{ - (#iter_pat, #field_name) - }; - - iter_type = quote!{ - iter::Zip<#iter_type, slice::Iter<'a, #field_type>> - }; - - create_iter = quote!{ - #create_iter.zip(self.#field_name.iter()) - }; - - iter_mut_type = quote!{ - iter::Zip<#iter_mut_type, slice::IterMut<'a, #field_type>> - }; - - create_iter_mut = quote!{ - #create_iter_mut.zip(self.#field_name.iter_mut()) - }; - } - } - - let mut generated = quote! { + let generated = quote!{ #[allow(non_snake_case, dead_code)] mod #detail_mod { use super::*; - use std::slice; - #[allow(unused_imports)] - use std::iter; - #[allow(missing_debug_implementations)] - #visibility struct Iter<'a>(pub(super) #iter_type); - - impl<'a> Iterator for Iter<'a> { - type Item = #ref_name<'a>; - - #[inline] - fn next(&mut self) -> Option<#ref_name<'a>> { - self.0.next().and_then(|#iter_pat| - Some(#ref_name{ - #(#fields_names,)* - }) - ) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - } - - impl<'a> DoubleEndedIterator for Iter<'a> { - - #[inline] - fn next_back(&mut self) -> Option<#ref_name<'a>> { - self.0.next_back().and_then(|#iter_pat| - Some(#ref_name{ - #(#fields_names,)* - }) - ) - } - } - - impl #vec_name { - /// Get an iterator over the - #[doc = #ref_doc_url] - /// in this vector - #visibility fn iter(&self) -> Iter { - Iter(#create_iter) - } + pub struct VecIter<'a> { + pub(super) vec: &'a #vec_name, + pub(super) n: usize, } - impl<'a> #slice_name<'a> { - /// Get an iterator over the - #[doc = #ref_doc_url] - /// in this slice. - #visibility fn iter(&self) -> Iter { - Iter(#create_iter) + impl<'a> VecIter<'a> { + pub(self) fn new(vec: &'a #vec_name) -> VecIter<'a> { + VecIter { + vec, + n: 0, + } } } - #[allow(missing_debug_implementations)] - #visibility struct IterMut<'a>(pub(super) #iter_mut_type); + impl<'a> Iterator for VecIter<'a> { + type Item = #ref_name<'a>; - impl<'a> Iterator for IterMut<'a> { - type Item = #ref_mut_name<'a>; + fn next(&mut self) -> Option { + if self.n >= self.vec.len() { + return None; + } - #[inline] - fn next(&mut self) -> Option<#ref_mut_name<'a>> { - self.0.next().and_then(|#iter_pat| - Some(#ref_mut_name{ - #(#fields_names,)* + let item = unsafe { + Some(#ref_name { + #( + #fields_names_1: self.vec.data.#fields_names_2.ptr().add(self.n).as_ref().unwrap(), + )* }) - ) + }; + self.n += 1; + item } - #[inline] fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() + if self.n >= self.vec.len() { + return (0, Some(0)) + } + let left = self.vec.len() - self.n; + (left, Some(left)) } } - impl<'a> DoubleEndedIterator for IterMut<'a> { - - #[inline] - fn next_back(&mut self) -> Option<#ref_mut_name<'a>> { - self.0.next_back().and_then(|#iter_pat| - Some(#ref_mut_name{ - #(#fields_names,)* - }) - ) - } + pub struct VecIterMut<'a> { + pub(super) vec: &'a mut #vec_name, + pub(super) n: usize, } - impl #vec_name { - /// Get a mutable iterator over the - #[doc = #ref_mut_doc_url] - /// in this vector - #visibility fn iter_mut(&mut self) -> IterMut { - IterMut(#create_iter_mut) + impl<'a> VecIterMut<'a> { + pub(self) fn new(vec: &'a mut #vec_name) -> VecIterMut<'a> { + VecIterMut { + vec, + n: 0, + } } } - impl<'a> #slice_mut_name<'a> { - /// Get an iterator over the - #[doc = #ref_doc_url] - /// in this vector - #visibility fn iter(&mut self) -> Iter { - Iter(#create_iter) - } - /// Get a mutable iterator over the - #[doc = #ref_mut_doc_url] - /// in this vector - #visibility fn iter_mut(&mut self) -> IterMut { - IterMut(#create_iter_mut) - } - } - } - }; + impl<'a> Iterator for VecIterMut<'a> { + type Item = #ref_mut_name<'a>; - if let Visibility::Public(_) = *visibility { - generated.append_all(quote!{ - impl<'a> IntoIterator for #slice_name<'a> { - type Item = #ref_name<'a>; - type IntoIter = #detail_mod::Iter<'a>; + fn next(&mut self) -> Option { + if self.n >= self.vec.len() { + return None; + } - fn into_iter(self) -> Self::IntoIter { - #detail_mod::Iter(#create_iter) + let item = unsafe { + Some(#ref_mut_name { + #( + #fields_names_1: self.vec.data.#fields_names_2.ptr().add(self.n).as_mut().unwrap(), + )* + }) + }; + self.n += 1; + item } - } - - impl std::iter::FromIterator<#name> for #vec_name { - fn from_iter>(iter: T) -> Self { - let mut result = #vec_name::new(); - for element in iter { - #( - (result.#fields_names).push(element.#fields_names); - )* + fn size_hint(&self) -> (usize, Option) { + if self.n >= self.vec.len() { + return (0, Some(0)) } - result + let left = self.vec.len() - self.n; + (left, Some(left)) } } + } - impl<'a, 'b> IntoIterator for &'a #slice_name<'b> { - type Item = #ref_name<'a>; - type IntoIter = #detail_mod::Iter<'a>; - - fn into_iter(self) -> Self::IntoIter { - #detail_mod::Iter(#create_iter) + impl #vec_name { + pub fn iter<'a>(&'a self) -> #detail_mod::VecIter<'a> { + #detail_mod::VecIter { + vec: self, + n: 0, } } - impl<'a> IntoIterator for &'a #vec_name { - type Item = #ref_name<'a>; - type IntoIter = #detail_mod::Iter<'a>; - - fn into_iter(self) -> Self::IntoIter { - #detail_mod::Iter(#create_iter) + pub fn iter_mut<'a>(&'a mut self) -> #detail_mod::VecIterMut<'a> { + #detail_mod::VecIterMut { + vec: self, + n: 0, } } + } - impl<'a> IntoIterator for #slice_mut_name<'a> { - type Item = #ref_mut_name<'a>; - type IntoIter = #detail_mod::IterMut<'a>; + impl<'a> IntoIterator for &'a #vec_name { + type Item = #ref_name<'a>; + type IntoIter = #detail_mod::VecIter<'a>; - fn into_iter(self) -> Self::IntoIter { - #detail_mod::IterMut(#create_iter_mut) - } + fn into_iter(self) -> Self::IntoIter { + return self.iter() } + } - impl<'a> IntoIterator for &'a mut #vec_name { - type Item = #ref_mut_name<'a>; - type IntoIter = #detail_mod::IterMut<'a>; + impl<'a> IntoIterator for &'a mut #vec_name { + type Item = #ref_mut_name<'a>; + type IntoIter = #detail_mod::VecIterMut<'a>; - fn into_iter(self) -> Self::IntoIter { - #detail_mod::IterMut(#create_iter_mut) - } + fn into_iter(self) -> Self::IntoIter { + return self.iter_mut() } - }); - } + } + }; return generated; } diff --git a/soa-derive-internal/src/lib.rs b/soa-derive-internal/src/lib.rs index b2510c0..8bf9545 100644 --- a/soa-derive-internal/src/lib.rs +++ b/soa-derive-internal/src/lib.rs @@ -29,6 +29,7 @@ pub fn soa_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { generated.append_all(slice::derive_mut(&input)); generated.append_all(iter::derive(&input)); generated.append_all(derive_trait(&input)); + // println!("{}", generated); // Useful for debugging. generated.into() } diff --git a/soa-derive-internal/src/slice.rs b/soa-derive-internal/src/slice.rs index f47c063..0e778af 100644 --- a/soa-derive-internal/src/slice.rs +++ b/soa-derive-internal/src/slice.rs @@ -77,66 +77,66 @@ pub fn derive(input: &Input) -> TokenStream { #(debug_assert_eq!(self.#fields_names_1.is_empty(), empty);)* empty } - - /// Similar to [` - #[doc = #slice_name_str] - /// ::first()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first). - pub fn first(&self) -> Option<#ref_name<'a>> { - if self.is_empty() { - None - } else { - #( - let #fields_names_1 = self.#fields_names_2.first().unwrap(); - )* - Some(#ref_name{#(#fields_names_1: #fields_names_2),*}) - } - } - - /// Similar to [` - #[doc = #slice_name_str] - /// ::split_first()`](https://doc.rust-lang.org/std/primitive.slice.html#method.split_first). - pub fn split_first(&self) -> Option<(#ref_name<'a>, #slice_name<'a>)> { - if self.is_empty() { - None - } else { - #( - let (#fields_names_1, #slice_names_1) = self.#fields_names_2.split_first().unwrap(); - )* - let ref_ = #ref_name{#(#fields_names_1: #fields_names_2),*}; - let slice = #slice_name{#(#fields_names_1: #slice_names_1),*}; - Some((ref_, slice)) - } - } - - /// Similar to [` - #[doc = #slice_name_str] - /// ::last()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last). - pub fn last(&self) -> Option<#ref_name<'a>> { - if self.is_empty() { - None - } else { - #( - let #fields_names_1 = self.#fields_names_2.last().unwrap(); - )* - Some(#ref_name{#(#fields_names_1: #fields_names_2),*}) - } - } - - /// Similar to [` - #[doc = #slice_name_str] - /// ::split_last()`](https://doc.rust-lang.org/std/primitive.slice.html#method.split_last). - pub fn split_last(&self) -> Option<(#ref_name<'a>, #slice_name<'a>)> { - if self.is_empty() { - None - } else { - #( - let (#fields_names_1, #slice_names_1) = self.#fields_names_2.split_last().unwrap(); - )* - let ref_ = #ref_name{#(#fields_names_1: #fields_names_2),*}; - let slice = #slice_name{#(#fields_names_1: #slice_names_1),*}; - Some((ref_, slice)) - } - } + // + // /// Similar to [` + // #[doc = #slice_name_str] + // /// ::first()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first). + // pub fn first(&self) -> Option<#ref_name<'a>> { + // if self.is_empty() { + // None + // } else { + // #( + // let #fields_names_1 = self.#fields_names_2.first().unwrap(); + // )* + // Some(#ref_name{#(#fields_names_1: #fields_names_2),*}) + // } + // } + // + // /// Similar to [` + // #[doc = #slice_name_str] + // /// ::split_first()`](https://doc.rust-lang.org/std/primitive.slice.html#method.split_first). + // pub fn split_first(&self) -> Option<(#ref_name<'a>, #slice_name<'a>)> { + // if self.is_empty() { + // None + // } else { + // #( + // let (#fields_names_1, #slice_names_1) = self.#fields_names_2.split_first().unwrap(); + // )* + // let ref_ = #ref_name{#(#fields_names_1: #fields_names_2),*}; + // let slice = #slice_name{#(#fields_names_1: #slice_names_1),*}; + // Some((ref_, slice)) + // } + // } + // + // /// Similar to [` + // #[doc = #slice_name_str] + // /// ::last()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last). + // pub fn last(&self) -> Option<#ref_name<'a>> { + // if self.is_empty() { + // None + // } else { + // #( + // let #fields_names_1 = self.#fields_names_2.last().unwrap(); + // )* + // Some(#ref_name{#(#fields_names_1: #fields_names_2),*}) + // } + // } + // + // /// Similar to [` + // #[doc = #slice_name_str] + // /// ::split_last()`](https://doc.rust-lang.org/std/primitive.slice.html#method.split_last). + // pub fn split_last(&self) -> Option<(#ref_name<'a>, #slice_name<'a>)> { + // if self.is_empty() { + // None + // } else { + // #( + // let (#fields_names_1, #slice_names_1) = self.#fields_names_2.split_last().unwrap(); + // )* + // let ref_ = #ref_name{#(#fields_names_1: #fields_names_2),*}; + // let slice = #slice_name{#(#fields_names_1: #slice_names_1),*}; + // Some((ref_, slice)) + // } + // } /// Similar to [` #[doc = #slice_name_str] @@ -149,28 +149,28 @@ pub fn derive(input: &Input) -> TokenStream { let right = #slice_name{#(#fields_names_1: #slice_names_2),*}; (left, right) } - - /// Similar to [` - #[doc = #slice_name_str] - /// ::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get). - pub fn get(&self, i: usize) -> Option<#ref_name> { - if self.is_empty() || i >= self.len() { - None - } else { - Some(#ref_name { - #(#fields_names_1: self.#fields_names_2.get(i).unwrap(),)* - }) - } - } - - /// Similar to [` - #[doc = #slice_name_str] - /// ::get_unchecked()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_unchecked). - pub unsafe fn get_unchecked(&self, i: usize) -> #ref_name { - #ref_name { - #(#fields_names_1: self.#fields_names_2.get_unchecked(i),)* - } - } + // + // /// Similar to [` + // #[doc = #slice_name_str] + // /// ::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get). + // pub fn get(&self, i: usize) -> Option<#ref_name> { + // if self.is_empty() || i >= self.len() { + // None + // } else { + // Some(#ref_name { + // #(#fields_names_1: self.#fields_names_2.get(i).unwrap(),)* + // }) + // } + // } + // + // /// Similar to [` + // #[doc = #slice_name_str] + // /// ::get_unchecked()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_unchecked). + // pub unsafe fn get_unchecked(&self, i: usize) -> #ref_name { + // #ref_name { + // #(#fields_names_1: self.#fields_names_2.get_unchecked(i),)* + // } + // } /// Similar to [` #[doc = #slice_name_str] @@ -297,78 +297,78 @@ pub fn derive_mut(input: &Input) -> TokenStream { #(debug_assert_eq!(self.#fields_names_1.is_empty(), empty);)* empty } - - /// Similar to [` - #[doc = #slice_name_str] - /// ::first_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first_mut). - pub fn first_mut(&mut self) -> Option<#ref_mut_name> { - if self.is_empty() { - None - } else { - #( - let #fields_names_1 = self.#fields_names_2.first_mut().unwrap(); - )* - Some(#ref_mut_name{#(#fields_names_1: #fields_names_2),*}) - } - } - - /// Similar to [` - #[doc = #slice_name_str] - /// ::split_first_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.split_first_mut). - pub fn split_first_mut(&mut self) -> Option<(#ref_mut_name, #slice_mut_name)> { - if self.is_empty() { - None - } else { - #( - let (#fields_names_1, #slice_names_1) = self.#fields_names_2.split_first_mut().unwrap(); - )* - let ref_ = #ref_mut_name{#(#fields_names_1: #fields_names_2),*}; - let slice = #slice_mut_name{#(#fields_names_1: #slice_names_1),*}; - Some((ref_, slice)) - } - } - - /// Similar to [` - #[doc = #slice_name_str] - /// ::last_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last_mut). - pub fn last_mut(&mut self) -> Option<#ref_mut_name> { - if self.is_empty() { - None - } else { - #( - let #fields_names_1 = self.#fields_names_2.last_mut().unwrap(); - )* - Some(#ref_mut_name{#(#fields_names_1: #fields_names_2),*}) - } - } - - /// Similar to [` - #[doc = #slice_name_str] - /// ::last_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last_mut). - pub fn split_last_mut(&mut self) -> Option<(#ref_mut_name, #slice_mut_name)> { - if self.is_empty() { - None - } else { - #( - let (#fields_names_1, #slice_names_1) = self.#fields_names_2.split_last_mut().unwrap(); - )* - let ref_ = #ref_mut_name{#(#fields_names_1: #fields_names_2),*}; - let slice = #slice_mut_name{#(#fields_names_1: #slice_names_1),*}; - Some((ref_, slice)) - } - } - - /// Similar to [` - #[doc = #slice_name_str] - /// ::split_at_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.split_at_mut). - pub fn split_at_mut(&mut self, mid: usize) -> (#slice_mut_name, #slice_mut_name) { - #( - let (#slice_names_1, #slice_names_2) = self.#fields_names_2.split_at_mut(mid); - )* - let left = #slice_mut_name{#(#fields_names_1: #slice_names_1),*}; - let right = #slice_mut_name{#(#fields_names_1: #slice_names_2),*}; - (left, right) - } + // + // /// Similar to [` + // #[doc = #slice_name_str] + // /// ::first_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.first_mut). + // pub fn first_mut(&mut self) -> Option<#ref_mut_name> { + // if self.is_empty() { + // None + // } else { + // #( + // let #fields_names_1 = self.#fields_names_2.first_mut().unwrap(); + // )* + // Some(#ref_mut_name{#(#fields_names_1: #fields_names_2),*}) + // } + // } + // + // /// Similar to [` + // #[doc = #slice_name_str] + // /// ::split_first_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.split_first_mut). + // pub fn split_first_mut(&mut self) -> Option<(#ref_mut_name, #slice_mut_name)> { + // if self.is_empty() { + // None + // } else { + // #( + // let (#fields_names_1, #slice_names_1) = self.#fields_names_2.split_first_mut().unwrap(); + // )* + // let ref_ = #ref_mut_name{#(#fields_names_1: #fields_names_2),*}; + // let slice = #slice_mut_name{#(#fields_names_1: #slice_names_1),*}; + // Some((ref_, slice)) + // } + // } + // + // /// Similar to [` + // #[doc = #slice_name_str] + // /// ::last_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last_mut). + // pub fn last_mut(&mut self) -> Option<#ref_mut_name> { + // if self.is_empty() { + // None + // } else { + // #( + // let #fields_names_1 = self.#fields_names_2.last_mut().unwrap(); + // )* + // Some(#ref_mut_name{#(#fields_names_1: #fields_names_2),*}) + // } + // } + // + // /// Similar to [` + // #[doc = #slice_name_str] + // /// ::last_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.last_mut). + // pub fn split_last_mut(&mut self) -> Option<(#ref_mut_name, #slice_mut_name)> { + // if self.is_empty() { + // None + // } else { + // #( + // let (#fields_names_1, #slice_names_1) = self.#fields_names_2.split_last_mut().unwrap(); + // )* + // let ref_ = #ref_mut_name{#(#fields_names_1: #fields_names_2),*}; + // let slice = #slice_mut_name{#(#fields_names_1: #slice_names_1),*}; + // Some((ref_, slice)) + // } + // } + // + // /// Similar to [` + // #[doc = #slice_name_str] + // /// ::split_at_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.split_at_mut). + // pub fn split_at_mut(&mut self, mid: usize) -> (#slice_mut_name, #slice_mut_name) { + // #( + // let (#slice_names_1, #slice_names_2) = self.#fields_names_2.split_at_mut(mid); + // )* + // let left = #slice_mut_name{#(#fields_names_1: #slice_names_1),*}; + // let right = #slice_mut_name{#(#fields_names_1: #slice_names_2),*}; + // (left, right) + // } /// Similar to [` #[doc = #slice_name_str] @@ -379,49 +379,49 @@ pub fn derive_mut(input: &Input) -> TokenStream { )* } - /// Similar to [` - #[doc = #slice_name_str] - /// ::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get). - pub fn get(&self, i: usize) -> Option<#ref_name> { - if self.is_empty() || i >= self.len() { - None - } else { - Some(#ref_name { - #(#fields_names_1: self.#fields_names_2.get(i).unwrap(),)* - }) - } - } - - /// Similar to [` - #[doc = #slice_name_str] - /// ::get_unchecked()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_unchecked). - pub unsafe fn get_unchecked(&self, i: usize) -> #ref_name { - #ref_name { - #(#fields_names_1: self.#fields_names_2.get_unchecked(i),)* - } - } - - /// Similar to [` - #[doc = #slice_name_str] - /// ::get_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_mut). - pub fn get_mut(&mut self, i: usize) -> Option<#ref_mut_name> { - if self.is_empty() || i >= self.len() { - None - } else { - Some(#ref_mut_name { - #(#fields_names_1: self.#fields_names_2.get_mut(i).unwrap(),)* - }) - } - } - - /// Similar to [` - #[doc = #slice_name_str] - /// ::get_unchecked_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_unchecked_mut). - pub unsafe fn get_unchecked_mut(&mut self, i: usize) -> #ref_mut_name { - #ref_mut_name { - #(#fields_names_1: self.#fields_names_2.get_unchecked_mut(i),)* - } - } + // /// Similar to [` + // #[doc = #slice_name_str] + // /// ::get()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get). + // pub fn get(&self, i: usize) -> Option<#ref_name> { + // if self.is_empty() || i >= self.len() { + // None + // } else { + // Some(#ref_name { + // #(#fields_names_1: self.#fields_names_2.get(i).unwrap(),)* + // }) + // } + // } + // + // /// Similar to [` + // #[doc = #slice_name_str] + // /// ::get_unchecked()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_unchecked). + // pub unsafe fn get_unchecked(&self, i: usize) -> #ref_name { + // #ref_name { + // #(#fields_names_1: self.#fields_names_2.get_unchecked(i),)* + // } + // } + // + // /// Similar to [` + // #[doc = #slice_name_str] + // /// ::get_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_mut). + // pub fn get_mut(&mut self, i: usize) -> Option<#ref_mut_name> { + // if self.is_empty() || i >= self.len() { + // None + // } else { + // Some(#ref_mut_name { + // #(#fields_names_1: self.#fields_names_2.get_mut(i).unwrap(),)* + // }) + // } + // } + // + // /// Similar to [` + // #[doc = #slice_name_str] + // /// ::get_unchecked_mut()`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_unchecked_mut). + // pub unsafe fn get_unchecked_mut(&mut self, i: usize) -> #ref_mut_name { + // #ref_mut_name { + // #(#fields_names_1: self.#fields_names_2.get_unchecked_mut(i),)* + // } + // } /// Similar to [` #[doc = #slice_name_str] diff --git a/soa-derive-internal/src/vec.rs b/soa-derive-internal/src/vec.rs index e741c05..cb5e525 100644 --- a/soa-derive-internal/src/vec.rs +++ b/soa-derive-internal/src/vec.rs @@ -11,9 +11,9 @@ pub fn derive(input: &Input) -> TokenStream { let other_derive = &input.derive(); let visibility = &input.visibility; let vec_name = &input.vec_name(); + let vec_fields_name = &input.vec_fields_name(); let slice_name = &input.slice_name(); let slice_mut_name = &input.slice_mut_name(); - let ref_name = &input.ref_name(); let ptr_name = &input.ptr_name(); let ptr_mut_name = &input.ptr_mut_name(); @@ -22,27 +22,38 @@ pub fn derive(input: &Input) -> TokenStream { .collect::>(); let fields_names_1 = &fields_names; let fields_names_2 = &fields_names; - let first_field = &fields_names[0]; - - let fields_doc = fields_names.iter() - .map(|field| format!("A vector of `{0}` from a [`{1}`](struct.{1}.html)", field, name)) - .collect::>(); let fields_types = &input.fields.iter() .map(|field| &field.ty) .collect::>(); + let imports = quote!{ + extern crate alloc; + + use alloc::raw_vec::RawVec; + use std::ptr; + use std::slice; + }; + let mut generated = quote! { + #imports + + /// Contains the RawVecs of the SoA + #other_derive + struct #vec_fields_name { + #( + pub #fields_names_1: RawVec<#fields_types>, + )* + } + /// An analog to ` #[doc = #vec_name_str] /// ` with Struct of Array (SoA) layout #[allow(dead_code)] #other_derive #visibility struct #vec_name { - #( - #[doc = #fields_doc] - pub #fields_names_1: Vec<#fields_types>, - )* + data: #vec_fields_name, + len: usize, } #[allow(dead_code)] @@ -52,7 +63,10 @@ pub fn derive(input: &Input) -> TokenStream { /// ::new()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.new) pub fn new() -> #vec_name { #vec_name { - #(#fields_names_1 : Vec::new(),)* + data: #vec_fields_name{ + #(#fields_names_1: RawVec::new(),)* + }, + len: 0, } } @@ -62,7 +76,10 @@ pub fn derive(input: &Input) -> TokenStream { /// initializing all fields with the given `capacity`. pub fn with_capacity(capacity: usize) -> #vec_name { #vec_name { - #(#fields_names_1 : Vec::with_capacity(capacity),)* + data: #vec_fields_name { + #(#fields_names_1 : RawVec::with_capacity(capacity),)* + }, + len: 0, } } @@ -71,9 +88,11 @@ pub fn derive(input: &Input) -> TokenStream { /// ::capacity()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.capacity), /// the capacity of all fields should be the same. pub fn capacity(&self) -> usize { - let capacity = self.#first_field.capacity(); - #(debug_assert_eq!(self.#fields_names_1.capacity(), capacity);)* - capacity + let vec: Vec = vec![#(self.data.#fields_names_1.capacity()),*]; + match vec.iter().min() { + None => usize::MAX, // If there are no fields, capacity is the maximum possible (no need to allocate anything). + Some(result) => *result + } } /// Similar to [` @@ -81,7 +100,7 @@ pub fn derive(input: &Input) -> TokenStream { /// ::reserve()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.reserve), /// reserving the same `additional` space for all fields. pub fn reserve(&mut self, additional: usize) { - #(self.#fields_names_1.reserve(additional);)* + #(self.data.#fields_names_1.reserve(self.len, additional);)* } /// Similar to [` @@ -89,15 +108,7 @@ pub fn derive(input: &Input) -> TokenStream { /// ::reserve_exact()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.reserve_exact) /// reserving the same `additional` space for all fields. pub fn reserve_exact(&mut self, additional: usize) { - #(self.#fields_names_1.reserve_exact(additional);)* - } - - /// Similar to [` - #[doc = #vec_name_str] - /// ::shrink_to_fit()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.shrink_to_fit) - /// shrinking all fields. - pub fn shrink_to_fit(&mut self) { - #(self.#fields_names_1.shrink_to_fit();)* + #(self.data.#fields_names_1.reserve_exact(self.len, additional);)* } /// Similar to [` @@ -105,25 +116,42 @@ pub fn derive(input: &Input) -> TokenStream { /// ::truncate()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.truncate) /// truncating all fields. pub fn truncate(&mut self, len: usize) { - #(self.#fields_names_1.truncate(len);)* + unsafe { + // Destroy the elements that are outside the given length + while len < self.len { + let i = self.len - 1; + + // Decrement len before calling drop_in_place() so a panic on Drop + // doesn't try to drop it a second time. + self.len -= 1; + + #(ptr::drop_in_place(self.data.#fields_names_1.ptr().add(i));)* + } + } } /// Similar to [` #[doc = #vec_name_str] /// ::push()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.push). pub fn push(&mut self, value: #name) { + fn write_to_raw_vec(buf: &mut RawVec, value: T, index: usize) { + unsafe { + let ptr = buf.ptr().add(index); + ptr::write(ptr, value); + } + } + let #name{#(#fields_names_1),*} = value; - #(self.#fields_names_1.push(#fields_names_2);)* + self.reserve(1); + #(write_to_raw_vec(&mut self.data.#fields_names_1, #fields_names_2, self.len);)* + self.len += 1; } /// Similar to [` #[doc = #vec_name_str] - /// ::len()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.len), - /// all the fields should have the same length. + /// ::len()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.len) pub fn len(&self) -> usize { - let len = self.#first_field.len(); - #(debug_assert_eq!(self.#fields_names_1.len(), len);)* - len + self.len } /// Similar to [` @@ -131,37 +159,72 @@ pub fn derive(input: &Input) -> TokenStream { /// ::is_empty()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.is_empty), /// all the fields should have the same length. pub fn is_empty(&self) -> bool { - let empty = self.#first_field.is_empty(); - #(debug_assert_eq!(self.#fields_names_1.is_empty(), empty);)* - empty + self.len == 0 } /// Similar to [` #[doc = #vec_name_str] /// ::swap_remove()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.swap_remove). pub fn swap_remove(&mut self, index: usize) -> #name { - #( - let #fields_names_1 = self.#fields_names_2.swap_remove(index); - )* - #name{#(#fields_names_1: #fields_names_2),*} + let length = self.len; + let slices = self.as_mut_slice(); + #(slices.#fields_names_1.swap(index, length - 1);)* + self.pop().unwrap() } /// Similar to [` #[doc = #vec_name_str] /// ::insert()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.insert). pub fn insert(&mut self, index: usize, element: #name) { + fn insert_into_raw_vec(buf: &mut RawVec, len: usize, value: T, index: usize) { + unsafe { + // infallible + // The spot to put the new value + let p = buf.ptr().add(index); + // Shift everything over to make space. (Duplicating the + // `index`th element into two consecutive places.) + ptr::copy(p, p.offset(1), len - index); + // Write it in, overwriting the first copy of the `index`th + // element. + ptr::write(p, value); + } + } + let #name{#(#fields_names_1),*} = element; - #(self.#fields_names_1.insert(index, #fields_names_2);)* + let len = self.len(); + assert!(index <= len); + + self.reserve(1); + #(insert_into_raw_vec(&mut self.data.#fields_names_1, len, #fields_names_2, index);)* + self.len += 1; } /// Similar to [` #[doc = #vec_name_str] /// ::remove()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.remove). pub fn remove(&mut self, index: usize) -> #name { - #( - let #fields_names_1 = self.#fields_names_2.remove(index); - )* - #name{#(#fields_names_1: #fields_names_2),*} + fn raw_vec_remove(buf: &mut RawVec, len: usize, index: usize) -> T { + unsafe { + // infallible + let ret; + { + // the place we are taking from. + let ptr = buf.ptr().add(index); + // copy it out, unsafely having a copy of the value on + // the stack and in the vector at the same time. + ret = ptr::read(ptr); + + // Shift everything down to fill in that spot. + ptr::copy(ptr.offset(1), ptr, len - index - 1); + } + ret + } + } + + let len = self.len(); + assert!(index < len); + self.len -= 1; + #name{#(#fields_names_1: raw_vec_remove(&mut self.data.#fields_names_2, len, index)),*} } /// Similar to [` @@ -171,10 +234,14 @@ pub fn derive(input: &Input) -> TokenStream { if self.is_empty() { None } else { - #( - let #fields_names_1 = self.#fields_names_2.pop().unwrap(); - )* - Some(#name{#(#fields_names_1: #fields_names_2),*}) + self.len -= 1; + + unsafe { + #( + let #fields_names_1 = ptr::read(self.data.#fields_names_2.ptr().offset(self.len as isize)); + )* + Some(#name{#(#fields_names_1: #fields_names_2),*}) + } } } @@ -182,33 +249,38 @@ pub fn derive(input: &Input) -> TokenStream { #[doc = #vec_name_str] /// ::append()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.append). pub fn append(&mut self, other: &mut #vec_name) { + fn append_raw_vec(src: &RawVec, srclen: usize, dst: &mut RawVec, dstlen: usize) { + dst.reserve(dstlen, srclen); + unsafe { + ptr::copy_nonoverlapping(src.ptr(), dst.ptr().add(dstlen), srclen) + } + } + + let len = self.len(); + let otherlen = other.len(); + self.reserve(otherlen); #( - self.#fields_names_1.append(&mut other.#fields_names_2); + append_raw_vec(&other.data.#fields_names_1, otherlen, &mut self.data.#fields_names_2, len); )* + other.len = 0; + self.len += otherlen; } /// Similar to [` #[doc = #vec_name_str] /// ::clear()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.clear). pub fn clear(&mut self) { - #(self.#fields_names_1.clear();)* - } - - /// Similar to [` - #[doc = #vec_name_str] - /// ::split_off()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.split_off). - pub fn split_off(&mut self, at: usize) -> #vec_name { - #vec_name { - #(#fields_names_1 : self.#fields_names_2.split_off(at), )* - } + self.truncate(0); } /// Similar to [` #[doc = #vec_name_str] /// ::as_slice()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.as_slice). pub fn as_slice(&self) -> #slice_name { - #slice_name { - #(#fields_names_1 : &self.#fields_names_2, )* + unsafe { + #slice_name { + #(#fields_names_1 : slice::from_raw_parts(self.data.#fields_names_2.ptr(), self.len()), )* + } } } @@ -216,47 +288,11 @@ pub fn derive(input: &Input) -> TokenStream { #[doc = #vec_name_str] /// ::as_mut_slice()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.as_mut_slice). pub fn as_mut_slice(&mut self) -> #slice_mut_name { - #slice_mut_name { - #(#fields_names_1 : &mut self.#fields_names_2, )* - } - } - - /// Create a slice of this vector matching the given `range`. This - /// is analogous to `Index>`. - pub fn slice(&self, range: ::std::ops::Range) -> #slice_name { - #slice_name { - #(#fields_names_1 : &self.#fields_names_2[range.clone()], )* - } - } - - /// Create a mutable slice of this vector matching the given - /// `range`. This is analogous to `IndexMut>`. - pub fn slice_mut(&mut self, range: ::std::ops::Range) -> #slice_mut_name { - #slice_mut_name { - #(#fields_names_1 : &mut self.#fields_names_2[range.clone()], )* - } - } - - /// Similar to [` - #[doc = #vec_name_str] - /// ::retain()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.retain). - pub fn retain(&mut self, mut f: F) where F: FnMut(#ref_name) -> bool { - let len = self.len(); - let mut del = 0; - - { - let mut slice = self.as_mut_slice(); - for i in 0..len { - if !f(slice.get(i).unwrap()) { - del += 1; - } else if del > 0 { - slice.swap(i - del, i); - } + unsafe { + #slice_mut_name { + #(#fields_names_1 : slice::from_raw_parts_mut(self.data.#fields_names_2.ptr(), self.len()), )* } } - if del > 0 { - self.truncate(len - del); - } } /// Similar to [` @@ -264,7 +300,7 @@ pub fn derive(input: &Input) -> TokenStream { /// ::as_ptr()`](https://doc.rust-lang.org/std/struct.Vec.html#method.as_ptr). pub fn as_ptr(&self) -> #ptr_name { #ptr_name { - #(#fields_names_1: self.#fields_names_2.as_ptr(),)* + #(#fields_names_1: self.data.#fields_names_2.ptr(),)* } } @@ -273,36 +309,11 @@ pub fn derive(input: &Input) -> TokenStream { /// ::as_mut_ptr()`](https://doc.rust-lang.org/std/struct.Vec.html#method.as_mut_ptr). pub fn as_mut_ptr(&mut self) -> #ptr_mut_name { #ptr_mut_name { - #(#fields_names_1: self.#fields_names_2.as_mut_ptr(),)* - } - } - - /// Similar to [` - #[doc = #vec_name_str] - /// ::from_raw_parts()`](https://doc.rust-lang.org/std/struct.Vec.html#method.from_raw_parts). - pub unsafe fn from_raw_parts(data: #ptr_mut_name, len: usize, capacity: usize) -> #vec_name { - #vec_name { - #(#fields_names_1: Vec::from_raw_parts(data.#fields_names_2, len, capacity),)* + #(#fields_names_1: self.data.#fields_names_2.ptr(),)* } } } }; - if input.derives.contains(&Ident::new("Clone", Span::call_site())) { - generated.append_all(quote!{ - #[allow(dead_code)] - impl #vec_name { - /// Similar to [` - #[doc = #vec_name_str] - /// ::resize()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.resize). - pub fn resize(&mut self, new_len: usize, value: #name) { - #( - self.#fields_names_1.resize(new_len, value.#fields_names_2); - )* - } - } - }); - } - return generated; } diff --git a/tests/particles/mod.rs b/tests/particles/mod.rs index 9903bb0..e3f5faa 100644 --- a/tests/particles/mod.rs +++ b/tests/particles/mod.rs @@ -3,7 +3,7 @@ use soa_derive::StructOfArray; #[derive(Debug, Clone, PartialEq, StructOfArray)] -#[soa_derive = "Debug, Clone, PartialEq"] +// #[soa_derive = "Debug, Clone, PartialEq"] pub struct Particle { pub name: String, pub mass: f64, diff --git a/tests/vec.rs b/tests/vec.rs index 0416201..ccb76e9 100644 --- a/tests/vec.rs +++ b/tests/vec.rs @@ -1,19 +1,15 @@ +#![feature(raw_vec_internals)] + mod particles; use self::particles::{Particle, ParticleVec}; -use soa_derive::StructOfArray; - -#[test] -fn ty() { - let _: ::Type = ParticleVec::new(); -} #[test] fn push() { let mut particles = ParticleVec::new(); particles.push(Particle::new(String::from("Na"), 56.0)); - assert_eq!(particles.name[0], "Na"); - assert_eq!(particles.mass[0], 56.0); + assert_eq!(particles.as_slice().name[0], "Na"); + assert_eq!(particles.as_slice().mass[0], 56.0); } #[test] @@ -47,10 +43,6 @@ fn capacity() { particles.push(Particle::new(String::from("Na"), 56.0)); assert_eq!(particles.len(), 2); assert!(particles.capacity() == 100); - - particles.shrink_to_fit(); - assert_eq!(particles.len(), 2); - assert_eq!(particles.capacity(), 2); } #[test] @@ -63,9 +55,9 @@ fn remove() { let particle = particles.remove(1); assert_eq!(particle.name, "Na"); - assert_eq!(particles.name[0], "Cl"); - assert_eq!(particles.name[1], "Br"); - assert_eq!(particles.name[2], "Zn"); + assert_eq!(particles.as_slice().name[0], "Cl"); + assert_eq!(particles.as_slice().name[1], "Br"); + assert_eq!(particles.as_slice().name[2], "Zn"); } #[test] @@ -78,9 +70,9 @@ fn swap_remove() { let particle = particles.swap_remove(1); assert_eq!(particle.name, "Na"); - assert_eq!(particles.name[0], "Cl"); - assert_eq!(particles.name[1], "Zn"); - assert_eq!(particles.name[2], "Br"); + assert_eq!(particles.as_slice().name[0], "Cl"); + assert_eq!(particles.as_slice().name[1], "Zn"); + assert_eq!(particles.as_slice().name[2], "Br"); } #[test] @@ -90,9 +82,9 @@ fn insert() { particles.push(Particle::new(String::from("Na"), 0.0)); particles.insert(1, Particle::new(String::from("Zn"), 0.0)); - assert_eq!(particles.name[0], "Cl"); - assert_eq!(particles.name[1], "Zn"); - assert_eq!(particles.name[2], "Na"); + assert_eq!(particles.as_slice().name[0], "Cl"); + assert_eq!(particles.as_slice().name[1], "Zn"); + assert_eq!(particles.as_slice().name[2], "Na"); } #[test] @@ -122,40 +114,8 @@ fn append() { others.push(Particle::new(String::from("Mg"), 0.0)); particles.append(&mut others); - assert_eq!(particles.name[0], "Cl"); - assert_eq!(particles.name[1], "Na"); - assert_eq!(particles.name[2], "Zn"); - assert_eq!(particles.name[3], "Mg"); -} - -#[test] -fn split_off() { - let mut particles = ParticleVec::new(); - particles.push(Particle::new(String::from("Cl"), 0.0)); - particles.push(Particle::new(String::from("Na"), 0.0)); - particles.push(Particle::new(String::from("Zn"), 0.0)); - particles.push(Particle::new(String::from("Mg"), 0.0)); - - let other = particles.split_off(2); - assert_eq!(particles.len(), 2); - assert_eq!(other.len(), 2); - - assert_eq!(particles.name[0], "Cl"); - assert_eq!(particles.name[1], "Na"); - assert_eq!(other.name[0], "Zn"); - assert_eq!(other.name[1], "Mg"); -} - -#[test] -fn retain() { - let mut particles = ParticleVec::new(); - particles.push(Particle::new(String::from("Cl"), 0.0)); - particles.push(Particle::new(String::from("Na"), 0.0)); - particles.push(Particle::new(String::from("Zn"), 0.0)); - particles.push(Particle::new(String::from("C"), 0.0)); - - particles.retain(|particle| particle.name.starts_with("C")); - assert_eq!(particles.len(), 2); - assert_eq!(particles.name[0], "Cl"); - assert_eq!(particles.name[1], "C"); + assert_eq!(particles.as_slice().name[0], "Cl"); + assert_eq!(particles.as_slice().name[1], "Na"); + assert_eq!(particles.as_slice().name[2], "Zn"); + assert_eq!(particles.as_slice().name[3], "Mg"); }