mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Fix missing free on GrowableBitSet. init_new/init_temp for GrowableBitSet, LinkedList, List, HashMap, DString, ByteBuffer. Interface to_string renamed to_new_string. Change in allocator usage, malloc is now heap. Added new_array, new_zero_array, new, new_clear, clone. Concat => concat_new. string::printf => string::new_format, string::tprintf => string::tformat. "to_*" are now "to_new_*" and "to_temp_*". "from_*" is "new_from*"
This commit is contained in:
committed by
Christoffer Lerno
parent
69470b8738
commit
1e38ccdd2b
@@ -82,14 +82,24 @@ struct GrowableBitSet
|
||||
GrowableBitSetList data;
|
||||
}
|
||||
|
||||
fn void GrowableBitSet.init(&self, usz initial_capacity = 1, Allocator* using = mem::heap())
|
||||
/**
|
||||
* @param initial_capacity
|
||||
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
|
||||
**/
|
||||
fn GrowableBitSet* GrowableBitSet.init_new(&self, usz initial_capacity = 1, Allocator* allocator = mem::heap())
|
||||
{
|
||||
self.data.init(initial_capacity, using);
|
||||
self.data.init_new(initial_capacity, allocator);
|
||||
return self;
|
||||
}
|
||||
|
||||
fn void GrowableBitSet.tinit(&self)
|
||||
fn GrowableBitSet* GrowableBitSet.init_temp(&self, usz initial_capacity = 1)
|
||||
{
|
||||
self.init(.using = mem::temp());
|
||||
return self.init_new(initial_capacity, mem::temp()) @inline;
|
||||
}
|
||||
|
||||
fn void GrowableBitSet.free(&self)
|
||||
{
|
||||
self.data.free();
|
||||
}
|
||||
|
||||
fn usz GrowableBitSet.cardinality(&self)
|
||||
|
||||
@@ -25,9 +25,14 @@ fn usz! EnumMap.to_format(&self, Formatter* formatter) @dynamic
|
||||
return n;
|
||||
}
|
||||
|
||||
fn String EnumMap.to_string(&self, Allocator* using = mem::heap()) @dynamic
|
||||
fn String EnumMap.to_new_string(&self, Allocator* allocator = mem::heap()) @dynamic
|
||||
{
|
||||
return string::printf("%s", *self);
|
||||
return string::new_format("%s", *self, .allocator = allocator);
|
||||
}
|
||||
|
||||
fn String EnumMap.to_tstring(&self) @dynamic
|
||||
{
|
||||
return string::tformat("%s", *self);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -140,9 +140,14 @@ fn usz! EnumSet.to_format(&set, Formatter* formatter) @dynamic
|
||||
return n;
|
||||
}
|
||||
|
||||
fn String EnumSet.to_string(&set, Allocator* using = mem::heap()) @dynamic
|
||||
fn String EnumSet.to_new_string(&set, Allocator* allocator = mem::heap()) @dynamic
|
||||
{
|
||||
return string::printf("%s", *set);
|
||||
return string::new_format("%s", *set, .allocator = allocator);
|
||||
}
|
||||
|
||||
fn String EnumSet.to_tstring(&set) @dynamic
|
||||
{
|
||||
return string::tformat("%s", *set);
|
||||
}
|
||||
|
||||
module std::collections::enumset::private;
|
||||
|
||||
@@ -28,12 +28,20 @@ fn void LinkedList.push_last(&self, Type value)
|
||||
self.link_last(value);
|
||||
}
|
||||
|
||||
fn void LinkedList.init(&self, Allocator* using = mem::heap())
|
||||
/**
|
||||
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
|
||||
* @return "the initialized list"
|
||||
**/
|
||||
fn LinkedList* LinkedList.init_new(&self, Allocator* allocator = mem::heap())
|
||||
{
|
||||
*self = { .allocator = using };
|
||||
*self = { .allocator = allocator };
|
||||
return self;
|
||||
}
|
||||
|
||||
fn void LinkedList.tinit(&self) => self.init(mem::temp()) @inline;
|
||||
fn LinkedList* LinkedList.init_temp(&self)
|
||||
{
|
||||
return self.init_new(mem::temp()) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require self.allocator
|
||||
@@ -45,7 +53,7 @@ macro void LinkedList.free_node(&self, Node* node) @private
|
||||
macro Node* LinkedList.alloc_node(&self) @private
|
||||
{
|
||||
if (!self.allocator) self.allocator = mem::heap();
|
||||
return malloc(Node, .using = self.allocator);
|
||||
return self.allocator.new(Node);
|
||||
}
|
||||
|
||||
fn void LinkedList.link_first(&self, Type value) @private
|
||||
@@ -175,7 +183,7 @@ fn void LinkedList.insert(&self, usz index, Type element)
|
||||
fn void LinkedList.link_before(&self, Node *succ, Type value) @private
|
||||
{
|
||||
Node* pred = succ.prev;
|
||||
Node* new_node = malloc(Node);
|
||||
Node* new_node = self.alloc_node();
|
||||
*new_node = { .prev = pred, .next = succ, .value = value };
|
||||
succ.prev = new_node;
|
||||
if (!pred)
|
||||
|
||||
@@ -19,36 +19,42 @@ struct List (Printable)
|
||||
}
|
||||
|
||||
/**
|
||||
* @require using "A valid allocator must be provided"
|
||||
* @param initial_capacity "The initial capacity to reserve"
|
||||
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
|
||||
**/
|
||||
fn void List.init(&self, usz initial_capacity = 16, Allocator* using = mem::heap())
|
||||
fn List* List.init_new(&self, usz initial_capacity = 16, Allocator* allocator = mem::heap())
|
||||
{
|
||||
self.allocator = using;
|
||||
self.allocator = allocator;
|
||||
self.size = 0;
|
||||
if (initial_capacity > 0)
|
||||
{
|
||||
initial_capacity = math::next_power_of_2(initial_capacity);
|
||||
self.entries = malloc_aligned(Type, initial_capacity, .alignment = Type[1].alignof, .using = using)!!;
|
||||
self.entries = allocator.alloc_aligned(Type.sizeof * initial_capacity, .alignment = Type[1].alignof)!!;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.entries = null;
|
||||
}
|
||||
self.capacity = initial_capacity;
|
||||
}
|
||||
|
||||
fn void List.tinit(&self, usz initial_capacity = 16)
|
||||
{
|
||||
self.init(initial_capacity, mem::temp()) @inline;
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the list using the temp allocator.
|
||||
*
|
||||
* @param initial_capacity "The initial capacity to reserve"
|
||||
**/
|
||||
fn List* List.init_temp(&self, usz initial_capacity = 16)
|
||||
{
|
||||
return self.init_new(initial_capacity, mem::temp()) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the List by referencing the provided types.
|
||||
* @require self.size == 0 "The List must be empty"
|
||||
**/
|
||||
fn void List.init_wrapping_array(&self, Type[] types, Allocator* using = mem::heap())
|
||||
fn void List.init_wrapping_array(&self, Type[] types, Allocator* allocator = mem::heap())
|
||||
{
|
||||
self.allocator = using;
|
||||
self.allocator = allocator;
|
||||
self.size = types.len;
|
||||
self.capacity = types.len;
|
||||
self.entries = types.ptr;
|
||||
@@ -74,9 +80,14 @@ fn usz! List.to_format(&self, Formatter* formatter) @dynamic
|
||||
}
|
||||
}
|
||||
|
||||
fn String List.to_string(&self, Allocator* using = mem::heap()) @dynamic
|
||||
fn String List.to_new_string(&self, Allocator* allocator = mem::heap()) @dynamic
|
||||
{
|
||||
return string::printf("%s", *self);
|
||||
return string::new_format("%s", *self, .allocator = allocator);
|
||||
}
|
||||
|
||||
fn String List.to_tstring(&self)
|
||||
{
|
||||
return string::tformat("%s", *self);
|
||||
}
|
||||
|
||||
fn void List.push(&self, Type element) @inline
|
||||
@@ -136,14 +147,19 @@ fn void List.add_all(&self, List* other_list)
|
||||
}
|
||||
|
||||
|
||||
fn Type[] List.to_array(&self, Allocator* using = mem::heap())
|
||||
fn Type[] List.to_new_array(&self, Allocator* allocator = mem::heap())
|
||||
{
|
||||
if (!self.size) return Type[] {};
|
||||
Type[] result = malloc(Type, self.size, .using = using);
|
||||
Type[] result = allocator.new_array(Type, self.size);
|
||||
result[..] = self.entries[:self.size];
|
||||
return result;
|
||||
}
|
||||
|
||||
fn Type[] List.to_tarray(&self)
|
||||
{
|
||||
return self.to_new_array(mem::temp());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the elements in a list.
|
||||
**/
|
||||
@@ -244,7 +260,7 @@ fn Type List.get(&self, usz index) @inline
|
||||
fn void List.free(&self)
|
||||
{
|
||||
if (!self.allocator) return;
|
||||
free_aligned(self.entries, .using = self.allocator);
|
||||
self.allocator.free_aligned(self.entries);
|
||||
self.capacity = 0;
|
||||
self.size = 0;
|
||||
self.entries = null;
|
||||
@@ -342,7 +358,7 @@ fn void List.reserve(&self, usz min_capacity)
|
||||
if (self.capacity >= min_capacity) return;
|
||||
if (!self.allocator) self.allocator = mem::heap();
|
||||
min_capacity = math::next_power_of_2(min_capacity);
|
||||
self.entries = realloc_aligned(self.entries, Type.sizeof * min_capacity, .alignment = Type[1].alignof, .using = self.allocator) ?? null;
|
||||
self.entries = self.allocator.realloc_aligned(self.entries, Type.sizeof * min_capacity, .alignment = Type[1].alignof) ?? null;
|
||||
self.capacity = min_capacity;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,19 +20,20 @@ struct HashMap
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] allocator "The allocator to use"
|
||||
* @require capacity > 0 "The capacity must be 1 or higher"
|
||||
* @require load_factor > 0.0 "The load factor must be higher than 0"
|
||||
* @require !map.allocator "Map was already initialized"
|
||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
||||
* @require (bool)using "The allocator must be non-null"
|
||||
**/
|
||||
fn void HashMap.init(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator* using = mem::heap())
|
||||
fn HashMap* HashMap.init_new(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator* allocator = mem::heap())
|
||||
{
|
||||
capacity = math::next_power_of_2(capacity);
|
||||
map.allocator = using;
|
||||
map.allocator = allocator;
|
||||
map.load_factor = load_factor;
|
||||
map.threshold = (uint)(capacity * load_factor);
|
||||
map.table = calloc(Entry*, capacity, .using = using);
|
||||
map.table = allocator.new_zero_array(Entry*, capacity);
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,9 +42,9 @@ fn void HashMap.init(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_
|
||||
* @require !map.allocator "Map was already initialized"
|
||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
||||
**/
|
||||
fn void HashMap.tinit(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
|
||||
fn HashMap* HashMap.init_temp(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
|
||||
{
|
||||
map.init(capacity, load_factor, mem::temp());
|
||||
return map.init_new(capacity, load_factor, mem::temp());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,15 +58,23 @@ fn bool HashMap.is_initialized(&map)
|
||||
return (bool)map.allocator;
|
||||
}
|
||||
|
||||
fn void HashMap.init_from_map(&map, HashMap* other_map, Allocator* using = mem::heap())
|
||||
/**
|
||||
* @param [&inout] allocator "The allocator to use"
|
||||
* @param [&in] other_map "The map to copy from."
|
||||
**/
|
||||
fn HashMap* HashMap.init_new_from_map(&self, HashMap* other_map, Allocator* allocator = mem::heap())
|
||||
{
|
||||
map.init(other_map.table.len, other_map.load_factor, using);
|
||||
map.put_all_for_create(other_map);
|
||||
self.init_new(other_map.table.len, other_map.load_factor, allocator);
|
||||
self.put_all_for_create(other_map);
|
||||
return self;
|
||||
}
|
||||
|
||||
fn void HashMap.tinit_from_map(&map, HashMap* other_map)
|
||||
/**
|
||||
* @param [&in] other_map "The map to copy from."
|
||||
**/
|
||||
fn HashMap* HashMap.init_temp_from_map(&map, HashMap* other_map)
|
||||
{
|
||||
map.init_from_map(other_map, mem::temp()) @inline;
|
||||
return map.init_new_from_map(other_map, mem::temp()) @inline;
|
||||
}
|
||||
|
||||
fn bool HashMap.is_empty(&map) @inline
|
||||
@@ -137,7 +146,7 @@ fn bool HashMap.set(&map, Key key, Value value) @operator([]=)
|
||||
// If the map isn't initialized, use the defaults to initialize it.
|
||||
if (!map.allocator)
|
||||
{
|
||||
map.init();
|
||||
map.init_new();
|
||||
}
|
||||
uint hash = rehash(key.hash());
|
||||
uint index = index_for(hash, map.table.len);
|
||||
@@ -188,14 +197,14 @@ fn void HashMap.free(&map)
|
||||
|
||||
fn Key[] HashMap.key_tlist(&map)
|
||||
{
|
||||
return map.key_list(mem::temp()) @inline;
|
||||
return map.key_new_list(mem::temp()) @inline;
|
||||
}
|
||||
|
||||
fn Key[] HashMap.key_list(&map, Allocator* using = mem::heap())
|
||||
fn Key[] HashMap.key_new_list(&map, Allocator* allocator = mem::heap())
|
||||
{
|
||||
if (!map.count) return {};
|
||||
|
||||
Key[] list = calloc(Key, map.count, .using = using);
|
||||
Key[] list = allocator.new_array(Key, map.count);
|
||||
usz index = 0;
|
||||
foreach (Entry* entry : map.table)
|
||||
{
|
||||
@@ -232,13 +241,13 @@ macro HashMap.@each_entry(map; @body(entry))
|
||||
|
||||
fn Value[] HashMap.value_tlist(&map)
|
||||
{
|
||||
return map.value_list(mem::temp()) @inline;
|
||||
return map.value_new_list(mem::temp()) @inline;
|
||||
}
|
||||
|
||||
fn Value[] HashMap.value_list(&map, Allocator* using = mem::heap())
|
||||
fn Value[] HashMap.value_new_list(&map, Allocator* allocator = mem::heap())
|
||||
{
|
||||
if (!map.count) return {};
|
||||
Value[] list = calloc(Value, map.count, .using = using);
|
||||
Value[] list = allocator.new_array(Value, map.count);
|
||||
usz index = 0;
|
||||
foreach (Entry* entry : map.table)
|
||||
{
|
||||
@@ -269,7 +278,7 @@ fn bool HashMap.has_value(&map, Value v) @if(VALUE_IS_EQUATABLE)
|
||||
|
||||
fn void HashMap.add_entry(&map, uint hash, Key key, Value value, uint bucket_index) @private
|
||||
{
|
||||
Entry* entry = malloc(Entry, .using = map.allocator);
|
||||
Entry* entry = map.allocator.new(Entry);
|
||||
$if COPY_KEYS:
|
||||
key = key.copy(map.allocator);
|
||||
$endif
|
||||
@@ -290,7 +299,7 @@ fn void HashMap.resize(&map, uint new_capacity) @private
|
||||
map.threshold = uint.max;
|
||||
return;
|
||||
}
|
||||
Entry*[] new_table = calloc(Entry*, new_capacity, .using = map.allocator);
|
||||
Entry*[] new_table = map.allocator.new_zero_array(Entry*, new_capacity);
|
||||
map.transfer(new_table);
|
||||
map.table = new_table;
|
||||
map.free_internal(old_table.ptr);
|
||||
@@ -389,7 +398,7 @@ fn bool HashMap.remove_entry_for_key(&map, Key key) @private
|
||||
fn void HashMap.create_entry(&map, uint hash, Key key, Value value, int bucket_index) @private
|
||||
{
|
||||
Entry *e = map.table[bucket_index];
|
||||
Entry* entry = malloc(Entry, .using = map.allocator);
|
||||
Entry* entry = map.allocator.new(Entry);
|
||||
$if COPY_KEYS:
|
||||
key = key.copy(map.allocator);
|
||||
$endif
|
||||
@@ -401,7 +410,7 @@ fn void HashMap.create_entry(&map, uint hash, Key key, Value value, int bucket_i
|
||||
fn void HashMap.free_entry(&self, Entry *entry) @local
|
||||
{
|
||||
$if COPY_KEYS:
|
||||
entry.key.free(self.allocator);
|
||||
self.allocator.free(entry.key);
|
||||
$endif
|
||||
self.free_internal(entry);
|
||||
}
|
||||
|
||||
@@ -78,10 +78,10 @@ fn usz! Object.to_format(&self, Formatter* formatter) @dynamic
|
||||
}
|
||||
}
|
||||
|
||||
fn Object* new_obj(Allocator* using = mem::heap())
|
||||
fn Object* new_obj(Allocator* allocator)
|
||||
{
|
||||
Object* o = malloc(Object, .using = using);
|
||||
*o = { .allocator = using, .type = void.typeid };
|
||||
Object* o = allocator.new(Object);
|
||||
*o = { .allocator = allocator, .type = void.typeid };
|
||||
return o;
|
||||
}
|
||||
|
||||
@@ -90,31 +90,31 @@ fn Object* new_null()
|
||||
return &NULL_OBJECT;
|
||||
}
|
||||
|
||||
fn Object* new_int(int128 i, Allocator* using = mem::heap())
|
||||
fn Object* new_int(int128 i, Allocator* allocator)
|
||||
{
|
||||
Object* o = malloc(Object, .using = using);
|
||||
*o = { .i = i, .allocator = using, .type = int128.typeid };
|
||||
Object* o = allocator.new(Object);
|
||||
*o = { .i = i, .allocator = allocator, .type = int128.typeid };
|
||||
return o;
|
||||
}
|
||||
|
||||
macro Object* new_enum(e, Allocator* using = mem::heap())
|
||||
macro Object* new_enum(e, Allocator* allocator)
|
||||
{
|
||||
Object* o = malloc(Object, .using = using);
|
||||
*o = { .i = (int128)e, .allocator = using, .type = $typeof(e).typeid };
|
||||
Object* o = allocator.new(Object);
|
||||
*o = { .i = (int128)e, .allocator = allocator, .type = $typeof(e).typeid };
|
||||
return o;
|
||||
}
|
||||
|
||||
fn Object* new_float(double f, Allocator* using = mem::heap())
|
||||
fn Object* new_float(double f, Allocator* allocator)
|
||||
{
|
||||
Object* o = malloc(Object, .using = using);
|
||||
*o = { .f = f, .allocator = using, .type = double.typeid };
|
||||
Object* o = allocator.new(Object);
|
||||
*o = { .f = f, .allocator = allocator, .type = double.typeid };
|
||||
return o;
|
||||
}
|
||||
|
||||
fn Object* new_string(String s, Allocator* using = mem::heap())
|
||||
fn Object* new_string(String s, Allocator* allocator)
|
||||
{
|
||||
Object* o = malloc(Object, .using = using);
|
||||
*o = { .s = s.copy(using), .allocator = using, .type = String.typeid };
|
||||
Object* o = allocator.new(Object);
|
||||
*o = { .s = s.copy(allocator), .allocator = allocator, .type = String.typeid };
|
||||
return o;
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ fn void Object.free(&self)
|
||||
case void:
|
||||
break;
|
||||
case String:
|
||||
free(self.s, .using = self.allocator);
|
||||
self.allocator.free(self.s);
|
||||
case ObjectInternalList:
|
||||
foreach (ol : self.array)
|
||||
{
|
||||
@@ -140,13 +140,13 @@ fn void Object.free(&self)
|
||||
self.array.free();
|
||||
case ObjectInternalMap:
|
||||
self.map.@each_entry(; ObjectInternalMapEntry* entry) {
|
||||
free(entry.key, .using = self.allocator);
|
||||
self.allocator.free(entry.key);
|
||||
entry.value.free();
|
||||
};
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (self.allocator) free(self, .using = self.allocator);
|
||||
if (self.allocator) self.allocator.free(self);
|
||||
}
|
||||
|
||||
fn bool Object.is_null(&self) @inline => self == &NULL_OBJECT;
|
||||
@@ -168,7 +168,7 @@ fn void Object.init_map_if_needed(&self) @private
|
||||
if (self.is_empty())
|
||||
{
|
||||
self.type = ObjectInternalMap.typeid;
|
||||
self.map.init(.using = self.allocator);
|
||||
self.map.init_new(.allocator = self.allocator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ fn void Object.init_array_if_needed(&self) @private
|
||||
if (self.is_empty())
|
||||
{
|
||||
self.type = ObjectInternalList.typeid;
|
||||
self.array.init(.using = self.allocator);
|
||||
self.array.init_new(.allocator = self.allocator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ fn void Object.set_object(&self, String key, Object* new_object) @private
|
||||
ObjectInternalMapEntry*! entry = self.map.get_entry(key);
|
||||
defer
|
||||
{
|
||||
(void)free(entry.key, .using = self.allocator);
|
||||
(void)self.allocator.free(entry.key);
|
||||
(void)entry.value.free();
|
||||
}
|
||||
self.map.set(key.copy(self.map.allocator), new_object);
|
||||
|
||||
@@ -31,19 +31,19 @@ import std::collections::list;
|
||||
|
||||
def Heap = List(<Type>);
|
||||
|
||||
struct PrivatePriorityQueue
|
||||
struct PrivatePriorityQueue (Printable)
|
||||
{
|
||||
Heap heap;
|
||||
}
|
||||
|
||||
fn void PrivatePriorityQueue.init(&self, usz initial_capacity = 16, Allocator* using = mem::heap()) @inline
|
||||
fn void PrivatePriorityQueue.init_new(&self, usz initial_capacity = 16, Allocator* allocator = mem::heap()) @inline
|
||||
{
|
||||
self.heap.init(initial_capacity, using);
|
||||
self.heap.init_new(initial_capacity, allocator);
|
||||
}
|
||||
|
||||
fn void PrivatePriorityQueue.tinit(&self, usz initial_capacity = 16) @inline
|
||||
fn void PrivatePriorityQueue.init_temp(&self, usz initial_capacity = 16) @inline
|
||||
{
|
||||
self.init(initial_capacity, mem::temp());
|
||||
self.heap.init_new(initial_capacity, mem::temp()) @inline;
|
||||
}
|
||||
|
||||
fn void PrivatePriorityQueue.push(&self, Type element)
|
||||
@@ -133,13 +133,13 @@ fn Type PrivatePriorityQueue.peek_at(&self, usz index) @operator([])
|
||||
return self.heap[index];
|
||||
}
|
||||
|
||||
fn usz! PrivatePriorityQueue.to_format(&self, Formatter* formatter)
|
||||
fn usz! PrivatePriorityQueue.to_format(&self, Formatter* formatter) @dynamic
|
||||
{
|
||||
return self.heap.to_format(formatter);
|
||||
}
|
||||
|
||||
fn String PrivatePriorityQueue.to_string(&self, Allocator* using = mem::heap())
|
||||
fn String PrivatePriorityQueue.to_new_string(&self, Allocator* allocator = mem::heap()) @dynamic
|
||||
{
|
||||
return self.heap.to_string(using);
|
||||
return self.heap.to_new_string(allocator);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,9 +28,14 @@ fn Type Range.get(&self, usz index) @operator([])
|
||||
return (Type)(self.start + (usz)index);
|
||||
}
|
||||
|
||||
fn String Range.to_string(&self, Allocator* using = mem::heap()) @dynamic
|
||||
fn String Range.to_new_string(&self, Allocator* allocator = mem::heap()) @dynamic
|
||||
{
|
||||
return string::printf("[%s..%s]", self.start, self.end);
|
||||
return string::new_format("[%s..%s]", self.start, self.end, .allocator = allocator);
|
||||
}
|
||||
|
||||
fn String Range.to_tstring(&self)
|
||||
{
|
||||
return self.to_new_string(mem::temp());
|
||||
}
|
||||
|
||||
fn usz! Range.to_format(&self, Formatter* formatter) @dynamic
|
||||
@@ -60,9 +65,14 @@ fn usz! ExclusiveRange.to_format(&self, Formatter* formatter) @dynamic
|
||||
return formatter.printf("[%s..<%s]", self.start, self.end)!;
|
||||
}
|
||||
|
||||
fn String ExclusiveRange.to_string(&self, Allocator* using = mem::heap()) @dynamic
|
||||
fn String ExclusiveRange.to_new_string(&self, Allocator* allocator = mem::heap()) @dynamic
|
||||
{
|
||||
return string::printf("[%s..<%s]", self.start, self.end);
|
||||
return string::new_format("[%s..<%s]", self.start, self.end, .allocator = allocator);
|
||||
}
|
||||
|
||||
fn String ExclusiveRange.to_tstring(&self)
|
||||
{
|
||||
return self.to_new_string(mem::temp());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,14 +12,15 @@ struct DynamicArenaAllocator (Allocator)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] allocator
|
||||
* @require page_size >= 128
|
||||
**/
|
||||
fn void DynamicArenaAllocator.init(&self, usz page_size, Allocator* using = mem::heap())
|
||||
fn void DynamicArenaAllocator.init(&self, usz page_size, Allocator* allocator)
|
||||
{
|
||||
self.page = null;
|
||||
self.unused_page = null;
|
||||
self.page_size = page_size;
|
||||
self.backing_allocator = using;
|
||||
self.backing_allocator = allocator;
|
||||
}
|
||||
|
||||
fn void DynamicArenaAllocator.free(&self)
|
||||
@@ -140,10 +141,10 @@ fn void*! DynamicArenaAllocator._alloc_new(&self, usz size, usz alignment, usz o
|
||||
|
||||
// Grab the page without alignment (we do it ourselves)
|
||||
void* mem = self.backing_allocator.alloc_checked(page_size)!;
|
||||
DynamicArenaPage*! page = malloc(DynamicArenaPage, .using = self.backing_allocator);
|
||||
DynamicArenaPage*! page = self.backing_allocator.new(DynamicArenaPage);
|
||||
if (catch err = page)
|
||||
{
|
||||
free(mem, .using = self.backing_allocator);
|
||||
self.backing_allocator.free(mem);
|
||||
return err?;
|
||||
}
|
||||
page.memory = mem;
|
||||
|
||||
@@ -17,12 +17,13 @@ struct OnStackAllocatorExtraChunk @local
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] allocator
|
||||
* Initialize a memory arena for use using the provided bytes.
|
||||
**/
|
||||
fn void OnStackAllocator.init(&self, char[] data, Allocator* using = mem::heap())
|
||||
fn void OnStackAllocator.init(&self, char[] data, Allocator* allocator)
|
||||
{
|
||||
self.data = data;
|
||||
self.backing_allocator = using;
|
||||
self.backing_allocator = allocator;
|
||||
self.used = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,14 +35,14 @@ macro bool TempAllocatorPage.is_aligned(&self) => self.size & PAGE_IS_ALIGNED ==
|
||||
/**
|
||||
* @require size >= 16
|
||||
**/
|
||||
fn TempAllocator*! new_temp(usz size, Allocator* using)
|
||||
fn TempAllocator*! new_temp(usz size, Allocator* allocator)
|
||||
{
|
||||
TempAllocator* allocator = malloc_checked(TempAllocator, .using = using, .end_padding = size)!;
|
||||
allocator.last_page = null;
|
||||
allocator.backing_allocator = using;
|
||||
allocator.used = 0;
|
||||
allocator.capacity = size;
|
||||
return allocator;
|
||||
TempAllocator* temp = allocator.alloc_checked(TempAllocator.sizeof + size)!;
|
||||
temp.last_page = null;
|
||||
temp.backing_allocator = allocator;
|
||||
temp.used = 0;
|
||||
temp.capacity = size;
|
||||
return temp;
|
||||
}
|
||||
|
||||
fn usz TempAllocator.mark(&self) @dynamic => self.used;
|
||||
@@ -202,20 +202,20 @@ fn void*! TempAllocator.acquire(&self, usz size, bool clear, usz alignment, usz
|
||||
return &page.data[0];
|
||||
}
|
||||
|
||||
fn void! TempAllocator.print_pages(&self, File f)
|
||||
fn void! TempAllocator.print_pages(&self, File* f)
|
||||
{
|
||||
TempAllocatorPage *last_page = self.last_page;
|
||||
if (!last_page)
|
||||
{
|
||||
io::fprintf(&f, "No pages.\n")!;
|
||||
io::fprintf(f, "No pages.\n")!;
|
||||
return;
|
||||
}
|
||||
io::fprintf(&f, "---Pages----\n")!;
|
||||
io::fprintf(f, "---Pages----\n")!;
|
||||
uint index = 0;
|
||||
while (last_page)
|
||||
{
|
||||
bool is_not_aligned = !(last_page.size & (1u64 << 63));
|
||||
io::fprintf(&f, "%d. Alloc: %d %d at %p%s\n", ++index,
|
||||
io::fprintf(f, "%d. Alloc: %d %d at %p%s\n", ++index,
|
||||
last_page.size & ~(1u64 << 63), last_page.mark, &last_page.data[0], is_not_aligned ? "" : " [aligned]")!;
|
||||
last_page = last_page.prev_page;
|
||||
}
|
||||
|
||||
@@ -21,12 +21,12 @@ struct TrackingAllocator (Allocator)
|
||||
/**
|
||||
* Initialize a tracking allocator to wrap (and track) another allocator.
|
||||
*
|
||||
* @param [&inout] using "The allocator to track"
|
||||
* @param [&inout] allocator "The allocator to track"
|
||||
**/
|
||||
fn void TrackingAllocator.init(&self, Allocator* using)
|
||||
fn void TrackingAllocator.init(&self, Allocator* allocator)
|
||||
{
|
||||
*self = { .inner_allocator = using };
|
||||
self.map.init(.using = using);
|
||||
*self = { .inner_allocator = allocator };
|
||||
self.map.init_new(.allocator = allocator);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,16 +35,16 @@ macro rindex_of(array, element)
|
||||
*
|
||||
* @param [in] arr1
|
||||
* @param [in] arr2
|
||||
* @param [&inout] using "The allocator to use, default is the heap allocator"
|
||||
* @param [&inout] allocator "The allocator to use, default is the heap allocator"
|
||||
* @require @typekind(arr1) == SUBARRAY || @typekind(arr1) == ARRAY
|
||||
* @require @typekind(arr2) == SUBARRAY || @typekind(arr2) == ARRAY
|
||||
* @require @typeis(arr1[0], $typeof(arr2[0])) "Arrays must have the same type"
|
||||
* @ensure result.len == arr1.len + arr2.len
|
||||
**/
|
||||
macro concat(arr1, arr2, Allocator* using = mem::heap())
|
||||
macro concat_new(arr1, arr2, Allocator* allocator = mem::heap())
|
||||
{
|
||||
var $Type = $typeof(arr1[0]);
|
||||
$Type[] result = malloc($Type, arr1.len + arr2.len, .using = using);
|
||||
$Type[] result = allocator.new_array($Type, arr1.len + arr2.len);
|
||||
if (arr1.len > 0)
|
||||
{
|
||||
mem::copy(result.ptr, &arr1[0], arr1.len * $Type.sizeof, $Type.alignof, $Type.alignof);
|
||||
|
||||
@@ -160,11 +160,11 @@ PanicFn panic = &default_panic;
|
||||
|
||||
fn void panicf(String fmt, String file, String function, uint line, args...)
|
||||
{
|
||||
@stack_mem(512; Allocator* mem)
|
||||
@stack_mem(512; Allocator* allocator)
|
||||
{
|
||||
DString s;
|
||||
s.init(.using = mem);
|
||||
s.printf(fmt, ...args);
|
||||
s.init_new(.allocator = allocator);
|
||||
s.appendf(fmt, ...args);
|
||||
panic(s.str_view(), file, function, line);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,34 +8,36 @@ const usz MIN_CAPACITY @private = 16;
|
||||
/**
|
||||
* @require !self.data() "String already initialized"
|
||||
**/
|
||||
fn void DString.init(&self, usz capacity = MIN_CAPACITY, Allocator* using = mem::heap())
|
||||
fn DString DString.init_new(&self, usz capacity = MIN_CAPACITY, Allocator* allocator = mem::heap())
|
||||
{
|
||||
if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY;
|
||||
StringData* data = malloc(StringData, 1, .using = using, .end_padding = capacity);
|
||||
data.allocator = using;
|
||||
StringData* data = allocator.new(StringData, .end_padding = capacity);
|
||||
data.allocator = allocator;
|
||||
data.len = 0;
|
||||
data.capacity = capacity;
|
||||
*self = (DString)data;
|
||||
return *self = (DString)data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require !self.data() "String already initialized"
|
||||
**/
|
||||
fn void DString.tinit(&self, usz capacity = MIN_CAPACITY) => self.init(capacity, mem::temp()) @inline;
|
||||
|
||||
fn DString new_with_capacity(usz capacity, Allocator* using = mem::heap())
|
||||
fn DString DString.init_temp(&self, usz capacity = MIN_CAPACITY)
|
||||
{
|
||||
DString dstr;
|
||||
dstr.init(capacity, using);
|
||||
return dstr;
|
||||
self.init_new(capacity, mem::temp()) @inline;
|
||||
return *self;
|
||||
}
|
||||
|
||||
fn DString tnew_with_capacity(usz capacity) => new_with_capacity(capacity, mem::temp()) @inline;
|
||||
fn DString new_with_capacity(usz capacity, Allocator* allocator = mem::heap())
|
||||
{
|
||||
return DString{}.init_new(capacity, allocator);
|
||||
}
|
||||
|
||||
fn DString new(String c = "", Allocator* using = mem::heap())
|
||||
fn DString temp_with_capacity(usz capacity) => new_with_capacity(capacity, mem::temp()) @inline;
|
||||
|
||||
fn DString new(String c = "", Allocator* allocator = mem::heap())
|
||||
{
|
||||
usz len = c.len;
|
||||
StringData* data = (StringData*)new_with_capacity(len, using);
|
||||
StringData* data = (StringData*)new_with_capacity(len, allocator);
|
||||
if (len)
|
||||
{
|
||||
data.len = len;
|
||||
@@ -44,12 +46,12 @@ fn DString new(String c = "", Allocator* using = mem::heap())
|
||||
return (DString)data;
|
||||
}
|
||||
|
||||
fn DString tnew(String s = "") => new(s, mem::temp()) @inline;
|
||||
fn DString temp_new(String s = "") => new(s, mem::temp()) @inline;
|
||||
|
||||
fn DString DString.new_concat(self, DString b, Allocator* using = mem::heap())
|
||||
fn DString DString.new_concat(self, DString b, Allocator* allocator = mem::heap())
|
||||
{
|
||||
DString string;
|
||||
string.init(self.len() + b.len(), using);
|
||||
string.init_new(self.len() + b.len(), allocator);
|
||||
string.append(self);
|
||||
string.append(b);
|
||||
return string;
|
||||
@@ -146,37 +148,37 @@ fn void DString.append_char32(&self, Char32 c)
|
||||
|
||||
fn DString DString.tcopy(&self) => self.copy(mem::temp());
|
||||
|
||||
fn DString DString.copy(self, Allocator* using = null)
|
||||
fn DString DString.copy(self, Allocator* allocator = null)
|
||||
{
|
||||
if (!self)
|
||||
{
|
||||
if (using) return new_with_capacity(0, using);
|
||||
if (allocator) return new_with_capacity(0, allocator);
|
||||
return (DString)null;
|
||||
}
|
||||
StringData* data = self.data();
|
||||
if (!using) using = mem::heap();
|
||||
DString new_string = new_with_capacity(data.capacity, using);
|
||||
if (!allocator) allocator = mem::heap();
|
||||
DString new_string = new_with_capacity(data.capacity, allocator);
|
||||
mem::copy((char*)new_string.data(), (char*)data, StringData.sizeof + data.len);
|
||||
return new_string;
|
||||
}
|
||||
|
||||
fn ZString DString.copy_zstr(self, Allocator* using = mem::heap())
|
||||
fn ZString DString.copy_zstr(self, Allocator* allocator = mem::heap())
|
||||
{
|
||||
usz str_len = self.len();
|
||||
if (!str_len)
|
||||
{
|
||||
return (ZString)calloc(1, .using = using);
|
||||
return (ZString)allocator.calloc(1);
|
||||
}
|
||||
char* zstr = malloc(str_len + 1, .using = using);
|
||||
char* zstr = allocator.alloc(str_len + 1);
|
||||
StringData* data = self.data();
|
||||
mem::copy(zstr, &data.chars, str_len);
|
||||
zstr[str_len] = 0;
|
||||
return (ZString)zstr;
|
||||
}
|
||||
|
||||
fn String DString.copy_str(self, Allocator* using = mem::heap())
|
||||
fn String DString.copy_str(self, Allocator* allocator = mem::heap())
|
||||
{
|
||||
return (String)self.copy_zstr(using)[:self.len()];
|
||||
return (String)self.copy_zstr(allocator)[:self.len()];
|
||||
}
|
||||
|
||||
fn String DString.tcopy_str(self) => self.copy_str(mem::temp()) @inline;
|
||||
@@ -202,7 +204,7 @@ fn void DString.free(&self)
|
||||
if (!*self) return;
|
||||
StringData* data = self.data();
|
||||
if (!data) return;
|
||||
free(data, .using = data.allocator);
|
||||
data.allocator.free(data);
|
||||
*self = (DString)null;
|
||||
}
|
||||
|
||||
@@ -238,9 +240,9 @@ fn void DString.append_chars(&self, String str)
|
||||
data.len += other_len;
|
||||
}
|
||||
|
||||
fn Char32[] DString.copy_utf32(&self, Allocator* using = mem::heap())
|
||||
fn Char32[] DString.copy_utf32(&self, Allocator* allocator = mem::heap())
|
||||
{
|
||||
return self.str_view().to_utf32(using) @inline!!;
|
||||
return self.str_view().to_new_utf32(allocator) @inline!!;
|
||||
}
|
||||
|
||||
fn void DString.append_string(&self, DString str)
|
||||
@@ -299,7 +301,7 @@ macro void DString.append(&self, value)
|
||||
$case $defined((String)value):
|
||||
self.append_chars((String)value);
|
||||
$default:
|
||||
$error "Unsupported type for append – use printf instead.";
|
||||
$error "Unsupported type for append – use appendf instead.";
|
||||
$endswitch
|
||||
$endswitch
|
||||
}
|
||||
@@ -336,14 +338,14 @@ fn void DString.insert_at(&self, usz index, String s)
|
||||
}
|
||||
}
|
||||
|
||||
fn usz! DString.printf(&self, String format, args...) @maydiscard
|
||||
fn usz! DString.appendf(&self, String format, args...) @maydiscard
|
||||
{
|
||||
Formatter formatter;
|
||||
formatter.init(&out_string_append_fn, self);
|
||||
return formatter.vprintf(format, args);
|
||||
}
|
||||
|
||||
fn usz! DString.printfn(&self, String format, args...) @maydiscard
|
||||
fn usz! DString.appendfn(&self, String format, args...) @maydiscard
|
||||
{
|
||||
Formatter formatter;
|
||||
formatter.init(&out_string_append_fn, self);
|
||||
@@ -352,7 +354,7 @@ fn usz! DString.printfn(&self, String format, args...) @maydiscard
|
||||
return len + 1;
|
||||
}
|
||||
|
||||
fn DString new_join(String[] s, String joiner, Allocator* using = mem::heap())
|
||||
fn DString new_join(String[] s, String joiner, Allocator* allocator = mem::heap())
|
||||
{
|
||||
if (!s.len) return (DString)null;
|
||||
usz total_size = joiner.len * s.len;
|
||||
@@ -360,7 +362,7 @@ fn DString new_join(String[] s, String joiner, Allocator* using = mem::heap())
|
||||
{
|
||||
total_size += str.len;
|
||||
}
|
||||
DString res = new_with_capacity(total_size, using);
|
||||
DString res = new_with_capacity(total_size, allocator);
|
||||
res.append(s[0]);
|
||||
foreach (String* &str : s[1..])
|
||||
{
|
||||
@@ -396,7 +398,7 @@ fn void DString.reserve(&self, usz addition)
|
||||
if (new_capacity < MIN_CAPACITY) new_capacity = MIN_CAPACITY;
|
||||
while (new_capacity < len) new_capacity *= 2;
|
||||
data.capacity = new_capacity;
|
||||
*self = (DString)realloc(data, StringData.sizeof + new_capacity, .using = data.allocator);
|
||||
*self = (DString)data.allocator.realloc(data, StringData.sizeof + new_capacity);
|
||||
}
|
||||
|
||||
fn usz! DString.read_from_stream(&self, InStream* reader)
|
||||
|
||||
@@ -368,191 +368,103 @@ macro bool equals(a, b, isz len = -1, usz $align = 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
macro @clone(value, Allocator *using = mem::heap()) @builtin
|
||||
macro @clone(value) @builtin
|
||||
{
|
||||
$typeof(value)* x = malloc($typeof(value), .using = using);
|
||||
*x = value;
|
||||
return x;
|
||||
return mem::heap().clone(value);
|
||||
}
|
||||
|
||||
macro @tclone(value) @builtin => @clone(value, mem::temp());
|
||||
macro @tclone(value) @builtin
|
||||
{
|
||||
return mem::temp().clone(value);
|
||||
}
|
||||
|
||||
macro type_alloc_must_be_aligned($Type)
|
||||
{
|
||||
return $Type.alignof > DEFAULT_MEM_ALIGNMENT;
|
||||
}
|
||||
/**
|
||||
* @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len"
|
||||
* @require $vacount != 2 || $defined($vatype(0)) "Expected 'malloc(Foo, 12)'"
|
||||
**/
|
||||
macro malloc(..., Allocator* using = mem::heap(), usz end_padding = 0) @builtin
|
||||
|
||||
fn void* malloc(usz size) @builtin @inline
|
||||
{
|
||||
return malloc_checked($vasplat(), .using = using, .end_padding = end_padding)!!;
|
||||
return mem::heap().alloc(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len"
|
||||
* @require $vacount != 2 || $defined($vatype(0)) "Expected 'malloc(Foo, 12)'"
|
||||
**/
|
||||
macro malloc_checked(..., Allocator* using = mem::heap(), usz end_padding = 0) @builtin
|
||||
fn void* tmalloc(usz size, usz alignment = 0, usz offset = 0) @builtin @inline
|
||||
{
|
||||
$if $defined($vatype(0)):
|
||||
var $Type = $vatype(0);
|
||||
$assert !type_alloc_must_be_aligned($Type) : "Type must be allocated with malloc_aligned";
|
||||
$if $vacount == 2:
|
||||
usz size = $vaarg(1);
|
||||
return (($Type*)using.alloc_checked($Type.sizeof * size + end_padding))[:size];
|
||||
$else
|
||||
return ($Type*)using.alloc_checked($Type.sizeof + end_padding);
|
||||
$endif
|
||||
$else
|
||||
return using.alloc_checked($vaarg(0) + end_padding);
|
||||
$endif
|
||||
return temp().acquire(size, false, alignment, offset)!!;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len"
|
||||
* @require $vacount != 2 || $defined($vatype(0)) "Expected 'malloc(Foo, 12)'"
|
||||
* @require alignment && math::is_power_of_2(alignment)
|
||||
**/
|
||||
macro malloc_aligned(..., usz alignment = 0, usz end_padding = 0, Allocator* using = mem::heap()) @builtin
|
||||
macro new($Type)
|
||||
{
|
||||
$if $defined($vatype(0)):
|
||||
var $Type = $vatype(0);
|
||||
$if $vacount == 2:
|
||||
usz size = $vaarg(1);
|
||||
return (($Type*)using.alloc_aligned($Type.sizeof * size + end_padding, alignment))[:size];
|
||||
$else
|
||||
return ($Type*)using.alloc_aligned($Type.sizeof + end_padding, alignment);
|
||||
$endif
|
||||
$else
|
||||
return using.alloc_aligned($vaarg(0) + end_padding, alignment);
|
||||
$endif
|
||||
return heap().new($Type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len"
|
||||
* @require $vacount != 2 || $defined($vatype(0)) "Expected 'malloc(Foo, 12)'"
|
||||
**/
|
||||
macro calloc(..., Allocator* using = mem::heap(), usz end_padding = 0) @builtin
|
||||
macro new_clear($Type)
|
||||
{
|
||||
return calloc_checked($vasplat(), .using = using, .end_padding = end_padding)!!;
|
||||
return heap().new_clear($Type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len"
|
||||
* @require $vacount != 2 || $defined($vatype(0)) "Expected 'malloc(Foo, 12)'"
|
||||
**/
|
||||
macro calloc_checked(..., Allocator* using = mem::heap(), usz end_padding = 0) @builtin
|
||||
macro new_temp($Type)
|
||||
{
|
||||
$if $defined($vatype(0)):
|
||||
var $Type = $vatype(0);
|
||||
$assert !type_alloc_must_be_aligned($Type) : "Type must be allocated with calloc_aligned";
|
||||
$if $vacount == 2:
|
||||
usz size = $vaarg(1);
|
||||
return (($Type*)using.calloc_checked($Type.sizeof * size + end_padding))[:size];
|
||||
$else
|
||||
return ($Type*)using.calloc_checked($Type.sizeof + end_padding);
|
||||
$endif
|
||||
$else
|
||||
return using.calloc_checked($vaarg(0) + end_padding);
|
||||
$endif
|
||||
return tmalloc($Type.sizeof);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len"
|
||||
* @require $vacount != 2 || $defined($vatype(0)) "Expected 'malloc(Foo, 12)'"
|
||||
* @require alignment && math::is_power_of_2(alignment)
|
||||
**/
|
||||
macro calloc_aligned(..., usz alignment = 0, Allocator* using = mem::heap(), usz end_padding = 0) @builtin
|
||||
macro new_temp_clear($Type)
|
||||
{
|
||||
$if $defined($vatype(0)):
|
||||
var $Type = $vatype(0);
|
||||
$if $vacount == 2:
|
||||
usz size = $vaarg(1);
|
||||
return (($Type*)using.calloc_aligned($Type.sizeof * size + end_padding, alignment))[:size];
|
||||
$else
|
||||
return ($Type*)using.calloc_aligned($Type.sizeof + end_padding, alignment);
|
||||
$endif
|
||||
$else
|
||||
return using.calloc_aligned($vaarg(0) + end_padding, alignment);
|
||||
$endif
|
||||
return tcalloc($Type.sizeof);
|
||||
}
|
||||
|
||||
fn void* realloc(void *ptr, usz new_size, Allocator* using = mem::heap()) @builtin @inline
|
||||
macro new_array($Type, usz elements)
|
||||
{
|
||||
return using.realloc(ptr, new_size);
|
||||
return heap().new_array($Type, elements);
|
||||
}
|
||||
|
||||
fn void*! realloc_checked(void *ptr, usz new_size, Allocator* using = mem::heap()) @builtin @inline
|
||||
macro temp_array($Type, usz elements)
|
||||
{
|
||||
return using.realloc_checked(ptr, new_size);
|
||||
return (($Type*)tmalloc($Type.sizeof * elements, $Type.alignof))[:elements];
|
||||
}
|
||||
|
||||
/**
|
||||
* @require alignment && math::is_power_of_2(alignment)
|
||||
*/
|
||||
fn void*! realloc_aligned(void *ptr, usz new_size, usz alignment, Allocator* using = mem::heap()) @builtin @inline
|
||||
macro new_zero_array($Type, usz elements)
|
||||
{
|
||||
return using.realloc_aligned(ptr, new_size, alignment);
|
||||
return heap().new_zero_array($Type, elements);
|
||||
}
|
||||
|
||||
macro temp_zero_array($Type, usz elements)
|
||||
{
|
||||
return (($Type*)tcalloc($Type.sizeof * elements, $Type.alignof))[:elements];
|
||||
}
|
||||
|
||||
fn void* calloc(usz size) @builtin @inline
|
||||
{
|
||||
return heap().calloc(size);
|
||||
}
|
||||
|
||||
fn void* tcalloc(usz size, usz alignment = 0, usz offset = 0) @builtin @inline
|
||||
{
|
||||
return temp().acquire(size, false, alignment, offset)!!;
|
||||
}
|
||||
|
||||
fn void* realloc(void *ptr, usz new_size) @builtin @inline
|
||||
{
|
||||
return heap().realloc(ptr, new_size);
|
||||
}
|
||||
|
||||
fn void free(void* ptr) @builtin @inline
|
||||
{
|
||||
heap().free(ptr);
|
||||
}
|
||||
|
||||
macro void free(void* ptr, Allocator* using = mem::heap()) @builtin => using.free(ptr);
|
||||
//macro void! free_checked(void* ptr, Allocator* using = mem::heap()) @builtin => using.free(ptr);
|
||||
macro void free_aligned(void* ptr, Allocator* using = mem::heap()) @builtin => using.free_aligned(ptr);
|
||||
//macro void! free_aligned_checked(void* ptr, Allocator* using = mem::heap()) @builtin => using.free_aligned(ptr);
|
||||
|
||||
/**
|
||||
* Run with a specific allocator inside of the macro body.
|
||||
**/
|
||||
macro void @scoped(Allocator* using; @body())
|
||||
macro void @scoped(Allocator* allocator; @body())
|
||||
{
|
||||
Allocator* old_allocator = thread_allocator;
|
||||
thread_allocator = using;
|
||||
thread_allocator = allocator;
|
||||
defer thread_allocator = old_allocator;
|
||||
@body();
|
||||
}
|
||||
|
||||
/**
|
||||
* @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len"
|
||||
* @require $vacount != 2 || $defined($vatype(0)) "Expected 'malloc(Foo, 12)'"
|
||||
**/
|
||||
macro tmalloc(..., usz end_padding = 0, usz alignment = DEFAULT_MEM_ALIGNMENT) @builtin
|
||||
{
|
||||
$if $defined($vatype(0)):
|
||||
var $Type = $vatype(0);
|
||||
$if $vacount == 2:
|
||||
usz size = $vaarg(1);
|
||||
return (($Type*)temp().acquire($Type.sizeof * size + end_padding, false, alignment, 0))[:size]!!;
|
||||
$else
|
||||
return ($Type*)temp().acquire($Type.sizeof + end_padding, false, alignment, 0)!!;
|
||||
$endif
|
||||
$else
|
||||
return temp().acquire($vaarg(0) + end_padding, false, alignment, 0)!!;
|
||||
$endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len"
|
||||
* @require $vacount != 2 || $defined($vatype(0)) "Expected 'malloc(Foo, 12)'"
|
||||
**/
|
||||
macro tcalloc(..., usz end_padding = 0, usz alignment = mem::DEFAULT_MEM_ALIGNMENT) @builtin
|
||||
{
|
||||
$if $defined($vatype(0)):
|
||||
var $Type = $vatype(0);
|
||||
$if $vacount == 2:
|
||||
usz size = $vaarg(1);
|
||||
return (($Type*)temp().acquire($Type.sizeof * size + end_padding, true, alignment, 0))[:size]!!;
|
||||
$else
|
||||
return ($Type*)temp().acquire($Type.sizeof + end_padding, true, alignment, 0)!!;
|
||||
$endif
|
||||
$else
|
||||
return temp().acquire($vaarg(0) + end_padding, true, alignment, 0)!!;
|
||||
$endif
|
||||
}
|
||||
|
||||
fn void* trealloc(void* ptr, usz size, usz alignment = mem::DEFAULT_MEM_ALIGNMENT) @builtin @inline
|
||||
{
|
||||
return temp().resize(ptr, size, alignment, 0)!!;
|
||||
|
||||
@@ -32,6 +32,53 @@ macro void*! Allocator.alloc_checked(&self, usz size)
|
||||
macro void*! Allocator.calloc_checked(&self, usz size) => self.acquire(size, true, 0, 0);
|
||||
macro void*! Allocator.realloc_checked(&self, void* ptr, usz new_size) => self.resize(ptr, new_size, 0, 0);
|
||||
|
||||
macro Allocator.new_array(&self, $Type, usz size, usz end_padding = 0)
|
||||
{
|
||||
return (($Type*)self.alloc_checked($Type.sizeof * size + end_padding))[:size]!!;
|
||||
}
|
||||
|
||||
macro Allocator.new_array_checked(&self, $Type, usz size, usz end_padding = 0)
|
||||
{
|
||||
return (($Type*)self.alloc_checked($Type.sizeof * size + end_padding))[:size];
|
||||
}
|
||||
|
||||
macro Allocator.new_zero_array(&self, $Type, usz size, usz end_padding = 0)
|
||||
{
|
||||
return (($Type*)self.calloc_checked($Type.sizeof * size + end_padding))[:size]!!;
|
||||
}
|
||||
|
||||
macro Allocator.new_zero_array_checked(&self, $Type, usz size, usz end_padding = 0)
|
||||
{
|
||||
return (($Type*)self.calloc_checked($Type.sizeof * size + end_padding))[:size];
|
||||
}
|
||||
|
||||
macro Allocator.new(&self, $Type, usz end_padding = 0) @nodiscard
|
||||
{
|
||||
return ($Type*)self.alloc_checked($Type.sizeof + end_padding)!!;
|
||||
}
|
||||
|
||||
macro Allocator.new_checked(&self, $Type, usz end_padding = 0) @nodiscard
|
||||
{
|
||||
return ($Type*)self.alloc_checked($Type.sizeof + end_padding);
|
||||
}
|
||||
|
||||
macro Allocator.new_clear(&self, $Type, usz end_padding = 0) @nodiscard
|
||||
{
|
||||
return ($Type*)self.calloc_checked($Type.sizeof + end_padding)!!;
|
||||
}
|
||||
|
||||
macro Allocator.new_clear_checked(&self, $Type, usz end_padding = 0) @nodiscard
|
||||
{
|
||||
return ($Type*)self.calloc_checked($Type.sizeof + end_padding);
|
||||
}
|
||||
|
||||
macro Allocator.clone(&self, value)
|
||||
{
|
||||
var x = self.alloc($typeof(value));
|
||||
*x = value;
|
||||
return x;
|
||||
}
|
||||
|
||||
macro void* Allocator.alloc(&self, usz size) @nodiscard => self.alloc_checked(size)!!;
|
||||
macro void* Allocator.calloc(&self, usz size) @nodiscard => self.acquire(size, true, 0, 0)!!;
|
||||
macro void* Allocator.realloc(&self, void* ptr, usz new_size) @nodiscard => self.resize(ptr, new_size, 0, 0)!!;
|
||||
|
||||
@@ -21,7 +21,7 @@ macro int @main_to_void_main(#m, int, char**)
|
||||
|
||||
macro String[] args_to_strings(int argc, char** argv) @private
|
||||
{
|
||||
String[] list = malloc(String, argc);
|
||||
String[] list = mem::new_array(String, argc);
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
char* arg = argv[i];
|
||||
@@ -68,12 +68,12 @@ macro String[] win_command_line_to_strings(ushort* cmd_line) @private
|
||||
|
||||
macro String[] wargs_strings(int argc, Char16** argv) @private
|
||||
{
|
||||
String[] list = malloc(String, argc);
|
||||
String[] list = mem::new_array(String, argc);
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
Char16* arg = argv[i];
|
||||
Char16[] argstring = arg[:_strlen(arg)];
|
||||
list[i] = string::from_utf16(argstring) ?? "?".copy();
|
||||
list[i] = string::new_from_utf16(argstring) ?? "?".copy();
|
||||
}
|
||||
return list[:argc];
|
||||
}
|
||||
|
||||
@@ -32,11 +32,11 @@ struct BenchmarkUnit
|
||||
BenchmarkFn func;
|
||||
}
|
||||
|
||||
fn BenchmarkUnit[] benchmark_collection_create(Allocator* using = mem::heap())
|
||||
fn BenchmarkUnit[] benchmark_collection_create(Allocator* allocator = mem::heap())
|
||||
{
|
||||
BenchmarkFn[] fns = $$BENCHMARK_FNS;
|
||||
String[] names = $$BENCHMARK_NAMES;
|
||||
BenchmarkUnit[] benchmarks = malloc(BenchmarkUnit, names.len, .using = using);
|
||||
BenchmarkUnit[] benchmarks = allocator.new_array(BenchmarkUnit, names.len);
|
||||
foreach (i, benchmark : fns)
|
||||
{
|
||||
benchmarks[i] = { names[i], fns[i] };
|
||||
@@ -74,9 +74,7 @@ fn bool run_benchmarks(BenchmarkUnit[] benchmarks)
|
||||
|
||||
usz len = max_name + 9;
|
||||
|
||||
DString name;
|
||||
|
||||
name.tinit();
|
||||
DString name = dstring::temp_with_capacity(64);
|
||||
name.append_repeat('-', len / 2);
|
||||
name.append(" BENCHMARKS ");
|
||||
name.append_repeat('-', len - len / 2);
|
||||
@@ -94,7 +92,7 @@ fn bool run_benchmarks(BenchmarkUnit[] benchmarks)
|
||||
foreach(unit : benchmarks)
|
||||
{
|
||||
defer name.clear();
|
||||
name.printf("Benchmarking %s ", unit.name);
|
||||
name.appendf("Benchmarking %s ", unit.name);
|
||||
name.append_repeat('.', max_name - unit.name.len + 2);
|
||||
io::printf("%s ", name.str_view());
|
||||
|
||||
@@ -152,11 +150,11 @@ struct TestUnit
|
||||
TestFn func;
|
||||
}
|
||||
|
||||
fn TestUnit[] test_collection_create(Allocator* using = mem::heap())
|
||||
fn TestUnit[] test_collection_create(Allocator* allocator = mem::heap())
|
||||
{
|
||||
TestFn[] fns = $$TEST_FNS;
|
||||
String[] names = $$TEST_NAMES;
|
||||
TestUnit[] tests = malloc(TestUnit, names.len, .using = using);
|
||||
TestUnit[] tests = allocator.new_array(TestUnit, names.len);
|
||||
foreach (i, test : fns)
|
||||
{
|
||||
tests[i] = { names[i], fns[i] };
|
||||
@@ -212,8 +210,7 @@ fn bool run_tests(TestUnit[] tests)
|
||||
builtin::panic = &test_panic;
|
||||
int tests_passed = 0;
|
||||
int test_count = tests.len;
|
||||
DString name;
|
||||
name.tinit();
|
||||
DString name = dstring::temp_with_capacity(64);
|
||||
usz len = max_name + 9;
|
||||
name.append_repeat('-', len / 2);
|
||||
name.append(" TESTS ");
|
||||
@@ -223,7 +220,7 @@ fn bool run_tests(TestUnit[] tests)
|
||||
foreach(unit : tests)
|
||||
{
|
||||
defer name.clear();
|
||||
name.printf("Testing %s ", unit.name);
|
||||
name.appendf("Testing %s ", unit.name);
|
||||
name.append_repeat('.', max_name - unit.name.len + 2);
|
||||
io::printf("%s ", name.str_view());
|
||||
CallstackElement* stack = $$stacktrace();
|
||||
|
||||
@@ -31,24 +31,23 @@ fault NumberConversion
|
||||
FLOAT_OUT_OF_RANGE,
|
||||
}
|
||||
|
||||
macro String printf(String fmt, ..., Allocator* using = mem::heap())
|
||||
macro String tformat(String fmt, ...)
|
||||
{
|
||||
@pool(using)
|
||||
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
|
||||
str.appendf(fmt, $vasplat());
|
||||
return str.str_view();
|
||||
}
|
||||
|
||||
macro String new_format(String fmt, ..., Allocator* allocator = mem::heap())
|
||||
{
|
||||
@pool(allocator)
|
||||
{
|
||||
DString str;
|
||||
str.tinit();
|
||||
str.printf(fmt, $vasplat());
|
||||
return str.copy_str(using);
|
||||
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
|
||||
str.appendf(fmt, $vasplat());
|
||||
return str.copy_str(allocator);
|
||||
};
|
||||
}
|
||||
|
||||
macro String tprintf(String fmt, ...)
|
||||
{
|
||||
DString str;
|
||||
str.tinit();
|
||||
str.printf(fmt, $vasplat());
|
||||
return str.str_view();
|
||||
}
|
||||
|
||||
macro bool char_in_set(char c, String set)
|
||||
{
|
||||
@@ -56,11 +55,11 @@ macro bool char_in_set(char c, String set)
|
||||
return false;
|
||||
}
|
||||
|
||||
fn String join(String[] s, String joiner, Allocator* using = mem::heap())
|
||||
fn String join_new(String[] s, String joiner, Allocator* allocator = mem::heap())
|
||||
{
|
||||
if (!s)
|
||||
{
|
||||
return (String)(calloc(char, 2, .using = using)[:0]);
|
||||
return (String)allocator.new_zero_array(char, 2)[:0];
|
||||
}
|
||||
|
||||
usz total_size = joiner.len * s.len;
|
||||
@@ -68,16 +67,16 @@ fn String join(String[] s, String joiner, Allocator* using = mem::heap())
|
||||
{
|
||||
total_size += str.len;
|
||||
}
|
||||
@pool(using)
|
||||
@pool(allocator)
|
||||
{
|
||||
DString res = dstring::tnew_with_capacity(total_size);
|
||||
DString res = dstring::temp_with_capacity(total_size);
|
||||
res.append(s[0]);
|
||||
foreach (String* &str : s[1..])
|
||||
{
|
||||
res.append(joiner);
|
||||
res.append(*str);
|
||||
}
|
||||
return res.copy_str(using);
|
||||
return res.copy_str(allocator);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -149,16 +148,16 @@ fn String String.strip_end(string, String needle)
|
||||
*
|
||||
* @param [in] s
|
||||
* @param [in] needle
|
||||
* @param [&inout] using "The allocator, defaults to the heap allocator"
|
||||
* @param [&inout] allocator "The allocator, defaults to the heap allocator"
|
||||
* @param max "Max number of elements, 0 means no limit, defaults to 0"
|
||||
* @require needle.len > 0 "The needle must be at least 1 character long"
|
||||
* @ensure return.len > 0
|
||||
**/
|
||||
fn String[] String.split(s, String needle, usz max = 0, Allocator* using = mem::heap())
|
||||
fn String[] String.split(s, String needle, usz max = 0, Allocator* allocator = mem::heap())
|
||||
{
|
||||
usz capacity = 16;
|
||||
usz i = 0;
|
||||
String* holder = malloc(String, capacity, .using = using);
|
||||
String* holder = allocator.new_array(String, capacity);
|
||||
bool no_more = false;
|
||||
while (!no_more)
|
||||
{
|
||||
@@ -177,7 +176,7 @@ fn String[] String.split(s, String needle, usz max = 0, Allocator* using = mem::
|
||||
if (i == capacity)
|
||||
{
|
||||
capacity *= 2;
|
||||
holder = realloc(holder, String.sizeof * capacity, .using = using);
|
||||
holder = allocator.realloc(holder, String.sizeof * capacity);
|
||||
}
|
||||
holder[i++] = res;
|
||||
}
|
||||
@@ -313,19 +312,19 @@ fn usz ZString.len(str)
|
||||
}
|
||||
|
||||
|
||||
fn ZString String.zstr_copy(s, Allocator* using = mem::heap())
|
||||
fn ZString String.zstr_copy(s, Allocator* allocator = mem::heap())
|
||||
{
|
||||
usz len = s.len;
|
||||
char* str = malloc(len + 1, .using = using);
|
||||
char* str = allocator.alloc(len + 1);
|
||||
mem::copy(str, s.ptr, len);
|
||||
str[len] = 0;
|
||||
return (ZString)str;
|
||||
}
|
||||
|
||||
fn String String.concat(s1, String s2, Allocator* using = mem::heap())
|
||||
fn String String.concat(s1, String s2, Allocator* allocator = mem::heap())
|
||||
{
|
||||
usz full_len = s1.len + s2.len;
|
||||
char* str = malloc(full_len + 1, .using = using);
|
||||
char* str = allocator.alloc(full_len + 1);
|
||||
usz s1_len = s1.len;
|
||||
mem::copy(str, s1.ptr, s1_len);
|
||||
mem::copy(str + s1_len, s2.ptr, s2.len);
|
||||
@@ -338,25 +337,33 @@ fn String String.tconcat(s1, String s2) => s1.concat(s2, mem::temp());
|
||||
|
||||
fn ZString String.zstr_tcopy(s) => s.zstr_copy(mem::temp()) @inline;
|
||||
|
||||
fn String String.copy(s, Allocator* using = mem::heap())
|
||||
fn String String.copy(s, Allocator* allocator = mem::heap())
|
||||
{
|
||||
usz len = s.len;
|
||||
char* str = malloc(len + 1, .using = using);
|
||||
char* str = allocator.alloc(len + 1);
|
||||
mem::copy(str, s.ptr, len);
|
||||
str[len] = 0;
|
||||
return (String)str[:len];
|
||||
}
|
||||
fn void String.free(&s, Allocator* using = mem::heap())
|
||||
|
||||
fn void String.free(&s, Allocator* allocator = mem::heap())
|
||||
{
|
||||
if (!s.len) return;
|
||||
mem::free(s.ptr, .using = using);
|
||||
allocator.free(s.ptr);
|
||||
*s = "";
|
||||
}
|
||||
|
||||
fn String String.tcopy(s) => s.copy(mem::temp()) @inline;
|
||||
|
||||
fn String ZString.copy(z, Allocator* using = mem::heap()) => z.str_view().copy(using) @inline;
|
||||
fn String ZString.tcopy(z) => z.str_view().copy(mem::temp()) @inline;
|
||||
fn String ZString.copy(z, Allocator* allocator = mem::temp())
|
||||
{
|
||||
return z.str_view().copy(allocator) @inline;
|
||||
}
|
||||
|
||||
fn String ZString.tcopy(z)
|
||||
{
|
||||
return z.str_view().copy(mem::temp()) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an UTF-8 string to UTF-16
|
||||
@@ -364,80 +371,114 @@ fn String ZString.tcopy(z) => z.str_view().copy(mem::temp()) @inline;
|
||||
* @return! UnicodeResult.INVALID_UTF8 "If the string contained an invalid UTF-8 sequence"
|
||||
* @return! AllocationFailure "If allocation of the string fails"
|
||||
**/
|
||||
fn Char16[]! String.to_utf16(s, Allocator* using = mem::heap())
|
||||
fn Char16[]! String.to_new_utf16(s, Allocator* allocator = mem::heap())
|
||||
{
|
||||
usz len16 = conv::utf16len_for_utf8(s);
|
||||
Char16* data = malloc_checked(Char16, len16 + 1, .using = using)!;
|
||||
Char16* data = allocator.new_array_checked(Char16, len16 + 1)!;
|
||||
conv::utf8to16_unsafe(s, data)!;
|
||||
data[len16] = 0;
|
||||
return data[:len16];
|
||||
}
|
||||
|
||||
fn WString! String.to_wstring(s, Allocator* using = mem::heap()) => (WString)s.to_utf16(using).ptr;
|
||||
/**
|
||||
* Convert an UTF-8 string to UTF-16
|
||||
* @return "The UTF-16 string as a slice, allocated using the given allocator"
|
||||
* @return! UnicodeResult.INVALID_UTF8 "If the string contained an invalid UTF-8 sequence"
|
||||
* @return! AllocationFailure "If allocation of the string fails"
|
||||
**/
|
||||
fn Char16[]! String.to_temp_utf16(s)
|
||||
{
|
||||
return s.to_new_utf16(mem::temp());
|
||||
}
|
||||
|
||||
fn Char32[]! String.to_utf32(s, Allocator* using = mem::heap())
|
||||
fn WString! String.to_new_wstring(s, Allocator* allocator = mem::heap())
|
||||
{
|
||||
return (WString)s.to_new_utf16(allocator).ptr;
|
||||
}
|
||||
|
||||
fn WString! String.to_temp_wstring(s)
|
||||
{
|
||||
return (WString)s.to_temp_utf16().ptr;
|
||||
}
|
||||
|
||||
fn Char32[]! String.to_new_utf32(s, Allocator* allocator = mem::heap())
|
||||
{
|
||||
usz codepoints = conv::utf8_codepoints(s);
|
||||
Char32* data = malloc_checked(Char32, codepoints + 1, .using = using)!;
|
||||
Char32* data = allocator.new_array(Char32, codepoints + 1);
|
||||
conv::utf8to32_unsafe(s, data)!;
|
||||
data[codepoints] = 0;
|
||||
return data[:codepoints];
|
||||
}
|
||||
|
||||
fn Char32[]! String.to_temp_utf32(s)
|
||||
{
|
||||
return s.to_new_utf32(mem::temp());
|
||||
}
|
||||
|
||||
fn void String.convert_ascii_to_lower(s)
|
||||
{
|
||||
foreach (&c : s) if (c.is_upper()) *c += 'a' - 'A';
|
||||
}
|
||||
|
||||
fn String String.ascii_to_lower(s, Allocator* using = mem::heap())
|
||||
fn String String.new_ascii_to_lower(s, Allocator* allocator = mem::heap())
|
||||
{
|
||||
String copy = s.copy(using);
|
||||
String copy = s.copy(allocator);
|
||||
copy.convert_ascii_to_lower();
|
||||
return copy;
|
||||
}
|
||||
|
||||
fn String String.temp_ascii_to_lower(s, Allocator* allocator = mem::heap())
|
||||
{
|
||||
return s.new_ascii_to_lower(mem::temp());
|
||||
}
|
||||
|
||||
fn void String.convert_ascii_to_upper(s)
|
||||
{
|
||||
foreach (&c : s) if (c.is_lower()) *c -= 'a' - 'A';
|
||||
}
|
||||
|
||||
fn String String.ascii_to_upper(s, Allocator* using = mem::heap())
|
||||
fn String String.new_ascii_to_upper(s, Allocator* allocator = mem::heap())
|
||||
{
|
||||
String copy = s.copy(using);
|
||||
String copy = s.copy(allocator);
|
||||
copy.convert_ascii_to_upper();
|
||||
return copy;
|
||||
}
|
||||
|
||||
fn String! from_utf32(Char32[] utf32, Allocator* using = mem::heap())
|
||||
fn String String.temp_ascii_to_upper(s)
|
||||
{
|
||||
return s.new_ascii_to_upper(mem::temp());
|
||||
}
|
||||
|
||||
fn String! new_from_utf32(Char32[] utf32, Allocator* allocator = mem::heap())
|
||||
{
|
||||
usz len = conv::utf8len_for_utf32(utf32);
|
||||
char* data = malloc_checked(len + 1, .using = using)!;
|
||||
defer catch free(data, .using = using);
|
||||
char* data = allocator.alloc_checked(len + 1)!;
|
||||
defer catch allocator.free(data);
|
||||
conv::utf32to8_unsafe(utf32, data);
|
||||
data[len] = 0;
|
||||
return (String)data[:len];
|
||||
}
|
||||
|
||||
fn String! from_utf16(Char16[] utf16, Allocator* using = mem::heap())
|
||||
fn String! new_from_utf16(Char16[] utf16, Allocator* allocator = mem::heap())
|
||||
{
|
||||
usz len = conv::utf8len_for_utf16(utf16);
|
||||
char* data = malloc_checked(len + 1, .using = using)!;
|
||||
defer catch free(data, .using = using);
|
||||
char* data = allocator.alloc_checked(len + 1)!;
|
||||
defer catch allocator.free(data);
|
||||
conv::utf16to8_unsafe(utf16, data)!;
|
||||
data[len] = 0;
|
||||
return (String)data[:len];
|
||||
}
|
||||
|
||||
fn String! from_wstring(WString wstring, Allocator* using = mem::heap())
|
||||
fn String! new_from_wstring(WString wstring, Allocator* allocator = mem::heap())
|
||||
{
|
||||
usz utf16_len;
|
||||
while (wstring[utf16_len] != 0) utf16_len++;
|
||||
Char16[] utf16 = wstring[:utf16_len];
|
||||
return from_utf16(utf16, using);
|
||||
return new_from_utf16(utf16, allocator);
|
||||
}
|
||||
|
||||
fn String! temp_from_wstring(WString wstring) => from_wstring(wstring) @inline;
|
||||
fn String! temp_from_utf16(Char16[] utf16) => temp_from_utf16(utf16) @inline;
|
||||
fn String! temp_from_wstring(WString wstring) => new_from_wstring(wstring, mem::temp()) @inline;
|
||||
fn String! temp_from_utf16(Char16[] utf16) => new_from_utf16(utf16, mem::temp()) @inline;
|
||||
|
||||
fn usz String.utf8_codepoints(s)
|
||||
{
|
||||
@@ -449,7 +490,6 @@ fn usz String.utf8_codepoints(s)
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
macro String.to_integer(string, $Type)
|
||||
{
|
||||
usz len = string.len;
|
||||
@@ -521,10 +561,6 @@ macro String.to_integer(string, $Type)
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
fn Char16[]! String.to_temp_utf16(s) => s.to_utf16(mem::temp());
|
||||
fn WString! String.to_temp_wstring(s) => s.to_wstring(mem::temp());
|
||||
|
||||
fn int128! String.to_int128(s) => s.to_integer(int128);
|
||||
fn long! String.to_long(s) => s.to_integer(long);
|
||||
fn int! String.to_int(s) => s.to_integer(int);
|
||||
|
||||
@@ -13,17 +13,22 @@ fn void CsvReader.init(&self, InStream* stream, String separator = ",")
|
||||
self.separator = separator;
|
||||
}
|
||||
|
||||
fn String[]! CsvReader.read_row(self, Allocator* using = mem::heap())
|
||||
fn String[]! CsvReader.read_new_row(self, Allocator* allocator = mem::heap())
|
||||
{
|
||||
@pool(using)
|
||||
return self.read_new_row_with_allocator(mem::temp()) @inline;
|
||||
}
|
||||
|
||||
fn String[]! CsvReader.read_new_row_with_allocator(self, Allocator* allocator = mem::heap())
|
||||
{
|
||||
@pool(allocator)
|
||||
{
|
||||
return io::treadline(self.stream).split(self.separator, .using = using);
|
||||
return io::treadline(self.stream).split(self.separator, .allocator = allocator);
|
||||
};
|
||||
}
|
||||
|
||||
fn String[]! CsvReader.tread_row(self)
|
||||
fn String[]! CsvReader.read_temp_row(self)
|
||||
{
|
||||
return self.read_row(mem::temp()) @inline;
|
||||
return self.read_new_row_with_allocator(mem::temp()) @inline;
|
||||
}
|
||||
|
||||
fn void! CsvReader.skip_row(self) @maydiscard
|
||||
@@ -45,13 +50,13 @@ macro CsvReader.@each_row(self, int rows = int.max; @body(String[] row))
|
||||
String[] parts;
|
||||
@pool()
|
||||
{
|
||||
String! s = stream.readline(mem::temp());
|
||||
String! s = stream.treadline();
|
||||
if (catch err = s)
|
||||
{
|
||||
if (err == IoError.EOF) return;
|
||||
return err?;
|
||||
}
|
||||
parts = s.split(sep, .using = mem);
|
||||
parts = s.split(sep, .allocator = mem);
|
||||
};
|
||||
@body(parts);
|
||||
};
|
||||
|
||||
@@ -15,9 +15,9 @@ fault JsonParsingError
|
||||
INVALID_NUMBER,
|
||||
}
|
||||
|
||||
fn Object*! parse(InStream* s, Allocator* using = mem::heap())
|
||||
fn Object*! parse(InStream* s, Allocator* allocator = mem::heap())
|
||||
{
|
||||
JsonContext context = { .last_string = dstring::new_with_capacity(64, using), .stream = s, .allocator = using };
|
||||
JsonContext context = { .last_string = dstring::new_with_capacity(64, allocator), .stream = s, .allocator = allocator };
|
||||
defer context.last_string.free();
|
||||
return parse_any(&context);
|
||||
}
|
||||
@@ -86,7 +86,7 @@ fn JsonTokenType! lex_number(JsonContext *context, char c) @local
|
||||
{
|
||||
@pool()
|
||||
{
|
||||
DString t = dstring::tnew_with_capacity(32);
|
||||
DString t = dstring::temp_with_capacity(32);
|
||||
bool negate = c == '-';
|
||||
if (negate)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ const int PRINTF_NTOA_BUFFER_SIZE = 256;
|
||||
|
||||
interface Printable
|
||||
{
|
||||
fn String to_string(Allocator *using) @optional;
|
||||
fn String to_new_string(Allocator *allocator) @optional;
|
||||
fn usz! to_format(Formatter* formatter) @optional;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ fn usz! Formatter.print_with_function(&self, Printable* arg)
|
||||
}
|
||||
return arg.to_format(self);
|
||||
}
|
||||
if (&arg.to_string)
|
||||
if (&arg.to_new_string)
|
||||
{
|
||||
PrintFlags old = self.flags;
|
||||
uint old_width = self.width;
|
||||
@@ -100,7 +100,7 @@ fn usz! Formatter.print_with_function(&self, Printable* arg)
|
||||
}
|
||||
@pool()
|
||||
{
|
||||
return self.out_substr(arg.to_string(mem::temp()));
|
||||
return self.out_substr(arg.to_new_string(mem::temp()));
|
||||
};
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
|
||||
@@ -49,7 +49,7 @@ fault IoError
|
||||
* @param stream
|
||||
* @require @is_instream(stream)
|
||||
**/
|
||||
macro String! readline(stream = io::stdin(), Allocator* using = mem::heap())
|
||||
macro String! readline(stream = io::stdin(), Allocator* allocator = mem::heap())
|
||||
{
|
||||
bool $is_stream = $typeof(stream).typeid == InStream*.typeid;
|
||||
$if $is_stream:
|
||||
@@ -60,9 +60,9 @@ macro String! readline(stream = io::stdin(), Allocator* using = mem::heap())
|
||||
$endif
|
||||
|
||||
if (val == '\n') return "";
|
||||
@pool(using)
|
||||
@pool(allocator)
|
||||
{
|
||||
DString str = dstring::tnew_with_capacity(256);
|
||||
DString str = dstring::temp_with_capacity(256);
|
||||
if (val != '\r') str.append(val);
|
||||
while (1)
|
||||
{
|
||||
@@ -80,7 +80,7 @@ macro String! readline(stream = io::stdin(), Allocator* using = mem::heap())
|
||||
if (c == '\n') break;
|
||||
str.append_char(c);
|
||||
}
|
||||
return str.copy_str(using);
|
||||
return str.copy_str(allocator);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module std::io::os;
|
||||
import libc;
|
||||
|
||||
macro String! getcwd(Allocator* using = mem::heap())
|
||||
macro String! getcwd(Allocator* allocator = mem::heap())
|
||||
{
|
||||
$switch
|
||||
$case env::WIN32:
|
||||
@@ -17,7 +17,7 @@ macro String! getcwd(Allocator* using = mem::heap())
|
||||
free = true;
|
||||
}
|
||||
Char16[] str16 = res[:win32::wcslen(res)];
|
||||
return string::from_utf16(str16, using);
|
||||
return string::new_from_utf16(str16, allocator);
|
||||
|
||||
$case env::POSIX:
|
||||
const usz DEFAULT_BUFFER = 256;
|
||||
@@ -32,7 +32,7 @@ macro String! getcwd(Allocator* using = mem::heap())
|
||||
free = true;
|
||||
}
|
||||
defer if (free) libc::free((void*)res);
|
||||
return res.copy(using);
|
||||
return res.copy(allocator);
|
||||
|
||||
$default:
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
module std::io::file::os @if(env::POSIX);
|
||||
|
||||
fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator* using)
|
||||
fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator* allocator)
|
||||
{
|
||||
PathList list;
|
||||
list.init(.using = using);
|
||||
list.init_new(.allocator = allocator);
|
||||
DIRPtr directory = posix::opendir(dir.str_view() ? dir.as_zstr() : (ZString)".");
|
||||
defer if (directory) posix::closedir(directory);
|
||||
if (!directory) return (path::is_dir(dir) ? IoError.CANNOT_READ_DIR : IoError.FILE_NOT_DIR)?;
|
||||
@@ -14,7 +14,7 @@ fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Al
|
||||
if (!name || name == "." || name == "..") continue;
|
||||
if (entry.d_type == posix::DT_LNK && no_symlinks) continue;
|
||||
if (entry.d_type == posix::DT_DIR && no_dirs) continue;
|
||||
Path path = path::new(name, using)!!;
|
||||
Path path = path::new(name, allocator)!!;
|
||||
list.append(path);
|
||||
}
|
||||
return list;
|
||||
@@ -22,12 +22,12 @@ fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Al
|
||||
|
||||
module std::io::os @if(env::WIN32);
|
||||
|
||||
fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator* using)
|
||||
fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator* allocator)
|
||||
{
|
||||
PathList list;
|
||||
list.init(.using = using);
|
||||
list.init_new(.allocator = allocator);
|
||||
|
||||
@pool(using)
|
||||
@pool(allocator)
|
||||
{
|
||||
WString result = dir.str_view().tconcat(`\*`).to_temp_wstring()!!;
|
||||
Win32_WIN32_FIND_DATAW find_data;
|
||||
@@ -37,11 +37,11 @@ fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Al
|
||||
do
|
||||
{
|
||||
if (no_dirs && (find_data.dwFileAttributes & win32::FILE_ATTRIBUTE_DIRECTORY)) continue;
|
||||
@pool(using)
|
||||
@pool(allocator)
|
||||
{
|
||||
String filename = string::temp_from_wstring((WString)&find_data.cFileName)!;
|
||||
if (filename == ".." || filename == ".") continue;
|
||||
list.append(path::new(filename, using)!);
|
||||
list.append(path::new(filename, allocator)!);
|
||||
};
|
||||
} while (win32::findNextFileW(find, &find_data));
|
||||
return list;
|
||||
|
||||
@@ -38,7 +38,7 @@ fn void! native_rmtree(Path path)
|
||||
{
|
||||
Win32_WIN32_FIND_DATAW find_data;
|
||||
String s = path.str_view().tconcat("\\*");
|
||||
Win32_HANDLE find = win32::findFirstFileW(s.to_utf16(mem::temp()), &find_data)!;
|
||||
Win32_HANDLE find = win32::findFirstFileW(s.to_temp_utf16(), &find_data)!;
|
||||
|
||||
if (find == win32::INVALID_HANDLE_VALUE) return IoError.CANNOT_READ_DIR?;
|
||||
defer win32::findClose(find);
|
||||
@@ -46,7 +46,7 @@ fn void! native_rmtree(Path path)
|
||||
{
|
||||
@pool()
|
||||
{
|
||||
String filename = string::from_wstring((WString)&find_data.cFileName, mem::temp())!;
|
||||
String filename = string::new_from_wstring((WString)&find_data.cFileName, mem::temp())!;
|
||||
if (filename == "." || filename == "..") continue;
|
||||
Path file_path = path.tappend(filename)!;
|
||||
if (find_data.dwFileAttributes & win32::FILE_ATTRIBUTE_DIRECTORY)
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
module std::io::os @if(env::LIBC);
|
||||
|
||||
fn Path! native_temp_directory(Allocator* using = mem::heap()) @if(!env::WIN32)
|
||||
fn Path! native_temp_directory(Allocator* allocator = mem::heap()) @if(!env::WIN32)
|
||||
{
|
||||
foreach (String env : { "TMPDIR", "TMP", "TEMP", "TEMPDIR" })
|
||||
{
|
||||
String tmpdir = env::get_var(env) ?? "";
|
||||
if (tmpdir) return path::new(tmpdir, using);
|
||||
if (tmpdir) return path::new(tmpdir, allocator);
|
||||
}
|
||||
return path::new("/tmp", using);
|
||||
return path::new("/tmp", allocator);
|
||||
}
|
||||
|
||||
fn Path! native_temp_directory(Allocator* using = mem::heap()) @if(env::WIN32)
|
||||
fn Path! native_temp_directory(Allocator* allocator = mem::heap()) @if(env::WIN32)
|
||||
{
|
||||
@pool(using)
|
||||
@pool(allocator)
|
||||
{
|
||||
Win32_DWORD len = win32::getTempPathW(0, null);
|
||||
if (!len) return IoError.GENERAL_ERROR?;
|
||||
Char16[] buff = tmalloc(Char16, len + 1);
|
||||
Char16[] buff = mem::temp_array(Char16, len + (usz)1);
|
||||
if (!win32::getTempPathW(len, buff)) return IoError.GENERAL_ERROR?;
|
||||
return path::new(string::temp_from_utf16(buff[:len]), using);
|
||||
return path::new(string::temp_from_utf16(buff[:len]), allocator);
|
||||
};
|
||||
}
|
||||
|
||||
module std::io::os @if(env::NO_LIBC);
|
||||
|
||||
macro Path! native_temp_directory(Allocator* using = mem::heap())
|
||||
macro Path! native_temp_directory(Allocator* allocator = mem::heap())
|
||||
{
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
}
|
||||
|
||||
@@ -26,11 +26,11 @@ enum PathEnv
|
||||
POSIX
|
||||
}
|
||||
|
||||
fn Path! getcwd(Allocator* using = mem::heap())
|
||||
fn Path! getcwd(Allocator* allocator = mem::heap())
|
||||
{
|
||||
@pool(using)
|
||||
@pool(allocator)
|
||||
{
|
||||
return new(os::getcwd(mem::temp()), using);
|
||||
return new(os::getcwd(mem::temp()), allocator);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ fn usz! file_size(Path path) => os::native_file_size(path.str_view());
|
||||
fn bool exists(Path path) => os::native_file_or_dir_exists(path.str_view());
|
||||
fn Path! tgetcwd() => getcwd(mem::temp()) @inline;
|
||||
fn void! chdir(Path path) => os::native_chdir(path) @inline;
|
||||
fn Path! temp_directory(Allocator* using = mem::heap()) => os::native_temp_directory(using);
|
||||
fn Path! temp_directory(Allocator* allocator = mem::heap()) => os::native_temp_directory(allocator);
|
||||
fn void! delete(Path path) => os::native_remove(path.str_view()) @inline;
|
||||
|
||||
macro bool is_separator(char c, PathEnv path_env = DEFAULT_PATH_ENV)
|
||||
@@ -58,10 +58,10 @@ macro bool is_win32_separator(char c)
|
||||
return c == '/' || c == '\\';
|
||||
}
|
||||
|
||||
fn PathList! ls(Path dir, bool no_dirs = false, bool no_symlinks = false, String mask = "", Allocator* using = mem::heap())
|
||||
fn PathList! ls(Path dir, bool no_dirs = false, bool no_symlinks = false, String mask = "", Allocator* allocator = mem::heap())
|
||||
{
|
||||
$if $defined(os::native_ls):
|
||||
return os::native_ls(dir, no_dirs, no_symlinks, mask, using);
|
||||
return os::native_ls(dir, no_dirs, no_symlinks, mask, allocator);
|
||||
$else
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
$endif
|
||||
@@ -105,27 +105,32 @@ fn void! rmtree(Path path)
|
||||
$endif
|
||||
}
|
||||
|
||||
fn Path! new(String path, Allocator* using = mem::heap(), PathEnv path_env = DEFAULT_PATH_ENV)
|
||||
fn Path! new(String path, Allocator* allocator = mem::heap(), PathEnv path_env = DEFAULT_PATH_ENV)
|
||||
{
|
||||
return { normalize(path.copy(using), path_env), path_env };
|
||||
return { normalize(path.copy(allocator), path_env), path_env };
|
||||
}
|
||||
|
||||
fn Path! new_win32_wstring(WString path, Allocator* using = mem::heap())
|
||||
fn Path! temp_new(String path, PathEnv path_env = DEFAULT_PATH_ENV)
|
||||
{
|
||||
@pool(using)
|
||||
return new(path, mem::temp(), path_env);
|
||||
}
|
||||
|
||||
fn Path! new_win32_wstring(WString path, Allocator* allocator = mem::heap())
|
||||
{
|
||||
@pool(allocator)
|
||||
{
|
||||
return path::new(string::temp_from_wstring(path)!, .using = using);
|
||||
return path::new(string::temp_from_wstring(path)!, .allocator = allocator);
|
||||
};
|
||||
}
|
||||
|
||||
fn Path! new_windows(String path, Allocator* using = mem::heap())
|
||||
fn Path! new_windows(String path, Allocator* allocator = mem::heap())
|
||||
{
|
||||
return new(path, using, WIN32);
|
||||
return new(path, allocator, WIN32);
|
||||
}
|
||||
|
||||
fn Path! new_posix(String path, Allocator* using = mem::heap())
|
||||
fn Path! new_posix(String path, Allocator* allocator = mem::heap())
|
||||
{
|
||||
return new(path, using, POSIX);
|
||||
return new(path, allocator, POSIX);
|
||||
}
|
||||
|
||||
fn bool Path.equals(self, Path p2)
|
||||
@@ -138,18 +143,18 @@ fn bool Path.equals(self, Path p2)
|
||||
*
|
||||
* @param [in] filename
|
||||
**/
|
||||
fn Path! Path.append(self, String filename, Allocator* using = mem::heap())
|
||||
fn Path! Path.append(self, String filename, Allocator* allocator = mem::heap())
|
||||
{
|
||||
if (!self.path_string.len) return new(filename, using, self.env)!;
|
||||
if (!self.path_string.len) return new(filename, allocator, self.env)!;
|
||||
assert(!is_separator(self.path_string[^1], self.env));
|
||||
|
||||
@pool(using)
|
||||
@pool(allocator)
|
||||
{
|
||||
DString dstr = dstring::tnew_with_capacity(self.path_string.len + 1 + filename.len);
|
||||
DString dstr = dstring::temp_with_capacity(self.path_string.len + 1 + filename.len);
|
||||
dstr.append(self.path_string);
|
||||
dstr.append(PREFERRED_SEPARATOR);
|
||||
dstr.append(filename);
|
||||
return { normalize(dstr.copy_str(using), self.env), self.env };
|
||||
return { normalize(dstr.copy_str(allocator), self.env), self.env };
|
||||
};
|
||||
}
|
||||
|
||||
@@ -174,14 +179,14 @@ fn bool! Path.is_absolute(self)
|
||||
return path_start < path_str.len && is_separator(path_str[path_start], self.env);
|
||||
}
|
||||
|
||||
fn Path! Path.absolute(self, Allocator* using = mem::heap())
|
||||
fn Path! Path.absolute(self, Allocator* allocator = mem::heap())
|
||||
{
|
||||
String path_str = self.str_view();
|
||||
if (!path_str.len) path_str = ".";
|
||||
if (path_str == ".")
|
||||
{
|
||||
String cwd = os::getcwd(mem::temp())!;
|
||||
return new(cwd, using, self.env);
|
||||
return new(cwd, allocator, self.env);
|
||||
}
|
||||
switch (self.env)
|
||||
{
|
||||
@@ -192,7 +197,7 @@ fn Path! Path.absolute(self, Allocator* using = mem::heap())
|
||||
if (path_str[0] == PREFERRED_SEPARATOR_POSIX) return self;
|
||||
}
|
||||
String cwd = os::getcwd(mem::temp())!;
|
||||
return Path{ cwd, self.env }.append(path_str, using)!;
|
||||
return Path{ cwd, self.env }.append(path_str, allocator)!;
|
||||
}
|
||||
|
||||
fn String Path.basename(self)
|
||||
@@ -416,14 +421,14 @@ def PathWalker = fn bool! (Path, bool is_dir, void*);
|
||||
fn bool! Path.walk(self, PathWalker w, void* data)
|
||||
{
|
||||
const PATH_MAX = 512;
|
||||
@stack_mem(PATH_MAX; Allocator* using)
|
||||
@stack_mem(PATH_MAX; Allocator* allocator)
|
||||
{
|
||||
Path abs = self.absolute(using)!;
|
||||
PathList files = ls(abs, .using = using)!;
|
||||
Path abs = self.absolute(allocator)!;
|
||||
PathList files = ls(abs, .allocator = allocator)!;
|
||||
foreach (f : files)
|
||||
{
|
||||
if (f.str_view() == "." || f.str_view() == "..") continue;
|
||||
f = abs.append(f.str_view(), using)!;
|
||||
f = abs.append(f.str_view(), allocator)!;
|
||||
bool is_directory = is_dir(f);
|
||||
if (w(f, is_directory, data)!) return true;
|
||||
if (is_directory && f.walk(w, data)!) return true;
|
||||
@@ -454,9 +459,9 @@ fn usz! Path.to_format(&self, Formatter* formatter) @dynamic
|
||||
return formatter.print(self.str_view());
|
||||
}
|
||||
|
||||
fn String Path.to_string(&self, Allocator* using = mem::heap()) @dynamic
|
||||
fn String Path.to_new_string(&self, Allocator* allocator = mem::heap()) @dynamic
|
||||
{
|
||||
return self.str_view().copy(using);
|
||||
return self.str_view().copy(allocator);
|
||||
}
|
||||
|
||||
const bool[256] RESERVED_PATH_CHAR_POSIX = {
|
||||
|
||||
@@ -142,12 +142,12 @@ fn usz! copy_to(InStream* in, OutStream* dst, char[] buffer = {})
|
||||
$case NORMAL:
|
||||
@pool()
|
||||
{
|
||||
return copy_through_buffer(in, dst, tmalloc(char, 4096));
|
||||
return copy_through_buffer(in, dst, mem::temp_array(char, 4096));
|
||||
};
|
||||
$case SMALL:
|
||||
@pool()
|
||||
{
|
||||
return copy_through_buffer(in, dst, tmalloc(char, 1024));
|
||||
return copy_through_buffer(in, dst, mem::temp_array(char, 1024));
|
||||
};
|
||||
$case TINY:
|
||||
$case NONE:
|
||||
|
||||
@@ -16,17 +16,17 @@ struct ByteBuffer (InStream, OutStream)
|
||||
* max_read defines how many bytes might be kept before its internal buffer is shrinked.
|
||||
* @require self.bytes.len == 0 "Buffer already initialized."
|
||||
**/
|
||||
fn ByteBuffer*! ByteBuffer.init(&self, usz max_read, usz initial_capacity = 16, Allocator* using = mem::heap())
|
||||
fn ByteBuffer*! ByteBuffer.init_new(&self, usz max_read, usz initial_capacity = 16, Allocator* allocator = mem::heap())
|
||||
{
|
||||
*self = { .allocator = using, .max_read = max_read };
|
||||
*self = { .allocator = allocator, .max_read = max_read };
|
||||
initial_capacity = max(initial_capacity, 16);
|
||||
self.grow(initial_capacity)!;
|
||||
return self;
|
||||
}
|
||||
|
||||
fn ByteBuffer*! ByteBuffer.tinit(&self, usz max_read, usz initial_capacity = 16)
|
||||
fn ByteBuffer*! ByteBuffer.init_temp(&self, usz max_read, usz initial_capacity = 16)
|
||||
{
|
||||
return self.init(max_read, initial_capacity, mem::temp())!;
|
||||
return self.init_new(max_read, initial_capacity, mem::temp());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,7 +131,7 @@ fn usz! ByteBuffer.available(&self) @inline @dynamic
|
||||
fn void! ByteBuffer.grow(&self, usz n)
|
||||
{
|
||||
n = math::next_power_of_2(n);
|
||||
char* p = realloc_aligned(self.bytes, n, .alignment = char.alignof, .using = self.allocator)!;
|
||||
char* p = self.allocator.realloc_aligned(self.bytes, n, .alignment = char.alignof)!;
|
||||
self.bytes = p[:n];
|
||||
}
|
||||
|
||||
|
||||
@@ -9,35 +9,36 @@ struct ByteWriter (OutStream)
|
||||
|
||||
/**
|
||||
* @param [&inout] self
|
||||
* @param [&in] using
|
||||
* @param [&inout] allocator
|
||||
* @require self.bytes.len == 0 "Init may not run on on already initialized data"
|
||||
* @ensure (bool)using, self.index == 0
|
||||
* @ensure (bool)allocator, self.index == 0
|
||||
**/
|
||||
fn ByteWriter* ByteWriter.init(&self, Allocator* using = mem::heap())
|
||||
fn ByteWriter* ByteWriter.init_new(&self, Allocator* allocator = mem::heap())
|
||||
{
|
||||
*self = { .bytes = {}, .allocator = using };
|
||||
return self;
|
||||
}
|
||||
|
||||
fn ByteWriter* ByteWriter.init_buffer(&self, char[] data)
|
||||
{
|
||||
*self = { .bytes = data, .allocator = null };
|
||||
*self = { .bytes = {}, .allocator = allocator };
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] self
|
||||
* @require self.bytes.len == 0 "Init may not run on on already initialized data"
|
||||
* @ensure self.index == 0
|
||||
**/
|
||||
fn ByteWriter* ByteWriter.tinit(&self)
|
||||
fn ByteWriter* ByteWriter.init_temp(&self)
|
||||
{
|
||||
return self.init(mem::temp());
|
||||
return self.init_new(mem::temp());
|
||||
}
|
||||
|
||||
fn ByteWriter* ByteWriter.init_with_buffer(&self, char[] data)
|
||||
{
|
||||
*self = { .bytes = data, .allocator = null };
|
||||
return self;
|
||||
}
|
||||
|
||||
fn void! ByteWriter.destroy(&self) @dynamic
|
||||
{
|
||||
if (!self.allocator) return;
|
||||
if (void* ptr = self.bytes.ptr) free(ptr, .using = self.allocator);
|
||||
if (void* ptr = self.bytes.ptr) self.allocator.free(ptr);
|
||||
*self = { };
|
||||
}
|
||||
|
||||
@@ -52,7 +53,7 @@ fn void! ByteWriter.ensure_capacity(&self, usz len) @inline
|
||||
if (!self.allocator) return IoError.OUT_OF_SPACE?;
|
||||
if (len < 16) len = 16;
|
||||
usz new_capacity = math::next_power_of_2(len);
|
||||
char* new_ptr = realloc_checked(self.bytes.ptr, new_capacity, .using = self.allocator)!;
|
||||
char* new_ptr = self.allocator.realloc_checked(self.bytes.ptr, new_capacity)!;
|
||||
self.bytes = new_ptr[:new_capacity];
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ fn void seeder(char[] input, char[] out_buffer)
|
||||
usz out_chars = out_buffer.len;
|
||||
@pool()
|
||||
{
|
||||
ulong[] words = tmalloc(ulong, (out_chars + 7) / 8);
|
||||
ulong[] words = mem::temp_array(ulong, (out_chars + 7) / 8);
|
||||
words[..] = ODD_PHI64;
|
||||
usz words_len_2 = words.len * 2;
|
||||
|
||||
@@ -85,7 +85,7 @@ fn char[8 * 4] entropy()
|
||||
hash(&entropy),
|
||||
random_int,
|
||||
hash(clock::now()),
|
||||
hash(&DString.init),
|
||||
hash(&DString.init_new),
|
||||
hash(mem::heap())
|
||||
};
|
||||
return bitcast(entropy_data, char[8 * 4]);
|
||||
|
||||
@@ -56,7 +56,7 @@ fn usz! InetAddress.to_format(InetAddress* addr, Formatter* formatter) @dynamic
|
||||
return formatter.printf("%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)!;
|
||||
}
|
||||
|
||||
fn String InetAddress.to_string(InetAddress* addr, Allocator* using = mem::heap()) @dynamic
|
||||
fn String InetAddress.to_new_string(InetAddress* addr, Allocator* allocator = mem::heap()) @dynamic
|
||||
{
|
||||
if (addr.is_ipv6)
|
||||
{
|
||||
@@ -64,11 +64,11 @@ fn String InetAddress.to_string(InetAddress* addr, Allocator* using = mem::heap(
|
||||
String res = (String)io::bprintf(&buffer, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
|
||||
addr.ipv6.a, addr.ipv6.b, addr.ipv6.c, addr.ipv6.d,
|
||||
addr.ipv6.e, addr.ipv6.f, addr.ipv6.g, addr.ipv6.h)!!;
|
||||
return res.copy(using);
|
||||
return res.copy(allocator);
|
||||
}
|
||||
char[3 * 4 + 3 + 1] buffer;
|
||||
String res = (String)io::bprintf(&buffer, "%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)!!;
|
||||
return res.copy(using);
|
||||
return res.copy(allocator);
|
||||
}
|
||||
|
||||
fn InetAddress! ipv6_from_str(String s)
|
||||
@@ -262,12 +262,11 @@ fn AddrInfo*! addrinfo(String host, uint port, AIFamily ai_family, AISockType ai
|
||||
@pool()
|
||||
{
|
||||
ZString zhost = host.zstr_tcopy();
|
||||
DString str;
|
||||
str.tinit();
|
||||
str.printf("%d", port);
|
||||
DString str = dstring::temp_with_capacity(32);
|
||||
str.appendf("%d", port);
|
||||
AddrInfo hints = { .ai_family = ai_family, .ai_socktype = ai_socktype };
|
||||
AddrInfo* ai;
|
||||
if (os::getaddrinfo(zhost, str.copy_zstr(mem::temp()), &hints, &ai)) return NetError.ADDRINFO_FAILED?;
|
||||
if (os::getaddrinfo(zhost, str.zstr_view(), &hints, &ai)) return NetError.ADDRINFO_FAILED?;
|
||||
return ai;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -56,9 +56,14 @@ fn uint! ipv4toint(String s)
|
||||
return out;
|
||||
}
|
||||
|
||||
fn String! inttoipv4(uint val, Allocator* using = mem::heap())
|
||||
fn String! int_to_new_ipv4(uint val, Allocator* allocator = mem::heap())
|
||||
{
|
||||
char[3 * 4 + 3 + 1] buffer;
|
||||
String res = (String)io::bprintf(&buffer, "%d.%d.%d.%d", val >> 24, (val >> 16) & 0xFF, (val >> 8) & 0xFF, val & 0xFF)!;
|
||||
return res.copy(using);
|
||||
}
|
||||
return res.copy(allocator);
|
||||
}
|
||||
|
||||
fn String! int_to_temp_ipv4(uint val)
|
||||
{
|
||||
return int_to_new_ipv4(val, mem::temp());
|
||||
}
|
||||
|
||||
@@ -45,9 +45,9 @@ fn usz! Backtrace.to_format(&self, Formatter* formatter) @dynamic
|
||||
fn void Backtrace.free(&self)
|
||||
{
|
||||
if (!self.allocator) return;
|
||||
free(self.function, .using = self.allocator);
|
||||
free(self.object_file, .using = self.allocator);
|
||||
free(self.file, .using = self.allocator);
|
||||
self.allocator.free(self.function);
|
||||
self.allocator.free(self.object_file);
|
||||
self.allocator.free(self.file);
|
||||
}
|
||||
|
||||
fn Backtrace* Backtrace.init(&self, uptr offset, String function, String object_file, String file = "", uint line = 0, Allocator* using = mem::heap())
|
||||
|
||||
@@ -9,19 +9,19 @@ import libc;
|
||||
* @require name.len > 0
|
||||
* @return! SearchResult.MISSING
|
||||
**/
|
||||
fn String! get_var(String name, Allocator* using = mem::heap())
|
||||
fn String! get_var(String name, Allocator* allocator = mem::heap())
|
||||
{
|
||||
@pool(using)
|
||||
@pool(allocator)
|
||||
{
|
||||
$switch
|
||||
$case env::LIBC && !env::WIN32:
|
||||
ZString val = libc::getenv(name.zstr_tcopy());
|
||||
return val ? val.copy(using) : SearchResult.MISSING?;
|
||||
return val ? val.copy(allocator) : SearchResult.MISSING?;
|
||||
$case env::WIN32:
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getenvironmentvariable
|
||||
const usz BUFSIZE = 1024;
|
||||
WString buff = (WString)tcalloc(BUFSIZE * 2 + 2);
|
||||
WString wstr = name.to_wstring(mem::temp())!;
|
||||
WString wstr = name.to_temp_wstring()!;
|
||||
usz len = win32::getEnvironmentVariableW(wstr, buff, BUFSIZE);
|
||||
if (len == 0) return SearchResult.MISSING?;
|
||||
if (len > BUFSIZE)
|
||||
@@ -29,13 +29,17 @@ fn String! get_var(String name, Allocator* using = mem::heap())
|
||||
buff = (WString)tmalloc(len * 2 + 2);
|
||||
win32::getEnvironmentVariableW(wstr, buff, (Win32_DWORD)len);
|
||||
}
|
||||
return string::from_wstring(buff, using);
|
||||
return string::new_from_wstring(buff, allocator);
|
||||
$default:
|
||||
return "";
|
||||
$endswitch
|
||||
};
|
||||
}
|
||||
|
||||
fn String! get_var_temp(String name)
|
||||
{
|
||||
return get_var(name, mem::temp());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [in] name
|
||||
@@ -48,14 +52,14 @@ fn bool set_var(String name, String value, bool overwrite = true)
|
||||
{
|
||||
$switch
|
||||
$case env::WIN32:
|
||||
WString wname = name.to_wstring(mem::temp())!!;
|
||||
WString wname = name.to_temp_wstring()!!;
|
||||
if (!overwrite)
|
||||
{
|
||||
Char16[8] buff;
|
||||
if (win32::getEnvironmentVariableW(wname, &buff, 8) > 0) return true;
|
||||
}
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setenvironmentvariable
|
||||
return (win32::setEnvironmentVariableW(wname, value.to_wstring(mem::temp())) ?? 1) == 0;
|
||||
return (win32::setEnvironmentVariableW(wname, value.to_temp_wstring()) ?? 1) == 0;
|
||||
$case env::LIBC && !env::WIN32:
|
||||
return libc::setenv(name.zstr_tcopy(), value.zstr_copy(), (int)overwrite) == 0;
|
||||
$default:
|
||||
@@ -82,21 +86,21 @@ fn String! get_home_dir(Allocator* using = mem::heap())
|
||||
/**
|
||||
* Returns the current user's config directory.
|
||||
**/
|
||||
fn Path! get_config_dir(Allocator* using = mem::heap())
|
||||
fn Path! get_config_dir(Allocator* allocator = mem::heap())
|
||||
{
|
||||
@pool(using)
|
||||
@pool(allocator)
|
||||
{
|
||||
$if env::WIN32:
|
||||
return path::new(get_var("AppData", .using = mem::temp()), .using = using);
|
||||
return path::new(get_var_temp("AppData"), allocator);
|
||||
$else
|
||||
$if env::DARWIN:
|
||||
String s = get_var("HOME", .using = mem::temp())!;
|
||||
String s = get_var_temp("HOME")!;
|
||||
const DIR = "Library/Application Support";
|
||||
$else
|
||||
String s = get_var("XDG_CONFIG_HOME", .using = mem::temp()) ?? get_var("HOME", .using = mem::temp())!;
|
||||
String s = get_var_temp("XDG_CONFIG_HOME") ?? get_var_temp("HOME")!;
|
||||
const DIR = ".config";
|
||||
$endif
|
||||
return path::new(s, .using = mem::temp()).append(DIR, .using = using);
|
||||
return path::temp_new(s).append(DIR, .allocator = allocator);
|
||||
$endif
|
||||
};
|
||||
}
|
||||
@@ -112,7 +116,7 @@ fn bool clear_var(String name)
|
||||
{
|
||||
$switch
|
||||
$case env::WIN32:
|
||||
WString wname = name.to_wstring(mem::temp())!!;
|
||||
WString wname = name.to_temp_wstring()!!;
|
||||
return win32::setEnvironmentVariableW(wname, null) == 0;
|
||||
$case env::LIBC && !env::WIN32:
|
||||
return libc::unsetenv(name.zstr_tcopy()) == 0;
|
||||
@@ -122,10 +126,10 @@ fn bool clear_var(String name)
|
||||
};
|
||||
}
|
||||
|
||||
fn String! executable_path(Allocator *using = mem::heap())
|
||||
fn String! executable_path(Allocator *allocator = mem::heap())
|
||||
{
|
||||
$if env::DARWIN:
|
||||
return darwin::executable_path();
|
||||
return darwin::executable_path(allocator);
|
||||
$else
|
||||
return "<Unsupported>";
|
||||
$endif
|
||||
|
||||
@@ -68,12 +68,12 @@ struct Darwin_segment_command_64
|
||||
}
|
||||
|
||||
|
||||
fn String! executable_path(Allocator *using = mem::heap())
|
||||
fn String! executable_path(Allocator *allocator)
|
||||
{
|
||||
char[4096] path;
|
||||
uint len = path.len;
|
||||
if (darwin_NSGetExecutablePath(&path, &len) < 0) return SearchResult.MISSING?;
|
||||
return ((ZString)&path).copy(.using = using);
|
||||
return ((ZString)&path).copy(allocator);
|
||||
}
|
||||
|
||||
def BacktraceList = List(<Backtrace>);
|
||||
@@ -95,16 +95,16 @@ fn uptr! load_address() @local
|
||||
}
|
||||
|
||||
|
||||
fn Backtrace! backtrace_load_element(String execpath, void* buffer, void* load_address, Allocator* using = mem::heap()) @local
|
||||
fn Backtrace! backtrace_load_element(String execpath, void* buffer, void* load_address, Allocator* allocator = mem::heap()) @local
|
||||
{
|
||||
@pool(using)
|
||||
@pool(allocator)
|
||||
{
|
||||
if (buffer)
|
||||
{
|
||||
SubProcess process = process::create({ "atos",
|
||||
"-o", execpath, "-arch", env::AARCH64 ? "arm64" : "x86_64", "-l",
|
||||
string::tprintf("%p", load_address),
|
||||
string::tprintf("%p", buffer),
|
||||
string::tformat("%p", load_address),
|
||||
string::tformat("%p", buffer),
|
||||
"-fullPath" })!;
|
||||
process.join()!;
|
||||
char* buf = tmalloc(1024);
|
||||
@@ -116,11 +116,11 @@ fn Backtrace! backtrace_load_element(String execpath, void* buffer, void* load_a
|
||||
String[] path_parts = parts[3].tsplit(":");
|
||||
return {
|
||||
.offset = (uptr)buffer,
|
||||
.function = parts[0].copy(using),
|
||||
.object_file = parts[2][..^2].copy(using),
|
||||
.file = path_parts[0][1..].copy(using),
|
||||
.function = parts[0].copy(allocator),
|
||||
.object_file = parts[2][..^2].copy(allocator),
|
||||
.file = path_parts[0][1..].copy(allocator),
|
||||
.line = path_parts[1][..^2].to_uint()!,
|
||||
.allocator = using
|
||||
.allocator = allocator
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -128,21 +128,21 @@ fn Backtrace! backtrace_load_element(String execpath, void* buffer, void* load_a
|
||||
if (!buffer || !darwin::dladdr(buffer, &info)) return backtrace::BACKTRACE_UNKNOWN;
|
||||
return {
|
||||
.offset = (uptr)buffer,
|
||||
.function = info.dli_sname ? info.dli_sname.copy(using) : "???".copy(using),
|
||||
.object_file = info.dli_fname.copy(using),
|
||||
.file = "".copy(using),
|
||||
.function = info.dli_sname ? info.dli_sname.copy(allocator) : "???".copy(allocator),
|
||||
.object_file = info.dli_fname.copy(allocator),
|
||||
.file = "".copy(allocator),
|
||||
.line = 0
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
fn BacktraceList! backtrace_load(Allocator* using = mem::heap())
|
||||
fn BacktraceList! backtrace_load(Allocator* allocator)
|
||||
{
|
||||
void*[256] bt_buffer;
|
||||
CInt size = posix::backtrace(&bt_buffer, 256);
|
||||
void *load_addr = (void *)load_address()!;
|
||||
BacktraceList list;
|
||||
list.init(size, .using = using);
|
||||
list.init_new(size, allocator);
|
||||
defer catch
|
||||
{
|
||||
foreach (trace : list)
|
||||
@@ -151,13 +151,13 @@ fn BacktraceList! backtrace_load(Allocator* using = mem::heap())
|
||||
}
|
||||
list.free();
|
||||
}
|
||||
@pool(using)
|
||||
@pool(allocator)
|
||||
{
|
||||
String execpath = executable_path(mem::temp())!;
|
||||
for (usz i = 1; i < size; i++)
|
||||
{
|
||||
void* buffer = bt_buffer[i];
|
||||
Backtrace trace = backtrace_load_element(execpath, buffer, load_addr, .using = using)!;
|
||||
Backtrace trace = backtrace_load_element(execpath, buffer, load_addr, allocator)!;
|
||||
list.append(trace);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -26,11 +26,11 @@ macro Class! class_by_name(char* c)
|
||||
return cls;
|
||||
}
|
||||
|
||||
macro Class[] class_get_list(Allocator *using = mem::heap())
|
||||
macro Class[] class_get_list(Allocator *allocator = mem::heap())
|
||||
{
|
||||
int num_classes = _macos_objc_getClassList(null, 0);
|
||||
if (!num_classes) return {};
|
||||
Class[] entries = array::make(Class, num_classes, using);
|
||||
Class[] entries = allocator.new_array(Class, num_classes);
|
||||
_macos_objc_getClassList(entries.ptr, entries.len);
|
||||
return entries;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ fn void! create_named_pipe_helper(void** rd, void **wr) @local @if(env::WIN32)
|
||||
long unique = index++;
|
||||
@pool()
|
||||
{
|
||||
String s = string::tprintf(`\\.\pipe\c3_subprocess.%08x.%08x.%d`, win32::getCurrentProcessId(), win32::getCurrentThreadId(), unique);
|
||||
String s = string::tformat(`\\.\pipe\c3_subprocess.%08x.%08x.%d`, win32::getCurrentProcessId(), win32::getCurrentThreadId(), unique);
|
||||
Win32_LPCSTR str = (Win32_LPCSTR)s.ptr;
|
||||
*rd = win32::createNamedPipeA(
|
||||
str,
|
||||
@@ -75,8 +75,7 @@ fn void! create_named_pipe_helper(void** rd, void **wr) @local @if(env::WIN32)
|
||||
|
||||
fn WString convert_command_line_win32(String[] command_line) @inline @if(env::WIN32) @local
|
||||
{
|
||||
DString str;
|
||||
str.tinit(512);
|
||||
DString str = dstring::temp_with_capacity(512);
|
||||
foreach (i, s : command_line)
|
||||
{
|
||||
if (i != 0) str.append(' ');
|
||||
@@ -142,8 +141,7 @@ fn SubProcess! create(String[] command_line, SubProcessOptions options = {}, Str
|
||||
WString used_environment = null;
|
||||
if (!options.inherit_environment)
|
||||
{
|
||||
DString env;
|
||||
env.tinit();
|
||||
DString env = dstring::temp_with_capacity(64);
|
||||
if (!environment.len)
|
||||
{
|
||||
env.append("\0");
|
||||
@@ -249,7 +247,7 @@ fn SubProcess! create(String[] command_line, SubProcessOptions options = {}, Str
|
||||
**/
|
||||
fn ZString* tcopy_command_line(String[] command_line) @local @inline @if(env::POSIX)
|
||||
{
|
||||
ZString* copy = tmalloc(ZString, command_line.len + 1);
|
||||
ZString* copy = mem::temp_array(ZString, command_line.len + 1);
|
||||
foreach (i, str : command_line)
|
||||
{
|
||||
copy[i] = str.zstr_tcopy();
|
||||
@@ -262,7 +260,7 @@ const ZString[1] EMPTY_ENVIRONMENT @if(env::POSIX) = { null };
|
||||
fn ZString* tcopy_env(String[] environment) @local @inline @if(env::POSIX)
|
||||
{
|
||||
if (!environment.len) return &EMPTY_ENVIRONMENT;
|
||||
ZString* copy = tmalloc(ZString, environment.len + 1);
|
||||
ZString* copy = mem::temp_array(ZString, environment.len + 1);
|
||||
copy[environment.len] = null;
|
||||
foreach (i, str : environment)
|
||||
{
|
||||
|
||||
@@ -151,7 +151,7 @@ fn void* callback(void* arg) @private
|
||||
|
||||
fn void! NativeThread.create(&thread, ThreadFn thread_fn, void* arg)
|
||||
{
|
||||
PosixThreadData *thread_data = malloc(PosixThreadData);
|
||||
PosixThreadData *thread_data = mem::new(PosixThreadData);
|
||||
*thread_data = { .thread_fn = thread_fn, .arg = arg };
|
||||
if (posix::pthread_create(thread, null, &callback, thread_data) != 0)
|
||||
{
|
||||
|
||||
@@ -108,26 +108,25 @@ fn usz! NanoDuration.to_format(&self, Formatter* formatter) @dynamic
|
||||
bool neg = nd < 0;
|
||||
if (neg) nd = -nd;
|
||||
|
||||
DString str;
|
||||
str.tinit();
|
||||
DString str = dstring::temp_with_capacity(64);
|
||||
if (nd < 1_000_000_000)
|
||||
{
|
||||
// Less than 1s: print milliseconds, microseconds and nanoseconds.
|
||||
NanoDuration ms = nd / 1_000_000;
|
||||
if (ms > 0)
|
||||
{
|
||||
str.printf("%dms", ms);
|
||||
str.appendf("%dms", ms);
|
||||
nd -= ms * 1_000_000;
|
||||
}
|
||||
NanoDuration us = nd / 1000;
|
||||
if (us > 0)
|
||||
{
|
||||
str.printf("%dµs", us);
|
||||
str.appendf("%dµs", us);
|
||||
nd -= us * 1000;
|
||||
}
|
||||
if (nd > 0)
|
||||
{
|
||||
str.printf("%dns", nd);
|
||||
str.appendf("%dns", nd);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -139,13 +138,13 @@ fn usz! NanoDuration.to_format(&self, Formatter* formatter) @dynamic
|
||||
NanoDuration hour = nd / 3600;
|
||||
if (hour > 0)
|
||||
{
|
||||
str.printf("%dh", hour);
|
||||
str.appendf("%dh", hour);
|
||||
nd -= hour * 3600;
|
||||
}
|
||||
NanoDuration min = nd / 60;
|
||||
if (min > 0)
|
||||
{
|
||||
str.printf("%dm", min);
|
||||
str.appendf("%dm", min);
|
||||
nd -= min * 60;
|
||||
}
|
||||
NanoDuration sec = nd;
|
||||
@@ -153,11 +152,11 @@ fn usz! NanoDuration.to_format(&self, Formatter* formatter) @dynamic
|
||||
{
|
||||
// Ignore trailing zeroes.
|
||||
while (ms / 10 * 10 == ms) ms /= 10;
|
||||
str.printf("%d.%ds", sec, ms);
|
||||
str.appendf("%d.%ds", sec, ms);
|
||||
}
|
||||
else
|
||||
{
|
||||
str.printf("%ds", sec);
|
||||
str.appendf("%ds", sec);
|
||||
}
|
||||
}
|
||||
return formatter.printf(str.str_view())!;
|
||||
|
||||
Reference in New Issue
Block a user