core_builtin.odin 43 KB

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