123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596 |
- #import "os.odin"
- #import "mem.odin"
- #import "utf8.odin"
- PRINT_BUF_SIZE :: 1<<12
- fprint :: proc(f: ^os.File, args: ..any) -> int {
- data: [PRINT_BUF_SIZE]byte
- buf := data[:0]
- bprint(^buf, ..args)
- os.write(f, buf)
- return buf.count
- }
- fprintln :: proc(f: ^os.File, args: ..any) -> int {
- data: [PRINT_BUF_SIZE]byte
- buf := data[:0]
- bprintln(^buf, ..args)
- os.write(f, buf)
- return buf.count
- }
- fprintf :: proc(f: ^os.File, fmt: string, args: ..any) -> int {
- data: [PRINT_BUF_SIZE]byte
- buf := data[:0]
- bprintf(^buf, fmt, ..args)
- os.write(f, buf)
- return buf.count
- }
- print :: proc(args: ..any) -> int {
- return fprint(os.stdout, ..args)
- }
- println :: proc(args: ..any) -> int {
- return fprintln(os.stdout, ..args)
- }
- printf :: proc(fmt: string, args: ..any) -> int {
- return fprintf(os.stdout, fmt, ..args)
- }
- fprint_type :: proc(f: ^os.File, info: ^Type_Info) {
- data: [PRINT_BUF_SIZE]byte
- buf := data[:0]
- bprint_type(^buf, info)
- os.write(f, buf)
- }
- print_byte_buffer :: proc(buf: ^[]byte, b: []byte) {
- if buf.count < buf.capacity {
- n := min(buf.capacity-buf.count, b.count)
- if n > 0 {
- mem.copy(buf.data + buf.count, b.data, n)
- buf.count += n
- }
- }
- }
- bprint_string :: proc(buf: ^[]byte, s: string) {
- print_byte_buffer(buf, s as []byte)
- }
- byte_reverse :: proc(b: []byte) {
- n := b.count
- for i := 0; i < n/2; i++ {
- b[i], b[n-1-i] = b[n-1-i], b[i]
- }
- }
- bprint_rune :: proc(buf: ^[]byte, r: rune) {
- b, n := utf8.encode_rune(r)
- bprint_string(buf, b[:n] as string)
- }
- bprint_space :: proc(buf: ^[]byte) { bprint_rune(buf, ' '); }
- bprint_nl :: proc(buf: ^[]byte) { bprint_rune(buf, '\n'); }
- __NUM_TO_CHAR_TABLE := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$"
- bprint_bool :: proc(buffer: ^[]byte, b : bool) {
- if b {
- bprint_string(buffer, "true")
- } else {
- bprint_string(buffer, "false")
- }
- }
- bprint_pointer :: proc(buffer: ^[]byte, p: rawptr) #inline {
- bprint_string(buffer, "0x")
- bprint_u64(buffer, p as uint as u64)
- }
- bprint_f16 :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 4); }
- bprint_f32 :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 7); }
- bprint_f64 :: proc(buffer: ^[]byte, f: f64) #inline { print__f64(buffer, f as f64, 16); }
- bprint_u64 :: proc(buffer: ^[]byte, value: u64) {
- i := value
- buf: [20]byte
- len := 0
- if i == 0 {
- buf[len] = '0'
- len++
- }
- for i > 0 {
- buf[len] = __NUM_TO_CHAR_TABLE[i % 10]
- len++
- i /= 10
- }
- byte_reverse(buf[:len])
- bprint_string(buffer, buf[:len] as string)
- }
- bprint_i64 :: proc(buffer: ^[]byte, value: i64) {
- // TODO(bill): Cleanup printing
- i := value
- if i < 0 {
- i = -i
- bprint_rune(buffer, '-')
- }
- bprint_u64(buffer, i as u64)
- }
- /*
- bprint_u128 :: proc(buffer: ^[]byte, value: u128) {
- a := value transmute [2]u64
- if a[1] != 0 {
- bprint_u64(buffer, a[1])
- }
- bprint_u64(buffer, a[0])
- }
- bprint_i128 :: proc(buffer: ^[]byte, value: i128) {
- i := value
- if i < 0 {
- i = -i
- bprint_rune(buffer, '-')
- }
- bprint_u128(buffer, i as u128)
- }
- */
- print__f64 :: proc(buffer: ^[]byte, value: f64, decimal_places: int) {
- f := value
- if f == 0 {
- bprint_rune(buffer, '0')
- return
- }
- if f < 0 {
- bprint_rune(buffer, '-')
- f = -f
- }
- i := f as u64
- bprint_u64(buffer, i)
- f -= i as f64
- bprint_rune(buffer, '.')
- mult: f64 = 10.0
- for ; decimal_places >= 0; decimal_places-- {
- i = (f * mult) as u64
- bprint_u64(buffer, i as u64)
- f -= i as f64 / mult
- mult *= 10
- }
- }
- bprint_type :: proc(buf: ^[]byte, ti: ^Type_Info) {
- if ti == nil {
- return
- }
- using Type_Info
- match type info : ti {
- case Named:
- bprint_string(buf, info.name)
- case Integer:
- match {
- case ti == type_info(int):
- bprint_string(buf, "int")
- case ti == type_info(uint):
- bprint_string(buf, "uint")
- default:
- if info.signed {
- bprint_string(buf, "i")
- } else {
- bprint_string(buf, "u")
- }
- bprint_u64(buf, 8*info.size as u64)
- }
- case Float:
- match info.size {
- case 4: bprint_string(buf, "f32")
- case 8: bprint_string(buf, "f64")
- }
- case String: bprint_string(buf, "string")
- case Boolean: bprint_string(buf, "bool")
- case Pointer:
- if info.elem == nil {
- bprint_string(buf, "rawptr")
- } else {
- bprint_string(buf, "^")
- bprint_type(buf, info.elem)
- }
- case Maybe:
- bprint_string(buf, "?")
- bprint_type(buf, info.elem)
- case Procedure:
- bprint_string(buf, "proc")
- if info.params == nil {
- bprint_string(buf, "()")
- } else {
- count := (info.params as ^Tuple).fields.count
- if count == 1 { bprint_string(buf, "("); }
- bprint_type(buf, info.params)
- if count == 1 { bprint_string(buf, ")"); }
- }
- if info.results != nil {
- bprint_string(buf, " -> ")
- bprint_type(buf, info.results)
- }
- case Tuple:
- count := info.fields.count
- if count != 1 { bprint_string(buf, "("); }
- for i := 0; i < count; i++ {
- if i > 0 { bprint_string(buf, ", "); }
- f := info.fields[i]
- if f.name.count > 0 {
- bprint_string(buf, f.name)
- bprint_string(buf, ": ")
- }
- bprint_type(buf, f.type_info)
- }
- if count != 1 { bprint_string(buf, ")"); }
- case Array:
- bprint_string(buf, "[")
- bprint_i64(buf, info.count as i64)
- bprint_string(buf, "]")
- bprint_type(buf, info.elem)
- case Slice:
- bprint_string(buf, "[")
- bprint_string(buf, "]")
- bprint_type(buf, info.elem)
- case Vector:
- bprint_string(buf, "[vector ")
- bprint_i64(buf, info.count as i64)
- bprint_string(buf, "]")
- bprint_type(buf, info.elem)
- case Struct:
- bprint_string(buf, "struct ")
- if info.packed { bprint_string(buf, "#packed "); }
- if info.ordered { bprint_string(buf, "#ordered "); }
- bprint_string(buf, "{")
- for i := 0; i < info.fields.count; i++ {
- if i > 0 {
- bprint_string(buf, ", ")
- }
- bprint_any(buf, info.fields[i].name)
- bprint_string(buf, ": ")
- bprint_type(buf, info.fields[i].type_info)
- }
- bprint_string(buf, "}")
- case Union:
- bprint_string(buf, "union {")
- for i := 0; i < info.fields.count; i++ {
- if i > 0 {
- bprint_string(buf, ", ")
- }
- bprint_any(buf, info.fields[i].name)
- bprint_string(buf, ": ")
- bprint_type(buf, info.fields[i].type_info)
- }
- bprint_string(buf, "}")
- case Raw_Union:
- bprint_string(buf, "raw_union {")
- for i := 0; i < info.fields.count; i++ {
- if i > 0 {
- bprint_string(buf, ", ")
- }
- bprint_any(buf, info.fields[i].name)
- bprint_string(buf, ": ")
- bprint_type(buf, info.fields[i].type_info)
- }
- bprint_string(buf, "}")
- case Enum:
- bprint_string(buf, "enum ")
- bprint_type(buf, info.base)
- bprint_string(buf, "{}")
- }
- }
- make_any :: proc(type_info: ^Type_Info, data: rawptr) -> any {
- a: any
- a.type_info = type_info
- a.data = data
- return a
- }
- bprint_any :: proc(buf: ^[]byte, arg: any) {
- if arg.type_info == nil {
- bprint_string(buf, "<nil>")
- return
- }
- if arg.data == nil {
- bprint_string(buf, "<nil>")
- return
- }
- using Type_Info
- match type info : arg.type_info {
- case Named:
- a := make_any(info.base, arg.data)
- match type b : info.base {
- case Struct:
- bprint_string(buf, info.name)
- bprint_string(buf, "{")
- for i := 0; i < b.fields.count; i++ {
- f := b.fields[i]
- if i > 0 {
- bprint_string(buf, ", ")
- }
- bprint_string(buf, f.name)
- // bprint_any(buf, f.offset)
- bprint_string(buf, " = ")
- data := arg.data as ^byte + f.offset
- bprint_any(buf, make_any(f.type_info, data))
- }
- bprint_string(buf, "}")
- default:
- bprint_any(buf, a)
- }
- case Integer:
- match type i : arg {
- case i8: bprint_i64(buf, i as i64)
- case u8: bprint_u64(buf, i as u64)
- case i16: bprint_i64(buf, i as i64)
- case u16: bprint_u64(buf, i as u64)
- case i32: bprint_i64(buf, i as i64)
- case u32: bprint_u64(buf, i as u64)
- case i64: bprint_i64(buf, i)
- case u64: bprint_u64(buf, i)
- // case i128: bprint_i128(buf, i)
- // case u128: bprint_u128(buf, i)
- case int: bprint_i64(buf, i as i64)
- case uint: bprint_u64(buf, i as u64)
- }
- case Float:
- match type f : arg {
- // case f16: bprint_f64(buf, f as f64)
- case f32: bprint_f32(buf, f)
- case f64: bprint_f64(buf, f)
- // case f128: bprint_f64(buf, f as f64)
- }
- case String:
- match type s : arg {
- case string: bprint_string(buf, s)
- }
- case Boolean:
- match type b : arg {
- case bool: bprint_bool(buf, b)
- }
- case Pointer:
- match type p : arg {
- case ^Type_Info: bprint_type(buf, p)
- default: bprint_pointer(buf, (arg.data as ^rawptr)^)
- }
- case Maybe:
- size := mem.size_of_type_info(info.elem)
- data := slice_ptr(arg.data as ^byte, size+1)
- if data[size] != 0 {
- bprint_any(buf, make_any(info.elem, arg.data))
- } else {
- bprint_string(buf, "nil")
- }
- case Enum:
- value: i64 = 0
- match type i : make_any(info.base, arg.data) {
- case i8: value = i as i64
- case i16: value = i as i64
- case i32: value = i as i64
- case i64: value = i as i64
- case u8: value = i as i64
- case u16: value = i as i64
- case u32: value = i as i64
- case u64: value = i as i64
- }
- bprint_string(buf, __enum_to_string(arg.type_info, value))
- case Array:
- bprintf(buf, "[%]%{", info.count, info.elem)
- defer bprint_string(buf, "}")
- for i := 0; i < info.count; i++ {
- if i > 0 {
- bprint_string(buf, ", ")
- }
- data := arg.data as ^byte + i*info.elem_size
- bprint_any(buf, make_any(info.elem, data))
- }
- case Slice:
- slice := arg.data as ^[]byte
- bprintf(buf, "[]%{", info.elem)
- defer bprint_string(buf, "}")
- for i := 0; i < slice.count; i++ {
- if i > 0 {
- bprint_string(buf, ", ")
- }
- data := slice.data + i*info.elem_size
- bprint_any(buf, make_any(info.elem, data))
- }
- case Vector:
- is_bool :: proc(type_info: ^Type_Info) -> bool {
- match type info : type_info {
- case Named:
- return is_bool(info.base)
- case Boolean:
- return true
- }
- return false
- }
- bprintf(buf, "[vector %]%{", info.count, info.elem)
- defer bprint_string(buf, "}")
- if is_bool(info.elem) {
- return
- }
- for i := 0; i < info.count; i++ {
- if i > 0 {
- bprint_string(buf, ", ")
- }
- data := arg.data as ^byte + i*info.elem_size
- bprint_any(buf, make_any(info.elem, data))
- }
- case Struct:
- bprintf(buf, "%{", arg.type_info)
- defer bprint_string(buf, "}")
- for i := 0; i < info.fields.count; i++ {
- if i > 0 {
- bprint_string(buf, ", ")
- }
- bprint_string(buf, info.fields[i].name)
- bprint_string(buf, " = ")
- data := arg.data as ^byte + info.fields[i].offset
- ti := info.fields[i].type_info
- bprint_any(buf, make_any(ti, data))
- }
- case Union:
- bprint_string(buf, "(union)")
- case Raw_Union:
- bprint_string(buf, "(raw_union)")
- case Procedure:
- bprint_type(buf, arg.type_info)
- bprint_string(buf, " @ ")
- bprint_pointer(buf, (arg.data as ^rawptr)^)
- }
- }
- bprintf :: proc(buf: ^[]byte, fmt: string, args: ..any) -> int {
- is_digit :: proc(r: rune) -> bool #inline {
- return '0' <= r && r <= '9'
- }
- parse_int :: proc(s: string, offset: int) -> (int, int) {
- result := 0
- for ; offset < s.count; offset++ {
- c := s[offset] as rune
- if !is_digit(c) {
- break
- }
- result *= 10
- result += (c - '0') as int
- }
- return result, offset
- }
- prev := 0
- implicit_index := 0
- for i := 0; i < fmt.count; i++ {
- r := fmt[i] as rune
- index := implicit_index
- if r != '%' {
- continue
- }
- bprint_string(buf, fmt[prev:i])
- i++; // Skip %
- if i < fmt.count {
- next := fmt[i] as rune
- if next == '%' {
- bprint_string(buf, "%")
- i++
- prev = i
- continue
- }
- if is_digit(next) {
- index, i = parse_int(fmt, i)
- }
- }
- if 0 <= index && index < args.count {
- bprint_any(buf, args[index])
- implicit_index = index+1
- } else {
- // TODO(bill): Error check index out bounds
- bprint_string(buf, "<invalid>")
- }
- prev = i
- }
- bprint_string(buf, fmt[prev:])
- return buf.count
- }
- bprint :: proc(buf: ^[]byte, args: ..any) -> int {
- is_type_string :: proc(info: ^Type_Info) -> bool {
- using Type_Info
- if info == nil {
- return false
- }
- match type i : type_info_base(info) {
- case String:
- return true
- }
- return false
- }
- prev_string := false
- for i := 0; i < args.count; i++ {
- arg := args[i]
- is_string := arg.data != nil && is_type_string(arg.type_info)
- if i > 0 && !is_string && !prev_string {
- bprint_space(buf)
- }
- bprint_any(buf, arg)
- prev_string = is_string
- }
- return buf.count
- }
- bprintln :: proc(buf: ^[]byte, args: ..any) -> int {
- for i := 0; i < args.count; i++ {
- if i > 0 {
- append(buf, ' ')
- }
- bprint_any(buf, args[i])
- }
- bprint_nl(buf)
- return buf.count
- }
|