mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Fix #809 missing checks on generic types, accepting both types where constants should be and vice versa.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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--;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user