package orca // Implementations of the `Orca` API that are defined as macros in Orca. //////////////////////////////////////////////////////////////////////////////// // Helpers for logging, asserting and aborting. //////////////////////////////////////////////////////////////////////////////// log_error :: proc "contextless" (msg: cstring, loc := #caller_location) { log_ext( .ERROR, cstring(raw_data(loc.procedure)), cstring(raw_data(loc.file_path)), loc.line, msg, ) } log_warning :: proc "contextless" (msg: cstring, loc := #caller_location) { log_ext( .WARNING, cstring(raw_data(loc.procedure)), cstring(raw_data(loc.file_path)), loc.line, msg, ) } log_info :: proc "contextless" (msg: cstring, loc := #caller_location) { log_ext( .INFO, cstring(raw_data(loc.procedure)), cstring(raw_data(loc.file_path)), loc.line, msg, ) } abort :: proc "contextless" (msg: cstring, loc := #caller_location) { abort_ext(cstring(raw_data(loc.procedure)), cstring(raw_data(loc.file_path)), loc.line, msg) } //////////////////////////////////////////////////////////////////////////////// // Types and helpers for doubly-linked lists. //////////////////////////////////////////////////////////////////////////////// // Get the entry for a given list element. list_entry :: proc "contextless" (elt: ^list_elt, $T: typeid, $member: string) -> ^T { return container_of(elt, T, member) } // Get the next entry in a list. list_next_entry :: proc "contextless" ( list: ^list, elt: ^list_elt, $T: typeid, $member: string, ) -> ^T { if elt.next != list.last { return list_entry(elt.next, T, member) } return nil } // Get the previous entry in a list. list_prev_entry :: proc "contextless" ( list: ^list, elt: ^list_elt, $T: typeid, $member: string, ) -> ^T { if elt.prev != list.last { return list_entry(elt.prev, T, member) } return nil } // Same as `list_entry` but `elt` might be `nil`. list_checked_entry :: proc "contextless" (elt: ^list_elt, $T: typeid, $member: string) -> ^T { if elt != nil { return list_entry(elt, T, member) } return nil } list_first_entry :: proc "contextless" (list: ^list, $T: typeid, $member: string) -> ^T { return list_checked_entry(list.first, T, member) } list_last_entry :: proc "contextless" (list: ^list, $T: typeid, $member: string) -> ^T { return list_checked_entry(list.last, T, member) } // Example: // // _elt: ^list_elt // for elt in oc.list_for(list, &_elt, int, "elt") { // } list_for :: proc "contextless" ( list: ^list, elt: ^^list_elt, $T: typeid, $member: string, ) -> ( ^T, bool, ) { if elt == nil { assert_fail( #file, #procedure, #line, "elt != nil", "misuse of `list_for`, expected `elt` to not be nil", ) } if elt^ == nil { elt^ = list.first entry := list_checked_entry(elt^, T, member) return entry, entry != nil } elt^ = elt^.next entry := list_checked_entry(elt^, T, member) return entry, entry != nil } list_iter :: list_for list_for_reverse :: proc "contextless" ( list: ^list, elt: ^^list_elt, $T: typeid, $member: string, ) -> ( ^T, bool, ) { if elt^ == nil { elt^ = list.last entry := list_checked_entry(elt^, T, member) return entry, entry != nil } elt^ = elt^.prev entry := list_checked_entry(elt^, T, member) return entry, entry != nil } list_iter_reverse :: list_for_reverse list_pop_front_entry :: proc "contextless" (list: ^list, $T: typeid, $member: string) -> ^T { if list_empty(list^) { return nil } return list_entry(list_pop_front(list), T, member) } list_pop_back_entry :: proc "contextless" (list: ^list, $T: typeid, $member: string) -> ^T { if list_empty(list^) { return nil } return list_entry(list_pop_back(list), T, member) } //////////////////////////////////////////////////////////////////////////////// // Base allocator and memory arenas. //////////////////////////////////////////////////////////////////////////////// arena_push_type :: proc "contextless" (arena: ^arena, $T: typeid) -> ^T { return (^T)(arena_push_aligned(arena, size_of(T), align_of(T))) } arena_push_array :: proc "contextless" (arena: ^arena, $T: typeid, count: u64) -> []T { return ([^]T)(arena_push_aligned(arena, size_of(T) * count, align_of(T)))[:count] } scratch_end :: arena_scope_end //////////////////////////////////////////////////////////////////////////////// // String slices and string lists. //////////////////////////////////////////////////////////////////////////////// str8_list_first :: proc "contextless" (sl: ^str8_list) -> str8 { if list_empty(sl.list) { return "" } return list_first_entry(&sl.list, str8_elt, "listElt").string } str8_list_last :: proc "contextless" (sl: ^str8_list) -> str8 { if list_empty(sl.list) { return "" } return list_last_entry(&sl.list, str8_elt, "listElt").string } str8_list_for :: proc "contextless" (list: ^str8_list, elt: ^^list_elt) -> (^str8_elt, bool) { return list_for(&list.list, elt, str8_elt, "listElt") } str8_list_iter :: str8_list_for str8_list_empty :: proc "contextless" (list: str8_list) -> bool { return list_empty(list.list) } str16_list_first :: proc "contextless" (sl: ^str16_list) -> str16 { if list_empty(sl.list) { return {} } return list_first_entry(&sl.list, str16_elt, "listElt").string } str16_list_last :: proc "contextless" (sl: ^str16_list) -> str16 { if list_empty(sl.list) { return {} } return list_last_entry(&sl.list, str16_elt, "listElt").string } str16_list_for :: proc "contextless" (list: ^str16_list, elt: ^^list_elt) -> (^str16_elt, bool) { return list_for(&list.list, elt, str16_elt, "listElt") } str32_list_first :: proc "contextless" (sl: ^str32_list) -> str32 { if list_empty(sl.list) { return {} } return list_first_entry(&sl.list, str32_elt, "listElt").string } str32_list_last :: proc "contextless" (sl: ^str32_list) -> str32 { if list_empty(sl.list) { return {} } return list_last_entry(&sl.list, str32_elt, "listElt").string } str32_list_for :: proc "contextless" (list: ^str32_list, elt: ^^list_elt) -> (^str32_elt, bool) { return list_for(&list.list, elt, str32_elt, "listElt") } @(deferred_none = ui_box_end) ui_container :: proc "contextless" (name: string) -> ^ui_box { return ui_box_begin_str8(name) } @(deferred_none = ui_menu_end) ui_menu :: proc "contextless" (key, name: string) { ui_menu_begin_str8(key, name) } @(deferred_none = ui_menu_bar_end) ui_menu_bar :: proc "contextless" (key: string) { ui_menu_bar_begin_str8(key) }