mirror of
https://github.com/odin-lang/Odin.git
synced 2026-07-29 18:37:47 +00:00
Merge pull request #6406 from odin-lang/bill/fixed-capacity-dynamic-array
Fixed Capacity Dynamic Arrays
This commit is contained in:
@@ -285,6 +285,32 @@ _marshal_into_encoder :: proc(e: Encoder, v: any, ti: ^runtime.Type_Info) -> (er
|
||||
}
|
||||
return
|
||||
|
||||
|
||||
case runtime.Type_Info_Fixed_Capacity_Dynamic_Array:
|
||||
array_data := uintptr(v.data)
|
||||
array_len := (^int)(array_data + info.len_offset)^
|
||||
if info.elem.id == byte {
|
||||
raw := runtime.Raw_Slice{v.data, array_len}
|
||||
return err_conv(_encode_bytes(e, transmute([]byte)raw))
|
||||
}
|
||||
|
||||
err_conv(_encode_u64(e, u64(array_len), .Array)) or_return
|
||||
|
||||
if impl, ok := _tag_implementations_type[info.elem.id]; ok {
|
||||
for i in 0..<array_len {
|
||||
data := array_data + uintptr(i*info.elem_size)
|
||||
impl->marshal(e, any{rawptr(data), info.elem.id}) or_return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
elem_ti := runtime.type_info_core(type_info_of(info.elem.id))
|
||||
for i in 0..<array_len {
|
||||
data := array_data + uintptr(i*info.elem_size)
|
||||
_marshal_into_encoder(e, any{rawptr(data), info.elem.id}, elem_ti) or_return
|
||||
}
|
||||
return
|
||||
|
||||
case runtime.Type_Info_Slice:
|
||||
if info.elem.id == byte {
|
||||
raw := (^[]byte)(v.data)
|
||||
|
||||
@@ -389,6 +389,23 @@ _unmarshal_bytes :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
|
||||
n := copy(slice, bytes)
|
||||
assert(n == len(bytes))
|
||||
return
|
||||
|
||||
case reflect.Type_Info_Fixed_Capacity_Dynamic_Array:
|
||||
elem_base := reflect.type_info_base(t.elem)
|
||||
|
||||
if elem_base.id != byte { return _unsupported(v, hdr) }
|
||||
|
||||
bytes := err_conv(_decode_bytes(d, add, allocator=context.temp_allocator)) or_return
|
||||
defer delete(bytes, context.temp_allocator)
|
||||
|
||||
if len(bytes) > t.capacity { return _unsupported(v, hdr) }
|
||||
|
||||
// Copy into array type, delete original.
|
||||
slice := ([^]byte)(v.data)[:len(bytes)]
|
||||
n := copy(slice, bytes)
|
||||
assert(n == len(bytes))
|
||||
(^int)(uintptr(v.data) + t.len_offset)^ = n
|
||||
return
|
||||
}
|
||||
|
||||
return _unsupported(v, hdr)
|
||||
@@ -553,6 +570,21 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
|
||||
if out_of_space { return _unsupported(v, hdr) }
|
||||
return
|
||||
|
||||
case reflect.Type_Info_Fixed_Capacity_Dynamic_Array:
|
||||
length, _ := err_conv(_decode_len_container(d, add)) or_return
|
||||
if length > t.capacity {
|
||||
return _unsupported(v, hdr)
|
||||
}
|
||||
|
||||
da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, length, allocator }
|
||||
|
||||
out_of_space := assign_array(d, &da, t.elem, length, growable=false) or_return
|
||||
if out_of_space { return _unsupported(v, hdr) }
|
||||
|
||||
(^int)(uintptr(v.data) + t.len_offset)^ = length
|
||||
|
||||
return
|
||||
|
||||
case reflect.Type_Info_Complex:
|
||||
length, _ := err_conv(_decode_len_container(d, add)) or_return
|
||||
if length > 2 {
|
||||
|
||||
@@ -320,6 +320,16 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
|
||||
}
|
||||
opt_write_end(w, opt, ']') or_return
|
||||
|
||||
case runtime.Type_Info_Fixed_Capacity_Dynamic_Array:
|
||||
opt_write_start(w, opt, '[') or_return
|
||||
len := (^int)(uintptr(v.data) + info.len_offset)^
|
||||
for i in 0..<len {
|
||||
opt_write_iteration(w, opt, i == 0) or_return
|
||||
data := uintptr(v.data) + uintptr(i*info.elem_size)
|
||||
marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
|
||||
}
|
||||
opt_write_end(w, opt, ']') or_return
|
||||
|
||||
case runtime.Type_Info_Slice:
|
||||
opt_write_start(w, opt, '[') or_return
|
||||
slice := cast(^mem.Raw_Slice)v.data
|
||||
|
||||
@@ -3246,6 +3246,21 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
}
|
||||
fmt_array(fi, ptr, n, info.elem_size, info.elem, verb)
|
||||
|
||||
|
||||
case runtime.Type_Info_Fixed_Capacity_Dynamic_Array:
|
||||
n := (^int)(uintptr(v.data) + info.len_offset)^
|
||||
|
||||
ptr := v.data // data is stored at the start
|
||||
if ol, ok := fi.optional_len.?; ok {
|
||||
fi.optional_len = nil
|
||||
n = min(n, ol)
|
||||
} else if fi.use_nul_termination {
|
||||
fi.use_nul_termination = false
|
||||
fmt_array_nul_terminated(fi, ptr, n, info.elem_size, info.elem, verb)
|
||||
return
|
||||
}
|
||||
fmt_array(fi, ptr, n, info.elem_size, info.elem, verb)
|
||||
|
||||
case runtime.Type_Info_Simd_Vector:
|
||||
io.write_byte(fi.writer, '<', &fi.n)
|
||||
defer io.write_byte(fi.writer, '>', &fi.n)
|
||||
|
||||
@@ -11,7 +11,6 @@ import "core:strings"
|
||||
import "core:sys/posix"
|
||||
import "core:time"
|
||||
import kq "core:sys/kqueue"
|
||||
import sa "core:container/small_array"
|
||||
|
||||
@(private="package")
|
||||
_FULLY_SUPPORTED :: true
|
||||
@@ -23,7 +22,7 @@ _Event_Loop :: struct {
|
||||
// that would be the same (ident, filter) pair we need to bundle the operations under one kevent.
|
||||
submitted: map[Queue_Identifier]^Operation,
|
||||
// Holds all events we want to flush. Flushing is done each tick at which point this is emptied.
|
||||
pending: sa.Small_Array(QUEUE_SIZE, kq.KEvent),
|
||||
pending: [dynamic; QUEUE_SIZE]kq.KEvent,
|
||||
// Holds what should be in `pending` but didn't fit.
|
||||
// When `pending`is flushed these are moved to `pending`.
|
||||
overflow: queue.Queue(kq.KEvent),
|
||||
@@ -116,7 +115,7 @@ _init :: proc(l: ^Event_Loop, allocator: mem.Allocator) -> (rerr: General_Error)
|
||||
|
||||
l.kqueue = kqueue
|
||||
|
||||
sa.append(&l.pending, kq.KEvent{
|
||||
append(&l.pending, kq.KEvent{
|
||||
ident = IDENT_WAKE_UP,
|
||||
filter = .User,
|
||||
flags = {.Add, .Enable, .Clear},
|
||||
@@ -150,7 +149,7 @@ __tick :: proc(l: ^Event_Loop, timeout: time.Duration) -> General_Error {
|
||||
}
|
||||
|
||||
if NBIO_DEBUG {
|
||||
npending := sa.len(l.pending)
|
||||
npending := len(l.pending)
|
||||
if npending > 0 {
|
||||
debug("queueing", npending, "new events, there are", int(len(l.submitted)), "events pending")
|
||||
} else {
|
||||
@@ -177,9 +176,9 @@ __tick :: proc(l: ^Event_Loop, timeout: time.Duration) -> General_Error {
|
||||
results_buf: [128]kq.KEvent
|
||||
results := kevent(l, results_buf[:], ts_pointer) or_return
|
||||
|
||||
sa.clear(&l.pending)
|
||||
clear(&l.pending)
|
||||
for overflow in queue.pop_front_safe(&l.overflow) {
|
||||
sa.append(&l.pending, overflow) or_break
|
||||
(append(&l.pending, overflow) != 0) or_break
|
||||
}
|
||||
|
||||
l.now = time.now()
|
||||
@@ -202,7 +201,7 @@ __tick :: proc(l: ^Event_Loop, timeout: time.Duration) -> General_Error {
|
||||
|
||||
kevent :: proc(l: ^Event_Loop, buf: []kq.KEvent, ts: ^posix.timespec) -> ([]kq.KEvent, General_Error) {
|
||||
for {
|
||||
new_events, err := kq.kevent(l.kqueue, sa.slice(&l.pending), buf, ts)
|
||||
new_events, err := kq.kevent(l.kqueue, l.pending[:], buf, ts)
|
||||
#partial switch err {
|
||||
case nil:
|
||||
assert(new_events >= 0)
|
||||
@@ -1188,7 +1187,7 @@ add_pending :: proc(op: ^Operation, filter: kq.Filter, ident: uintptr) {
|
||||
}
|
||||
|
||||
append_pending :: #force_inline proc(l: ^Event_Loop, ev: kq.KEvent) {
|
||||
if !sa.append(&l.pending, ev) {
|
||||
if append(&l.pending, ev) == 0 {
|
||||
warn("queue is full, adding to overflow, should QUEUE_SIZE be increased?")
|
||||
_, err := queue.append(&l.overflow, ev)
|
||||
ensure(err == nil, "allocation failure")
|
||||
@@ -1325,7 +1324,7 @@ timeout_and_delete :: proc(target: ^Operation) {
|
||||
flags = {.Add, .Enable, .One_Shot},
|
||||
udata = target._impl.next,
|
||||
}
|
||||
if !sa.append(&target.l.pending, ev) {
|
||||
if append(&target.l.pending, ev) == 0 {
|
||||
warn("just removed the head operation of a list of multiple, and the queue is full, have to force this update through inefficiently")
|
||||
// This has to happen the next time we submit or we could have udata pointing wrong.
|
||||
// Very inefficient but probably never hit.
|
||||
|
||||
@@ -786,6 +786,16 @@ Dynamic_Array_Type :: struct {
|
||||
elem: ^Expr,
|
||||
}
|
||||
|
||||
Fixed_Capacity_Dynamic_Array_Type :: struct {
|
||||
using node: Expr,
|
||||
tag: ^Expr, // possibly nil
|
||||
open: tokenizer.Pos,
|
||||
dynamic_pos: tokenizer.Pos,
|
||||
capacity: ^Expr,
|
||||
close: tokenizer.Pos,
|
||||
elem: ^Expr,
|
||||
}
|
||||
|
||||
Struct_Type :: struct {
|
||||
using node: Expr,
|
||||
tok_pos: tokenizer.Pos,
|
||||
@@ -931,6 +941,7 @@ Any_Node :: union {
|
||||
^Multi_Pointer_Type,
|
||||
^Array_Type,
|
||||
^Dynamic_Array_Type,
|
||||
^Fixed_Capacity_Dynamic_Array_Type,
|
||||
^Struct_Type,
|
||||
^Union_Type,
|
||||
^Enum_Type,
|
||||
@@ -1017,6 +1028,7 @@ Any_Expr :: union {
|
||||
^Multi_Pointer_Type,
|
||||
^Array_Type,
|
||||
^Dynamic_Array_Type,
|
||||
^Fixed_Capacity_Dynamic_Array_Type,
|
||||
^Struct_Type,
|
||||
^Union_Type,
|
||||
^Enum_Type,
|
||||
|
||||
@@ -311,10 +311,16 @@ clone_node :: proc(node: ^Node) -> ^Node {
|
||||
case ^Multi_Pointer_Type:
|
||||
r.elem = clone(r.elem)
|
||||
case ^Array_Type:
|
||||
r.tag = clone(r.tag)
|
||||
r.len = clone(r.len)
|
||||
r.elem = clone(r.elem)
|
||||
case ^Dynamic_Array_Type:
|
||||
r.tag = clone(r.tag)
|
||||
r.elem = clone(r.elem)
|
||||
case ^Fixed_Capacity_Dynamic_Array_Type:
|
||||
r.tag = clone(r.tag)
|
||||
r.capacity = clone(r.capacity)
|
||||
r.elem = clone(r.elem)
|
||||
case ^Struct_Type:
|
||||
r.poly_params = auto_cast clone(r.poly_params)
|
||||
r.align = clone(r.align)
|
||||
|
||||
@@ -380,6 +380,12 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
||||
walk(v, n.tag)
|
||||
}
|
||||
walk(v, n.elem)
|
||||
case ^Fixed_Capacity_Dynamic_Array_Type:
|
||||
if n.tag != nil {
|
||||
walk(v, n.tag)
|
||||
}
|
||||
walk(v, n.capacity)
|
||||
walk(v, n.elem)
|
||||
case ^Struct_Type:
|
||||
if n.poly_params != nil {
|
||||
walk(v, n.poly_params)
|
||||
|
||||
@@ -12,7 +12,7 @@ String :: distinct Array(byte)
|
||||
|
||||
Version_Type_Major :: 0
|
||||
Version_Type_Minor :: 3
|
||||
Version_Type_Patch :: 1
|
||||
Version_Type_Patch :: 2
|
||||
|
||||
Version_Type :: struct {
|
||||
major, minor, patch: u8,
|
||||
@@ -168,32 +168,33 @@ Attribute :: struct {
|
||||
}
|
||||
|
||||
Type_Kind :: enum u32le {
|
||||
Invalid = 0,
|
||||
Basic = 1,
|
||||
Named = 2,
|
||||
Generic = 3,
|
||||
Pointer = 4,
|
||||
Array = 5,
|
||||
Enumerated_Array = 6,
|
||||
Slice = 7,
|
||||
Dynamic_Array = 8,
|
||||
Map = 9,
|
||||
Struct = 10,
|
||||
Union = 11,
|
||||
Enum = 12,
|
||||
Parameters = 13,
|
||||
Proc = 14,
|
||||
Bit_Set = 15,
|
||||
Simd_Vector = 16,
|
||||
SOA_Struct_Fixed = 17,
|
||||
SOA_Struct_Slice = 18,
|
||||
SOA_Struct_Dynamic = 19,
|
||||
Relative_Pointer = 20,
|
||||
Relative_Multi_Pointer = 21,
|
||||
Multi_Pointer = 22,
|
||||
Matrix = 23,
|
||||
Soa_Pointer = 24,
|
||||
Bit_Field = 25,
|
||||
Invalid = 0,
|
||||
Basic = 1,
|
||||
Named = 2,
|
||||
Generic = 3,
|
||||
Pointer = 4,
|
||||
Array = 5,
|
||||
Enumerated_Array = 6,
|
||||
Slice = 7,
|
||||
Dynamic_Array = 8,
|
||||
Map = 9,
|
||||
Struct = 10,
|
||||
Union = 11,
|
||||
Enum = 12,
|
||||
Parameters = 13,
|
||||
Proc = 14,
|
||||
Bit_Set = 15,
|
||||
Simd_Vector = 16,
|
||||
SOA_Struct_Fixed = 17,
|
||||
SOA_Struct_Slice = 18,
|
||||
SOA_Struct_Dynamic = 19,
|
||||
Relative_Pointer = 20,
|
||||
Relative_Multi_Pointer = 21,
|
||||
Multi_Pointer = 22,
|
||||
Matrix = 23,
|
||||
Soa_Pointer = 24,
|
||||
Bit_Field = 25,
|
||||
Fixed_Capacity_Dynamic_Array = 26,
|
||||
}
|
||||
|
||||
Type_Elems_Cap :: 4
|
||||
@@ -219,13 +220,14 @@ Type :: struct {
|
||||
custom_align: String,
|
||||
|
||||
// Used by:
|
||||
// .Array - 1 count: 0=len
|
||||
// .Enumerated_Array - 1 count: 0=len
|
||||
// .SOA_Struct_Fixed - 1 count: 0=len
|
||||
// .Bit_Set - 2 count: 0=lower, 1=upper
|
||||
// .Simd_Vector - 1 count: 0=len
|
||||
// .Matrix - 2 count: 0=row_count, 1=column_count
|
||||
// .Struct - <=2 count: 0=min_field_align, 1=max_field_align
|
||||
// .Array - 1 count: 0=len
|
||||
// .Enumerated_Array - 1 count: 0=len
|
||||
// .SOA_Struct_Fixed - 1 count: 0=len
|
||||
// .Bit_Set - 2 count: 0=lower, 1=upper
|
||||
// .Simd_Vector - 1 count: 0=len
|
||||
// .Matrix - 2 count: 0=row_count, 1=column_count
|
||||
// .Struct - <=2 count: 0=min_field_align, 1=max_field_align
|
||||
// .Fixed_Capacity_Dynamic_Array - 1 count: 0=cap
|
||||
elem_count_len: u32le,
|
||||
elem_counts: [Type_Elems_Cap]i64le,
|
||||
|
||||
@@ -234,27 +236,28 @@ Type :: struct {
|
||||
calling_convention: String,
|
||||
|
||||
// Used by:
|
||||
// .Named - 1 type: 0=base type
|
||||
// .Generic - <1 type: 0=specialization
|
||||
// .Pointer - 1 type: 0=element
|
||||
// .Array - 1 type: 0=element
|
||||
// .Enumerated_Array - 2 types: 0=index and 1=element
|
||||
// .Slice - 1 type: 0=element
|
||||
// .Dynamic_Array - 1 type: 0=element
|
||||
// .Map - 2 types: 0=key, 1=value
|
||||
// .SOA_Struct_Fixed - 1 type: underlying SOA struct element
|
||||
// .SOA_Struct_Slice - 1 type: underlying SOA struct element
|
||||
// .SOA_Struct_Dynamic - 1 type: underlying SOA struct element
|
||||
// .Union - 0+ types: variants
|
||||
// .Enum - <1 type: 0=base type
|
||||
// .Proc - 2 types: 0=parameters, 1=results
|
||||
// .Bit_Set - <=2 types: 0=element type, 1=underlying type (Underlying_Type flag will be set)
|
||||
// .Simd_Vector - 1 type: 0=element
|
||||
// .Relative_Pointer - 2 types: 0=pointer type, 1=base integer
|
||||
// .Multi_Pointer - 1 type: 0=element
|
||||
// .Matrix - 1 type: 0=element
|
||||
// .Soa_Pointer - 1 type: 0=element
|
||||
// .Bit_Field - 1 type: 0=backing type
|
||||
// .Named - 1 type: 0=base type
|
||||
// .Generic - <1 type: 0=specialization
|
||||
// .Pointer - 1 type: 0=element
|
||||
// .Array - 1 type: 0=element
|
||||
// .Enumerated_Array - 2 types: 0=index and 1=element
|
||||
// .Slice - 1 type: 0=element
|
||||
// .Dynamic_Array - 1 type: 0=element
|
||||
// .Map - 2 types: 0=key, 1=value
|
||||
// .SOA_Struct_Fixed - 1 type: underlying SOA struct element
|
||||
// .SOA_Struct_Slice - 1 type: underlying SOA struct element
|
||||
// .SOA_Struct_Dynamic - 1 type: underlying SOA struct element
|
||||
// .Union - 0+ types: variants
|
||||
// .Enum - <1 type: 0=base type
|
||||
// .Proc - 2 types: 0=parameters, 1=results
|
||||
// .Bit_Set - <=2 types: 0=element type, 1=underlying type (Underlying_Type flag will be set)
|
||||
// .Simd_Vector - 1 type: 0=element
|
||||
// .Relative_Pointer - 2 types: 0=pointer type, 1=base integer
|
||||
// .Multi_Pointer - 1 type: 0=element
|
||||
// .Matrix - 1 type: 0=element
|
||||
// .Soa_Pointer - 1 type: 0=element
|
||||
// .Bit_Field - 1 type: 0=backing type
|
||||
// .Fixed_Capacity_Dynamic_Array - 1 type: 0=element
|
||||
types: Array(Type_Index),
|
||||
|
||||
// Used by:
|
||||
|
||||
@@ -2389,6 +2389,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
case ^ast.Array_Type: t.tag = bd
|
||||
case ^ast.Dynamic_Array_Type: t.tag = bd
|
||||
case ^ast.Pointer_Type: t.tag = bd
|
||||
case ^ast.Fixed_Capacity_Dynamic_Array_Type: t.tag = bd
|
||||
case:
|
||||
error(p, original_type.pos, "expected an array or pointer type after #%s", name.text)
|
||||
}
|
||||
@@ -2626,6 +2627,20 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
return t
|
||||
case .Dynamic:
|
||||
tok := expect_token(p, .Dynamic)
|
||||
if allow_token(p, .Semicolon) {
|
||||
capacity := parse_expr(p, false)
|
||||
close := expect_token(p, .Close_Bracket)
|
||||
elem := parse_type(p)
|
||||
|
||||
da := ast.new(ast.Fixed_Capacity_Dynamic_Array_Type, open.pos, elem)
|
||||
da.open = open.pos
|
||||
da.dynamic_pos = tok.pos
|
||||
da.capacity = capacity
|
||||
da.close = close.pos
|
||||
da.elem = elem
|
||||
return da
|
||||
}
|
||||
|
||||
close := expect_token(p, .Close_Bracket)
|
||||
elem := parse_type(p)
|
||||
da := ast.new(ast.Dynamic_Array_Type, open.pos, elem)
|
||||
@@ -3107,6 +3122,7 @@ is_literal_type :: proc(expr: ^ast.Expr) -> bool {
|
||||
^ast.Union_Type,
|
||||
^ast.Enum_Type,
|
||||
^ast.Dynamic_Array_Type,
|
||||
^ast.Fixed_Capacity_Dynamic_Array_Type,
|
||||
^ast.Map_Type,
|
||||
^ast.Bit_Set_Type,
|
||||
^ast.Matrix_Type,
|
||||
|
||||
@@ -44,6 +44,15 @@ iterate_array :: proc(val: any, it: ^int) -> (elem: any, index: int, ok: bool) {
|
||||
index = it^
|
||||
it^ += 1
|
||||
}
|
||||
case Type_Info_Fixed_Capacity_Dynamic_Array:
|
||||
count := (^int)(uintptr(val.data) + info.len_offset)^
|
||||
if it^ < count {
|
||||
elem.data = rawptr(uintptr(val.data) + uintptr(it^ * info.elem_size))
|
||||
elem.id = info.elem.id
|
||||
ok = true
|
||||
index = it^
|
||||
it^ += 1
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
@@ -6,33 +6,34 @@ _ :: intrinsics
|
||||
|
||||
Type_Info :: runtime.Type_Info
|
||||
|
||||
Type_Info_Named :: runtime.Type_Info_Named
|
||||
Type_Info_Integer :: runtime.Type_Info_Integer
|
||||
Type_Info_Rune :: runtime.Type_Info_Rune
|
||||
Type_Info_Float :: runtime.Type_Info_Float
|
||||
Type_Info_Complex :: runtime.Type_Info_Complex
|
||||
Type_Info_Quaternion :: runtime.Type_Info_Quaternion
|
||||
Type_Info_String :: runtime.Type_Info_String
|
||||
Type_Info_Boolean :: runtime.Type_Info_Boolean
|
||||
Type_Info_Any :: runtime.Type_Info_Any
|
||||
Type_Info_Type_Id :: runtime.Type_Info_Type_Id
|
||||
Type_Info_Pointer :: runtime.Type_Info_Pointer
|
||||
Type_Info_Multi_Pointer :: runtime.Type_Info_Multi_Pointer
|
||||
Type_Info_Procedure :: runtime.Type_Info_Procedure
|
||||
Type_Info_Array :: runtime.Type_Info_Array
|
||||
Type_Info_Enumerated_Array :: runtime.Type_Info_Enumerated_Array
|
||||
Type_Info_Dynamic_Array :: runtime.Type_Info_Dynamic_Array
|
||||
Type_Info_Slice :: runtime.Type_Info_Slice
|
||||
Type_Info_Parameters :: runtime.Type_Info_Parameters
|
||||
Type_Info_Struct :: runtime.Type_Info_Struct
|
||||
Type_Info_Union :: runtime.Type_Info_Union
|
||||
Type_Info_Enum :: runtime.Type_Info_Enum
|
||||
Type_Info_Map :: runtime.Type_Info_Map
|
||||
Type_Info_Bit_Set :: runtime.Type_Info_Bit_Set
|
||||
Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector
|
||||
Type_Info_Matrix :: runtime.Type_Info_Matrix
|
||||
Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer
|
||||
Type_Info_Bit_Field :: runtime.Type_Info_Bit_Field
|
||||
Type_Info_Named :: runtime.Type_Info_Named
|
||||
Type_Info_Integer :: runtime.Type_Info_Integer
|
||||
Type_Info_Rune :: runtime.Type_Info_Rune
|
||||
Type_Info_Float :: runtime.Type_Info_Float
|
||||
Type_Info_Complex :: runtime.Type_Info_Complex
|
||||
Type_Info_Quaternion :: runtime.Type_Info_Quaternion
|
||||
Type_Info_String :: runtime.Type_Info_String
|
||||
Type_Info_Boolean :: runtime.Type_Info_Boolean
|
||||
Type_Info_Any :: runtime.Type_Info_Any
|
||||
Type_Info_Type_Id :: runtime.Type_Info_Type_Id
|
||||
Type_Info_Pointer :: runtime.Type_Info_Pointer
|
||||
Type_Info_Multi_Pointer :: runtime.Type_Info_Multi_Pointer
|
||||
Type_Info_Procedure :: runtime.Type_Info_Procedure
|
||||
Type_Info_Array :: runtime.Type_Info_Array
|
||||
Type_Info_Enumerated_Array :: runtime.Type_Info_Enumerated_Array
|
||||
Type_Info_Dynamic_Array :: runtime.Type_Info_Dynamic_Array
|
||||
Type_Info_Slice :: runtime.Type_Info_Slice
|
||||
Type_Info_Parameters :: runtime.Type_Info_Parameters
|
||||
Type_Info_Struct :: runtime.Type_Info_Struct
|
||||
Type_Info_Union :: runtime.Type_Info_Union
|
||||
Type_Info_Enum :: runtime.Type_Info_Enum
|
||||
Type_Info_Map :: runtime.Type_Info_Map
|
||||
Type_Info_Bit_Set :: runtime.Type_Info_Bit_Set
|
||||
Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector
|
||||
Type_Info_Matrix :: runtime.Type_Info_Matrix
|
||||
Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer
|
||||
Type_Info_Bit_Field :: runtime.Type_Info_Bit_Field
|
||||
Type_Info_Fixed_Capacity_Dynamic_Array :: runtime.Type_Info_Fixed_Capacity_Dynamic_Array
|
||||
|
||||
Type_Info_Enum_Value :: runtime.Type_Info_Enum_Value
|
||||
|
||||
@@ -67,6 +68,7 @@ Type_Kind :: enum {
|
||||
Matrix,
|
||||
Soa_Pointer,
|
||||
Bit_Field,
|
||||
Fixed_Capacity_Dynamic_Array,
|
||||
}
|
||||
|
||||
|
||||
@@ -76,33 +78,34 @@ type_kind :: proc(T: typeid) -> Type_Kind {
|
||||
ti := type_info_of(T)
|
||||
if ti != nil {
|
||||
switch _ in ti.variant {
|
||||
case Type_Info_Named: return .Named
|
||||
case Type_Info_Integer: return .Integer
|
||||
case Type_Info_Rune: return .Rune
|
||||
case Type_Info_Float: return .Float
|
||||
case Type_Info_Complex: return .Complex
|
||||
case Type_Info_Quaternion: return .Quaternion
|
||||
case Type_Info_String: return .String
|
||||
case Type_Info_Boolean: return .Boolean
|
||||
case Type_Info_Any: return .Any
|
||||
case Type_Info_Type_Id: return .Type_Id
|
||||
case Type_Info_Pointer: return .Pointer
|
||||
case Type_Info_Multi_Pointer: return .Multi_Pointer
|
||||
case Type_Info_Procedure: return .Procedure
|
||||
case Type_Info_Array: return .Array
|
||||
case Type_Info_Enumerated_Array: return .Enumerated_Array
|
||||
case Type_Info_Dynamic_Array: return .Dynamic_Array
|
||||
case Type_Info_Slice: return .Slice
|
||||
case Type_Info_Parameters: return .Parameters
|
||||
case Type_Info_Struct: return .Struct
|
||||
case Type_Info_Union: return .Union
|
||||
case Type_Info_Enum: return .Enum
|
||||
case Type_Info_Map: return .Map
|
||||
case Type_Info_Bit_Set: return .Bit_Set
|
||||
case Type_Info_Simd_Vector: return .Simd_Vector
|
||||
case Type_Info_Matrix: return .Matrix
|
||||
case Type_Info_Soa_Pointer: return .Soa_Pointer
|
||||
case Type_Info_Bit_Field: return .Bit_Field
|
||||
case Type_Info_Named: return .Named
|
||||
case Type_Info_Integer: return .Integer
|
||||
case Type_Info_Rune: return .Rune
|
||||
case Type_Info_Float: return .Float
|
||||
case Type_Info_Complex: return .Complex
|
||||
case Type_Info_Quaternion: return .Quaternion
|
||||
case Type_Info_String: return .String
|
||||
case Type_Info_Boolean: return .Boolean
|
||||
case Type_Info_Any: return .Any
|
||||
case Type_Info_Type_Id: return .Type_Id
|
||||
case Type_Info_Pointer: return .Pointer
|
||||
case Type_Info_Multi_Pointer: return .Multi_Pointer
|
||||
case Type_Info_Procedure: return .Procedure
|
||||
case Type_Info_Array: return .Array
|
||||
case Type_Info_Enumerated_Array: return .Enumerated_Array
|
||||
case Type_Info_Dynamic_Array: return .Dynamic_Array
|
||||
case Type_Info_Slice: return .Slice
|
||||
case Type_Info_Parameters: return .Parameters
|
||||
case Type_Info_Struct: return .Struct
|
||||
case Type_Info_Union: return .Union
|
||||
case Type_Info_Enum: return .Enum
|
||||
case Type_Info_Map: return .Map
|
||||
case Type_Info_Bit_Set: return .Bit_Set
|
||||
case Type_Info_Simd_Vector: return .Simd_Vector
|
||||
case Type_Info_Matrix: return .Matrix
|
||||
case Type_Info_Soa_Pointer: return .Soa_Pointer
|
||||
case Type_Info_Bit_Field: return .Bit_Field
|
||||
case Type_Info_Fixed_Capacity_Dynamic_Array: return .Fixed_Capacity_Dynamic_Array
|
||||
}
|
||||
|
||||
}
|
||||
@@ -215,6 +218,7 @@ typeid_elem :: proc(id: typeid) -> typeid {
|
||||
case Type_Info_Slice: return v.elem.id
|
||||
case Type_Info_Dynamic_Array: return v.elem.id
|
||||
case Type_Info_Simd_Vector: return v.elem.id
|
||||
case Type_Info_Fixed_Capacity_Dynamic_Array: return v.elem.id
|
||||
}
|
||||
return id
|
||||
}
|
||||
@@ -305,6 +309,9 @@ length :: proc(val: any) -> int {
|
||||
case Type_Info_Dynamic_Array:
|
||||
return (^runtime.Raw_Dynamic_Array)(val.data).len
|
||||
|
||||
case Type_Info_Fixed_Capacity_Dynamic_Array:
|
||||
return (^int)(uintptr(val.data) + a.len_offset)^
|
||||
|
||||
case Type_Info_Map:
|
||||
return runtime.map_len((^runtime.Raw_Map)(val.data)^)
|
||||
|
||||
@@ -357,6 +364,9 @@ capacity :: proc(val: any) -> int {
|
||||
case Type_Info_Dynamic_Array:
|
||||
return (^runtime.Raw_Dynamic_Array)(val.data).cap
|
||||
|
||||
case Type_Info_Fixed_Capacity_Dynamic_Array:
|
||||
return a.capacity
|
||||
|
||||
case Type_Info_Map:
|
||||
return runtime.map_cap((^runtime.Raw_Map)(val.data)^)
|
||||
|
||||
@@ -417,6 +427,13 @@ index :: proc(val: any, i: int, loc := #caller_location) -> any {
|
||||
data := rawptr(uintptr(raw.data) + offset)
|
||||
return any{data, a.elem.id}
|
||||
|
||||
case Type_Info_Fixed_Capacity_Dynamic_Array:
|
||||
count := (^int)(uintptr(val.data) + a.len_offset)^
|
||||
runtime.bounds_check_error_loc(loc, i, count)
|
||||
offset := uintptr(a.elem.size * i)
|
||||
data := rawptr(uintptr(val.data) + offset)
|
||||
return any{data, a.elem.id}
|
||||
|
||||
case Type_Info_String:
|
||||
if a.is_cstring { return nil }
|
||||
|
||||
@@ -1773,6 +1790,10 @@ as_raw_data :: proc(a: any) -> (value: rawptr, valid: bool) {
|
||||
valid = true
|
||||
value = (^runtime.Raw_Slice)(a.data).data
|
||||
|
||||
case Type_Info_Fixed_Capacity_Dynamic_Array:
|
||||
valid = true
|
||||
value = a.data
|
||||
|
||||
case Type_Info_Dynamic_Array:
|
||||
valid = true
|
||||
value = (^runtime.Raw_Dynamic_Array)(a.data).data
|
||||
@@ -1919,6 +1940,23 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
|
||||
}
|
||||
}
|
||||
return true
|
||||
case Type_Info_Fixed_Capacity_Dynamic_Array:
|
||||
a_count := (^int)(uintptr(a.data) + v.len_offset)^
|
||||
b_count := (^int)(uintptr(b.data) + v.len_offset)^
|
||||
if a_count != b_count {
|
||||
return false
|
||||
}
|
||||
|
||||
for i in 0..<a_count {
|
||||
// since the data is stored at the start, this is possible
|
||||
x := rawptr(uintptr(a.data) + uintptr(v.elem_size*i))
|
||||
y := rawptr(uintptr(b.data) + uintptr(v.elem_size*i))
|
||||
if !equal(any{x, v.elem.id}, any{y, v.elem.id}, including_indirect_array_recursion, recursion_level) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
case Type_Info_Enumerated_Array:
|
||||
for i in 0..<v.count {
|
||||
x := rawptr(uintptr(a.data) + uintptr(v.elem_size*i))
|
||||
|
||||
@@ -32,36 +32,36 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
||||
return x.signed == y.signed && x.endianness == y.endianness
|
||||
|
||||
case Type_Info_Rune:
|
||||
_, ok := b.variant.(Type_Info_Rune)
|
||||
return ok
|
||||
_ = b.variant.(Type_Info_Rune) or_return
|
||||
return true
|
||||
|
||||
case Type_Info_Float:
|
||||
_, ok := b.variant.(Type_Info_Float)
|
||||
return ok
|
||||
y := b.variant.(Type_Info_Float) or_return
|
||||
return x.endianness == y.endianness
|
||||
|
||||
case Type_Info_Complex:
|
||||
_, ok := b.variant.(Type_Info_Complex)
|
||||
return ok
|
||||
_ = b.variant.(Type_Info_Complex) or_return
|
||||
return true
|
||||
|
||||
case Type_Info_Quaternion:
|
||||
_, ok := b.variant.(Type_Info_Quaternion)
|
||||
return ok
|
||||
_ = b.variant.(Type_Info_Quaternion) or_return
|
||||
return true
|
||||
|
||||
case Type_Info_Type_Id:
|
||||
_, ok := b.variant.(Type_Info_Type_Id)
|
||||
return ok
|
||||
_ = b.variant.(Type_Info_Type_Id) or_return
|
||||
return true
|
||||
|
||||
case Type_Info_String:
|
||||
_, ok := b.variant.(Type_Info_String)
|
||||
return ok
|
||||
y := b.variant.(Type_Info_String) or_return
|
||||
return x.is_cstring == y.is_cstring && x.encoding == y.encoding
|
||||
|
||||
case Type_Info_Boolean:
|
||||
_, ok := b.variant.(Type_Info_Boolean)
|
||||
return ok
|
||||
_ = b.variant.(Type_Info_Boolean) or_return
|
||||
return true
|
||||
|
||||
case Type_Info_Any:
|
||||
_, ok := b.variant.(Type_Info_Any)
|
||||
return ok
|
||||
_ = b.variant.(Type_Info_Any) or_return
|
||||
return true
|
||||
|
||||
case Type_Info_Pointer:
|
||||
y := b.variant.(Type_Info_Pointer) or_return
|
||||
@@ -78,22 +78,19 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
||||
|
||||
case Type_Info_Procedure:
|
||||
y := b.variant.(Type_Info_Procedure) or_return
|
||||
switch {
|
||||
case x.variadic != y.variadic,
|
||||
x.convention != y.convention:
|
||||
return false
|
||||
}
|
||||
(x.variadic == y.variadic) or_return
|
||||
(x.convention == y.convention) or_return
|
||||
|
||||
return are_types_identical(x.params, y.params) && are_types_identical(x.results, y.results)
|
||||
|
||||
case Type_Info_Array:
|
||||
y := b.variant.(Type_Info_Array) or_return
|
||||
if x.count != y.count { return false }
|
||||
(x.count == y.count) or_return
|
||||
return are_types_identical(x.elem, y.elem)
|
||||
|
||||
case Type_Info_Enumerated_Array:
|
||||
y := b.variant.(Type_Info_Enumerated_Array) or_return
|
||||
if x.count != y.count { return false }
|
||||
(x.count == y.count) or_return
|
||||
return are_types_identical(x.index, y.index) &&
|
||||
are_types_identical(x.elem, y.elem)
|
||||
|
||||
@@ -105,14 +102,17 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
||||
y := b.variant.(Type_Info_Slice) or_return
|
||||
return are_types_identical(x.elem, y.elem)
|
||||
|
||||
case Type_Info_Fixed_Capacity_Dynamic_Array:
|
||||
y := b.variant.(Type_Info_Fixed_Capacity_Dynamic_Array) or_return
|
||||
(x.capacity == y.capacity) or_return
|
||||
return are_types_identical(x.elem, y.elem)
|
||||
|
||||
case Type_Info_Parameters:
|
||||
y := b.variant.(Type_Info_Parameters) or_return
|
||||
if len(x.types) != len(y.types) { return false }
|
||||
(len(x.types) == len(y.types)) or_return
|
||||
for _, i in x.types {
|
||||
xt, yt := x.types[i], y.types[i]
|
||||
if !are_types_identical(xt, yt) {
|
||||
return false
|
||||
}
|
||||
are_types_identical(xt, yt) or_return
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -131,59 +131,64 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
||||
xt, yt := x.types[i], y.types[i]
|
||||
xl, yl := x.tags[i], y.tags[i]
|
||||
|
||||
if xn != yn { return false }
|
||||
if !are_types_identical(xt, yt) { return false }
|
||||
if xl != yl { return false }
|
||||
(xn == yn) or_return
|
||||
are_types_identical(xt, yt) or_return
|
||||
(xl == yl) or_return
|
||||
}
|
||||
return true
|
||||
|
||||
case Type_Info_Union:
|
||||
y := b.variant.(Type_Info_Union) or_return
|
||||
if len(x.variants) != len(y.variants) { return false }
|
||||
y := b.variant.(Type_Info_Union) or_return
|
||||
(len(x.variants) == len(y.variants)) or_return
|
||||
|
||||
for _, i in x.variants {
|
||||
xv, yv := x.variants[i], y.variants[i]
|
||||
if !are_types_identical(xv, yv) { return false }
|
||||
are_types_identical(xv, yv) or_return
|
||||
}
|
||||
return true
|
||||
|
||||
case Type_Info_Enum:
|
||||
// NOTE(bill): Should be handled above
|
||||
return false
|
||||
y := b.variant.(Type_Info_Enum) or_return
|
||||
are_types_identical(x.base, y.base) or_return
|
||||
(len(x.names) == len(y.names)) or_return
|
||||
|
||||
for _, i in x.names {
|
||||
(x.names[i] == y.names[i]) or_return
|
||||
(x.values[i] == y.values[i]) or_return
|
||||
}
|
||||
return true
|
||||
|
||||
case Type_Info_Map:
|
||||
y := b.variant.(Type_Info_Map) or_return
|
||||
return are_types_identical(x.key, y.key) && are_types_identical(x.value, y.value)
|
||||
|
||||
case Type_Info_Bit_Set:
|
||||
y := b.variant.(Type_Info_Bit_Set) or_return
|
||||
return x.elem == y.elem && x.lower == y.lower && x.upper == y.upper
|
||||
y := b.variant.(Type_Info_Bit_Set) or_return
|
||||
are_types_identical(x.underlying, y.underlying) or_return
|
||||
are_types_identical(x.elem, y.elem) or_return
|
||||
|
||||
return x.lower == y.lower && x.upper == y.upper
|
||||
|
||||
case Type_Info_Simd_Vector:
|
||||
y := b.variant.(Type_Info_Simd_Vector) or_return
|
||||
return x.count == y.count && x.elem == y.elem
|
||||
|
||||
case Type_Info_Matrix:
|
||||
y := b.variant.(Type_Info_Matrix) or_return
|
||||
if x.row_count != y.row_count { return false }
|
||||
if x.column_count != y.column_count { return false }
|
||||
if x.layout != y.layout { return false }
|
||||
y := b.variant.(Type_Info_Matrix) or_return
|
||||
(x.row_count == y.row_count) or_return
|
||||
(x.column_count == y.column_count) or_return
|
||||
(x.layout == y.layout) or_return
|
||||
return are_types_identical(x.elem, y.elem)
|
||||
|
||||
case Type_Info_Bit_Field:
|
||||
y := b.variant.(Type_Info_Bit_Field) or_return
|
||||
if !are_types_identical(x.backing_type, y.backing_type) { return false }
|
||||
if x.field_count != y.field_count { return false }
|
||||
y := b.variant.(Type_Info_Bit_Field) or_return
|
||||
are_types_identical(x.backing_type, y.backing_type) or_return
|
||||
(x.field_count == y.field_count) or_return
|
||||
|
||||
for _, i in x.names[:x.field_count] {
|
||||
if x.names[i] != y.names[i] {
|
||||
return false
|
||||
}
|
||||
if !are_types_identical(x.types[i], y.types[i]) {
|
||||
return false
|
||||
}
|
||||
if x.bit_sizes[i] != y.bit_sizes[i] {
|
||||
return false
|
||||
}
|
||||
(x.names[i] == y.names[i]) or_return
|
||||
are_types_identical(x.types[i], y.types[i]) or_return
|
||||
(x.bit_sizes[i] == y.bit_sizes[i]) or_return
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -329,7 +334,8 @@ is_soa_pointer :: proc(info: ^Type_Info) -> bool {
|
||||
is_pointer_internally :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
#partial switch v in type_info_base(info).variant {
|
||||
case Type_Info_Pointer, Type_Info_Multi_Pointer,
|
||||
case Type_Info_Pointer,
|
||||
Type_Info_Multi_Pointer,
|
||||
Type_Info_Procedure:
|
||||
return true
|
||||
case Type_Info_String:
|
||||
@@ -428,6 +434,13 @@ is_simd_vector :: proc(info: ^Type_Info) -> bool {
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Simd_Vector)
|
||||
return ok
|
||||
}
|
||||
// Returns true when the type is a fixed-capacity dynamic-array type ([dynamic; N]T), false otherwise.
|
||||
@(require_results)
|
||||
is_fixed_capacity_dynamic_array :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Fixed_Capacity_Dynamic_Array)
|
||||
return ok
|
||||
}
|
||||
|
||||
|
||||
// Returns true when the core-type is represented with a platform-native endian type, and returns false otherwise.
|
||||
@@ -441,6 +454,8 @@ is_endian_platform :: proc(info: ^Type_Info) -> bool {
|
||||
#partial switch v in info.variant {
|
||||
case Type_Info_Integer:
|
||||
return v.endianness == .Platform
|
||||
case Type_Info_Float:
|
||||
return v.endianness == .Platform
|
||||
case Type_Info_Bit_Set:
|
||||
return is_endian_platform(v.underlying)
|
||||
case Type_Info_Pointer:
|
||||
@@ -463,6 +478,11 @@ is_endian_little :: proc(info: ^Type_Info) -> bool {
|
||||
return ODIN_ENDIAN == .Little
|
||||
}
|
||||
return v.endianness == .Little
|
||||
case Type_Info_Float:
|
||||
if v.endianness == .Platform {
|
||||
return ODIN_ENDIAN == .Little
|
||||
}
|
||||
return v.endianness == .Little
|
||||
case Type_Info_Bit_Set:
|
||||
return is_endian_little(v.underlying)
|
||||
case Type_Info_Pointer:
|
||||
@@ -485,6 +505,11 @@ is_endian_big :: proc(info: ^Type_Info) -> bool {
|
||||
return ODIN_ENDIAN == .Big
|
||||
}
|
||||
return v.endianness == .Big
|
||||
case Type_Info_Float:
|
||||
if v.endianness == .Platform {
|
||||
return ODIN_ENDIAN == .Big
|
||||
}
|
||||
return v.endianness == .Big
|
||||
case Type_Info_Bit_Set:
|
||||
return is_endian_big(v.underlying)
|
||||
case Type_Info_Pointer:
|
||||
@@ -661,6 +686,12 @@ write_type_writer :: #force_no_inline proc(w: io.Writer, ti: ^Type_Info, n_writt
|
||||
io.write_string(w, "[]", &n) or_return
|
||||
write_type(w, info.elem, &n) or_return
|
||||
|
||||
case Type_Info_Fixed_Capacity_Dynamic_Array:
|
||||
io.write_string(w, "[dynamic; ", &n) or_return
|
||||
io.write_i64(w, i64(info.capacity), 10, &n) or_return
|
||||
io.write_string(w, "]", &n) or_return
|
||||
write_type(w, info.elem, &n) or_return
|
||||
|
||||
case Type_Info_Map:
|
||||
io.write_string(w, "map[", &n) or_return
|
||||
write_type(w, info.key, &n) or_return
|
||||
@@ -829,6 +860,8 @@ has_no_indirections :: proc(ti: ^Type_Info) -> bool {
|
||||
return has_no_indirections(info.elem)
|
||||
case Type_Info_Enumerated_Array:
|
||||
return has_no_indirections(info.elem)
|
||||
case Type_Info_Fixed_Capacity_Dynamic_Array:
|
||||
return has_no_indirections(info.elem)
|
||||
|
||||
case Type_Info_Simd_Vector:
|
||||
return true
|
||||
|
||||
Reference in New Issue
Block a user