core_builtin.odin 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010
  1. package runtime
  2. import "base:intrinsics"
  3. @builtin
  4. Maybe :: union($T: typeid) {T}
  5. /*
  6. Recovers the containing/parent struct from a pointer to one of its fields.
  7. Works by "walking back" to the struct's starting address using the offset between the field and the struct.
  8. Inputs:
  9. - ptr: Pointer to the field of a container struct
  10. - T: The type of the container struct
  11. - field_name: The name of the field in the `T` struct
  12. Returns:
  13. - A pointer to the container struct based on a pointer to a field in it
  14. Example:
  15. package container_of
  16. import "base:runtime"
  17. Node :: struct {
  18. value: int,
  19. prev: ^Node,
  20. next: ^Node,
  21. }
  22. main :: proc() {
  23. node: Node
  24. field_ptr := &node.next
  25. container_struct_ptr: ^Node = runtime.container_of(field_ptr, Node, "next")
  26. assert(container_struct_ptr == &node)
  27. assert(uintptr(field_ptr) - uintptr(container_struct_ptr) == size_of(node.value) + size_of(node.prev))
  28. }
  29. Output:
  30. ^Node
  31. */
  32. @(builtin, require_results)
  33. container_of :: #force_inline proc "contextless" (ptr: $P/^$Field_Type, $T: typeid, $field_name: string) -> ^T
  34. where intrinsics.type_has_field(T, field_name),
  35. intrinsics.type_field_type(T, field_name) == Field_Type {
  36. offset :: offset_of_by_string(T, field_name)
  37. return (^T)(uintptr(ptr) - offset) if ptr != nil else nil
  38. }
  39. when !NO_DEFAULT_TEMP_ALLOCATOR {
  40. @thread_local global_default_temp_allocator_data: Default_Temp_Allocator
  41. }
  42. @(builtin, disabled=NO_DEFAULT_TEMP_ALLOCATOR)
  43. init_global_temporary_allocator :: proc(size: int, backup_allocator := context.allocator) {
  44. when !NO_DEFAULT_TEMP_ALLOCATOR {
  45. default_temp_allocator_init(&global_default_temp_allocator_data, size, backup_allocator)
  46. }
  47. }
  48. // `copy_slice` is a built-in procedure that copies elements from a source slice `src` to a destination slice `dst`.
  49. // The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum
  50. // of len(src) and len(dst).
  51. //
  52. // Prefer the procedure group `copy`.
  53. @builtin
  54. copy_slice :: proc "contextless" (dst, src: $T/[]$E) -> int {
  55. n := max(0, min(len(dst), len(src)))
  56. if n > 0 {
  57. intrinsics.mem_copy(raw_data(dst), raw_data(src), n*size_of(E))
  58. }
  59. return n
  60. }
  61. // `copy_from_string` is a built-in procedure that copies elements from a source string `src` to a destination slice `dst`.
  62. // The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum
  63. // of len(src) and len(dst).
  64. //
  65. // Prefer the procedure group `copy`.
  66. @builtin
  67. copy_from_string :: proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int {
  68. n := max(0, min(len(dst), len(src)))
  69. if n > 0 {
  70. intrinsics.mem_copy(raw_data(dst), raw_data(src), n)
  71. }
  72. return n
  73. }
  74. // `copy` is a built-in procedure that copies elements from a source slice/string `src` to a destination slice `dst`.
  75. // The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum
  76. // of len(src) and len(dst).
  77. @builtin
  78. copy :: proc{copy_slice, copy_from_string}
  79. // `unordered_remove` removed the element at the specified `index`. It does so by replacing the current end value
  80. // with the old value, and reducing the length of the dynamic array by 1.
  81. //
  82. // Note: This is an O(1) operation.
  83. // Note: If you want the elements to remain in their order, use `ordered_remove`.
  84. // Note: If the index is out of bounds, this procedure will panic.
  85. @builtin
  86. unordered_remove :: proc(array: ^$D/[dynamic]$T, #any_int index: int, loc := #caller_location) #no_bounds_check {
  87. bounds_check_error_loc(loc, index, len(array))
  88. n := len(array)-1
  89. if index != n {
  90. array[index] = array[n]
  91. }
  92. (^Raw_Dynamic_Array)(array).len -= 1
  93. }
  94. // `ordered_remove` removed the element at the specified `index` whilst keeping the order of the other elements.
  95. //
  96. // Note: This is an O(N) operation.
  97. // Note: If the elements do not have to remain in their order, prefer `unordered_remove`.
  98. // Note: If the index is out of bounds, this procedure will panic.
  99. @builtin
  100. ordered_remove :: proc(array: ^$D/[dynamic]$T, #any_int index: int, loc := #caller_location) #no_bounds_check {
  101. bounds_check_error_loc(loc, index, len(array))
  102. if index+1 < len(array) {
  103. copy(array[index:], array[index+1:])
  104. }
  105. (^Raw_Dynamic_Array)(array).len -= 1
  106. }
  107. // `remove_range` removes a range of elements specified by the range `lo` and `hi`, whilst keeping the order of the other elements.
  108. //
  109. // Note: This is an O(N) operation.
  110. // Note: If the range is out of bounds, this procedure will panic.
  111. @builtin
  112. remove_range :: proc(array: ^$D/[dynamic]$T, #any_int lo, hi: int, loc := #caller_location) #no_bounds_check {
  113. slice_expr_error_lo_hi_loc(loc, lo, hi, len(array))
  114. n := max(hi-lo, 0)
  115. if n > 0 {
  116. if hi != len(array) {
  117. copy(array[lo:], array[hi:])
  118. }
  119. (^Raw_Dynamic_Array)(array).len -= n
  120. }
  121. }
  122. // `pop` will remove and return the end value of dynamic array `array` and reduces the length of `array` by 1.
  123. //
  124. // Note: If the dynamic array has no elements (`len(array) == 0`), this procedure will panic.
  125. @builtin
  126. pop :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check {
  127. assert(len(array) > 0, loc=loc)
  128. res = array[len(array)-1]
  129. (^Raw_Dynamic_Array)(array).len -= 1
  130. return res
  131. }
  132. // `pop_safe` trys to remove and return the end value of dynamic array `array` and reduces the length of `array` by 1.
  133. // If the operation is not possible, it will return false.
  134. @builtin
  135. pop_safe :: proc "contextless" (array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check {
  136. if len(array) == 0 {
  137. return
  138. }
  139. res, ok = array[len(array)-1], true
  140. (^Raw_Dynamic_Array)(array).len -= 1
  141. return
  142. }
  143. // `pop_front` will remove and return the first value of dynamic array `array` and reduces the length of `array` by 1.
  144. //
  145. // Note: If the dynamic array as no elements (`len(array) == 0`), this procedure will panic.
  146. @builtin
  147. pop_front :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check {
  148. assert(len(array) > 0, loc=loc)
  149. res = array[0]
  150. if len(array) > 1 {
  151. copy(array[0:], array[1:])
  152. }
  153. (^Raw_Dynamic_Array)(array).len -= 1
  154. return res
  155. }
  156. // `pop_front_safe` trys to return and remove the first value of dynamic array `array` and reduces the length of `array` by 1.
  157. // If the operation is not possible, it will return false.
  158. @builtin
  159. pop_front_safe :: proc "contextless" (array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check {
  160. if len(array) == 0 {
  161. return
  162. }
  163. res, ok = array[0], true
  164. if len(array) > 1 {
  165. copy(array[0:], array[1:])
  166. }
  167. (^Raw_Dynamic_Array)(array).len -= 1
  168. return
  169. }
  170. // `clear` will set the length of a passed dynamic array or map to `0`
  171. @builtin
  172. clear :: proc{
  173. clear_dynamic_array,
  174. clear_map,
  175. clear_soa_dynamic_array,
  176. }
  177. // `reserve` will try to reserve memory of a passed dynamic array or map to the requested element count (setting the `cap`).
  178. @builtin
  179. reserve :: proc{
  180. reserve_dynamic_array,
  181. reserve_map,
  182. reserve_soa,
  183. }
  184. @builtin
  185. non_zero_reserve :: proc{
  186. non_zero_reserve_dynamic_array,
  187. non_zero_reserve_soa,
  188. }
  189. // `resize` will try to resize memory of a passed dynamic array to the requested element count (setting the `len`, and possibly `cap`).
  190. @builtin
  191. resize :: proc{
  192. resize_dynamic_array,
  193. resize_soa,
  194. }
  195. @builtin
  196. non_zero_resize :: proc{
  197. non_zero_resize_dynamic_array,
  198. non_zero_resize_soa,
  199. }
  200. // Shrinks the capacity of a dynamic array or map down to the current length, or the given capacity.
  201. @builtin
  202. shrink :: proc{shrink_dynamic_array, shrink_map}
  203. // `free` will try to free the passed pointer, with the given `allocator` if the allocator supports this operation.
  204. @builtin
  205. free :: proc{mem_free}
  206. // `free_all` will try to free/reset all of the memory of the given `allocator` if the allocator supports this operation.
  207. @builtin
  208. free_all :: proc{mem_free_all}
  209. // `delete_string` will try to free the underlying data of the passed string, with the given `allocator` if the allocator supports this operation.
  210. //
  211. // Note: Prefer the procedure group `delete`.
  212. @builtin
  213. delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
  214. return mem_free_with_size(raw_data(str), len(str), allocator, loc)
  215. }
  216. // `delete_cstring` will try to free the underlying data of the passed string, with the given `allocator` if the allocator supports this operation.
  217. //
  218. // Note: Prefer the procedure group `delete`.
  219. @builtin
  220. delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
  221. return mem_free((^byte)(str), allocator, loc)
  222. }
  223. // `delete_dynamic_array` will try to free the underlying data of the passed dynamic array, with the given `allocator` if the allocator supports this operation.
  224. //
  225. // Note: Prefer the procedure group `delete`.
  226. @builtin
  227. delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) -> Allocator_Error {
  228. return mem_free_with_size(raw_data(array), cap(array)*size_of(E), array.allocator, loc)
  229. }
  230. // `delete_slice` will try to free the underlying data of the passed sliced, with the given `allocator` if the allocator supports this operation.
  231. //
  232. // Note: Prefer the procedure group `delete`.
  233. @builtin
  234. delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
  235. return mem_free_with_size(raw_data(array), len(array)*size_of(E), allocator, loc)
  236. }
  237. // `delete_map` will try to free the underlying data of the passed map, with the given `allocator` if the allocator supports this operation.
  238. //
  239. // Note: Prefer the procedure group `delete`.
  240. @builtin
  241. delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error {
  242. return map_free_dynamic(transmute(Raw_Map)m, map_info(T), loc)
  243. }
  244. // `delete` will try to free the underlying data of the passed built-in data structure (string, cstring, dynamic array, slice, or map), with the given `allocator` if the allocator supports this operation.
  245. //
  246. // Note: Prefer `delete` over the specific `delete_*` procedures where possible.
  247. @builtin
  248. delete :: proc{
  249. delete_string,
  250. delete_cstring,
  251. delete_dynamic_array,
  252. delete_slice,
  253. delete_map,
  254. delete_soa_slice,
  255. delete_soa_dynamic_array,
  256. }
  257. // The new built-in procedure allocates memory. The first argument is a type, not a value, and the value
  258. // return is a pointer to a newly allocated value of that type using the specified allocator, default is context.allocator
  259. @(builtin, require_results)
  260. new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) #optional_allocator_error {
  261. return new_aligned(T, align_of(T), allocator, loc)
  262. }
  263. @(require_results)
  264. new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) {
  265. data := mem_alloc_bytes(size_of(T), alignment, allocator, loc) or_return
  266. t = (^T)(raw_data(data))
  267. return
  268. }
  269. @(builtin, require_results)
  270. new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) #optional_allocator_error {
  271. t_data := mem_alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return
  272. t = (^T)(raw_data(t_data))
  273. if t != nil {
  274. t^ = data
  275. }
  276. return
  277. }
  278. DEFAULT_DYNAMIC_ARRAY_CAPACITY :: 8
  279. @(require_results)
  280. make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
  281. make_slice_error_loc(loc, len)
  282. data, err := mem_alloc_bytes(size_of(E)*len, alignment, allocator, loc)
  283. if data == nil && size_of(E) != 0 {
  284. return nil, err
  285. }
  286. s := Raw_Slice{raw_data(data), len}
  287. return transmute(T)s, err
  288. }
  289. // `make_slice` allocates and initializes a slice. Like `new`, the first argument is a type, not a value.
  290. // Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
  291. //
  292. // Note: Prefer using the procedure group `make`.
  293. @(builtin, require_results)
  294. make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
  295. return make_aligned(T, len, align_of(E), allocator, loc)
  296. }
  297. // `make_dynamic_array` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
  298. // Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
  299. //
  300. // Note: Prefer using the procedure group `make`.
  301. @(builtin, require_results)
  302. make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
  303. return make_dynamic_array_len_cap(T, 0, 0, allocator, loc)
  304. }
  305. // `make_dynamic_array_len` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
  306. // Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
  307. //
  308. // Note: Prefer using the procedure group `make`.
  309. @(builtin, require_results)
  310. make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
  311. return make_dynamic_array_len_cap(T, len, len, allocator, loc)
  312. }
  313. // `make_dynamic_array_len_cap` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
  314. // Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
  315. //
  316. // Note: Prefer using the procedure group `make`.
  317. @(builtin, require_results)
  318. make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
  319. err = _make_dynamic_array_len_cap((^Raw_Dynamic_Array)(&array), size_of(E), align_of(E), len, cap, allocator, loc)
  320. return
  321. }
  322. @(require_results)
  323. _make_dynamic_array_len_cap :: proc(array: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (err: Allocator_Error) {
  324. make_dynamic_array_error_loc(loc, len, cap)
  325. array.allocator = allocator // initialize allocator before just in case it fails to allocate any memory
  326. data := mem_alloc_bytes(size_of_elem*cap, align_of_elem, allocator, loc) or_return
  327. use_zero := data == nil && size_of_elem != 0
  328. array.data = raw_data(data)
  329. array.len = 0 if use_zero else len
  330. array.cap = 0 if use_zero else cap
  331. array.allocator = allocator
  332. return
  333. }
  334. // `make_map` allocates and initializes a map. Like `new`, the first argument is a type, not a value.
  335. // Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
  336. //
  337. // Note: Prefer using the procedure group `make`.
  338. @(builtin, require_results)
  339. make_map :: proc($T: typeid/map[$K]$E, #any_int capacity: int = 1<<MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> (m: T, err: Allocator_Error) #optional_allocator_error {
  340. make_map_expr_error_loc(loc, capacity)
  341. context.allocator = allocator
  342. err = reserve_map(&m, capacity, loc)
  343. return
  344. }
  345. // `make_multi_pointer` allocates and initializes a multi-pointer. Like `new`, the first argument is a type, not a value.
  346. // Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
  347. //
  348. // This is "similar" to doing `raw_data(make([]E, len, allocator))`.
  349. //
  350. // Note: Prefer using the procedure group `make`.
  351. @(builtin, require_results)
  352. make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) #optional_allocator_error {
  353. make_slice_error_loc(loc, len)
  354. data := mem_alloc_bytes(size_of(E)*len, align_of(E), allocator, loc) or_return
  355. if data == nil && size_of(E) != 0 {
  356. return
  357. }
  358. mp = cast(T)raw_data(data)
  359. return
  360. }
  361. // `make` built-in procedure allocates and initializes a value of type slice, dynamic array, map, or multi-pointer (only).
  362. //
  363. // Similar to `new`, the first argument is a type, not a value. Unlike new, make's return type is the same as the
  364. // type of its argument, not a pointer to it.
  365. // Make uses the specified allocator, default is context.allocator.
  366. @builtin
  367. make :: proc{
  368. make_slice,
  369. make_dynamic_array,
  370. make_dynamic_array_len,
  371. make_dynamic_array_len_cap,
  372. make_map,
  373. make_multi_pointer,
  374. make_soa_slice,
  375. make_soa_dynamic_array,
  376. make_soa_dynamic_array_len,
  377. make_soa_dynamic_array_len_cap,
  378. }
  379. // `clear_map` will set the length of a passed map to `0`
  380. //
  381. // Note: Prefer the procedure group `clear`
  382. @builtin
  383. clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {
  384. if m == nil {
  385. return
  386. }
  387. map_clear_dynamic((^Raw_Map)(m), map_info(T))
  388. }
  389. // `reserve_map` will try to reserve memory of a passed map to the requested element count (setting the `cap`).
  390. //
  391. // Note: Prefer the procedure group `reserve`
  392. @builtin
  393. reserve_map :: proc(m: ^$T/map[$K]$V, #any_int capacity: int, loc := #caller_location) -> Allocator_Error {
  394. return __dynamic_map_reserve((^Raw_Map)(m), map_info(T), uint(capacity), loc) if m != nil else nil
  395. }
  396. // Shrinks the capacity of a map down to the current length.
  397. //
  398. // Note: Prefer the procedure group `shrink`
  399. @builtin
  400. shrink_map :: proc(m: ^$T/map[$K]$V, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
  401. if m != nil {
  402. return map_shrink_dynamic((^Raw_Map)(m), map_info(T), loc)
  403. }
  404. return
  405. }
  406. // The delete_key built-in procedure deletes the element with the specified key (m[key]) from the map.
  407. // If m is nil, or there is no such element, this procedure is a no-op
  408. @builtin
  409. delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value: V) {
  410. if m != nil {
  411. key := key
  412. old_k, old_v, ok := map_erase_dynamic((^Raw_Map)(m), map_info(T), uintptr(&key))
  413. if ok {
  414. deleted_key = (^K)(old_k)^
  415. deleted_value = (^V)(old_v)^
  416. }
  417. }
  418. return
  419. }
  420. _append_elem :: #force_inline proc(array: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, arg_ptr: rawptr, should_zero: bool, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
  421. if array == nil {
  422. return
  423. }
  424. if array.cap < array.len+1 {
  425. // Same behavior as _append_elems but there's only one arg, so we always just add DEFAULT_DYNAMIC_ARRAY_CAPACITY.
  426. cap := 2 * array.cap + DEFAULT_DYNAMIC_ARRAY_CAPACITY
  427. // do not 'or_return' here as it could be a partial success
  428. err = _reserve_dynamic_array(array, size_of_elem, align_of_elem, cap, should_zero, loc)
  429. }
  430. if array.cap-array.len > 0 {
  431. data := ([^]byte)(array.data)
  432. assert(data != nil, loc=loc)
  433. data = data[array.len*size_of_elem:]
  434. intrinsics.mem_copy_non_overlapping(data, arg_ptr, size_of_elem)
  435. array.len += 1
  436. n = 1
  437. }
  438. return
  439. }
  440. @builtin
  441. append_elem :: proc(array: ^$T/[dynamic]$E, #no_broadcast arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
  442. when size_of(E) == 0 {
  443. (^Raw_Dynamic_Array)(array).len += 1
  444. return 1, nil
  445. } else {
  446. arg := arg
  447. return _append_elem((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), &arg, true, loc=loc)
  448. }
  449. }
  450. @builtin
  451. non_zero_append_elem :: proc(array: ^$T/[dynamic]$E, #no_broadcast arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
  452. when size_of(E) == 0 {
  453. (^Raw_Dynamic_Array)(array).len += 1
  454. return 1, nil
  455. } else {
  456. arg := arg
  457. return _append_elem((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), &arg, false, loc=loc)
  458. }
  459. }
  460. _append_elems :: #force_inline proc(array: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, should_zero: bool, loc := #caller_location, args: rawptr, arg_len: int) -> (n: int, err: Allocator_Error) #optional_allocator_error {
  461. if array == nil {
  462. return 0, nil
  463. }
  464. if arg_len <= 0 {
  465. return 0, nil
  466. }
  467. if array.cap < array.len+arg_len {
  468. cap := 2 * array.cap + max(DEFAULT_DYNAMIC_ARRAY_CAPACITY, arg_len)
  469. // do not 'or_return' here as it could be a partial success
  470. err = _reserve_dynamic_array(array, size_of_elem, align_of_elem, cap, should_zero, loc)
  471. }
  472. arg_len := arg_len
  473. arg_len = min(array.cap-array.len, arg_len)
  474. if arg_len > 0 {
  475. data := ([^]byte)(array.data)
  476. assert(data != nil, loc=loc)
  477. data = data[array.len*size_of_elem:]
  478. intrinsics.mem_copy(data, args, size_of_elem * arg_len) // must be mem_copy (overlapping)
  479. array.len += arg_len
  480. }
  481. return arg_len, err
  482. }
  483. @builtin
  484. append_elems :: proc(array: ^$T/[dynamic]$E, #no_broadcast args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
  485. when size_of(E) == 0 {
  486. a := (^Raw_Dynamic_Array)(array)
  487. a.len += len(args)
  488. return len(args), nil
  489. } else {
  490. return _append_elems((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), true, loc, raw_data(args), len(args))
  491. }
  492. }
  493. @builtin
  494. non_zero_append_elems :: proc(array: ^$T/[dynamic]$E, #no_broadcast args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
  495. when size_of(E) == 0 {
  496. a := (^Raw_Dynamic_Array)(array)
  497. a.len += len(args)
  498. return len(args), nil
  499. } else {
  500. return _append_elems((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), false, loc, raw_data(args), len(args))
  501. }
  502. }
  503. // The append_string built-in procedure appends a string to the end of a [dynamic]u8 like type
  504. _append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, should_zero: bool, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
  505. return _append_elems((^Raw_Dynamic_Array)(array), 1, 1, should_zero, loc, raw_data(arg), len(arg))
  506. }
  507. @builtin
  508. append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
  509. return _append_elem_string(array, arg, true, loc)
  510. }
  511. @builtin
  512. non_zero_append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
  513. return _append_elem_string(array, arg, false, loc)
  514. }
  515. // The append_string built-in procedure appends multiple strings to the end of a [dynamic]u8 like type
  516. @builtin
  517. append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
  518. n_arg: int
  519. for arg in args {
  520. n_arg, err = append(array, ..transmute([]E)(arg), loc=loc)
  521. n += n_arg
  522. if err != nil {
  523. return
  524. }
  525. }
  526. return
  527. }
  528. // The append built-in procedure appends elements to the end of a dynamic array
  529. @builtin append :: proc{
  530. append_elem,
  531. append_elems,
  532. append_elem_string,
  533. append_soa_elem,
  534. append_soa_elems,
  535. }
  536. @builtin non_zero_append :: proc{
  537. non_zero_append_elem,
  538. non_zero_append_elems,
  539. non_zero_append_elem_string,
  540. non_zero_append_soa_elem,
  541. non_zero_append_soa_elems,
  542. }
  543. @builtin
  544. append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
  545. if array == nil {
  546. return 0, nil
  547. }
  548. prev_len := len(array)
  549. resize(array, len(array)+1, loc) or_return
  550. return len(array)-prev_len, nil
  551. }
  552. @builtin
  553. inject_at_elem :: proc(array: ^$T/[dynamic]$E, #any_int index: int, #no_broadcast arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
  554. if array == nil {
  555. return
  556. }
  557. n := max(len(array), index)
  558. m :: 1
  559. new_size := n + m
  560. resize(array, new_size, loc) or_return
  561. when size_of(E) != 0 {
  562. copy(array[index + m:], array[index:])
  563. array[index] = arg
  564. }
  565. ok = true
  566. return
  567. }
  568. @builtin
  569. inject_at_elems :: proc(array: ^$T/[dynamic]$E, #any_int index: int, #no_broadcast args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
  570. if array == nil {
  571. return
  572. }
  573. if len(args) == 0 {
  574. ok = true
  575. return
  576. }
  577. n := max(len(array), index)
  578. m := len(args)
  579. new_size := n + m
  580. resize(array, new_size, loc) or_return
  581. when size_of(E) != 0 {
  582. copy(array[index + m:], array[index:])
  583. copy(array[index:], args)
  584. }
  585. ok = true
  586. return
  587. }
  588. @builtin
  589. inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, #any_int index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
  590. if array == nil {
  591. return
  592. }
  593. if len(arg) == 0 {
  594. ok = true
  595. return
  596. }
  597. n := max(len(array), index)
  598. m := len(arg)
  599. new_size := n + m
  600. resize(array, new_size, loc) or_return
  601. copy(array[index+m:], array[index:])
  602. copy(array[index:], arg)
  603. ok = true
  604. return
  605. }
  606. @builtin inject_at :: proc{inject_at_elem, inject_at_elems, inject_at_elem_string}
  607. @builtin
  608. assign_at_elem :: proc(array: ^$T/[dynamic]$E, #any_int index: int, arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
  609. if index < len(array) {
  610. array[index] = arg
  611. ok = true
  612. } else {
  613. resize(array, index+1, loc) or_return
  614. array[index] = arg
  615. ok = true
  616. }
  617. return
  618. }
  619. @builtin
  620. assign_at_elems :: proc(array: ^$T/[dynamic]$E, #any_int index: int, #no_broadcast args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
  621. new_size := index + len(args)
  622. if len(args) == 0 {
  623. ok = true
  624. } else if new_size < len(array) {
  625. copy(array[index:], args)
  626. ok = true
  627. } else {
  628. resize(array, new_size, loc) or_return
  629. copy(array[index:], args)
  630. ok = true
  631. }
  632. return
  633. }
  634. @builtin
  635. assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, #any_int index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
  636. new_size := index + len(arg)
  637. if len(arg) == 0 {
  638. ok = true
  639. } else if new_size < len(array) {
  640. copy(array[index:], arg)
  641. ok = true
  642. } else {
  643. resize(array, new_size, loc) or_return
  644. copy(array[index:], arg)
  645. ok = true
  646. }
  647. return
  648. }
  649. @builtin assign_at :: proc{assign_at_elem, assign_at_elems, assign_at_elem_string}
  650. // `clear_dynamic_array` will set the length of a passed dynamic array to `0`
  651. //
  652. // Note: Prefer the procedure group `clear`.
  653. @builtin
  654. clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) {
  655. if array != nil {
  656. (^Raw_Dynamic_Array)(array).len = 0
  657. }
  658. }
  659. // `reserve_dynamic_array` will try to reserve memory of a passed dynamic array or map to the requested element count (setting the `cap`).
  660. //
  661. // Note: Prefer the procedure group `reserve`.
  662. _reserve_dynamic_array :: #force_inline proc(a: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, capacity: int, should_zero: bool, loc := #caller_location) -> Allocator_Error {
  663. if a == nil {
  664. return nil
  665. }
  666. if capacity <= a.cap {
  667. return nil
  668. }
  669. if a.allocator.procedure == nil {
  670. a.allocator = context.allocator
  671. }
  672. assert(a.allocator.procedure != nil)
  673. old_size := a.cap * size_of_elem
  674. new_size := capacity * size_of_elem
  675. allocator := a.allocator
  676. new_data: []byte
  677. if should_zero {
  678. new_data = mem_resize(a.data, old_size, new_size, align_of_elem, allocator, loc) or_return
  679. } else {
  680. new_data = non_zero_mem_resize(a.data, old_size, new_size, align_of_elem, allocator, loc) or_return
  681. }
  682. if new_data == nil && new_size > 0 {
  683. return .Out_Of_Memory
  684. }
  685. a.data = raw_data(new_data)
  686. a.cap = capacity
  687. return nil
  688. }
  689. @builtin
  690. reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int capacity: int, loc := #caller_location) -> Allocator_Error {
  691. return _reserve_dynamic_array((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), capacity, true, loc)
  692. }
  693. @builtin
  694. non_zero_reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int capacity: int, loc := #caller_location) -> Allocator_Error {
  695. return _reserve_dynamic_array((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), capacity, false, loc)
  696. }
  697. _resize_dynamic_array :: #force_inline proc(a: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, length: int, should_zero: bool, loc := #caller_location) -> Allocator_Error {
  698. if a == nil {
  699. return nil
  700. }
  701. if length <= a.cap {
  702. if should_zero && a.len < length {
  703. intrinsics.mem_zero(([^]byte)(a.data)[a.len*size_of_elem:], (length-a.len)*size_of_elem)
  704. }
  705. a.len = max(length, 0)
  706. return nil
  707. }
  708. if a.allocator.procedure == nil {
  709. a.allocator = context.allocator
  710. }
  711. assert(a.allocator.procedure != nil)
  712. old_size := a.cap * size_of_elem
  713. new_size := length * size_of_elem
  714. allocator := a.allocator
  715. new_data : []byte
  716. if should_zero {
  717. new_data = mem_resize(a.data, old_size, new_size, align_of_elem, allocator, loc) or_return
  718. } else {
  719. new_data = non_zero_mem_resize(a.data, old_size, new_size, align_of_elem, allocator, loc) or_return
  720. }
  721. if new_data == nil && new_size > 0 {
  722. return .Out_Of_Memory
  723. }
  724. a.data = raw_data(new_data)
  725. a.len = length
  726. a.cap = length
  727. return nil
  728. }
  729. // `resize_dynamic_array` will try to resize memory of a passed dynamic array or map to the requested element count (setting the `len`, and possibly `cap`).
  730. //
  731. // Note: Prefer the procedure group `resize`
  732. @builtin
  733. resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int length: int, loc := #caller_location) -> Allocator_Error {
  734. return _resize_dynamic_array((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), length, true, loc=loc)
  735. }
  736. @builtin
  737. non_zero_resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int length: int, loc := #caller_location) -> Allocator_Error {
  738. return _resize_dynamic_array((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), length, false, loc=loc)
  739. }
  740. /*
  741. Shrinks the capacity of a dynamic array down to the current length, or the given capacity.
  742. If `new_cap` is negative, then `len(array)` is used.
  743. Returns false if `cap(array) < new_cap`, or the allocator report failure.
  744. If `len(array) < new_cap`, then `len(array)` will be left unchanged.
  745. Note: Prefer the procedure group `shrink`
  746. */
  747. shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int new_cap := -1, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
  748. return _shrink_dynamic_array((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), new_cap, loc)
  749. }
  750. _shrink_dynamic_array :: proc(a: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, new_cap := -1, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
  751. if a == nil {
  752. return
  753. }
  754. new_cap := new_cap if new_cap >= 0 else a.len
  755. if new_cap > a.cap {
  756. return
  757. }
  758. if a.allocator.procedure == nil {
  759. a.allocator = context.allocator
  760. }
  761. assert(a.allocator.procedure != nil)
  762. old_size := a.cap * size_of_elem
  763. new_size := new_cap * size_of_elem
  764. new_data := mem_resize(a.data, old_size, new_size, align_of_elem, a.allocator, loc) or_return
  765. a.data = raw_data(new_data)
  766. a.len = min(new_cap, a.len)
  767. a.cap = new_cap
  768. return true, nil
  769. }
  770. @builtin
  771. map_insert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) -> (ptr: ^V) {
  772. key, value := key, value
  773. return (^V)(__dynamic_map_set_without_hash((^Raw_Map)(m), map_info(T), rawptr(&key), rawptr(&value), loc))
  774. }
  775. // Explicitly inserts a key and value into a map `m`, the same as `map_insert`, but the return values differ.
  776. // - `prev_key` will return the previous pointer of a key if it exists, check `found_previous` if was previously found
  777. // - `value_ptr` will return the pointer of the memory where the insertion happens, and `nil` if the map failed to resize
  778. // - `found_previous` will be true a previous key was found
  779. @(builtin, require_results)
  780. map_upsert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) -> (prev_key: K, value_ptr: ^V, found_previous: bool) {
  781. key, value := key, value
  782. kp, vp := __dynamic_map_set_extra_without_hash((^Raw_Map)(m), map_info(T), rawptr(&key), rawptr(&value), loc)
  783. if kp != nil {
  784. prev_key = (^K)(kp)^
  785. found_previous = true
  786. }
  787. value_ptr = (^V)(vp)
  788. return
  789. }
  790. @builtin
  791. card :: proc "contextless" (s: $S/bit_set[$E; $U]) -> int {
  792. when size_of(S) == 1 {
  793. return int(intrinsics.count_ones(transmute(u8)s))
  794. } else when size_of(S) == 2 {
  795. return int(intrinsics.count_ones(transmute(u16)s))
  796. } else when size_of(S) == 4 {
  797. return int(intrinsics.count_ones(transmute(u32)s))
  798. } else when size_of(S) == 8 {
  799. return int(intrinsics.count_ones(transmute(u64)s))
  800. } else when size_of(S) == 16 {
  801. return int(intrinsics.count_ones(transmute(u128)s))
  802. } else {
  803. #panic("Unhandled card bit_set size")
  804. }
  805. }
  806. @builtin
  807. @(disabled=ODIN_DISABLE_ASSERT)
  808. assert :: proc(condition: bool, message := #caller_expression(condition), loc := #caller_location) {
  809. if !condition {
  810. // NOTE(bill): This is wrapped in a procedure call
  811. // to improve performance to make the CPU not
  812. // execute speculatively, making it about an order of
  813. // magnitude faster
  814. @(cold)
  815. internal :: proc(message: string, loc: Source_Code_Location) {
  816. p := context.assertion_failure_proc
  817. if p == nil {
  818. p = default_assertion_failure_proc
  819. }
  820. p("runtime assertion", message, loc)
  821. }
  822. internal(message, loc)
  823. }
  824. }
  825. @builtin
  826. panic :: proc(message: string, loc := #caller_location) -> ! {
  827. p := context.assertion_failure_proc
  828. if p == nil {
  829. p = default_assertion_failure_proc
  830. }
  831. p("panic", message, loc)
  832. }
  833. @builtin
  834. unimplemented :: proc(message := "", loc := #caller_location) -> ! {
  835. p := context.assertion_failure_proc
  836. if p == nil {
  837. p = default_assertion_failure_proc
  838. }
  839. p("not yet implemented", message, loc)
  840. }
  841. @builtin
  842. @(disabled=ODIN_DISABLE_ASSERT)
  843. assert_contextless :: proc "contextless" (condition: bool, message := #caller_expression(condition), loc := #caller_location) {
  844. if !condition {
  845. // NOTE(bill): This is wrapped in a procedure call
  846. // to improve performance to make the CPU not
  847. // execute speculatively, making it about an order of
  848. // magnitude faster
  849. @(cold)
  850. internal :: proc "contextless" (message: string, loc: Source_Code_Location) {
  851. default_assertion_contextless_failure_proc("runtime assertion", message, loc)
  852. }
  853. internal(message, loc)
  854. }
  855. }
  856. @builtin
  857. panic_contextless :: proc "contextless" (message: string, loc := #caller_location) -> ! {
  858. default_assertion_contextless_failure_proc("panic", message, loc)
  859. }
  860. @builtin
  861. unimplemented_contextless :: proc "contextless" (message := "", loc := #caller_location) -> ! {
  862. default_assertion_contextless_failure_proc("not yet implemented", message, loc)
  863. }