#[cfg(test)]
#[path = "./array_tests.rs"]
mod tests;
use crate::MaybeItem;
use crate::Span;
use crate::arena::Arena;
use crate::item::{ArrayStyle, FLAG_AOT, FLAG_ARRAY, Item, ItemMetadata, TAG_ARRAY};
use std::mem::size_of;
use std::ptr::NonNull;
const MIN_CAP: u32 = 4;
#[repr(C, align(8))]
pub(crate) struct InternalArray<'de> {
pub(super) len: u32,
pub(super) cap: u32,
pub(super) ptr: NonNull<Item<'de>>,
}
impl<'de> Default for InternalArray<'de> {
fn default() -> Self {
Self::new()
}
}
impl<'de> InternalArray<'de> {
#[inline]
pub(crate) fn new() -> Self {
Self {
len: 0,
cap: 0,
ptr: NonNull::dangling(),
}
}
pub(crate) fn with_capacity(cap: u32, arena: &'de Arena) -> Self {
let mut arr = Self::new();
if cap > 0 {
arr.grow_to(cap, arena);
}
arr
}
pub(crate) fn with_single(value: Item<'de>, arena: &'de Arena) -> Self {
let mut arr = Self::with_capacity(MIN_CAP, arena);
unsafe {
arr.ptr.as_ptr().write(value);
}
arr.len = 1;
arr
}
#[inline]
pub(crate) fn push(&mut self, value: Item<'de>, arena: &'de Arena) {
let len = self.len;
if len == self.cap {
self.grow(arena);
}
unsafe {
self.ptr.as_ptr().add(len as usize).write(value);
}
self.len = len + 1;
}
#[inline]
pub(crate) fn len(&self) -> usize {
self.len as usize
}
#[inline]
pub(crate) fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub(crate) fn get(&self, index: usize) -> Option<&Item<'de>> {
if index < self.len as usize {
Some(unsafe { &*self.ptr.as_ptr().add(index) })
} else {
None
}
}
#[inline]
pub(crate) fn get_mut(&mut self, index: usize) -> Option<&mut Item<'de>> {
if index < self.len as usize {
Some(unsafe { &mut *self.ptr.as_ptr().add(index) })
} else {
None
}
}
pub(crate) fn remove(&mut self, index: usize) -> Item<'de> {
assert!(index < self.len as usize, "index out of bounds");
let len = self.len as usize;
unsafe {
let ptr = self.ptr.as_ptr().add(index);
let removed = ptr.read();
std::ptr::copy(ptr.add(1), ptr, len - index - 1);
self.len -= 1;
removed
}
}
#[inline]
pub(crate) fn pop(&mut self) -> Option<Item<'de>> {
if self.len == 0 {
None
} else {
self.len -= 1;
Some(unsafe { self.ptr.as_ptr().add(self.len as usize).read() })
}
}
#[inline]
pub(crate) fn last_mut(&mut self) -> Option<&mut Item<'de>> {
if self.len == 0 {
None
} else {
Some(unsafe { &mut *self.ptr.as_ptr().add(self.len as usize - 1) })
}
}
#[inline]
pub(crate) fn iter(&self) -> std::slice::Iter<'_, Item<'de>> {
self.as_slice().iter()
}
#[inline]
pub(crate) fn as_slice(&self) -> &[Item<'de>] {
if self.len == 0 {
&[]
} else {
unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len as usize) }
}
}
#[inline]
pub(crate) fn as_mut_slice(&mut self) -> &mut [Item<'de>] {
if self.len == 0 {
&mut []
} else {
unsafe { std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len as usize) }
}
}
#[cold]
fn grow(&mut self, arena: &'de Arena) {
let new_cap = if self.cap == 0 {
MIN_CAP
} else {
self.cap.checked_mul(2).expect("capacity overflow")
};
self.grow_to(new_cap, arena);
}
fn grow_to(&mut self, new_cap: u32, arena: &'de Arena) {
#[cfg(target_pointer_width = "32")]
let new_size = (new_cap as usize)
.checked_mul(size_of::<Item<'_>>())
.expect("capacity overflow");
#[cfg(not(target_pointer_width = "32"))]
let new_size = new_cap as usize * size_of::<Item<'_>>();
if self.cap > 0 {
let old_size = self.cap as usize * size_of::<Item<'_>>();
self.ptr = unsafe { arena.realloc(self.ptr.cast(), old_size, new_size).cast() };
} else {
self.ptr = arena.alloc(new_size).cast();
}
self.cap = new_cap;
}
pub(crate) fn clone_in(&self, arena: &'de Arena) -> Self {
let len = self.len as usize;
if len == 0 {
return Self::new();
}
let size = len * size_of::<Item<'de>>();
let dst: NonNull<Item<'de>> = arena.alloc(size).cast();
let src = self.ptr.as_ptr();
let dst_ptr = dst.as_ptr();
let mut run_start = 0;
for i in 0..len {
if unsafe { !(*src.add(i)).is_scalar() } {
if run_start < i {
unsafe {
std::ptr::copy_nonoverlapping(
src.add(run_start),
dst_ptr.add(run_start),
i - run_start,
);
}
}
unsafe {
dst_ptr.add(i).write((*src.add(i)).clone_in(arena));
}
run_start = i + 1;
}
}
if run_start < len {
unsafe {
std::ptr::copy_nonoverlapping(
src.add(run_start),
dst_ptr.add(run_start),
len - run_start,
);
}
}
Self {
len: self.len,
cap: self.len,
ptr: dst,
}
}
pub(crate) unsafe fn emplace_in(
&self,
target: &mut crate::item::owned::ItemCopyTarget,
) -> InternalArray<'static> {
let len = self.len as usize;
if len == 0 {
return InternalArray::new();
}
let byte_size = len * size_of::<Item<'static>>();
let dst_ptr = unsafe { target.alloc_aligned(byte_size) }
.as_ptr()
.cast::<Item<'static>>();
for (i, item) in self.as_slice().iter().enumerate() {
let new_item = unsafe { item.emplace_in(target) };
unsafe { dst_ptr.add(i).write(new_item) };
}
InternalArray {
len: self.len,
cap: self.len,
ptr: unsafe { NonNull::new_unchecked(dst_ptr) },
}
}
}
impl std::fmt::Debug for InternalArray<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_list().entries(self.as_slice()).finish()
}
}
impl<'a, 'de> IntoIterator for &'a InternalArray<'de> {
type Item = &'a Item<'de>;
type IntoIter = std::slice::Iter<'a, Item<'de>>;
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter()
}
}
impl<'a, 'de> IntoIterator for &'a mut InternalArray<'de> {
type Item = &'a mut Item<'de>;
type IntoIter = std::slice::IterMut<'a, Item<'de>>;
fn into_iter(self) -> Self::IntoIter {
self.as_mut_slice().iter_mut()
}
}
pub(crate) struct InternalArrayIntoIter<'de> {
arr: InternalArray<'de>,
index: u32,
}
impl<'de> Iterator for InternalArrayIntoIter<'de> {
type Item = Item<'de>;
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.arr.len {
let val = unsafe { self.arr.ptr.as_ptr().add(self.index as usize).read() };
self.index += 1;
Some(val)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = (self.arr.len - self.index) as usize;
(remaining, Some(remaining))
}
}
impl<'de> ExactSizeIterator for InternalArrayIntoIter<'de> {}
impl<'de> IntoIterator for InternalArray<'de> {
type Item = Item<'de>;
type IntoIter = InternalArrayIntoIter<'de>;
fn into_iter(self) -> Self::IntoIter {
InternalArrayIntoIter {
arr: self,
index: 0,
}
}
}
impl<'de> std::ops::Index<usize> for InternalArray<'de> {
type Output = MaybeItem<'de>;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
if let Some(item) = self.get(index) {
return MaybeItem::from_ref(item);
}
&crate::item::NONE
}
}
#[repr(C)]
pub struct Array<'de> {
pub(crate) value: InternalArray<'de>,
pub(crate) meta: ItemMetadata,
}
const _: () = assert!(std::mem::size_of::<Array<'_>>() == std::mem::size_of::<Item<'_>>());
const _: () = assert!(std::mem::align_of::<Array<'_>>() == std::mem::align_of::<Item<'_>>());
unsafe impl Send for Array<'_> {}
unsafe impl Sync for Array<'_> {}
unsafe impl Send for IntoIter<'_> {}
unsafe impl Sync for IntoIter<'_> {}
impl<'de> Array<'de> {
pub fn new() -> Self {
let mut meta = ItemMetadata::hints(TAG_ARRAY, FLAG_ARRAY);
meta.set_auto_style();
Self {
meta,
value: InternalArray::new(),
}
}
pub fn try_with_capacity(cap: usize, arena: &'de Arena) -> Option<Self> {
let cap: u32 = cap.try_into().ok()?;
let mut meta = ItemMetadata::hints(TAG_ARRAY, FLAG_ARRAY);
meta.set_auto_style();
Some(Self {
meta,
value: InternalArray::with_capacity(cap, arena),
})
}
#[cfg(test)]
pub(crate) fn new_spanned(span: Span) -> Self {
Self {
meta: ItemMetadata::spanned(TAG_ARRAY, FLAG_ARRAY, span.start, span.end),
value: InternalArray::new(),
}
}
#[cfg_attr(not(test), allow(dead_code))]
pub(crate) fn span_unchecked(&self) -> Span {
self.meta.span_unchecked()
}
pub fn span(&self) -> Span {
self.meta.span()
}
#[inline]
pub fn push(&mut self, value: Item<'de>, arena: &'de Arena) {
self.value.push(value, arena);
}
#[inline]
pub fn len(&self) -> usize {
self.value.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.value.is_empty()
}
#[inline]
pub fn get(&self, index: usize) -> Option<&Item<'de>> {
self.value.get(index)
}
#[inline]
pub fn get_mut(&mut self, index: usize) -> Option<&mut Item<'de>> {
self.value.get_mut(index)
}
#[inline]
pub fn remove(&mut self, index: usize) -> Item<'de> {
self.value.remove(index)
}
#[inline]
pub fn pop(&mut self) -> Option<Item<'de>> {
self.value.pop()
}
#[inline]
pub fn last_mut(&mut self) -> Option<&mut Item<'de>> {
self.value.last_mut()
}
#[inline]
pub fn iter(&self) -> std::slice::Iter<'_, Item<'de>> {
self.value.iter()
}
#[inline]
pub fn as_slice(&self) -> &[Item<'de>] {
self.value.as_slice()
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [Item<'de>] {
self.value.as_mut_slice()
}
pub fn as_item(&self) -> &Item<'de> {
unsafe { &*(self as *const Array<'de>).cast::<Item<'de>>() }
}
pub fn into_item(self) -> Item<'de> {
unsafe { std::mem::transmute(self) }
}
#[inline]
pub fn style(&self) -> ArrayStyle {
match self.meta.flag() {
FLAG_AOT => ArrayStyle::Header,
_ => ArrayStyle::Inline,
}
}
#[inline]
pub fn set_style(&mut self, kind: ArrayStyle) {
let flag = match kind {
ArrayStyle::Inline => FLAG_ARRAY,
ArrayStyle::Header => FLAG_AOT,
};
self.meta.set_flag(flag);
self.meta.clear_auto_style();
}
pub fn clone_in(&self, arena: &'de Arena) -> Array<'de> {
Array {
value: self.value.clone_in(arena),
meta: self.meta,
}
}
}
impl<'de> Default for Array<'de> {
fn default() -> Self {
Self::new()
}
}
impl std::fmt::Debug for Array<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.value.fmt(f)
}
}
impl<'de> std::ops::Index<usize> for Array<'de> {
type Output = MaybeItem<'de>;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
if let Some(item) = self.value.get(index) {
return MaybeItem::from_ref(item);
}
&crate::item::NONE
}
}
impl<'a, 'de> IntoIterator for &'a Array<'de> {
type Item = &'a Item<'de>;
type IntoIter = std::slice::Iter<'a, Item<'de>>;
fn into_iter(self) -> Self::IntoIter {
self.value.as_slice().iter()
}
}
impl<'a, 'de> IntoIterator for &'a mut Array<'de> {
type Item = &'a mut Item<'de>;
type IntoIter = std::slice::IterMut<'a, Item<'de>>;
fn into_iter(self) -> Self::IntoIter {
self.value.as_mut_slice().iter_mut()
}
}
pub struct IntoIter<'de> {
arr: InternalArray<'de>,
index: u32,
}
impl<'de> Iterator for IntoIter<'de> {
type Item = Item<'de>;
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.arr.len {
let val = unsafe { self.arr.ptr.as_ptr().add(self.index as usize).read() };
self.index += 1;
Some(val)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = (self.arr.len - self.index) as usize;
(remaining, Some(remaining))
}
}
impl<'de> ExactSizeIterator for IntoIter<'de> {}
impl<'de> IntoIterator for Array<'de> {
type Item = Item<'de>;
type IntoIter = IntoIter<'de>;
fn into_iter(self) -> Self::IntoIter {
IntoIter {
arr: self.value,
index: 0,
}
}
}