- Warn on use of visibility modifiers on methods. #2962

This commit is contained in:
Christoffer Lerno
2026-02-21 21:10:08 +01:00
parent e1ec4b1235
commit dc52478c09
49 changed files with 907 additions and 890 deletions

View File

@@ -150,7 +150,7 @@ fn bool HashMap.is_initialized(&map)
fn HashMap* HashMap.init_from_map(&self, Allocator allocator, HashMap* other_map) fn HashMap* HashMap.init_from_map(&self, Allocator allocator, HashMap* other_map)
{ {
self.init(allocator, other_map.table.len, other_map.load_factor); self.init(allocator, other_map.table.len, other_map.load_factor);
self.put_all_for_create(other_map); hashmap_put_all_for_create(self, other_map);
return self; return self;
} }
@@ -233,7 +233,7 @@ macro Value HashMap.@get_or_set(&map, Key key, Value #expr)
if (e.hash == hash && equals(key, e.key)) return e.value; if (e.hash == hash && equals(key, e.key)) return e.value;
} }
Value val = #expr; Value val = #expr;
map.add_entry(hash, key, val, index); hashmap_add_entry(map, hash, key, val, index);
return val; return val;
} }
@@ -269,13 +269,13 @@ fn bool HashMap.set(&map, Key key, Value value) @operator([]=)
return true; return true;
} }
} }
map.add_entry(hash, key, value, index); hashmap_add_entry(map, hash, key, value, index);
return false; return false;
} }
fn void? HashMap.remove(&map, Key key) @maydiscard fn void? HashMap.remove(&map, Key key) @maydiscard
{ {
if (!map.remove_entry_for_key(key)) return NOT_FOUND~; if (!hashmap_remove_entry_for_key(map, key)) return NOT_FOUND~;
} }
fn void HashMap.clear(&map) fn void HashMap.clear(&map)
@@ -290,9 +290,9 @@ fn void HashMap.clear(&map)
{ {
Entry *to_delete = next; Entry *to_delete = next;
next = next.next; next = next.next;
map.free_entry(to_delete); hashmap_free_entry(map, to_delete);
} }
map.free_entry(entry); hashmap_free_entry(map, entry);
*entry_ref = null; *entry_ref = null;
} }
map.count = 0; map.count = 0;
@@ -302,7 +302,7 @@ fn void HashMap.free(&map)
{ {
if (!map.is_initialized()) return; if (!map.is_initialized()) return;
map.clear(); map.clear();
map.free_internal(map.table.ptr); hashmap_free_internal(map, map.table.ptr);
map.table = {}; map.table = {};
} }
@@ -402,7 +402,7 @@ fn HashMapKeyIterator HashMap.key_iter(&self)
// --- private methods // --- private methods
fn void HashMap.add_entry(&map, uint hash, Key key, Value value, uint bucket_index) @private fn void hashmap_add_entry(HashMap* map, uint hash, Key key, Value value, uint bucket_index) @private
{ {
$if COPY_KEYS: $if COPY_KEYS:
key = key.copy(map.allocator); key = key.copy(map.allocator);
@@ -411,11 +411,11 @@ fn void HashMap.add_entry(&map, uint hash, Key key, Value value, uint bucket_ind
map.table[bucket_index] = entry; map.table[bucket_index] = entry;
if (map.count++ >= map.threshold) if (map.count++ >= map.threshold)
{ {
map.resize(map.table.len * 2); hashmap_resize(map, map.table.len * 2);
} }
} }
fn void HashMap.resize(&map, uint new_capacity) @private fn void hashmap_resize(HashMap* map, uint new_capacity) @private
{ {
Entry*[] old_table = map.table; Entry*[] old_table = map.table;
uint old_capacity = old_table.len; uint old_capacity = old_table.len;
@@ -425,9 +425,9 @@ fn void HashMap.resize(&map, uint new_capacity) @private
return; return;
} }
Entry*[] new_table = allocator::new_array(map.allocator, Entry*, new_capacity); Entry*[] new_table = allocator::new_array(map.allocator, Entry*, new_capacity);
map.transfer(new_table); hashmap_transfer(map, new_table);
map.table = new_table; map.table = new_table;
map.free_internal(old_table.ptr); hashmap_free_internal(map, old_table.ptr);
map.threshold = (uint)(new_capacity * map.load_factor); map.threshold = (uint)(new_capacity * map.load_factor);
} }
@@ -443,7 +443,7 @@ fn usz? HashMap.to_format(&self, Formatter* f) @dynamic
return len + f.print(" }"); return len + f.print(" }");
} }
fn void HashMap.transfer(&map, Entry*[] new_table) @private fn void hashmap_transfer(HashMap* map, Entry*[] new_table) @private
{ {
Entry*[] src = map.table; Entry*[] src = map.table;
uint new_capacity = new_table.len; uint new_capacity = new_table.len;
@@ -462,20 +462,20 @@ fn void HashMap.transfer(&map, Entry*[] new_table) @private
} }
} }
fn void HashMap.put_all_for_create(&map, HashMap* other_map) @private fn void hashmap_put_all_for_create(HashMap* map, HashMap* other_map) @private
{ {
if (!other_map.count) return; if (!other_map.count) return;
foreach (Entry *e : other_map.table) foreach (Entry *e : other_map.table)
{ {
while (e) while (e)
{ {
map.put_for_create(e.key, e.value); hashmap_put_for_create(map, e.key, e.value);
e = e.next; e = e.next;
} }
} }
} }
fn void HashMap.put_for_create(&map, Key key, Value value) @private fn void hashmap_put_for_create(HashMap* map, Key key, Value value) @private
{ {
uint hash = rehash(key.hash()); uint hash = rehash(key.hash());
uint i = index_for(hash, map.table.len); uint i = index_for(hash, map.table.len);
@@ -487,15 +487,15 @@ fn void HashMap.put_for_create(&map, Key key, Value value) @private
return; return;
} }
} }
map.create_entry(hash, key, value, i); hashmap_create_entry(map, hash, key, value, i);
} }
fn void HashMap.free_internal(&map, void* ptr) @inline @private fn void hashmap_free_internal(HashMap* map, void* ptr) @inline @private
{ {
allocator::free(map.allocator, ptr); allocator::free(map.allocator, ptr);
} }
fn bool HashMap.remove_entry_for_key(&map, Key key) @private fn bool hashmap_remove_entry_for_key(HashMap* map, Key key) @private
{ {
if (!map.count) return false; if (!map.count) return false;
uint hash = rehash(key.hash()); uint hash = rehash(key.hash());
@@ -516,7 +516,7 @@ fn bool HashMap.remove_entry_for_key(&map, Key key) @private
{ {
prev.next = next; prev.next = next;
} }
map.free_entry(e); hashmap_free_entry(map, e);
return true; return true;
} }
prev = e; prev = e;
@@ -525,7 +525,7 @@ fn bool HashMap.remove_entry_for_key(&map, Key key) @private
return false; return false;
} }
fn void HashMap.create_entry(&map, uint hash, Key key, Value value, int bucket_index) @private fn void hashmap_create_entry(HashMap* map, uint hash, Key key, Value value, int bucket_index) @private
{ {
Entry *e = map.table[bucket_index]; Entry *e = map.table[bucket_index];
$if COPY_KEYS: $if COPY_KEYS:
@@ -536,12 +536,12 @@ fn void HashMap.create_entry(&map, uint hash, Key key, Value value, int bucket_i
map.count++; map.count++;
} }
fn void HashMap.free_entry(&self, Entry *entry) @local fn void hashmap_free_entry(HashMap* map, Entry *entry) @local
{ {
$if COPY_KEYS: $if COPY_KEYS:
allocator::free(self.allocator, entry.key); allocator::free(map.allocator, entry.key);
$endif $endif
self.free_internal(entry); hashmap_free_internal(map, entry);
} }

View File

@@ -135,7 +135,7 @@ fn bool HashSet.is_initialized(&set)
fn HashSet* HashSet.init_from_set(&self, Allocator allocator, HashSet* other_set) fn HashSet* HashSet.init_from_set(&self, Allocator allocator, HashSet* other_set)
{ {
self.init(allocator, other_set.table.len, other_set.load_factor); self.init(allocator, other_set.table.len, other_set.load_factor);
self.put_all_for_create(other_set); hashset_put_all_for_create(self, other_set);
return self; return self;
} }
@@ -213,7 +213,7 @@ fn bool HashSet.add(&set, Value value)
{ {
if (e.hash == hash && equals(value, e.value)) return false; if (e.hash == hash && equals(value, e.value)) return false;
} }
set.add_entry(hash, value, index); hashset_add_entry(set, hash, value, index);
return true; return true;
} }
@@ -258,7 +258,7 @@ fn bool HashSet.contains(&set, Value value)
*> *>
fn void? HashSet.remove(&set, Value value) @maydiscard fn void? HashSet.remove(&set, Value value) @maydiscard
{ {
if (!set.remove_entry_for_value(value)) return NOT_FOUND~; if (!hashset_remove_entry_for_value(set, value)) return NOT_FOUND~;
} }
fn usz HashSet.remove_all(&set, Value[] values) fn usz HashSet.remove_all(&set, Value[] values)
@@ -266,7 +266,7 @@ fn usz HashSet.remove_all(&set, Value[] values)
usz total; usz total;
foreach (v : values) foreach (v : values)
{ {
if (set.remove_entry_for_value(v)) total++; if (hashset_remove_entry_for_value(set, v)) total++;
} }
return total; return total;
} }
@@ -279,7 +279,7 @@ fn usz HashSet.remove_all_from(&set, HashSet* other)
usz total; usz total;
other.@each(;Value val) other.@each(;Value val)
{ {
if (set.remove_entry_for_value(val)) total++; if (hashset_remove_entry_for_value(set, val)) total++;
}; };
return total; return total;
} }
@@ -291,7 +291,7 @@ fn void HashSet.free(&set)
{ {
if (!set.is_initialized()) return; if (!set.is_initialized()) return;
set.clear(); set.clear();
set.free_internal(set.table.ptr); hashset_free_internal(set, set.table.ptr);
*set = {}; *set = {};
} }
@@ -314,10 +314,10 @@ fn void HashSet.clear(&set)
{ {
Entry *to_delete = next; Entry *to_delete = next;
next = next.next; next = next.next;
set.free_entry(to_delete); hashset_free_entry(set, to_delete);
} }
set.free_entry(entry); hashset_free_entry(set, entry);
*entry_ref = null; *entry_ref = null;
} }
set.count = 0; set.count = 0;
@@ -327,7 +327,7 @@ fn void HashSet.reserve(&set, usz capacity)
{ {
if (capacity > set.threshold) if (capacity > set.threshold)
{ {
set.resize(math::next_power_of_2(capacity)); hashset_resize(set, math::next_power_of_2(capacity));
} }
} }
@@ -464,17 +464,17 @@ fn bool HashSet.is_subset(&self, HashSet* other)
// --- private methods // --- private methods
fn void HashSet.add_entry(&set, uint hash, Value value, uint bucket_index) @private fn void hashset_add_entry(HashSet* set, uint hash, Value value, uint bucket_index) @private
{ {
Entry* entry = allocator::new(set.allocator, Entry, { .hash = hash, .value = value, .next = set.table[bucket_index] }); Entry* entry = allocator::new(set.allocator, Entry, { .hash = hash, .value = value, .next = set.table[bucket_index] });
set.table[bucket_index] = entry; set.table[bucket_index] = entry;
if (set.count++ >= set.threshold) if (set.count++ >= set.threshold)
{ {
set.resize(set.table.len * 2); hashset_resize(set, set.table.len * 2);
} }
} }
fn void HashSet.resize(&self, usz new_capacity) @private fn void hashset_resize(HashSet* self, usz new_capacity) @private
{ {
Entry*[] old_table = self.table; Entry*[] old_table = self.table;
usz old_capacity = old_table.len; usz old_capacity = old_table.len;
@@ -484,9 +484,9 @@ fn void HashSet.resize(&self, usz new_capacity) @private
return; return;
} }
Entry*[] new_table = allocator::new_array(self.allocator, Entry*, new_capacity); Entry*[] new_table = allocator::new_array(self.allocator, Entry*, new_capacity);
self.transfer(new_table); hashset_transfer(self, new_table);
self.table = new_table; self.table = new_table;
self.free_internal(old_table.ptr); hashset_free_internal(self, old_table.ptr);
self.threshold = (uint)(new_capacity * self.load_factor); self.threshold = (uint)(new_capacity * self.load_factor);
} }
@@ -502,7 +502,7 @@ fn usz? HashSet.to_format(&self, Formatter* f) @dynamic
return len + f.print(" }"); return len + f.print(" }");
} }
fn void HashSet.transfer(&self, Entry*[] new_table) @private fn void hashset_transfer(HashSet* self, Entry*[] new_table) @private
{ {
Entry*[] src = self.table; Entry*[] src = self.table;
uint new_capacity = new_table.len; uint new_capacity = new_table.len;
@@ -521,20 +521,20 @@ fn void HashSet.transfer(&self, Entry*[] new_table) @private
} }
} }
fn void HashSet.put_all_for_create(&set, HashSet* other_set) @private fn void hashset_put_all_for_create(HashSet* set, HashSet* other_set) @private
{ {
if (!other_set.count) return; if (!other_set.count) return;
foreach (Entry *e : other_set.table) foreach (Entry *e : other_set.table)
{ {
while (e) while (e)
{ {
set.put_for_create(e.value); hashset_put_for_create(set, e.value);
e = e.next; e = e.next;
} }
} }
} }
fn void HashSet.put_for_create(&set, Value value) @private fn void hashset_put_for_create(HashSet* set, Value value) @private
{ {
uint hash = rehash(value.hash()); uint hash = rehash(value.hash());
uint i = index_for(hash, set.table.len); uint i = index_for(hash, set.table.len);
@@ -546,15 +546,15 @@ fn void HashSet.put_for_create(&set, Value value) @private
return; return;
} }
} }
set.create_entry(hash, value, i); hashset_create_entry(set, hash, value, i);
} }
fn void HashSet.free_internal(&self, void* ptr) @inline @private fn void hashset_free_internal(HashSet* self, void* ptr) @inline @private
{ {
allocator::free(self.allocator, ptr); allocator::free(self.allocator, ptr);
} }
fn void HashSet.create_entry(&set, uint hash, Value value, int bucket_index) @private fn void hashset_create_entry(HashSet* set, uint hash, Value value, int bucket_index) @private
{ {
Entry* entry = allocator::new(set.allocator, Entry, { Entry* entry = allocator::new(set.allocator, Entry, {
.hash = hash, .hash = hash,
@@ -569,7 +569,7 @@ fn void HashSet.create_entry(&set, uint hash, Value value, int bucket_index) @pr
Removes the entry for the specified value if present Removes the entry for the specified value if present
@return "true if found and removed, false otherwise" @return "true if found and removed, false otherwise"
*> *>
fn bool HashSet.remove_entry_for_value(&set, Value value) @private fn bool hashset_remove_entry_for_value(HashSet* set, Value value) @private
{ {
if (!set.count) return false; if (!set.count) return false;
uint hash = rehash(value.hash()); uint hash = rehash(value.hash());
@@ -590,7 +590,7 @@ fn bool HashSet.remove_entry_for_value(&set, Value value) @private
{ {
prev.next = next; prev.next = next;
} }
set.free_entry(e); hashset_free_entry(set, e);
return true; return true;
} }
prev = e; prev = e;
@@ -600,7 +600,7 @@ fn bool HashSet.remove_entry_for_value(&set, Value value) @private
return false; return false;
} }
fn void HashSet.free_entry(&set, Entry *entry) @private fn void hashset_free_entry(HashSet* set, Entry *entry) @private
{ {
allocator::free(set.allocator, entry); allocator::free(set.allocator, entry);
} }

View File

@@ -73,7 +73,7 @@ fn bool InterfaceList.is_initialized(&self) @inline => self.allocator != null;
macro void InterfaceList.push(&self, element) macro void InterfaceList.push(&self, element)
{ {
if (!self.allocator) self.allocator = tmem; if (!self.allocator) self.allocator = tmem;
self._append(allocator::clone(self.allocator, element)); interfacelist_append(self, allocator::clone(self.allocator, element));
} }
<* <*
@@ -381,7 +381,7 @@ fn usz? InterfaceList.to_format(&self, Formatter* formatter) @dynamic
*> *>
fn usz InterfaceList.remove_if(&self, InterfacePredicate filter) fn usz InterfaceList.remove_if(&self, InterfacePredicate filter)
{ {
return self._remove_if(filter, false); return interfacelist_remove_if(self, filter, false);
} }
<* <*
@@ -392,7 +392,7 @@ fn usz InterfaceList.remove_if(&self, InterfacePredicate filter)
*> *>
fn usz InterfaceList.retain_if(&self, InterfacePredicate selection) fn usz InterfaceList.retain_if(&self, InterfacePredicate selection)
{ {
return self._remove_if(selection, true); return interfacelist_remove_if(self, selection, true);
} }
<* <*
@@ -404,7 +404,7 @@ fn usz InterfaceList.retain_if(&self, InterfacePredicate selection)
*> *>
fn usz InterfaceList.remove_using_test(&self, InterfaceTest filter, Type context) fn usz InterfaceList.remove_using_test(&self, InterfaceTest filter, Type context)
{ {
return self._remove_using_test(filter, false, context); return interfacelist_remove_using_test(self, filter, false, context);
} }
<* <*
@@ -416,7 +416,7 @@ fn usz InterfaceList.remove_using_test(&self, InterfaceTest filter, Type context
*> *>
fn usz InterfaceList.retain_using_test(&self, InterfaceTest selection, Type context) fn usz InterfaceList.retain_using_test(&self, InterfaceTest selection, Type context)
{ {
return self._remove_using_test(selection, true, context); return interfacelist_remove_using_test(self, selection, true, context);
} }
<* <*
@@ -455,7 +455,7 @@ macro void InterfaceList.set(&self, usz index, value)
// -- private // -- private
fn void InterfaceList.ensure_capacity(&self, usz added = 1) @inline @private fn void interfacelist_ensure_capacity(InterfaceList* self, usz added = 1) @inline @private
{ {
usz new_size = self.size + added; usz new_size = self.size + added;
if (self.capacity >= new_size) return; if (self.capacity >= new_size) return;
@@ -466,18 +466,18 @@ fn void InterfaceList.ensure_capacity(&self, usz added = 1) @inline @private
self.reserve(new_capacity); self.reserve(new_capacity);
} }
fn void InterfaceList._append(&self, Type element) @local fn void interfacelist_append(InterfaceList* self, Type element) @local
{ {
self.ensure_capacity(); interfacelist_ensure_capacity(self);
self.entries[self.size++] = element; self.entries[self.size++] = element;
} }
<* <*
@require index < self.size @require index < self.size
*> *>
fn void InterfaceList._insert_at(&self, usz index, Type value) @local fn void interfacelist_insert_at(InterfaceList* self, usz index, Type value) @local
{ {
self.ensure_capacity(); interfacelist_ensure_capacity(self);
for (usz i = self.size; i > index; i--) for (usz i = self.size; i > index; i--)
{ {
self.entries[i] = self.entries[i - 1]; self.entries[i] = self.entries[i - 1];
@@ -486,7 +486,7 @@ fn void InterfaceList._insert_at(&self, usz index, Type value) @local
self.entries[index] = value; self.entries[index] = value;
} }
macro usz InterfaceList._remove_using_test(&self, InterfaceTest filter, bool $invert, ctx) @local macro usz interfacelist_remove_using_test(InterfaceList* self, InterfaceTest filter, bool $invert, ctx) @local
{ {
usz size = self.size; usz size = self.size;
for (usz i = size, usz k = size; k > 0; k = i) for (usz i = size, usz k = size; k > 0; k = i)
@@ -512,7 +512,7 @@ macro usz InterfaceList._remove_using_test(&self, InterfaceTest filter, bool $in
return size - self.size; return size - self.size;
} }
macro usz InterfaceList._remove_if(&self, InterfacePredicate filter, bool $invert) @local macro usz interfacelist_remove_if(InterfaceList* self, InterfacePredicate filter, bool $invert) @local
{ {
usz size = self.size; usz size = self.size;
for (usz i = size, usz k = size; k > 0; k = i) for (usz i = size, usz k = size; k > 0; k = i)

View File

@@ -75,7 +75,7 @@ fn void LinkedBlockingQueue.free(&self)
self.not_full.destroy(); self.not_full.destroy();
} }
fn void LinkedBlockingQueue.link_entry(&self, QueueEntry* entry) @private fn void linkedblockingqueue_link_entry(LinkedBlockingQueue* self, QueueEntry* entry) @private
{ {
entry.next = null; entry.next = null;
entry.prev = self.tail; entry.prev = self.tail;
@@ -95,7 +95,7 @@ fn void LinkedBlockingQueue.link_entry(&self, QueueEntry* entry) @private
} }
fn QueueEntry* LinkedBlockingQueue.unlink_head(&self) @private fn QueueEntry* linkedblockingqueue_unlink_head(LinkedBlockingQueue* self) @private
{ {
if (self.head == null) return null; if (self.head == null) return null;
@@ -134,7 +134,7 @@ fn void LinkedBlockingQueue.push(&self, Value value)
.next = null, .next = null,
.prev = null .prev = null
}); });
self.link_entry(entry); linkedblockingqueue_link_entry(self, entry);
// Signal that queue is no longer empty // Signal that queue is no longer empty
self.not_empty.signal(); self.not_empty.signal();
@@ -156,7 +156,7 @@ fn Value LinkedBlockingQueue.poll(&self)
self.not_empty.wait(&self.lock); self.not_empty.wait(&self.lock);
} }
QueueEntry* entry = self.unlink_head(); QueueEntry* entry = linkedblockingqueue_unlink_head(self);
Value value = entry.value; Value value = entry.value;
allocator::free(self.allocator, entry); allocator::free(self.allocator, entry);
if (self.capacity > 0) if (self.capacity > 0)
@@ -180,7 +180,7 @@ fn Value? LinkedBlockingQueue.pop(&self)
{ {
if (self.count == 0) return NO_MORE_ELEMENT~; if (self.count == 0) return NO_MORE_ELEMENT~;
QueueEntry* entry = self.unlink_head(); QueueEntry* entry = linkedblockingqueue_unlink_head(self);
Value value = entry.value; Value value = entry.value;
allocator::free(self.allocator, entry); allocator::free(self.allocator, entry);
@@ -217,7 +217,7 @@ fn Value? LinkedBlockingQueue.poll_timeout(&self, Duration timeout)
if (!self.count) return NO_MORE_ELEMENT~; if (!self.count) return NO_MORE_ELEMENT~;
} }
QueueEntry* entry = self.unlink_head(); QueueEntry* entry = linkedblockingqueue_unlink_head(self);
Value value = entry.value; Value value = entry.value;
allocator::free(self.allocator, entry); allocator::free(self.allocator, entry);
@@ -273,7 +273,7 @@ fn void? LinkedBlockingQueue.try_push(&self, Value value)
.next = null, .next = null,
.prev = null .prev = null
}); });
self.link_entry(entry); linkedblockingqueue_link_entry(self, entry);
self.not_empty.signal(); self.not_empty.signal();
}; };
} }
@@ -307,7 +307,7 @@ fn void? LinkedBlockingQueue.push_timeout(&self, Value value, Duration timeout)
.next = null, .next = null,
.prev = null .prev = null
}); });
self.link_entry(entry); linkedblockingqueue_link_entry(self, entry);
self.not_empty.signal(); self.not_empty.signal();
}; };
} }

View File

