mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
Don't require Clone on as many RocList methods
This commit is contained in:
parent
1f45d13c67
commit
90badfe81f
1 changed files with 86 additions and 84 deletions
|
@ -147,6 +147,92 @@ impl<T> RocList<T>
|
||||||
where
|
where
|
||||||
T: Clone,
|
T: Clone,
|
||||||
{
|
{
|
||||||
|
pub fn from_slice(slice: &[T]) -> Self {
|
||||||
|
let mut list = Self::empty();
|
||||||
|
list.extend_from_slice(slice);
|
||||||
|
list
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extend_from_slice(&mut self, slice: &[T]) {
|
||||||
|
// TODO: Can we do better for ZSTs? Alignment might be a problem.
|
||||||
|
if slice.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_len = self.len() + slice.len();
|
||||||
|
let non_null_elements = if let Some((elements, storage)) = self.elements_and_storage() {
|
||||||
|
// Decrement the list's refence count.
|
||||||
|
let mut copy = storage.get();
|
||||||
|
let is_unique = copy.decrease();
|
||||||
|
|
||||||
|
if is_unique {
|
||||||
|
// If we have enough capacity, we can add to the existing elements in-place.
|
||||||
|
if self.capacity() >= slice.len() {
|
||||||
|
elements
|
||||||
|
} else {
|
||||||
|
// There wasn't enough capacity, so we need a new allocation.
|
||||||
|
// Since this is a unique RocList, we can use realloc here.
|
||||||
|
let new_ptr = unsafe {
|
||||||
|
roc_realloc(
|
||||||
|
storage.as_ptr().cast(),
|
||||||
|
Self::alloc_bytes(new_len),
|
||||||
|
Self::alloc_bytes(self.capacity),
|
||||||
|
Self::alloc_alignment(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.capacity = new_len;
|
||||||
|
|
||||||
|
Self::elems_from_allocation(NonNull::new(new_ptr).unwrap_or_else(|| {
|
||||||
|
todo!("Reallocation failed");
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !copy.is_readonly() {
|
||||||
|
// Write the decremented reference count back.
|
||||||
|
storage.set(copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate new memory.
|
||||||
|
let new_elements = Self::elems_with_capacity(slice.len());
|
||||||
|
|
||||||
|
// Copy the old elements to the new allocation.
|
||||||
|
unsafe {
|
||||||
|
copy_nonoverlapping(elements.as_ptr(), new_elements.as_ptr(), self.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
new_elements
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Self::elems_with_capacity(slice.len())
|
||||||
|
};
|
||||||
|
|
||||||
|
self.elements = Some(non_null_elements);
|
||||||
|
|
||||||
|
let elements = self.elements.unwrap().as_ptr();
|
||||||
|
|
||||||
|
let append_ptr = unsafe { elements.add(self.len()) };
|
||||||
|
|
||||||
|
// Use .cloned() to increment the elements' reference counts, if needed.
|
||||||
|
for (i, new_elem) in slice.iter().cloned().enumerate() {
|
||||||
|
unsafe {
|
||||||
|
// Write the element into the slot, without dropping it.
|
||||||
|
append_ptr
|
||||||
|
.add(i)
|
||||||
|
.write(ptr::read(&ManuallyDrop::new(new_elem)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's important that the length is increased one by one, to
|
||||||
|
// make sure that we don't drop uninitialized elements, even when
|
||||||
|
// a incrementing the reference count panics.
|
||||||
|
self.length += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.capacity = self.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> RocList<T> {
|
||||||
/// Increase a RocList's capacity by at least the requested number of elements (possibly more).
|
/// Increase a RocList's capacity by at least the requested number of elements (possibly more).
|
||||||
///
|
///
|
||||||
/// May return a new RocList, if the provided one was not unique.
|
/// May return a new RocList, if the provided one was not unique.
|
||||||
|
@ -232,90 +318,6 @@ where
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_slice(slice: &[T]) -> Self {
|
|
||||||
let mut list = Self::empty();
|
|
||||||
list.extend_from_slice(slice);
|
|
||||||
list
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn extend_from_slice(&mut self, slice: &[T]) {
|
|
||||||
// TODO: Can we do better for ZSTs? Alignment might be a problem.
|
|
||||||
if slice.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_len = self.len() + slice.len();
|
|
||||||
let non_null_elements = if let Some((elements, storage)) = self.elements_and_storage() {
|
|
||||||
// Decrement the list's refence count.
|
|
||||||
let mut copy = storage.get();
|
|
||||||
let is_unique = copy.decrease();
|
|
||||||
|
|
||||||
if is_unique {
|
|
||||||
// If we have enough capacity, we can add to the existing elements in-place.
|
|
||||||
if self.capacity() >= slice.len() {
|
|
||||||
elements
|
|
||||||
} else {
|
|
||||||
// There wasn't enough capacity, so we need a new allocation.
|
|
||||||
// Since this is a unique RocList, we can use realloc here.
|
|
||||||
let new_ptr = unsafe {
|
|
||||||
roc_realloc(
|
|
||||||
storage.as_ptr().cast(),
|
|
||||||
Self::alloc_bytes(new_len),
|
|
||||||
Self::alloc_bytes(self.capacity),
|
|
||||||
Self::alloc_alignment(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
self.capacity = new_len;
|
|
||||||
|
|
||||||
Self::elems_from_allocation(NonNull::new(new_ptr).unwrap_or_else(|| {
|
|
||||||
todo!("Reallocation failed");
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if !copy.is_readonly() {
|
|
||||||
// Write the decremented reference count back.
|
|
||||||
storage.set(copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate new memory.
|
|
||||||
let new_elements = Self::elems_with_capacity(slice.len());
|
|
||||||
|
|
||||||
// Copy the old elements to the new allocation.
|
|
||||||
unsafe {
|
|
||||||
copy_nonoverlapping(elements.as_ptr(), new_elements.as_ptr(), self.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
new_elements
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Self::elems_with_capacity(slice.len())
|
|
||||||
};
|
|
||||||
|
|
||||||
self.elements = Some(non_null_elements);
|
|
||||||
|
|
||||||
let elements = self.elements.unwrap().as_ptr();
|
|
||||||
|
|
||||||
let append_ptr = unsafe { elements.add(self.len()) };
|
|
||||||
|
|
||||||
// Use .cloned() to increment the elements' reference counts, if needed.
|
|
||||||
for (i, new_elem) in slice.iter().cloned().enumerate() {
|
|
||||||
unsafe {
|
|
||||||
// Write the element into the slot, without dropping it.
|
|
||||||
append_ptr
|
|
||||||
.add(i)
|
|
||||||
.write(ptr::read(&ManuallyDrop::new(new_elem)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// It's important that the length is increased one by one, to
|
|
||||||
// make sure that we don't drop uninitialized elements, even when
|
|
||||||
// a incrementing the reference count panics.
|
|
||||||
self.length += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.capacity = self.length
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Replace self with a new version, without letting `drop` run in between.
|
/// Replace self with a new version, without letting `drop` run in between.
|
||||||
fn update_to(&mut self, mut updated: Self) {
|
fn update_to(&mut self, mut updated: Self) {
|
||||||
// We want to replace `self` with `updated` in a way that makes sure
|
// We want to replace `self` with `updated` in a way that makes sure
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue