Fix precedence of braces. Updated to lib2.

This commit is contained in:
Christoffer Lerno
2025-02-23 01:30:34 +01:00
parent a986d053c0
commit 3a1aa8bdf0
25 changed files with 194 additions and 832 deletions

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2024 Christoffer Lerno. All rights reserved.
// Copyright (c) 2024-2025 Christoffer Lerno. All rights reserved.
// Use of self source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::collections::anylist;
@@ -16,16 +16,6 @@ struct AnyList (Printable)
}
<*
Use `init` for to use a custom allocator.
@param initial_capacity "The initial capacity to reserve"
*>
fn AnyList* AnyList.new_init(&self, usz initial_capacity = 16, Allocator allocator = null)
{
return self.init(allocator ?: allocator::heap(), initial_capacity) @inline;
}
<*
@param [&inout] allocator "The allocator to use"
@param initial_capacity "The initial capacity to reserve"
@@ -52,9 +42,9 @@ fn AnyList* AnyList.init(&self, Allocator allocator, usz initial_capacity = 16)
@param initial_capacity "The initial capacity to reserve"
*>
fn AnyList* AnyList.temp_init(&self, usz initial_capacity = 16)
fn AnyList* AnyList.tinit(&self, usz initial_capacity = 16)
{
return self.init(allocator::temp(), initial_capacity) @inline;
return self.init(tmem(), initial_capacity) @inline;
}
fn usz! AnyList.to_format(&self, Formatter* formatter) @dynamic
@@ -152,13 +142,13 @@ fn any! AnyList.new_pop(&self, Allocator allocator = allocator::heap())
@return! IteratorResult.NO_MORE_ELEMENT
@deprecated `use tcopy_pop`
*>
fn any! AnyList.temp_pop(&self) => self.copy_pop(allocator::temp());
fn any! AnyList.temp_pop(&self) => self.copy_pop(tmem());
<*
Pop the last value and allocate the copy using the temp allocator
@return! IteratorResult.NO_MORE_ELEMENT
*>
fn any! AnyList.tcopy_pop(&self) => self.copy_pop(allocator::temp());
fn any! AnyList.tcopy_pop(&self) => self.copy_pop(tmem());
<*
Pop the last value. It must later be released using list.free_element()
@@ -222,13 +212,13 @@ fn any! AnyList.copy_pop_first(&self, Allocator allocator = allocator::heap())
<*
Same as temp_pop() but pops the first value instead.
*>
fn any! AnyList.tcopy_pop_first(&self) => self.copy_pop_first(allocator::temp());
fn any! AnyList.tcopy_pop_first(&self) => self.copy_pop_first(tmem());
<*
Same as temp_pop() but pops the first value instead.
@deprecated `use tcopy_pop_first`
*>
fn any! AnyList.temp_pop_first(&self) => self.new_pop_first(allocator::temp());
fn any! AnyList.temp_pop_first(&self) => self.new_pop_first(tmem());
<*
@require index < self.size
@@ -466,7 +456,7 @@ fn void AnyList.reserve(&self, usz min_capacity)
{
if (!min_capacity) return;
if (self.capacity >= min_capacity) return;
if (!self.allocator) self.allocator = allocator::heap();
if (!self.allocator) self.allocator = tmem();
min_capacity = math::next_power_of_2(min_capacity);
self.entries = allocator::realloc(self.allocator, self.entries, any.sizeof * min_capacity);
self.capacity = min_capacity;

View File

@@ -1,7 +1,7 @@
<*
@require SIZE > 0
*>
module std::collections::bitset(<SIZE>);
module std::collections::bitset{SIZE};
def Type = uint;
@@ -75,7 +75,7 @@ import std::collections::list;
const BITS = Type.sizeof * 8;
def GrowableBitSetList = List(<Type>);
def GrowableBitSetList = List{Type};
struct GrowableBitSet
{
@@ -86,15 +86,15 @@ struct GrowableBitSet
@param initial_capacity
@param [&inout] allocator "The allocator to use, defaults to the heap allocator"
*>
fn GrowableBitSet* GrowableBitSet.new_init(&self, usz initial_capacity = 1, Allocator allocator = allocator::heap())
fn GrowableBitSet* GrowableBitSet.init(&self, Allocator allocator, usz initial_capacity = 1)
{
self.data.new_init(initial_capacity, allocator);
self.data.init(allocator, initial_capacity);
return self;
}
fn GrowableBitSet* GrowableBitSet.temp_init(&self, usz initial_capacity = 1)
fn GrowableBitSet* GrowableBitSet.tinit(&self, usz initial_capacity = 1)
{
return self.new_init(initial_capacity, allocator::temp()) @inline;
return self.init(tmem(), initial_capacity) @inline;
}
fn void GrowableBitSet.free(&self)

View File

@@ -4,7 +4,7 @@
<*
@require MAX_SIZE >= 1 `The size must be at least 1 element big.`
*>
module std::collections::elastic_array(<Type, MAX_SIZE>);
module std::collections::elastic_array{Type, MAX_SIZE};
import std::io, std::math, std::collections::list_common;
def ElementPredicate = fn bool(Type *type);
@@ -195,9 +195,9 @@ macro Type[] ElasticArray.to_array(&self, Allocator allocator)
fn Type[] ElasticArray.to_tarray(&self)
{
$if type_is_overaligned():
return self.to_aligned_array(allocator::temp());
return self.to_aligned_array(tmem());
$else
return self.to_array(allocator::temp());
return self.to_array(tmem());
$endif;
}

View File

@@ -1,7 +1,7 @@
<*
@require Enum.kindof == TypeKind.ENUM : "Only enums may be used with an enummap"
*>
module std::collections::enummap(<Enum, ValueType>);
module std::collections::enummap{Enum, ValueType};
import std::io;
struct EnumMap (Printable)
{
@@ -33,11 +33,6 @@ fn String EnumMap.to_string(&self, Allocator allocator) @dynamic
return string::format("%s", *self, allocator: allocator);
}
fn String EnumMap.to_new_string(&self, Allocator allocator = null) @dynamic
{
return string::format("%s", *self, allocator: allocator ?: allocator::heap());
}
fn String EnumMap.to_tstring(&self) @dynamic
{
return string::tformat("%s", *self);

View File

@@ -5,10 +5,10 @@
<*
@require Enum.kindof == TypeKind.ENUM : "Only enums may be used with an enumset"
*>
module std::collections::enumset(<Enum>);
module std::collections::enumset{Enum};
import std::io;
def EnumSetType = $typefrom(private::type_for_enum_elements(Enum.elements)) @private;
def EnumSetType = $typefrom(type_for_enum_elements(Enum.elements)) @private;
const IS_CHAR_ARRAY = Enum.elements > 128;
distinct EnumSet (Printable) = EnumSetType;
@@ -141,24 +141,7 @@ fn usz! EnumSet.to_format(&set, Formatter* formatter) @dynamic
return n;
}
fn String EnumSet.to_new_string(&set, Allocator allocator = allocator::heap()) @dynamic
{
return string::format("%s", *set, allocator: allocator);
}
fn String EnumSet.to_string(&set, Allocator allocator) @dynamic
{
return string::format("%s", *set, allocator: allocator);
}
fn String EnumSet.to_tstring(&set) @dynamic
{
return string::tformat("%s", *set);
}
module std::collections::enumset::private;
macro typeid type_for_enum_elements(usz $elements)
macro typeid type_for_enum_elements(usz $elements) @local
{
$switch
$case ($elements > 128):

View File

@@ -4,10 +4,25 @@
<*
@require $defined((Key){}.hash()) `No .hash function found on the key`
*>
module std::collections::map(<Key, Value>);
module std::collections::map{Key, Value};
import std::math;
import std::io @norecurse;
const uint DEFAULT_INITIAL_CAPACITY = 16;
const uint MAXIMUM_CAPACITY = 1u << 31;
const float DEFAULT_LOAD_FACTOR = 0.75;
const VALUE_IS_EQUATABLE = Value.is_eq;
const bool COPY_KEYS = types::implements_copy(Key);
struct Entry
{
uint hash;
Key key;
Value value;
Entry* next;
}
struct HashMap (Printable)
{
Entry*[] table;
@@ -17,17 +32,6 @@ struct HashMap (Printable)
float load_factor;
}
<*
@param [&inout] allocator "The allocator to use"
@require capacity > 0 "The capacity must be 1 or higher"
@require load_factor > 0.0 "The load factor must be higher than 0"
@require !self.allocator "Map was already initialized"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
fn HashMap* HashMap.new_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = null)
{
return self.init(allocator ?: allocator::heap(), capacity, load_factor);
}
<*
@param [&inout] allocator "The allocator to use"
@@ -52,9 +56,9 @@ fn HashMap* HashMap.init(&self, Allocator allocator, uint capacity = DEFAULT_INI
@require !self.allocator "Map was already initialized"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
fn HashMap* HashMap.temp_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
fn HashMap* HashMap.tinit(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
{
return self.init(allocator::temp(), capacity, load_factor) @inline;
return self.init(tmem(), capacity, load_factor) @inline;
}
<*
@@ -65,15 +69,27 @@ fn HashMap* HashMap.temp_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, f
@require !self.allocator "Map was already initialized"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
macro HashMap* HashMap.new_init_with_key_values(&self, ..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
macro HashMap* HashMap.init_with_key_values(&self, Allocator allocator, ..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
{
self.new_init(capacity, load_factor, allocator);
self.init(allocator, capacity, load_factor);
$for (var $i = 0; $i < $vacount; $i += 2)
self.set($vaarg[$i], $vaarg[$i+1]);
self.set($vaarg[$i], $vaarg[$i + 1]);
$endfor
return self;
}
<*
@require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values"
@require capacity > 0 "The capacity must be 1 or higher"
@require load_factor > 0.0 "The load factor must be higher than 0"
@require !self.allocator "Map was already initialized"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
macro HashMap* HashMap.tinit_with_key_values(&self, ..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
{
return self.tinit_with_key_values(tmem(), capacity, load_factor);
}
<*
@param [in] keys "The keys for the HashMap entries"
@param [in] values "The values for the HashMap entries"
@@ -84,10 +100,10 @@ macro HashMap* HashMap.new_init_with_key_values(&self, ..., uint capacity = DEFA
@require !self.allocator "Map was already initialized"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
fn HashMap* HashMap.new_init_from_keys_and_values(&self, Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
fn HashMap* HashMap.init_from_keys_and_values(&self, Allocator allocator, Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
{
assert(keys.len == values.len);
self.new_init(capacity, load_factor, allocator);
self.init(allocator, capacity, load_factor);
for (usz i = 0; i < keys.len; i++)
{
self.set(keys[i], values[i]);
@@ -95,41 +111,19 @@ fn HashMap* HashMap.new_init_from_keys_and_values(&self, Key[] keys, Value[] val
return self;
}
<*
@require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values"
@require capacity > 0 "The capacity must be 1 or higher"
@require load_factor > 0.0 "The load factor must be higher than 0"
@require !self.allocator "Map was already initialized"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
macro HashMap* HashMap.temp_init_with_key_values(&self, ..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
{
self.temp_init(capacity, load_factor);
$for (var $i = 0; $i < $vacount; $i += 2)
self.set($vaarg[$i], $vaarg[$i+1]);
$endfor
return self;
}
<*
@param [in] keys "The keys for the HashMap entries"
@param [in] values "The values for the HashMap entries"
@param [&inout] allocator "The allocator to use"
@require keys.len == values.len "Both keys and values arrays must be the same length"
@require capacity > 0 "The capacity must be 1 or higher"
@require load_factor > 0.0 "The load factor must be higher than 0"
@require !self.allocator "Map was already initialized"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
fn HashMap* HashMap.temp_init_from_keys_and_values(&self, Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
fn HashMap* HashMap.tinit_from_keys_and_values(&self, Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
{
assert(keys.len == values.len);
self.temp_init(capacity, load_factor);
for (usz i = 0; i < keys.len; i++)
{
self.set(keys[i], values[i]);
}
return self;
return self.init_from_keys_and_values(tmem(), keys, values, capacity, load_factor);
}
<*
@@ -143,21 +137,13 @@ fn bool HashMap.is_initialized(&map)
return (bool)map.allocator;
}
<*
@param [&in] other_map "The map to copy from."
*>
fn HashMap* HashMap.new_init_from_map(&self, HashMap* other_map)
{
return self.init_from_map(other_map, allocator::heap()) @inline;
}
<*
@param [&inout] allocator "The allocator to use"
@param [&in] other_map "The map to copy from."
*>
fn HashMap* HashMap.init_from_map(&self, HashMap* other_map, Allocator allocator)
fn HashMap* HashMap.init_from_map(&self, Allocator allocator, HashMap* other_map)
{
self.new_init(other_map.table.len, other_map.load_factor, allocator);
self.init(allocator, other_map.table.len, other_map.load_factor);
self.put_all_for_create(other_map);
return self;
}
@@ -165,9 +151,9 @@ fn HashMap* HashMap.init_from_map(&self, HashMap* other_map, Allocator allocator
<*
@param [&in] other_map "The map to copy from."
*>
fn HashMap* HashMap.temp_init_from_map(&map, HashMap* other_map)
fn HashMap* HashMap.tinit_from_map(&map, HashMap* other_map)
{
return map.init_from_map(other_map, allocator::temp()) @inline;
return map.init_from_map(tmem(), other_map) @inline;
}
fn bool HashMap.is_empty(&map) @inline
@@ -240,7 +226,7 @@ fn bool HashMap.set(&map, Key key, Value value) @operator([]=)
// If the map isn't initialized, use the defaults to initialize it.
if (!map.allocator)
{
map.new_init();
map.tinit();
}
uint hash = rehash(key.hash());
uint index = index_for(hash, map.table.len);
@@ -289,31 +275,18 @@ fn void HashMap.free(&map)
map.table = {};
}
fn Key[] HashMap.tcopy_keys(&map)
fn Key[] HashMap.tkeys(&self)
{
return map.copy_keys(allocator::temp()) @inline;
return self.keys(tmem()) @inline;
}
fn Key[] HashMap.key_tlist(&map) @deprecated("Use 'tcopy_keys'")
fn Key[] HashMap.keys(&self, Allocator allocator)
{
return map.copy_keys(allocator::temp()) @inline;
}
if (!self.count) return {};
<*
@deprecated "use copy_keys"
*>
fn Key[] HashMap.key_new_list(&map, Allocator allocator = allocator::heap())
{
return map.copy_keys(allocator) @inline;
}
fn Key[] HashMap.copy_keys(&map, Allocator allocator = allocator::heap())
{
if (!map.count) return {};
Key[] list = allocator::alloc_array(allocator, Key, map.count);
Key[] list = allocator::alloc_array(allocator, Key, self.count);
usz index = 0;
foreach (Entry* entry : map.table)
foreach (Entry* entry : self.table)
{
while (entry)
{
@@ -330,53 +303,36 @@ fn Key[] HashMap.copy_keys(&map, Allocator allocator = allocator::heap())
macro HashMap.@each(map; @body(key, value))
{
map.@each_entry(; Entry* entry) {
map.@each_entry(; Entry* entry)
{
@body(entry.key, entry.value);
};
}
macro HashMap.@each_entry(map; @body(entry))
{
if (map.count)
if (!map.count) return;
foreach (Entry* entry : map.table)
{
foreach (Entry* entry : map.table)
while (entry)
{
while (entry)
{
@body(entry);
entry = entry.next;
}
@body(entry);
entry = entry.next;
}
}
}
<*
@deprecated `use tcopy_values`
*>
fn Value[] HashMap.value_tlist(&map)
fn Value[] HashMap.tvalues(&map)
{
return map.copy_values(allocator::temp()) @inline;
return map.values(tmem()) @inline;
}
fn Value[] HashMap.tcopy_values(&map)
fn Value[] HashMap.values(&self, Allocator allocator)
{
return map.copy_values(allocator::temp()) @inline;
}
<*
@deprecated `use copy_values`
*>
fn Value[] HashMap.value_new_list(&map, Allocator allocator = allocator::heap())
{
return map.copy_values(allocator);
}
fn Value[] HashMap.copy_values(&map, Allocator allocator = allocator::heap())
{
if (!map.count) return {};
Value[] list = allocator::alloc_array(allocator, Value, map.count);
if (!self.count) return {};
Value[] list = allocator::alloc_array(allocator, Value, self.count);
usz index = 0;
foreach (Entry* entry : map.table)
foreach (Entry* entry : self.table)
{
while (entry)
{
@@ -611,3 +567,14 @@ fn Key HashMapKeyIterator.get(&self, usz idx) @operator([])
fn usz HashMapValueIterator.len(self) @operator(len) => self.map.count;
fn usz HashMapKeyIterator.len(self) @operator(len) => self.map.count;
fn usz HashMapIterator.len(self) @operator(len) => self.map.count;
fn uint rehash(uint hash) @inline @private
{
hash ^= (hash >> 20) ^ (hash >> 12);
return hash ^ ((hash >> 7) ^ (hash >> 4));
}
macro uint index_for(uint hash, uint capacity) @private
{
return hash & (capacity - 1);
}

View File

@@ -1,7 +1,7 @@
// Copyright (c) 2021-2024 Christoffer Lerno. All rights reserved.
// Use of self source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::collections::linkedlist(<Type>);
module std::collections::linkedlist{Type};
const ELEMENT_IS_EQUATABLE = types::is_equatable_type(Type);
@@ -30,18 +30,9 @@ fn LinkedList* LinkedList.init(&self, Allocator allocator)
return self;
}
<*
@return "the initialized list"
*>
fn LinkedList* LinkedList.new_init(&self)
fn LinkedList* LinkedList.tinit(&self)
{
return self.init(allocator::heap()) @inline;
}
fn LinkedList* LinkedList.temp_init(&self)
{
return self.init(allocator::temp()) @inline;
return self.init(tmem()) @inline;
}
<*
@@ -54,7 +45,7 @@ macro void LinkedList.free_node(&self, Node* node) @private
macro Node* LinkedList.alloc_node(&self) @private
{
if (!self.allocator) self.allocator = allocator::heap();
if (!self.allocator) self.allocator = tmem();
return allocator::alloc(self.allocator, Node);
}

View File

@@ -1,7 +1,7 @@
// Copyright (c) 2021-2024 Christoffer Lerno. All rights reserved.
// Use of self source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::collections::list(<Type>);
module std::collections::list{Type};
import std::io, std::math, std::collections::list_common;
def ElementPredicate = fn bool(Type *type);
@@ -33,28 +33,15 @@ fn List* List.init(&self, Allocator allocator, usz initial_capacity = 16)
return self;
}
<*
@param initial_capacity "The initial capacity to reserve"
@param [&inout] allocator "The allocator to use, defaults to the heap allocator"
*>
fn List* List.new_init(&self, usz initial_capacity = 16, Allocator allocator = allocator::heap())
{
self.allocator = allocator;
self.size = 0;
self.capacity = 0;
self.entries = null;
self.reserve(initial_capacity);
return self;
}
<*
Initialize the list using the temp allocator.
@param initial_capacity "The initial capacity to reserve"
*>
fn List* List.temp_init(&self, usz initial_capacity = 16)
fn List* List.tinit(&self, usz initial_capacity = 16)
{
return self.init(allocator::temp(), initial_capacity) @inline;
return self.init(tmem(), initial_capacity) @inline;
}
<*
@@ -63,9 +50,9 @@ fn List* List.temp_init(&self, usz initial_capacity = 16)
@param [in] values `The values to initialize the list with.`
@require self.size == 0 "The List must be empty"
*>
fn List* List.new_init_with_array(&self, Type[] values, Allocator allocator = allocator::heap())
fn List* List.init_with_array(&self, Allocator allocator, Type[] values)
{
self.new_init(values.len, allocator) @inline;
self.init(allocator, values.len) @inline;
self.add_array(values) @inline;
return self;
}
@@ -76,9 +63,9 @@ fn List* List.new_init_with_array(&self, Type[] values, Allocator allocator = al
@param [in] values `The values to initialize the list with.`
@require self.size == 0 "The List must be empty"
*>
fn List* List.temp_init_with_array(&self, Type[] values)
fn List* List.tinit_with_array(&self, Type[] values)
{
self.temp_init(values.len) @inline;
self.tinit(values.len) @inline;
self.add_array(values) @inline;
return self;
}
@@ -86,7 +73,7 @@ fn List* List.temp_init_with_array(&self, Type[] values)
<*
@require self.capacity == 0 "The List must not be allocated"
*>
fn void List.init_wrapping_array(&self, Type[] types, Allocator allocator = allocator::heap())
fn void List.init_wrapping_array(&self, Allocator allocator, Type[] types)
{
self.allocator = allocator;
self.capacity = types.len;
@@ -114,16 +101,6 @@ fn usz! List.to_format(&self, Formatter* formatter) @dynamic
}
}
fn String List.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
{
return string::format("%s", *self, allocator: allocator);
}
fn String List.to_tstring(&self)
{
return string::tformat("%s", *self);
}
fn void List.push(&self, Type element) @inline
{
self.reserve(1);
@@ -174,25 +151,25 @@ fn void List.add_all(&self, List* other_list)
<*
IMPORTANT The returned array must be freed using free_aligned.
*>
fn Type[] List.to_new_aligned_array(&self, Allocator allocator = allocator::heap())
fn Type[] List.to_aligned_array(&self, Allocator allocator)
{
return list_common::list_to_new_aligned_array(Type, self, allocator);
return list_common::list_to_aligned_array(Type, self, allocator);
}
<*
@require !type_is_overaligned() : "This function is not available on overaligned types"
*>
macro Type[] List.to_new_array(&self, Allocator allocator = allocator::heap())
macro Type[] List.to_array(&self, Allocator allocator)
{
return list_common::list_to_new_array(Type, self, allocator);
return list_common::list_to_array(Type, self, allocator);
}
fn Type[] List.to_tarray(&self)
{
$if type_is_overaligned():
return self.to_new_aligned_array(allocator::temp());
return self.to_aligned_array(tmem());
$else
return self.to_new_array(allocator::temp());
return self.to_array(tmem());
$endif;
}
@@ -364,7 +341,7 @@ fn void List.ensure_capacity(&self, usz min_capacity) @local
{
if (!min_capacity) return;
if (self.capacity >= min_capacity) return;
if (!self.allocator) self.allocator = allocator::heap();
if (!self.allocator) self.allocator = tmem();
self.pre_free(); // Remove sanitizer annotation

View File

@@ -3,7 +3,7 @@ module std::collections::list_common;
<*
IMPORTANT The returned array must be freed using free_aligned.
*>
macro list_to_new_aligned_array($Type, self, Allocator allocator)
macro list_to_aligned_array($Type, self, Allocator allocator)
{
if (!self.size) return ($Type[]){};
$Type[] result = allocator::alloc_array_aligned(allocator, $Type, self.size);
@@ -11,7 +11,7 @@ macro list_to_new_aligned_array($Type, self, Allocator allocator)
return result;
}
macro list_to_new_array($Type, self, Allocator allocator)
macro list_to_array($Type, self, Allocator allocator)
{
if (!self.size) return ($Type[]){};
$Type[] result = allocator::alloc_array(allocator, $Type, self.size);

View File

@@ -1,508 +0,0 @@
// Copyright (c) 2023 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::collections::map(<Key, Value>);
import std::math;
const uint DEFAULT_INITIAL_CAPACITY = 16;
const uint MAXIMUM_CAPACITY = 1u << 31;
const float DEFAULT_LOAD_FACTOR = 0.75;
const VALUE_IS_EQUATABLE = Value.is_eq;
const bool COPY_KEYS = types::implements_copy(Key);
distinct Map = void*;
struct MapImpl
{
Entry*[] table;
Allocator allocator;
uint count; // Number of elements
uint threshold; // Resize limit
float load_factor;
}
<*
@require capacity > 0 "The capacity must be 1 or higher"
@require load_factor > 0.0 "The load factor must be higher than 0"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
fn Map new(uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
{
MapImpl* map = allocator::alloc(allocator, MapImpl);
_init(map, capacity, load_factor, allocator);
return (Map)map;
}
<*
@require capacity > 0 "The capacity must be 1 or higher"
@require load_factor > 0.0 "The load factor must be higher than 0"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
fn Map temp(uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
{
MapImpl* map = mem::temp_alloc(MapImpl);
_init(map, capacity, load_factor, allocator::temp());
return (Map)map;
}
<*
@param [&inout] allocator "The allocator to use"
@require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values"
@require capacity > 0 "The capacity must be 1 or higher"
@require load_factor > 0.0 "The load factor must be higher than 0"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
macro Map new_init_with_key_values(..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
{
Map map = new(capacity, load_factor, allocator);
$for (var $i = 0; $i < $vacount; $i += 2)
map.set($vaarg[$i], $vaarg[$i+1]);
$endfor
return map;
}
<*
@param [in] keys "Array of keys for the Map entries"
@param [in] values "Array of values for the Map entries"
@param [&inout] allocator "The allocator to use"
@require keys.len == values.len "Both keys and values arrays must be the same length"
@require capacity > 0 "The capacity must be 1 or higher"
@require load_factor > 0.0 "The load factor must be higher than 0"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
fn Map new_init_from_keys_and_values(Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
{
assert(keys.len == values.len);
Map map = new(capacity, load_factor, allocator);
for (usz i = 0; i < keys.len; i++)
{
map.set(keys[i], values[i]);
}
return map;
}
<*
@require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values"
@require capacity > 0 "The capacity must be 1 or higher"
@require load_factor > 0.0 "The load factor must be higher than 0"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
macro Map temp_new_with_key_values(..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
{
Map map = temp(capacity, load_factor);
$for (var $i = 0; $i < $vacount; $i += 2)
map.set($vaarg[$i], $vaarg[$i+1]);
$endfor
return map;
}
<*
@param [in] keys "The keys for the HashMap entries"
@param [in] values "The values for the HashMap entries"
@param [&inout] allocator "The allocator to use"
@require keys.len == values.len "Both keys and values arrays must be the same length"
@require capacity > 0 "The capacity must be 1 or higher"
@require load_factor > 0.0 "The load factor must be higher than 0"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
fn Map temp_init_from_keys_and_values(Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
{
assert(keys.len == values.len);
Map map = temp(capacity, load_factor);
for (usz i = 0; i < keys.len; i++)
{
map.set(keys[i], values[i]);
}
return map;
}
<*
@param [&in] other_map "The map to copy from."
*>
fn Map new_from_map(Map other_map, Allocator allocator = null)
{
MapImpl* other_map_impl = (MapImpl*)other_map;
if (!other_map_impl)
{
if (allocator) return new(allocator: allocator);
return null;
}
MapImpl* map = (MapImpl*)new(other_map_impl.table.len, other_map_impl.load_factor, allocator ?: allocator::heap());
if (!other_map_impl.count) return (Map)map;
foreach (Entry *e : other_map_impl.table)
{
while (e)
{
map._put_for_create(e.key, e.value);
e = e.next;
}
}
return (Map)map;
}
<*
@param [&in] other_map "The map to copy from."
*>
fn Map temp_from_map(Map other_map)
{
return new_from_map(other_map, allocator::temp());
}
fn bool Map.is_empty(map) @inline
{
return !map || !((MapImpl*)map).count;
}
fn usz Map.len(map) @inline
{
return map ? ((MapImpl*)map).count : 0;
}
fn Value*! Map.get_ref(self, Key key)
{
MapImpl *map = (MapImpl*)self;
if (!map || !map.count) return SearchResult.MISSING?;
uint hash = rehash(key.hash());
for (Entry *e = map.table[index_for(hash, map.table.len)]; e != null; e = e.next)
{
if (e.hash == hash && equals(key, e.key)) return &e.value;
}
return SearchResult.MISSING?;
}
fn Entry*! Map.get_entry(map, Key key)
{
MapImpl *map_impl = (MapImpl*)map;
if (!map_impl || !map_impl.count) return SearchResult.MISSING?;
uint hash = rehash(key.hash());
for (Entry *e = map_impl.table[index_for(hash, map_impl.table.len)]; e != null; e = e.next)
{
if (e.hash == hash && equals(key, e.key)) return e;
}
return SearchResult.MISSING?;
}
<*
Get the value or update and
@require $assignable(#expr, Value)
*>
macro Value Map.@get_or_set(&self, Key key, Value #expr)
{
MapImpl *map = (MapImpl*)*self;
if (!map || !map.count)
{
Value val = #expr;
map.set(key, val);
return val;
}
uint hash = rehash(key.hash());
uint index = index_for(hash, map.table.len);
for (Entry *e = map.table[index]; e != null; e = e.next)
{
if (e.hash == hash && equals(key, e.key)) return e.value;
}
Value val = #expr;
map.add_entry(hash, key, val, index);
return val;
}
fn Value! Map.get(map, Key key) @operator([])
{
return *map.get_ref(key) @inline;
}
fn bool Map.has_key(map, Key key)
{
return @ok(map.get_ref(key));
}
macro Value Map.set_value_return(&map, Key key, Value value) @operator([]=)
{
map.set(key, value);
return value;
}
fn bool Map.set(&self, Key key, Value value)
{
// If the map isn't initialized, use the defaults to initialize it.
if (!*self) *self = new();
MapImpl* map = (MapImpl*)*self;
uint hash = rehash(key.hash());
uint index = index_for(hash, map.table.len);
for (Entry *e = map.table[index]; e != null; e = e.next)
{
if (e.hash == hash && equals(key, e.key))
{
e.value = value;
return true;
}
}
map._add_entry(hash, key, value, index);
return false;
}
fn void! Map.remove(map, Key key) @maydiscard
{
if (!map || !((MapImpl*)map)._remove_entry_for_key(key)) return SearchResult.MISSING?;
}
fn void Map.clear(self)
{
MapImpl* map = (MapImpl*)self;
if (!map || !map.count) return;
foreach (Entry** &entry_ref : map.table)
{
Entry* entry = *entry_ref;
if (!entry) continue;
Entry *next = entry.next;
while (next)
{
Entry *to_delete = next;
next = next.next;
map._free_entry(to_delete);
}
map._free_entry(entry);
*entry_ref = null;
}
map.count = 0;
}
fn void Map.free(self)
{
if (!self) return;
MapImpl* map = (MapImpl*)self;
self.clear();
map._free_internal(map.table.ptr);
map.table = {};
allocator::free(map.allocator, map);
}
fn Key[] Map.temp_keys_list(map)
{
return map.new_keys_list(allocator::temp()) @inline;
}
fn Key[] Map.new_keys_list(self, Allocator allocator = allocator::heap())
{
MapImpl* map = (MapImpl*)self;
if (!map || !map.count) return {};
Key[] list = allocator::alloc_array(allocator, Key, map.count);
usz index = 0;
foreach (Entry* entry : map.table)
{
while (entry)
{
list[index++] = entry.key;
entry = entry.next;
}
}
return list;
}
macro Map.@each(map; @body(key, value))
{
map.@each_entry(; Entry* entry) {
@body(entry.key, entry.value);
};
}
macro Map.@each_entry(self; @body(entry))
{
MapImpl *map = (MapImpl*)self;
if (!map || !map.count) return;
foreach (Entry* entry : map.table)
{
while (entry)
{
@body(entry);
entry = entry.next;
}
}
}
fn Value[] Map.temp_values_list(map)
{
return map.new_values_list(allocator::temp()) @inline;
}
fn Value[] Map.new_values_list(self, Allocator allocator = allocator::heap())
{
MapImpl* map = (MapImpl*)self;
if (!map || !map.count) return {};
Value[] list = allocator::alloc_array(allocator, Value, map.count);
usz index = 0;
foreach (Entry* entry : map.table)
{
while (entry)
{
list[index++] = entry.value;
entry = entry.next;
}
}
return list;
}
fn bool Map.has_value(self, Value v) @if(VALUE_IS_EQUATABLE)
{
MapImpl* map = (MapImpl*)self;
if (!map || !map.count) return false;
foreach (Entry* entry : map.table)
{
while (entry)
{
if (equals(v, entry.value)) return true;
entry = entry.next;
}
}
return false;
}
// --- private methods
fn void MapImpl._add_entry(&map, uint hash, Key key, Value value, uint bucket_index) @private
{
$if COPY_KEYS:
key = key.copy(map.allocator);
$endif
Entry* entry = allocator::new(map.allocator, Entry, { .hash = hash, .key = key, .value = value, .next = map.table[bucket_index] });
map.table[bucket_index] = entry;
if (map.count++ >= map.threshold)
{
map._resize(map.table.len * 2);
}
}
fn void MapImpl._resize(&map, uint new_capacity) @private
{
Entry*[] old_table = map.table;
uint old_capacity = old_table.len;
if (old_capacity == MAXIMUM_CAPACITY)
{
map.threshold = uint.max;
return;
}
Entry*[] new_table = allocator::new_array(map.allocator, Entry*, new_capacity);
map._transfer(new_table);
map.table = new_table;
map._free_internal(old_table.ptr);
map.threshold = (uint)(new_capacity * map.load_factor);
}
fn uint rehash(uint hash) @inline @private
{
hash ^= (hash >> 20) ^ (hash >> 12);
return hash ^ ((hash >> 7) ^ (hash >> 4));
}
macro uint index_for(uint hash, uint capacity) @private
{
return hash & (capacity - 1);
}
fn void MapImpl._transfer(&map, Entry*[] new_table) @private
{
Entry*[] src = map.table;
uint new_capacity = new_table.len;
foreach (uint j, Entry *e : src)
{
if (!e) continue;
do
{
Entry* next = e.next;
uint i = index_for(e.hash, new_capacity);
e.next = new_table[i];
new_table[i] = e;
e = next;
}
while (e);
}
}
fn void _init(MapImpl* impl, uint capacity, float load_factor, Allocator allocator) @private
{
capacity = math::next_power_of_2(capacity);
*impl = {
.allocator = allocator,
.load_factor = load_factor,
.threshold = (uint)(capacity * load_factor),
.table = allocator::new_array(allocator, Entry*, capacity)
};
}
fn void MapImpl._put_for_create(&map, Key key, Value value) @private
{
uint hash = rehash(key.hash());
uint i = index_for(hash, map.table.len);
for (Entry *e = map.table[i]; e != null; e = e.next)
{
if (e.hash == hash && equals(key, e.key))
{
e.value = value;
return;
}
}
map._create_entry(hash, key, value, i);
}
fn void MapImpl._free_internal(&map, void* ptr) @inline @private
{
allocator::free(map.allocator, ptr);
}
fn bool MapImpl._remove_entry_for_key(&map, Key key) @private
{
if (!map.count) return false;
uint hash = rehash(key.hash());
uint i = index_for(hash, map.table.len);
Entry* prev = map.table[i];
Entry* e = prev;
while (e)
{
Entry *next = e.next;
if (e.hash == hash && equals(key, e.key))
{
map.count--;
if (prev == e)
{
map.table[i] = next;
}
else
{
prev.next = next;
}
map._free_entry(e);
return true;
}
prev = e;
e = next;
}
return false;
}
fn void MapImpl._create_entry(&map, uint hash, Key key, Value value, int bucket_index) @private
{
Entry *e = map.table[bucket_index];
$if COPY_KEYS:
key = key.copy(map.allocator);
$endif
Entry* entry = allocator::new(map.allocator, Entry, { .hash = hash, .key = key, .value = value, .next = map.table[bucket_index] });
map.table[bucket_index] = entry;
map.count++;
}
fn void MapImpl._free_entry(&self, Entry *entry) @local
{
$if COPY_KEYS:
allocator::free(self.allocator, entry.key);
$endif
self._free_internal(entry);
}
struct Entry
{
uint hash;
Key key;
Value value;
Entry* next;
}

View File

@@ -1,4 +1,4 @@
module std::collections::maybe(<Type>);
module std::collections::maybe{Type};
import std::io;
struct Maybe (Printable)

View File

@@ -50,7 +50,7 @@ fn usz! Object.to_format(&self, Formatter* formatter) @dynamic
usz n = formatter.printf("{")!;
@stack_mem(1024; Allocator mem)
{
foreach (i, key : self.map.copy_keys(mem))
foreach (i, key : self.map.keys(mem))
{
if (i > 0) n += formatter.printf(",")!;
n += formatter.printf(`"%s":`, key)!;
@@ -156,7 +156,7 @@ fn void Object.init_map_if_needed(&self) @private
if (self.is_empty())
{
self.type = ObjectInternalMap.typeid;
self.map.new_init(allocator: self.allocator);
self.map.tinit();
}
}
@@ -168,7 +168,7 @@ fn void Object.init_array_if_needed(&self) @private
if (self.is_empty())
{
self.type = ObjectInternalList.typeid;
self.array.new_init(allocator: self.allocator);
self.array.init(self.allocator);
}
}

View File

@@ -1,7 +1,7 @@
// priorityqueue.c3
// A priority queue using a classic binary heap for C3.
//
// Copyright (c) 2022 David Kopec
// Copyright (c) 2022-2025 David Kopec
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -20,35 +20,30 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
module std::collections::priorityqueue(<Type>);
module std::collections::priorityqueue{Type};
import std::collections::priorityqueue::private;
distinct PriorityQueue = inline PrivatePriorityQueue(<Type, false>);
distinct PriorityQueueMax = inline PrivatePriorityQueue(<Type, true>);
distinct PriorityQueue = inline List{Type};
distinct PriorityQueueMax = inline List{Type};
module std::collections::priorityqueue::private(<Type, MAX>);
module std::collections::priorityqueue::private{Type, MAX};
import std::collections::list, std::io;
def Heap = List(<Type>);
struct PrivatePriorityQueue (Printable)
{
Heap heap;
List{Type} heap;
}
fn void PrivatePriorityQueue.init(&self, Allocator allocator, usz initial_capacity = 16, ) @inline
fn PrivatePriorityQueue* PrivatePriorityQueue.init(&self, Allocator allocator, usz initial_capacity = 16, ) @inline
{
self.heap.new_init(initial_capacity, allocator);
self.heap.init(allocator, initial_capacity);
return self;
}
fn void PrivatePriorityQueue.new_init(&self, usz initial_capacity = 16, Allocator allocator = allocator::heap()) @inline
fn PrivatePriorityQueue* PrivatePriorityQueue.tinit(&self, usz initial_capacity = 16) @inline
{
self.heap.new_init(initial_capacity, allocator);
}
fn void PrivatePriorityQueue.temp_init(&self, usz initial_capacity = 16) @inline
{
self.heap.new_init(initial_capacity, allocator::temp()) @inline;
self.init(tmem(), initial_capacity);
return self;
}
@@ -72,11 +67,14 @@ fn void PrivatePriorityQueue.push(&self, Type element)
}
}
<*
@require index < self.len : "Index out of range"
*>
fn void PrivatePriorityQueue.remove_at(&self, usz index)
{
if (index == 0)
{
self.pop()!!;
self.heap.remove_last();
return;
}
self.heap.remove_at(index);
@@ -124,8 +122,7 @@ fn Type! PrivatePriorityQueue.pop(&self)
fn Type! PrivatePriorityQueue.first(&self)
{
if (!self.len()) return IteratorResult.NO_MORE_ELEMENT?;
return self.heap.get(0);
return self.heap.first();
}
fn void PrivatePriorityQueue.free(&self)
@@ -135,12 +132,12 @@ fn void PrivatePriorityQueue.free(&self)
fn usz PrivatePriorityQueue.len(&self) @operator(len)
{
return self.heap.len();
return self.heap.len() @inline;
}
fn bool PrivatePriorityQueue.is_empty(&self)
{
return self.heap.is_empty();
return self.heap.is_empty() @inline;
}
<*
@@ -156,8 +153,3 @@ fn usz! PrivatePriorityQueue.to_format(&self, Formatter* formatter) @dynamic
return self.heap.to_format(formatter);
}
fn String PrivatePriorityQueue.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
{
return self.heap.to_new_string(allocator);
}

View File

@@ -1,7 +1,7 @@
<*
@require Type.is_ordered : "The type must be ordered"
*>
module std::collections::range(<Type>);
module std::collections::range{Type};
import std::io;
struct Range (Printable)
@@ -29,21 +29,6 @@ fn Type Range.get(&self, usz index) @operator([])
return (Type)(self.start + (usz)index);
}
fn String Range.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic @deprecated
{
return string::format("[%s..%s]", self.start, self.end, allocator: allocator);
}
fn String Range.to_string(&self, Allocator allocator) @dynamic
{
return string::format("[%s..%s]", self.start, self.end, allocator: allocator);
}
fn String Range.to_tstring(&self)
{
return self.to_string(allocator::temp());
}
fn usz! Range.to_format(&self, Formatter* formatter) @dynamic
{
return formatter.printf("[%s..%s]", self.start, self.end)!;
@@ -71,21 +56,6 @@ fn usz! ExclusiveRange.to_format(&self, Formatter* formatter) @dynamic
return formatter.printf("[%s..<%s]", self.start, self.end)!;
}
fn String ExclusiveRange.to_new_string(&self, Allocator allocator = null) @dynamic
{
return self.to_string(allocator ?: allocator::heap());
}
fn String ExclusiveRange.to_string(&self, Allocator allocator) @dynamic
{
return string::format("[%s..<%s]", self.start, self.end, allocator: allocator);
}
fn String ExclusiveRange.to_tstring(&self)
{
return self.to_new_string(allocator::temp());
}
<*
@require index < self.len() : "Can't index into an empty range"
*>

View File

@@ -1,11 +1,13 @@
<*
@require values::@is_int(SIZE) &&& SIZE > 0 "The size must be positive integer"
@require Type.kindof == ARRAY : "Required an array type"
*>
module std::collections::ringbuffer(<Type, SIZE>);
module std::collections::ringbuffer(<Type>);
def Element = $typeof((Type){}[0]);
struct RingBuffer
{
Type[SIZE] buf;
Type buf;
usz written;
usz head;
}
@@ -15,9 +17,9 @@ fn void RingBuffer.init(&self) @inline
*self = {};
}
fn void RingBuffer.push(&self, Type c)
fn void RingBuffer.push(&self, Element c)
{
if (self.written < SIZE)
if (self.written < buf.len)
{
self.buf[self.written] = c;
self.written++;
@@ -25,14 +27,14 @@ fn void RingBuffer.push(&self, Type c)
else
{
self.buf[self.head] = c;
self.head = (self.head + 1) % SIZE;
self.head = (self.head + 1) % buf.len;
}
}
fn Type RingBuffer.get(&self, usz index) @operator([])
fn Element RingBuffer.get(&self, usz index) @operator([])
{
index %= SIZE;
usz avail = SIZE - self.head;
index %= buf.len;
usz avail = buf.len - self.head;
if (index < avail)
{
return self.buf[self.head + index];
@@ -40,25 +42,31 @@ fn Type RingBuffer.get(&self, usz index) @operator([])
return self.buf[index - avail];
}
fn Type! RingBuffer.pop(&self)
fn Element! RingBuffer.pop(&self)
{
switch
{
case self.written == 0:
return SearchResult.MISSING?;
case self.written < SIZE:
case self.written < buf.len:
self.written--;
return self.buf[self.written];
default:
self.head = (self.head - 1) % SIZE;
self.head = (self.head - 1) % buf.len;
return self.buf[self.head];
}
}
fn usz RingBuffer.read(&self, usz index, Type[] buffer)
fn usz! RingBuffer.to_format(&self, Formatter* format)
{
index %= SIZE;
if (self.written < SIZE)
// Improve this?
return format.printnf("%s", self.buf);
}
fn usz RingBuffer.read(&self, usz index, Element[] buffer)
{
index %= buf.len;
if (self.written < buf.len)
{
if (index >= self.written) return 0;
usz end = self.written - index;
@@ -66,7 +74,7 @@ fn usz RingBuffer.read(&self, usz index, Type[] buffer)
buffer[:n] = self.buf[index:n];
return n;
}
usz end = SIZE - self.head;
usz end = buf.len - self.head;
if (index >= end)
{
index -= end;
@@ -75,13 +83,13 @@ fn usz RingBuffer.read(&self, usz index, Type[] buffer)
buffer[:n] = self.buf[index:n];
return n;
}
if (buffer.len <= SIZE - index)
if (buffer.len <= buf.len - index)
{
usz n = buffer.len;
buffer[:n] = self.buf[self.head + index:n];
return n;
}
usz n1 = SIZE - index;
usz n1 = buf.len - index;
buffer[:n1] = self.buf[self.head + index:n1];
buffer = buffer[n1..];
index -= n1;
@@ -90,10 +98,10 @@ fn usz RingBuffer.read(&self, usz index, Type[] buffer)
return n1 + n2;
}
fn void RingBuffer.write(&self, Type[] buffer)
fn void RingBuffer.write(&self, Element[] buffer)
{
usz i;
while (self.written < SIZE && i < buffer.len)
while (self.written < buf.len && i < buffer.len)
{
self.buf[self.written] = buffer[i++];
self.written++;
@@ -101,6 +109,6 @@ fn void RingBuffer.write(&self, Type[] buffer)
foreach (c : buffer[i..])
{
self.buf[self.head] = c;
self.head = (self.head + 1) % SIZE;
self.head = (self.head + 1) % buf.len;
}
}

View File

@@ -1,4 +1,4 @@
module std::collections::tuple(<Type1, Type2>);
module std::collections::tuple{Type1, Type2};
struct Tuple
{
@@ -6,7 +6,7 @@ struct Tuple
Type2 second;
}
module std::collections::triple(<Type1, Type2, Type3>);
module std::collections::triple{Type1, Type2, Type3};
struct Triple
{

View File

@@ -34,7 +34,7 @@ struct TrackingAllocator (Allocator)
fn void TrackingAllocator.init(&self, Allocator allocator)
{
*self = { .inner_allocator = allocator };
self.map.new_init(allocator: allocator);
self.map.init(allocator);
}
<*
@@ -52,7 +52,7 @@ fn void TrackingAllocator.free(&self)
fn usz TrackingAllocator.allocated(&self) => @pool()
{
usz allocated = 0;
foreach (&allocation : self.map.value_tlist()) allocated += allocation.size;
foreach (&allocation : self.map.tvalues()) allocated += allocation.size;
return allocated;
}
@@ -68,7 +68,7 @@ fn usz TrackingAllocator.total_allocation_count(&self) => self.allocs_total;
fn Allocation[] TrackingAllocator.allocations_tlist(&self, Allocator allocator)
{
return self.map.value_tlist();
return self.map.tvalues();
}
<*
@@ -127,7 +127,7 @@ fn void! TrackingAllocator.fprint_report(&self, OutStream out) => @pool()
usz entries = 0;
bool leaks = false;
Allocation[] allocs = self.map.value_tlist();
Allocation[] allocs = self.map.tvalues();
if (allocs.len)
{
if (!allocs[0].backtrace[0])
@@ -155,7 +155,7 @@ fn void! TrackingAllocator.fprint_report(&self, OutStream out) => @pool()
Backtrace trace = backtrace::BACKTRACE_UNKNOWN;
if (allocation.backtrace[3])
{
trace = backtrace::symbolize_backtrace(allocation.backtrace[3:1], allocator::temp()).get(0) ?? backtrace::BACKTRACE_UNKNOWN;
trace = backtrace::symbolize_backtrace(tmem(), allocation.backtrace[3:1]).get(0) ?? backtrace::BACKTRACE_UNKNOWN;
}
if (trace.function.len) leaks = true;
io::fprintfn(out, "%13s %p %s:%d", allocation.size,
@@ -194,7 +194,7 @@ fn void! TrackingAllocator.fprint_report(&self, OutStream out) => @pool()
break;
}
}
BacktraceList list = backtrace::symbolize_backtrace(allocation.backtrace[3..(end - 1)], allocator::temp())!;
BacktraceList list = backtrace::symbolize_backtrace(tmem(), allocation.backtrace[3..(end - 1)])!;
io::fprintfn(out, "Allocation %d (%d bytes): ", i + 1, allocation.size)!;
foreach (trace : list)
{

View File

@@ -67,7 +67,7 @@ fn bool print_backtrace(String message, int backtraces_to_ignore) @if(env::NATIV
void*[256] buffer;
void*[] backtraces = backtrace::capture_current(&buffer);
backtraces_to_ignore++;
BacktraceList! backtrace = backtrace::symbolize_backtrace(backtraces, allocator::temp());
BacktraceList! backtrace = backtrace::symbolize_backtrace(allocator::temp(), backtraces);
if (catch backtrace) return false;
if (backtrace.len() <= backtraces_to_ignore) return false;
io::eprint("\nERROR: '");

View File

@@ -401,6 +401,15 @@ macro TempAllocator* temp()
return thread_temp_allocator;
}
macro TempAllocator* tmem() @builtin
{
if (!thread_temp_allocator)
{
init_default_temp_allocators();
}
return thread_temp_allocator;
}
fn void init_default_temp_allocators() @private
{
temp_allocator_pair[0] = create_default_sized_temp_allocator(temp_base_allocator);

View File

@@ -6,8 +6,7 @@ const int PRINTF_NTOA_BUFFER_SIZE = 256;
interface Printable
{
fn String to_string(Allocator allocator) @optional;
fn String to_new_string(Allocator allocator) @optional @deprecated("Use to_string");
fn String to_constant_string() @optional;
fn usz! to_format(Formatter* formatter) @optional;
}
@@ -125,7 +124,7 @@ fn usz! Formatter.print_with_function(&self, Printable arg)
if (!arg) return self.out_substr("(null)");
return arg.to_format(self);
}
if (&arg.to_string)
if (&arg.to_constant_string)
{
PrintFlags old = self.flags;
uint old_width = self.width;
@@ -137,10 +136,7 @@ fn usz! Formatter.print_with_function(&self, Printable arg)
self.prec = old_prec;
}
if (!arg) return self.out_substr("(null)");
@stack_mem(1024; Allocator mem)
{
return self.out_substr(arg.to_string(mem));
};
return self.out_substr(arg.to_constant_string());
}
return SearchResult.MISSING?;
}

View File

@@ -4,7 +4,7 @@ import std::io, std::os;
fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator allocator)
{
PathList list;
list.new_init(allocator: allocator);
list.init(allocator);
DIRPtr directory = posix::opendir(dir.str_view() ? dir.as_zstr() : (ZString)".");
defer if (directory) posix::closedir(directory);
if (!directory) return (path::is_dir(dir) ? IoError.CANNOT_READ_DIR : IoError.FILE_NOT_DIR)?;

View File

@@ -275,7 +275,7 @@ fn UrlQueryValues parse_query(String query, Allocator allocator)
{
UrlQueryValues vals;
vals.map.init(allocator);
vals.key_order.new_init(allocator: allocator);
vals.key_order.init(allocator);
Splitter raw_vals = query.tokenize("&");
while (try String rv = raw_vals.next())
@@ -309,7 +309,7 @@ fn UrlQueryValues* UrlQueryValues.add(&self, String key, String value)
else
{
UrlQueryValueList new_list;
new_list.new_init_with_array({ value_copy }, self.allocator);
new_list.init_with_array(self.allocator, { value_copy });
(*self)[key] = new_list;
self.key_order.push(key.copy(self.allocator));
}

View File

@@ -132,11 +132,11 @@ fn Backtrace! backtrace_load_element(String execpath, void* buffer, void* load_a
};
}
fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator allocator)
fn BacktraceList! symbolize_backtrace(Allocator allocator, void*[] backtrace)
{
void *load_addr = (void *)load_address()!;
BacktraceList list;
list.new_init(backtrace.len, allocator);
list.init(allocator, backtrace.len);
defer catch
{
foreach (trace : list)

View File

@@ -2149,7 +2149,7 @@ ParseRule rules[TOKEN_EOF + 1] = {
[TOKEN_CT_TYPEOF] = { parse_type_expr, NULL, PREC_NONE },
[TOKEN_CT_STRINGIFY] = { parse_ct_stringify, NULL, PREC_NONE },
[TOKEN_CT_EVALTYPE] = { parse_type_expr, NULL, PREC_NONE },
[TOKEN_LBRACE] = { parse_initializer_list, parse_generic_expr, PREC_NONE },
[TOKEN_LBRACE] = { parse_initializer_list, parse_generic_expr, PREC_PRIMARY },
[TOKEN_CT_VACOUNT] = { parse_ct_arg, NULL, PREC_NONE },
[TOKEN_CT_VAARG] = { parse_ct_arg, NULL, PREC_NONE },
[TOKEN_CT_VAREF] = { parse_ct_arg, NULL, PREC_NONE },

View File

@@ -18,14 +18,6 @@ static Ast *parse_decl_stmt_after_type(ParseContext *c, TypeInfo *type)
Decl *decl = ast->declare_stmt;
switch (c->tok)
{
case TOKEN_LBRACE:
if (decl->var.init_expr && decl->var.init_expr->expr_kind == EXPR_UNRESOLVED_IDENTIFIER)
{
print_error_at(decl->var.init_expr->span,
"An identifier would not usually be followed by a '{'. Did you intend write the name of a type here?");
return poisoned_ast;
}
break;
case TOKEN_LBRACKET:
if (!decl->var.init_expr)
{