mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Added ElasticArray
This commit is contained in:
434
lib/std/collections/elastic_array.c3
Normal file
434
lib/std/collections/elastic_array.c3
Normal file
@@ -0,0 +1,434 @@
|
||||
// Copyright (c) 2021-2024 Christoffer Lerno. All rights reserved.
|
||||
// Use of self source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
/**
|
||||
* @require MAX_SIZE >= 1 `The size must be at least 1 element big.`
|
||||
**/
|
||||
module std::collections::elastic_array(<Type, MAX_SIZE>);
|
||||
import std::io, std::math, std::collections::list_common;
|
||||
|
||||
def ElementPredicate = fn bool(Type *type);
|
||||
def ElementTest = fn bool(Type *type, any context);
|
||||
const ELEMENT_IS_EQUATABLE = types::is_equatable_type(Type);
|
||||
const ELEMENT_IS_POINTER = Type.kindof == POINTER;
|
||||
macro type_is_overaligned() => Type.alignof > mem::DEFAULT_MEM_ALIGNMENT;
|
||||
|
||||
struct ElasticArray (Printable)
|
||||
{
|
||||
usz size;
|
||||
Type[MAX_SIZE] entries;
|
||||
}
|
||||
|
||||
fn usz! ElasticArray.to_format(&self, Formatter* formatter) @dynamic
|
||||
{
|
||||
switch (self.size)
|
||||
{
|
||||
case 0:
|
||||
return formatter.print("[]")!;
|
||||
case 1:
|
||||
return formatter.printf("[%s]", self.entries[0])!;
|
||||
default:
|
||||
usz n = formatter.print("[")!;
|
||||
foreach (i, element : self.entries[:self.size])
|
||||
{
|
||||
if (i != 0) formatter.print(", ")!;
|
||||
n += formatter.printf("%s", element)!;
|
||||
}
|
||||
n += formatter.print("]")!;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
fn String ElasticArray.to_string(&self, Allocator allocator) @dynamic
|
||||
{
|
||||
return string::new_format("%s", *self, .allocator = allocator);
|
||||
}
|
||||
|
||||
fn String ElasticArray.to_tstring(&self)
|
||||
{
|
||||
return string::tformat("%s", *self);
|
||||
}
|
||||
|
||||
fn void! ElasticArray.push_try(&self, Type element) @inline
|
||||
{
|
||||
if (self.size == MAX_SIZE) return AllocationFailure.OUT_OF_MEMORY?;
|
||||
self.entries[self.size++] = element;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require self.size < MAX_SIZE `Tried to exceed the max size`
|
||||
**/
|
||||
fn void ElasticArray.push(&self, Type element) @inline
|
||||
{
|
||||
self.entries[self.size++] = element;
|
||||
}
|
||||
|
||||
fn Type! ElasticArray.pop(&self)
|
||||
{
|
||||
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
return self.entries[--self.size];
|
||||
}
|
||||
|
||||
fn void ElasticArray.clear(&self)
|
||||
{
|
||||
self.size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require self.size > 0
|
||||
**/
|
||||
fn Type! ElasticArray.pop_first(&self)
|
||||
{
|
||||
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
defer self.remove_at(0);
|
||||
return self.entries[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @require index < self.size
|
||||
**/
|
||||
fn void ElasticArray.remove_at(&self, usz index)
|
||||
{
|
||||
if (!--self.size || index == self.size) return;
|
||||
self.entries[index .. self.size - 1] = self.entries[index + 1 .. self.size];
|
||||
}
|
||||
|
||||
/**
|
||||
* @require other_list.size + self.size <= MAX_SIZE
|
||||
**/
|
||||
fn void ElasticArray.add_all(&self, ElasticArray* other_list)
|
||||
{
|
||||
if (!other_list.size) return;
|
||||
foreach (&value : other_list)
|
||||
{
|
||||
self.entries[self.size++] = *value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add as many elements as possible to the new array,
|
||||
* returning the number of elements that didn't fit.
|
||||
**/
|
||||
fn usz ElasticArray.add_all_to_limit(&self, ElasticArray* other_list)
|
||||
{
|
||||
if (!other_list.size) return 0;
|
||||
foreach (i, &value : other_list)
|
||||
{
|
||||
if (self.size == MAX_SIZE) return other_list.size - i;
|
||||
self.entries[self.size++] = *value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add as many values from this array as possible, returning the
|
||||
* number of elements that didn't fit.
|
||||
*
|
||||
* @param [in] array
|
||||
**/
|
||||
fn usz ElasticArray.add_array_to_limit(&self, Type[] array)
|
||||
{
|
||||
if (!array.len) return 0;
|
||||
foreach (i, &value : array)
|
||||
{
|
||||
if (self.size == MAX_SIZE) return array.len - i;
|
||||
self.entries[self.size++] = *value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the values of an array to this list.
|
||||
*
|
||||
* @param [in] array
|
||||
* @require array.len + self.size <= MAX_SIZE `Size would exceed max.`
|
||||
* @ensure self.size >= array.len
|
||||
**/
|
||||
fn void ElasticArray.add_array(&self, Type[] array)
|
||||
{
|
||||
if (!array.len) return;
|
||||
foreach (&value : array)
|
||||
{
|
||||
self.entries[self.size++] = *value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* IMPORTANT The returned array must be freed using free_aligned.
|
||||
**/
|
||||
fn Type[] ElasticArray.to_new_aligned_array(&self, Allocator allocator = allocator::heap())
|
||||
{
|
||||
return list_common::list_to_new_aligned_array(Type, self, allocator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require !type_is_overaligned() : "This function is not available on overaligned types"
|
||||
**/
|
||||
macro Type[] ElasticArray.to_new_array(&self, Allocator allocator = allocator::heap())
|
||||
{
|
||||
return list_common::list_to_new_array(Type, self, allocator);
|
||||
}
|
||||
|
||||
fn Type[] ElasticArray.to_tarray(&self)
|
||||
{
|
||||
$if type_is_overaligned():
|
||||
return self.to_new_aligned_array(allocator::temp());
|
||||
$else
|
||||
return self.to_new_array(allocator::temp());
|
||||
$endif;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the elements in a list.
|
||||
**/
|
||||
fn void ElasticArray.reverse(&self)
|
||||
{
|
||||
list_common::list_reverse(self);
|
||||
}
|
||||
|
||||
fn Type[] ElasticArray.array_view(&self)
|
||||
{
|
||||
return self.entries[:self.size];
|
||||
}
|
||||
|
||||
/**
|
||||
* @require self.size < MAX_SIZE `List would exceed max size`
|
||||
**/
|
||||
fn void ElasticArray.push_front(&self, Type type) @inline
|
||||
{
|
||||
self.insert_at(0, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require self.size < MAX_SIZE `List would exceed max size`
|
||||
**/
|
||||
fn void! ElasticArray.push_front_try(&self, Type type) @inline
|
||||
{
|
||||
return self.insert_at_try(0, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require index <= self.size
|
||||
**/
|
||||
fn void! ElasticArray.insert_at_try(&self, usz index, Type value)
|
||||
{
|
||||
if (self.size == MAX_SIZE) return AllocationFailure.OUT_OF_MEMORY?;
|
||||
self.insert_at(index, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require self.size < MAX_SIZE `List would exceed max size`
|
||||
* @require index <= self.size
|
||||
**/
|
||||
fn void ElasticArray.insert_at(&self, usz index, Type type)
|
||||
{
|
||||
for (usz i = self.size; i > index; i--)
|
||||
{
|
||||
self.entries[i] = self.entries[i - 1];
|
||||
}
|
||||
self.size++;
|
||||
self.entries[index] = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require index < self.size
|
||||
**/
|
||||
fn void ElasticArray.set_at(&self, usz index, Type type)
|
||||
{
|
||||
self.entries[index] = type;
|
||||
}
|
||||
|
||||
fn void! ElasticArray.remove_last(&self) @maydiscard
|
||||
{
|
||||
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
self.size--;
|
||||
}
|
||||
|
||||
fn void! ElasticArray.remove_first(&self) @maydiscard
|
||||
{
|
||||
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
self.remove_at(0);
|
||||
}
|
||||
|
||||
fn Type! ElasticArray.first(&self)
|
||||
{
|
||||
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
return self.entries[0];
|
||||
}
|
||||
|
||||
fn Type! ElasticArray.last(&self)
|
||||
{
|
||||
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
return self.entries[self.size - 1];
|
||||
}
|
||||
|
||||
fn bool ElasticArray.is_empty(&self) @inline
|
||||
{
|
||||
return !self.size;
|
||||
}
|
||||
|
||||
fn usz ElasticArray.byte_size(&self) @inline
|
||||
{
|
||||
return Type.sizeof * self.size;
|
||||
}
|
||||
|
||||
fn usz ElasticArray.len(&self) @operator(len) @inline
|
||||
{
|
||||
return self.size;
|
||||
}
|
||||
|
||||
fn Type ElasticArray.get(&self, usz index) @inline
|
||||
{
|
||||
return self.entries[index];
|
||||
}
|
||||
|
||||
fn void ElasticArray.swap(&self, usz i, usz j)
|
||||
{
|
||||
@swap(self.entries[i], self.entries[j]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param filter "The function to determine if it should be removed or not"
|
||||
* @return "the number of deleted elements"
|
||||
**/
|
||||
fn usz ElasticArray.remove_if(&self, ElementPredicate filter)
|
||||
{
|
||||
return list_common::list_remove_if(self, filter, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param selection "The function to determine if it should be kept or not"
|
||||
* @return "the number of deleted elements"
|
||||
**/
|
||||
fn usz ElasticArray.retain_if(&self, ElementPredicate selection)
|
||||
{
|
||||
return list_common::list_remove_if(self, selection, true);
|
||||
}
|
||||
|
||||
fn usz ElasticArray.remove_using_test(&self, ElementTest filter, any context)
|
||||
{
|
||||
return list_common::list_remove_using_test(self, filter, false, context);
|
||||
}
|
||||
|
||||
fn usz ElasticArray.retain_using_test(&self, ElementTest filter, any context)
|
||||
{
|
||||
return list_common::list_remove_using_test(self, filter, true, context);
|
||||
}
|
||||
|
||||
|
||||
macro Type ElasticArray.@item_at(&self, usz index) @operator([])
|
||||
{
|
||||
return self.entries[index];
|
||||
}
|
||||
|
||||
fn Type* ElasticArray.get_ref(&self, usz index) @operator(&[]) @inline
|
||||
{
|
||||
return &self.entries[index];
|
||||
}
|
||||
|
||||
fn void ElasticArray.set(&self, usz index, Type value) @operator([]=)
|
||||
{
|
||||
self.entries[index] = value;
|
||||
}
|
||||
|
||||
|
||||
// Functions for equatable types
|
||||
fn usz! ElasticArray.index_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
foreach (i, v : self)
|
||||
{
|
||||
if (equals(v, type)) return i;
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
}
|
||||
|
||||
fn usz! ElasticArray.rindex_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
foreach_r (i, v : self)
|
||||
{
|
||||
if (equals(v, type)) return i;
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
}
|
||||
|
||||
fn bool ElasticArray.equals(&self, ElasticArray other_list) @if(ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
if (self.size != other_list.size) return false;
|
||||
foreach (i, v : self)
|
||||
{
|
||||
if (!equals(v, other_list.entries[i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for presence of a value in a list.
|
||||
*
|
||||
* @param [&in] self "the list to find elements in"
|
||||
* @param value "The value to search for"
|
||||
* @return "True if the value is found, false otherwise"
|
||||
**/
|
||||
fn bool ElasticArray.contains(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
foreach (i, v : self)
|
||||
{
|
||||
if (equals(v, value)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] self "The list to remove elements from"
|
||||
* @param value "The value to remove"
|
||||
* @return "true if the value was found"
|
||||
**/
|
||||
fn bool ElasticArray.remove_last_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
return @ok(self.remove_at(self.rindex_of(value)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] self "The list to remove elements from"
|
||||
* @param value "The value to remove"
|
||||
* @return "true if the value was found"
|
||||
**/
|
||||
fn bool ElasticArray.remove_first_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
return @ok(self.remove_at(self.index_of(value)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] self "The list to remove elements from"
|
||||
* @param value "The value to remove"
|
||||
* @return "the number of deleted elements."
|
||||
**/
|
||||
fn usz ElasticArray.remove_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
return list_common::list_remove_item(self, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn void ElasticArray.remove_all_from(&self, ElasticArray* other_list) @if(ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
if (!other_list.size) return;
|
||||
foreach (v : other_list) self.remove_item(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&in] self
|
||||
* @return "The number non-null values in the list"
|
||||
**/
|
||||
fn usz ElasticArray.compact_count(&self) @if(ELEMENT_IS_POINTER)
|
||||
{
|
||||
usz vals = 0;
|
||||
foreach (v : self) if (v) vals++;
|
||||
return vals;
|
||||
}
|
||||
|
||||
fn usz ElasticArray.compact(&self) @if(ELEMENT_IS_POINTER)
|
||||
{
|
||||
return list_common::list_compact(self);
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of self source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module std::collections::list(<Type>);
|
||||
import std::io,std::math;
|
||||
import std::io, std::math, std::collections::list_common;
|
||||
|
||||
def ElementPredicate = fn bool(Type *type);
|
||||
def ElementTest = fn bool(Type *type, any context);
|
||||
@@ -173,10 +173,7 @@ fn void List.add_all(&self, List* other_list)
|
||||
**/
|
||||
fn Type[] List.to_new_aligned_array(&self, Allocator allocator = allocator::heap())
|
||||
{
|
||||
if (!self.size) return Type[] {};
|
||||
Type[] result = allocator::alloc_array_aligned(allocator, Type, self.size);
|
||||
result[..] = self.entries[:self.size];
|
||||
return result;
|
||||
return list_common::list_to_new_aligned_array(Type, self, allocator);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,10 +181,7 @@ fn Type[] List.to_new_aligned_array(&self, Allocator allocator = allocator::heap
|
||||
**/
|
||||
macro Type[] List.to_new_array(&self, Allocator allocator = allocator::heap())
|
||||
{
|
||||
if (!self.size) return Type[] {};
|
||||
Type[] result = allocator::alloc_array(allocator, Type, self.size);
|
||||
result[..] = self.entries[:self.size];
|
||||
return result;
|
||||
return list_common::list_to_new_array(Type, self, allocator);
|
||||
}
|
||||
|
||||
fn Type[] List.to_tarray(&self)
|
||||
@@ -204,13 +198,7 @@ fn Type[] List.to_tarray(&self)
|
||||
**/
|
||||
fn void List.reverse(&self)
|
||||
{
|
||||
if (self.size < 2) return;
|
||||
usz half = self.size / 2U;
|
||||
usz end = self.size - 1;
|
||||
for (usz i = 0; i < half; i++)
|
||||
{
|
||||
@swap(self.entries[i], self.entries[end - i]);
|
||||
}
|
||||
list_common::list_reverse(self);
|
||||
}
|
||||
|
||||
fn Type[] List.array_view(&self)
|
||||
@@ -228,10 +216,8 @@ fn void List.add_array(&self, Type[] array)
|
||||
{
|
||||
if (!array.len) return;
|
||||
self.reserve(array.len);
|
||||
foreach (&value : array)
|
||||
{
|
||||
self.entries[self.size++] = *value;
|
||||
}
|
||||
self.entries[self.size : array.len] = array[..];
|
||||
self.size += array.len;
|
||||
}
|
||||
|
||||
fn void List.push_front(&self, Type type) @inline
|
||||
@@ -329,7 +315,7 @@ fn void List.swap(&self, usz i, usz j)
|
||||
**/
|
||||
fn usz List.remove_if(&self, ElementPredicate filter)
|
||||
{
|
||||
return self._remove_if(filter, false);
|
||||
return list_common::list_remove_if(self, filter, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -338,67 +324,17 @@ fn usz List.remove_if(&self, ElementPredicate filter)
|
||||
**/
|
||||
fn usz List.retain_if(&self, ElementPredicate selection)
|
||||
{
|
||||
return self._remove_if(selection, true);
|
||||
}
|
||||
|
||||
macro usz List._remove_if(&self, ElementPredicate filter, bool $invert) @local
|
||||
{
|
||||
usz size = self.size;
|
||||
for (usz i = size, usz k = size; k > 0; k = i)
|
||||
{
|
||||
// Find last index of item to be deleted.
|
||||
$if $invert:
|
||||
while (i > 0 && !filter(&self.entries[i - 1])) i--;
|
||||
$else
|
||||
while (i > 0 && filter(&self.entries[i - 1])) i--;
|
||||
$endif
|
||||
// Remove the items from this index up to the one not to be deleted.
|
||||
usz n = self.size - k;
|
||||
self.entries[i:n] = self.entries[k:n];
|
||||
self.size -= k - i;
|
||||
// Find last index of item not to be deleted.
|
||||
$if $invert:
|
||||
while (i > 0 && filter(&self.entries[i - 1])) i--;
|
||||
$else
|
||||
while (i > 0 && !filter(&self.entries[i - 1])) i--;
|
||||
$endif
|
||||
}
|
||||
return size - self.size;
|
||||
return list_common::list_remove_if(self, selection, true);
|
||||
}
|
||||
|
||||
fn usz List.remove_using_test(&self, ElementTest filter, any context)
|
||||
{
|
||||
return self._remove_using_test(filter, false, context);
|
||||
return list_common::list_remove_using_test(self, filter, false, context);
|
||||
}
|
||||
|
||||
fn usz List.retain_using_test(&self, ElementTest filter, any context)
|
||||
{
|
||||
return self._remove_using_test(filter, true, context);
|
||||
}
|
||||
|
||||
macro usz List._remove_using_test(&self, ElementTest filter, bool $invert, ctx) @local
|
||||
{
|
||||
usz size = self.size;
|
||||
for (usz i = size, usz k = size; k > 0; k = i)
|
||||
{
|
||||
// Find last index of item to be deleted.
|
||||
$if $invert:
|
||||
while (i > 0 && !filter(&self.entries[i - 1], ctx)) i--;
|
||||
$else
|
||||
while (i > 0 && filter(&self.entries[i - 1], ctx)) i--;
|
||||
$endif
|
||||
// Remove the items from this index up to the one not to be deleted.
|
||||
usz n = self.size - k;
|
||||
self.entries[i:n] = self.entries[k:n];
|
||||
self.size -= k - i;
|
||||
// Find last index of item not to be deleted.
|
||||
$if $invert:
|
||||
while (i > 0 && filter(&self.entries[i - 1], ctx)) i--;
|
||||
$else
|
||||
while (i > 0 && !filter(&self.entries[i - 1], ctx)) i--;
|
||||
$endif
|
||||
}
|
||||
return size - self.size;
|
||||
return list_common::list_remove_using_test(self, filter, true, context);
|
||||
}
|
||||
|
||||
fn void List.ensure_capacity(&self, usz min_capacity) @local
|
||||
@@ -515,17 +451,7 @@ fn bool List.remove_first_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
|
||||
**/
|
||||
fn usz List.remove_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
usz size = self.size;
|
||||
for (usz i = size; i > 0; i--)
|
||||
{
|
||||
if (!equals(self.entries[i - 1], value)) continue;
|
||||
for (usz j = i; j < self.size; j++)
|
||||
{
|
||||
self.entries[j - 1] = self.entries[j];
|
||||
}
|
||||
self.size--;
|
||||
}
|
||||
return size - self.size;
|
||||
return list_common::list_remove_item(self, value);
|
||||
}
|
||||
|
||||
|
||||
@@ -549,17 +475,7 @@ fn usz List.compact_count(&self) @if(ELEMENT_IS_POINTER)
|
||||
|
||||
fn usz List.compact(&self) @if(ELEMENT_IS_POINTER)
|
||||
{
|
||||
usz size = self.size;
|
||||
for (usz i = size; i > 0; i--)
|
||||
{
|
||||
if (self.entries[i - 1]) continue;
|
||||
for (usz j = i; j < size; j++)
|
||||
{
|
||||
self.entries[j - 1] = self.entries[j];
|
||||
}
|
||||
self.size--;
|
||||
}
|
||||
return size - self.size;
|
||||
return list_common::list_compact(self);
|
||||
}
|
||||
|
||||
// --> Deprecated
|
||||
|
||||
112
lib/std/collections/list_common.c3
Normal file
112
lib/std/collections/list_common.c3
Normal file
@@ -0,0 +1,112 @@
|
||||
module std::collections::list_common;
|
||||
|
||||
/**
|
||||
* IMPORTANT The returned array must be freed using free_aligned.
|
||||
**/
|
||||
macro list_to_new_aligned_array($Type, self, Allocator allocator)
|
||||
{
|
||||
if (!self.size) return $Type[] {};
|
||||
$Type[] result = allocator::alloc_array_aligned(allocator, $Type, self.size);
|
||||
result[..] = self.entries[:self.size];
|
||||
return result;
|
||||
}
|
||||
|
||||
macro list_to_new_array($Type, self, Allocator allocator)
|
||||
{
|
||||
if (!self.size) return $Type[] {};
|
||||
$Type[] result = allocator::alloc_array(allocator, $Type, self.size);
|
||||
result[..] = self.entries[:self.size];
|
||||
return result;
|
||||
}
|
||||
|
||||
macro void list_reverse(self)
|
||||
{
|
||||
if (self.size < 2) return;
|
||||
usz half = self.size / 2U;
|
||||
usz end = self.size - 1;
|
||||
for (usz i = 0; i < half; i++)
|
||||
{
|
||||
@swap(self.entries[i], self.entries[end - i]);
|
||||
}
|
||||
}
|
||||
|
||||
macro usz list_remove_using_test(self, filter, bool $invert, ctx)
|
||||
{
|
||||
usz size = self.size;
|
||||
for (usz i = size, usz k = size; k > 0; k = i)
|
||||
{
|
||||
// Find last index of item to be deleted.
|
||||
$if $invert:
|
||||
while (i > 0 && !filter(&self.entries[i - 1], ctx)) i--;
|
||||
$else
|
||||
while (i > 0 && filter(&self.entries[i - 1], ctx)) i--;
|
||||
$endif
|
||||
// Remove the items from this index up to the one not to be deleted.
|
||||
usz n = self.size - k;
|
||||
self.entries[i:n] = self.entries[k:n];
|
||||
self.size -= k - i;
|
||||
// Find last index of item not to be deleted.
|
||||
$if $invert:
|
||||
while (i > 0 && filter(&self.entries[i - 1], ctx)) i--;
|
||||
$else
|
||||
while (i > 0 && !filter(&self.entries[i - 1], ctx)) i--;
|
||||
$endif
|
||||
}
|
||||
return size - self.size;
|
||||
}
|
||||
|
||||
macro usz list_compact(self)
|
||||
{
|
||||
usz size = self.size;
|
||||
for (usz i = size; i > 0; i--)
|
||||
{
|
||||
if (self.entries[i - 1]) continue;
|
||||
for (usz j = i; j < size; j++)
|
||||
{
|
||||
self.entries[j - 1] = self.entries[j];
|
||||
}
|
||||
self.size--;
|
||||
}
|
||||
return size - self.size;
|
||||
}
|
||||
|
||||
macro usz list_remove_item(self, value)
|
||||
{
|
||||
usz size = self.size;
|
||||
for (usz i = size; i > 0; i--)
|
||||
{
|
||||
if (!equals(self.entries[i - 1], value)) continue;
|
||||
for (usz j = i; j < self.size; j++)
|
||||
{
|
||||
self.entries[j - 1] = self.entries[j];
|
||||
}
|
||||
self.size--;
|
||||
}
|
||||
return size - self.size;
|
||||
}
|
||||
|
||||
|
||||
macro usz list_remove_if(self, filter, bool $invert)
|
||||
{
|
||||
usz size = self.size;
|
||||
for (usz i = size, usz k = size; k > 0; k = i)
|
||||
{
|
||||
// Find last index of item to be deleted.
|
||||
$if $invert:
|
||||
while (i > 0 && !filter(&self.entries[i - 1])) i--;
|
||||
$else
|
||||
while (i > 0 && filter(&self.entries[i - 1])) i--;
|
||||
$endif
|
||||
// Remove the items from this index up to the one not to be deleted.
|
||||
usz n = self.size - k;
|
||||
self.entries[i:n] = self.entries[k:n];
|
||||
self.size -= k - i;
|
||||
// Find last index of item not to be deleted.
|
||||
$if $invert:
|
||||
while (i > 0 && filter(&self.entries[i - 1])) i--;
|
||||
$else
|
||||
while (i > 0 && !filter(&self.entries[i - 1])) i--;
|
||||
$endif
|
||||
}
|
||||
return size - self.size;
|
||||
}
|
||||
Reference in New Issue
Block a user