core_builtin.odin 34 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` initializes a map with an allocator. 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, allocator := context.allocator, loc := #caller_location) -> (m: T) {
  340. m.allocator = allocator
  341. return m
  342. }
  343. // `make_map_cap` initializes a map with an allocator and allocates space using `capacity`.
  344. // Like `new`, the first argument is a type, not a value.
  345. // Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
  346. //
  347. // Note: Prefer using the procedure group `make`.
  348. @(builtin, require_results)
  349. make_map_cap :: proc($T: typeid/map[$K]$E, #any_int capacity: int, allocator := context.allocator, loc := #caller_location) -> (m: T, err: Allocator_Error) #optional_allocator_error {
  350. make_map_expr_error_loc(loc, capacity)
  351. context.allocator = allocator
  352. err = reserve_map(&m, capacity, loc)
  353. return
  354. }
  355. // `make_multi_pointer` allocates and initializes a multi-pointer. Like `new`, the first argument is a type, not a value.
  356. // Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
  357. //
  358. // This is "similar" to doing `raw_data(make([]E, len, allocator))`.
  359. //
  360. // Note: Prefer using the procedure group `make`.
  361. @(builtin, require_results)
  362. 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 {
  363. make_slice_error_loc(loc, len)
  364. data := mem_alloc_bytes(size_of(E)*len, align_of(E), allocator, loc) or_return
  365. if data == nil && size_of(E) != 0 {
  366. return
  367. }
  368. mp = cast(T)raw_data(data)
  369. return
  370. }
  371. // `make` built-in procedure allocates and initializes a value of type slice, dynamic array, map, or multi-pointer (only).
  372. //
  373. // Similar to `new`, the first argument is a type, not a value. Unlike new, make's return type is the same as the
  374. // type of its argument, not a pointer to it.
  375. // Make uses the specified allocator, default is context.allocator.
  376. @builtin
  377. make :: proc{
  378. make_slice,
  379. make_dynamic_array,
  380. make_dynamic_array_len,
  381. make_dynamic_array_len_cap,
  382. make_map,
  383. make_map_cap,
  384. make_multi_pointer,
  385. make_soa_slice,
  386. make_soa_dynamic_array,
  387. make_soa_dynamic_array_len,
  388. make_soa_dynamic_array_len_cap,
  389. }
  390. // `clear_map` will set the length of a passed map to `0`
  391. //
  392. // Note: Prefer the procedure group `clear`
  393. @builtin
  394. clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {
  395. if m == nil {
  396. return
  397. }
  398. map_clear_dynamic((^Raw_Map)(m), map_info(T))
  399. }
  400. // `reserve_map` will try to reserve memory of a passed map to the requested element count (setting the `cap`).
  401. //
  402. // Note: Prefer the procedure group `reserve`
  403. @builtin
  404. reserve_map :: proc(m: ^$T/map[$K]$V, #any_int capacity: int, loc := #caller_location) -> Allocator_Error {
  405. return __dynamic_map_reserve((^Raw_Map)(m), map_info(T), uint(capacity), loc) if m != nil else nil
  406. }
  407. // Shrinks the capacity of a map down to the current length.
  408. //
  409. // Note: Prefer the procedure group `shrink`
  410. @builtin
  411. shrink_map :: proc(m: ^$T/map[$K]$V, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
  412. if m != nil {
  413. return map_shrink_dynamic((^Raw_Map)(m), map_info(T), loc)
  414. }
  415. return
  416. }
  417. // The delete_key built-in procedure deletes the element with the specified key (m[key]) from the map.
  418. // If m is nil, or there is no such element, this procedure is a no-op
  419. @builtin
  420. delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value: V) {
  421. if m != nil {
  422. key := key
  423. old_k, old_v, ok := map_erase_dynamic((^Raw_Map)(m), map_info(T), uintptr(&key))
  424. if ok {
  425. deleted_key = (^K)(old_k)^
  426. deleted_value = (^V)(old_v)^
  427. }
  428. }
  429. return
  430. }
  431. _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 {
  432. if array == nil {
  433. return
  434. }
  435. if array.cap < array.len+1 {
  436. // Same behavior as _append_elems but there's only one arg, so we always just add DEFAULT_DYNAMIC_ARRAY_CAPACITY.
  437. cap := 2 * array.cap + DEFAULT_DYNAMIC_ARRAY_CAPACITY
  438. // do not 'or_return' here as it could be a partial success
  439. err = _reserve_dynamic_array(array, size_of_elem, align_of_elem, cap, should_zero, loc)
  440. }
  441. if array.cap-array.len > 0 {
  442. data := ([^]byte)(array.data)
  443. assert(data != nil, loc=loc)
  444. data = data[array.len*size_of_elem:]
  445. intrinsics.mem_copy_non_overlapping(data, arg_ptr, size_of_elem)
  446. array.len += 1
  447. n = 1
  448. }
  449. return
  450. }
  451. @builtin
  452. append_elem :: proc(array: ^$T/[dynamic]$E, #no_broadcast arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
  453. when size_of(E) == 0 {
  454. (^Raw_Dynamic_Array)(array).len += 1
  455. return 1, nil
  456. } else {
  457. arg := arg
  458. return _append_elem((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), &arg, true, loc=loc)
  459. }
  460. }
  461. @builtin
  462. non_zero_append_elem :: proc(array: ^$T/[dynamic]$E, #no_broadcast arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
  463. when size_of(E) == 0 {
  464. (^Raw_Dynamic_Array)(array).len += 1
  465. return 1, nil
  466. } else {
  467. arg := arg
  468. return _append_elem((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), &arg, false, loc=loc)
  469. }
  470. }
  471. _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 {
  472. if array == nil {
  473. return 0, nil
  474. }
  475. if arg_len <= 0 {
  476. return 0, nil
  477. }
  478. if array.cap < array.len+arg_len {
  479. cap := 2 * array.cap + max(DEFAULT_DYNAMIC_ARRAY_CAPACITY, arg_len)
  480. // do not 'or_return' here as it could be a partial success
  481. err = _reserve_dynamic_array(array, size_of_elem, align_of_elem, cap, should_zero, loc)
  482. }
  483. arg_len := arg_len
  484. arg_len = min(array.cap-array.len, arg_len)
  485. if arg_len > 0 {
  486. data := ([^]byte)(array.data)
  487. assert(data != nil, loc=loc)
  488. data = data[array.len*size_of_elem:]
  489. intrinsics.mem_copy(data, args, size_of_elem * arg_len) // must be mem_copy (overlapping)
  490. array.len += arg_len
  491. }
  492. return arg_len, err
  493. }
  494. @builtin
  495. append_elems :: proc(array: ^$T/[dynamic]$E, #no_broadcast args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
  496. when size_of(E) == 0 {
  497. a := (^Raw_Dynamic_Array)(array)
  498. a.len += len(args)
  499. return len(args), nil
  500. } else {
  501. return _append_elems((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), true, loc, raw_data(args), len(args))
  502. }
  503. }
  504. @builtin
  505. non_zero_append_elems :: proc(array: ^$T/[dynamic]$E, #no_broadcast args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
  506. when size_of(E) == 0 {
  507. a := (^Raw_Dynamic_Array)(array)
  508. a.len += len(args)
  509. return len(args), nil
  510. } else {
  511. return _append_elems((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), false, loc, raw_data(args), len(args))
  512. }
  513. }
  514. // The append_string built-in procedure appends a string to the end of a [dynamic]u8 like type
  515. _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 {
  516. return _append_elems((^Raw_Dynamic_Array)(array), 1, 1, should_zero, loc, raw_data(arg), len(arg))
  517. }
  518. @builtin
  519. append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
  520. return _append_elem_string(array, arg, true, loc)
  521. }
  522. @builtin
  523. 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 {
  524. return _append_elem_string(array, arg, false, loc)
  525. }
  526. // The append_string built-in procedure appends multiple strings to the end of a [dynamic]u8 like type
  527. @builtin
  528. append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
  529. n_arg: int
  530. for arg in args {
  531. n_arg, err = append(array, ..transmute([]E)(arg), loc=loc)
  532. n += n_arg
  533. if err != nil {
  534. return
  535. }
  536. }
  537. return
  538. }
  539. // The append built-in procedure appends elements to the end of a dynamic array
  540. @builtin append :: proc{
  541. append_elem,
  542. append_elems,
  543. append_elem_string,
  544. append_soa_elem,
  545. append_soa_elems,
  546. }
  547. @builtin non_zero_append :: proc{
  548. non_zero_append_elem,
  549. non_zero_append_elems,
  550. non_zero_append_elem_string,
  551. non_zero_append_soa_elem,
  552. non_zero_append_soa_elems,
  553. }
  554. @builtin
  555. append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
  556. if array == nil {
  557. return 0, nil
  558. }
  559. prev_len := len(array)
  560. resize(array, len(array)+1, loc) or_return
  561. return len(array)-prev_len, nil
  562. }
  563. @builtin
  564. 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 {
  565. if array == nil {
  566. return
  567. }
  568. n := max(len(array), index)
  569. m :: 1
  570. new_size := n + m
  571. resize(array, new_size, loc) or_return
  572. when size_of(E) != 0 {
  573. copy(array[index + m:], array[index:])
  574. array[index] = arg
  575. }
  576. ok = true
  577. return
  578. }
  579. @builtin
  580. 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 {
  581. if array == nil {
  582. return
  583. }
  584. if len(args) == 0 {
  585. ok = true
  586. return
  587. }
  588. n := max(len(array), index)
  589. m := len(args)
  590. new_size := n + m
  591. resize(array, new_size, loc) or_return
  592. when size_of(E) != 0 {
  593. copy(array[index + m:], array[index:])
  594. copy(array[index:], args)
  595. }
  596. ok = true
  597. return
  598. }
  599. @builtin
  600. 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 {
  601. if array == nil {
  602. return
  603. }
  604. if len(arg) == 0 {
  605. ok = true
  606. return
  607. }
  608. n := max(len(array), index)
  609. m := len(arg)
  610. new_size := n + m
  611. resize(array, new_size, loc) or_return
  612. copy(array[index+m:], array[index:])
  613. copy(array[index:], arg)
  614. ok = true
  615. return
  616. }
  617. @builtin inject_at :: proc{inject_at_elem, inject_at_elems, inject_at_elem_string}
  618. @builtin
  619. 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 {
  620. if index < len(array) {
  621. array[index] = arg
  622. ok = true
  623. } else {
  624. resize(array, index+1, loc) or_return
  625. array[index] = arg
  626. ok = true
  627. }
  628. return
  629. }
  630. @builtin
  631. 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 {
  632. new_size := index + len(args)
  633. if len(args) == 0 {
  634. ok = true
  635. } else if new_size < len(array) {
  636. copy(array[index:], args)
  637. ok = true
  638. } else {
  639. resize(array, new_size, loc) or_return
  640. copy(array[index:], args)
  641. ok = true
  642. }
  643. return
  644. }
  645. @builtin
  646. 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 {
  647. new_size := index + len(arg)
  648. if len(arg) == 0 {
  649. ok = true
  650. } else if new_size < len(array) {
  651. copy(array[index:], arg)
  652. ok = true
  653. } else {
  654. resize(array, new_size, loc) or_return
  655. copy(array[index:], arg)
  656. ok = true
  657. }
  658. return
  659. }
  660. @builtin assign_at :: proc{assign_at_elem, assign_at_elems, assign_at_elem_string}
  661. // `clear_dynamic_array` will set the length of a passed dynamic array to `0`
  662. //
  663. // Note: Prefer the procedure group `clear`.
  664. @builtin
  665. clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) {
  666. if array != nil {
  667. (^Raw_Dynamic_Array)(array).len = 0
  668. }
  669. }
  670. // `reserve_dynamic_array` will try to reserve memory of a passed dynamic array or map to the requested element count (setting the `cap`).
  671. //
  672. // Note: Prefer the procedure group `reserve`.
  673. _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 {
  674. if a == nil {
  675. return nil
  676. }
  677. if capacity <= a.cap {
  678. return nil
  679. }
  680. if a.allocator.procedure == nil {
  681. a.allocator = context.allocator
  682. }
  683. assert(a.allocator.procedure != nil)
  684. old_size := a.cap * size_of_elem
  685. new_size := capacity * size_of_elem
  686. allocator := a.allocator
  687. new_data: []byte
  688. if should_zero {
  689. new_data = mem_resize(a.data, old_size, new_size, align_of_elem, allocator, loc) or_return
  690. } else {
  691. new_data = non_zero_mem_resize(a.data, old_size, new_size, align_of_elem, allocator, loc) or_return
  692. }
  693. if new_data == nil && new_size > 0 {
  694. return .Out_Of_Memory
  695. }
  696. a.data = raw_data(new_data)
  697. a.cap = capacity
  698. return nil
  699. }
  700. @builtin
  701. reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int capacity: int, loc := #caller_location) -> Allocator_Error {
  702. return _reserve_dynamic_array((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), capacity, true, loc)
  703. }
  704. @builtin
  705. non_zero_reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int capacity: int, loc := #caller_location) -> Allocator_Error {
  706. return _reserve_dynamic_array((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), capacity, false, loc)
  707. }
  708. _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 {
  709. if a == nil {
  710. return nil
  711. }
  712. if length <= a.cap {
  713. if should_zero && a.len < length {
  714. intrinsics.mem_zero(([^]byte)(a.data)[a.len*size_of_elem:], (length-a.len)*size_of_elem)
  715. }
  716. a.len = max(length, 0)
  717. return nil
  718. }
  719. if a.allocator.procedure == nil {
  720. a.allocator = context.allocator
  721. }
  722. assert(a.allocator.procedure != nil)
  723. old_size := a.cap * size_of_elem
  724. new_size := length * size_of_elem
  725. allocator := a.allocator
  726. new_data : []byte
  727. if should_zero {
  728. new_data = mem_resize(a.data, old_size, new_size, align_of_elem, allocator, loc) or_return
  729. } else {
  730. new_data = non_zero_mem_resize(a.data, old_size, new_size, align_of_elem, allocator, loc) or_return
  731. }
  732. if new_data == nil && new_size > 0 {
  733. return .Out_Of_Memory
  734. }
  735. a.data = raw_data(new_data)
  736. a.len = length
  737. a.cap = length
  738. return nil
  739. }
  740. // `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`).
  741. //
  742. // Note: Prefer the procedure group `resize`
  743. @builtin
  744. resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int length: int, loc := #caller_location) -> Allocator_Error {
  745. return _resize_dynamic_array((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), length, true, loc=loc)
  746. }
  747. @builtin
  748. non_zero_resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int length: int, loc := #caller_location) -> Allocator_Error {
  749. return _resize_dynamic_array((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), length, false, loc=loc)
  750. }
  751. /*
  752. Shrinks the capacity of a dynamic array down to the current length, or the given capacity.
  753. If `new_cap` is negative, then `len(array)` is used.
  754. Returns false if `cap(array) < new_cap`, or the allocator report failure.
  755. If `len(array) < new_cap`, then `len(array)` will be left unchanged.
  756. Note: Prefer the procedure group `shrink`
  757. */
  758. shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int new_cap := -1, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
  759. return _shrink_dynamic_array((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), new_cap, loc)
  760. }
  761. _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) {
  762. if a == nil {
  763. return
  764. }
  765. new_cap := new_cap if new_cap >= 0 else a.len
  766. if new_cap > a.cap {
  767. return
  768. }
  769. if a.allocator.procedure == nil {
  770. a.allocator = context.allocator
  771. }
  772. assert(a.allocator.procedure != nil)
  773. old_size := a.cap * size_of_elem
  774. new_size := new_cap * size_of_elem
  775. new_data := mem_resize(a.data, old_size, new_size, align_of_elem, a.allocator, loc) or_return
  776. a.data = raw_data(new_data)
  777. a.len = min(new_cap, a.len)
  778. a.cap = new_cap
  779. return true, nil
  780. }
  781. @builtin
  782. map_insert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) -> (ptr: ^V) {
  783. key, value := key, value
  784. return (^V)(__dynamic_map_set_without_hash((^Raw_Map)(m), map_info(T), rawptr(&key), rawptr(&value), loc))
  785. }
  786. // Explicitly inserts a key and value into a map `m`, the same as `map_insert`, but the return values differ.
  787. // - `prev_key` will return the previous pointer of a key if it exists, check `found_previous` if was previously found
  788. // - `value_ptr` will return the pointer of the memory where the insertion happens, and `nil` if the map failed to resize
  789. // - `found_previous` will be true a previous key was found
  790. @(builtin, require_results)
  791. map_upsert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) -> (prev_key: K, value_ptr: ^V, found_previous: bool) {
  792. key, value := key, value
  793. kp, vp := __dynamic_map_set_extra_without_hash((^Raw_Map)(m), map_info(T), rawptr(&key), rawptr(&value), loc)
  794. if kp != nil {
  795. prev_key = (^K)(kp)^
  796. found_previous = true
  797. }
  798. value_ptr = (^V)(vp)
  799. return
  800. }
  801. @builtin
  802. card :: proc "contextless" (s: $S/bit_set[$E; $U]) -> int {
  803. return int(intrinsics.count_ones(transmute(intrinsics.type_bit_set_underlying_type(S))s))
  804. }
  805. @builtin
  806. @(disabled=ODIN_DISABLE_ASSERT)
  807. assert :: proc(condition: bool, message := #caller_expression(condition), loc := #caller_location) {
  808. if !condition {
  809. // NOTE(bill): This is wrapped in a procedure call
  810. // to improve performance to make the CPU not
  811. // execute speculatively, making it about an order of
  812. // magnitude faster
  813. @(cold)
  814. internal :: proc(message: string, loc: Source_Code_Location) {
  815. p := context.assertion_failure_proc
  816. if p == nil {
  817. p = default_assertion_failure_proc
  818. }
  819. p("runtime assertion", message, loc)
  820. }
  821. internal(message, loc)
  822. }
  823. }
  824. @builtin
  825. panic :: proc(message: string, loc := #caller_location) -> ! {
  826. p := context.assertion_failure_proc
  827. if p == nil {
  828. p = default_assertion_failure_proc
  829. }
  830. p("panic", message, loc)
  831. }
  832. @builtin
  833. unimplemented :: proc(message := "", loc := #caller_location) -> ! {
  834. p := context.assertion_failure_proc
  835. if p == nil {
  836. p = default_assertion_failure_proc
  837. }
  838. p("not yet implemented", message, loc)
  839. }
  840. @builtin
  841. @(disabled=ODIN_DISABLE_ASSERT)
  842. assert_contextless :: proc "contextless" (condition: bool, message := #caller_expression(condition), loc := #caller_location) {
  843. if !condition {
  844. // NOTE(bill): This is wrapped in a procedure call
  845. // to improve performance to make the CPU not
  846. // execute speculatively, making it about an order of
  847. // magnitude faster
  848. @(cold)
  849. internal :: proc "contextless" (message: string, loc: Source_Code_Location) {
  850. default_assertion_contextless_failure_proc("runtime assertion", message, loc)
  851. }
  852. internal(message, loc)
  853. }
  854. }
  855. @builtin
  856. panic_contextless :: proc "contextless" (message: string, loc := #caller_location) -> ! {
  857. default_assertion_contextless_failure_proc("panic", message, loc)
  858. }
  859. @builtin
  860. unimplemented_contextless :: proc "contextless" (message := "", loc := #caller_location) -> ! {
  861. default_assertion_contextless_failure_proc("not yet implemented", message, loc)
  862. }