mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
- Warn on use of visibility modifiers on methods. #2962
This commit is contained in:
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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++;
|
||||||
|
|||||||
@@ -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)!;
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 ;
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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..])
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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~;
|
||||||
|
|||||||
@@ -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, "ient, &remainder);
|
single_byte_divide(self, &other, "ient, &remainder);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
self.multi_byte_divide(&other, "ient, &remainder);
|
multi_byte_divide(self, &other, "ient, &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, "ient, &remainder);
|
single_byte_divide(self, &bi2, "ient, &remainder);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
self.multi_byte_divide(&bi2, "ient, &remainder);
|
multi_byte_divide(self, &bi2, "ient, &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, "ient, &remainder);
|
single_byte_divide(&a, &big_radix, "ient, &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);
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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, ¶m->attributes, NULL, NULL, NULL)) return false;
|
if (!parse_attributes(c, ¶m->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, ¶m->attributes, NULL, NULL, NULL)) return false;
|
if (!parse_attributes(c, ¶m->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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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 };
|
||||||
|
|||||||
Reference in New Issue
Block a user