Add "allocator-required" functions.

This commit is contained in:
Christoffer Lerno
2024-08-25 21:53:42 +02:00
parent 61246d713d
commit 4b2019cf20
13 changed files with 476 additions and 305 deletions

View File

@@ -18,9 +18,18 @@ struct AnyList (Printable)
/**
* @param initial_capacity "The initial capacity to reserve"
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
* Use `init` for to use a custom allocator.
**/
fn AnyList* AnyList.new_init(&self, usz initial_capacity = 16, Allocator allocator = allocator::heap())
fn AnyList* AnyList.new_init(&self, usz initial_capacity = 16, Allocator allocator = null)
{
return self.init(allocator ?: allocator::heap(), initial_capacity) @inline;
}
/**
* @param [&inout] allocator "The allocator to use"
* @param initial_capacity "The initial capacity to reserve"
**/
fn AnyList* AnyList.init(&self, Allocator allocator, usz initial_capacity = 16)
{
self.allocator = allocator;
self.size = 0;
@@ -44,7 +53,7 @@ fn AnyList* AnyList.new_init(&self, usz initial_capacity = 16, Allocator allocat
**/
fn AnyList* AnyList.temp_init(&self, usz initial_capacity = 16)
{
return self.new_init(initial_capacity, allocator::temp()) @inline;
return self.init(allocator::temp(), initial_capacity) @inline;
}
fn usz! AnyList.to_format(&self, Formatter* formatter) @dynamic
@@ -67,16 +76,19 @@ fn usz! AnyList.to_format(&self, Formatter* formatter) @dynamic
}
}
fn String AnyList.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
fn String AnyList.to_new_string(&self, Allocator allocator = null) @dynamic
{
return string::new_format("%s", *self, .allocator = allocator);
return string::format("%s", *self, .allocator = allocator ?: allocator::heap());
}
fn String AnyList.to_tstring(&self)
fn String AnyList.to_string(&self, Allocator allocator) @dynamic
{
return string::tformat("%s", *self);
return string::format("%s", *self, .allocator = allocator);
}
fn String AnyList.to_tstring(&self) => string::tformat("%s", *self);
/**
* Push an element on the list by cloning it.
**/
@@ -117,18 +129,35 @@ macro AnyList.pop(&self, $Type)
* Pop the last value and allocate the copy using the given allocator.
* @return! IteratorResult.NO_MORE_ELEMENT
**/
fn any! AnyList.new_pop(&self, Allocator allocator = allocator::heap())
fn any! AnyList.copy_pop(&self, Allocator allocator = allocator::heap())
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
defer self.free_element(self.entries[self.size]);
return allocator::clone_any(allocator, self.entries[--self.size]);
}
/**
* Pop the last value and allocate the copy using the given allocator.
* @return! IteratorResult.NO_MORE_ELEMENT
* @deprecated `use copy_pop`
**/
fn any! AnyList.new_pop(&self, Allocator allocator = allocator::heap())
{
return self.copy_pop(allocator);
}
/**
* Pop the last value and allocate the copy using the temp allocator
* @return! IteratorResult.NO_MORE_ELEMENT
* @deprecated `use tcopy_pop`
**/
fn any! AnyList.temp_pop(&self) => self.copy_pop(allocator::temp());
/**
* Pop the last value and allocate the copy using the temp allocator
* @return! IteratorResult.NO_MORE_ELEMENT
**/
fn any! AnyList.temp_pop(&self) => self.new_pop(allocator::temp());
fn any! AnyList.tcopy_pop(&self) => self.copy_pop(allocator::temp());
/**
* Pop the last value. It must later be released using list.free_element()
@@ -171,8 +200,17 @@ fn any! AnyList.pop_first_retained(&self)
/**
* Same as new_pop() but pops the first value instead.
* @deprecated `use copy_pop_first`
**/
fn any! AnyList.new_pop_first(&self, Allocator allocator = allocator::heap())
{
return self.copy_pop_first(allocator) @inline;
}
/**
* Same as new_pop() but pops the first value instead.
**/
fn any! AnyList.copy_pop_first(&self, Allocator allocator = allocator::heap())
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
defer self.free_element(self.entries[self.size]);
@@ -183,6 +221,12 @@ fn any! AnyList.new_pop_first(&self, Allocator allocator = allocator::heap())
/**
* Same as temp_pop() but pops the first value instead.
**/
fn any! AnyList.tcopy_pop_first(&self) => self.copy_pop_first(allocator::temp());
/**
* Same as temp_pop() but pops the first value instead.
* @deprecated `use tcopy_pop_first`
**/
fn any! AnyList.temp_pop_first(&self) => self.new_pop_first(allocator::temp());
/**

View File

@@ -41,7 +41,12 @@ fn usz! ElasticArray.to_format(&self, Formatter* formatter) @dynamic
fn String ElasticArray.to_string(&self, Allocator allocator) @dynamic
{
return string::new_format("%s", *self, .allocator = allocator);
return string::format("%s", *self, .allocator = allocator);
}
fn String ElasticArray.to_new_string(&self, Allocator allocator = nul) @dynamic
{
return string::format("%s", *self, .allocator = allocator ?: allocator::heap());
}
fn String ElasticArray.to_tstring(&self)
@@ -158,7 +163,15 @@ fn void ElasticArray.add_array(&self, Type[] array)
/**
* IMPORTANT The returned array must be freed using free_aligned.
**/
fn Type[] ElasticArray.to_new_aligned_array(&self, Allocator allocator = allocator::heap())
fn Type[] ElasticArray.to_new_aligned_array(&self)
{
return list_common::list_to_new_aligned_array(Type, self, allocator::heap());
}
/**
* IMPORTANT The returned array must be freed using free_aligned.
**/
fn Type[] ElasticArray.to_aligned_array(&self, Allocator allocator)
{
return list_common::list_to_new_aligned_array(Type, self, allocator);
}
@@ -166,7 +179,15 @@ fn Type[] ElasticArray.to_new_aligned_array(&self, Allocator allocator = allocat
/**
* @require !type_is_overaligned() : "This function is not available on overaligned types"
**/
macro Type[] ElasticArray.to_new_array(&self, Allocator allocator = allocator::heap())
macro Type[] ElasticArray.to_new_array(&self)
{
return list_common::list_to_array(Type, self, allocator::heap());
}
/**
* @require !type_is_overaligned() : "This function is not available on overaligned types"
**/
macro Type[] ElasticArray.to_array(&self, Allocator allocator)
{
return list_common::list_to_new_array(Type, self, allocator);
}
@@ -174,9 +195,9 @@ macro Type[] ElasticArray.to_new_array(&self, Allocator allocator = allocator::h
fn Type[] ElasticArray.to_tarray(&self)
{
$if type_is_overaligned():
return self.to_new_aligned_array(allocator::temp());
return self.to_aligned_array(allocator::temp());
$else
return self.to_new_array(allocator::temp());
return self.to_array(allocator::temp());
$endif;
}

View File

@@ -25,9 +25,14 @@ fn usz! EnumMap.to_format(&self, Formatter* formatter) @dynamic
return n;
}
fn String EnumMap.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
fn String EnumMap.to_string(&self, Allocator allocator) @dynamic
{
return string::new_format("%s", *self, .allocator = allocator);
return string::format("%s", *self, .allocator = allocator);
}
fn String EnumMap.to_new_string(&self, Allocator allocator = null) @dynamic
{
return string::format("%s", *self, .allocator = allocator ?: allocator::heap());
}
fn String EnumMap.to_tstring(&self) @dynamic

View File

@@ -143,7 +143,12 @@ fn usz! EnumSet.to_format(&set, Formatter* formatter) @dynamic
fn String EnumSet.to_new_string(&set, Allocator allocator = allocator::heap()) @dynamic
{
return string::new_format("%s", *set, .allocator = allocator);
return string::format("%s", *set, .allocator = allocator);
}
fn String EnumSet.to_string(&set, Allocator allocator) @dynamic
{
return string::format("%s", *set, .allocator = allocator);
}
fn String EnumSet.to_tstring(&set) @dynamic

View File

@@ -20,7 +20,19 @@ struct HashMap
* @require !self.allocator "Map was already initialized"
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
**/
fn HashMap* HashMap.new_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
fn HashMap* HashMap.new_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = null)
{
return self.init(allocator ?: allocator::heap(), capacity, load_factor);
}
/**
* @param [&inout] allocator "The allocator to use"
* @require capacity > 0 "The capacity must be 1 or higher"
* @require load_factor > 0.0 "The load factor must be higher than 0"
* @require !self.allocator "Map was already initialized"
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
**/
fn HashMap* HashMap.init(&self, Allocator allocator, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
{
capacity = math::next_power_of_2(capacity);
self.allocator = allocator;
@@ -38,7 +50,7 @@ fn HashMap* HashMap.new_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, fl
**/
fn HashMap* HashMap.temp_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
{
return self.new_init(capacity, load_factor, allocator::temp()) @inline;
return self.init(allocator::temp(), capacity, load_factor) @inline;
}
@@ -53,11 +65,19 @@ fn bool HashMap.is_initialized(&map)
return (bool)map.allocator;
}
/**
* @param [&in] other_map "The map to copy from."
**/
fn HashMap* HashMap.new_init_from_map(&self, HashMap* other_map)
{
return self.init_from_map(other_map, allocator::heap()) @inline;
}
/**
* @param [&inout] allocator "The allocator to use"
* @param [&in] other_map "The map to copy from."
**/
fn HashMap* HashMap.new_init_from_map(&self, HashMap* other_map, Allocator allocator = allocator::heap())
fn HashMap* HashMap.init_from_map(&self, HashMap* other_map, Allocator allocator)
{
self.new_init(other_map.table.len, other_map.load_factor, allocator);
self.put_all_for_create(other_map);
@@ -69,7 +89,7 @@ fn HashMap* HashMap.new_init_from_map(&self, HashMap* other_map, Allocator alloc
**/
fn HashMap* HashMap.temp_init_from_map(&map, HashMap* other_map)
{
return map.new_init_from_map(other_map, allocator::temp()) @inline;
return map.init_from_map(other_map, allocator::temp()) @inline;
}
fn bool HashMap.is_empty(&map) @inline
@@ -191,12 +211,25 @@ fn void HashMap.free(&map)
map.table = {};
}
fn Key[] HashMap.key_tlist(&map)
fn Key[] HashMap.tcopy_keys(&map)
{
return map.key_new_list(allocator::temp()) @inline;
return map.copy_keys(allocator::temp()) @inline;
}
fn Key[] HashMap.key_tlist(&map) @deprecated("Use 'tcopy_keys'")
{
return map.copy_keys(allocator::temp()) @inline;
}
/**
* @deprecated "use copy_keys"
**/
fn Key[] HashMap.key_new_list(&map, Allocator allocator = allocator::heap())
{
return map.copy_keys() @inline;
}
fn Key[] HashMap.copy_keys(&map, Allocator allocator = allocator::heap())
{
if (!map.count) return {};
@@ -235,12 +268,28 @@ macro HashMap.@each_entry(map; @body(entry))
}
}
/**
* @deprecated `use tcopy_values`
**/
fn Value[] HashMap.value_tlist(&map)
{
return map.value_new_list(allocator::temp()) @inline;
return map.copy_values(allocator::temp()) @inline;
}
fn Value[] HashMap.tcopy_values(&map)
{
return map.copy_values(allocator::temp()) @inline;
}
/**
* @deprecated `use copy_values`
**/
fn Value[] HashMap.value_new_list(&map, Allocator allocator = allocator::heap())
{
return map.copy_values(allocator);
}
fn Value[] HashMap.copy_values(&map, Allocator allocator = allocator::heap())
{
if (!map.count) return {};
Value[] list = allocator::alloc_array(allocator, Value, map.count);

View File

@@ -24,16 +24,24 @@ struct LinkedList
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
* @return "the initialized list"
**/
fn LinkedList* LinkedList.new_init(&self, Allocator allocator = allocator::heap())
fn LinkedList* LinkedList.init(&self, Allocator allocator)
{
*self = { .allocator = allocator };
return self;
}
/**
* @return "the initialized list"
**/
fn LinkedList* LinkedList.new_init(&self)
{
return self.init(allocator::heap()) @inline;
}
fn LinkedList* LinkedList.temp_init(&self)
{
return self.new_init(allocator::temp()) @inline;
return self.init(allocator::temp()) @inline;
}
/**

View File

@@ -102,7 +102,7 @@ fn usz! List.to_format(&self, Formatter* formatter) @dynamic
fn String List.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
{
return string::new_format("%s", *self, .allocator = allocator);
return string::format("%s", *self, .allocator = allocator);
}
fn String List.to_tstring(&self)

View File

@@ -29,14 +29,19 @@ fn Type Range.get(&self, usz index) @operator([])
return (Type)(self.start + (usz)index);
}
fn String Range.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
fn String Range.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic @deprecated
{
return string::new_format("[%s..%s]", self.start, self.end, .allocator = allocator);
return string::format("[%s..%s]", self.start, self.end, .allocator = allocator);
}
fn String Range.to_string(&self, Allocator allocator) @dynamic
{
return string::format("[%s..%s]", self.start, self.end, .allocator = allocator);
}
fn String Range.to_tstring(&self)
{
return self.to_new_string(allocator::temp());
return self.to_string(allocator::temp());
}
fn usz! Range.to_format(&self, Formatter* formatter) @dynamic
@@ -66,9 +71,14 @@ fn usz! ExclusiveRange.to_format(&self, Formatter* formatter) @dynamic
return formatter.printf("[%s..<%s]", self.start, self.end)!;
}
fn String ExclusiveRange.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
fn String ExclusiveRange.to_new_string(&self, Allocator allocator = null) @dynamic
{
return string::new_format("[%s..<%s]", self.start, self.end, .allocator = allocator);
return self.to_string(allocator ?: allocator::heap());
}
fn String ExclusiveRange.to_string(&self, Allocator allocator) @dynamic
{
return string::format("[%s..<%s]", self.start, self.end, .allocator = allocator);
}
fn String ExclusiveRange.to_tstring(&self)

View File

@@ -292,7 +292,7 @@ fn void DString.append_chars(&self, String str)
fn Char32[] DString.copy_utf32(&self, Allocator allocator = allocator::heap())
{
return self.str_view().to_new_utf32(allocator) @inline!!;
return self.str_view().to_utf32(allocator) @inline!!;
}
fn void DString.append_string(&self, DString str)

View File

@@ -32,17 +32,6 @@ fault NumberConversion
FLOAT_OUT_OF_RANGE,
}
/**
* Return a temporary String created using the formatting function.
*
* @param [in] fmt `The formatting string`
**/
macro String tformat(String fmt, ...)
{
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
str.appendf(fmt, $vasplat);
return str.str_view();
}
/**
* Return a temporary ZString created using the formatting function.
@@ -59,10 +48,10 @@ macro ZString tformat_zstr(String fmt, ...)
/**
* Return a new String created using the formatting function.
*
* @param [in] fmt `The formatting string`
* @param [inout] allocator `The allocator to use`
* @param [in] fmt `The formatting string`
**/
macro String new_format(String fmt, ..., Allocator allocator = allocator::heap())
macro String format(String fmt, ..., Allocator allocator)
{
@pool(allocator)
{
@@ -72,6 +61,25 @@ macro String new_format(String fmt, ..., Allocator allocator = allocator::heap()
};
}
/**
* Return a heap allocated String created using the formatting function.
*
* @param [in] fmt `The formatting string`
**/
macro String new_format(String fmt, ..., Allocator allocator = null) => format(fmt, $vasplat, .allocator = allocator ?: allocator::heap());
/**
* Return a temporary String created using the formatting function.
*
* @param [in] fmt `The formatting string`
**/
macro String tformat(String fmt, ...)
{
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
str.appendf(fmt, $vasplat);
return str.str_view();
}
/**
* Return a new ZString created using the formatting function.
*
@@ -205,13 +213,12 @@ fn String String.strip_end(string, String needle)
return string[:(string.len - needle.len)];
}
/**
* Split a string into parts, e.g "a|b|c" split with "|" yields { "a", "b", "c" }
*
* @param [in] s
* @param [in] needle
* @param [&inout] allocator "The allocator, defaults to the heap allocator"
* @param [&inout] allocator "The allocator to use for the String[]"
* @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
@@ -246,6 +253,18 @@ fn String[] String.split(s, String needle, usz max = 0, Allocator allocator = al
return holder[:i];
}
/**
* Split a string into parts, e.g "a|b|c" split with "|" yields { "a", "b", "c" }, using the heap allocator
* to store the parts.
*
* @param [in] s
* @param [in] needle
* @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.new_split(s, String needle, usz max = 0) => s.split(needle, max, allocator::heap()) @inline;
/**
* This function is identical to String.split, but implicitly uses the
* temporary allocator.
@@ -254,10 +273,7 @@ fn String[] String.split(s, String needle, usz max = 0, Allocator allocator = al
* @param [in] needle
* @param max "Max number of elements, 0 means no limit, defaults to 0"
**/
fn String[] String.tsplit(s, String needle, usz max = 0)
{
return s.split(needle, max, allocator::temp()) @inline;
}
fn String[] String.tsplit(s, String needle, usz max = 0) => s.split(needle, max, allocator::temp()) @inline;
/**
* Check if a substring is found in the string.
@@ -486,17 +502,15 @@ fn Char16[]! String.to_temp_utf16(s)
return s.to_new_utf16(allocator::temp());
}
fn WString! String.to_new_wstring(s, Allocator allocator = allocator::heap())
fn WString! String.to_wstring(s, Allocator allocator)
{
return (WString)s.to_new_utf16(allocator).ptr;
}
fn WString! String.to_temp_wstring(s)
{
return (WString)s.to_temp_utf16().ptr;
}
fn WString! String.to_temp_wstring(s) => s.to_wstring(allocator::temp());
fn WString! String.to_new_wstring(s) => s.to_wstring(allocator::heap());
fn Char32[]! String.to_new_utf32(s, Allocator allocator = allocator::heap())
fn Char32[]! String.to_utf32(s, Allocator allocator)
{
usz codepoints = conv::utf8_codepoints(s);
Char32* data = allocator::alloc_array_try(allocator, Char32, codepoints + 1)!;
@@ -505,10 +519,8 @@ fn Char32[]! String.to_new_utf32(s, Allocator allocator = allocator::heap())
return data[:codepoints];
}
fn Char32[]! String.to_temp_utf32(s)
{
return s.to_new_utf32(allocator::temp());
}
fn Char32[]! String.to_new_utf32(s) => s.to_utf32(allocator::heap()) @inline;
fn Char32[]! String.to_temp_utf32(s) => s.to_utf32(allocator::temp()) @inline;
/**
* Convert a string to ASCII lower case.

View File

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