Merge pull request #6406 from odin-lang/bill/fixed-capacity-dynamic-array

Fixed Capacity Dynamic Arrays
This commit is contained in:
gingerBill
2026-03-15 15:31:31 +00:00
committed by GitHub
39 changed files with 1643 additions and 259 deletions

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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

View File

@@ -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)

View File

@@ -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.

View File

@@ -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,

View File

@@ -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)

View File

@@ -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)

View File

@@ -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:

View File

@@ -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,

View File

@@ -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

View File

@@ -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))

View File

@@ -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