macros.odin 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. package orca
  2. // Implementations of the `Orca` API that are defined as macros in Orca.
  3. ////////////////////////////////////////////////////////////////////////////////
  4. // Helpers for logging, asserting and aborting.
  5. ////////////////////////////////////////////////////////////////////////////////
  6. log_error :: proc "contextless" (msg: cstring, loc := #caller_location) {
  7. log_ext(
  8. .ERROR,
  9. cstring(raw_data(loc.procedure)),
  10. cstring(raw_data(loc.file_path)),
  11. loc.line,
  12. msg,
  13. )
  14. }
  15. log_warning :: proc "contextless" (msg: cstring, loc := #caller_location) {
  16. log_ext(
  17. .WARNING,
  18. cstring(raw_data(loc.procedure)),
  19. cstring(raw_data(loc.file_path)),
  20. loc.line,
  21. msg,
  22. )
  23. }
  24. log_info :: proc "contextless" (msg: cstring, loc := #caller_location) {
  25. log_ext(
  26. .INFO,
  27. cstring(raw_data(loc.procedure)),
  28. cstring(raw_data(loc.file_path)),
  29. loc.line,
  30. msg,
  31. )
  32. }
  33. abort :: proc "contextless" (msg: cstring, loc := #caller_location) {
  34. abort_ext(cstring(raw_data(loc.procedure)), cstring(raw_data(loc.file_path)), loc.line, msg)
  35. }
  36. ////////////////////////////////////////////////////////////////////////////////
  37. // Types and helpers for doubly-linked lists.
  38. ////////////////////////////////////////////////////////////////////////////////
  39. // Get the entry for a given list element.
  40. list_entry :: proc "contextless" (elt: ^list_elt, $T: typeid, $member: string) -> ^T {
  41. return container_of(elt, T, member)
  42. }
  43. // Get the next entry in a list.
  44. list_next_entry :: proc "contextless" (
  45. list: ^list,
  46. elt: ^list_elt,
  47. $T: typeid,
  48. $member: string,
  49. ) -> ^T {
  50. if elt.next != list.last {
  51. return list_entry(elt.next, T, member)
  52. }
  53. return nil
  54. }
  55. // Get the previous entry in a list.
  56. list_prev_entry :: proc "contextless" (
  57. list: ^list,
  58. elt: ^list_elt,
  59. $T: typeid,
  60. $member: string,
  61. ) -> ^T {
  62. if elt.prev != list.last {
  63. return list_entry(elt.prev, T, member)
  64. }
  65. return nil
  66. }
  67. // Same as `list_entry` but `elt` might be `nil`.
  68. list_checked_entry :: proc "contextless" (elt: ^list_elt, $T: typeid, $member: string) -> ^T {
  69. if elt != nil {
  70. return list_entry(elt, T, member)
  71. }
  72. return nil
  73. }
  74. list_first_entry :: proc "contextless" (list: ^list, $T: typeid, $member: string) -> ^T {
  75. return list_checked_entry(list.first, T, member)
  76. }
  77. list_last_entry :: proc "contextless" (list: ^list, $T: typeid, $member: string) -> ^T {
  78. return list_checked_entry(list.last, T, member)
  79. }
  80. // Example:
  81. //
  82. // _elt: ^list_elt
  83. // for elt in oc.list_for(list, &_elt, int, "elt") {
  84. // }
  85. list_for :: proc "contextless" (
  86. list: ^list,
  87. elt: ^^list_elt,
  88. $T: typeid,
  89. $member: string,
  90. ) -> (
  91. ^T,
  92. bool,
  93. ) {
  94. if elt == nil {
  95. assert_fail(
  96. #file,
  97. #procedure,
  98. #line,
  99. "elt != nil",
  100. "misuse of `list_for`, expected `elt` to not be nil",
  101. )
  102. }
  103. if elt^ == nil {
  104. elt^ = list.first
  105. entry := list_checked_entry(elt^, T, member)
  106. return entry, entry != nil
  107. }
  108. elt^ = elt^.next
  109. entry := list_checked_entry(elt^, T, member)
  110. return entry, entry != nil
  111. }
  112. list_iter :: list_for
  113. list_for_reverse :: proc "contextless" (
  114. list: ^list,
  115. elt: ^^list_elt,
  116. $T: typeid,
  117. $member: string,
  118. ) -> (
  119. ^T,
  120. bool,
  121. ) {
  122. if elt^ == nil {
  123. elt^ = list.last
  124. entry := list_checked_entry(elt^, T, member)
  125. return entry, entry != nil
  126. }
  127. elt^ = elt^.prev
  128. entry := list_checked_entry(elt^, T, member)
  129. return entry, entry != nil
  130. }
  131. list_iter_reverse :: list_for_reverse
  132. list_pop_front_entry :: proc "contextless" (list: ^list, $T: typeid, $member: string) -> ^T {
  133. if list_empty(list^) {
  134. return nil
  135. }
  136. return list_entry(list_pop_front(list), T, member)
  137. }
  138. list_pop_back_entry :: proc "contextless" (list: ^list, $T: typeid, $member: string) -> ^T {
  139. if list_empty(list^) {
  140. return nil
  141. }
  142. return list_entry(list_pop_back(list), T, member)
  143. }
  144. ////////////////////////////////////////////////////////////////////////////////
  145. // Base allocator and memory arenas.
  146. ////////////////////////////////////////////////////////////////////////////////
  147. arena_push_type :: proc "contextless" (arena: ^arena, $T: typeid) -> ^T {
  148. return (^T)(arena_push_aligned(arena, size_of(T), align_of(T)))
  149. }
  150. arena_push_array :: proc "contextless" (arena: ^arena, $T: typeid, count: u64) -> []T {
  151. return ([^]T)(arena_push_aligned(arena, size_of(T) * count, align_of(T)))[:count]
  152. }
  153. scratch_end :: arena_scope_end
  154. ////////////////////////////////////////////////////////////////////////////////
  155. // String slices and string lists.
  156. ////////////////////////////////////////////////////////////////////////////////
  157. str8_list_first :: proc "contextless" (sl: ^str8_list) -> str8 {
  158. if list_empty(sl.list) {
  159. return ""
  160. }
  161. return list_first_entry(&sl.list, str8_elt, "listElt").string
  162. }
  163. str8_list_last :: proc "contextless" (sl: ^str8_list) -> str8 {
  164. if list_empty(sl.list) {
  165. return ""
  166. }
  167. return list_last_entry(&sl.list, str8_elt, "listElt").string
  168. }
  169. str8_list_for :: proc "contextless" (list: ^str8_list, elt: ^^list_elt) -> (^str8_elt, bool) {
  170. return list_for(&list.list, elt, str8_elt, "listElt")
  171. }
  172. str8_list_iter :: str8_list_for
  173. str8_list_empty :: proc "contextless" (list: str8_list) -> bool {
  174. return list_empty(list.list)
  175. }
  176. str16_list_first :: proc "contextless" (sl: ^str16_list) -> str16 {
  177. if list_empty(sl.list) {
  178. return {}
  179. }
  180. return list_first_entry(&sl.list, str16_elt, "listElt").string
  181. }
  182. str16_list_last :: proc "contextless" (sl: ^str16_list) -> str16 {
  183. if list_empty(sl.list) {
  184. return {}
  185. }
  186. return list_last_entry(&sl.list, str16_elt, "listElt").string
  187. }
  188. str16_list_for :: proc "contextless" (list: ^str16_list, elt: ^^list_elt) -> (^str16_elt, bool) {
  189. return list_for(&list.list, elt, str16_elt, "listElt")
  190. }
  191. str32_list_first :: proc "contextless" (sl: ^str32_list) -> str32 {
  192. if list_empty(sl.list) {
  193. return {}
  194. }
  195. return list_first_entry(&sl.list, str32_elt, "listElt").string
  196. }
  197. str32_list_last :: proc "contextless" (sl: ^str32_list) -> str32 {
  198. if list_empty(sl.list) {
  199. return {}
  200. }
  201. return list_last_entry(&sl.list, str32_elt, "listElt").string
  202. }
  203. str32_list_for :: proc "contextless" (list: ^str32_list, elt: ^^list_elt) -> (^str32_elt, bool) {
  204. return list_for(&list.list, elt, str32_elt, "listElt")
  205. }
  206. @(deferred_none = ui_box_end)
  207. ui_container :: proc "contextless" (name: string) -> ^ui_box {
  208. return ui_box_begin_str8(name)
  209. }
  210. @(deferred_none = ui_menu_end)
  211. ui_menu :: proc "contextless" (key, name: string) {
  212. ui_menu_begin_str8(key, name)
  213. }
  214. @(deferred_none = ui_menu_bar_end)
  215. ui_menu_bar :: proc "contextless" (key: string) {
  216. ui_menu_bar_begin_str8(key)
  217. }