@@ -150,7 +150,7 @@ fn bool LinkedHashMap.is_initialized(&map)
fn LinkedHashMap* LinkedHashMap.init_from_map(&self, Allocator allocator, LinkedHashMap* other_map) fn LinkedHashMap* LinkedHashMap.init_from_map(&self, Allocator allocator, LinkedHashMap* other_map)
{ {
self.init(allocator, other_map.table.len, other_map.load_factor); self.init(allocator, other_map.table.len, other_map.load_factor);
self.put_all_for_create(other_map); linkedhashmap_put_all_for_create(self, other_map);
return self; return self;
} }
@@ -242,13 +242,13 @@ fn bool LinkedHashMap.set(&map, Key key, Value value) @operator([]=)
return true; return true;
} }
} }
map.add_entry(hash, key, value, index); linkedhashmap_add_entry(map, hash, key, value, index);
return false; return false;
} }
fn void? LinkedHashMap.remove(&map, Key key) @maydiscard fn void? LinkedHashMap.remove(&map, Key key) @maydiscard
{ {
if (!map.remove_entry_for_key(key)) return NOT_FOUND~; if (!linkedhashmap_remove_entry_for_key(map, key)) return NOT_FOUND~;
} }
fn void LinkedHashMap.clear(&map) fn void LinkedHashMap.clear(&map)
@@ -259,7 +259,7 @@ fn void LinkedHashMap.clear(&map)
while (entry) while (entry)
{ {
LinkedEntry* next = entry.after; LinkedEntry* next = entry.after;
map.free_entry(entry); linkedhashmap_free_entry(map, entry);
entry = next; entry = next;
} }
@@ -277,7 +277,7 @@ fn void LinkedHashMap.free(&map)
{ {
if (!map.is_initialized()) return; if (!map.is_initialized()) return;
map.clear(); map.clear();
map.free_internal(map.table.ptr); linkedhashmap_free_internal(map, map.table.ptr);
map.table = {}; map.table = {};
} }
@@ -396,7 +396,7 @@ fn bool LinkedHashMapIterator.has_next(&self)
// --- private methods // --- private methods
fn void LinkedHashMap.add_entry(&map, uint hash, Key key, Value value, uint bucket_index) @private fn void linkedhashmap_add_entry(LinkedHashMap* map, uint hash, Key key, Value value, uint bucket_index) @private
{ {
$if COPY_KEYS: $if COPY_KEYS:
key = key.copy(map.allocator); key = key.copy(map.allocator);
@@ -428,11 +428,11 @@ fn void LinkedHashMap.add_entry(&map, uint hash, Key key, Value value, uint buck
if (map.count++ >= map.threshold) if (map.count++ >= map.threshold)
{ {
map.resize(map.table.len * 2); linkedhashmap_resize(map, map.table.len * 2);
} }
} }
fn void LinkedHashMap.resize(&map, uint new_capacity) @private fn void linkedhashmap_resize(LinkedHashMap* map, uint new_capacity) @private
{ {
LinkedEntry*[] old_table = map.table; LinkedEntry*[] old_table = map.table;
uint old_capacity = old_table.len; uint old_capacity = old_table.len;
@@ -502,7 +502,7 @@ fn void LinkedHashMap.resize(&map, uint new_capacity) @private
} }
} }
map.free_internal(old_table.ptr); linkedhashmap_free_internal(map, old_table.ptr);
} }
fn usz? LinkedHashMap.to_format(&self, Formatter* f) @dynamic fn usz? LinkedHashMap.to_format(&self, Formatter* f) @dynamic
@@ -517,7 +517,7 @@ fn usz? LinkedHashMap.to_format(&self, Formatter* f) @dynamic
return len + f.print(" }"); return len + f.print(" }");
} }
fn void LinkedHashMap.transfer(&map, LinkedEntry*[] new_table) @private fn void linkedhashmap_transfer(LinkedHashMap* map, LinkedEntry*[] new_table) @private
{ {
LinkedEntry*[] src = map.table; LinkedEntry*[] src = map.table;
uint new_capacity = new_table.len; uint new_capacity = new_table.len;
@@ -536,7 +536,7 @@ fn void LinkedHashMap.transfer(&map, LinkedEntry*[] new_table) @private
} }
} }
fn void LinkedHashMap.put_all_for_create(&map, LinkedHashMap* other_map) @private fn void linkedhashmap_put_all_for_create(LinkedHashMap* map, LinkedHashMap* other_map) @private
{ {
if (!other_map.count) return; if (!other_map.count) return;
other_map.@each(; Key key, Value value) { other_map.@each(; Key key, Value value) {
@@ -544,7 +544,7 @@ fn void LinkedHashMap.put_all_for_create(&map, LinkedHashMap* other_map) @privat
}; };
} }
fn void LinkedHashMap.put_for_create(&map, Key key, Value value) @private fn void linkedhashmap_put_for_create(LinkedHashMap* map, Key key, Value value) @private
{ {
uint hash = rehash(key.hash()); uint hash = rehash(key.hash());
uint i = index_for(hash, map.table.len); uint i = index_for(hash, map.table.len);
@@ -556,15 +556,15 @@ fn void LinkedHashMap.put_for_create(&map, Key key, Value value) @private
return; return;
} }
} }
map.create_entry(hash, key, value, i); linkedhashmap_create_entry(map, hash, key, value, i);
} }
fn void LinkedHashMap.free_internal(&map, void* ptr) @inline @private fn void linkedhashmap_free_internal(LinkedHashMap* map, void* ptr) @inline @private
{ {
allocator::free(map.allocator, ptr); allocator::free(map.allocator, ptr);
} }
fn bool LinkedHashMap.remove_entry_for_key(&map, Key key) @private fn bool linkedhashmap_remove_entry_for_key(LinkedHashMap* map, Key key) @private
{ {
if (!map.count) return false; if (!map.count) return false;
@@ -605,7 +605,7 @@ fn bool LinkedHashMap.remove_entry_for_key(&map, Key key) @private
} }
map.count--; map.count--;
map.free_entry(e); linkedhashmap_free_entry(map, e);
return true; return true;
} }
prev = e; prev = e;
@@ -614,23 +614,23 @@ fn bool LinkedHashMap.remove_entry_for_key(&map, Key key) @private
return false; return false;
} }
fn void LinkedHashMap.create_entry(&map, uint hash, Key key, Value value, int bucket_index) @private fn void linkedhashmap_create_entry(LinkedHashMap* map, uint hash, Key key, Value value, int bucket_index) @private
{ {
LinkedEntry *e = map.table[bucket_index]; LinkedEntry *e = map.table[bucket_index];
$if COPY_KEYS: $if COPY_KEYS:
key = key.copy(map.allocator); key = key.copy(map.allocator);
$endif $endif
LinkedEntry* entry = allocator::new(map.allocator, LinkedEntry, { .hash = hash, .key = key, .value = value, .next = map.table[bucket_index] }); LinkedEntry* entry = allocator::new(map.allocator, LinkedEntry, { .hash = hash, .key = key, .value = value, .next = map.table[bucket_index] });
map.table[bucket_index] = entry; map.table[bucket_index] = entry;
map.count++; map.count++;
} }
fn void LinkedHashMap.free_entry(&self, LinkedEntry *entry) @local fn void linkedhashmap_free_entry(LinkedHashMap* self, LinkedEntry *entry) @local
{ {
$if COPY_KEYS: $if COPY_KEYS:
allocator::free(self.allocator, entry.key); allocator::free(self.allocator, entry.key);
$endif $endif
self.free_internal(entry); linkedhashmap_free_internal(self, entry);
} }

View File

