diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index c958c2d2e..27168d6c2 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -2142,6 +2142,108 @@ __handle_raw_union_tag :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime. return false } +@(private) +fmt_soa_struct_internal :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime.Type_Info_Struct, type_name: string, hash: bool, indent: int) { + is_empty := info.field_count == 0 + + fi.indent += 1 + defer fi.indent -= 1 + + base_type_name: string + if v, ok := info.soa_base_type.variant.(runtime.Type_Info_Named); ok { + base_type_name = v.name + } + + actual_field_count := info.field_count + + n := uintptr(info.soa_len) + + if info.soa_kind == .Slice { + actual_field_count = info.field_count-1 // len + + n = uintptr((^int)(uintptr(v.data) + info.offsets[actual_field_count])^) + + } else if info.soa_kind == .Dynamic { + actual_field_count = info.field_count-3 // len, cap, allocator + + n = uintptr((^int)(uintptr(v.data) + info.offsets[actual_field_count])^) + } + + if hash && n > 0 { + io.write_byte(fi.writer, '\n', &fi.n) + } + + for index in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } + + field_count := -1 + + if !hash && field_count > 0 { io.write_string(fi.writer, ", ", &fi.n) } + + if hash { + fi.indent -= 1 + fmt_write_indent(fi) + fi.indent += 1 + } + io.write_string(fi.writer, base_type_name, &fi.n) + io.write_byte(fi.writer, '{', &fi.n) + if hash && !is_empty { io.write_byte(fi.writer, '\n', &fi.n) } + defer { + if hash && !is_empty { + fi.indent -= 1 + fmt_write_indent(fi) + fi.indent += 1 + } + io.write_byte(fi.writer, '}', &fi.n) + if hash { io.write_string(fi.writer, ",\n", &fi.n) } + } + fi.record_level += 1 + defer fi.record_level -= 1 + + for i in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } + if hash { + fmt_write_indent(fi) + } + + io.write_string(fi.writer, name, &fi.n) + io.write_string(fi.writer, " = ", &fi.n) + + if info.soa_kind == .Fixed { + t := info.types[i].variant.(runtime.Type_Info_Array).elem + t_size := uintptr(t.size) + if reflect.is_any(t) { + io.write_string(fi.writer, "any{}", &fi.n) + } else { + data := rawptr(uintptr(v.data) + info.offsets[i] + index*t_size) + fmt_arg(fi, any{data, t.id}, verb) + } + } else { + t := info.types[i].variant.(runtime.Type_Info_Multi_Pointer).elem + t_size := uintptr(t.size) + if reflect.is_any(t) { + io.write_string(fi.writer, "any{}", &fi.n) + } else { + field_ptr := (^^byte)(uintptr(v.data) + info.offsets[i])^ + data := rawptr(uintptr(field_ptr) + index*t_size) + fmt_arg(fi, any{data, t.id}, verb) + } + } + + if hash { io.write_string(fi.writer, ",\n", &fi.n) } + } + } + + if hash && n > 0 { + for _ in 0.. 0 { - io.write_byte(fi.writer, '\n', &fi.n) - } - - for index in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } - - field_count := -1 - - if !hash && field_count > 0 { io.write_string(fi.writer, ", ", &fi.n) } - - if hash { - fi.indent -= 1 - fmt_write_indent(fi) - fi.indent += 1 - } - io.write_string(fi.writer, base_type_name, &fi.n) - io.write_byte(fi.writer, '{', &fi.n) - if hash && !is_empty { io.write_byte(fi.writer, '\n', &fi.n) } - defer { - if hash && !is_empty { - fi.indent -= 1 - fmt_write_indent(fi) - fi.indent += 1 - } - io.write_byte(fi.writer, '}', &fi.n) - if hash { io.write_string(fi.writer, ",\n", &fi.n) } - } - fi.record_level += 1 - defer fi.record_level -= 1 - - for i in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } - if hash { - fmt_write_indent(fi) - } - - io.write_string(fi.writer, name, &fi.n) - io.write_string(fi.writer, " = ", &fi.n) - - if info.soa_kind == .Fixed { - t := info.types[i].variant.(runtime.Type_Info_Array).elem - t_size := uintptr(t.size) - if reflect.is_any(t) { - io.write_string(fi.writer, "any{}", &fi.n) - } else { - data := rawptr(uintptr(v.data) + info.offsets[i] + index*t_size) - fmt_arg(fi, any{data, t.id}, verb) - } - } else { - t := info.types[i].variant.(runtime.Type_Info_Multi_Pointer).elem - t_size := uintptr(t.size) - if reflect.is_any(t) { - io.write_string(fi.writer, "any{}", &fi.n) - } else { - field_ptr := (^^byte)(uintptr(v.data) + info.offsets[i])^ - data := rawptr(uintptr(field_ptr) + index*t_size) - fmt_arg(fi, any{data, t.id}, verb) - } - } - - if hash { io.write_string(fi.writer, ",\n", &fi.n) } - } - } - - if hash && n > 0 { - for _ in 0..", &fi.n) + return + } + if fi.indirection_level < 1 { + fi.indirection_level += 1 + defer fi.indirection_level -= 1 + io.write_byte(fi.writer, '&') + fmt_value(fi, a, verb) + return + } + + case runtime.Type_Info_Struct, + runtime.Type_Info_Union, + runtime.Type_Info_Bit_Field: + if ptr == nil { + io.write_string(fi.writer, "", &fi.n) + return + } + if fi.indirection_level < 1 { + fi.indirection_level += 1 + defer fi.indirection_level -= 1 + io.write_byte(fi.writer, '&', &fi.n) + fmt_value(fi, a, verb) + return + } + } + } + } + fmt_pointer(fi, ptr, verb) + } +} + +@(private) +fmt_multi_pointer :: proc(fi: ^Info, v: any, info: runtime.Type_Info_Multi_Pointer, verb: rune) { + ptr := (^rawptr)(v.data)^ + if ptr == nil { + io.write_string(fi.writer, "", &fi.n) + return + } + if verb != 'p' && info.elem != nil { + a := any{ptr, info.elem.id} + + elem := runtime.type_info_base(info.elem) + if elem != nil { + if n, ok := fi.optional_len.?; ok { + fi.optional_len = nil + fmt_array(fi, ptr, n, elem.size, elem, verb) + return + } else if fi.use_nul_termination { + fi.use_nul_termination = false + fmt_array_nul_terminated(fi, ptr, -1, elem.size, elem, verb) + return + } + + #partial switch &e in elem.variant { + case runtime.Type_Info_Integer: + switch verb { + case 's', 'q': + switch elem.id { + case u8: + fmt_cstring(fi, cstring(ptr), verb) + return + case u16, u32, rune: + n := search_nul_termination(ptr, elem.size, -1) + fmt_array(fi, ptr, n, elem.size, elem, verb) + return + } + } + + case runtime.Type_Info_Array, + runtime.Type_Info_Slice, + runtime.Type_Info_Dynamic_Array, + runtime.Type_Info_Map: + if fi.indirection_level < 1 { + fi.indirection_level += 1 + defer fi.indirection_level -= 1 + io.write_byte(fi.writer, '&', &fi.n) + fmt_value(fi, a, verb) + return + } + + case runtime.Type_Info_Struct, + runtime.Type_Info_Union: + if fi.indirection_level < 1 { + fi.indirection_level += 1 + defer fi.indirection_level -= 1 + io.write_byte(fi.writer, '&', &fi.n) + fmt_value(fi, a, verb) + return + } + } + } + } + fmt_pointer(fi, ptr, verb) +} + +fmt_enumerated_array :: proc(fi: ^Info, v: any, info: runtime.Type_Info_Enumerated_Array, verb: rune) { + fi.record_level += 1 + defer fi.record_level -= 1 + + if fi.hash { + io.write_byte(fi.writer, '[' if verb != 'w' else '{', &fi.n) + io.write_byte(fi.writer, '\n', &fi.n) + defer { + fmt_write_indent(fi) + io.write_byte(fi.writer, ']' if verb != 'w' else '}', &fi.n) + } + indent := fi.indent + fi.indent += 1 + defer fi.indent = indent + + for i in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } + + idx, ok := stored_enum_value_to_string(info.index, info.min_value, i) + if ok { + io.write_byte(fi.writer, '.', &fi.n) + io.write_string(fi.writer, idx, &fi.n) + } else { + io.write_i64(fi.writer, i64(info.min_value)+i64(i), 10, &fi.n) + } + io.write_string(fi.writer, " = ", &fi.n) + + data := uintptr(v.data) + uintptr(i*info.elem_size) + fmt_arg(fi, any{rawptr(data), info.elem.id}, verb) + } + } +} + +fmt_map :: proc(fi: ^Info, v: any, info: runtime.Type_Info_Map, verb: rune) { + switch verb { + case: + fmt_bad_verb(fi, verb) + case 'v', 'w': + if verb == 'v' { + io.write_string(fi.writer, "map", &fi.n) + } + io.write_byte(fi.writer, '[' if verb != 'w' else '{', &fi.n) + defer io.write_byte(fi.writer, ']' if verb != 'w' else '}', &fi.n) + + + hash := fi.hash; defer fi.hash = hash + indent := fi.indent; defer fi.indent -= 1 + do_trailing_comma := hash + + fi.indent += 1 + if hash { + io.write_byte(fi.writer, '\n', &fi.n) + } + defer { + if hash { + for _ in 0.. 0 { io.write_string(fi.writer, ", ") } + if hash { + fmt_write_indent(fi) + } + j += 1 + + key := runtime.map_cell_index_dynamic(ks, info.map_info.ks, bucket_index) + value := runtime.map_cell_index_dynamic(vs, info.map_info.vs, bucket_index) + + fmt_arg(&Info{writer = fi.writer}, any{rawptr(key), info.key.id}, verb) + if hash { + io.write_string(fi.writer, " = ", &fi.n) + } else { + io.write_string(fi.writer, "=", &fi.n) + } + fmt_arg(fi, any{rawptr(value), info.value.id}, verb) + + if do_trailing_comma { io.write_string(fi.writer, ",\n", &fi.n) } + } + } + } + +} // Formats a value based on its type and formatting verb // @@ -2872,184 +3106,35 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { type_info := type_info_of(v.id) switch &info in type_info.variant { - case runtime.Type_Info_Any: // Ignore - case runtime.Type_Info_Parameters: // Ignore + case runtime.Type_Info_Any: + // Ignore + case runtime.Type_Info_Parameters: + // Ignore case runtime.Type_Info_Named: fmt_named(fi, v, verb, info) - case runtime.Type_Info_Boolean: fmt_arg(fi, v, verb) - case runtime.Type_Info_Integer: fmt_arg(fi, v, verb) - case runtime.Type_Info_Rune: fmt_arg(fi, v, verb) - case runtime.Type_Info_Float: fmt_arg(fi, v, verb) - case runtime.Type_Info_Complex: fmt_arg(fi, v, verb) - case runtime.Type_Info_Quaternion: fmt_arg(fi, v, verb) - case runtime.Type_Info_String: fmt_arg(fi, v, verb) + case runtime.Type_Info_Boolean, + runtime.Type_Info_Integer, + runtime.Type_Info_Rune, + runtime.Type_Info_Float, + runtime.Type_Info_Complex, + runtime.Type_Info_Quaternion, + runtime.Type_Info_String: + fmt_arg(fi, v, verb) case runtime.Type_Info_Pointer: - if v.id == typeid_of(^runtime.Type_Info) { - reflect.write_type(fi.writer, (^^runtime.Type_Info)(v.data)^, &fi.n) - } else { - ptr := (^rawptr)(v.data)^ - if verb != 'p' && info.elem != nil { - a := any{ptr, info.elem.id} - - elem := runtime.type_info_base(info.elem) - if elem != nil { - #partial switch &e in elem.variant { - case runtime.Type_Info_Array, - runtime.Type_Info_Slice, - runtime.Type_Info_Dynamic_Array, - runtime.Type_Info_Map: - if ptr == nil { - io.write_string(fi.writer, "", &fi.n) - return - } - if fi.indirection_level < 1 { - fi.indirection_level += 1 - defer fi.indirection_level -= 1 - io.write_byte(fi.writer, '&') - fmt_value(fi, a, verb) - return - } - - case runtime.Type_Info_Struct, - runtime.Type_Info_Union, - runtime.Type_Info_Bit_Field: - if ptr == nil { - io.write_string(fi.writer, "", &fi.n) - return - } - if fi.indirection_level < 1 { - fi.indirection_level += 1 - defer fi.indirection_level -= 1 - io.write_byte(fi.writer, '&', &fi.n) - fmt_value(fi, a, verb) - return - } - } - } - } - fmt_pointer(fi, ptr, verb) - } + fmt_pointer_from_value(fi, v, info, verb) case runtime.Type_Info_Soa_Pointer: ptr := (^runtime.Raw_Soa_Pointer)(v.data)^ fmt_soa_pointer(fi, ptr, verb) case runtime.Type_Info_Multi_Pointer: - ptr := (^rawptr)(v.data)^ - if ptr == nil { - io.write_string(fi.writer, "", &fi.n) - return - } - if verb != 'p' && info.elem != nil { - a := any{ptr, info.elem.id} - - elem := runtime.type_info_base(info.elem) - if elem != nil { - if n, ok := fi.optional_len.?; ok { - fi.optional_len = nil - fmt_array(fi, ptr, n, elem.size, elem, verb) - return - } else if fi.use_nul_termination { - fi.use_nul_termination = false - fmt_array_nul_terminated(fi, ptr, -1, elem.size, elem, verb) - return - } - - #partial switch &e in elem.variant { - case runtime.Type_Info_Integer: - switch verb { - case 's', 'q': - switch elem.id { - case u8: - fmt_cstring(fi, cstring(ptr), verb) - return - case u16, u32, rune: - n := search_nul_termination(ptr, elem.size, -1) - fmt_array(fi, ptr, n, elem.size, elem, verb) - return - } - } - - case runtime.Type_Info_Array, - runtime.Type_Info_Slice, - runtime.Type_Info_Dynamic_Array, - runtime.Type_Info_Map: - if fi.indirection_level < 1 { - fi.indirection_level += 1 - defer fi.indirection_level -= 1 - io.write_byte(fi.writer, '&', &fi.n) - fmt_value(fi, a, verb) - return - } - - case runtime.Type_Info_Struct, - runtime.Type_Info_Union: - if fi.indirection_level < 1 { - fi.indirection_level += 1 - defer fi.indirection_level -= 1 - io.write_byte(fi.writer, '&', &fi.n) - fmt_value(fi, a, verb) - return - } - } - } - } - fmt_pointer(fi, ptr, verb) + fmt_multi_pointer(fi, v, info, verb) case runtime.Type_Info_Enumerated_Array: - fi.record_level += 1 - defer fi.record_level -= 1 - - if fi.hash { - io.write_byte(fi.writer, '[' if verb != 'w' else '{', &fi.n) - io.write_byte(fi.writer, '\n', &fi.n) - defer { - fmt_write_indent(fi) - io.write_byte(fi.writer, ']' if verb != 'w' else '}', &fi.n) - } - indent := fi.indent - fi.indent += 1 - defer fi.indent = indent - - for i in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } - - idx, ok := stored_enum_value_to_string(info.index, info.min_value, i) - if ok { - io.write_byte(fi.writer, '.', &fi.n) - io.write_string(fi.writer, idx, &fi.n) - } else { - io.write_i64(fi.writer, i64(info.min_value)+i64(i), 10, &fi.n) - } - io.write_string(fi.writer, " = ", &fi.n) - - data := uintptr(v.data) + uintptr(i*info.elem_size) - fmt_arg(fi, any{rawptr(data), info.elem.id}, verb) - } - } + fmt_enumerated_array(fi, v, info, verb) case runtime.Type_Info_Array: n := info.count @@ -3104,63 +3189,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Map: - switch verb { - case: - fmt_bad_verb(fi, verb) - case 'v', 'w': - if verb == 'v' { - io.write_string(fi.writer, "map", &fi.n) - } - io.write_byte(fi.writer, '[' if verb != 'w' else '{', &fi.n) - defer io.write_byte(fi.writer, ']' if verb != 'w' else '}', &fi.n) - - - hash := fi.hash; defer fi.hash = hash - indent := fi.indent; defer fi.indent -= 1 - do_trailing_comma := hash - - fi.indent += 1 - if hash { - io.write_byte(fi.writer, '\n', &fi.n) - } - defer { - if hash { - for _ in 0.. 0 { io.write_string(fi.writer, ", ") } - if hash { - fmt_write_indent(fi) - } - j += 1 - - key := runtime.map_cell_index_dynamic(ks, info.map_info.ks, bucket_index) - value := runtime.map_cell_index_dynamic(vs, info.map_info.vs, bucket_index) - - fmt_arg(&Info{writer = fi.writer}, any{rawptr(key), info.key.id}, verb) - if hash { - io.write_string(fi.writer, " = ", &fi.n) - } else { - io.write_string(fi.writer, "=", &fi.n) - } - fmt_arg(fi, any{rawptr(value), info.value.id}, verb) - - if do_trailing_comma { io.write_string(fi.writer, ",\n", &fi.n) } - } - } - } + fmt_map(fi, v, info, verb) case runtime.Type_Info_Struct: fmt_struct(fi, v, verb, info, "")