mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
List no longer uses a temp allocator by default. Incorrect check in the temp allocator removed. Added DString.
This commit is contained in:
@@ -151,7 +151,7 @@ fn void List.reserve(List* list, usz min_capacity)
|
||||
{
|
||||
if (!min_capacity) return;
|
||||
if (list.capacity >= min_capacity) return;
|
||||
if (!list.allocator) list.allocator = mem::temp_allocator();
|
||||
if (!list.allocator) list.allocator = mem::current_allocator();
|
||||
min_capacity = math::next_power_of_2(min_capacity);
|
||||
list.entries = realloc_aligned(list.entries, Type.sizeof * min_capacity, .alignment = Type[1].alignof, .using = list.allocator) ?? null;
|
||||
list.capacity = min_capacity;
|
||||
|
||||
@@ -154,8 +154,6 @@ fn void*! TempAllocator._realloc(TempAllocator* this, void* pointer, usz size, u
|
||||
TempAllocatorPage *page = pointer - TempAllocatorPage.sizeof;
|
||||
return this._realloc_page(page, size, alignment, offset);
|
||||
}
|
||||
assert(pointer < &this.data + this.capacity && pointer >= &this.data, "This is not a temp allocated pointer.");
|
||||
assert(pointer < &this.data + this.used, "This is a stale temp pointer.");
|
||||
|
||||
// TODO optimize last allocation
|
||||
TempAllocatorChunk* data = this._alloc(size, alignment, offset, size > chunk.size)?;
|
||||
|
||||
368
lib/std/core/dstring.c3
Normal file
368
lib/std/core/dstring.c3
Normal file
@@ -0,0 +1,368 @@
|
||||
module std::core::dstring;
|
||||
|
||||
typedef DString = distinct void*;
|
||||
|
||||
const usz MIN_CAPACITY @private = 16;
|
||||
|
||||
fn DString new_with_capacity(usz capacity, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY;
|
||||
StringData* data = malloc(StringData, 1, .using = allocator, .end_padding = capacity);
|
||||
data.allocator = allocator;
|
||||
data.len = 0;
|
||||
data.capacity = capacity;
|
||||
return (DString)data;
|
||||
}
|
||||
|
||||
fn DString tnew_with_capacity(usz capacity) => new_with_capacity(capacity, mem::temp_allocator()) @inline;
|
||||
|
||||
fn DString new(String c = "", Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
usz len = c.len;
|
||||
StringData* data = (StringData*)new_with_capacity(len, allocator);
|
||||
if (len)
|
||||
{
|
||||
data.len = len;
|
||||
mem::copy(&data.chars, c.ptr, len);
|
||||
}
|
||||
return (DString)data;
|
||||
}
|
||||
|
||||
fn DString tnew(String s = "") => new(s, mem::temp_allocator()) @inline;
|
||||
|
||||
fn DString DString.new_concat(DString a, DString b, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
DString string = new_with_capacity(a.len() + b.len(), allocator);
|
||||
string.append(a);
|
||||
string.append(b);
|
||||
return string;
|
||||
}
|
||||
|
||||
fn DString DString.new_tconcat(DString a, DString b) => a.new_concat(b, mem::temp_allocator());
|
||||
|
||||
fn ZString DString.zstr(DString str)
|
||||
{
|
||||
StringData* data = str.data();
|
||||
if (!data) return (ZString)"";
|
||||
if (data.capacity == data.len)
|
||||
{
|
||||
str.reserve(1);
|
||||
data.chars[data.len] = 0;
|
||||
}
|
||||
else if (data.chars[data.len] != 0)
|
||||
{
|
||||
data.chars[data.len] = 0;
|
||||
}
|
||||
return (ZString)&data.chars[0];
|
||||
}
|
||||
|
||||
fn usz DString.capacity(DString this)
|
||||
{
|
||||
if (!this) return 0;
|
||||
return this.data().capacity;
|
||||
}
|
||||
|
||||
fn usz DString.len(DString this)
|
||||
{
|
||||
if (!this) return 0;
|
||||
return this.data().len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require new_size <= this.len()
|
||||
*/
|
||||
fn void DString.chop(DString this, usz new_size)
|
||||
{
|
||||
if (!this) return;
|
||||
this.data().len = new_size;
|
||||
}
|
||||
|
||||
fn String DString.str(DString str)
|
||||
{
|
||||
StringData* data = (StringData*)str;
|
||||
if (!data) return String {};
|
||||
return (String)data.chars[:data.len];
|
||||
}
|
||||
|
||||
fn void DString.append_utf32(DString* str, Char32[] chars)
|
||||
{
|
||||
str.reserve(chars.len);
|
||||
foreach (Char32 c : chars)
|
||||
{
|
||||
str.append_char32(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @require index < str.len()
|
||||
**/
|
||||
fn void DString.set(DString str, usz index, char c)
|
||||
{
|
||||
str.data().chars[index] = c;
|
||||
}
|
||||
|
||||
fn void DString.append_repeat(DString* str, char c, usz times)
|
||||
{
|
||||
if (times == 0) return;
|
||||
str.reserve(times);
|
||||
StringData* data = str.data();
|
||||
for (usz i = 0; i < times; i++)
|
||||
{
|
||||
data.chars[data.len++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @require c <= 0x10ffff
|
||||
*/
|
||||
fn void DString.append_char32(DString* str, Char32 c)
|
||||
{
|
||||
if (c < 0x7f)
|
||||
{
|
||||
str.reserve(1);
|
||||
StringData* data = str.data();
|
||||
data.chars[data.len++] = (char)c;
|
||||
return;
|
||||
}
|
||||
if (c < 0x7ff)
|
||||
{
|
||||
str.reserve(2);
|
||||
StringData* data = str.data();
|
||||
data.chars[data.len++] = (char)(0xC0 | c >> 6);
|
||||
data.chars[data.len++] = (char)(0x80 | (c & 0x3F));
|
||||
return;
|
||||
}
|
||||
if (c < 0xffff)
|
||||
{
|
||||
str.reserve(3);
|
||||
StringData* data = str.data();
|
||||
data.chars[data.len++] = (char)(0xE0 | c >> 12);
|
||||
data.chars[data.len++] = (char)(0x80 | (c >> 6 & 0x3F));
|
||||
data.chars[data.len++] = (char)(0x80 | (c & 0x3F));
|
||||
return;
|
||||
}
|
||||
str.reserve(4);
|
||||
StringData* data = str.data();
|
||||
data.chars[data.len++] = (char)(0xF0 | c >> 18);
|
||||
data.chars[data.len++] = (char)(0x80 | (c >> 12 & 0x3F));
|
||||
data.chars[data.len++] = (char)(0x80 | (c >> 6 & 0x3F));
|
||||
data.chars[data.len++] = (char)(0x80 | (c & 0x3F));
|
||||
}
|
||||
|
||||
fn DString DString.tcopy(DString* str) => str.copy(mem::temp_allocator());
|
||||
|
||||
fn DString DString.copy(DString* str, Allocator* allocator = null)
|
||||
{
|
||||
if (!str)
|
||||
{
|
||||
if (allocator) return new_with_capacity(0, allocator);
|
||||
return (DString)null;
|
||||
}
|
||||
if (!allocator) allocator = mem::current_allocator();
|
||||
StringData* data = str.data();
|
||||
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(DString* str, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
usz str_len = str.len();
|
||||
if (!str_len)
|
||||
{
|
||||
return (ZString)calloc(1, .using = allocator);
|
||||
}
|
||||
char* zstr = malloc(str_len + 1, .using = allocator);
|
||||
StringData* data = str.data();
|
||||
mem::copy(zstr, &data.chars, str_len);
|
||||
zstr[str_len] = 0;
|
||||
return (ZString)zstr;
|
||||
}
|
||||
|
||||
fn String DString.copy_str(DString* str, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
return (String)str.copy_zstr(allocator)[:str.len()];
|
||||
}
|
||||
|
||||
fn String DString.tcopy_str(DString* str) => str.copy_str(mem::temp_allocator()) @inline;
|
||||
|
||||
fn bool DString.equals(DString str, DString other_string)
|
||||
{
|
||||
StringData *str1 = str.data();
|
||||
StringData *str2 = other_string.data();
|
||||
if (str1 == str2) return true;
|
||||
if (!str1) return str2.len == 0;
|
||||
if (!str2) return str1.len == 0;
|
||||
usz str1_len = str1.len;
|
||||
if (str1_len != str2.len) return false;
|
||||
for (int i = 0; i < str1_len; i++)
|
||||
{
|
||||
if (str1.chars[i] != str2.chars[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn void DString.free(DString* str)
|
||||
{
|
||||
if (!*str) return;
|
||||
StringData* data = str.data();
|
||||
if (!data) return;
|
||||
free(data, .using = data.allocator);
|
||||
*str = (DString)null;
|
||||
}
|
||||
|
||||
fn bool DString.less(DString str, DString other_string)
|
||||
{
|
||||
StringData* str1 = str.data();
|
||||
StringData* str2 = other_string.data();
|
||||
if (str1 == str2) return false;
|
||||
if (!str1) return str2.len != 0;
|
||||
if (!str2) return str1.len == 0;
|
||||
usz str1_len = str1.len;
|
||||
usz str2_len = str2.len;
|
||||
if (str1_len != str2_len) return str1_len < str2_len;
|
||||
for (int i = 0; i < str1_len; i++)
|
||||
{
|
||||
if (str1.chars[i] >= str2.chars[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn void DString.append_chars(DString* this, String str)
|
||||
{
|
||||
usz other_len = str.len;
|
||||
if (!other_len) return;
|
||||
if (!*this)
|
||||
{
|
||||
*this = new(str);
|
||||
return;
|
||||
}
|
||||
this.reserve(other_len);
|
||||
StringData* data = (StringData*)*this;
|
||||
mem::copy(&data.chars[data.len], str.ptr, other_len);
|
||||
data.len += other_len;
|
||||
}
|
||||
|
||||
fn Char32[] DString.copy_utf32(DString* this, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
return str::utf8to32(this.str(), allocator) @inline!!;
|
||||
}
|
||||
|
||||
fn void DString.append_string(DString* this, DString str)
|
||||
{
|
||||
StringData* other = (StringData*)str;
|
||||
if (!other) return;
|
||||
this.append(str.str());
|
||||
}
|
||||
|
||||
fn void DString.clear(DString* str)
|
||||
{
|
||||
str.data().len = 0;
|
||||
}
|
||||
|
||||
fn void DString.append_char(DString* str, char c)
|
||||
{
|
||||
if (!*str)
|
||||
{
|
||||
*str = new_with_capacity(MIN_CAPACITY);
|
||||
}
|
||||
str.reserve(1);
|
||||
StringData* data = (StringData*)*str;
|
||||
data.chars[data.len++] = c;
|
||||
}
|
||||
|
||||
|
||||
macro void DString.append(DString* str, value)
|
||||
{
|
||||
var $Type = $typeof(value);
|
||||
$switch ($Type):
|
||||
$case char:
|
||||
$case ichar:
|
||||
str.append_char(value);
|
||||
$case DString:
|
||||
str.append_string(value);
|
||||
$case String:
|
||||
str.append_chars(value);
|
||||
$case Char32:
|
||||
str.append_char32(value);
|
||||
$default:
|
||||
$if (@convertible(value, Char32)):
|
||||
str.append_char32(value);
|
||||
$elif (@convertible(value, String)):
|
||||
str.append_chars(value);
|
||||
$else:
|
||||
$assert(false, "Unsupported type for append – use printf instead.");
|
||||
$endif;
|
||||
$endswitch;
|
||||
}
|
||||
|
||||
|
||||
fn usz! DString.printf(DString* str, String format, args...) @maydiscard
|
||||
{
|
||||
Formatter formatter;
|
||||
formatter.init(&out_string_append_fn, str);
|
||||
return formatter.vprintf(format, args);
|
||||
}
|
||||
|
||||
fn usz! DString.printfn(DString* str, String format, args...) @maydiscard
|
||||
{
|
||||
Formatter formatter;
|
||||
formatter.init(&out_string_append_fn, str);
|
||||
usz len = formatter.vprintf(format, args)?;
|
||||
str.append('\n');
|
||||
return len + 1;
|
||||
}
|
||||
|
||||
fn DString new_join(String[] s, String joiner, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
if (!s.len) return (DString)null;
|
||||
usz total_size = joiner.len * s.len;
|
||||
foreach (String* &str : s)
|
||||
{
|
||||
total_size += str.len;
|
||||
}
|
||||
DString res = new_with_capacity(total_size, allocator);
|
||||
res.append(s[0]);
|
||||
foreach (String* &str : s[1..])
|
||||
{
|
||||
res.append(joiner);
|
||||
res.append(*str);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
fn void! out_string_append_fn(char c, void* data) @private
|
||||
{
|
||||
DynString* s = data;
|
||||
s.append_char(c);
|
||||
}
|
||||
|
||||
|
||||
fn StringData* DString.data(DString str) @inline @private
|
||||
{
|
||||
return (StringData*)str;
|
||||
}
|
||||
|
||||
fn void DString.reserve(DString* str, usz addition) @private
|
||||
{
|
||||
StringData* data = str.data();
|
||||
if (!data)
|
||||
{
|
||||
*str = dstring::new_with_capacity(addition);
|
||||
return;
|
||||
}
|
||||
usz len = data.len + addition;
|
||||
if (data.capacity >= len) return;
|
||||
usz new_capacity = data.capacity *= 2;
|
||||
if (new_capacity < MIN_CAPACITY) new_capacity = MIN_CAPACITY;
|
||||
*str = (DString)realloc(data, StringData.sizeof + new_capacity, .using = data.allocator);
|
||||
}
|
||||
|
||||
|
||||
struct StringData @private
|
||||
{
|
||||
Allocator* allocator;
|
||||
usz len;
|
||||
usz capacity;
|
||||
char[*] chars;
|
||||
}
|
||||
@@ -22,6 +22,7 @@ fault NumberConversion
|
||||
MALFORMED_FLOAT,
|
||||
FLOAT_OUT_OF_RANGE,
|
||||
}
|
||||
|
||||
fn VarString join(String[] s, String joiner)
|
||||
{
|
||||
if (!s.len) return (VarString)null;
|
||||
@@ -335,7 +336,7 @@ fn String! utf16to8(Char16[] utf16, Allocator* allocator = mem::current_allocato
|
||||
return data[:len];
|
||||
}
|
||||
|
||||
fn String copy(String s, Allocator* allocator = mem::current_allocator())
|
||||
fn String copy(String s, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
usz len = s.len;
|
||||
ZString str_copy = copy_zstring(s, allocator) @inline;
|
||||
|
||||
@@ -4,7 +4,6 @@ import libc;
|
||||
typedef VarString = distinct void*;
|
||||
typedef DynStr = VarString;
|
||||
typedef DynString = VarString;
|
||||
typedef DString = VarString;
|
||||
typedef VString = VarString;
|
||||
typedef Text = VarString;
|
||||
|
||||
|
||||
@@ -57,6 +57,8 @@ macro void print(x)
|
||||
catch(stdout().print(x));
|
||||
$case ZString:
|
||||
catch(stdout().print(x.as_str()));
|
||||
$case DString:
|
||||
catch(stdout().print(x.str()));
|
||||
$case VarString:
|
||||
catch(stdout().print(x.str()));
|
||||
$default:
|
||||
@@ -76,6 +78,8 @@ macro void printn(x = "")
|
||||
catch(stdout().printn(x));
|
||||
$case ZString:
|
||||
catch(stdout().printn(x.as_str()));
|
||||
$case DString:
|
||||
catch(stdout().printn(x.str()));
|
||||
$case VarString:
|
||||
catch(stdout().printn(x.str()));
|
||||
$default:
|
||||
|
||||
@@ -131,9 +131,9 @@ fn usz! File.println(File file, String string) => file.printn(string);
|
||||
* @param [&in] file
|
||||
* @require file.file `File must be initialized`
|
||||
*/
|
||||
fn VarString File.getline(File* file, Allocator* allocator = mem::current_allocator())
|
||||
fn DString File.getline(File* file, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
VarString s = string::new_with_capacity(120, allocator);
|
||||
DString s = dstring::new_with_capacity(120, allocator);
|
||||
while (!file.eof())
|
||||
{
|
||||
int c = libc::fgetc(file.file);
|
||||
|
||||
@@ -236,6 +236,10 @@ fn void! Formatter.out_str(Formatter* this, variant arg) @private
|
||||
{
|
||||
return this.out_substr(((VarString*)arg).str());
|
||||
}
|
||||
if (arg.type == DString.typeid)
|
||||
{
|
||||
return this.out_substr(((DString*)arg).str());
|
||||
}
|
||||
return this.out_str(variant { arg.ptr, arg.type.inner });
|
||||
case POINTER:
|
||||
if (this.print_with_function(arg)?) return;
|
||||
|
||||
Reference in New Issue
Block a user