Fix #809 missing checks on generic types, accepting both types where constants should be and vice versa.

This commit is contained in:
Christoffer Lerno
2023-07-01 23:58:00 +02:00
parent 45820d45e5
commit 21d8a8b6da
9 changed files with 329 additions and 307 deletions

View File

@@ -5,19 +5,19 @@ struct EnumMap
ValueType[Enum.len] values;
}
fn void EnumMap.init(EnumMap* this, ValueType init_value)
fn void EnumMap.init(&self, ValueType init_value)
{
foreach(&a : this.values)
foreach(&a : self.values)
{
*a = init_value;
}
}
fn void! EnumMap.to_format(EnumMap* map, Formatter* formatter) @dynamic
fn void! EnumMap.to_format(&self, Formatter* formatter) @dynamic
{
formatter.print("{ ")!;
foreach (i, &value : map.values)
foreach (i, &value : self.values)
{
if (i != 0) formatter.print(", ")!;
formatter.printf("%s: %s", (Enum)i, *value)!;
@@ -25,11 +25,11 @@ fn void! EnumMap.to_format(EnumMap* map, Formatter* formatter) @dynamic
formatter.print(" }")!;
}
fn String EnumMap.to_string(EnumMap* map, Allocator* using = mem::heap()) @dynamic
fn String EnumMap.to_string(&self, Allocator* using = mem::heap()) @dynamic
{
return string::printf("%s", *map);
return string::printf("%s", *self);
}
fn uint EnumMap.len(EnumMap* this) @operator(len) => this.values.len;
fn ValueType EnumMap.get(EnumMap* this, Enum key) @operator([]) => this.values[key.ordinal];
fn void EnumMap.set(EnumMap* this, Enum key, ValueType value) @operator([]=) => this.values[key.ordinal] = value;
fn uint EnumMap.len(&self) @operator(len) => self.values.len;
fn ValueType EnumMap.get(&self, Enum key) @operator([]) => self.values[key.ordinal];
fn void EnumMap.set(&self, Enum key, ValueType value) @operator([]=) => self.values[key.ordinal] = value;

View File

@@ -1,5 +1,5 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// Use of self source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
/**
@@ -12,120 +12,120 @@ def EnumSetType = $typefrom(private::type_for_enum_elements(Enum.elements)) @pri
const IS_CHAR_ARRAY = Enum.elements > 128;
def EnumSet = distinct EnumSetType;
fn void EnumSet.add(EnumSet* this, Enum v)
fn void EnumSet.add(&self, Enum v)
{
$if IS_CHAR_ARRAY:
(*this)[(usz)v / 8] |= (char)(1u << ((usz)v % 8));
(*self)[(usz)v / 8] |= (char)(1u << ((usz)v % 8));
$else
*this = (EnumSet)((EnumSetType)*this | 1u << (EnumSetType)v);
*self = (EnumSet)((EnumSetType)*self | 1u << (EnumSetType)v);
$endif
}
fn void EnumSet.clear(EnumSet* this)
fn void EnumSet.clear(&self)
{
$if IS_CHAR_ARRAY:
*this = {};
*self = {};
$else
*this = 0;
*self = 0;
$endif
}
fn bool EnumSet.remove(EnumSet* this, Enum v)
fn bool EnumSet.remove(&self, Enum v)
{
$if IS_CHAR_ARRAY:
if (!this.has(v) @inline) return false;
(*this)[(usz)v / 8] &= (char)~(1u << ((usz)v % 8));
if (!self.has(v) @inline) return false;
(*self)[(usz)v / 8] &= (char)~(1u << ((usz)v % 8));
return true;
$else
EnumSetType old = (EnumSetType)*this;
EnumSetType old = (EnumSetType)*self;
EnumSetType new = old & ~(1u << (EnumSetType)v);
*this = (EnumSet)new;
*self = (EnumSet)new;
return old != new;
$endif
}
fn bool EnumSet.has(EnumSet* this, Enum v)
fn bool EnumSet.has(&self, Enum v)
{
$if IS_CHAR_ARRAY:
return (bool)(((*this)[(usz)v / 8] << ((usz)v % 8)) & 0x01);
return (bool)(((*self)[(usz)v / 8] << ((usz)v % 8)) & 0x01);
$else
return ((EnumSetType)*this & (1u << (EnumSetType)v)) != 0;
return ((EnumSetType)*self & (1u << (EnumSetType)v)) != 0;
$endif
}
fn void EnumSet.add_all(EnumSet* this, EnumSet s)
fn void EnumSet.add_all(&self, EnumSet s)
{
$if IS_CHAR_ARRAY:
foreach (i, c : s) (*this)[i] |= c;
foreach (i, c : s) (*self)[i] |= c;
$else
*this = (EnumSet)((EnumSetType)*this | (EnumSetType)s);
*self = (EnumSet)((EnumSetType)*self | (EnumSetType)s);
$endif
}
fn void EnumSet.retain_all(EnumSet* this, EnumSet s)
fn void EnumSet.retain_all(&self, EnumSet s)
{
$if IS_CHAR_ARRAY:
foreach (i, c : s) (*this)[i] &= c;
foreach (i, c : s) (*self)[i] &= c;
$else
*this = (EnumSet)((EnumSetType)*this & (EnumSetType)s);
*self = (EnumSet)((EnumSetType)*self & (EnumSetType)s);
$endif
}
fn void EnumSet.remove_all(EnumSet* this, EnumSet s)
fn void EnumSet.remove_all(&self, EnumSet s)
{
$if IS_CHAR_ARRAY:
foreach (i, c : s) (*this)[i] &= ~c;
foreach (i, c : s) (*self)[i] &= ~c;
$else
*this = (EnumSet)((EnumSetType)*this & ~(EnumSetType)s);
*self = (EnumSet)((EnumSetType)*self & ~(EnumSetType)s);
$endif
}
fn EnumSet EnumSet.and_of(EnumSet* this, EnumSet s)
fn EnumSet EnumSet.and_of(&self, EnumSet s)
{
$if IS_CHAR_ARRAY:
EnumSet copy = *this;
EnumSet copy = *self;
copy.retain_all(s);
return copy;
$else
return (EnumSet)((EnumSetType)*this & (EnumSetType)s);
return (EnumSet)((EnumSetType)*self & (EnumSetType)s);
$endif
}
fn EnumSet EnumSet.or_of(EnumSet* this, EnumSet s)
fn EnumSet EnumSet.or_of(&self, EnumSet s)
{
$if IS_CHAR_ARRAY:
EnumSet copy = *this;
EnumSet copy = *self;
copy.add_all(s);
return copy;
$else
return (EnumSet)((EnumSetType)*this | (EnumSetType)s);
return (EnumSet)((EnumSetType)*self | (EnumSetType)s);
$endif
}
fn EnumSet EnumSet.diff_of(EnumSet* this, EnumSet s)
fn EnumSet EnumSet.diff_of(&self, EnumSet s)
{
$if IS_CHAR_ARRAY:
EnumSet copy = *this;
EnumSet copy = *self;
copy.remove_all(s);
return copy;
$else
return (EnumSet)((EnumSetType)*this & ~(EnumSetType)s);
return (EnumSet)((EnumSetType)*self & ~(EnumSetType)s);
$endif
}
fn EnumSet EnumSet.xor_of(EnumSet* this, EnumSet s)
fn EnumSet EnumSet.xor_of(&self, EnumSet s)
{
$if IS_CHAR_ARRAY:
EnumSet copy = *this;
EnumSet copy = *self;
foreach (i, c : s) copy[i] ^= c;
return copy;
$else
return (EnumSet)((EnumSetType)*this ^ (EnumSetType)s);
return (EnumSet)((EnumSetType)*self ^ (EnumSetType)s);
$endif
}
fn void! EnumSet.to_format(EnumSet* set, Formatter* formatter) @dynamic
fn void! EnumSet.to_format(&set, Formatter* formatter) @dynamic
{
formatter.print("[")!;
bool found = false;
@@ -139,7 +139,7 @@ fn void! EnumSet.to_format(EnumSet* set, Formatter* formatter) @dynamic
formatter.print("]")!;
}
fn String EnumSet.to_string(EnumSet* set, Allocator* using = mem::heap()) @dynamic
fn String EnumSet.to_string(&set, Allocator* using = mem::heap()) @dynamic
{
return string::printf("%s", *set);
}

View File

@@ -1,5 +1,5 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// 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::linkedlist<Type>;
@@ -18,161 +18,161 @@ struct LinkedList
Node *_last;
}
fn void LinkedList.push(LinkedList* list, Type value)
fn void LinkedList.push(&self, Type value)
{
list.link_first(value);
self.link_first(value);
}
fn void LinkedList.push_last(LinkedList* list, Type value)
fn void LinkedList.push_last(&self, Type value)
{
list.link_last(value);
self.link_last(value);
}
fn void LinkedList.init(LinkedList* list, Allocator* using = mem::heap())
fn void LinkedList.init(&self, Allocator* using = mem::heap())
{
*list = { .allocator = using };
*self = { .allocator = using };
}
fn void LinkedList.tinit(LinkedList* list) => list.init(mem::temp()) @inline;
fn void LinkedList.tinit(&self) => self.init(mem::temp()) @inline;
/**
* @require list.allocator
* @require self.allocator
**/
macro void LinkedList.@free_node(LinkedList &list, Node* node) @private
macro void LinkedList.free_node(&self, Node* node) @private
{
list.allocator.free(node)!!;
self.allocator.free(node)!!;
}
macro Node* LinkedList.@alloc_node(LinkedList &list) @private
macro Node* LinkedList.alloc_node(&self) @private
{
if (!list.allocator) list.allocator = mem::heap();
return malloc(Node, .using = list.allocator);
if (!self.allocator) self.allocator = mem::heap();
return malloc(Node, .using = self.allocator);
}
fn void LinkedList.link_first(LinkedList* list, Type value) @private
fn void LinkedList.link_first(&self, Type value) @private
{
Node *first = list._first;
Node *new_node = list.@alloc_node();
Node *first = self._first;
Node *new_node = self.alloc_node();
*new_node = { .next = first, .value = value };
list._first = new_node;
self._first = new_node;
if (!first)
{
list._last = new_node;
self._last = new_node;
}
else
{
first.prev = new_node;
}
list.size++;
self.size++;
}
fn void LinkedList.link_last(LinkedList* list, Type value) @private
fn void LinkedList.link_last(&self, Type value) @private
{
Node *last = list._last;
Node *new_node = list.@alloc_node();
Node *last = self._last;
Node *new_node = self.alloc_node();
*new_node = { .prev = last, .value = value };
list._last = new_node;
self._last = new_node;
if (!last)
{
list._first = new_node;
self._first = new_node;
}
else
{
last.next = new_node;
}
list.size++;
self.size++;
}
fn Type! LinkedList.peek(LinkedList* list) => list.first() @inline;
fn Type! LinkedList.peek_last(LinkedList* list) => list.last() @inline;
fn Type! LinkedList.peek(&self) => self.first() @inline;
fn Type! LinkedList.peek_last(&self) => self.last() @inline;
fn Type! LinkedList.first(LinkedList *list)
fn Type! LinkedList.first(&self)
{
if (!list._first) return IteratorResult.NO_MORE_ELEMENT?;
return list._first.value;
if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
return self._first.value;
}
fn Type! LinkedList.last(LinkedList* list)
fn Type! LinkedList.last(&self)
{
if (!list._last) return IteratorResult.NO_MORE_ELEMENT?;
return list._last.value;
if (!self._last) return IteratorResult.NO_MORE_ELEMENT?;
return self._last.value;
}
fn void LinkedList.free(LinkedList* list) => list.clear() @inline;
fn void LinkedList.free(&self) => self.clear() @inline;
fn void LinkedList.clear(LinkedList* list)
fn void LinkedList.clear(&self)
{
for (Node* node = list._first; node != null;)
for (Node* node = self._first; node != null;)
{
Node* next = node.next;
list.@free_node(node);
self.free_node(node);
node = next;
}
list._first = null;
list._last = null;
list.size = 0;
self._first = null;
self._last = null;
self.size = 0;
}
fn usz LinkedList.len(LinkedList* list) @inline => list.size;
fn usz LinkedList.len(&self) @inline => self.size;
/**
* @require index < list.size
* @require index < self.size
**/
macro Node* LinkedList.node_at_index(LinkedList* list, usz index)
macro Node* LinkedList.node_at_index(&self, usz index)
{
if (index * 2 >= list.size)
if (index * 2 >= self.size)
{
Node* node = list._last;
index = list.size - index - 1;
Node* node = self._last;
index = self.size - index - 1;
while (index--) node = node.prev;
return node;
}
Node* node = list._first;
Node* node = self._first;
while (index--) node = node.next;
return node;
}
/**
* @require index < list.size
* @require index < self.size
**/
fn Type LinkedList.get(LinkedList* list, usz index)
fn Type LinkedList.get(&self, usz index)
{
return list.node_at_index(index).value;
return self.node_at_index(index).value;
}
/**
* @require index < list.size
* @require index < self.size
**/
fn void LinkedList.set(LinkedList* list, usz index, Type element)
fn void LinkedList.set(&self, usz index, Type element)
{
list.node_at_index(index).value = element;
self.node_at_index(index).value = element;
}
/**
* @require index < list.size
* @require index < self.size
**/
fn void LinkedList.remove(LinkedList* list, usz index)
fn void LinkedList.remove(&self, usz index)
{
list.unlink(list.node_at_index(index));
self.unlink(self.node_at_index(index));
}
/**
* @require index <= list.size
* @require index <= self.size
**/
fn void LinkedList.insert(LinkedList* list, usz index, Type element)
fn void LinkedList.insert(&self, usz index, Type element)
{
switch (index)
{
case 0:
list.push(element);
case list.size:
list.push_last(element);
self.push(element);
case self.size:
self.push_last(element);
default:
list.link_before(list.node_at_index(index), element);
self.link_before(self.node_at_index(index), element);
}
}
/**
* @require succ != null
**/
fn void LinkedList.link_before(LinkedList *list, Node *succ, Type value) @private
fn void LinkedList.link_before(&self, Node *succ, Type value) @private
{
Node* pred = succ.prev;
Node* new_node = malloc(Node);
@@ -180,120 +180,110 @@ fn void LinkedList.link_before(LinkedList *list, Node *succ, Type value) @privat
succ.prev = new_node;
if (!pred)
{
list._first = new_node;
self._first = new_node;
}
else
{
pred.next = new_node;
}
list.size++;
self.size++;
}
/**
* @require list && list._first
* @require self._first
**/
fn void LinkedList.unlink_first(LinkedList* list) @private
fn void LinkedList.unlink_first(&self) @private
{
Node* f = list._first;
Node* f = self._first;
Node* next = f.next;
list.@free_node(f);
list._first = next;
self.free_node(f);
self._first = next;
if (!next)
{
list._last = null;
self._last = null;
}
else
{
next.prev = null;
}
list.size--;
self.size--;
}
fn bool LinkedList.remove_value(LinkedList* list, Type t)
fn bool LinkedList.remove_value(&self, Type t)
{
for (Node* node = list._first; node != null; node = node.next)
for (Node* node = self._first; node != null; node = node.next)
{
if (node.value == t)
{
list.unlink(node);
self.unlink(node);
return true;
}
}
return false;
}
fn bool LinkedList.remove_last_value(LinkedList* list, Type t)
fn bool LinkedList.remove_last_value(&self, Type t)
{
for (Node* node = list._last; node != null; node = node.prev)
for (Node* node = self._last; node != null; node = node.prev)
{
if (node.value == t)
{
list.unlink(node);
self.unlink(node);
return true;
}
}
return false;
}
/**
* @param [&inout] list
**/
fn Type! LinkedList.pop(LinkedList* list)
fn Type! LinkedList.pop(&self)
{
if (!list._first) return IteratorResult.NO_MORE_ELEMENT?;
defer list.unlink_first();
return list._first.value;
if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
defer self.unlink_first();
return self._first.value;
}
fn void! LinkedList.remove_last(&self)
{
if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
self.unlink_last();
}
fn void! LinkedList.remove_first(&self)
{
if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
self.unlink_first();
}
/**
* @param [&inout] list
* @require self._last
**/
fn void! LinkedList.remove_last(LinkedList* list)
fn void LinkedList.unlink_last(&self) @inline @private
{
if (!list._first) return IteratorResult.NO_MORE_ELEMENT?;
list.unlink_last();
}
/**
* @param [&inout] list
**/
fn void! LinkedList.remove_first(LinkedList* list)
{
if (!list._first) return IteratorResult.NO_MORE_ELEMENT?;
list.unlink_first();
}
/**
* @param [&inout] list
* @require list._last
**/
fn void LinkedList.unlink_last(LinkedList *list) @inline @private
{
Node* l = list._last;
Node* l = self._last;
Node* prev = l.prev;
list._last = prev;
list.@free_node(l);
self._last = prev;
self.free_node(l);
if (!prev)
{
list._first = null;
self._first = null;
}
else
{
prev.next = null;
}
list.size--;
self.size--;
}
/**
* @require list != null, x != null
* @require x != null
**/
fn void LinkedList.unlink(LinkedList* list, Node* x) @private
fn void LinkedList.unlink(&self, Node* x) @private
{
Node* next = x.next;
Node* prev = x.prev;
if (!prev)
{
list._first = next;
self._first = next;
}
else
{
@@ -301,12 +291,12 @@ fn void LinkedList.unlink(LinkedList* list, Node* x) @private
}
if (!next)
{
list._last = prev;
self._last = prev;
}
else
{
next.prev = prev;
}
list.@free_node(x);
list.size--;
self.free_node(x);
self.size--;
}

View File

@@ -1,5 +1,5 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// 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::math;
@@ -19,38 +19,38 @@ struct List
/**
* @require using != null "A valid allocator must be provided"
**/
fn void List.init(List* list, usz initial_capacity = 16, Allocator* using = mem::heap())
fn void List.init(&self, usz initial_capacity = 16, Allocator* using = mem::heap())
{
list.allocator = using;
list.size = 0;
self.allocator = using;
self.size = 0;
if (initial_capacity > 0)
{
initial_capacity = math::next_power_of_2(initial_capacity);
list.entries = malloc_aligned(Type, initial_capacity, .alignment = Type[1].alignof, .using = using)!!;
self.entries = malloc_aligned(Type, initial_capacity, .alignment = Type[1].alignof, .using = using)!!;
}
else
{
list.entries = null;
self.entries = null;
}
list.capacity = initial_capacity;
self.capacity = initial_capacity;
}
fn void List.tinit(List* list, usz initial_capacity = 16)
fn void List.tinit(&self, usz initial_capacity = 16)
{
list.init(initial_capacity, mem::temp()) @inline;
self.init(initial_capacity, mem::temp()) @inline;
}
fn void! List.to_format(List* list, Formatter* formatter) @dynamic
fn void! List.to_format(&self, Formatter* formatter) @dynamic
{
switch (list.size)
switch (self.size)
{
case 0:
formatter.print("[]")!;
case 1:
formatter.printf("[%s]", list.entries[0])!;
formatter.printf("[%s]", self.entries[0])!;
default:
formatter.print("[")!;
foreach (i, element : list.entries[:list.size])
foreach (i, element : self.entries[:self.size])
{
if (i != 0) formatter.print(", ")!;
formatter.printf("%s", element)!;
@@ -59,277 +59,273 @@ fn void! List.to_format(List* list, Formatter* formatter) @dynamic
}
}
fn String List.to_string(List* list, Allocator* using = mem::heap()) @dynamic
fn String List.to_string(&self, Allocator* using = mem::heap()) @dynamic
{
return string::printf("%s", *list);
return string::printf("%s", *self);
}
fn void List.push(List* list, Type element) @inline
fn void List.push(&self, Type element) @inline
{
list.append(element);
self.append(element);
}
fn void List.append(List* list, Type element)
fn void List.append(&self, Type element)
{
list.ensure_capacity();
list.entries[list.size++] = element;
self.ensure_capacity();
self.entries[self.size++] = element;
}
/**
* @require list.size > 0
* @require self.size > 0
*/
fn Type List.pop(List* list)
fn Type List.pop(&self)
{
return list.entries[--list.size];
return self.entries[--self.size];
}
fn void List.clear(List* list)
fn void List.clear(&self)
{
list.size = 0;
self.size = 0;
}
/**
* @require list.size > 0
* @require self.size > 0
*/
fn Type List.pop_first(List* list)
fn Type List.pop_first(&self)
{
Type value = list.entries[0];
list.remove_at(0);
Type value = self.entries[0];
self.remove_at(0);
return value;
}
fn void List.remove_at(List* list, usz index)
fn void List.remove_at(&self, usz index)
{
for (usz i = index + 1; i < list.size; i++)
for (usz i = index + 1; i < self.size; i++)
{
list.entries[i - 1] = list.entries[i];
self.entries[i - 1] = self.entries[i];
}
list.size--;
self.size--;
}
fn void List.add_all(List* list, List* other_list)
fn void List.add_all(&self, List* other_list)
{
if (!other_list.size) return;
list.reserve(other_list.size);
self.reserve(other_list.size);
foreach (&value : other_list)
{
list.entries[list.size++] = *value;
self.entries[self.size++] = *value;
}
}
fn Type[] List.to_array(List* list, Allocator* using = mem::heap())
fn Type[] List.to_array(&self, Allocator* using = mem::heap())
{
if (!list.size) return Type[] {};
Type[] result = malloc(Type, list.size, .using = using);
result[..] = list.entries[:list.size];
if (!self.size) return Type[] {};
Type[] result = malloc(Type, self.size, .using = using);
result[..] = self.entries[:self.size];
return result;
}
/**
* Reverse the elements in a list.
*
* @param [&inout] list "The list to reverse"
**/
fn void List.reverse(List* list)
fn void List.reverse(&self)
{
if (list.size < 2) return;
usz half = list.size / 2U;
usz end = list.size - 1;
if (self.size < 2) return;
usz half = self.size / 2U;
usz end = self.size - 1;
for (usz i = 0; i < half; i++)
{
@swap(list.entries[i], list.entries[end - i]);
@swap(self.entries[i], self.entries[end - i]);
}
}
fn Type[] List.array_view(List* list)
fn Type[] List.array_view(&self)
{
return list.entries[:list.size];
return self.entries[:self.size];
}
fn void List.add_array(List* list, Type[] array)
fn void List.add_array(&self, Type[] array)
{
if (!array.len) return;
list.reserve(array.len);
self.reserve(array.len);
foreach (&value : array)
{
list.entries[list.size++] = *value;
self.entries[self.size++] = *value;
}
}
fn void List.push_front(List* list, Type type) @inline
fn void List.push_front(&self, Type type) @inline
{
list.insert_at(0, type);
self.insert_at(0, type);
}
fn void List.insert_at(List* list, usz index, Type type)
fn void List.insert_at(&self, usz index, Type type)
{
list.ensure_capacity();
for (usz i = list.size; i > index; i--)
self.ensure_capacity();
for (usz i = self.size; i > index; i--)
{
list.entries[i] = list.entries[i - 1];
self.entries[i] = self.entries[i - 1];
}
list.size++;
list.entries[index] = type;
self.size++;
self.entries[index] = type;
}
/**
* @require index < list.size
* @require index < self.size
**/
fn void List.set_at(List* list, usz index, Type type)
fn void List.set_at(&self, usz index, Type type)
{
list.entries[index] = type;
self.entries[index] = type;
}
fn void List.remove_last(List* list)
fn void List.remove_last(&self)
{
list.size--;
self.size--;
}
fn void List.remove_first(List* list)
fn void List.remove_first(&self)
{
list.remove_at(0);
self.remove_at(0);
}
fn Type* List.first(List* list)
fn Type* List.first(&self)
{
return list.size ? &list.entries[0] : null;
return self.size ? &self.entries[0] : null;
}
fn Type* List.last(List* list)
fn Type* List.last(&self)
{
return list.size ? &list.entries[list.size - 1] : null;
return self.size ? &self.entries[self.size - 1] : null;
}
fn bool List.is_empty(List* list)
fn bool List.is_empty(&self)
{
return !list.size;
return !self.size;
}
fn usz List.len(List* list) @operator(len)
fn usz List.len(&self) @operator(len)
{
return list.size;
return self.size;
}
fn Type List.get(List* list, usz index)
fn Type List.get(&self, usz index)
{
return list.entries[index];
return self.entries[index];
}
fn void List.free(List* list)
fn void List.free(&self)
{
if (!list.allocator) return;
free_aligned(list.entries, .using = list.allocator);
list.capacity = 0;
list.size = 0;
list.entries = null;
if (!self.allocator) return;
free_aligned(self.entries, .using = self.allocator);
self.capacity = 0;
self.size = 0;
self.entries = null;
}
fn void List.swap(List* list, usz i, usz j)
fn void List.swap(&self, usz i, usz j)
{
@swap(list.entries[i], list.entries[j]);
@swap(self.entries[i], self.entries[j]);
}
/**
* @param [&inout] list "The list to remove elements from"
* @param filter "The function to determine if it should be removed or not"
* @return "the number of deleted elements"
**/
fn usz List.remove_if(List* list, ElementPredicate filter)
fn usz List.remove_if(&self, ElementPredicate filter)
{
usz size = list.size;
usz size = self.size;
for (usz i = size; i > 0; i--)
{
if (filter(&list.entries[i - 1])) continue;
if (filter(&self.entries[i - 1])) continue;
for (usz j = i; j < size; j++)
{
list.entries[j - 1] = list.entries[j];
self.entries[j - 1] = self.entries[j];
}
list.size--;
self.size--;
}
return size - list.size;
return size - self.size;
}
/**
* @param [&inout] list "The list to remove elements from"
* @param selection "The function to determine if it should be kept or not"
* @return "the number of deleted elements"
**/
fn usz List.retain_if(List* list, ElementPredicate selection)
fn usz List.retain_if(&self, ElementPredicate selection)
{
usz size = list.size;
usz size = self.size;
for (usz i = size; i > 0; i--)
{
if (!selection(&list.entries[i - 1])) continue;
if (!selection(&self.entries[i - 1])) continue;
for (usz j = i; j < size; j++)
{
list.entries[j - 1] = list.entries[j];
self.entries[j - 1] = self.entries[j];
}
list.size--;
self.size--;
}
return size - list.size;
return size - self.size;
}
/**
* Reserve at least min_capacity
**/
fn void List.reserve(List* list, usz min_capacity)
fn void List.reserve(&self, usz min_capacity)
{
if (!min_capacity) return;
if (list.capacity >= min_capacity) return;
if (!list.allocator) list.allocator = mem::heap();
if (self.capacity >= min_capacity) return;
if (!self.allocator) self.allocator = mem::heap();
min_capacity = math::next_power_of_2(min_capacity);
list.entries = realloc_aligned(list.entries, Type.sizeof * min_capacity, .alignment = Type[1].alignof, .using = list.allocator) ?? null;
list.capacity = min_capacity;
self.entries = realloc_aligned(self.entries, Type.sizeof * min_capacity, .alignment = Type[1].alignof, .using = self.allocator) ?? null;
self.capacity = min_capacity;
}
macro Type List.@item_at(List &list, usz index) @operator([])
macro Type List.@item_at(&self, usz index) @operator([])
{
return list.entries[index];
return self.entries[index];
}
fn Type* List.get_ref(List* list, usz index) @operator(&[]) @inline
fn Type* List.get_ref(&self, usz index) @operator(&[]) @inline
{
return &list.entries[index];
return &self.entries[index];
}
fn void List.ensure_capacity(List* list, usz added = 1) @inline @private
fn void List.ensure_capacity(&self, usz added = 1) @inline @private
{
usz new_size = list.size + added;
if (list.capacity > new_size) return;
usz new_size = self.size + added;
if (self.capacity > new_size) return;
assert(new_size < usz.max / 2U);
usz new_capacity = list.capacity ? 2U * list.capacity : 16U;
usz new_capacity = self.capacity ? 2U * self.capacity : 16U;
while (new_size >= new_capacity) new_capacity *= 2U;
list.reserve(new_capacity);
self.reserve(new_capacity);
}
// Functions for equatable types
fn usz! List.index_of(List* list, Type type) @if(ELEMENT_IS_EQUATABLE)
fn usz! List.index_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
{
foreach (i, v : list)
foreach (i, v : self)
{
if (v == type) return i;
}
return SearchResult.MISSING?;
}
fn usz! List.rindex_of(List* list, Type type) @if(ELEMENT_IS_EQUATABLE)
fn usz! List.rindex_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
{
foreach_r (i, v : list)
foreach_r (i, v : self)
{
if (v == type) return i;
}
return SearchResult.MISSING?;
}
fn bool List.equals(List* list, List other_list) @if(ELEMENT_IS_EQUATABLE)
fn bool List.equals(&self, List other_list) @if(ELEMENT_IS_EQUATABLE)
{
if (list.size != other_list.size) return false;
foreach (i, v : list)
if (self.size != other_list.size) return false;
foreach (i, v : self)
{
if (v != other_list.entries[i]) return false;
}
@@ -339,13 +335,13 @@ fn bool List.equals(List* list, List other_list) @if(ELEMENT_IS_EQUATABLE)
/**
* Check for presence of a value in a list.
*
* @param [&in] list "the list to find elements in"
* @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 List.contains(List* list, Type value) @if(ELEMENT_IS_EQUATABLE)
fn bool List.contains(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
{
foreach (i, v : list)
foreach (i, v : self)
{
if (v == value) return true;
}
@@ -354,53 +350,53 @@ fn bool List.contains(List* list, Type value) @if(ELEMENT_IS_EQUATABLE)
/**
* @param [&inout] list "The list to remove elements from"
* @param [&inout] self "The list to remove elements from"
* @param value "The value to remove"
* @return "the number of deleted elements."
**/
fn usz List.remove(List* list, Type value) @if(ELEMENT_IS_EQUATABLE)
fn usz List.remove(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
{
usz size = list.size;
usz size = self.size;
for (usz i = size; i > 0; i--)
{
if (list.entries[i - 1] != value) continue;
if (self.entries[i - 1] != value) continue;
for (usz j = i; j < size; j++)
{
list.entries[j - 1] = list.entries[j];
self.entries[j - 1] = self.entries[j];
}
list.size--;
self.size--;
}
return size - list.size;
return size - self.size;
}
fn void List.remove_all(List* list, List* other_list) @if(ELEMENT_IS_EQUATABLE)
fn void List.remove_all(&self, List* other_list) @if(ELEMENT_IS_EQUATABLE)
{
if (!other_list.size) return;
foreach (v : other_list) list.remove(v);
foreach (v : other_list) self.remove(v);
}
/**
* @param [&in] list
* @param [&in] self
* @return "The number non-null values in the list"
**/
fn usz List.compact_count(List* list) @if(ELEMENT_IS_POINTER)
fn usz List.compact_count(&self) @if(ELEMENT_IS_POINTER)
{
usz vals = 0;
foreach (v : list) if (v) vals++;
foreach (v : self) if (v) vals++;
return vals;
}
fn usz List.compact(List* list) @if(ELEMENT_IS_POINTER)
fn usz List.compact(&self) @if(ELEMENT_IS_POINTER)
{
usz size = list.size;
usz size = self.size;
for (usz i = size; i > 0; i--)
{
if (list.entries[i - 1]) continue;
if (self.entries[i - 1]) continue;
for (usz j = i; j < size; j++)
{
list.entries[j - 1] = list.entries[j];
self.entries[j - 1] = self.entries[j];
}
list.size--;
self.size--;
}
return size - list.size;
return size - self.size;
}