@@ -143,7 +143,7 @@ fn LinkedHashSet* LinkedHashSet.init_from_set(&self, Allocator allocator, Linked
LinkedEntry* entry = other_set.head; LinkedEntry* entry = other_set.head;
while (entry) // Save insertion order while (entry) // Save insertion order
{ {
self.put_for_create(entry.value); linkedhashset_put_for_create(self, entry.value);
entry = entry.after; entry = entry.after;
} }
return self; return self;
@@ -223,7 +223,7 @@ fn bool LinkedHashSet.add(&set, Value value)
{ {
if (e.hash == hash && equals(value, e.value)) return false; if (e.hash == hash && equals(value, e.value)) return false;
} }
set.add_entry(hash, value, index); linkedhashset_add_entry(set, hash, value, index);
return true; return true;
} }
@@ -266,7 +266,7 @@ fn bool LinkedHashSet.contains(&set, Value value)
*> *>
fn void? LinkedHashSet.remove(&set, Value value) @maydiscard fn void? LinkedHashSet.remove(&set, Value value) @maydiscard
{ {
if (!set.remove_entry_for_value(value)) return NOT_FOUND~; if (!linkedhashset_remove_entry_for_value(set, value)) return NOT_FOUND~;
} }
fn usz LinkedHashSet.remove_all(&set, Value[] values) fn usz LinkedHashSet.remove_all(&set, Value[] values)
@@ -274,7 +274,7 @@ fn usz LinkedHashSet.remove_all(&set, Value[] values)
usz total; usz total;
foreach (v : values) foreach (v : values)
{ {
if (set.remove_entry_for_value(v)) total++; if (linkedhashset_remove_entry_for_value(set, v)) total++;
} }
return total; return total;
} }
@@ -287,7 +287,7 @@ fn usz LinkedHashSet.remove_all_from(&set, LinkedHashSet* other)
usz total; usz total;
other.@each(;Value val) other.@each(;Value val)
{ {
if (set.remove_entry_for_value(val)) total++; if (linkedhashset_remove_entry_for_value(set, val)) total++;
}; };
return total; return total;
} }
@@ -299,7 +299,7 @@ fn void LinkedHashSet.free(&set)
{ {
if (!set.is_initialized()) return; if (!set.is_initialized()) return;
set.clear(); set.clear();
set.free_internal(set.table.ptr); linkedhashset_free_internal(set, set.table.ptr);
set.table = {}; set.table = {};
} }
@@ -316,7 +316,7 @@ fn void LinkedHashSet.clear(&set)
while (entry) while (entry)
{ {
LinkedEntry* next = entry.after; LinkedEntry* next = entry.after;
set.free_entry(entry); linkedhashset_free_entry(set, entry);
entry = next; entry = next;
} }
@@ -334,7 +334,7 @@ fn void LinkedHashSet.reserve(&set, usz capacity)
{ {
if (capacity > set.threshold) if (capacity > set.threshold)
{ {
set.resize(math::next_power_of_2(capacity)); linkedhashset_resize(set, math::next_power_of_2(capacity));
} }
} }
@@ -451,7 +451,7 @@ fn bool LinkedHashSet.is_subset(&self, LinkedHashSet* other)
// --- private methods // --- private methods
fn void LinkedHashSet.add_entry(&set, uint hash, Value value, uint bucket_index) @private fn void linkedhashset_add_entry(LinkedHashSet* set, uint hash, Value value, uint bucket_index) @private
{ {
LinkedEntry* entry = allocator::new(set.allocator, LinkedEntry, { LinkedEntry* entry = allocator::new(set.allocator, LinkedEntry, {
.hash = hash, .hash = hash,
@@ -478,11 +478,11 @@ fn void LinkedHashSet.add_entry(&set, uint hash, Value value, uint bucket_index)
if (set.count++ >= set.threshold) if (set.count++ >= set.threshold)
{ {
set.resize(set.table.len * 2); linkedhashset_resize(set, set.table.len * 2);
} }
} }
fn void LinkedHashSet.resize(&set, usz new_capacity) @private fn void linkedhashset_resize(LinkedHashSet* set, usz new_capacity) @private
{ {
LinkedEntry*[] old_table = set.table; LinkedEntry*[] old_table = set.table;
usz old_capacity = old_table.len; usz old_capacity = old_table.len;
@@ -552,7 +552,7 @@ fn void LinkedHashSet.resize(&set, usz new_capacity) @private
} }
} }
set.free_internal(old_table.ptr); linkedhashset_free_internal(set, old_table.ptr);
} }
fn usz? LinkedHashSet.to_format(&self, Formatter* f) @dynamic fn usz? LinkedHashSet.to_format(&self, Formatter* f) @dynamic
@@ -567,7 +567,7 @@ fn usz? LinkedHashSet.to_format(&self, Formatter* f) @dynamic
return len + f.print(" }"); return len + f.print(" }");
} }
fn void LinkedHashSet.transfer(&set, LinkedEntry*[] new_table) @private fn void linked_hashset_transfer(LinkedHashSet* set, LinkedEntry*[] new_table) @private
{ {
LinkedEntry*[] src = set.table; LinkedEntry*[] src = set.table;
uint new_capacity = new_table.len; uint new_capacity = new_table.len;
@@ -586,7 +586,7 @@ fn void LinkedHashSet.transfer(&set, LinkedEntry*[] new_table) @private
} }
} }
fn void LinkedHashSet.put_for_create(&set, Value value) @private fn void linkedhashset_put_for_create(LinkedHashSet* set, Value value) @private
{ {
uint hash = rehash(value.hash()); uint hash = rehash(value.hash());
uint i = index_for(hash, set.table.len); uint i = index_for(hash, set.table.len);
@@ -598,15 +598,15 @@ fn void LinkedHashSet.put_for_create(&set, Value value) @private
return; return;
} }
} }
set.create_entry(hash, value, i); linkedhashset_create_entry(set, hash, value, i);
} }
fn void LinkedHashSet.free_internal(&set, void* ptr) @inline @private fn void linkedhashset_free_internal(LinkedHashSet* set, void* ptr) @inline @private
{ {
allocator::free(set.allocator, ptr); allocator::free(set.allocator, ptr);
} }
fn void LinkedHashSet.create_entry(&set, uint hash, Value value, int bucket_index) @private fn void linkedhashset_create_entry(LinkedHashSet* set, uint hash, Value value, int bucket_index) @private
{ {
LinkedEntry* entry = allocator::new(set.allocator, LinkedEntry, { LinkedEntry* entry = allocator::new(set.allocator, LinkedEntry, {
.hash = hash, .hash = hash,
@@ -633,7 +633,7 @@ fn void LinkedHashSet.create_entry(&set, uint hash, Value value, int bucket_inde
set.count++; set.count++;
} }
fn bool LinkedHashSet.remove_entry_for_value(&set, Value value) @private fn bool linkedhashset_remove_entry_for_value(LinkedHashSet* set, Value value) @private
{ {
if (!set.count) return false; if (!set.count) return false;
@@ -674,7 +674,7 @@ fn bool LinkedHashSet.remove_entry_for_value(&set, Value value) @private
} }
set.count--; set.count--;
set.free_entry(e); linkedhashset_free_entry(set, e);
return true; return true;
} }
prev = e; prev = e;
@@ -683,7 +683,7 @@ fn bool LinkedHashSet.remove_entry_for_value(&set, Value value) @private
return false; return false;
} }
fn void LinkedHashSet.free_entry(&set, LinkedEntry *entry) @private fn void linkedhashset_free_entry(LinkedHashSet* set, LinkedEntry *entry) @private
{ {
allocator::free(set.allocator, entry); allocator::free(set.allocator, entry);
} }

View File

@@ -217,7 +217,7 @@ fn usz? LinkedList.rindex_of(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
*> *>
fn void LinkedList.remove_at(&self, usz index) fn void LinkedList.remove_at(&self, usz index)
{ {
self.unlink(self.node_at_index(index)); linked_list_unlink(self, self.node_at_index(index));
} }
<* <*
@@ -232,47 +232,47 @@ fn void LinkedList.insert_at(&self, usz index, Type element)
case self.size: case self.size:
self.push(element); self.push(element);
default: default:
self.link_before(self.node_at_index(index), element); linked_list_link_before(self, self.node_at_index(index), element);
} }
} }
<* <*
@require succ != null @require succ != null
*> *>
fn void LinkedList.link_before(&self, Node *succ, Type value) @private fn void linked_list_link_before(LinkedList* l, Node *succ, Type value) @private
{ {
Node* pred = succ.prev; Node* pred = succ.prev;
Node* new_node = self.alloc_node(); Node* new_node = l.alloc_node();
*new_node = { .prev = pred, .next = succ, .value = value }; *new_node = { .prev = pred, .next = succ, .value = value };
succ.prev = new_node; succ.prev = new_node;
if (!pred) if (!pred)
{ {
self._first = new_node; l._first = new_node;
} }
else else
{ {
pred.next = new_node; pred.next = new_node;
} }
self.size++; l.size++;
} }
<* <*
@require self._first != null @require l._first != null
*> *>
fn void LinkedList.unlink_first(&self) @private fn void linked_list_unlink_first(LinkedList* l) @private
{ {
Node* f = self._first; Node* f = l._first;
Node* next = f.next; Node* next = f.next;
self.free_node(f); l.free_node(f);
self._first = next; l._first = next;
if (!next) if (!next)
{ {
self._last = null; l._last = null;
} }
else else
{ {
next.prev = null; next.prev = null;
} }
self.size--; l.size--;
} }
fn usz LinkedList.remove(&self, Type t) @if(ELEMENT_IS_EQUATABLE) fn usz LinkedList.remove(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
@@ -285,7 +285,7 @@ fn usz LinkedList.remove(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
{ {
case equals(node.value, t): case equals(node.value, t):
Node* next = node.next; Node* next = node.next;
self.unlink(node); linked_list_unlink(self, node);
node = next; node = next;
default: default:
node = node.next; node = node.next;
@@ -297,7 +297,7 @@ fn usz LinkedList.remove(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
fn Type? LinkedList.pop(&self) fn Type? LinkedList.pop(&self)
{ {
if (!self._last) return NO_MORE_ELEMENT~; if (!self._last) return NO_MORE_ELEMENT~;
defer self.unlink_last(); defer linked_list_unlink_last(self);
return self._last.value; return self._last.value;
} }
@@ -309,20 +309,20 @@ fn bool LinkedList.is_empty(&self)
fn Type? LinkedList.pop_front(&self) fn Type? LinkedList.pop_front(&self)
{ {
if (!self._first) return NO_MORE_ELEMENT~; if (!self._first) return NO_MORE_ELEMENT~;
defer self.unlink_first(); defer linked_list_unlink_first(self);
return self._first.value; return self._first.value;
} }
fn void? LinkedList.remove_last(&self) @maydiscard fn void? LinkedList.remove_last(&self) @maydiscard
{ {
if (!self._first) return NO_MORE_ELEMENT~; if (!self._first) return NO_MORE_ELEMENT~;
self.unlink_last(); linked_list_unlink_last(self);
} }
fn void? LinkedList.remove_first(&self) @maydiscard fn void? LinkedList.remove_first(&self) @maydiscard
{ {
if (!self._first) return NO_MORE_ELEMENT~; if (!self._first) return NO_MORE_ELEMENT~;
self.unlink_first(); linked_list_unlink_first(self);
} }
@@ -332,7 +332,7 @@ fn bool LinkedList.remove_first_match(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
{ {
if (node.value == t) if (node.value == t)
{ {
self.unlink(node); linked_list_unlink(self, node);
return true; return true;
} }
} }
@@ -345,7 +345,7 @@ fn bool LinkedList.remove_last_match(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
{ {
if (node.value == t) if (node.value == t)
{ {
self.unlink(node); linked_list_unlink(self, node);
return true; return true;
} }
} }
@@ -354,7 +354,7 @@ fn bool LinkedList.remove_last_match(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
<* <*
@require self._last != null @require self._last != null
*> *>
fn void LinkedList.unlink_last(&self) @inline @private fn void linked_list_unlink_last(LinkedList* self) @inline @private
{ {
Node* l = self._last; Node* l = self._last;
Node* prev = l.prev; Node* prev = l.prev;
@@ -374,7 +374,7 @@ fn void LinkedList.unlink_last(&self) @inline @private
<* <*
@require x != null @require x != null
*> *>
fn void LinkedList.unlink(&self, Node* x) @private fn void linked_list_unlink(LinkedList* self, Node* x) @private
{ {
Node* next = x.next; Node* next = x.next;
Node* prev = x.prev; Node* prev = x.prev;

View File

@@ -82,7 +82,7 @@ fn void List.init_wrapping_array(&self, Allocator allocator, Type[] types)
self.allocator = allocator; self.allocator = allocator;
self.capacity = types.len; self.capacity = types.len;
self.entries = types.ptr; self.entries = types.ptr;
self.set_size(types.len); list_set_size(self, types.len);
} }
fn bool List.is_initialized(&self) @inline => self.allocator != null && self.allocator != (Allocator)&dummy; fn bool List.is_initialized(&self) @inline => self.allocator != null && self.allocator != (Allocator)&dummy;
@@ -110,19 +110,19 @@ fn usz? List.to_format(&self, Formatter* formatter) @dynamic
fn void List.push(&self, Type element) @inline fn void List.push(&self, Type element) @inline
{ {
self.reserve(1); self.reserve(1);
self.entries[self.set_size(self.size + 1)] = element; self.entries[list_set_size(self, self.size + 1)] = element;
} }
fn Type? List.pop(&self) fn Type? List.pop(&self)
{ {
if (!self.size) return NO_MORE_ELEMENT~; if (!self.size) return NO_MORE_ELEMENT~;
defer self.set_size(self.size - 1); defer list_set_size(self, self.size - 1);
return self.entries[self.size - 1]; return self.entries[self.size - 1];
} }
fn void List.clear(&self) fn void List.clear(&self)
{ {
self.set_size(0); list_set_size(self, 0);
} }
fn Type? List.pop_first(&self) fn Type? List.pop_first(&self)
@@ -138,7 +138,7 @@ fn Type? List.pop_first(&self)
fn void List.remove_at(&self, usz index) fn void List.remove_at(&self, usz index)
{ {
usz new_size = self.size - 1; usz new_size = self.size - 1;
defer self.set_size(new_size); defer list_set_size(self, new_size);
if (!new_size || index == new_size) return; if (!new_size || index == new_size) return;
self.entries[index .. new_size - 1] = self.entries[index + 1 .. new_size]; self.entries[index .. new_size - 1] = self.entries[index + 1 .. new_size];
} }
@@ -147,7 +147,7 @@ fn void List.add_all(&self, List* other_list)
{ {
if (!other_list.size) return; if (!other_list.size) return;
self.reserve(other_list.size); self.reserve(other_list.size);
usz index = self.set_size(self.size + other_list.size); usz index = list_set_size(self, self.size + other_list.size);
foreach (&value : other_list) foreach (&value : other_list)
{ {
self.entries[index++] = *value; self.entries[index++] = *value;
@@ -203,7 +203,7 @@ fn void List.add_array(&self, Type[] array) @deprecated("Use push_all")
{ {
if (!array.len) return; if (!array.len) return;
self.reserve(array.len); self.reserve(array.len);
usz index = self.set_size(self.size + array.len); usz index = list_set_size(self, self.size + array.len);
self.entries[index : array.len] = array[..]; self.entries[index : array.len] = array[..];
} }
@@ -217,7 +217,7 @@ fn void List.push_all(&self, Type[] array)
{ {
if (!array.len) return; if (!array.len) return;
self.reserve(array.len); self.reserve(array.len);
usz index = self.set_size(self.size + array.len); usz index = list_set_size(self, self.size + array.len);
self.entries[index : array.len] = array[..]; self.entries[index : array.len] = array[..];
} }
@@ -232,7 +232,7 @@ fn void List.push_front(&self, Type type) @inline
fn void List.insert_at(&self, usz index, Type type) fn void List.insert_at(&self, usz index, Type type)
{ {
self.reserve(1); self.reserve(1);
self.set_size(self.size + 1); list_set_size(self, self.size + 1);
for (isz i = self.size - 1; i > index; i--) for (isz i = self.size - 1; i > index; i--)
{ {
self.entries[i] = self.entries[i - 1]; self.entries[i] = self.entries[i - 1];
@@ -251,7 +251,7 @@ fn void List.set_at(&self, usz index, Type type)
fn void? List.remove_last(&self) @maydiscard fn void? List.remove_last(&self) @maydiscard
{ {
if (!self.size) return NO_MORE_ELEMENT~; if (!self.size) return NO_MORE_ELEMENT~;
self.set_size(self.size - 1); list_set_size(self, self.size - 1);
} }
fn void? List.remove_first(&self) @maydiscard fn void? List.remove_first(&self) @maydiscard
@@ -299,7 +299,7 @@ fn void List.free(&self)
{ {
if (!self.allocator || self.allocator.ptr == &dummy || !self.capacity) return; if (!self.allocator || self.allocator.ptr == &dummy || !self.capacity) return;
self.pre_free(); // Remove sanitizer annotation list_pre_free(self); // Remove sanitizer annotation
$if type_is_overaligned(): $if type_is_overaligned():
allocator::free_aligned(self.allocator, self.entries); allocator::free_aligned(self.allocator, self.entries);
@@ -358,7 +358,7 @@ fn usz List.retain_using_test(&self, ElementTest filter, any context)
return list_common::list_remove_using_test(self, filter, true, context); return list_common::list_remove_using_test(self, filter, true, context);
} }
fn void List.ensure_capacity(&self, usz min_capacity) @local fn void list_ensure_capacity(List* self, usz min_capacity) @local
{ {
if (!min_capacity) return; if (!min_capacity) return;
if (self.capacity >= min_capacity) return; if (self.capacity >= min_capacity) return;
@@ -374,7 +374,7 @@ fn void List.ensure_capacity(&self, usz min_capacity) @local
break; break;
} }
self.pre_free(); // Remove sanitizer annotation list_pre_free(self); // Remove sanitizer annotation
min_capacity = math::next_power_of_2(min_capacity); min_capacity = math::next_power_of_2(min_capacity);
$if type_is_overaligned(): $if type_is_overaligned():
@@ -384,7 +384,7 @@ fn void List.ensure_capacity(&self, usz min_capacity) @local
$endif; $endif;
self.capacity = min_capacity; self.capacity = min_capacity;
self.post_alloc(); // Add sanitizer annotation list_post_alloc(self); // Add sanitizer annotation
} }
<* <*
@@ -419,7 +419,7 @@ fn void List.reserve(&self, usz added)
assert(new_size < usz.max / 2U); assert(new_size < usz.max / 2U);
usz new_capacity = self.capacity ? 2U * self.capacity : 16U; usz new_capacity = self.capacity ? 2U * self.capacity : 16U;
while (new_capacity < new_size) new_capacity *= 2U; while (new_capacity < new_size) new_capacity *= 2U;
self.ensure_capacity(new_capacity); list_ensure_capacity(self, new_capacity);
} }
fn void List._update_size_change(&self,usz old_size, usz new_size) fn void List._update_size_change(&self,usz old_size, usz new_size)
@@ -436,7 +436,7 @@ fn void List._update_size_change(&self,usz old_size, usz new_size)
<* <*
@require new_size == 0 || self.capacity != 0 @require new_size == 0 || self.capacity != 0
*> *>
fn usz List.set_size(&self, usz new_size) @inline @private fn usz list_set_size(List* self, usz new_size) @inline @private
{ {
usz old_size = self.size; usz old_size = self.size;
self._update_size_change(old_size, new_size); self._update_size_change(old_size, new_size);
@@ -444,7 +444,7 @@ fn usz List.set_size(&self, usz new_size) @inline @private
return old_size; return old_size;
} }
macro void List.pre_free(&self) @private macro void list_pre_free(List* self) @private
{ {
if (!self.capacity) return; if (!self.capacity) return;
self._update_size_change(self.size, self.capacity); self._update_size_change(self.size, self.capacity);
@@ -453,7 +453,7 @@ macro void List.pre_free(&self) @private
<* <*
@require self.capacity > 0 @require self.capacity > 0
*> *>
macro void List.post_alloc(&self) @private macro void list_post_alloc(List* self) @private
{ {
self._update_size_change(self.capacity, self.size); self._update_size_change(self.capacity, self.size);
} }

View File

@@ -151,7 +151,7 @@ fn bool Object.is_indexable(&self) => self.is_empty() || self.is_array();
<* <*
@require self.is_keyable() @require self.is_keyable()
*> *>
fn void Object.init_map_if_needed(&self) @private fn void object_init_map_if_needed(Object* self) @private
{ {
if (self.is_empty()) if (self.is_empty())
{ {
@@ -163,7 +163,7 @@ fn void Object.init_map_if_needed(&self) @private
<* <*
@require self.is_indexable() @require self.is_indexable()
*> *>
fn void Object.init_array_if_needed(&self) @private fn void object_init_array_if_needed(Object* self) @private
{ {
if (self.is_empty()) if (self.is_empty())
{ {
@@ -175,9 +175,9 @@ fn void Object.init_array_if_needed(&self) @private
<* <*
@require self.is_keyable() @require self.is_keyable()
*> *>
fn void Object.set_object(&self, String key, Object* new_object) @private fn void object_set_object(Object* self, String key, Object* new_object) @private
{ {
self.init_map_if_needed(); object_init_map_if_needed(self);
Object*? val = self.map.get_entry(key).value; Object*? val = self.map.get_entry(key).value;
defer (void)val.free(); defer (void)val.free();
self.map.set(key, new_object); self.map.set(key, new_object);
@@ -214,7 +214,7 @@ macro Object* Object.object_from_value(&self, value) @private
macro Object* Object.set(&self, String key, value) macro Object* Object.set(&self, String key, value)
{ {
Object* val = self.object_from_value(value); Object* val = self.object_from_value(value);
self.set_object(key, val); object_set_object(self, key, val);
return val; return val;
} }
@@ -267,7 +267,7 @@ fn usz Object.get_len(&self)
*> *>
fn void Object.push_object(&self, Object* to_append) fn void Object.push_object(&self, Object* to_append)
{ {
self.init_array_if_needed(); object_init_array_if_needed(self);
self.array.push(to_append); self.array.push(to_append);
} }
@@ -276,7 +276,7 @@ fn void Object.push_object(&self, Object* to_append)
*> *>
fn void Object.set_object_at(&self, usz index, Object* to_set) fn void Object.set_object_at(&self, usz index, Object* to_set)
{ {
self.init_array_if_needed(); object_init_array_if_needed(self);
while (self.array.len() < index) while (self.array.len() < index)
{ {
self.array.push(&NULL_OBJECT); self.array.push(&NULL_OBJECT);

View File

@@ -90,7 +90,7 @@ fn usz? Inflater.read(&self, char[] buffer) @dynamic
if (self.pos - self.read_pos >= 32768U) break; if (self.pos - self.read_pos >= 32768U) break;
self.step()!; inflater_step(self)!;
} }
return total_out; return total_out;
@@ -521,7 +521,7 @@ fn void StreamBitReader.close(&self)
} }
} }
fn void? StreamBitReader.refill(&self) @private @inline fn void? StreamBitReader.refill(&self) @inline
{ {
if (self.buf_pos >= self.buf_len) if (self.buf_pos >= self.buf_len)
{ {
@@ -532,7 +532,7 @@ fn void? StreamBitReader.refill(&self) @private @inline
} }
} }
fn uint? StreamBitReader.read_bits(&self, uint count) @private @inline fn uint? StreamBitReader.read_bits(&self, uint count) @inline
{ {
if (count == 0) return 0; if (count == 0) return 0;
if (self.nbits < count) if (self.nbits < count)
@@ -554,7 +554,7 @@ fn uint? StreamBitReader.read_bits(&self, uint count) @private @inline
return value; return value;
} }
fn void StreamBitReader.align(&self) @private @inline fn void StreamBitReader.align(&self) @inline
{ {
uint skip = self.nbits % 8; uint skip = self.nbits % 8;
self.bit_buf >>= skip; self.bit_buf >>= skip;
@@ -570,7 +570,7 @@ struct BitWriter @private
Allocator allocator; Allocator allocator;
} }
fn void BitWriter.init(&self, Allocator allocator, usz initial_cap) @private fn void BitWriter.init(&self, Allocator allocator, usz initial_cap)
{ {
self.allocator = allocator; self.allocator = allocator;
self.data = allocator::alloc_array(allocator, char, initial_cap); self.data = allocator::alloc_array(allocator, char, initial_cap);
@@ -579,7 +579,7 @@ fn void BitWriter.init(&self, Allocator allocator, usz initial_cap) @private
self.nbits = 0; self.nbits = 0;
} }
fn void BitWriter.write_bits(&self, uint value, uint count) @private fn void BitWriter.write_bits(&self, uint value, uint count)
{ {
self.buffer |= (ulong)(value & ((1 << count) - 1)) << self.nbits; self.buffer |= (ulong)(value & ((1 << count) - 1)) << self.nbits;
self.nbits += count; self.nbits += count;
@@ -602,13 +602,13 @@ fn void BitWriter.write_bits(&self, uint value, uint count) @private
} }
} }
fn void BitWriter.write_huffman(&self, uint code, uint len) @private fn void BitWriter.write_huffman(&self, uint code, uint len)
{ {
uint rev = bits::reverse(code << (32 - len)); uint rev = bits::reverse(code << (32 - len));
self.write_bits(rev, len); self.write_bits(rev, len);
} }
fn char[] BitWriter.finish(&self) @private fn char[] BitWriter.finish(&self)
{ {
if (self.nbits > 0) if (self.nbits > 0)
{ {
@@ -630,7 +630,7 @@ struct Huffman @private
ushort[288] symbols; ushort[288] symbols;
} }
fn void Huffman.build(&self, char[] lengths) @private fn void Huffman.build(&self, char[] lengths)
{ {
ushort[16] offsets; ushort[16] offsets;
self.counts = {}; self.counts = {};
@@ -805,7 +805,7 @@ fn char[] pkg_merge(Allocator allocator, uint[] freqs, uint max_bits) @private =
return blen; return blen;
} }
fn char[] Huffman.get_lengths(&self, usz max_sym) @private fn char[] Huffman.get_lengths(&self, usz max_sym)
{ {
char[] blen = allocator::new_array(tmem, char, max_sym + 1); char[] blen = allocator::new_array(tmem, char, max_sym + 1);
@@ -821,7 +821,7 @@ fn char[] Huffman.get_lengths(&self, usz max_sym) @private
return blen; return blen;
} }
fn void Huffman.build_from_freqs(&self, uint[] freqs, uint max_bits) @private => @pool() fn void Huffman.build_from_freqs(&self, uint[] freqs, uint max_bits) => @pool()
{ {
char[] blen = pkg_merge(tmem, freqs, max_bits); char[] blen = pkg_merge(tmem, freqs, max_bits);
self.build(blen); self.build(blen);
@@ -922,7 +922,7 @@ fn void gen_fixed_codes(Code* codes) @private
} }
} }
fn ushort? Huffman.decode_stream(&self, StreamBitReader* reader) @private @inline fn ushort? Huffman.decode_stream(&self, StreamBitReader* reader) @inline
{ {
uint code = 0; uint code = 0;
uint first = 0; uint first = 0;
@@ -943,7 +943,7 @@ fn ushort? Huffman.decode_stream(&self, StreamBitReader* reader) @private @inlin
return CORRUPTED_DATA~; return CORRUPTED_DATA~;
} }
fn void? Inflater.step(&self) @private fn void? inflater_step(Inflater* self) @private
{ {
switch (self.state) switch (self.state)
{ {
@@ -975,7 +975,7 @@ fn void? Inflater.step(&self) @private
self.state = COPY_STORED; self.state = COPY_STORED;
case COPY_STORED: case COPY_STORED:
char c = (char)self.reader.read_bits(8)!; char c = (char)self.reader.read_bits(8)!;
self.write_byte(c); inflater_write_byte(self, c);
self.stored_len--; self.stored_len--;
if (self.stored_len == 0) if (self.stored_len == 0)
{ {
@@ -1045,7 +1045,7 @@ fn void? Inflater.step(&self) @private
switch switch
{ {
case symbol < 256: case symbol < 256:
self.write_byte((char)symbol); inflater_write_byte(self, (char)symbol);
case symbol == 256: case symbol == 256:
self.state = self.final ? DONE : START_BLOCK; self.state = self.final ? DONE : START_BLOCK;
case symbol <= 285: case symbol <= 285:
@@ -1064,7 +1064,7 @@ fn void? Inflater.step(&self) @private
case COPY_MATCH: case COPY_MATCH:
if (self.match_dist > self.pos) return CORRUPTED_DATA~; if (self.match_dist > self.pos) return CORRUPTED_DATA~;
char c = self.window[(usz)((self.pos - self.match_dist) & 0xFFFF)]; char c = self.window[(usz)((self.pos - self.match_dist) & 0xFFFF)];
self.write_byte(c); inflater_write_byte(self, c);
self.match_len--; self.match_len--;
if (self.match_len == 0) if (self.match_len == 0)
{ {
@@ -1078,7 +1078,7 @@ fn void? Inflater.step(&self) @private
return; return;
} }
fn void Inflater.write_byte(&self, char c) @private @inline fn void inflater_write_byte(Inflater* self, char c) @private @inline
{ {
self.window[(usz)(self.pos & 0xFFFF)] = c; self.window[(usz)(self.pos & 0xFFFF)] = c;
self.pos++; self.pos++;

View File

@@ -56,7 +56,7 @@ fn BackedArenaAllocator*? new_backed_allocator(usz size, Allocator allocator)
fn void BackedArenaAllocator.destroy(&self) fn void BackedArenaAllocator.destroy(&self)
{ {
self.reset(0); self.reset(0);
if (self.last_page) (void)self._free_page(self.last_page); if (self.last_page) (void)_free_page(self, self.last_page);
allocator::free(self.backing_allocator, self); allocator::free(self.backing_allocator, self);
} }
@@ -79,7 +79,7 @@ fn void BackedArenaAllocator.reset(&self, usz mark)
self.used = last_page.mark; self.used = last_page.mark;
ExtraPage *to_free = last_page; ExtraPage *to_free = last_page;
last_page = last_page.prev_page; last_page = last_page.prev_page;
self._free_page(to_free)!!; _free_page(self, to_free)!!;
} }
self.last_page = last_page; self.last_page = last_page;
$if env::COMPILER_SAFE_MODE || env::ADDRESS_SANITIZER: $if env::COMPILER_SAFE_MODE || env::ADDRESS_SANITIZER:
@@ -98,13 +98,13 @@ fn void BackedArenaAllocator.reset(&self, usz mark)
self.used = mark; self.used = mark;
} }
fn void? BackedArenaAllocator._free_page(&self, ExtraPage* page) @inline @local fn void? _free_page(BackedArenaAllocator* self, ExtraPage* page) @inline @local
{ {
void* mem = page.start; void* mem = page.start;
return self.backing_allocator.release(mem, page.is_aligned()); return self.backing_allocator.release(mem, page.is_aligned());
} }
fn void*? BackedArenaAllocator._realloc_page(&self, ExtraPage* page, usz size, usz alignment) @inline @local fn void*? _realloc_page(BackedArenaAllocator* self, ExtraPage* page, usz size, usz alignment) @inline @local
{ {
// Then the actual start pointer: // Then the actual start pointer:
void* real_pointer = page.start; void* real_pointer = page.start;
@@ -133,7 +133,7 @@ fn void*? BackedArenaAllocator.resize(&self, void* pointer, usz size, usz alignm
assert(self.last_page, "Realloc of unrelated pointer"); assert(self.last_page, "Realloc of unrelated pointer");
// First grab the page // First grab the page
ExtraPage *page = pointer - ExtraPage.sizeof; ExtraPage *page = pointer - ExtraPage.sizeof;
return self._realloc_page(page, size, alignment); return _realloc_page(self, page, size, alignment);
} }
AllocChunk* data = self.acquire(size, NO_ZERO, alignment)!; AllocChunk* data = self.acquire(size, NO_ZERO, alignment)!;

View File

@@ -137,12 +137,67 @@ fn void DynamicArenaAllocator.reset(&self)
self.page = page; self.page = page;
} }
<*
@require size > 0 : `acquire expects size > 0`
@require !alignment || math::is_power_of_2(alignment)
@return? mem::INVALID_ALLOC_SIZE, mem::OUT_OF_MEMORY
*>
fn void*? DynamicArenaAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
{
alignment = alignment_for_allocation(alignment);
DynamicArenaPage* page = self.page;
void* ptr @noinit;
do SET_DONE:
{
if (!page && self.unused_page)
{
self.page = page = self.unused_page;
self.unused_page = page.prev_arena;
page.prev_arena = null;
}
if (!page)
{
ptr = _alloc_new(self, size, alignment)!;
break SET_DONE;
}
void* start = mem::aligned_pointer(page.memory + page.used + DynamicArenaChunk.sizeof, alignment);
usz new_used = start - page.memory + size;
if ALLOCATE_NEW: (new_used > page.total)
{
if ((page = self.unused_page))
{
start = mem::aligned_pointer(page.memory + page.used + DynamicArenaChunk.sizeof, alignment);
new_used = start + size - page.memory;
if (page.total >= new_used)
{
self.unused_page = page.prev_arena;
page.prev_arena = self.page;
self.page = page;
break ALLOCATE_NEW;
}
}
ptr = _alloc_new(self, size, alignment)!;
break SET_DONE;
}
page.used = new_used;
assert(start + size == page.memory + page.used);
ptr = start;
DynamicArenaChunk* chunk = (DynamicArenaChunk*)ptr - 1;
chunk.size = size;
};
if (init_type == ZERO) mem::clear(ptr, size, mem::DEFAULT_MEM_ALIGNMENT);
return ptr;
}
<* <*
@require math::is_power_of_2(alignment) @require math::is_power_of_2(alignment)
@require size > 0 @require size > 0
@return? mem::INVALID_ALLOC_SIZE, mem::OUT_OF_MEMORY @return? mem::INVALID_ALLOC_SIZE, mem::OUT_OF_MEMORY
*> *>
fn void*? DynamicArenaAllocator._alloc_new(&self, usz size, usz alignment) @local fn void*? _alloc_new(DynamicArenaAllocator* self, usz size, usz alignment) @local
{ {
// First, make sure that we can align it, extending the page size if needed. // First, make sure that we can align it, extending the page size if needed.
usz page_size = max(self.page_size, mem::aligned_offset(size + DynamicArenaChunk.sizeof + alignment, alignment)); usz page_size = max(self.page_size, mem::aligned_offset(size + DynamicArenaChunk.sizeof + alignment, alignment));
@@ -166,57 +221,4 @@ fn void*? DynamicArenaAllocator._alloc_new(&self, usz size, usz alignment) @loca
self.page = page; self.page = page;
page.current_stack_ptr = mem_start; page.current_stack_ptr = mem_start;
return mem_start; return mem_start;
} }
<*
@require size > 0 : `acquire expects size > 0`
@require !alignment || math::is_power_of_2(alignment)
@return? mem::INVALID_ALLOC_SIZE, mem::OUT_OF_MEMORY
*>
fn void*? DynamicArenaAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
{
alignment = alignment_for_allocation(alignment);
DynamicArenaPage* page = self.page;
void* ptr @noinit;
do SET_DONE:
{
if (!page && self.unused_page)
{
self.page = page = self.unused_page;
self.unused_page = page.prev_arena;
page.prev_arena = null;
}
if (!page)
{
ptr = self._alloc_new(size, alignment)!;
break SET_DONE;
}
void* start = mem::aligned_pointer(page.memory + page.used + DynamicArenaChunk.sizeof, alignment);
usz new_used = start - page.memory + size;
if ALLOCATE_NEW: (new_used > page.total)
{
if ((page = self.unused_page))
{
start = mem::aligned_pointer(page.memory + page.used + DynamicArenaChunk.sizeof, alignment);
new_used = start + size - page.memory;
if (page.total >= new_used)
{
self.unused_page = page.prev_arena;
page.prev_arena = self.page;
self.page = page;
break ALLOCATE_NEW;
}
}
ptr = self._alloc_new(size, alignment)!;
break SET_DONE;
}
page.used = new_used;
assert(start + size == page.memory + page.used);
ptr = start;
DynamicArenaChunk* chunk = (DynamicArenaChunk*)ptr - 1;
chunk.size = size;
};
if (init_type == ZERO) mem::clear(ptr, size, mem::DEFAULT_MEM_ALIGNMENT);
return ptr;
}

View File

@@ -32,58 +32,58 @@ fn void*? SimpleHeapAllocator.acquire(&self, usz size, AllocInitType init_type,
{ {
if (init_type == ZERO) if (init_type == ZERO)
{ {
return alignment > 0 ? @aligned_alloc(self._calloc, size, alignment) : self._calloc(size); return alignment > 0 ? @aligned_alloc_fn(self, simple_alloc_calloc, size, alignment) : simple_alloc_calloc(self, size);
} }
return alignment > 0 ? @aligned_alloc(self._alloc, size, alignment) : self._alloc(size); return alignment > 0 ? @aligned_alloc_fn(self, simple_alloc_alloc, size, alignment) : simple_alloc_alloc(self, size);
} }
fn void*? SimpleHeapAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic fn void*? SimpleHeapAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic
{ {
return alignment > 0 return alignment > 0
? @aligned_realloc(self._calloc, self._free, old_pointer, size, alignment) ? @aligned_realloc_fn(self, simple_alloc_calloc, simple_alloc_free, old_pointer, size, alignment)
: self._realloc(old_pointer, size); : simple_alloc_realloc(self, old_pointer, size);
} }
fn void SimpleHeapAllocator.release(&self, void* old_pointer, bool aligned) @dynamic fn void SimpleHeapAllocator.release(&self, void* old_pointer, bool aligned) @dynamic
{ {
if (aligned) if (aligned)
{ {
@aligned_free(self._free, old_pointer)!!; @aligned_free_fn(self, simple_alloc_free, old_pointer)!!;
} }
else else
{ {
self._free(old_pointer); simple_alloc_free(self, old_pointer);
} }
} }
<* <*
@require old_pointer && bytes > 0 @require old_pointer && bytes > 0
*> *>
fn void*? SimpleHeapAllocator._realloc(&self, void* old_pointer, usz bytes) @local fn void*? simple_alloc_realloc(SimpleHeapAllocator* self, void* old_pointer, usz bytes) @local
{ {
// Find the block header. // Find the block header.
Header* block = (Header*)old_pointer - 1; Header* block = (Header*)old_pointer - 1;
if (block.size >= bytes) return old_pointer; if (block.size >= bytes) return old_pointer;
void* new = self._alloc(bytes)!; void* new = simple_alloc_alloc(self, bytes)!;
usz max_to_copy = math::min(block.size, bytes); usz max_to_copy = math::min(block.size, bytes);
mem::copy(new, old_pointer, max_to_copy); mem::copy(new, old_pointer, max_to_copy);
self._free(old_pointer); simple_alloc_free(self, old_pointer);
return new; return new;
} }
fn void*? SimpleHeapAllocator._calloc(&self, usz bytes) @local fn void*? simple_alloc_calloc(SimpleHeapAllocator* self, usz bytes) @local
{ {
void* data = self._alloc(bytes)!; void* data = simple_alloc_alloc(self, bytes)!;
mem::clear(data, bytes, mem::DEFAULT_MEM_ALIGNMENT); mem::clear(data, bytes, mem::DEFAULT_MEM_ALIGNMENT);
return data; return data;
} }
fn void*? SimpleHeapAllocator._alloc(&self, usz bytes) @local fn void*? simple_alloc_alloc(SimpleHeapAllocator* self, usz bytes) @local
{ {
usz aligned_bytes = mem::aligned_offset(bytes, mem::DEFAULT_MEM_ALIGNMENT); usz aligned_bytes = mem::aligned_offset(bytes, mem::DEFAULT_MEM_ALIGNMENT);
if (!self.free_list) if (!self.free_list)
{ {
self.add_block(aligned_bytes)!; simple_alloc_add_block(self, aligned_bytes)!;
} }
Header* current = self.free_list; Header* current = self.free_list;
@@ -123,22 +123,22 @@ fn void*? SimpleHeapAllocator._alloc(&self, usz bytes) @local
current = current.next; current = current.next;
} }
} }
self.add_block(aligned_bytes)!; simple_alloc_add_block(self, aligned_bytes)!;
return self._alloc(aligned_bytes); return simple_alloc_alloc(self, aligned_bytes);
} }
fn void? SimpleHeapAllocator.add_block(&self, usz aligned_bytes) @local fn void? simple_alloc_add_block(SimpleHeapAllocator* self, usz aligned_bytes) @local
{ {
assert(mem::aligned_offset(aligned_bytes, mem::DEFAULT_MEM_ALIGNMENT) == aligned_bytes); assert(mem::aligned_offset(aligned_bytes, mem::DEFAULT_MEM_ALIGNMENT) == aligned_bytes);
char[] result = self.alloc_fn(aligned_bytes + Header.sizeof)!; char[] result = self.alloc_fn(aligned_bytes + Header.sizeof)!;
Header* new_block = (Header*)result.ptr; Header* new_block = (Header*)result.ptr;
new_block.size = result.len - Header.sizeof; new_block.size = result.len - Header.sizeof;
new_block.next = null; new_block.next = null;
self._free(new_block + 1); simple_alloc_free(self, new_block + 1);
} }
fn void SimpleHeapAllocator._free(&self, void* ptr) @local fn void simple_alloc_free(SimpleHeapAllocator* self, void* ptr) @local
{ {
// Empty ptr -> do nothing. // Empty ptr -> do nothing.
if (!ptr) return; if (!ptr) return;

View File

@@ -127,7 +127,7 @@ fn void TempAllocator.reset(&self)
{ {
TempAllocator* old = child; TempAllocator* old = child;
child = old.derived; child = old.derived;
old.destroy(); temp_allocator_destroy(old);
} }
self.capacity = self.original_capacity; self.capacity = self.original_capacity;
$if env::ADDRESS_SANITIZER: $if env::ADDRESS_SANITIZER:
@@ -142,17 +142,17 @@ fn void TempAllocator.reset(&self)
fn void TempAllocator.free(&self) fn void TempAllocator.free(&self)
{ {
self.reset(); self.reset();
self.destroy(); temp_allocator_destroy(self);
} }
fn void TempAllocator.destroy(&self) @local fn void temp_allocator_destroy(TempAllocator* self)
{ {
TempAllocatorPage *last_page = self.last_page; TempAllocatorPage *last_page = self.last_page;
while (last_page) while (last_page)
{ {
TempAllocatorPage *to_free = last_page; TempAllocatorPage *to_free = last_page;
last_page = last_page.prev_page; last_page = last_page.prev_page;
self._free_page(to_free)!!; _free_page(self, to_free)!!;
} }
if (self.allocated) if (self.allocated)
{ {
@@ -179,33 +179,6 @@ fn void TempAllocator.release(&self, void* old_pointer, bool) @dynamic
} }
fn void? TempAllocator._free_page(&self, TempAllocatorPage* page) @inline @local
{
void* mem = page.start;
return self.backing_allocator.release(mem, page.is_aligned());
}
fn void*? TempAllocator._realloc_page(&self, TempAllocatorPage* page, usz size, usz alignment) @inline @local
{
// Then the actual start pointer:
void* real_pointer = page.start;
// Walk backwards to find the pointer to this page.
TempAllocatorPage **pointer_to_prev = &self.last_page;
// Remove the page from the list
while (*pointer_to_prev != page)
{
pointer_to_prev = &((*pointer_to_prev).prev_page);
}
*pointer_to_prev = page.prev_page;
usz page_size = page.pagesize();
// Clear on size > original size.
void* data = self.acquire(size, NO_ZERO, alignment)!;
if (page_size > size) page_size = size;
mem::copy(data, &page.data[0], page_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
self.backing_allocator.release(real_pointer, page.is_aligned());
return data;
}
fn void*? TempAllocator.resize(&self, void* pointer, usz size, usz alignment) @dynamic fn void*? TempAllocator.resize(&self, void* pointer, usz size, usz alignment) @dynamic
{ {
@@ -215,7 +188,7 @@ fn void*? TempAllocator.resize(&self, void* pointer, usz size, usz alignment) @d
assert(self.last_page, "Realloc of non temp pointer"); assert(self.last_page, "Realloc of non temp pointer");
// First grab the page // First grab the page
TempAllocatorPage *page = pointer - TempAllocatorPage.sizeof; TempAllocatorPage *page = pointer - TempAllocatorPage.sizeof;
return self._realloc_page(page, size, alignment); return _realloc_page(self, page, size, alignment);
} }
bool is_realloc_of_last = chunk.size + pointer == &self.data[self.used]; bool is_realloc_of_last = chunk.size + pointer == &self.data[self.used];
if (is_realloc_of_last) if (is_realloc_of_last)
@@ -326,9 +299,39 @@ fn void*? TempAllocator.acquire(&self, usz size, AllocInitType init_type, usz al
return &page.data[0]; return &page.data[0];
} }
fn void? _free_page(TempAllocator* self, TempAllocatorPage* page) @inline @local
{
void* mem = page.start;
return self.backing_allocator.release(mem, page.is_aligned());
}
fn void*? _realloc_page(TempAllocator* self, TempAllocatorPage* page, usz size, usz alignment) @inline @local
{
// Then the actual start pointer:
void* real_pointer = page.start;
// Walk backwards to find the pointer to this page.
TempAllocatorPage **pointer_to_prev = &self.last_page;
// Remove the page from the list
while (*pointer_to_prev != page)
{
pointer_to_prev = &((*pointer_to_prev).prev_page);
}
*pointer_to_prev = page.prev_page;
usz page_size = page.pagesize();
// Clear on size > original size.
void* data = self.acquire(size, NO_ZERO, alignment)!;
if (page_size > size) page_size = size;
mem::copy(data, &page.data[0], page_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
self.backing_allocator.release(real_pointer, page.is_aligned());
return data;
}
module std::core::mem::allocator @if((env::POSIX || env::WIN32) && $feature(VMEM_TEMP)); module std::core::mem::allocator @if((env::POSIX || env::WIN32) && $feature(VMEM_TEMP));
import std::math; import std::math;
tlocal VmemOptions temp_allocator_default_options = { tlocal VmemOptions temp_allocator_default_options = {
.shrink_on_reset = env::MEMORY_ENV != NORMAL, .shrink_on_reset = env::MEMORY_ENV != NORMAL,
.protect_unused_pages = env::COMPILER_OPT_LEVEL <= O1 || env::COMPILER_SAFE_MODE, .protect_unused_pages = env::COMPILER_OPT_LEVEL <= O1 || env::COMPILER_SAFE_MODE,
@@ -383,10 +386,10 @@ fn void TempAllocator.reset(&self)
} }
fn void TempAllocator.free(&self) fn void TempAllocator.free(&self)
{ {
self.destroy(); _destroy(self);
} }
fn void TempAllocator.destroy(&self) @local fn void _destroy(TempAllocator* self) @local
{ {
TempAllocator* child = self.derived; TempAllocator* child = self.derived;
if (!child) return; if (!child) return;
@@ -403,4 +406,4 @@ fn void*? TempAllocator.resize(&self, void* pointer, usz size, usz alignment) @d
fn void TempAllocator.release(&self, void* old_pointer, bool b) @dynamic fn void TempAllocator.release(&self, void* old_pointer, bool b) @dynamic
{ {
self.vmem.release(old_pointer, b) @inline; self.vmem.release(old_pointer, b) @inline;
} }

View File

@@ -631,7 +631,7 @@ fn void DString.reverse(self)
} }
} }
fn StringData* DString.data(self) @inline @private fn StringData* DString.data(self) @inline
{ {
return (StringData*)self; return (StringData*)self;
} }

View File

@@ -404,6 +404,28 @@ macro void*? @aligned_alloc(#alloc_fn, usz bytes, usz alignment)
return mem; return mem;
} }
<*
@require bytes > 0
@require alignment > 0
@require bytes <= isz.max
*>
macro void*? @aligned_alloc_fn(context, #alloc_fn, usz bytes, usz alignment)
{
if (alignment < void*.alignof) alignment = void*.alignof;
usz header = AlignedBlock.sizeof + alignment;
usz alignsize = bytes + header;
$if $kindof(#alloc_fn(context, bytes)) == OPTIONAL:
void* data = #alloc_fn(context, alignsize)!;
$else
void* data = #alloc_fn(context, alignsize);
$endif
void* mem = mem::aligned_pointer(data + AlignedBlock.sizeof, alignment);
AlignedBlock* desc = (AlignedBlock*)mem - 1;
assert(mem > data);
*desc = { bytes, data };
return mem;
}
struct AlignedBlock struct AlignedBlock
{ {
usz len; usz len;
@@ -420,6 +442,16 @@ macro void? @aligned_free(#free_fn, void* old_pointer)
$endif $endif
} }
macro void? @aligned_free_fn(context, #free_fn, void* old_pointer)
{
AlignedBlock* desc = (AlignedBlock*)old_pointer - 1;
$if $kindof(#free_fn(context, desc.start)) == OPTIONAL:
#free_fn(context, desc.start)!;
$else
#free_fn(context, desc.start);
$endif
}
<* <*
@require bytes > 0 @require bytes > 0
@require alignment > 0 @require alignment > 0
@@ -438,6 +470,23 @@ macro void*? @aligned_realloc(#calloc_fn, #free_fn, void* old_pointer, usz bytes
return new_data; return new_data;
} }
<*
@require bytes > 0
@require alignment > 0
*>
macro void*? @aligned_realloc_fn(context, #calloc_fn, #free_fn, void* old_pointer, usz bytes, usz alignment)
{
AlignedBlock* desc = (AlignedBlock*)old_pointer - 1;
void* data_start = desc.start;
void* new_data = @aligned_alloc_fn(context, #calloc_fn, bytes, alignment)!;
mem::copy(new_data, old_pointer, desc.len < bytes ? desc.len : bytes, 1, 1);
$if $kindof(#free_fn(context, data_start)) == OPTIONAL:
#free_fn(context, data_start)!;
$else
#free_fn(context, data_start);
$endif
return new_data;
}
// All allocators // All allocators
alias mem @builtin = thread_allocator ; alias mem @builtin = thread_allocator ;

View File

@@ -54,7 +54,7 @@ struct FixedBlockPool
@require calculate_actual_capacity(capacity, block_size) * block_size >= block_size @require calculate_actual_capacity(capacity, block_size) * block_size >= block_size
: "Total memory would overflow" : "Total memory would overflow"
*> *>
macro FixedBlockPool* FixedBlockPool.init(&self, Allocator allocator, usz block_size, usz capacity = INITIAL_CAPACITY, usz alignment = 0) fn FixedBlockPool* FixedBlockPool.init(&self, Allocator allocator, usz block_size, usz capacity = INITIAL_CAPACITY, usz alignment = 0)
{ {
self.allocator = allocator; self.allocator = allocator;
self.tail = &self.head; self.tail = &self.head;
@@ -64,7 +64,7 @@ macro FixedBlockPool* FixedBlockPool.init(&self, Allocator allocator, usz block_
self.alignment = allocator::alignment_for_allocation(alignment); self.alignment = allocator::alignment_for_allocation(alignment);
self.page_size = capacity * self.block_size; self.page_size = capacity * self.block_size;
assert(self.page_size >= self.block_size, "Total memory would overflow %d %d", block_size, capacity); assert(self.page_size >= self.block_size, "Total memory would overflow %d %d", block_size, capacity);
self.head.buffer = self.allocate_page(); self.head.buffer = fixedblockpool_allocate_page(self);
$if env::COMPILER_SAFE_MODE && env::ADDRESS_SANITIZER: $if env::COMPILER_SAFE_MODE && env::ADDRESS_SANITIZER:
asan::poison_memory_region(self.head.buffer, self.page_size); asan::poison_memory_region(self.head.buffer, self.page_size);
$endif $endif
@@ -119,7 +119,7 @@ fn void FixedBlockPool.free(&self)
$if env::COMPILER_SAFE_MODE && env::ADDRESS_SANITIZER: $if env::COMPILER_SAFE_MODE && env::ADDRESS_SANITIZER:
asan::unpoison_memory_region(self.head.buffer, self.page_size); asan::unpoison_memory_region(self.head.buffer, self.page_size);
$endif $endif
self.free_page(self.head.buffer); fixedblockpool_free_page(self, self.head.buffer);
FixedBlockPoolNode* iter = self.head.next; FixedBlockPoolNode* iter = self.head.next;
while (iter) while (iter)
@@ -127,7 +127,7 @@ fn void FixedBlockPool.free(&self)
$if env::COMPILER_SAFE_MODE && env::ADDRESS_SANITIZER: $if env::COMPILER_SAFE_MODE && env::ADDRESS_SANITIZER:
asan::unpoison_memory_region(iter.buffer, self.page_size); asan::unpoison_memory_region(iter.buffer, self.page_size);
$endif $endif
self.free_page(iter.buffer); fixedblockpool_free_page(self, iter.buffer);
FixedBlockPoolNode* current = iter; FixedBlockPoolNode* current = iter;
iter = iter.next; iter = iter.next;
allocator::free(self.allocator, current); allocator::free(self.allocator, current);
@@ -158,7 +158,7 @@ fn void* FixedBlockPool.alloc(&self)
} }
void* end = self.tail.buffer + (self.tail.capacity * self.block_size); void* end = self.tail.buffer + (self.tail.capacity * self.block_size);
if (self.next_free >= end) self.new_node(); if (self.next_free >= end) fixedblockpool_new_node(self);
void* ptr = self.next_free; void* ptr = self.next_free;
self.next_free += self.block_size; self.next_free += self.block_size;
$if env::COMPILER_SAFE_MODE && env::ADDRESS_SANITIZER: $if env::COMPILER_SAFE_MODE && env::ADDRESS_SANITIZER:
@@ -172,7 +172,7 @@ fn void* FixedBlockPool.alloc(&self)
Deallocate a block from the block pool Deallocate a block from the block pool
@require self.initialized : "The block pool must be initialized" @require self.initialized : "The block pool must be initialized"
@require self.check_ptr(ptr) : "The pointer should be part of the pool" @require fixedblockpool_check_ptr(self, ptr) : "The pointer should be part of the pool"
*> *>
fn void FixedBlockPool.dealloc(&self, void* ptr) fn void FixedBlockPool.dealloc(&self, void* ptr)
{ {
@@ -193,7 +193,7 @@ fn void FixedBlockPool.dealloc(&self, void* ptr)
<* <*
@require self.initialized : "The block pool must be initialized" @require self.initialized : "The block pool must be initialized"
*> *>
fn bool FixedBlockPool.check_ptr(&self, void *ptr) @local fn bool fixedblockpool_check_ptr(FixedBlockPool* self, void *ptr) @local
{ {
FixedBlockPoolNode* iter = &self.head; FixedBlockPoolNode* iter = &self.head;
@@ -210,10 +210,10 @@ fn bool FixedBlockPool.check_ptr(&self, void *ptr) @local
<* <*
@require self.grow_capacity > 0 : "How many blocks will it store" @require self.grow_capacity > 0 : "How many blocks will it store"
*> *>
fn void FixedBlockPool.new_node(&self) @local fn void fixedblockpool_new_node(FixedBlockPool* self) @local
{ {
FixedBlockPoolNode* node = allocator::new(self.allocator, FixedBlockPoolNode); FixedBlockPoolNode* node = allocator::new(self.allocator, FixedBlockPoolNode);
node.buffer = self.allocate_page(); node.buffer = fixedblockpool_allocate_page(self);
$if env::COMPILER_SAFE_MODE && env::ADDRESS_SANITIZER: $if env::COMPILER_SAFE_MODE && env::ADDRESS_SANITIZER:
asan::poison_memory_region(node.buffer, self.page_size); asan::poison_memory_region(node.buffer, self.page_size);
$endif $endif
@@ -224,14 +224,14 @@ fn void FixedBlockPool.new_node(&self) @local
self.allocated += node.capacity; self.allocated += node.capacity;
} }
macro void* FixedBlockPool.allocate_page(&self) @private macro void* fixedblockpool_allocate_page(FixedBlockPool* self) @private
{ {
return self.alignment > mem::DEFAULT_MEM_ALIGNMENT return self.alignment > mem::DEFAULT_MEM_ALIGNMENT
? allocator::calloc_aligned(self.allocator, self.page_size, self.alignment)!! ? allocator::calloc_aligned(self.allocator, self.page_size, self.alignment)!!
: allocator::calloc(self.allocator, self.page_size); : allocator::calloc(self.allocator, self.page_size);
} }
macro void FixedBlockPool.free_page(&self, void* page) @private macro void fixedblockpool_free_page(FixedBlockPool* self, void* page) @private
{ {
if (self.alignment > mem::DEFAULT_MEM_ALIGNMENT) if (self.alignment > mem::DEFAULT_MEM_ALIGNMENT)
{ {

View File

@@ -321,7 +321,7 @@ fn void? VirtualMemory.destroy(&self)
return release(self.ptr, self.size); return release(self.ptr, self.size);
} }
fn CInt VirtualMemoryAccess.to_posix(self) @if(env::POSIX) @private fn CInt VirtualMemoryAccess.to_posix(self) @if(env::POSIX)
{ {
switch (self) switch (self)
{ {
@@ -336,7 +336,7 @@ fn CInt VirtualMemoryAccess.to_posix(self) @if(env::POSIX) @private
} }
} }
fn Win32_Protect VirtualMemoryAccess.to_win32(self) @if(env::WIN32) @private fn Win32_Protect VirtualMemoryAccess.to_win32(self) @if(env::WIN32)
{ {
switch (self) switch (self)
{ {

View File

@@ -63,7 +63,7 @@ macro quarter_round(uint* x, int a, int b, int c, int d) @local
} }
<* Process the next (or final) chunk of ingested data. *> <* Process the next (or final) chunk of ingested data. *>
fn void ChaCha20.mutate_keystream(&self) @local @inline fn void chacha20_mutate_keystream(ChaCha20* self) @local @inline
{ {
self.key_stream[..] = self.state[..]; self.key_stream[..] = self.state[..];
@@ -137,7 +137,7 @@ fn void ChaCha20.transform(&self, char[] data)
for (usz x = offset; data.len >= BLOCK_SIZE; data = data[BLOCK_SIZE..], x = offset) for (usz x = offset; data.len >= BLOCK_SIZE; data = data[BLOCK_SIZE..], x = offset)
{ {
self.mutate_keystream(); chacha20_mutate_keystream(self);
if (offset) foreach (i, &b : data[:offset]) *b ^= key_stream[i]; if (offset) foreach (i, &b : data[:offset]) *b ^= key_stream[i];
char[] aligned_data = data[offset..]; char[] aligned_data = data[offset..];
for (; x <= (BLOCK_SIZE - usz.sizeof); x += usz.sizeof) for (; x <= (BLOCK_SIZE - usz.sizeof); x += usz.sizeof)
@@ -150,7 +150,7 @@ fn void ChaCha20.transform(&self, char[] data)
// 3. Process any remaining bytes. // 3. Process any remaining bytes.
if (data.len > 0) if (data.len > 0)
{ {
self.mutate_keystream(); chacha20_mutate_keystream(self);
for (usz i = 0; i < data.len; i++) data[i] ^= key_stream[i]; for (usz i = 0; i < data.len; i++) data[i] ^= key_stream[i];
self.position = data.len; self.position = data.len;
} }

View File

@@ -567,7 +567,7 @@ fn F25519Int F25519Int.inv(&s)
@param [&in] s @param [&in] s
*> *>
fn F25519Int F25519Int.pow_2523(&s) @local fn F25519Int pow_2523(F25519Int* s) @local
{ {
F25519Int r = *s; F25519Int r = *s;
@@ -587,7 +587,7 @@ fn F25519Int F25519Int.pow_2523(&s) @local
fn F25519Int F25519Int.sqrt(&s) fn F25519Int F25519Int.sqrt(&s)
{ {
F25519Int twice = s.mul_s(2); F25519Int twice = s.mul_s(2);
F25519Int pow = twice.pow_2523(); F25519Int pow = pow_2523(&twice);
return (twice * pow * pow - ONE) * s * pow; return (twice * pow * pow - ONE) * s * pow;
} }

View File

@@ -7,7 +7,7 @@ struct DelayedSchedulerEvent @local
Clock execution_time; Clock execution_time;
} }
fn int DelayedSchedulerEvent.compare_to(self, DelayedSchedulerEvent other) @local fn int DelayedSchedulerEvent.compare_to(self, DelayedSchedulerEvent other)
{ {
switch switch
{ {

View File

@@ -49,43 +49,43 @@ macro @round(r, m, $s, #v) @local
@g(r, m, $s, 7, #v[ 3], #v[ 4], #v[ 9], #v[14]); @g(r, m, $s, 7, #v[ 3], #v[ 4], #v[ 9], #v[14]);
} }
macro @common_compress(#instance, $rounds, $iv, $sigma, block) @local macro common_compress(instance, $rounds, $iv, $sigma, block) @local
{ {
$typeof(#instance.h[0])[16] m, v; $typeof(instance.h[0])[16] m, v;
((char*)&m)[:$sizeof(block)] = block[..]; ((char*)&m)[:$sizeof(block)] = block[..];
v[:8] = #instance.h[..]; v[:8] = instance.h[..];
v[ 8] = $iv[0]; v[ 8] = $iv[0];
v[ 9] = $iv[1]; v[ 9] = $iv[1];
v[10] = $iv[2]; v[10] = $iv[2];
v[11] = $iv[3]; v[11] = $iv[3];
v[12] = $iv[4] ^ #instance.t[0]; v[12] = $iv[4] ^ instance.t[0];
v[13] = $iv[5] ^ #instance.t[1]; v[13] = $iv[5] ^ instance.t[1];
v[14] = $iv[6] ^ #instance.f[0]; v[14] = $iv[6] ^ instance.f[0];
v[15] = $iv[7] ^ #instance.f[1]; v[15] = $iv[7] ^ instance.f[1];
$for usz $i = 0; $i < $rounds; $i++: $for usz $i = 0; $i < $rounds; $i++:
@round($i, m, $sigma, v); @round($i, m, $sigma, v);
$endfor $endfor
$for usz $i = 0; $i < 8; $i++: $for usz $i = 0; $i < 8; $i++:
#instance.h[$i] ^= v[$i] ^ v[$i + 8]; instance.h[$i] ^= v[$i] ^ v[$i + 8];
$endfor $endfor
} }
macro @add_ctr(#instance, usz amount) @local macro _add_ctr(instance, usz amount) @local
{ {
#instance.t[0] += ($typeof(#instance.t[0]))amount; instance.t[0] += ($typeof(instance.t[0]))amount;
#instance.t[1] += ($typeof(#instance.t[0]))(#instance.t[0] < amount); // adds 1 on overflow of [0] instance.t[1] += ($typeof(instance.t[0]))(instance.t[0] < amount); // adds 1 on overflow of [0]
} }
macro @common_init(#instance, $ParamType, $iv, usz out_len, char[] key = {}, char[] salt = {}, char[] personal = {}) @local macro common_init(instance, $ParamType, $iv, usz out_len, char[] key = {}, char[] salt = {}, char[] personal = {}) @local
{ {
mem::zero_volatile(@as_char_view(*#instance)); // explicitly because habits around hash init usually involve @noinit mem::zero_volatile(@as_char_view(*instance)); // explicitly because habits around hash init usually involve @noinit
#instance.h[..] = $iv[..]; instance.h[..] = $iv[..];
#instance.outlen = out_len; instance.outlen = out_len;
$ParamType p = { $ParamType p = {
.digest_length = (char)out_len, .digest_length = (char)out_len,
@@ -96,59 +96,60 @@ macro @common_init(#instance, $ParamType, $iv, usz out_len, char[] key = {}, cha
if (salt.len) p.salt[:salt.len] = salt[..]; if (salt.len) p.salt[:salt.len] = salt[..];
if (personal.len) p.personal[:personal.len] = personal[..]; if (personal.len) p.personal[:personal.len] = personal[..];
array::@zip_into(((char*)&#instance.h)[:$sizeof(p)], ((char*)&p)[:$sizeof(p)], fn (a, b) => a ^ b); // bytes(self.h) ^= bytes(p) array::@zip_into(((char*)&instance.h)[:$sizeof(p)], ((char*)&p)[:$sizeof(p)], fn (a, b) => a ^ b); // bytes(self.h) ^= bytes(p)
if (key.len) if (key.len)
{ {
char[$sizeof($iv[0])*16] dummy = {}; char[$sizeof($iv[0])*16] dummy = {};
dummy[:key.len] = key[..]; dummy[:key.len] = key[..];
#instance.update(dummy[..]); // consume a FULL block instance.update(dummy[..]); // consume a FULL block
mem::zero_volatile(dummy[..]); // do not optimize clearing this from the stack mem::zero_volatile(dummy[..]); // do not optimize clearing this from the stack
} }
} }
macro @common_update(#instance, $block_size, char[] data) @local macro common_update(instance, $block_size, char[] data) @local
{ {
if (@unlikely(!data.len)) return; if (@unlikely(!data.len)) return;
usz fill = $block_size - #instance.buflen; usz fill = $block_size - instance.buflen;
if (data.len > fill) if (data.len > fill)
{ {
#instance.buf[#instance.buflen:fill] = data[:fill]; instance.buf[instance.buflen:fill] = data[:fill];
#instance.buflen = 0; instance.buflen = 0;
@add_ctr(#instance, $block_size); _add_ctr(instance, $block_size);
#instance.compress(#instance.buf); instance._compress(instance.buf);
data = data[fill..]; data = data[fill..];
for (; data.len > $block_size; data = data[$block_size..]) for (; data.len > $block_size; data = data[$block_size..])
{ {
@add_ctr(#instance, $block_size); _add_ctr(instance, $block_size);
#instance.compress(data[:$block_size]); instance._compress(data[:$block_size]);
} }
} }
#instance.buf[#instance.buflen:data.len] = data[..]; instance.buf[instance.buflen:data.len] = data[..];
#instance.buflen += data.len; instance.buflen += data.len;
} }
macro @common_final(#instance, $output_length) @local macro common_final(instance, $output_length) @local
{ {
char[$output_length] result = {}; char[$output_length] result = {};
if ($output_length != #instance.outlen) return result; if ($output_length != instance.outlen) return result;
@add_ctr(#instance, #instance.buflen); _add_ctr(instance, instance.buflen);
if (#instance.f[0]) return result; // technically an error return if (instance.f[0]) return result; // technically an error return
if (#instance.last_node) #instance.f[1] = $typeof(#instance.h[0]).max; var $max = $typeof(instance.h[0]).max;
#instance.f[0] = $typeof(#instance.h[0]).max; if (instance.last_node) instance.f[1] = $max;
instance.f[0] = $max;
mem::zero_volatile(#instance.buf[#instance.buflen..]); // pad buffer with zeroes mem::zero_volatile(instance.buf[instance.buflen..]); // pad buffer with zeroes
#instance.compress(#instance.buf); instance._compress(instance.buf);
defer mem::zero_volatile(@as_char_view(*#instance)); // destroy the current context implicitly defer mem::zero_volatile(@as_char_view(*instance)); // destroy the current context implicitly
result[:#instance.outlen] = @as_char_view(#instance.h)[:#instance.outlen]; result[:instance.outlen] = @as_char_view(instance.h)[:instance.outlen];
return result; return result;
} }
@@ -244,13 +245,13 @@ alias b_512 = blake2b_512;
@require !personal.ptr || (personal.len > 0 && personal.len <= BLAKE2B_PERSONALBYTES) : "A specified personalization's length must be within the proper range." @require !personal.ptr || (personal.len > 0 && personal.len <= BLAKE2B_PERSONALBYTES) : "A specified personalization's length must be within the proper range."
*> *>
fn void Blake2b.init(&self, usz out_len, char[] key = {}, char[] salt = {}, char[] personal = {}) fn void Blake2b.init(&self, usz out_len, char[] key = {}, char[] salt = {}, char[] personal = {})
=> @common_init(self, Blake2bParam, BLAKE2B_IV, out_len, key, salt, personal); => common_init(self, Blake2bParam, BLAKE2B_IV, out_len, key, salt, personal);
<* <*
Core compression inline function for Blake2b. Core compression inline function for Blake2b.
*> *>
fn void Blake2b.compress(&self, char[BLAKE2B_BLOCKBYTES] block) @local @inline fn void Blake2b._compress(&self, char[BLAKE2B_BLOCKBYTES] block) @inline
=> @common_compress(self, 12, BLAKE2B_IV, BLAKE2B_SIGMA, block); => common_compress(self, 12, BLAKE2B_IV, BLAKE2B_SIGMA, block);
<* <*
Add more data to the hash context or stream. Add more data to the hash context or stream.
@@ -258,7 +259,7 @@ fn void Blake2b.compress(&self, char[BLAKE2B_BLOCKBYTES] block) @local @inline
@param[in] data : "The data to ingest into the hash context." @param[in] data : "The data to ingest into the hash context."
*> *>
fn void Blake2b.update(&self, char[] data) fn void Blake2b.update(&self, char[] data)
=> @common_update(self, BLAKE2B_BLOCKBYTES, data); => common_update(self, BLAKE2B_BLOCKBYTES, data);
<* <*
Finalize the hash context and return the hash result at the given size. Finalize the hash context and return the hash result at the given size.
@@ -267,9 +268,12 @@ fn void Blake2b.update(&self, char[] data)
@require $output_length == self.outlen : "The specified compile-time output size MUST be equal to the initialized output size." @require $output_length == self.outlen : "The specified compile-time output size MUST be equal to the initialized output size."
*> *>
macro char[*] Blake2b.final(&self, $output_length) macro char[*] Blake2b.final(&self, $output_length) => _blake2b_final{$output_length}(self);
=> @common_final(self, $output_length);
fn char[OUTPUT_LENGTH] _blake2b_final(Blake2b* self) <OUTPUT_LENGTH> @local
{
return common_final(self, OUTPUT_LENGTH);
}
// ====================================================================================== // ======================================================================================
// BEGIN Blake2s contents. Do not separate this from Blake2b: there's not really a point. // BEGIN Blake2s contents. Do not separate this from Blake2b: there's not really a point.
@@ -356,13 +360,13 @@ alias s_256 = blake2s_256;
@require !personal.ptr || (personal.len > 0 && personal.len <= BLAKE2B_PERSONALBYTES) : "A specified personalization's length must be within the proper range." @require !personal.ptr || (personal.len > 0 && personal.len <= BLAKE2B_PERSONALBYTES) : "A specified personalization's length must be within the proper range."
*> *>
fn void Blake2s.init(&self, usz out_len, char[] key = {}, char[] salt = {}, char[] personal = {}) fn void Blake2s.init(&self, usz out_len, char[] key = {}, char[] salt = {}, char[] personal = {})
=> @common_init(self, Blake2sParam, BLAKE2S_IV, out_len, key, salt, personal); => common_init(self, Blake2sParam, BLAKE2S_IV, out_len, key, salt, personal);
<* <*
Core compression inline function for Blake2s. Core compression inline function for Blake2s.
*> *>
fn void Blake2s.compress(&self, char[BLAKE2S_BLOCKBYTES] block) @local @inline fn void Blake2s._compress(&self, char[BLAKE2S_BLOCKBYTES] block) @inline
=> @common_compress(self, 10, BLAKE2S_IV, BLAKE2S_SIGMA, block); => common_compress(self, 10, BLAKE2S_IV, BLAKE2S_SIGMA, block);
<* <*
Add more data to the hash context or stream. Add more data to the hash context or stream.
@@ -370,7 +374,7 @@ fn void Blake2s.compress(&self, char[BLAKE2S_BLOCKBYTES] block) @local @inline
@param[in] data : "The data to ingest into the hash context." @param[in] data : "The data to ingest into the hash context."
*> *>
fn void Blake2s.update(&self, char[] data) fn void Blake2s.update(&self, char[] data)
=> @common_update(self, BLAKE2S_BLOCKBYTES, data); => common_update(self, BLAKE2S_BLOCKBYTES, data);
<* <*
Finalize the hash context and return the hash result at the given size. Finalize the hash context and return the hash result at the given size.
@@ -380,4 +384,4 @@ fn void Blake2s.update(&self, char[] data)
@require $output_length == self.outlen : "The specified compile-time output size MUST be equal to the initialized output size." @require $output_length == self.outlen : "The specified compile-time output size MUST be equal to the initialized output size."
*> *>
macro char[*] Blake2s.final(&self, $output_length) macro char[*] Blake2s.final(&self, $output_length)
=> @common_final(self, $output_length); => common_final(self, $output_length);

View File

@@ -246,7 +246,7 @@ fn void Blake3.init(&self, char[] key = {}, char explicit_flags = 0)
<* <*
Reset the state of the hashing context, in case it should be reused without reloading the key value. Reset the state of the hashing context, in case it should be reused without reloading the key value.
*> *>
fn void Blake3.reset(&self) @local @inline fn void _reset(Blake3* self) @local @inline
{ {
self.chunk.reset(self.key[..], 0); self.chunk.reset(self.key[..], 0);
self.cv_stack_len = 0; self.cv_stack_len = 0;
@@ -255,7 +255,7 @@ fn void Blake3.reset(&self) @local @inline
<* <*
Private function to merge tree results. Private function to merge tree results.
*> *>
fn void Blake3.merge_cv_stack(&self, ulong total_len) @local @inline fn void _merge_cv_stack(Blake3* self, ulong total_len) @local @inline
{ {
usz post_merge_stack_len = (usz)@popcnt(total_len); usz post_merge_stack_len = (usz)@popcnt(total_len);
for (; self.cv_stack_len > post_merge_stack_len; self.cv_stack_len--) for (; self.cv_stack_len > post_merge_stack_len; self.cv_stack_len--)
@@ -269,9 +269,9 @@ fn void Blake3.merge_cv_stack(&self, ulong total_len) @local @inline
<* <*
Private function to add a new tree onto the stack. Private function to add a new tree onto the stack.
*> *>
fn void Blake3.push_cv(&self, char* new_cv, ulong chunk_counter) @local @inline fn void Blake3.push_cv(&self, char* new_cv, ulong chunk_counter) @inline
{ {
self.merge_cv_stack(chunk_counter); _merge_cv_stack(self, chunk_counter);
self.cv_stack[self.cv_stack_len * OUT_SIZE : OUT_SIZE] = new_cv[:OUT_SIZE]; self.cv_stack[self.cv_stack_len * OUT_SIZE : OUT_SIZE] = new_cv[:OUT_SIZE];
self.cv_stack_len++; self.cv_stack_len++;
} }
@@ -334,7 +334,7 @@ fn void Blake3.update(&self, char[] input, bool use_tbb = false)
if (input.len > 0) if (input.len > 0)
{ {
self.chunk.update(input); self.chunk.update(input);
self.merge_cv_stack(self.chunk.chunk_counter); _merge_cv_stack(self, self.chunk.chunk_counter);
} }
} }
@@ -400,7 +400,7 @@ fn void Blake3.destroy(&self) @inline
@param [in] key @param [in] key
@param flags @param flags
*> *>
fn void Blake3ChunkState.init(&self, uint[] key, char flags) @local @inline fn void Blake3ChunkState.init(&self, uint[] key, char flags) @inline
{ {
mem::zero_volatile(@as_char_view(*self)); mem::zero_volatile(@as_char_view(*self));
self.cv[..] = key[..]; self.cv[..] = key[..];
@@ -413,7 +413,7 @@ fn void Blake3ChunkState.init(&self, uint[] key, char flags) @local @inline
@param [in] key @param [in] key
@param chunk_counter @param chunk_counter
*> *>
fn void Blake3ChunkState.reset(&self, uint[] key, ulong chunk_counter) @local @inline fn void Blake3ChunkState.reset(&self, uint[] key, ulong chunk_counter) @inline
{ {
self.init(key, self.flags); // maintain its own flags self.init(key, self.flags); // maintain its own flags
self.chunk_counter = chunk_counter; // update chunk counter self.chunk_counter = chunk_counter; // update chunk counter
@@ -422,7 +422,7 @@ fn void Blake3ChunkState.reset(&self, uint[] key, ulong chunk_counter) @local @i
<* <*
Get bytes length of consumed data. Get bytes length of consumed data.
*> *>
fn usz Blake3ChunkState.len(&self) @operator(len) @local @inline fn usz Blake3ChunkState.len(&self) @operator(len) @inline
=> (BLOCK_SIZE * (usz)self.blocks_compressed) + (usz)self.buf_len; => (BLOCK_SIZE * (usz)self.blocks_compressed) + (usz)self.buf_len;
<* <*
@@ -430,7 +430,7 @@ fn usz Blake3ChunkState.len(&self) @operator(len) @local @inline
@param [in] data : "Data to ingest." @param [in] data : "Data to ingest."
*> *>
fn usz Blake3ChunkState.fill_buf(&self, char[] data) @local @inline fn usz Blake3ChunkState.fill_buf(&self, char[] data) @inline
{ {
usz take = min(BLOCK_SIZE - (usz)self.buf_len, data.len); usz take = min(BLOCK_SIZE - (usz)self.buf_len, data.len);
self.buf[self.buf_len:take] = data[:take]; self.buf[self.buf_len:take] = data[:take];
@@ -441,7 +441,7 @@ fn usz Blake3ChunkState.fill_buf(&self, char[] data) @local @inline
<* <*
Determine whether to set the CHUNK_START flag. Determine whether to set the CHUNK_START flag.
*> *>
fn char Blake3ChunkState.maybe_start_flag(&self) @local @inline fn char Blake3ChunkState.maybe_start_flag(&self) @inline
=> !self.blocks_compressed ? Blake3Flags.CHUNK_START : 0; => !self.blocks_compressed ? Blake3Flags.CHUNK_START : 0;
<* <*
@@ -449,7 +449,7 @@ fn char Blake3ChunkState.maybe_start_flag(&self) @local @inline
@param [in] input : "Incoming bytes to update with." @param [in] input : "Incoming bytes to update with."
*> *>
fn void Blake3ChunkState.update(&self, char[] input) @local fn void Blake3ChunkState.update(&self, char[] input)
{ {
if (self.buf_len) if (self.buf_len)
{ {
@@ -473,7 +473,7 @@ fn void Blake3ChunkState.update(&self, char[] input) @local
<* <*
Convert the chunk state to an "output" type with the right flags. Convert the chunk state to an "output" type with the right flags.
*> *>
fn Blake3Output Blake3ChunkState.output(&self) @local @inline fn Blake3Output Blake3ChunkState.output(&self) @inline
=> make_output(self.cv[..], &self.buf, self.buf_len, self.chunk_counter, self.flags | self.maybe_start_flag() | Blake3Flags.CHUNK_END); => make_output(self.cv[..], &self.buf, self.buf_len, self.chunk_counter, self.flags | self.maybe_start_flag() | Blake3Flags.CHUNK_END);
<* <*
@@ -511,7 +511,7 @@ macro Blake3Output parent_output(char* block, uint[] key, char flags) @local
@param [&inout] cv @param [&inout] cv
*> *>
macro void Blake3Output.chaining_value(&self, char* cv) @local macro void Blake3Output.chaining_value(&self, char* cv)
{ {
uint[KEY_SIZE_WORDS] cv_words; uint[KEY_SIZE_WORDS] cv_words;
cv_words[..] = self.input_cv[..]; cv_words[..] = self.input_cv[..];
@@ -525,7 +525,7 @@ macro void Blake3Output.chaining_value(&self, char* cv) @local
@param seek @param seek
@param [inout] into @param [inout] into
*> *>
fn void Blake3Output.root_bytes(&self, usz seek, char[] into) @local fn void Blake3Output.root_bytes(&self, usz seek, char[] into)
{ {
if (!into.len) return; if (!into.len) return;

View File

@@ -147,13 +147,13 @@ fn void Streebog.update(&self, char[] data)
macro char[*] Streebog.final(&self, StreebogLength $hash_size) macro char[*] Streebog.final(&self, StreebogLength $hash_size)
{ {
char[$hash_size] result; char[$hash_size] result;
self._final_private(); streebog_final_private(self);
defer mem::zero_volatile(@as_char_view(*self)); // implicitly clear the structure when finalized defer mem::zero_volatile(@as_char_view(*self)); // implicitly clear the structure when finalized
result[..] = @as_char_view(self.h)[(BLOCK_SIZE - $hash_size)..]; result[..] = @as_char_view(self.h)[(BLOCK_SIZE - $hash_size)..];
return result; return result;
} }
fn void Streebog._final_private(&self) @local fn void streebog_final_private(Streebog* self) @local
{ {
ulong[8] unprocessed_bits_count; ulong[8] unprocessed_bits_count;
usz index = self.index >> 3; usz index = self.index >> 3;

View File

@@ -86,14 +86,14 @@ fn void Poly1305.update(&self, char[] input)
} }
// ingest up to a block size to finish the partial, then advance the slice ptr // ingest up to a block size to finish the partial, then advance the slice ptr
self.temp[self.num:rem] = input[:rem]; self.temp[self.num:rem] = input[:rem];
self.blocks(self.temp[..]); _blocks(self, self.temp[..]);
input = input[rem..]; input = input[rem..];
} }
usz even_length = input.len - (input.len % BLOCK_SIZE); usz even_length = input.len - (input.len % BLOCK_SIZE);
if (even_length >= BLOCK_SIZE) if (even_length >= BLOCK_SIZE)
{ {
self.blocks(input[:even_length]); // consume blocks _blocks(self, input[:even_length]); // consume blocks
input = input[even_length..]; // scroll to end (remainder) input = input[even_length..]; // scroll to end (remainder)
} }
@@ -109,7 +109,7 @@ fn char[TAG_SIZE] Poly1305.final(&self)
{ {
self.temp[self.num++] = 1; // partial blocks must end with 0x01 self.temp[self.num++] = 1; // partial blocks must end with 0x01
self.temp[self.num..] = {}; // explicit zeros on the rest self.temp[self.num..] = {}; // explicit zeros on the rest
self.blocks(self.temp[..], 0); // chomp _blocks(self, self.temp[..], 0); // chomp
} }
uint128 t = (uint128)self.h[0] + 5; uint128 t = (uint128)self.h[0] + 5;
@@ -135,7 +135,7 @@ fn char[TAG_SIZE] Poly1305.final(&self)
} }
fn void Poly1305.blocks(&self, char[] input, ulong pad_bit = 1) @local fn void _blocks(Poly1305* self, char[] input, ulong pad_bit = 1) @local
{ {
for (; input.len >= BLOCK_SIZE; input = input[BLOCK_SIZE..]) for (; input.len >= BLOCK_SIZE; input = input[BLOCK_SIZE..])
{ {

View File

@@ -68,18 +68,18 @@ fn void Sha256.update(&self, char[] data)
usz len = min(BLOCK_SIZE - buffer_pos, data.len); usz len = min(BLOCK_SIZE - buffer_pos, data.len);
self.buffer[buffer_pos:len] = data[:len]; self.buffer[buffer_pos:len] = data[:len];
data = data[len..]; data = data[len..];
if (buffer_pos + len == BLOCK_SIZE) self.transform(); if (buffer_pos + len == BLOCK_SIZE) _transform(self);
} }
// When the data pointer is aligned, we can disregard unaligned loading in the `transform` macro. // When the data pointer is aligned, we can disregard unaligned loading in the `transform` macro.
// We do this here from the outer call to reduce the expense of checking alignment on every single block. // We do this here from the outer call to reduce the expense of checking alignment on every single block.
if (0 == (usz)data.ptr % usz.sizeof) if (0 == (usz)data.ptr % usz.sizeof)
{ {
for (; data.len >= BLOCK_SIZE; data = data[BLOCK_SIZE..]) self.transform((uint*)data.ptr); for (; data.len >= BLOCK_SIZE; data = data[BLOCK_SIZE..]) _transform(self, (uint*)data.ptr);
} }
else else
{ {
for (; data.len >= BLOCK_SIZE; data = data[BLOCK_SIZE..]) self.transform_unaligned((uint*)data.ptr); for (; data.len >= BLOCK_SIZE; data = data[BLOCK_SIZE..]) _transform_unaligned(self, (uint*)data.ptr);
} }
// Leftover data just gets stored away for the next update or final. // Leftover data just gets stored away for the next update or final.
@@ -102,7 +102,7 @@ fn char[HASH_SIZE] Sha256.final(&self)
if (i > BLOCK_SIZE - 8) if (i > BLOCK_SIZE - 8)
{ {
self.buffer[i..] = 0x00; self.buffer[i..] = 0x00;
self.transform(); _transform(self);
i = 0; // Reset buffer index after transformation i = 0; // Reset buffer index after transformation
} }
@@ -111,7 +111,7 @@ fn char[HASH_SIZE] Sha256.final(&self)
// Append the bitcount in big-endian format // Append the bitcount in big-endian format
*(ulong*)(&self.buffer[BLOCK_SIZE - 8]) = env::BIG_ENDIAN ??? self.bitcount : bswap(self.bitcount); *(ulong*)(&self.buffer[BLOCK_SIZE - 8]) = env::BIG_ENDIAN ??? self.bitcount : bswap(self.bitcount);
self.transform(); _transform(self);
// Convert state to the final hash // Convert state to the final hash
foreach (x, s : self.state) *(uint*)(&hash[x * uint.sizeof]) = env::BIG_ENDIAN ??? s : bswap(s); foreach (x, s : self.state) *(uint*)(&hash[x * uint.sizeof]) = env::BIG_ENDIAN ??? s : bswap(s);
@@ -121,10 +121,10 @@ fn char[HASH_SIZE] Sha256.final(&self)
// These wrappers are necessary to significantly reduce code generation from macro expansions. // These wrappers are necessary to significantly reduce code generation from macro expansions.
// Note that transformations on `self.buffer` (when incoming == null) should always be aligned. // Note that transformations on `self.buffer` (when incoming == null) should always be aligned.
fn void Sha256.transform(&self, uint* incoming = null) @local @noinline => self.do_transform(incoming, true); fn void _transform(Sha256* self, uint* incoming = null) @local @noinline => _do_transform(self, incoming, true);
fn void Sha256.transform_unaligned(&self, uint* incoming = null) @local @noinline => self.do_transform(incoming, false); fn void _transform_unaligned(Sha256* self, uint* incoming = null) @local @noinline => _do_transform(self, incoming, false);
macro Sha256.do_transform(&self, uint* incoming = null, bool $aligned = true) @local macro _do_transform(Sha256* self, uint* incoming = null, bool $aligned = true) @local
{ {
uint a, b, c, d, e, f, g, h, t1, t2 @noinit; uint a, b, c, d, e, f, g, h, t1, t2 @noinit;
uint[64] m @noinit; uint[64] m @noinit;

View File

@@ -100,7 +100,7 @@ fn void SipHash.update(&self, char[] data)
self.v[3] ^= self.m; self.v[3] ^= self.m;
$for var $i = 0; $i < BLOCK_ROUNDS; ++$i : // unrolled loop $for var $i = 0; $i < BLOCK_ROUNDS; ++$i : // unrolled loop
self.round(); siphash_round(self);
$endfor $endfor
self.v[0] ^= self.m; self.v[0] ^= self.m;
@@ -123,7 +123,7 @@ fn OutType SipHash.final(&self)
$endif $endif
$for var $i = 0; $i < FINALIZE_ROUNDS; ++$i : // unrolled loop $for var $i = 0; $i < FINALIZE_ROUNDS; ++$i : // unrolled loop
self.round(); siphash_round(self);
$endfor $endfor
$if OutType.typeid == ulong.typeid : $if OutType.typeid == ulong.typeid :
@@ -134,7 +134,7 @@ fn OutType SipHash.final(&self)
self.v[1] ^= 0xDD; self.v[1] ^= 0xDD;
$for var $i = 0; $i < FINALIZE_ROUNDS; ++$i : // unrolled loop $for var $i = 0; $i < FINALIZE_ROUNDS; ++$i : // unrolled loop
self.round(); siphash_round(self);
$endfor $endfor
return lo | ((uint128)(self.v[0] ^ self.v[1] ^ self.v[2] ^ self.v[3]) << 64); return lo | ((uint128)(self.v[0] ^ self.v[1] ^ self.v[2] ^ self.v[3]) << 64);
@@ -142,7 +142,7 @@ fn OutType SipHash.final(&self)
} }
fn void SipHash.round(&self) @local fn void siphash_round(SipHash* self) @local
{ {
self.v[0] += self.v[1]; self.v[0] += self.v[1];
self.v[1] = self.v[1].rotl(13); self.v[1] = self.v[1].rotl(13);

View File

@@ -66,14 +66,14 @@ fn void Whirlpool.update(&self, char[] data)
// If the algorithm is finalized during a 'partial' block, it has its own padding to fill the remaining gap. // If the algorithm is finalized during a 'partial' block, it has its own padding to fill the remaining gap.
if (data.len < to_pad) return; if (data.len < to_pad) return;
self.process_block(&self.block); _process_block(self, &self.block);
data = data[to_pad..]; data = data[to_pad..];
} }
// Digest blocks wholesale. // Digest blocks wholesale.
while (data.len >= BLOCK_SIZE) while (data.len >= BLOCK_SIZE)
{ {
self.process_block(data); _process_block(self, data);
data = (data.len > BLOCK_SIZE) ? data[BLOCK_SIZE..] : {}; data = (data.len > BLOCK_SIZE) ? data[BLOCK_SIZE..] : {};
} }
@@ -100,7 +100,7 @@ fn char[HASH_SIZE] Whirlpool.final(&self)
{ {
if (remainder < 64) self.block[remainder..63] = 0x00; if (remainder < 64) self.block[remainder..63] = 0x00;
self.process_block(&self.block); _process_block(self, &self.block);
remainder = 0; remainder = 0;
} }
@@ -113,7 +113,7 @@ fn char[HASH_SIZE] Whirlpool.final(&self)
self.block_128[3] = $$bswap(self.counter_low << 3); self.block_128[3] = $$bswap(self.counter_low << 3);
// Process the final block. // Process the final block.
self.process_block(&self.block); _process_block(self, &self.block);
// Each ulong in the resultant hash should be bit-swapped before the final return. // Each ulong in the resultant hash should be bit-swapped before the final return.
char[HASH_SIZE] hash @align(ulong.alignof); char[HASH_SIZE] hash @align(ulong.alignof);
@@ -153,7 +153,7 @@ const ulong[10] RC @private = {
}; };
const ROUNDS = 10; const ROUNDS = 10;
fn void Whirlpool.process_block(&self, char* block) @local fn void _process_block(Whirlpool* self, char* block) @local
{ {
ulong[2 * 8] k; // key ulong[2 * 8] k; // key
ulong[2 * 8] state; // state ulong[2 * 8] state; // state

View File

@@ -91,16 +91,7 @@ fn void Formatter.init(&self, OutputFn out_fn, void* data = null)
*self = { .data = data, .out_fn = out_fn}; *self = { .data = data, .out_fn = out_fn};
} }
fn usz? Formatter.out(&self, char c) @private
{
if (catch err = self.out_fn(self.data, c))
{
if (self.first_fault) return self.first_fault~;
self.first_fault = err;
return err~;
}
return 1;
}
fn usz? Formatter.print_with_function(&self, Printable arg) fn usz? Formatter.print_with_function(&self, Printable arg)
{ {
@@ -115,7 +106,7 @@ fn usz? Formatter.print_with_function(&self, Printable arg)
self.width = old_width; self.width = old_width;
self.prec = old_prec; self.prec = old_prec;
} }
if (!arg) return self.out_substr("(null)"); if (!arg) return formatter_out_substr(self, "(null)");
return arg.to_format(self); return arg.to_format(self);
} }
if (&arg.to_constant_string) if (&arg.to_constant_string)
@@ -129,161 +120,12 @@ fn usz? Formatter.print_with_function(&self, Printable arg)
self.width = old_width; self.width = old_width;
self.prec = old_prec; self.prec = old_prec;
} }
if (!arg) return self.out_substr("(null)"); if (!arg) return formatter_out_substr(self, "(null)");
return self.out_substr(arg.to_constant_string()); return formatter_out_substr(self, arg.to_constant_string());
} }
return NOT_FOUND~; return NOT_FOUND~;
} }
fn usz? Formatter.out_unknown(&self, String category, any arg) @private
{
return self.out_substr("<") + self.out_substr(category) + self.out_substr(" type:") + self.ntoa((iptr)arg.type, false, 16) + self.out_substr(", addr:") + self.ntoa((iptr)arg.ptr, false, 16) + self.out_substr(">");
}
fn usz? Formatter.out_collection(&self, any arg, String open, String close) @private
{
typeid inner = arg.type.inner;
if (inner == void.typeid) inner = char.typeid;
usz size = inner.sizeof;
usz alen;
void* data_ptr;
if (arg.type.kindof == SLICE)
{
String* temp = arg.ptr;
data_ptr = temp.ptr;
alen = temp.len;
}
else
{
data_ptr = arg.ptr;
alen = arg.type.len;
}
PrintFlags flags = self.flags;
uint width = self.width;
defer
{
self.flags = flags;
self.width = width;
}
self.flags = {};
self.width = 0;
usz len = self.out_substr(open)!;
for (usz i = 0; i < alen; i++)
{
if (i != 0) len += self.out_substr(", ")!;
len += self.out_str(any_make(data_ptr, inner))!;
data_ptr += size;
}
len += self.out_substr(close)!;
return len;
}
fn usz? Formatter.out_str(&self, any arg) @private
{
switch (arg.type.kindof)
{
case VOID:
return self.out_substr("void");
case FAULT:
fault f = *(fault*)arg.ptr;
return self.out_substr(f ? f.nameof : "(empty-fault)");
case INTERFACE:
any a = *(any*)arg;
return a ? self.out_str(a) : self.out_substr("(empty-interface)");
case ANY:
any a = *(any*)arg;
return a ? self.out_str(a) : self.out_substr("(empty-any)");
case OPTIONAL:
unreachable();
case SIGNED_INT:
case UNSIGNED_INT:
case FLOAT:
case FUNC:
case POINTER:
PrintFlags flags = self.flags;
uint width = self.width;
defer
{
self.flags = flags;
self.width = width;
}
self.flags = {};
self.width = 0;
switch (arg.type.kindof)
{
case SIGNED_INT:
case UNSIGNED_INT:
return self.ntoa_any(arg, 10) ?? self.out_substr("<INVALID>");
case FLOAT:
return self.ftoa(float_from_any(arg)) ?? self.out_substr("ERR");
case FUNC:
case POINTER:
if (arg.type.kindof == POINTER && arg.type.inner != void.typeid)
{
void** pointer = arg.ptr;
any deref = any_make(*pointer, arg.type.inner);
usz? n = self.print_with_function((Printable)deref);
if (try n) return n;
if (@catch(n) != NOT_FOUND) n!;
}
return self.out_substr("0x")! + self.ntoa_any(arg, 16);
default:
unreachable();
}
case BOOL:
return self.out_substr(*(bool*)arg.ptr ? "true" : "false");
default:
}
usz? n = self.print_with_function((Printable)arg);
if (try n) return n;
if (@catch(n) != NOT_FOUND) n!;
switch (arg.type.kindof)
{
case TYPEID:
return self.out_substr("typeid[")! + self.ntoa((iptr)*(typeid*)arg, false, 16)! + self.out_substr("]")!;
case ENUM:
usz i = types::any_to_enum_ordinal(arg, usz)!!;
assert(i < arg.type.names.len, "Illegal enum value found, numerical value was %d.", i);
return self.out_substr(arg.type.names[i]);
case STRUCT:
return self.out_unknown("struct", arg);
case UNION:
return self.out_unknown("union", arg);
case BITSTRUCT:
return self.out_unknown("bitstruct", arg);
case CONST_ENUM:
case DISTINCT:
if (arg.type == String.typeid)
{
return self.out_substr(*(String*)arg);
}
if (arg.type == ZString.typeid)
{
return self.out_substr(*(ZString*)arg ? ((ZString*)arg).str_view() : "(null)");
}
if (arg.type == DString.typeid)
{
return self.out_substr(*(DString*)arg ? ((DString*)arg).str_view() : "(null)");
}
return self.out_str(arg.as_inner());
case ARRAY:
return self.out_collection(arg, "[", "]");
case VECTOR:
return self.out_collection(arg, "[<", ">]");
case SLICE:
return self.out_collection(arg, "[", "]");
case ANY:
case INTERFACE:
unreachable("Already handled");
default:
}
return self.out_substr("Invalid type");
}
fn void? out_null_fn(void* data @unused, char c @unused) @private fn void? out_null_fn(void* data @unused, char c @unused) @private
{ {
@@ -291,7 +133,7 @@ fn void? out_null_fn(void* data @unused, char c @unused) @private
macro usz? @report_fault(Formatter* f, $fault) macro usz? @report_fault(Formatter* f, $fault)
{ {
(void)f.out_substr($fault); (void)formatter_out_substr(f, $fault);
return INVALID_FORMAT~; return INVALID_FORMAT~;
} }
@@ -307,69 +149,14 @@ macro usz? @wrap_bad(Formatter* f, #action)
return f.first_err(err)~; return f.first_err(err)~;
default: default:
err = f.first_err(INVALID_ARGUMENT); err = f.first_err(INVALID_ARGUMENT);
f.out_substr("<INVALID>")!; formatter_out_substr(f, "<INVALID>")!;
return err~; return err~;
} }
} }
return len; return len;
} }
fn usz? Formatter.out_hex_buffer(&self, any arg) @private @inline
{
char[] out @noinit;
switch (arg.type)
{
case char[]:
case ichar[]:
out = *(char[]*)arg;
default:
if (arg.type.kindof == ARRAY && (arg.type.inner == char.typeid || arg.type.inner == ichar.typeid))
{
out = ((char*)arg.ptr)[:arg.type.sizeof];
break;
}
if (arg.type.kindof == POINTER)
{
// Maybe there is a more idiomatic way here
out = ((*(char**)arg.ptr))[:arg.type.inner.sizeof];
break;
}
return self.out_substr("<INVALID>");
}
usz len = out.len * 2;
usz total;
if (self.flags.left)
{
total += print_hex_chars(self, out, self.flags.uppercase)!;
total += self.pad(' ', self.width, (isz)total)!;
}
else
{
if (self.width) total += self.pad(' ', self.width, (isz)len)!;
total += print_hex_chars(self, out, self.flags.uppercase)!;
}
return total;
}
fn usz? Formatter.out_str_pad(&self, any arg) @private @inline
{
usz total;
if (self.width && !self.flags.left)
{
OutputFn out_fn = self.out_fn;
self.out_fn = (OutputFn)&out_null_fn;
usz len = self.out_str(arg)!;
self.out_fn = out_fn;
total += self.pad(' ', self.width, (isz)len)!;
}
usz len = self.out_str(arg)!;
total += len;
if (self.flags.left)
{
total += self.pad(' ', self.width, (isz)len)!;
}
return total;
}
fn usz? Formatter.vprintf(&self, String format, any[] anys) fn usz? Formatter.vprintf(&self, String format, any[] anys)
{ {
@@ -389,7 +176,7 @@ fn usz? Formatter.vprintf(&self, String format, any[] anys)
if (c != '%') if (c != '%')
{ {
// no // no
total_len += self.out(c)!; total_len += self.print_char(c)!;
continue; continue;
} }
i++; i++;
@@ -397,7 +184,7 @@ fn usz? Formatter.vprintf(&self, String format, any[] anys)
c = format[i]; c = format[i];
if (c == '%') if (c == '%')
{ {
total_len += self.out(c)!; total_len += self.print_char(c)!;
continue; continue;
} }
// evaluate flags // evaluate flags
@@ -443,7 +230,7 @@ fn usz? Formatter.vprintf(&self, String format, any[] anys)
if (variant_index >= anys.len) if (variant_index >= anys.len)
{ {
self.first_err(NOT_ENOUGH_ARGUMENTS); self.first_err(NOT_ENOUGH_ARGUMENTS);
total_len += self.out_substr("<MISSING>")!; total_len += formatter_out_substr(self, "<MISSING>")!;
continue; continue;
} }
any current = anys[variant_index++]; any current = anys[variant_index++];
@@ -471,37 +258,37 @@ fn usz? Formatter.vprintf(&self, String format, any[] anys)
self.flags.uppercase = true; self.flags.uppercase = true;
nextcase; nextcase;
case 'a': case 'a':
total_len += @wrap_bad(self, self.atoa(float_from_any(current)))!; total_len += @wrap_bad(self, formatter_atoa(self, float_from_any(current)))!;
continue; continue;
case 'F' : case 'F' :
self.flags.uppercase = true; self.flags.uppercase = true;
nextcase; nextcase;
case 'f': case 'f':
total_len += @wrap_bad(self, self.ftoa(float_from_any(current)))!; total_len += @wrap_bad(self, formatter_ftoa(self, float_from_any(current)))!;
continue; continue;
case 'E': case 'E':
self.flags.uppercase = true; self.flags.uppercase = true;
nextcase; nextcase;
case 'e': case 'e':
total_len += @wrap_bad(self, self.etoa(float_from_any(current)))!; total_len += @wrap_bad(self, formatter_etoa(self, float_from_any(current)))!;
continue; continue;
case 'G': case 'G':
self.flags.uppercase = true; self.flags.uppercase = true;
nextcase; nextcase;
case 'g': case 'g':
total_len += @wrap_bad(self, self.gtoa(float_from_any(current)))!; total_len += @wrap_bad(self, formatter_gtoa(self, float_from_any(current)))!;
continue; continue;
case 'c': case 'c':
total_len += self.out_char(current)!; total_len += formatter_out_char(self, current)!;
continue; continue;
case 'H': case 'H':
self.flags.uppercase = true; self.flags.uppercase = true;
nextcase; nextcase;
case 'h': case 'h':
total_len += self.out_hex_buffer(current)!; total_len += formatter_out_hex_buffer(self, current)!;
continue; continue;
case 's': case 's':
total_len += self.out_str_pad(current)!; total_len += formatter_out_str_pad(self, current)!;
continue; continue;
case 'p': case 'p':
self.flags.zeropad = true; self.flags.zeropad = true;
@@ -509,7 +296,7 @@ fn usz? Formatter.vprintf(&self, String format, any[] anys)
base = 16; base = 16;
default: default:
self.first_err(INVALID_FORMAT); self.first_err(INVALID_FORMAT);
total_len += self.out_substr("<BAD FORMAT>")!; total_len += formatter_out_substr(self, "<BAD FORMAT>")!;
continue; continue;
} }
if (base != 10) if (base != 10)
@@ -521,13 +308,25 @@ fn usz? Formatter.vprintf(&self, String format, any[] anys)
if (self.flags.precision) self.flags.zeropad = false; if (self.flags.precision) self.flags.zeropad = false;
bool is_neg; bool is_neg;
total_len += @wrap_bad(self, self.ntoa(int_from_any(current, &is_neg), is_neg, base))!; total_len += @wrap_bad(self, formatter_ntoa(self, int_from_any(current, &is_neg), is_neg, base))!;
} }
if (self.first_fault) return self.first_fault~; if (self.first_fault) return self.first_fault~;
return total_len; return total_len;
} }
fn usz? Formatter.out(&self, char c) @deprecated("Use print_char") => self.print_char(c);
fn usz? Formatter.print_char(&self, char c)
{
if (catch err = self.out_fn(self.data, c))
{
if (self.first_fault) return self.first_fault~;
self.first_fault = err;
return err~;
}
return 1;
}
fn usz? Formatter.print(&self, String str) fn usz? Formatter.print(&self, String str)
{ {
@@ -536,6 +335,6 @@ fn usz? Formatter.print(&self, String str)
// use null output function // use null output function
self.out_fn = &out_null_fn; self.out_fn = &out_null_fn;
} }
foreach (c : str) self.out(c)!; foreach (c : str) self.print_char(c)!;
return str.len; return str.len;
} }

View File

@@ -13,10 +13,10 @@ fn usz? print_hex_chars(Formatter* f, char[] out, bool uppercase) @inline
foreach (c : out) foreach (c : out)
{ {
char digit = c >> 4; char digit = c >> 4;
f.out(digit + (digit < 10 ? '0' : past_10))!; f.print_char(digit + (digit < 10 ? '0' : past_10))!;
len++; len++;
digit = c & 0xf; digit = c & 0xf;
f.out(digit + (digit < 10 ? '0' : past_10))!; f.print_char(digit + (digit < 10 ? '0' : past_10))!;
len++; len++;
} }
return len; return len;
@@ -29,10 +29,10 @@ macro fault Formatter.first_err(&self, fault f)
return f; return f;
} }
fn usz? Formatter.adjust(&self, usz len) @local fn usz? formatter_adjust(Formatter* f, usz len) @local
{ {
if (!self.flags.left) return 0; if (!f.flags.left) return 0;
return self.pad(' ', self.width, len); return formatter_pad(f, ' ', f.width, len);
} }
fn uint128? int_from_any(any arg, bool *is_neg) @private fn uint128? int_from_any(any arg, bool *is_neg) @private
@@ -156,11 +156,11 @@ fn uint simple_atoi(char* buf, usz maxlen, usz* len_ptr) @inline @private
return i; return i;
} }
fn usz? Formatter.out_substr(&self, String str) @private fn usz? formatter_out_substr(Formatter* f, String str) @private
{ {
usz l = conv::utf8_codepoints(str); usz l = conv::utf8_codepoints(str);
uint prec = self.prec; uint prec = f.prec;
if (self.flags.precision && l < prec) l = prec; if (f.flags.precision && l < prec) l = prec;
usz index = 0; usz index = 0;
usz chars = str.len; usz chars = str.len;
char* ptr = str.ptr; char* ptr = str.ptr;
@@ -168,17 +168,17 @@ fn usz? Formatter.out_substr(&self, String str) @private
{ {
char c = ptr[index]; char c = ptr[index];
// Break if we have precision set and we ran out... // Break if we have precision set and we ran out...
if (c & 0xC0 != 0x80 && self.flags.precision && !prec--) break; if (c & 0xC0 != 0x80 && f.flags.precision && !prec--) break;
self.out(c)!; f.print_char(c)!;
index++; index++;
} }
return index; return index;
} }
fn usz? Formatter.pad(&self, char c, isz width, isz len) @inline fn usz? formatter_pad(Formatter* f, char c, isz width, isz len) @inline
{ {
isz delta = width - len; isz delta = width - len;
for (isz i = 0; i < delta; i++) self.out(c)!; for (isz i = 0; i < delta; i++) f.print_char(c)!;
return max(0, delta); return max(0, delta);
} }
@@ -191,7 +191,7 @@ fn char* fmt_u(uint128 x, char* s)
fn usz? Formatter.out_chars(&self, char[] s) fn usz? Formatter.out_chars(&self, char[] s)
{ {
foreach (c : s) self.out(c)!; foreach (c : s) self.print_char(c)!;
return s.len; return s.len;
} }
@@ -203,12 +203,12 @@ enum FloatFormatting
HEX HEX
} }
fn usz? Formatter.etoa(&self, double y) => self.floatformat(EXPONENTIAL, y); fn usz? formatter_etoa(Formatter* self, double y) => formatter_floatformat(self, EXPONENTIAL, y);
fn usz? Formatter.ftoa(&self, double y) => self.floatformat(FLOAT, y); fn usz? formatter_ftoa(Formatter* self, double y) => formatter_floatformat(self, FLOAT, y);
fn usz? Formatter.gtoa(&self, double y) => self.floatformat(ADAPTIVE, y); fn usz? formatter_gtoa(Formatter* self, double y) => formatter_floatformat(self, ADAPTIVE, y);
fn usz? Formatter.atoa(&self, double y) => self.floatformat(HEX, y); fn usz? formatter_atoa(Formatter* self, double y) => formatter_floatformat(self, HEX, y);
fn usz? Formatter.floatformat_hex(&self, double y, bool is_neg, isz pl, isz p) @private @inline fn usz? formatter_floatformat_hex(Formatter* self, double y, bool is_neg, isz pl, isz p) @private @inline
{ {
double round = 8.0; double round = 8.0;
// 0x / 0X // 0x / 0X
@@ -261,18 +261,18 @@ fn usz? Formatter.floatformat_hex(&self, double y, bool is_neg, isz pl, isz p) @
usz l = (usz)(p && outlen - 2 < p usz l = (usz)(p && outlen - 2 < p
? p + 2 + explen ? p + 2 + explen
: outlen + explen); : outlen + explen);
if (!self.flags.left && !self.flags.zeropad) len += self.pad(' ', self.width, pl + l)!; if (!self.flags.left && !self.flags.zeropad) len += formatter_pad(self, ' ', self.width, pl + l)!;
if (is_neg || self.flags.plus) len += self.out(is_neg ? '-' : '+')!; if (is_neg || self.flags.plus) len += self.print_char(is_neg ? '-' : '+')!;
len += self.out_chars(self.flags.uppercase ? "0X" : "0x")!; len += self.out_chars(self.flags.uppercase ? "0X" : "0x")!;
if (self.flags.zeropad) len += self.pad('0', self.width, pl + l)!; if (self.flags.zeropad) len += formatter_pad(self, '0', self.width, pl + l)!;
len += self.out_chars(buf[:outlen])!; len += self.out_chars(buf[:outlen])!;
len += self.pad('0', (isz)l - outlen - explen, 0)!; len += formatter_pad(self, '0', (isz)l - outlen - explen, 0)!;
len += self.out_chars(estr[:explen])!; len += self.out_chars(estr[:explen])!;
if (self.flags.left) len += self.pad(' ', self.width, pl + (isz)l)!; if (self.flags.left) len += formatter_pad(self, ' ', self.width, pl + (isz)l)!;
return len; return len;
} }
fn usz? Formatter.floatformat(&self, FloatFormatting formatting, double y) @private fn usz? formatter_floatformat(Formatter* self, FloatFormatting formatting, double y) @private
{ {
// This code is heavily based on musl's printf code // This code is heavily based on musl's printf code
const BUF_SIZE = (math::DOUBLE_MANT_DIG + 28) / 29 + 1 const BUF_SIZE = (math::DOUBLE_MANT_DIG + 28) / 29 + 1
@@ -290,17 +290,17 @@ fn usz? Formatter.floatformat(&self, FloatFormatting formatting, double y) @priv
{ {
usz len; usz len;
// Add padding // Add padding
if (!self.flags.left) len += self.pad(' ', self.width, 3 + pl)!; if (!self.flags.left) len += formatter_pad(self, ' ', self.width, 3 + pl)!;
String s = self.flags.uppercase ? "INF" : "inf"; String s = self.flags.uppercase ? "INF" : "inf";
if (math::is_nan(y)) s = self.flags.uppercase ? "NAN" : "nan"; if (math::is_nan(y)) s = self.flags.uppercase ? "NAN" : "nan";
if (pl) len += self.out(is_neg ? '-' : '+')!; if (pl) len += self.print_char(is_neg ? '-' : '+')!;
len += self.out_chars(s)!; len += self.out_chars(s)!;
if (self.flags.left) len += self.pad(' ', self.width, 3 + pl)!; if (self.flags.left) len += formatter_pad(self, ' ', self.width, 3 + pl)!;
return len; return len;
} }
isz p = self.flags.precision ? self.prec : -1; isz p = self.flags.precision ? self.prec : -1;
if (formatting == HEX) return self.floatformat_hex(y, is_neg, pl, p); if (formatting == HEX) return formatter_floatformat_hex(self, y, is_neg, pl, p);
// Rescale // Rescale
int e2; int e2;
@@ -483,9 +483,9 @@ fn usz? Formatter.floatformat(&self, FloatFormatting formatting, double y) @priv
} }
if (l > int.max - pl) return INTERNAL_BUFFER_EXCEEDED~; if (l > int.max - pl) return INTERNAL_BUFFER_EXCEEDED~;
usz len; usz len;
if (!self.flags.left && !self.flags.zeropad) len += self.pad(' ', self.width, pl + l)!; if (!self.flags.left && !self.flags.zeropad) len += formatter_pad(self, ' ', self.width, pl + l)!;
if (is_neg || self.flags.plus) len += self.out(is_neg ? '-' : '+')!; if (is_neg || self.flags.plus) len += self.print_char(is_neg ? '-' : '+')!;
if (self.flags.zeropad) len += self.pad('0', self.width, pl + l)!; if (self.flags.zeropad) len += formatter_pad(self, '0', self.width, pl + l)!;
char[9] buf_array; char[9] buf_array;
char* buf = &buf_array[0]; char* buf = &buf_array[0];
@@ -506,14 +506,14 @@ fn usz? Formatter.floatformat(&self, FloatFormatting formatting, double y) @priv
} }
len += self.out_chars(s[:buf + 9 - s])!; len += self.out_chars(s[:buf + 9 - s])!;
} }
if (p || self.flags.hash) len += self.out('.')!; if (p || self.flags.hash) len += self.print_char('.')!;
for (; d < z && p > 0; d++, p -= 9) for (; d < z && p > 0; d++, p -= 9)
{ {
char* s = fmt_u(*d, buf + 9); char* s = fmt_u(*d, buf + 9);
while (s > buf) *--s = '0'; while (s > buf) *--s = '0';
len += self.out_chars(s[:math::min((isz)9, p)])!; len += self.out_chars(s[:math::min((isz)9, p)])!;
} }
len += self.pad('0', p + 9, 9)!; len += formatter_pad(self, '0', p + 9, 9)!;
} }
else else
{ {
@@ -528,21 +528,42 @@ fn usz? Formatter.floatformat(&self, FloatFormatting formatting, double y) @priv
} }
else else
{ {
len += self.out(s++[0])!; len += self.print_char(s++[0])!;
if (p > 0 || self.flags.hash) len += self.out('.')!; if (p > 0 || self.flags.hash) len += self.print_char('.')!;
} }
len += self.out_chars(s[:math::min(buf + 9 - s, p)])!; len += self.out_chars(s[:math::min(buf + 9 - s, p)])!;
p -= buf + 9 - s; p -= buf + 9 - s;
} }
len += self.pad('0', p + 18, 18)!; len += formatter_pad(self, '0', p + 18, 18)!;
len += self.out_chars(estr[:ebuf - estr])!; len += self.out_chars(estr[:ebuf - estr])!;
} }
if (self.flags.left) len += self.pad(' ', self.width, pl + l)!; if (self.flags.left) len += formatter_pad(self, ' ', self.width, pl + l)!;
return len; return len;
} }
fn usz? formatter_out_str_pad(Formatter* self, any arg) @private @inline
{
usz total;
if (self.width && !self.flags.left)
{
OutputFn out_fn = self.out_fn;
self.out_fn = (OutputFn)&out_null_fn;
usz len = formatter_out_str(self, arg)!;
self.out_fn = out_fn;
total += formatter_pad(self, ' ', self.width, (isz)len)!;
}
usz len = formatter_out_str(self, arg)!;
total += len;
if (self.flags.left)
{
total += formatter_pad(self, ' ', self.width, (isz)len)!;
}
return total;
}
const char[201] DIGIT_PAIRS @private = const char[201] DIGIT_PAIRS @private =
"00102030405060708090" "00102030405060708090"
"01112131415161718191" "01112131415161718191"
@@ -555,18 +576,18 @@ const char[201] DIGIT_PAIRS @private =
"08182838485868788898" "08182838485868788898"
"09192939495969798999"; "09192939495969798999";
fn usz? Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private fn usz? formatter_ntoa(Formatter* f, uint128 value, bool negative, uint base) @private
{ {
char[PRINTF_NTOA_BUFFER_SIZE] buf @noinit; char[PRINTF_NTOA_BUFFER_SIZE] buf @noinit;
usz len; usz len;
// no hash for 0 values // no hash for 0 values
if (!value) self.flags.hash = false; if (!value) f.flags.hash = false;
// write if precision != 0 or value is != 0 // write if precision != 0 or value is != 0
if (!self.flags.precision || value) if (!f.flags.precision || value)
{ {
char past_10 = (self.flags.uppercase ? 'A' : 'a') - 10; char past_10 = (f.flags.uppercase ? 'A' : 'a') - 10;
switch (base) switch (base)
{ {
case 2: case 2:
@@ -612,27 +633,26 @@ fn usz? Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED~; if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED~;
buf[len++] = '0' + (char)value & 0x7; buf[len++] = '0' + (char)value & 0x7;
value >>= 3; value >>= 3;
} } while (value);
while (value);
default: default:
unreachable(); unreachable();
} }
} }
return self.ntoa_format((String)buf[:PRINTF_NTOA_BUFFER_SIZE], len, negative, base); return formatter_ntoa_format(f, (String)buf[:PRINTF_NTOA_BUFFER_SIZE], len, negative, base);
} }
fn usz? Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint base) @private fn usz? formatter_ntoa_format(Formatter* f, String buf, usz len, bool negative, uint base) @private
{ {
// pad leading zeros // pad leading zeros
if (!self.flags.left) if (!f.flags.left)
{ {
if (self.width && self.flags.zeropad && (negative || self.flags.plus || self.flags.space)) self.width--; if (f.width && f.flags.zeropad && (negative || f.flags.plus || f.flags.space)) f.width--;
while (len < self.prec) while (len < f.prec)
{ {
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~; if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~;
buf[len++] = '0'; buf[len++] = '0';
} }
while (self.flags.zeropad && len < self.width) while (f.flags.zeropad && len < f.width)
{ {
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~; if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~;
buf[len++] = '0'; buf[len++] = '0';
@@ -640,9 +660,9 @@ fn usz? Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint ba
} }
// handle hash // handle hash
if (self.flags.hash && base != 10) if (f.flags.hash && base != 10)
{ {
if (!self.flags.precision && len && len == self.prec && len == self.width) if (!f.flags.precision && len && len == f.prec && len == f.width)
{ {
len--; len--;
if (len) len--; if (len) len--;
@@ -653,11 +673,11 @@ fn usz? Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint ba
switch (base) switch (base)
{ {
case 16: case 16:
buf[len++] = self.flags.uppercase ? 'X' : 'x'; buf[len++] = f.flags.uppercase ? 'X' : 'x';
case 8: case 8:
buf[len++] = self.flags.uppercase ? 'O' : 'o'; buf[len++] = f.flags.uppercase ? 'O' : 'o';
case 2: case 2:
buf[len++] = self.flags.uppercase ? 'B' : 'b'; buf[len++] = f.flags.uppercase ? 'B' : 'b';
default: default:
unreachable(); unreachable();
} }
@@ -670,35 +690,35 @@ fn usz? Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint ba
case negative: case negative:
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~; if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~;
buf[len++] = '-'; buf[len++] = '-';
case self.flags.plus: case f.flags.plus:
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~; if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~;
buf[len++] = '+'; buf[len++] = '+';
case self.flags.space: case f.flags.space:
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~; if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~;
buf[len++] = ' '; buf[len++] = ' ';
} }
if (len) self.out_reverse(buf[:len])!; if (len) formatter_out_reverse(f, buf[:len])!;
return len; return len;
} }
fn usz? Formatter.ntoa_any(&self, any arg, uint base) @private fn usz? formatter_ntoa_any(Formatter* f, any arg, uint base) @private
{ {
bool is_neg; bool is_neg;
return self.ntoa(int_from_any(arg, &is_neg)!!, is_neg, base) @inline; return formatter_ntoa(f, int_from_any(arg, &is_neg)!!, is_neg, base) @inline;
} }
fn usz? Formatter.out_char(&self, any arg) @private fn usz? formatter_out_char(Formatter* f, any arg) @private
{ {
if (!arg.type.kindof.is_int()) if (!arg.type.kindof.is_int())
{ {
return self.out_substr("<NOT CHAR>"); return formatter_out_substr(f, "<NOT CHAR>");
} }
usz len = 1; usz len = 1;
// pre padding // pre padding
if (!self.flags.left) if (!f.flags.left)
{ {
len += self.pad(' ', self.width, len)!; len += formatter_pad(f, ' ', f.width, len)!;
} }
// char output // char output
@@ -706,42 +726,42 @@ fn usz? Formatter.out_char(&self, any arg) @private
switch (true) switch (true)
{ {
case c < 0x7f: case c < 0x7f:
self.out((char)c)!; f.print_char((char)c)!;
case c < 0x7ff: case c < 0x7ff:
self.out((char)(0xC0 | c >> 6))!; f.print_char((char)(0xC0 | c >> 6))!;
self.out((char)(0x80 | (c & 0x3F)))!; f.print_char((char)(0x80 | (c & 0x3F)))!;
case c < 0xffff: case c < 0xffff:
self.out((char)(0xE0 | c >> 12))!; f.print_char((char)(0xE0 | c >> 12))!;
self.out((char)(0x80 | (c >> 6 & 0x3F)))!; f.print_char((char)(0x80 | (c >> 6 & 0x3F)))!;
self.out((char)(0x80 | (c & 0x3F)))!; f.print_char((char)(0x80 | (c & 0x3F)))!;
default: default:
self.out((char)(0xF0 | c >> 18))!; f.print_char((char)(0xF0 | c >> 18))!;
self.out((char)(0x80 | (c >> 12 & 0x3F)))!; f.print_char((char)(0x80 | (c >> 12 & 0x3F)))!;
self.out((char)(0x80 | (c >> 6 & 0x3F)))!; f.print_char((char)(0x80 | (c >> 6 & 0x3F)))!;
self.out((char)(0x80 | (c & 0x3F)))!; f.print_char((char)(0x80 | (c & 0x3F)))!;
} }
if (self.flags.left) if (f.flags.left)
{ {
len += self.pad(' ', self.width, len)!; len += formatter_pad(f, ' ', f.width, len)!;
} }
return len; return len;
} }
fn usz? Formatter.out_reverse(&self, char[] buf) @private fn usz? formatter_out_reverse(Formatter* f, char[] buf) @private
{ {
usz n; usz n;
usz len = buf.len; usz len = buf.len;
// pad spaces up to given width // pad spaces up to given width
if (!self.flags.zeropad && !self.flags.left) if (!f.flags.zeropad && !f.flags.left)
{ {
n += self.pad(' ', self.width, len)!; n += formatter_pad(f, ' ', f.width, len)!;
} }
// reverse string // reverse string
while (len) n += self.out(buf[--len])!; while (len) n += f.print_char(buf[--len])!;
// append pad spaces up to given width // append pad spaces up to given width
n += self.adjust(n)!; n += formatter_adjust(f, n)!;
return n; return n;
} }
@@ -761,3 +781,197 @@ fn int? printf_parse_format_field(
uint? intval = types::any_to_int(val, int); uint? intval = types::any_to_int(val, int);
return intval ?? BAD_FORMAT~; return intval ?? BAD_FORMAT~;
} }
fn usz? formatter_out_hex_buffer(Formatter* self, any arg) @private @inline
{
char[] out @noinit;
switch (arg.type)
{
case char[]:
case ichar[]:
out = *(char[]*)arg;
default:
if (arg.type.kindof == ARRAY && (arg.type.inner == char.typeid || arg.type.inner == ichar.typeid))
{
out = ((char*)arg.ptr)[:arg.type.sizeof];
break;
}
if (arg.type.kindof == POINTER)
{
// Maybe there is a more idiomatic way here
out = ((*(char**)arg.ptr))[:arg.type.inner.sizeof];
break;
}
return formatter_out_substr(self, "<INVALID>");
}
usz len = out.len * 2;
usz total;
if (self.flags.left)
{
total += print_hex_chars(self, out, self.flags.uppercase)!;
total += formatter_pad(self, ' ', self.width, (isz)total)!;
}
else
{
if (self.width) total += formatter_pad(self, ' ', self.width, (isz)len)!;
total += print_hex_chars(self, out, self.flags.uppercase)!;
}
return total;
}
fn usz? formatter_out_unknown(Formatter* self, String category, any arg) @private
{
return formatter_out_substr(self, "<")
+ formatter_out_substr(self, category)
+ formatter_out_substr(self, " type:")
+ formatter_ntoa(self, (iptr)arg.type, false, 16)
+ formatter_out_substr(self, ", addr:")
+ formatter_ntoa(self, (iptr)arg.ptr, false, 16)
+ formatter_out_substr(self, ">");
}
fn usz? formatter_out_collection(Formatter* self, any arg, String open, String close) @private
{
typeid inner = arg.type.inner;
if (inner == void.typeid) inner = char.typeid;
usz size = inner.sizeof;
usz alen;
void* data_ptr;
if (arg.type.kindof == SLICE)
{
String* temp = arg.ptr;
data_ptr = temp.ptr;
alen = temp.len;
}
else
{
data_ptr = arg.ptr;
alen = arg.type.len;
}
PrintFlags flags = self.flags;
uint width = self.width;
defer
{
self.flags = flags;
self.width = width;
}
self.flags = {};
self.width = 0;
usz len = formatter_out_substr(self, open)!;
for (usz i = 0; i < alen; i++)
{
if (i != 0) len += formatter_out_substr(self, ", ")!;
len += formatter_out_str(self, any_make(data_ptr, inner))!;
data_ptr += size;
}
len += formatter_out_substr(self, close)!;
return len;
}
fn usz? formatter_out_str(Formatter* self, any arg) @private
{
switch (arg.type.kindof)
{
case VOID:
return formatter_out_substr(self, "void");
case FAULT:
fault f = *(fault*)arg.ptr;
return formatter_out_substr(self, f ? f.nameof : "(empty-fault)");
case INTERFACE:
any a = *(any*)arg;
return a ? formatter_out_str(self, a) : formatter_out_substr(self, "(empty-interface)");
case ANY:
any a = *(any*)arg;
return a ? formatter_out_str(self, a) : formatter_out_substr(self, "(empty-any)");
case OPTIONAL:
unreachable();
case SIGNED_INT:
case UNSIGNED_INT:
case FLOAT:
case FUNC:
case POINTER:
PrintFlags flags = self.flags;
uint width = self.width;
defer
{
self.flags = flags;
self.width = width;
}
self.flags = {};
self.width = 0;
switch (arg.type.kindof)
{
case SIGNED_INT:
case UNSIGNED_INT:
return formatter_ntoa_any(self, arg, 10) ?? formatter_out_substr(self, "<INVALID>");
case FLOAT:
return formatter_ftoa(self, float_from_any(arg)) ?? formatter_out_substr(self, "ERR");
case FUNC:
case POINTER:
if (arg.type.kindof == POINTER && arg.type.inner != void.typeid)
{
void** pointer = arg.ptr;
any deref = any_make(*pointer, arg.type.inner);
usz? n = self.print_with_function((Printable)deref);
if (try n) return n;
if (@catch(n) != NOT_FOUND) n!;
}
return formatter_out_substr(self, "0x")! + formatter_ntoa_any(self, arg, 16);
default:
unreachable();
}
case BOOL:
return formatter_out_substr(self, *(bool*)arg.ptr ? "true" : "false");
default:
}
usz? n = self.print_with_function((Printable)arg);
if (try n) return n;
if (@catch(n) != NOT_FOUND) n!;
switch (arg.type.kindof)
{
case TYPEID:
return formatter_out_substr(self, "typeid[")! + formatter_ntoa(self, (iptr)*(typeid*)arg, false, 16)! + formatter_out_substr(self, "]")!;
case ENUM:
usz i = types::any_to_enum_ordinal(arg, usz)!!;
assert(i < arg.type.names.len, "Illegal enum value found, numerical value was %d.", i);
return formatter_out_substr(self, arg.type.names[i]);
case STRUCT:
return formatter_out_unknown(self, "struct", arg);
case UNION:
return formatter_out_unknown(self, "union", arg);
case BITSTRUCT:
return formatter_out_unknown(self, "bitstruct", arg);
case CONST_ENUM:
case DISTINCT:
if (arg.type == String.typeid)
{
return formatter_out_substr(self, *(String*)arg);
}
if (arg.type == ZString.typeid)
{
return formatter_out_substr(self, *(ZString*)arg ? ((ZString*)arg).str_view() : "(null)");
}
if (arg.type == DString.typeid)
{
return formatter_out_substr(self, *(DString*)arg ? ((DString*)arg).str_view() : "(null)");
}
return formatter_out_str(self, arg.as_inner());
case ARRAY:
return formatter_out_collection(self, arg, "[", "]");
case VECTOR:
return formatter_out_collection(self, arg, "[<", ">]");
case SLICE:
return formatter_out_collection(self, arg, "[", "]");
case ANY:
case INTERFACE:
unreachable("Already handled");
default:
}
return formatter_out_substr(self, "Invalid type");
}

View File

@@ -366,7 +366,7 @@ fn usz? printfn(String format, args...) @format(0) @maydiscard
PutcharBuffer buff; PutcharBuffer buff;
formatter.init(&out_putchar_buffer_fn, &buff); formatter.init(&out_putchar_buffer_fn, &buff);
usz? len = formatter.vprintf(format, args); usz? len = formatter.vprintf(format, args);
formatter.out('\n')!; formatter.print_char('\n')!;
write_putchar_buffer(&buff, true)!; write_putchar_buffer(&buff, true)!;
return len + 1; return len + 1;
} }

View File

@@ -38,7 +38,7 @@ fn usz? ReadBuffer.read(&self, char[] bytes) @dynamic
// Read directly into the input buffer. // Read directly into the input buffer.
return self.wrapped_stream.read(bytes)!; return self.wrapped_stream.read(bytes)!;
} }
self.refill()!; readbuffer_refill(self)!;
} }
usz n = min(self.write_idx - self.read_idx, bytes.len); usz n = min(self.write_idx - self.read_idx, bytes.len);
bytes[:n] = self.bytes[self.read_idx:n]; bytes[:n] = self.bytes[self.read_idx:n];
@@ -48,14 +48,14 @@ fn usz? ReadBuffer.read(&self, char[] bytes) @dynamic
fn char? ReadBuffer.read_byte(&self) @dynamic fn char? ReadBuffer.read_byte(&self) @dynamic
{ {
if (self.read_idx == self.write_idx) self.refill()!; if (self.read_idx == self.write_idx) readbuffer_refill(self)!;
if (self.read_idx == self.write_idx) return io::EOF~; if (self.read_idx == self.write_idx) return io::EOF~;
char c = self.bytes[self.read_idx]; char c = self.bytes[self.read_idx];
self.read_idx++; self.read_idx++;
return c; return c;
} }
fn void? ReadBuffer.refill(&self) @local @inline fn void? readbuffer_refill(ReadBuffer* self) @local @inline
{ {
self.read_idx = 0; self.read_idx = 0;
self.write_idx = self.wrapped_stream.read(self.bytes)!; self.write_idx = self.wrapped_stream.read(self.bytes)!;
@@ -92,7 +92,7 @@ fn void? WriteBuffer.close(&self) @dynamic
fn void? WriteBuffer.flush(&self) @dynamic fn void? WriteBuffer.flush(&self) @dynamic
{ {
self.write_pending()!; write_buffer_write_pending(self)!;
if (&self.wrapped_stream.flush) self.wrapped_stream.flush()!; if (&self.wrapped_stream.flush) self.wrapped_stream.flush()!;
} }
@@ -106,7 +106,7 @@ fn usz? WriteBuffer.write(&self, char[] bytes) @dynamic
self.index += bytes.len; self.index += bytes.len;
return bytes.len; return bytes.len;
} }
self.write_pending()!; write_buffer_write_pending(self)!;
if (bytes.len >= self.bytes.len) if (bytes.len >= self.bytes.len)
{ {
// Write directly to the stream. // Write directly to the stream.
@@ -123,13 +123,13 @@ fn void? WriteBuffer.write_byte(&self, char c) @dynamic
usz n = self.bytes.len - self.index; usz n = self.bytes.len - self.index;
if (n == 0) if (n == 0)
{ {
self.write_pending()!; write_buffer_write_pending(self)!;
} }
self.bytes[self.index] = c; self.bytes[self.index] = c;
self.index += 1; self.index += 1;
} }
fn void? WriteBuffer.write_pending(&self) @local fn void? write_buffer_write_pending(WriteBuffer* self) @local
{ {
self.index -= self.wrapped_stream.write(self.bytes[:self.index])!; self.index -= self.wrapped_stream.write(self.bytes[:self.index])!;
if (self.index != 0) return INCOMPLETE_WRITE~; if (self.index != 0) return INCOMPLETE_WRITE~;

View File

@@ -37,7 +37,7 @@ fn BigInt* BigInt.init(&self, int128 value)
assert(value < 0 || tmp == 0 || !self.is_negative()); assert(value < 0 || tmp == 0 || !self.is_negative());
assert(value >= 0 || tmp == -1 || self.is_negative()); assert(value >= 0 || tmp == -1 || self.is_negative());
self.len = len; self.len = len;
self.reduce_len(); reduce_len(self);
return self; return self;
} }
@@ -153,15 +153,11 @@ fn void BigInt.add_this(&self, BigInt other) @operator(+=)
self.data[self.len++] = (uint)carry; self.data[self.len++] = (uint)carry;
} }
self.reduce_len(); reduce_len(self);
assert(sign != sign_arg || sign == self.is_negative(), "Overflow in addition"); assert(sign != sign_arg || sign == self.is_negative(), "Overflow in addition");
} }
fn void BigInt.reduce_len(&self) @private
{
self.len = max(find_length(&self.data, self.len), 1);
}
macro uint find_length(uint* data, uint length) macro uint find_length(uint* data, uint length)
{ {
@@ -226,7 +222,7 @@ fn void BigInt.mult_this(&self, BigInt bi2) @operator(*=)
res.len = min(self.len + bi2.len, (uint)MAX_LEN); res.len = min(self.len + bi2.len, (uint)MAX_LEN);
res.reduce_len(); reduce_len(&res);
// overflow check (result is -ve) // overflow check (result is -ve)
assert(!res.is_negative(), "Multiplication overflow"); assert(!res.is_negative(), "Multiplication overflow");
@@ -265,7 +261,7 @@ fn void BigInt.negate(&self)
assert(self.is_negative() != was_negative, "Overflow in negation"); assert(self.is_negative() != was_negative, "Overflow in negation");
self.len = MAX_LEN; self.len = MAX_LEN;
self.reduce_len(); reduce_len(self);
} }
macro bool BigInt.is_zero(&self) => self.len == 1 && self.data[0] == 0; macro bool BigInt.is_zero(&self) => self.len == 1 && self.data[0] == 0;
@@ -301,7 +297,7 @@ fn BigInt* BigInt.sub_this(&self, BigInt other) @operator(-=)
self.len = MAX_LEN; self.len = MAX_LEN;
} }
self.reduce_len(); reduce_len(self);
// overflow check // overflow check
@@ -311,7 +307,7 @@ fn BigInt* BigInt.sub_this(&self, BigInt other) @operator(-=)
fn int BigInt.bitcount(&self) fn int BigInt.bitcount(&self)
{ {
self.reduce_len(); reduce_len(self);
uint val = self.data[self.len - 1]; uint val = self.data[self.len - 1];
uint mask = 0x80000000; uint mask = 0x80000000;
int bits = 32; int bits = 32;
@@ -364,11 +360,11 @@ fn void BigInt.div_this(&self, BigInt other) @operator(/=)
if (other.len == 1) if (other.len == 1)
{ {
self.single_byte_divide(&other, &quotient, &remainder); single_byte_divide(self, &other, &quotient, &remainder);
} }
else else
{ {
self.multi_byte_divide(&other, &quotient, &remainder); multi_byte_divide(self, &other, &quotient, &remainder);
} }
if (negate_answer) if (negate_answer)
{ {
@@ -407,11 +403,11 @@ fn void BigInt.mod_this(&self, BigInt bi2) @operator(%=)
if (bi2.len == 1) if (bi2.len == 1)
{ {
self.single_byte_divide(&bi2, &quotient, &remainder); single_byte_divide(self, &bi2, &quotient, &remainder);
} }
else else
{ {
self.multi_byte_divide(&bi2, &quotient, &remainder); multi_byte_divide(self, &bi2, &quotient, &remainder);
} }
if (negate_answer) if (negate_answer)
{ {
@@ -425,7 +421,7 @@ fn void BigInt.bit_negate_this(&self)
foreach (&r : self.data) *r = ~*r; foreach (&r : self.data) *r = ~*r;
self.len = MAX_LEN; self.len = MAX_LEN;
self.reduce_len(); reduce_len(self);
} }
fn BigInt BigInt.bit_negate(self) @operator(~) fn BigInt BigInt.bit_negate(self) @operator(~)
@@ -523,7 +519,7 @@ fn usz? BigInt.to_format(&self, Formatter* format) @dynamic
usz len; usz len;
if (negative) if (negative)
{ {
format.out('-')!; format.print_char('-')!;
len++; len++;
a.negate(); a.negate();
} }
@@ -580,7 +576,7 @@ fn String BigInt.to_string_with_radix(&self, int radix, Allocator allocator)
while (!a.is_zero()) while (!a.is_zero())
{ {
a.single_byte_divide(&big_radix, &quotient, &remainder); single_byte_divide(&a, &big_radix, &quotient, &remainder);
if (remainder.data[0] < 10) if (remainder.data[0] < 10)
{ {
@@ -740,7 +736,7 @@ fn BigInt barrett_reduction(BigInt x, BigInt n, BigInt constant)
} }
r2.len = k_plus_one; r2.len = k_plus_one;
r2.reduce_len(); reduce_len(&r2);
r1.sub_this(r2); r1.sub_this(r2);
if (r1.is_negative()) if (r1.is_negative())
@@ -816,7 +812,7 @@ fn void BigInt.bit_and_this(&self, BigInt bi2)
} }
self.len = MAX_LEN; self.len = MAX_LEN;
self.reduce_len(); reduce_len(self);
} }
fn BigInt BigInt.bit_or(self, BigInt bi2) @operator(|) fn BigInt BigInt.bit_or(self, BigInt bi2) @operator(|)
@@ -834,7 +830,7 @@ fn void BigInt.bit_or_this(&self, BigInt bi2)
} }
self.len = MAX_LEN; self.len = MAX_LEN;
self.reduce_len(); reduce_len(self);
} }
fn BigInt BigInt.bit_xor(self, BigInt bi2) @operator(^) fn BigInt BigInt.bit_xor(self, BigInt bi2) @operator(^)
@@ -852,7 +848,7 @@ fn void BigInt.bit_xor_this(&self, BigInt bi2)
} }
self.len = MAX_LEN; self.len = MAX_LEN;
self.reduce_len(); reduce_len(self);
} }
fn void BigInt.shl_this(&self, int shift) @operator(<<=) fn void BigInt.shl_this(&self, int shift) @operator(<<=)
@@ -928,13 +924,18 @@ fn void BigInt.randomize_bits(&self, Random random, int bits)
module std::math::bigint @private; module std::math::bigint @private;
fn void reduce_len(BigInt* self) @private
{
self.len = max(find_length(&self.data, self.len), 1);
}
<* <*
@param [&inout] quotient @param [&inout] quotient
@param [&in] bi2 @param [&in] bi2
@param [&inout] remainder @param [&inout] remainder
*> *>
fn void BigInt.single_byte_divide(&self, BigInt* bi2, BigInt* quotient, BigInt* remainder) fn void single_byte_divide(BigInt* self, BigInt* bi2, BigInt* quotient, BigInt* remainder) @private
{ {
uint[MAX_LEN] result; uint[MAX_LEN] result;
int result_pos = 0; int result_pos = 0;
@@ -977,8 +978,8 @@ fn void BigInt.single_byte_divide(&self, BigInt* bi2, BigInt* quotient, BigInt*
} }
quotient.data[j..] = 0; quotient.data[j..] = 0;
quotient.reduce_len(); reduce_len(quotient);
remainder.reduce_len(); reduce_len(remainder);
} }
<* <*
@@ -986,7 +987,7 @@ fn void BigInt.single_byte_divide(&self, BigInt* bi2, BigInt* quotient, BigInt*
@param [&in] other @param [&in] other
@param [&inout] remainder @param [&inout] remainder
*> *>
fn void BigInt.multi_byte_divide(&self, BigInt* other, BigInt* quotient, BigInt* remainder) fn void multi_byte_divide(BigInt* self, BigInt* other, BigInt* quotient, BigInt* remainder)
{ {
uint[MAX_LEN] result; uint[MAX_LEN] result;
uint[MAX_LEN] r; uint[MAX_LEN] r;
@@ -1081,7 +1082,7 @@ fn void BigInt.multi_byte_divide(&self, BigInt* other, BigInt* quotient, BigInt*
quotient.data[y] = 0; quotient.data[y] = 0;
} }
quotient.reduce_len(); reduce_len(quotient);
remainder.len = shift_right(&r, remainder_len, shift); remainder.len = shift_right(&r, remainder_len, shift);

View File

@@ -142,7 +142,7 @@ fn void NativeTimedMutex.destroy(&mtx)
*mtx = {}; *mtx = {};
} }
fn void? NativeTimedMutex.wait_cond_var(&mtx, uint ms) @local fn void? _wait_cond_var(NativeTimedMutex *mtx, uint ms) @local
{ {
if (!win32::sleepConditionVariableSRW(&mtx.cond_var, &mtx.srw_lock, ms, 0)) if (!win32::sleepConditionVariableSRW(&mtx.cond_var, &mtx.srw_lock, ms, 0))
{ {
@@ -169,7 +169,7 @@ fn void NativeTimedMutex.lock(&mtx)
while (mtx.locks) while (mtx.locks)
{ {
mtx.wait_cond_var(win32::INFINITE)!!; _wait_cond_var(mtx, win32::INFINITE)!!;
} }
mtx.locks = 1; mtx.locks = 1;
mtx.owner_thread = current_thread; mtx.owner_thread = current_thread;
@@ -206,7 +206,7 @@ fn void? NativeTimedMutex.lock_timeout(&mtx, ulong ms)
{ {
ulong remaining_ms = remaining.to_ms(); ulong remaining_ms = remaining.to_ms();
if (remaining_ms > uint.max) remaining_ms = uint.max; if (remaining_ms > uint.max) remaining_ms = uint.max;
mtx.wait_cond_var((uint)remaining_ms)!; _wait_cond_var(mtx, (uint)remaining_ms)!;
if (!mtx.locks) if (!mtx.locks)
{ {
// Got the lock // Got the lock

View File

@@ -55,6 +55,7 @@
- Adding the incorrect sized vector to a pointer vector would cause a crash. - Adding the incorrect sized vector to a pointer vector would cause a crash.
- Member access on a struct returned by the assignment expression, cause crash #2947 - Member access on a struct returned by the assignment expression, cause crash #2947
- Trying to slice an indexable type leads to misleading error message #2958 - Trying to slice an indexable type leads to misleading error message #2958
- Warn on use of visibility modifiers on methods. #2962
## 0.7.9 Change list ## 0.7.9 Change list

View File

@@ -97,6 +97,7 @@ typedef struct
WarningLevel deprecation; WarningLevel deprecation;
WarningLevel methods_not_resolved; WarningLevel methods_not_resolved;
WarningLevel dead_code; WarningLevel dead_code;
WarningLevel method_visibility;
} Warnings; } Warnings;
typedef enum typedef enum

View File

@@ -142,6 +142,7 @@ static void usage(bool full)
print_opt("--use-old-compact-eq", "Enable the old ability to use '@compact' to make a struct comparable."); print_opt("--use-old-compact-eq", "Enable the old ability to use '@compact' to make a struct comparable.");
print_opt("--print-large-functions", "Print functions with large compile size."); print_opt("--print-large-functions", "Print functions with large compile size.");
print_opt("--warn-deadcode=<yes|no|error>", "Print warning on dead-code: yes, no, error."); print_opt("--warn-deadcode=<yes|no|error>", "Print warning on dead-code: yes, no, error.");
print_opt("--warn-methodvisibility=<yes|no|error>", "Print warning when methods have ignored visibility attributes.");
print_opt("--warn-methodsnotresolved=<yes|no|error>", "Print warning on methods not resolved when accessed: yes, no, error."); print_opt("--warn-methodsnotresolved=<yes|no|error>", "Print warning on methods not resolved when accessed: yes, no, error.");
print_opt("--warn-deprecation=<yes|no|error>", "Print warning when using deprecated code and constructs: yes, no, error."); print_opt("--warn-deprecation=<yes|no|error>", "Print warning when using deprecated code and constructs: yes, no, error.");
} }
@@ -906,6 +907,11 @@ static void parse_option(BuildOptions *options)
options->warnings.dead_code = parse_opt_select(WarningLevel, argopt, warnings); options->warnings.dead_code = parse_opt_select(WarningLevel, argopt, warnings);
return; return;
} }
if ((argopt = match_argopt("warn-methodvisibility")))
{
options->warnings.method_visibility = parse_opt_select(WarningLevel, argopt, warnings);
return;
}
if ((argopt = match_argopt("warn-methodsnotresolved"))) if ((argopt = match_argopt("warn-methodsnotresolved")))
{ {
options->warnings.methods_not_resolved = parse_opt_select(WarningLevel, argopt, warnings); options->warnings.methods_not_resolved = parse_opt_select(WarningLevel, argopt, warnings);

View File

@@ -536,6 +536,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
update_warning_if_not_set(&target->warnings.deprecation, WARNING_SILENT); update_warning_if_not_set(&target->warnings.deprecation, WARNING_SILENT);
update_warning_if_not_set(&target->warnings.methods_not_resolved, WARNING_WARN); update_warning_if_not_set(&target->warnings.methods_not_resolved, WARNING_WARN);
update_warning_if_not_set(&target->warnings.dead_code, WARNING_SILENT); update_warning_if_not_set(&target->warnings.dead_code, WARNING_SILENT);
update_warning_if_not_set(&target->warnings.method_visibility, WARNING_WARN);
break; break;
case VALIDATION_NOT_SET: case VALIDATION_NOT_SET:
target->validation_level = VALIDATION_STRICT; target->validation_level = VALIDATION_STRICT;
@@ -544,16 +545,19 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
update_warning_if_not_set(&target->warnings.methods_not_resolved, WARNING_WARN); update_warning_if_not_set(&target->warnings.methods_not_resolved, WARNING_WARN);
update_warning_if_not_set(&target->warnings.deprecation, WARNING_WARN); update_warning_if_not_set(&target->warnings.deprecation, WARNING_WARN);
update_warning_if_not_set(&target->warnings.dead_code, WARNING_WARN); update_warning_if_not_set(&target->warnings.dead_code, WARNING_WARN);
update_warning_if_not_set(&target->warnings.method_visibility, WARNING_WARN);
break; break;
case VALIDATION_OBNOXIOUS: case VALIDATION_OBNOXIOUS:
update_warning_if_not_set(&target->warnings.methods_not_resolved, WARNING_ERROR); update_warning_if_not_set(&target->warnings.methods_not_resolved, WARNING_ERROR);
update_warning_if_not_set(&target->warnings.deprecation, WARNING_ERROR); update_warning_if_not_set(&target->warnings.deprecation, WARNING_ERROR);
update_warning_if_not_set(&target->warnings.dead_code, WARNING_ERROR); update_warning_if_not_set(&target->warnings.dead_code, WARNING_ERROR);
update_warning_if_not_set(&target->warnings.method_visibility, WARNING_ERROR);
break; break;
} }
update_warning(&target->warnings.deprecation, options->warnings.deprecation); update_warning(&target->warnings.deprecation, options->warnings.deprecation);
update_warning(&target->warnings.dead_code, options->warnings.dead_code); update_warning(&target->warnings.dead_code, options->warnings.dead_code);
update_warning(&target->warnings.methods_not_resolved, options->warnings.methods_not_resolved); update_warning(&target->warnings.methods_not_resolved, options->warnings.methods_not_resolved);
update_warning(&target->warnings.method_visibility, options->warnings.method_visibility);
target->print_linking = options->print_linking || options->verbosity_level > 1; target->print_linking = options->print_linking || options->verbosity_level > 1;

View File

@@ -414,7 +414,7 @@ static Expr *parse_lambda(ParseContext *c, Expr *left, SourceSpan lhs_span UNUSE
sig->params = decls; sig->params = decls;
sig->rtype = return_type ? type_infoid(return_type) : 0; sig->rtype = return_type ? type_infoid(return_type) : 0;
sig->variadic = variadic; sig->variadic = variadic;
if (!parse_attributes(c, &func->attributes, NULL, NULL, NULL)) return poisoned_expr; if (!parse_attributes(c, &func->attributes, NULL, NULL, NULL, "on lambda declarations")) return poisoned_expr;
RANGE_EXTEND_PREV(func); RANGE_EXTEND_PREV(func);
if (tok_is(c, TOKEN_IMPLIES)) if (tok_is(c, TOKEN_IMPLIES))
{ {

View File

@@ -310,7 +310,7 @@ bool parse_module(ParseContext *c, ContractDescription *contracts)
ASSIGN_DECL_OR_RET(Decl *generic_decl, parse_generic_decl(c), false); ASSIGN_DECL_OR_RET(Decl *generic_decl, parse_generic_decl(c), false);
if (!parse_attributes(c, &attrs, &visibility, NULL, &is_cond)) return false; if (!parse_attributes(c, &attrs, &visibility, NULL, &is_cond, NULL)) return false;
if (generic_decl_old) if (generic_decl_old)
{ {
SEMA_DEPRECATED(generic_decl_old, "Module-based generics is deprecated, use `<...>` instead."); SEMA_DEPRECATED(generic_decl_old, "Module-based generics is deprecated, use `<...>` instead.");
@@ -931,7 +931,7 @@ Decl *parse_local_decl_after_type(ParseContext *c, TypeInfo *type)
advance(c); advance(c);
bool is_cond; bool is_cond;
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond)) return poisoned_decl; if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond, "on local variables")) return poisoned_decl;
decl->is_cond = is_cond; decl->is_cond = is_cond;
if (tok_is(c, TOKEN_EQ)) if (tok_is(c, TOKEN_EQ))
{ {
@@ -1012,7 +1012,7 @@ Decl *parse_const_declaration(ParseContext *c, bool is_global, bool is_extern)
else else
{ {
bool is_cond; bool is_cond;
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond)) return poisoned_decl; if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond, "on local declarations")) return poisoned_decl;
decl->is_cond = is_cond; decl->is_cond = is_cond;
} }
@@ -1043,7 +1043,7 @@ Decl *parse_var_decl(ParseContext *c)
case TOKEN_IDENT: case TOKEN_IDENT:
decl = decl_new_var_current(c, NULL, VARDECL_LOCAL); decl = decl_new_var_current(c, NULL, VARDECL_LOCAL);
advance(c); advance(c);
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond)) return poisoned_decl; if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond, "on local declarations")) return poisoned_decl;
decl->is_cond = is_cond; decl->is_cond = is_cond;
if (!tok_is(c, TOKEN_EQ)) if (!tok_is(c, TOKEN_EQ))
{ {
@@ -1058,7 +1058,7 @@ Decl *parse_var_decl(ParseContext *c)
decl = decl_new_var_current(c, NULL, c->tok == TOKEN_CT_IDENT ? VARDECL_LOCAL_CT : VARDECL_LOCAL_CT_TYPE); decl = decl_new_var_current(c, NULL, c->tok == TOKEN_CT_IDENT ? VARDECL_LOCAL_CT : VARDECL_LOCAL_CT_TYPE);
advance(c); advance(c);
span = c->span; span = c->span;
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond)) return poisoned_decl; if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond, "on local declarations")) return poisoned_decl;
if (is_cond || decl->attributes) if (is_cond || decl->attributes)
{ {
print_error_at(span, "Attributes are not allowed on compile time variables."); print_error_at(span, "Attributes are not allowed on compile time variables.");
@@ -1320,7 +1320,8 @@ static bool parse_attributes_for_global(ParseContext *c, Decl *decl)
bool is_cond; bool is_cond;
bool can_be_generic = decl_may_be_generic(decl); bool can_be_generic = decl_may_be_generic(decl);
ASSIGN_DECL_OR_RET(Decl *generics, parse_generic_decl(c), false); ASSIGN_DECL_OR_RET(Decl *generics, parse_generic_decl(c), false);
if (!parse_attributes(c, &decl->attributes, &visibility, decl_needs_prefix(decl) ? &is_builtin : NULL, &is_cond)) return false; bool is_method = decl->decl_kind == DECL_FUNC && decl->func_decl.type_parent;
if (!parse_attributes(c, &decl->attributes, &visibility, decl_needs_prefix(decl) ? &is_builtin : NULL, &is_cond, is_method ? "for method declarations" : NULL)) return false;
if (generics) if (generics)
{ {
if (!can_be_generic) if (!can_be_generic)
@@ -1345,7 +1346,22 @@ static bool parse_attributes_for_global(ParseContext *c, Decl *decl)
return true; return true;
} }
static inline bool parse_attribute_list(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref, bool use_comma) static inline bool warn_method_visibility(Attr *attr, const char *mod, const char *err)
{
switch (compiler.build.warnings.method_visibility)
{
case WARNING_WARN:
sema_warning_at(attr->span, "'%s' modifiers are ignored %s.", mod, err);
return true;
case WARNING_ERROR:
print_error_at(attr->span, "'%s' modifiers are not allowed %s.", mod, err);
return false;
default:
return true;
}
}
static inline bool parse_attribute_list(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref, bool use_comma, const char *reject_visibility)
{ {
Visibility visibility = -1; // NOLINT Visibility visibility = -1; // NOLINT
if (cond_ref) *cond_ref = false; if (cond_ref) *cond_ref = false;
@@ -1364,12 +1380,36 @@ static inline bool parse_attribute_list(ParseContext *c, Attr ***attributes_ref,
switch (attr->attr_kind) switch (attr->attr_kind)
{ {
case ATTRIBUTE_PUBLIC: case ATTRIBUTE_PUBLIC:
if (reject_visibility && attributes_ref)
{
if (!warn_method_visibility(attr, "@public", reject_visibility)) return false;
}
else if (reject_visibility)
{
RETURN_PRINT_ERROR_AT(false, attr, "Visibility modifiers are not allowed %s.", reject_visibility);
}
parsed_visibility = VISIBLE_PUBLIC; parsed_visibility = VISIBLE_PUBLIC;
break; break;
case ATTRIBUTE_PRIVATE: case ATTRIBUTE_PRIVATE:
if (reject_visibility && attributes_ref)
{
if (!warn_method_visibility(attr, "@private", reject_visibility)) return false;
}
else if (reject_visibility)
{
RETURN_PRINT_ERROR_AT(false, attr, "Visibility modifiers are not allowed %s.", reject_visibility);
}
parsed_visibility = VISIBLE_PRIVATE; parsed_visibility = VISIBLE_PRIVATE;
break; break;
case ATTRIBUTE_LOCAL: case ATTRIBUTE_LOCAL:
if (reject_visibility && attributes_ref)
{
if (!warn_method_visibility(attr, "@local", reject_visibility)) return false;
}
else if (reject_visibility)
{
RETURN_PRINT_ERROR_AT(false, attr, "Visibility modifiers are not allowed %s.", reject_visibility);
}
parsed_visibility = VISIBLE_LOCAL; parsed_visibility = VISIBLE_LOCAL;
break; break;
case ATTRIBUTE_BUILTIN: case ATTRIBUTE_BUILTIN:
@@ -1458,9 +1498,9 @@ Decl *parse_generic_decl(ParseContext *c)
* *
* @return true if parsing succeeded, false if recovery is needed * @return true if parsing succeeded, false if recovery is needed
*/ */
bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref) bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref, const char *reject_visibility)
{ {
return parse_attribute_list(c, attributes_ref, visibility_ref, builtin_ref, cond_ref, false); return parse_attribute_list(c, attributes_ref, visibility_ref, builtin_ref, cond_ref, false, reject_visibility);
} }
/** /**
@@ -1594,7 +1634,7 @@ static inline bool parse_enum_param_decl(ParseContext *c, Decl*** parameters)
if (token_is_some_ident(c->tok)) RETURN_PRINT_ERROR_HERE("Expected a name starting with a lower-case letter."); if (token_is_some_ident(c->tok)) RETURN_PRINT_ERROR_HERE("Expected a name starting with a lower-case letter.");
RETURN_PRINT_ERROR_HERE("Expected a member name here."); RETURN_PRINT_ERROR_HERE("Expected a member name here.");
} }
if (!parse_attributes(c, &param->attributes, NULL, NULL, NULL)) return false; if (!parse_attributes(c, &param->attributes, NULL, NULL, NULL, "on parameter declarations")) return false;
vec_add(*parameters, param); vec_add(*parameters, param);
RANGE_EXTEND_PREV(param); RANGE_EXTEND_PREV(param);
return true; return true;
@@ -1847,7 +1887,7 @@ CHECK_ELLIPSIS:
Decl *param = decl_new_var(name, span, type, param_kind); Decl *param = decl_new_var(name, span, type, param_kind);
param->var.type_info = type ? type_infoid(type) : 0; param->var.type_info = type ? type_infoid(type) : 0;
param->var.self_addr = ref; param->var.self_addr = ref;
if (!parse_attributes(c, &param->attributes, NULL, NULL, NULL)) return false; if (!parse_attributes(c, &param->attributes, NULL, NULL, NULL, "on parameters")) return false;
if (!no_name) if (!no_name)
{ {
if (try_consume(c, TOKEN_EQ)) if (try_consume(c, TOKEN_EQ))
@@ -1985,7 +2025,7 @@ static bool parse_struct_body(ParseContext *c, Decl *parent)
else else
{ {
bool is_cond; bool is_cond;
if (!parse_attributes(c, &member->attributes, NULL, NULL, &is_cond)) return false; if (!parse_attributes(c, &member->attributes, NULL, NULL, &is_cond, "on struct and union fields")) return false;
member->is_cond = true; member->is_cond = true;
if (!parse_struct_body(c, member)) return decl_poison(parent); if (!parse_struct_body(c, member)) return decl_poison(parent);
} }
@@ -2029,7 +2069,7 @@ static bool parse_struct_body(ParseContext *c, Decl *parent)
} }
advance(c); advance(c);
bool is_cond; bool is_cond;
if (!parse_attributes(c, &member->attributes, NULL, NULL, &is_cond)) return false; if (!parse_attributes(c, &member->attributes, NULL, NULL, &is_cond, "on struct and union fields")) return false;
member->is_cond = true; member->is_cond = true;
if (!try_consume(c, TOKEN_COMMA)) break; if (!try_consume(c, TOKEN_COMMA)) break;
if (was_inline) if (was_inline)
@@ -2178,7 +2218,7 @@ static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl)
is_consecutive = true; is_consecutive = true;
} }
bool is_cond = false; bool is_cond = false;
if (!parse_attributes(c, &member_decl->attributes, NULL, NULL, &is_cond)) return false; if (!parse_attributes(c, &member_decl->attributes, NULL, NULL, &is_cond, "on bitstruct fields")) return false;
member_decl->is_cond = is_cond; member_decl->is_cond = is_cond;
CONSUME_OR_RET(TOKEN_EOS, false); CONSUME_OR_RET(TOKEN_EOS, false);
unsigned index = vec_size(decl->strukt.members); unsigned index = vec_size(decl->strukt.members);
@@ -2199,7 +2239,7 @@ static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl)
member_decl->var.end = NULL; member_decl->var.end = NULL;
} }
bool is_cond = false; bool is_cond = false;
if (!parse_attributes(c, &member_decl->attributes, NULL, NULL, &is_cond)) return false; if (!parse_attributes(c, &member_decl->attributes, NULL, NULL, &is_cond, "on bitstruct fields")) return false;
member_decl->is_cond = is_cond; member_decl->is_cond = is_cond;
CONSUME_EOS_OR_RET(false); CONSUME_EOS_OR_RET(false);
if (is_consecutive) if (is_consecutive)
@@ -2396,7 +2436,7 @@ static inline Decl *parse_alias_type(ParseContext *c, ContractDescription *contr
{ {
return poisoned_decl; return poisoned_decl;
} }
if (!parse_attributes(c, &decl_type->attributes, NULL, NULL, NULL)) return poisoned_decl; if (!parse_attributes(c, &decl_type->attributes, NULL, NULL, NULL, "on the target of an alias (maybe you intended it *before* the '='?)")) return poisoned_decl;
attach_deprecation_from_contract(c, contracts, decl_type); attach_deprecation_from_contract(c, contracts, decl_type);
RANGE_EXTEND_PREV(decl_type); RANGE_EXTEND_PREV(decl_type);
RANGE_EXTEND_PREV(decl); RANGE_EXTEND_PREV(decl);
@@ -2584,7 +2624,7 @@ static inline Decl *parse_attrdef(ParseContext *c)
bool is_cond; bool is_cond;
bool is_builtin = false; bool is_builtin = false;
if (!parse_attribute_list(c, &attributes, NULL, decl_needs_prefix(decl) ? &is_builtin : NULL, &is_cond, true)) return poisoned_decl; if (!parse_attribute_list(c, &attributes, NULL, decl_needs_prefix(decl) ? &is_builtin : NULL, &is_cond, true, "cannot be aliased using 'attrdef'")) return poisoned_decl;
decl->attr_decl.attrs = attributes; decl->attr_decl.attrs = attributes;
CONSUME_EOS_OR_RET(poisoned_decl); CONSUME_EOS_OR_RET(poisoned_decl);
return decl; return decl;

View File

@@ -64,7 +64,7 @@ Ast *parse_short_body(ParseContext *c, TypeInfoId return_type, bool is_regular_f
bool parse_attribute(ParseContext *c, Attr **attribute_ref, bool expect_eos); bool parse_attribute(ParseContext *c, Attr **attribute_ref, bool expect_eos);
bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref); bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref, const char *reject_visibility);
Decl *parse_generic_decl(ParseContext *c); Decl *parse_generic_decl(ParseContext *c);
bool parse_switch_body(ParseContext *c, Ast ***cases, TokenType case_type, TokenType default_type); bool parse_switch_body(ParseContext *c, Ast ***cases, TokenType case_type, TokenType default_type);

View File

@@ -2870,6 +2870,7 @@ static inline bool sema_compare_method_with_interface(SemaContext *context, Decl
static inline bool sema_analyse_method(SemaContext *context, Decl *decl) static inline bool sema_analyse_method(SemaContext *context, Decl *decl)
{ {
ASSERT_SPAN(decl, decl->decl_kind == DECL_FUNC); ASSERT_SPAN(decl, decl->decl_kind == DECL_FUNC);
// Check for @init, @finalizer, @test and @benchmark // Check for @init, @finalizer, @test and @benchmark
if (decl->func_decl.attr_init | decl->func_decl.attr_finalizer) if (decl->func_decl.attr_init | decl->func_decl.attr_finalizer)
{ {
@@ -2884,6 +2885,7 @@ static inline bool sema_analyse_method(SemaContext *context, Decl *decl)
// Resolve the parent type. // Resolve the parent type.
TypeInfo *parent_type = type_infoptr(decl->func_decl.type_parent); TypeInfo *parent_type = type_infoptr(decl->func_decl.type_parent);
ASSERT(parent_type->resolve_status == RESOLVE_DONE); ASSERT(parent_type->resolve_status == RESOLVE_DONE);
Type *par_type = parent_type->type->canonical; Type *par_type = parent_type->type->canonical;

View File

@@ -1,9 +1,9 @@
alias NodeNotifyHandler = fn void(TreeView* this, TreeNode* node, String prop, void* data); alias NodeNotifyHandler = fn void(TreeView* this, TreeNode* node, String prop, void* data);
fn void TreeView.nodeNotifyHandler(TreeView* this, TreeNode* node, String prop, void* data) @private {} fn void TreeView.nodeNotifyHandler(TreeView* this, TreeNode* node, String prop, void* data) {}
struct TreeNode { int abc; NodeNotifyHandler notifyHandler; } struct TreeNode { int abc; NodeNotifyHandler notifyHandler; }
struct TreeView { int abc; } struct TreeView { int abc; }
fn void TreeView.addNodeInternal(TreeView* this, int nop, TreeNode* node, TreeNode* pnode = null, int pos = -1) @private fn void TreeView.addNodeInternal(TreeView* this, int nop, TreeNode* node, TreeNode* pnode = null, int pos = -1)
{ {
node.notifyHandler = &TreeView.nodeNotifyHandler; // This is the line node.notifyHandler = &TreeView.nodeNotifyHandler; // This is the line
} }

View File

@@ -1,35 +0,0 @@
module test;
import abc;
struct Foo
{
int x;
}
fn int Foo.get1(Foo* f) @private => f.x;
fn int Foo.get2(Foo* f) => f.x;
fn int Foo.get3(Foo* f) @local => f.x;
fn int Bar.get1(Bar* f) @private => f.x;
fn int Bar.get2(Bar* f) => f.x;
fn int Bar.get3(Bar* f) @local => f.x;
fn int main()
{
Foo x = { 1 };
x.get1();
x.get2();
x.get3();
Bar y = { 1 };
y.get1();
y.get2();
y.get3();
return 1;
}
module abc;
struct Bar
{
int x;
}

View File

@@ -1,37 +0,0 @@
module test;
import abc;
struct Foo
{
int x;
}
fn int Foo.get1(Foo* f) @private => f.x;
fn int Foo.get2(Foo* f) => f.x;
fn int Foo.get3(Foo* f) @local => f.x;
fn int Bar.get1(Bar* f) @private => f.x;
fn int Bar.get2(Bar* f) => f.x;
fn int Bar.get3(Bar* f) @local => f.x;
module abc;
import test;
struct Bar
{
int x;
}
Foo x = { 1 };
Bar y = { 1 };
fn int test()
{
x.get1();
x.get2();
x.get3();
y.get1();
y.get2();
y.get3();
return 1;
}

View File

@@ -1,37 +0,0 @@
module test;
import abc;
struct Foo
{
int x;
}
fn int Foo.get1(Foo* f) @private => f.x;
fn int Foo.get2(Foo* f) => f.x;
fn int Foo.get3(Foo* f) @local => f.x;
fn int Bar.get1(Bar* f) @private => f.x;
fn int Bar.get2(Bar* f) => f.x;
fn int Bar.get3(Bar* f) @local => f.x;
module abc;
import test @public;
struct Bar
{
int x;
}
Foo x = { 1 };
Bar y = { 1 };
fn int test()
{
x.get1();
x.get2();
x.get3();
y.get1();
y.get2();
y.get3();
return 1;
}

View File

@@ -1,9 +1,9 @@
alias NodeNotifyHandler = fn void(TreeView* this, TreeNode* node, String prop, void* data); alias NodeNotifyHandler = fn void(TreeView* this, TreeNode* node, String prop, void* data);
fn void TreeView.nodeNotifyHandler(TreeView* this, TreeNode* node, String prop, void* data) @private {} fn void TreeView.nodeNotifyHandler(TreeView* this, TreeNode* node, String prop, void* data) {}
struct TreeNode { int abc; NodeNotifyHandler notifyHandler; } struct TreeNode { int abc; NodeNotifyHandler notifyHandler; }
struct TreeView { int abc; } struct TreeView { int abc; }
fn void TreeView.addNodeInternal(TreeView* this, int nop, TreeNode* node, TreeNode* pnode = null, int pos = -1) @private fn void TreeView.addNodeInternal(TreeView* this, int nop, TreeNode* node, TreeNode* pnode = null, int pos = -1)
{ {
node.notifyHandler = &(this.nodeNotifyHandler); // #error: Taking the address of a method node.notifyHandler = &(this.nodeNotifyHandler); // #error: Taking the address of a method
} }

View File

@@ -143,7 +143,7 @@ fn Token? Lexer.expect(&self, fault err, Token... tokens)
return err~; return err~;
} }
fn void? Lexer.skip_whitespace(&self) @private fn void? Lexer.skip_whitespace(&self)
{ {
self.span = 0; self.span = 0;
while (true) while (true)
@@ -166,7 +166,7 @@ fn void? Lexer.skip_whitespace(&self) @private
} }
} }
fn ulong? Lexer.parse_uint(&self) @private fn ulong? Lexer.parse_uint(&self)
{ {
ulong x; ulong x;
char c = self.reader.read_byte()!; char c = self.reader.read_byte()!;
@@ -190,7 +190,7 @@ fn ulong? Lexer.parse_uint(&self) @private
return self.parse_decimal()!; return self.parse_decimal()!;
} }
fn ulong? Lexer.parse_decimal(&self) @private fn ulong? Lexer.parse_decimal(&self)
{ {
return @parse_uint(self, ulong; ulong x, char c, bool ok) return @parse_uint(self, ulong; ulong x, char c, bool ok)
{ {
@@ -202,7 +202,7 @@ fn ulong? Lexer.parse_decimal(&self) @private
}; };
} }
fn ulong? Lexer.parse_hexadecimal(&self) @private fn ulong? Lexer.parse_hexadecimal(&self)
{ {
return @parse_uint(self, ulong; ulong x, char c, bool ok) return @parse_uint(self, ulong; ulong x, char c, bool ok)
{ {
@@ -219,7 +219,7 @@ fn ulong? Lexer.parse_hexadecimal(&self) @private
}; };
} }
fn ulong? Lexer.parse_binary(&self) @private fn ulong? Lexer.parse_binary(&self)
{ {
return @parse_uint(self, ulong; ulong x, char c, bool ok) return @parse_uint(self, ulong; ulong x, char c, bool ok)
{ {
@@ -231,7 +231,7 @@ fn ulong? Lexer.parse_binary(&self) @private
}; };
} }
fn ulong? Lexer.parse_octal(&self) @private fn ulong? Lexer.parse_octal(&self)
{ {
return @parse_uint(self, ulong; ulong x, char c, bool ok) return @parse_uint(self, ulong; ulong x, char c, bool ok)
{ {
@@ -275,7 +275,7 @@ macro @parse_uint(self, $Type; @body(x, c, ok)) @private
return x; return x;
} }
fn String? Lexer.parse_string(&self, char quote) @private fn String? Lexer.parse_string(&self, char quote)
{ {
char c = self.read_char_for_string()!; char c = self.read_char_for_string()!;
if (c == quote) return ""; if (c == quote) return "";
@@ -316,7 +316,7 @@ fn String? Lexer.parse_string(&self, char quote) @private
} }
} }
fn char? Lexer.parse_rune(&self) @private fn char? Lexer.parse_rune(&self)
{ {
char x = self.reader.read_byte()!; char x = self.reader.read_byte()!;
char c = self.reader.read_byte()!; char c = self.reader.read_byte()!;
@@ -324,7 +324,7 @@ fn char? Lexer.parse_rune(&self) @private
return x; return x;
} }
macro char? Lexer.read_char_for_string(&self) @private macro char? Lexer.read_char_for_string(&self)
{ {
char? c = self.reader.read_byte(); char? c = self.reader.read_byte();
if (catch err = c) if (catch err = c)
@@ -335,7 +335,7 @@ macro char? Lexer.read_char_for_string(&self) @private
return c; return c;
} }
fn Token? Lexer.parse_token(&self) @private fn Token? Lexer.parse_token(&self)
{ {
usz n = self.reader.read(self.buf)!; usz n = self.reader.read(self.buf)!;
defer self.unread(n); defer self.unread(n);
@@ -344,7 +344,7 @@ fn Token? Lexer.parse_token(&self) @private
return tok; return tok;
} }
fn void? Lexer.parse_comment(&self, String end) @private fn void? Lexer.parse_comment(&self, String end)
{ {
// Find the end token and accumulate the data in between. // Find the end token and accumulate the data in between.
DString acc; DString acc;
@@ -367,7 +367,7 @@ fn void? Lexer.parse_comment(&self, String end) @private
} }
} }
macro Lexer.unread(self, n) @private macro Lexer.unread(self, n)
{ {
switch switch
{ {
@@ -383,7 +383,7 @@ macro Lexer.unread(self, n) @private
} }
} }
fn String? Lexer.parse_ident(&self) @private fn String? Lexer.parse_ident(&self)
{ {
DString str; DString str;
str.init(self.allocator, 8); str.init(self.allocator, 8);
@@ -528,7 +528,7 @@ fn void? Trie.del(&self, char[] key)
self.nodes[0].del(self, key, path)!; self.nodes[0].del(self, key, path)!;
} }
fn Value? TrieNode.get(&self, Trie *t, char[] key) @private fn Value? TrieNode.get(&self, Trie *t, char[] key)
{ {
if (key.len == 0) return self.valid ? self.value : NOT_FOUND~; if (key.len == 0) return self.valid ? self.value : NOT_FOUND~;
char c = key[0]; char c = key[0];
@@ -537,7 +537,7 @@ fn Value? TrieNode.get(&self, Trie *t, char[] key) @private
return t.nodes[idx].get(t, key[1..]); return t.nodes[idx].get(t, key[1..]);
} }
fn Value? TrieNode.get_best(&self, Trie *t, char[] key, Index result) @private fn Value? TrieNode.get_best(&self, Trie *t, char[] key, Index result)
{ {
if (key.len == 0) if (key.len == 0)
{ {
@@ -556,7 +556,7 @@ fn Value? TrieNode.get_best(&self, Trie *t, char[] key, Index result) @private
return next.get_best(t, key[1..], result); return next.get_best(t, key[1..], result);
} }
fn void? TrieNode.set(&self, Trie *t, char[] key, Value value) @private fn void? TrieNode.set(&self, Trie *t, char[] key, Value value)
{ {
if (key.len == 0) if (key.len == 0)
{ {
@@ -578,7 +578,7 @@ fn void? TrieNode.set(&self, Trie *t, char[] key, Value value) @private
t.nodes[idx].set(t, key[1..], value)!; t.nodes[idx].set(t, key[1..], value)!;
} }
fn void? TrieNode.del(&self, Trie* t, char[] key, TriePath path) @private fn void? TrieNode.del(&self, Trie* t, char[] key, TriePath path)
{ {
if (key.len > 0) if (key.len > 0)
{ {

View File

@@ -15,7 +15,7 @@ fn int Abc.mul_abc(Abc abc, int self) @operator_s(*) => self * abc.a;
fn Abc Abc.negate(self) @operator(~) => { ~self.a }; fn Abc Abc.negate(self) @operator(~) => { ~self.a };
fn Abc Abc.negate2(self) @operator(-) => { -self.a }; fn Abc Abc.negate2(self) @operator(-) => { -self.a };
fn Abc Abc.shr2(self, int x) @operator(>>) => { self.a >> x }; fn Abc Abc.shr2(self, int x) @operator(>>) => { self.a >> x };
fn Abc Abc.shl2(self, int x) @operator(<<) @local { b++; return { self.a << x }; } fn Abc Abc.shl2(self, int x) @operator(<<) { b++; return { self.a << x }; }
fn Abc Abc.shl(self, Abc x) @operator(<<) => { self.a << x.a }; fn Abc Abc.shl(self, Abc x) @operator(<<) => { self.a << x.a };
fn Abc Abc.div(self, Abc abc) @operator(/) => { self.a / abc.a }; fn Abc Abc.div(self, Abc abc) @operator(/) => { self.a / abc.a };
fn Abc Abc.rem(self, Abc abc) @operator(%) => { self.a % abc.a }; fn Abc Abc.rem(self, Abc abc) @operator(%) => { self.a % abc.a };