mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
fix Object.free (#982)
* lib/std/collections: add HashMap.@each_entry()
* lib/std/json: fix Object.free() when object is a map
* lib/std/collections: fix allocator use in Object.{set,set_at,append}
* lib/std: add char.from_hex
* lib/std/collections: print arrays and objects compactly
* lib/std/io: fix Formatter.vprintf result
* lib/std/io/stream: rename module for ByteBuffer
* lib/std/io/stream: make Scanner a Stream reader
* lib/std/io: make std{in,err,out} return File* if no libc
This commit is contained in:
@@ -53,6 +53,10 @@ fn bool char.is_blank(char c) => is_blank_m(c);
|
||||
fn bool char.is_cntrl(char c) => is_cntrl_m(c);
|
||||
fn char char.to_lower(char c) => (char)to_lower_m(c);
|
||||
fn char char.to_upper(char c) => (char)to_upper_m(c);
|
||||
/**
|
||||
* @require c.is_xdigit()
|
||||
**/
|
||||
fn char char.from_hex(char c) => c.is_digit() ? c - '0' : 10 + (c | 0x20) - 'a';
|
||||
|
||||
fn bool uint.in_range(uint c, uint start, uint len) => in_range_m(c, start, len);
|
||||
fn bool uint.is_lower(uint c) => is_lower_m(c);
|
||||
|
||||
@@ -209,6 +209,13 @@ fn Key[] HashMap.key_list(&map, Allocator* using = mem::heap())
|
||||
}
|
||||
|
||||
macro HashMap.@each(map; @body(key, value))
|
||||
{
|
||||
map.@each_entry(; Entry* entry) {
|
||||
@body(entry.key, entry.value);
|
||||
};
|
||||
}
|
||||
|
||||
macro HashMap.@each_entry(map; @body(entry))
|
||||
{
|
||||
if (map.count)
|
||||
{
|
||||
@@ -216,7 +223,7 @@ macro HashMap.@each(map; @body(key, value))
|
||||
{
|
||||
while (entry)
|
||||
{
|
||||
@body(entry.key, entry.value);
|
||||
@body(entry);
|
||||
entry = entry.next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,10 +43,10 @@ fn usz! Object.to_format(&self, Formatter* formatter) @dynamic
|
||||
usz n = formatter.printf("[")!;
|
||||
foreach (i, ol : self.array)
|
||||
{
|
||||
n += formatter.printf(i == 0 ? " " : ", ")!;
|
||||
if (i > 0) n += formatter.printf(",")!;
|
||||
n += ol.to_format(formatter)!;
|
||||
}
|
||||
n += formatter.printf(" ]")!;
|
||||
n += formatter.printf("]")!;
|
||||
return n;
|
||||
case ObjectInternalMap:
|
||||
usz n = formatter.printf("{")!;
|
||||
@@ -54,12 +54,12 @@ fn usz! Object.to_format(&self, Formatter* formatter) @dynamic
|
||||
{
|
||||
foreach (i, key : self.map.key_tlist())
|
||||
{
|
||||
n += formatter.printf(i == 0 ? " " : ", ")!;
|
||||
n += formatter.printf(`"%s": `, key)!;
|
||||
if (i > 0) n += formatter.printf(",")!;
|
||||
n += formatter.printf(`"%s":`, key)!;
|
||||
n += self.map.get(key).to_format(formatter)!;
|
||||
}
|
||||
};
|
||||
n += formatter.printf(" }")!;
|
||||
n += formatter.printf("}")!;
|
||||
return n;
|
||||
default:
|
||||
switch (self.type.kindof)
|
||||
@@ -104,7 +104,7 @@ macro Object* new_enum(e, Allocator* using = mem::heap())
|
||||
return o;
|
||||
}
|
||||
|
||||
fn Object* new_float(double f, Allocator* using = mem::current_allocator())
|
||||
fn Object* new_float(double f, Allocator* using = mem::heap())
|
||||
{
|
||||
Object* o = malloc(Object, .using = using);
|
||||
*o = { .f = f, .allocator = using, .type = double.typeid };
|
||||
@@ -139,14 +139,9 @@ fn void Object.free(&self)
|
||||
}
|
||||
self.array.free();
|
||||
case ObjectInternalMap:
|
||||
@pool()
|
||||
{
|
||||
foreach (key : self.map.key_tlist())
|
||||
{
|
||||
(void)self.map.get(key).free();
|
||||
free(key, .using = self.allocator);
|
||||
}
|
||||
self.map.free();
|
||||
self.map.@each_entry(; ObjectInternalMapEntry* entry) {
|
||||
free(entry.key, .using = self.allocator);
|
||||
entry.value.free();
|
||||
};
|
||||
default:
|
||||
break;
|
||||
@@ -204,17 +199,17 @@ fn void Object.set_object(&self, String key, Object* new_object) @private
|
||||
self.map.set(key.copy(self.map.allocator), new_object);
|
||||
}
|
||||
|
||||
macro Object* object_from_value(value) @private
|
||||
macro Object* Object.object_from_value(&self, value) @private
|
||||
{
|
||||
var $Type = $typeof(value);
|
||||
|
||||
$switch
|
||||
$case types::is_int($Type):
|
||||
return new_int(value);
|
||||
return new_int(value, self.allocator);
|
||||
$case types::is_float($Type):
|
||||
return new_float(value);
|
||||
return new_float(value, self.allocator);
|
||||
$case $Type.typeid == String.typeid:
|
||||
return new_string(value);
|
||||
return new_string(value, self.allocator);
|
||||
$case $Type.typeid == bool.typeid:
|
||||
return new_bool(value);
|
||||
$case $Type.typeid == Object*.typeid:
|
||||
@@ -223,7 +218,7 @@ macro Object* object_from_value(value) @private
|
||||
if (value != null) return CastResult.TYPE_MISMATCH?;
|
||||
return &NULL_OBJECT;
|
||||
$case $checks(String s = value):
|
||||
return new_string(value);
|
||||
return new_string(value, self.allocator);
|
||||
$default:
|
||||
$error "Unsupported object type.";
|
||||
$endswitch
|
||||
@@ -232,7 +227,7 @@ macro Object* object_from_value(value) @private
|
||||
|
||||
macro Object* Object.set(&self, String key, value)
|
||||
{
|
||||
Object* val = object_from_value(value);
|
||||
Object* val = self.object_from_value(value);
|
||||
self.set_object(key, val);
|
||||
return val;
|
||||
}
|
||||
@@ -242,7 +237,7 @@ macro Object* Object.set(&self, String key, value)
|
||||
**/
|
||||
macro Object* Object.set_at(&self, usz index, String key, value)
|
||||
{
|
||||
Object* val = object_from_value(value);
|
||||
Object* val = self.object_from_value(value);
|
||||
self.set_object_at(key, index, val);
|
||||
return val;
|
||||
}
|
||||
@@ -253,7 +248,7 @@ macro Object* Object.set_at(&self, usz index, String key, value)
|
||||
**/
|
||||
macro Object* Object.append(&self, value)
|
||||
{
|
||||
Object* val = object_from_value(value);
|
||||
Object* val = self.object_from_value(value);
|
||||
self.append_object(val);
|
||||
return val;
|
||||
}
|
||||
@@ -477,7 +472,7 @@ fn double! Object.get_float_at(&self, usz index)
|
||||
fn Object* Object.get_or_create_obj(&self, String key)
|
||||
{
|
||||
if (try obj = self.get(key) && !obj.is_null()) return obj;
|
||||
Object* container = new_obj();
|
||||
Object* container = new_obj(self.allocator);
|
||||
self.set(key, container);
|
||||
return container;
|
||||
}
|
||||
|
||||
@@ -293,6 +293,7 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
|
||||
// use null output function
|
||||
self.out_fn = &out_null_fn;
|
||||
}
|
||||
usz total_len;
|
||||
usz format_len = format.len;
|
||||
usz variant_index = 0;
|
||||
for (usz i = 0; i < format_len; i++)
|
||||
@@ -302,7 +303,7 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
|
||||
if (c != '%')
|
||||
{
|
||||
// no
|
||||
self.out(c)!;
|
||||
total_len += self.out(c)!;
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
@@ -310,7 +311,7 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
|
||||
c = format[i];
|
||||
if (c == '%')
|
||||
{
|
||||
self.out(c)!;
|
||||
total_len += self.out(c)!;
|
||||
continue;
|
||||
}
|
||||
// evaluate flags
|
||||
@@ -377,42 +378,43 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
|
||||
self.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'a':
|
||||
self.atoa(float_from_any(current)!!)!;
|
||||
total_len += self.atoa(float_from_any(current)!!)!;
|
||||
continue;
|
||||
case 'F' :
|
||||
self.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'f':
|
||||
self.ftoa(float_from_any(current)!!)!;
|
||||
total_len += self.ftoa(float_from_any(current)!!)!;
|
||||
continue;
|
||||
case 'E':
|
||||
self.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'e':
|
||||
self.etoa(float_from_any(current)!!)!;
|
||||
total_len += self.etoa(float_from_any(current)!!)!;
|
||||
continue;
|
||||
case 'G':
|
||||
self.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'g':
|
||||
self.gtoa(float_from_any(current)!!)!;
|
||||
total_len += self.gtoa(float_from_any(current)!!)!;
|
||||
continue;
|
||||
case 'c':
|
||||
self.out_char(current)!;
|
||||
total_len += self.out_char(current)!;
|
||||
continue;
|
||||
case 's':
|
||||
if (self.flags.left)
|
||||
{
|
||||
usz len = self.out_str(current)!;
|
||||
self.pad(' ', self.width, len)!;
|
||||
total_len += len;
|
||||
total_len += self.pad(' ', self.width, len)!;
|
||||
continue;
|
||||
}
|
||||
OutputFn out_fn = self.out_fn;
|
||||
self.out_fn = (OutputFn)&out_null_fn;
|
||||
usz len = self.out_str(current)!;
|
||||
self.out_fn = out_fn;
|
||||
self.pad(' ', self.width, len)!;
|
||||
self.out_str(current)!;
|
||||
total_len += self.pad(' ', self.width, len)!;
|
||||
total_len += self.out_str(current)!;
|
||||
continue;
|
||||
case 'p':
|
||||
self.flags.zeropad = true;
|
||||
@@ -432,13 +434,13 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
|
||||
bool is_neg;
|
||||
uint128 v = int_from_any(current, &is_neg)!!;
|
||||
|
||||
self.ntoa(v, is_neg, base)!;
|
||||
total_len += self.ntoa(v, is_neg, base)!;
|
||||
}
|
||||
// termination
|
||||
// out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
|
||||
|
||||
// return written chars without terminating \0
|
||||
return self.idx;
|
||||
return total_len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -141,17 +141,17 @@ fn void putchar(char c) @inline
|
||||
(void)stdout_file.putc(c);
|
||||
}
|
||||
|
||||
fn File stdout()
|
||||
fn File* stdout()
|
||||
{
|
||||
return stdout_file;
|
||||
return &stdout_file;
|
||||
}
|
||||
|
||||
fn File stderr()
|
||||
fn File* stderr()
|
||||
{
|
||||
return stderr_file;
|
||||
return &stderr_file;
|
||||
}
|
||||
|
||||
fn File stdin()
|
||||
fn File* stdin()
|
||||
{
|
||||
return stdin_file;
|
||||
return &stdin_file;
|
||||
}
|
||||
|
||||
@@ -30,9 +30,19 @@ fn ByteBuffer*! ByteBuffer.tinit(&self, usz max_read, usz initial_capacity = 16)
|
||||
return self.init(max_read, initial_capacity, mem::temp())!;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require buf.len > 0
|
||||
* @require self.bytes.len == 0 "Buffer already initialized."
|
||||
**/
|
||||
fn ByteBuffer*! ByteBuffer.init_with_buffer(&self, char[] buf)
|
||||
{
|
||||
*self = { .stream.fns = &BYTEBUFFER_INTERFACE, .max_read = buf.len, .bytes = buf };
|
||||
return self;
|
||||
}
|
||||
|
||||
fn void! ByteBuffer.free(&self)
|
||||
{
|
||||
self.allocator.free(self.bytes)!;
|
||||
if (self.allocator) self.allocator.free(self.bytes)!;
|
||||
*self = {};
|
||||
}
|
||||
|
||||
@@ -104,6 +114,23 @@ fn void! ByteBuffer.pushback_byte(&self)
|
||||
self.has_last = false;
|
||||
}
|
||||
|
||||
fn void! ByteBuffer.seek(&self, isz offset, Seek seek)
|
||||
{
|
||||
switch (seek)
|
||||
{
|
||||
case SET:
|
||||
if (offset < 0 || offset > self.write_idx) return IoError.INVALID_POSITION?;
|
||||
self.read_idx = offset;
|
||||
case CURSOR:
|
||||
if ((offset < 0 && self.read_idx < -offset) ||
|
||||
(offset > 0 && self.read_idx + offset > self.write_idx)) return IoError.INVALID_POSITION?;
|
||||
self.read_idx += offset;
|
||||
case END:
|
||||
if (offset < 0 || offset > self.write_idx) return IoError.INVALID_POSITION?;
|
||||
self.read_idx = self.write_idx - offset;
|
||||
}
|
||||
}
|
||||
|
||||
fn usz! ByteBuffer.available(&self) @inline
|
||||
{
|
||||
return self.write_idx - self.read_idx;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::io::stream;
|
||||
module std::io;
|
||||
|
||||
struct LimitReader
|
||||
{
|
||||
|
||||
@@ -2,7 +2,8 @@ module std::io;
|
||||
|
||||
struct Scanner
|
||||
{
|
||||
Stream* stream;
|
||||
inline Stream stream;
|
||||
Stream* wrapped_stream;
|
||||
char[] buf;
|
||||
usz pattern_idx;
|
||||
usz read_idx;
|
||||
@@ -20,9 +21,14 @@ struct Scanner
|
||||
**/
|
||||
fn void Scanner.init(&self, Stream* stream, char[] buffer)
|
||||
{
|
||||
*self = { .stream = stream, .buf = buffer };
|
||||
*self = { .stream.fns = &SCANNER_INTERFACE, .wrapped_stream = stream, .buf = buffer };
|
||||
}
|
||||
|
||||
const StreamInterface SCANNER_INTERFACE = {
|
||||
.read_fn = (ReadStreamFn)&Scanner.read,
|
||||
.read_byte_fn = (ReadByteStreamFn)&Scanner.read_byte,
|
||||
};
|
||||
|
||||
/**
|
||||
* Return and clear any remaining unscanned data.
|
||||
**/
|
||||
@@ -85,7 +91,7 @@ macro usz! Scanner.find(&self, buf, pattern) @private
|
||||
|
||||
macro usz! Scanner.refill(&self, buf) @private
|
||||
{
|
||||
usz! n = self.stream.read(buf);
|
||||
usz! n = self.wrapped_stream.read(buf);
|
||||
if (catch err = n)
|
||||
{
|
||||
case IoError.EOF:
|
||||
@@ -94,4 +100,27 @@ macro usz! Scanner.refill(&self, buf) @private
|
||||
return err?;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
fn usz! Scanner.read(&self, char[] bytes)
|
||||
{
|
||||
usz n;
|
||||
if (self.pattern_idx < self.read_idx)
|
||||
{
|
||||
n = min(bytes.len, self.read_idx - self.pattern_idx);
|
||||
bytes[:n] = self.buf[self.pattern_idx:n];
|
||||
self.pattern_idx += n;
|
||||
bytes = bytes[n..];
|
||||
}
|
||||
n += self.wrapped_stream.read(bytes)!;
|
||||
return n;
|
||||
}
|
||||
|
||||
fn char! Scanner.read_byte(&self)
|
||||
{
|
||||
if (self.pattern_idx < self.read_idx)
|
||||
{
|
||||
return self.buf[self.pattern_idx++];
|
||||
}
|
||||
return self.wrapped_stream.read_byte();
|
||||
}
|
||||
Reference in New Issue
Block a user