mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-30 18:02:02 +00:00
270 lines
6.4 KiB
Odin
270 lines
6.4 KiB
Odin
// File contains implementations of the Orca API that are defined as macros in Orca.
|
|
|
|
package 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)
|
|
}
|