Add experimental support for tables of pointers#35
Add experimental support for tables of pointers#35rexim wants to merge 2 commits intorluba:masterfrom
Conversation
Tries to address rluba#15 Example: ```jai main :: () { json_string := "{\"foo\": 69, \"bar\": 420}"; success, json := json_parse_string(json_string, Table(string, *int)); if !success exit(69); for json { print("% => %\n", it_index, it.*); } } #import "jaison"; ``` Why Tables of Pointers only: Currently all the `Type_Info` handling is happening at Runtime. But supporting Tables of Values that differ in size requires polymorphing such operations as `table_add()` which means we need to know the `Type_Info`-s at compile time. Until the type.jai is refactored to pass all the necessary `Type_Info` with `$` we can only offer that. Unless I'm missing something. Please let me know if I do. If I get a spare minute in the foreseeable future, I can spend it on doing the refactoring to bring the support for more Table kinds, but if somebody else wants to tuckle it I won't mind it. Please let me know if you want me to make any changes to the patch. Thank you for making this very useful library!
Since Table is a .STRUCT anyway expecting a .STRUCT when encountring a JSON object should work out well in this case.
|
I posted this on X but it's probably better here: If your issue is finding the size+type of the table value at runtime, you can do this: #import "Hash_Table";
test :: ($T: Type) {
val_ti := type_info(T.Value_Type);
print("Table value type info = %\n", val_ti.*);
}
test(Table(string, s16));This works because |
Thank you for the suggestion! The problem is actually that we need to know it at compile time. Otherwise we can't polymorph the |
Ah I see, sorry for the confusion. A slight modification of your code makes it work for both pointers and non-pointers: parse_object_as_table_of_pointers :: (str: string, slot: *u8, $T: Type, value_info: *Type_Info, ignore_unknown: bool, rename: Rename_Proc, float_handling: Special_Float_Handling) -> remainder: string, success: bool {
assert(str[0] == #char "{", "Invalid object start %", str);
remainder := advance(str);
remainder = trim_left(remainder, WHITESPACE_CHARS);
if !remainder return "", false;
if remainder[0] == #char "}" {
remainder = advance(remainder);
return remainder, true;
}
IS_TABLE :: #run begins_with(tprint("%", T), "Table(");
IS_POINTER_VALUE_TYPE :: #run -> bool {
#if IS_TABLE {
return type_info(T.Value_Type).type == .POINTER;
}
return false;
};
#if IS_TABLE {
table := cast(*Table(string, T.Value_Type))slot;
while true {
if !remainder || remainder[0] != #char "\"" return remainder, false;
key: string;
success: bool;
key, remainder, success = parse_string(remainder);
if !success return remainder, false;
defer free(key);
remainder = trim_left(remainder, WHITESPACE_CHARS);
if !remainder || remainder[0] != #char ":" return remainder, false;
remainder = advance(remainder);
#if IS_POINTER_VALUE_TYPE {
member_info := value_info.(*Type_Info_Pointer).pointer_to;
member_slot := NewArray(member_info.runtime_size, u8).data;
remainder, success = parse_value(remainder, member_slot, T, member_info, ignore_unknown, key, rename, float_handling=float_handling);
if !success return remainder, false;
table_add(table, copy_string(key), member_slot.(T.Value_Type));
} else {
member_info := value_info;
member_slot: T.Value_Type;
remainder, success = parse_value(remainder, (*member_slot).(*u8), T, member_info, ignore_unknown, key, rename, float_handling=float_handling);
if !success return remainder, false;
table_add(table, copy_string(key), member_slot);
}
remainder = trim_left(remainder, WHITESPACE_CHARS);
if !remainder || remainder[0] != #char "," break;
remainder = advance(remainder);
remainder = trim_left(remainder, WHITESPACE_CHARS);
}
if !remainder || remainder[0] != #char "}" return remainder, false;
remainder = advance(remainder);
return remainder, true;
} else {
// Should never happen
return "", false;
}
}Of course the only requirement is that Notes:
|
|
@bloeys please submit an actual patch to https://github.com/tsoding/jaison to the branch |
There was a problem hiding this comment.
Thank you for the PR, oh famous Rexim!
- I would suggest extending
examples/example.jaito also use tables (preferably somewhere nested). I use the examples as a regression test, so adding things there avoids that I break them in the future. - Since things have evolved quite a bit in your fork, I’ll wait with merging until things have been resolved there. Or do you disagree?
| if it.name == "Value_Type" { | ||
| if (it.type.type == .TYPE) { | ||
| value_info := (cast(**Type_Info)(struct_info.constant_storage.data + it.offset_into_constant_storage)).*; | ||
| if value_info.type != .POINTER return null; |
There was a problem hiding this comment.
I would suggest logging an error or even asserting here. (We can’t deserialize into any other Table types, so passing them would be an error, no?
Tries to address #15
Example:
Why Tables of Pointers only:
Currently all the
Type_Infohandling is happening at Runtime. But supporting Tables of Values that differ in size requires polymorphing such operations astable_add()which means we need to know theType_Info-s at compile time. Until the type.jai is refactored to pass all the necessaryType_Infowith$we can only offer that.Unless I'm missing something. Please let me know if I do.
If I get a spare minute in the foreseeable future, I can spend it on doing the refactoring to bring the support for more Table kinds, but if somebody else wants to tackle it I won't mind it.
Please let me know if you want me to make any changes to the patch.
Thank you for making this very useful library!