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;
|
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;
|
*a = init_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn void! EnumMap.to_format(EnumMap* map, Formatter* formatter) @dynamic
|
fn void! EnumMap.to_format(&self, Formatter* formatter) @dynamic
|
||||||
{
|
{
|
||||||
formatter.print("{ ")!;
|
formatter.print("{ ")!;
|
||||||
foreach (i, &value : map.values)
|
foreach (i, &value : self.values)
|
||||||
{
|
{
|
||||||
if (i != 0) formatter.print(", ")!;
|
if (i != 0) formatter.print(", ")!;
|
||||||
formatter.printf("%s: %s", (Enum)i, *value)!;
|
formatter.printf("%s: %s", (Enum)i, *value)!;
|
||||||
@@ -25,11 +25,11 @@ fn void! EnumMap.to_format(EnumMap* map, Formatter* formatter) @dynamic
|
|||||||
formatter.print(" }")!;
|
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 uint EnumMap.len(&self) @operator(len) => self.values.len;
|
||||||
fn ValueType EnumMap.get(EnumMap* this, Enum key) @operator([]) => this.values[key.ordinal];
|
fn ValueType EnumMap.get(&self, Enum key) @operator([]) => self.values[key.ordinal];
|
||||||
fn void EnumMap.set(EnumMap* this, Enum key, ValueType value) @operator([]=) => this.values[key.ordinal] = value;
|
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.
|
// 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.
|
// 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;
|
const IS_CHAR_ARRAY = Enum.elements > 128;
|
||||||
def EnumSet = distinct EnumSetType;
|
def EnumSet = distinct EnumSetType;
|
||||||
|
|
||||||
fn void EnumSet.add(EnumSet* this, Enum v)
|
fn void EnumSet.add(&self, Enum v)
|
||||||
{
|
{
|
||||||
$if IS_CHAR_ARRAY:
|
$if IS_CHAR_ARRAY:
|
||||||
(*this)[(usz)v / 8] |= (char)(1u << ((usz)v % 8));
|
(*self)[(usz)v / 8] |= (char)(1u << ((usz)v % 8));
|
||||||
$else
|
$else
|
||||||
*this = (EnumSet)((EnumSetType)*this | 1u << (EnumSetType)v);
|
*self = (EnumSet)((EnumSetType)*self | 1u << (EnumSetType)v);
|
||||||
$endif
|
$endif
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void EnumSet.clear(EnumSet* this)
|
fn void EnumSet.clear(&self)
|
||||||
{
|
{
|
||||||
$if IS_CHAR_ARRAY:
|
$if IS_CHAR_ARRAY:
|
||||||
*this = {};
|
*self = {};
|
||||||
$else
|
$else
|
||||||
*this = 0;
|
*self = 0;
|
||||||
$endif
|
$endif
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bool EnumSet.remove(EnumSet* this, Enum v)
|
fn bool EnumSet.remove(&self, Enum v)
|
||||||
{
|
{
|
||||||
$if IS_CHAR_ARRAY:
|
$if IS_CHAR_ARRAY:
|
||||||
if (!this.has(v) @inline) return false;
|
if (!self.has(v) @inline) return false;
|
||||||
(*this)[(usz)v / 8] &= (char)~(1u << ((usz)v % 8));
|
(*self)[(usz)v / 8] &= (char)~(1u << ((usz)v % 8));
|
||||||
return true;
|
return true;
|
||||||
$else
|
$else
|
||||||
EnumSetType old = (EnumSetType)*this;
|
EnumSetType old = (EnumSetType)*self;
|
||||||
EnumSetType new = old & ~(1u << (EnumSetType)v);
|
EnumSetType new = old & ~(1u << (EnumSetType)v);
|
||||||
*this = (EnumSet)new;
|
*self = (EnumSet)new;
|
||||||
return old != new;
|
return old != new;
|
||||||
$endif
|
$endif
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bool EnumSet.has(EnumSet* this, Enum v)
|
fn bool EnumSet.has(&self, Enum v)
|
||||||
{
|
{
|
||||||
$if IS_CHAR_ARRAY:
|
$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
|
$else
|
||||||
return ((EnumSetType)*this & (1u << (EnumSetType)v)) != 0;
|
return ((EnumSetType)*self & (1u << (EnumSetType)v)) != 0;
|
||||||
$endif
|
$endif
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void EnumSet.add_all(EnumSet* this, EnumSet s)
|
fn void EnumSet.add_all(&self, EnumSet s)
|
||||||
{
|
{
|
||||||
$if IS_CHAR_ARRAY:
|
$if IS_CHAR_ARRAY:
|
||||||
foreach (i, c : s) (*this)[i] |= c;
|
foreach (i, c : s) (*self)[i] |= c;
|
||||||
$else
|
$else
|
||||||
*this = (EnumSet)((EnumSetType)*this | (EnumSetType)s);
|
*self = (EnumSet)((EnumSetType)*self | (EnumSetType)s);
|
||||||
$endif
|
$endif
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void EnumSet.retain_all(EnumSet* this, EnumSet s)
|
fn void EnumSet.retain_all(&self, EnumSet s)
|
||||||
{
|
{
|
||||||
$if IS_CHAR_ARRAY:
|
$if IS_CHAR_ARRAY:
|
||||||
foreach (i, c : s) (*this)[i] &= c;
|
foreach (i, c : s) (*self)[i] &= c;
|
||||||
$else
|
$else
|
||||||
*this = (EnumSet)((EnumSetType)*this & (EnumSetType)s);
|
*self = (EnumSet)((EnumSetType)*self & (EnumSetType)s);
|
||||||
$endif
|
$endif
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void EnumSet.remove_all(EnumSet* this, EnumSet s)
|
fn void EnumSet.remove_all(&self, EnumSet s)
|
||||||
{
|
{
|
||||||
$if IS_CHAR_ARRAY:
|
$if IS_CHAR_ARRAY:
|
||||||
foreach (i, c : s) (*this)[i] &= ~c;
|
foreach (i, c : s) (*self)[i] &= ~c;
|
||||||
$else
|
$else
|
||||||
*this = (EnumSet)((EnumSetType)*this & ~(EnumSetType)s);
|
*self = (EnumSet)((EnumSetType)*self & ~(EnumSetType)s);
|
||||||
$endif
|
$endif
|
||||||
}
|
}
|
||||||
|
|
||||||
fn EnumSet EnumSet.and_of(EnumSet* this, EnumSet s)
|
fn EnumSet EnumSet.and_of(&self, EnumSet s)
|
||||||
{
|
{
|
||||||
$if IS_CHAR_ARRAY:
|
$if IS_CHAR_ARRAY:
|
||||||
EnumSet copy = *this;
|
EnumSet copy = *self;
|
||||||
copy.retain_all(s);
|
copy.retain_all(s);
|
||||||
return copy;
|
return copy;
|
||||||
$else
|
$else
|
||||||
return (EnumSet)((EnumSetType)*this & (EnumSetType)s);
|
return (EnumSet)((EnumSetType)*self & (EnumSetType)s);
|
||||||
$endif
|
$endif
|
||||||
}
|
}
|
||||||
|
|
||||||
fn EnumSet EnumSet.or_of(EnumSet* this, EnumSet s)
|
fn EnumSet EnumSet.or_of(&self, EnumSet s)
|
||||||
{
|
{
|
||||||
$if IS_CHAR_ARRAY:
|
$if IS_CHAR_ARRAY:
|
||||||
EnumSet copy = *this;
|
EnumSet copy = *self;
|
||||||
copy.add_all(s);
|
copy.add_all(s);
|
||||||
return copy;
|
return copy;
|
||||||
$else
|
$else
|
||||||
return (EnumSet)((EnumSetType)*this | (EnumSetType)s);
|
return (EnumSet)((EnumSetType)*self | (EnumSetType)s);
|
||||||
$endif
|
$endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn EnumSet EnumSet.diff_of(EnumSet* this, EnumSet s)
|
fn EnumSet EnumSet.diff_of(&self, EnumSet s)
|
||||||
{
|
{
|
||||||
$if IS_CHAR_ARRAY:
|
$if IS_CHAR_ARRAY:
|
||||||
EnumSet copy = *this;
|
EnumSet copy = *self;
|
||||||
copy.remove_all(s);
|
copy.remove_all(s);
|
||||||
return copy;
|
return copy;
|
||||||
$else
|
$else
|
||||||
return (EnumSet)((EnumSetType)*this & ~(EnumSetType)s);
|
return (EnumSet)((EnumSetType)*self & ~(EnumSetType)s);
|
||||||
$endif
|
$endif
|
||||||
}
|
}
|
||||||
|
|
||||||
fn EnumSet EnumSet.xor_of(EnumSet* this, EnumSet s)
|
fn EnumSet EnumSet.xor_of(&self, EnumSet s)
|
||||||
{
|
{
|
||||||
$if IS_CHAR_ARRAY:
|
$if IS_CHAR_ARRAY:
|
||||||
EnumSet copy = *this;
|
EnumSet copy = *self;
|
||||||
foreach (i, c : s) copy[i] ^= c;
|
foreach (i, c : s) copy[i] ^= c;
|
||||||
return copy;
|
return copy;
|
||||||
$else
|
$else
|
||||||
return (EnumSet)((EnumSetType)*this ^ (EnumSetType)s);
|
return (EnumSet)((EnumSetType)*self ^ (EnumSetType)s);
|
||||||
$endif
|
$endif
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void! EnumSet.to_format(EnumSet* set, Formatter* formatter) @dynamic
|
fn void! EnumSet.to_format(&set, Formatter* formatter) @dynamic
|
||||||
{
|
{
|
||||||
formatter.print("[")!;
|
formatter.print("[")!;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
@@ -139,7 +139,7 @@ fn void! EnumSet.to_format(EnumSet* set, Formatter* formatter) @dynamic
|
|||||||
formatter.print("]")!;
|
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);
|
return string::printf("%s", *set);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
|
// 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.
|
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||||
module std::collections::linkedlist<Type>;
|
module std::collections::linkedlist<Type>;
|
||||||
|
|
||||||
@@ -18,161 +18,161 @@ struct LinkedList
|
|||||||
Node *_last;
|
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();
|
if (!self.allocator) self.allocator = mem::heap();
|
||||||
return malloc(Node, .using = list.allocator);
|
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 *first = self._first;
|
||||||
Node *new_node = list.@alloc_node();
|
Node *new_node = self.alloc_node();
|
||||||
*new_node = { .next = first, .value = value };
|
*new_node = { .next = first, .value = value };
|
||||||
list._first = new_node;
|
self._first = new_node;
|
||||||
if (!first)
|
if (!first)
|
||||||
{
|
{
|
||||||
list._last = new_node;
|
self._last = new_node;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
first.prev = new_node;
|
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 *last = self._last;
|
||||||
Node *new_node = list.@alloc_node();
|
Node *new_node = self.alloc_node();
|
||||||
*new_node = { .prev = last, .value = value };
|
*new_node = { .prev = last, .value = value };
|
||||||
list._last = new_node;
|
self._last = new_node;
|
||||||
if (!last)
|
if (!last)
|
||||||
{
|
{
|
||||||
list._first = new_node;
|
self._first = new_node;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
last.next = new_node;
|
last.next = new_node;
|
||||||
}
|
}
|
||||||
list.size++;
|
self.size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Type! LinkedList.peek(LinkedList* list) => list.first() @inline;
|
fn Type! LinkedList.peek(&self) => self.first() @inline;
|
||||||
fn Type! LinkedList.peek_last(LinkedList* list) => list.last() @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?;
|
if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
|
||||||
return list._first.value;
|
return self._first.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Type! LinkedList.last(LinkedList* list)
|
fn Type! LinkedList.last(&self)
|
||||||
{
|
{
|
||||||
if (!list._last) return IteratorResult.NO_MORE_ELEMENT?;
|
if (!self._last) return IteratorResult.NO_MORE_ELEMENT?;
|
||||||
return list._last.value;
|
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;
|
Node* next = node.next;
|
||||||
list.@free_node(node);
|
self.free_node(node);
|
||||||
node = next;
|
node = next;
|
||||||
}
|
}
|
||||||
list._first = null;
|
self._first = null;
|
||||||
list._last = null;
|
self._last = null;
|
||||||
list.size = 0;
|
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;
|
Node* node = self._last;
|
||||||
index = list.size - index - 1;
|
index = self.size - index - 1;
|
||||||
while (index--) node = node.prev;
|
while (index--) node = node.prev;
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
Node* node = list._first;
|
Node* node = self._first;
|
||||||
while (index--) node = node.next;
|
while (index--) node = node.next;
|
||||||
return node;
|
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)
|
switch (index)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
list.push(element);
|
self.push(element);
|
||||||
case list.size:
|
case self.size:
|
||||||
list.push_last(element);
|
self.push_last(element);
|
||||||
default:
|
default:
|
||||||
list.link_before(list.node_at_index(index), element);
|
self.link_before(self.node_at_index(index), element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @require succ != null
|
* @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* pred = succ.prev;
|
||||||
Node* new_node = malloc(Node);
|
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;
|
succ.prev = new_node;
|
||||||
if (!pred)
|
if (!pred)
|
||||||
{
|
{
|
||||||
list._first = new_node;
|
self._first = new_node;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pred.next = new_node;
|
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;
|
Node* next = f.next;
|
||||||
list.@free_node(f);
|
self.free_node(f);
|
||||||
list._first = next;
|
self._first = next;
|
||||||
if (!next)
|
if (!next)
|
||||||
{
|
{
|
||||||
list._last = null;
|
self._last = null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
next.prev = null;
|
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)
|
if (node.value == t)
|
||||||
{
|
{
|
||||||
list.unlink(node);
|
self.unlink(node);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
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)
|
if (node.value == t)
|
||||||
{
|
{
|
||||||
list.unlink(node);
|
self.unlink(node);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
fn Type! LinkedList.pop(&self)
|
||||||
* @param [&inout] list
|
|
||||||
**/
|
|
||||||
fn Type! LinkedList.pop(LinkedList* list)
|
|
||||||
{
|
{
|
||||||
if (!list._first) return IteratorResult.NO_MORE_ELEMENT?;
|
if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
|
||||||
defer list.unlink_first();
|
defer self.unlink_first();
|
||||||
return list._first.value;
|
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?;
|
Node* l = self._last;
|
||||||
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* prev = l.prev;
|
Node* prev = l.prev;
|
||||||
list._last = prev;
|
self._last = prev;
|
||||||
list.@free_node(l);
|
self.free_node(l);
|
||||||
if (!prev)
|
if (!prev)
|
||||||
{
|
{
|
||||||
list._first = null;
|
self._first = null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
prev.next = null;
|
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* next = x.next;
|
||||||
Node* prev = x.prev;
|
Node* prev = x.prev;
|
||||||
if (!prev)
|
if (!prev)
|
||||||
{
|
{
|
||||||
list._first = next;
|
self._first = next;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -301,12 +291,12 @@ fn void LinkedList.unlink(LinkedList* list, Node* x) @private
|
|||||||
}
|
}
|
||||||
if (!next)
|
if (!next)
|
||||||
{
|
{
|
||||||
list._last = prev;
|
self._last = prev;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
next.prev = prev;
|
next.prev = prev;
|
||||||
}
|
}
|
||||||
list.@free_node(x);
|
self.free_node(x);
|
||||||
list.size--;
|
self.size--;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
|
// 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.
|
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||||
module std::collections::list<Type>;
|
module std::collections::list<Type>;
|
||||||
import std::math;
|
import std::math;
|
||||||
@@ -19,38 +19,38 @@ struct List
|
|||||||
/**
|
/**
|
||||||
* @require using != null "A valid allocator must be provided"
|
* @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;
|
self.allocator = using;
|
||||||
list.size = 0;
|
self.size = 0;
|
||||||
if (initial_capacity > 0)
|
if (initial_capacity > 0)
|
||||||
{
|
{
|
||||||
initial_capacity = math::next_power_of_2(initial_capacity);
|
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
|
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:
|
case 0:
|
||||||
formatter.print("[]")!;
|
formatter.print("[]")!;
|
||||||
case 1:
|
case 1:
|
||||||
formatter.printf("[%s]", list.entries[0])!;
|
formatter.printf("[%s]", self.entries[0])!;
|
||||||
default:
|
default:
|
||||||
formatter.print("[")!;
|
formatter.print("[")!;
|
||||||
foreach (i, element : list.entries[:list.size])
|
foreach (i, element : self.entries[:self.size])
|
||||||
{
|
{
|
||||||
if (i != 0) formatter.print(", ")!;
|
if (i != 0) formatter.print(", ")!;
|
||||||
formatter.printf("%s", element)!;
|
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();
|
self.ensure_capacity();
|
||||||
list.entries[list.size++] = element;
|
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];
|
Type value = self.entries[0];
|
||||||
list.remove_at(0);
|
self.remove_at(0);
|
||||||
return value;
|
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;
|
if (!other_list.size) return;
|
||||||
list.reserve(other_list.size);
|
self.reserve(other_list.size);
|
||||||
foreach (&value : other_list)
|
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[] {};
|
if (!self.size) return Type[] {};
|
||||||
Type[] result = malloc(Type, list.size, .using = using);
|
Type[] result = malloc(Type, self.size, .using = using);
|
||||||
result[..] = list.entries[:list.size];
|
result[..] = self.entries[:self.size];
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reverse the elements in a list.
|
* 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;
|
if (self.size < 2) return;
|
||||||
usz half = list.size / 2U;
|
usz half = self.size / 2U;
|
||||||
usz end = list.size - 1;
|
usz end = self.size - 1;
|
||||||
for (usz i = 0; i < half; i++)
|
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;
|
if (!array.len) return;
|
||||||
list.reserve(array.len);
|
self.reserve(array.len);
|
||||||
foreach (&value : array)
|
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();
|
self.ensure_capacity();
|
||||||
for (usz i = list.size; i > index; i--)
|
for (usz i = self.size; i > index; i--)
|
||||||
{
|
{
|
||||||
list.entries[i] = list.entries[i - 1];
|
self.entries[i] = self.entries[i - 1];
|
||||||
}
|
}
|
||||||
list.size++;
|
self.size++;
|
||||||
list.entries[index] = type;
|
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;
|
if (!self.allocator) return;
|
||||||
free_aligned(list.entries, .using = list.allocator);
|
free_aligned(self.entries, .using = self.allocator);
|
||||||
list.capacity = 0;
|
self.capacity = 0;
|
||||||
list.size = 0;
|
self.size = 0;
|
||||||
list.entries = null;
|
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"
|
* @param filter "The function to determine if it should be removed or not"
|
||||||
* @return "the number of deleted elements"
|
* @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--)
|
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++)
|
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"
|
* @param selection "The function to determine if it should be kept or not"
|
||||||
* @return "the number of deleted elements"
|
* @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--)
|
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++)
|
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
|
* 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 (!min_capacity) return;
|
||||||
if (list.capacity >= min_capacity) return;
|
if (self.capacity >= min_capacity) return;
|
||||||
if (!list.allocator) list.allocator = mem::heap();
|
if (!self.allocator) self.allocator = mem::heap();
|
||||||
min_capacity = math::next_power_of_2(min_capacity);
|
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;
|
self.entries = realloc_aligned(self.entries, Type.sizeof * min_capacity, .alignment = Type[1].alignof, .using = self.allocator) ?? null;
|
||||||
list.capacity = min_capacity;
|
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;
|
usz new_size = self.size + added;
|
||||||
if (list.capacity > new_size) return;
|
if (self.capacity > new_size) return;
|
||||||
|
|
||||||
assert(new_size < usz.max / 2U);
|
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;
|
while (new_size >= new_capacity) new_capacity *= 2U;
|
||||||
list.reserve(new_capacity);
|
self.reserve(new_capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Functions for equatable types
|
// 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;
|
if (v == type) return i;
|
||||||
}
|
}
|
||||||
return SearchResult.MISSING?;
|
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;
|
if (v == type) return i;
|
||||||
}
|
}
|
||||||
return SearchResult.MISSING?;
|
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;
|
if (self.size != other_list.size) return false;
|
||||||
foreach (i, v : list)
|
foreach (i, v : self)
|
||||||
{
|
{
|
||||||
if (v != other_list.entries[i]) return false;
|
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.
|
* 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"
|
* @param value "The value to search for"
|
||||||
* @return "True if the value is found, false otherwise"
|
* @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;
|
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"
|
* @param value "The value to remove"
|
||||||
* @return "the number of deleted elements."
|
* @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--)
|
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++)
|
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;
|
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"
|
* @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;
|
usz vals = 0;
|
||||||
foreach (v : list) if (v) vals++;
|
foreach (v : self) if (v) vals++;
|
||||||
return 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--)
|
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++)
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3005,9 +3005,15 @@ static Module *module_instantiate_generic(SemaContext *context, Module *module,
|
|||||||
VECEACH(module->parameters, i)
|
VECEACH(module->parameters, i)
|
||||||
{
|
{
|
||||||
const char *param_name = module->parameters[i];
|
const char *param_name = module->parameters[i];
|
||||||
|
bool is_value = str_is_valid_constant(param_name);
|
||||||
Expr *param = params[i];
|
Expr *param = params[i];
|
||||||
if (param->expr_kind != EXPR_TYPEINFO)
|
if (param->expr_kind != EXPR_TYPEINFO)
|
||||||
{
|
{
|
||||||
|
if (!is_value)
|
||||||
|
{
|
||||||
|
SEMA_ERROR(param, "Expected a type, not a value.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
Decl *decl = decl_new_var(param_name, param->span, NULL, VARDECL_CONST);
|
Decl *decl = decl_new_var(param_name, param->span, NULL, VARDECL_CONST);
|
||||||
decl->var.init_expr = param;
|
decl->var.init_expr = param;
|
||||||
decl->type = param->type;
|
decl->type = param->type;
|
||||||
@@ -3015,6 +3021,11 @@ static Module *module_instantiate_generic(SemaContext *context, Module *module,
|
|||||||
vec_add(first_context->global_decls, decl);
|
vec_add(first_context->global_decls, decl);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (is_value)
|
||||||
|
{
|
||||||
|
SEMA_ERROR(param, "Expected a value, not a type.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
Decl *decl = decl_new_with_type(param_name, params[i]->span, DECL_TYPEDEF);
|
Decl *decl = decl_new_with_type(param_name, params[i]->span, DECL_TYPEDEF);
|
||||||
decl->resolve_status = RESOLVE_DONE;
|
decl->resolve_status = RESOLVE_DONE;
|
||||||
TypeInfo *type_info = param->type_expr;
|
TypeInfo *type_info = param->type_expr;
|
||||||
@@ -3233,6 +3244,7 @@ static bool sema_analyse_parameterized_define(SemaContext *c, Decl *decl)
|
|||||||
path->len = scratch_buffer.len;
|
path->len = scratch_buffer.len;
|
||||||
instantiated_module = module_instantiate_generic(c, module, path,
|
instantiated_module = module_instantiate_generic(c, module, path,
|
||||||
decl->define_decl.generic_params, decl->span);
|
decl->define_decl.generic_params, decl->span);
|
||||||
|
if (!instantiated_module) return decl_poison(decl);
|
||||||
sema_analyze_stage(instantiated_module, c->unit->module->stage - 1);
|
sema_analyze_stage(instantiated_module, c->unit->module->stage - 1);
|
||||||
}
|
}
|
||||||
if (global_context.errors_found) return decl_poison(decl);
|
if (global_context.errors_found) return decl_poison(decl);
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ char *str_printf(const char *var, ...) __printflike(1, 2);
|
|||||||
char *str_vprintf(const char *var, va_list list);
|
char *str_vprintf(const char *var, va_list list);
|
||||||
void str_ellide_in_place(char *string, size_t max_size_shown);
|
void str_ellide_in_place(char *string, size_t max_size_shown);
|
||||||
bool str_is_valid_lowercase_name(const char *string);
|
bool str_is_valid_lowercase_name(const char *string);
|
||||||
|
bool str_is_valid_constant(const char *string);
|
||||||
bool str_has_no_uppercase(const char *string);
|
bool str_has_no_uppercase(const char *string);
|
||||||
char *str_copy(const char *start, size_t str_len);
|
char *str_copy(const char *start, size_t str_len);
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,18 @@ bool str_is_valid_lowercase_name(const char *string)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool str_is_valid_constant(const char *string)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
// Must start with a lower case
|
||||||
|
int length = 0;
|
||||||
|
while ((c = *(string++)) != '\0')
|
||||||
|
{
|
||||||
|
if (!char_is_upper(c) && c != '_') return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void str_ellide_in_place(char *string, size_t max_size_shown)
|
void str_ellide_in_place(char *string, size_t max_size_shown)
|
||||||
{
|
{
|
||||||
size_t len = strlen(string);
|
size_t len = strlen(string);
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define COMPILER_VERSION "0.4.547"
|
#define COMPILER_VERSION "0.4.548"
|
||||||
11
test/test_suite/generic/incorrect_argument_type.c3
Normal file
11
test/test_suite/generic/incorrect_argument_type.c3
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
module foo<Type, SIZE>;
|
||||||
|
|
||||||
|
struct Foo
|
||||||
|
{
|
||||||
|
Type[SIZE] x;
|
||||||
|
}
|
||||||
|
module bar;
|
||||||
|
import foo;
|
||||||
|
|
||||||
|
def Bar = Foo<int, int>; // #error: Expected a value, not a type
|
||||||
|
def Baz = Foo<5, 4>; // #error: Expected a type, not a value
|
||||||
Reference in New Issue
Block a user