alloc.odin 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114
  1. package mem
  2. import "base:runtime"
  3. //NOTE(bill, 2019-12-31): These are defined in `package runtime` as they are used in the `context`. This is to prevent an import definition cycle.
  4. /*
  5. A request to allocator procedure.
  6. This type represents a type of allocation request made to an allocator
  7. procedure. There is one allocator procedure per allocator, and this value is
  8. used to discriminate between different functions of the allocator.
  9. The type is defined as follows:
  10. Allocator_Mode :: enum byte {
  11. Alloc,
  12. Alloc_Non_Zeroed,
  13. Free,
  14. Free_All,
  15. Resize,
  16. Resize_Non_Zeroed,
  17. Query_Features,
  18. }
  19. Depending on which value is used, the allocator procedure will perform different
  20. functions:
  21. - `Alloc`: Allocates a memory region with a given `size` and `alignment`.
  22. - `Alloc_Non_Zeroed`: Same as `Alloc` without explicit zero-initialization of
  23. the memory region.
  24. - `Free`: Free a memory region located at address `ptr` with a given `size`.
  25. - `Free_All`: Free all memory allocated using this allocator.
  26. - `Resize`: Resize a memory region located at address `old_ptr` with size
  27. `old_size` to be `size` bytes in length and have the specified `alignment`,
  28. in case a re-alllocation occurs.
  29. - `Resize_Non_Zeroed`: Same as `Resize`, without explicit zero-initialization.
  30. */
  31. Allocator_Mode :: runtime.Allocator_Mode
  32. /*
  33. A set of allocator features.
  34. This type represents values that contain a set of features an allocator has.
  35. Currently the type is defined as follows:
  36. Allocator_Mode_Set :: distinct bit_set[Allocator_Mode];
  37. */
  38. Allocator_Mode_Set :: runtime.Allocator_Mode_Set
  39. /*
  40. Allocator information.
  41. This type represents information about a given allocator at a specific point
  42. in time. Currently the type is defined as follows:
  43. Allocator_Query_Info :: struct {
  44. pointer: rawptr,
  45. size: Maybe(int),
  46. alignment: Maybe(int),
  47. }
  48. - `pointer`: Pointer to a backing buffer.
  49. - `size`: Size of the backing buffer.
  50. - `alignment`: The allocator's alignment.
  51. If not applicable, any of these fields may be `nil`.
  52. */
  53. Allocator_Query_Info :: runtime.Allocator_Query_Info
  54. /*
  55. An allocation request error.
  56. This type represents error values the allocators may return upon requests.
  57. Allocator_Error :: enum byte {
  58. None = 0,
  59. Out_Of_Memory = 1,
  60. Invalid_Pointer = 2,
  61. Invalid_Argument = 3,
  62. Mode_Not_Implemented = 4,
  63. }
  64. The meaning of the errors is as follows:
  65. - `None`: No error.
  66. - `Out_Of_Memory`: Either:
  67. 1. The allocator has ran out of the backing buffer, or the requested
  68. allocation size is too large to fit into a backing buffer.
  69. 2. The operating system error during memory allocation.
  70. 3. The backing allocator was used to allocate a new backing buffer and the
  71. backing allocator returned Out_Of_Memory.
  72. - `Invalid_Pointer`: The pointer referring to a memory region does not belong
  73. to any of the allocators backing buffers or does not point to a valid start
  74. of an allocation made in that allocator.
  75. - `Invalid_Argument`: Can occur if one of the arguments makes it impossible to
  76. satisfy a request (i.e. having alignment larger than the backing buffer
  77. of the allocation).
  78. - `Mode_Not_Implemented`: The allocator does not support the specified
  79. operation. For example, an arena does not support freeing individual
  80. allocations.
  81. */
  82. Allocator_Error :: runtime.Allocator_Error
  83. /*
  84. The allocator procedure.
  85. This type represents allocation procedures. An allocation procedure is a single
  86. procedure, implementing all allocator functions such as allocating the memory,
  87. freeing the memory, etc.
  88. Currently the type is defined as follows:
  89. Allocator_Proc :: #type proc(
  90. allocator_data: rawptr,
  91. mode: Allocator_Mode,
  92. size: int,
  93. alignment: int,
  94. old_memory: rawptr,
  95. old_size: int,
  96. location: Source_Code_Location = #caller_location,
  97. ) -> ([]byte, Allocator_Error);
  98. The function of this procedure and the meaning of parameters depends on the
  99. value of the `mode` parameter. For any operation the following constraints
  100. apply:
  101. - The `alignment` must be a power of two.
  102. - The `size` must be a positive integer.
  103. ## 1. `.Alloc`, `.Alloc_Non_Zeroed`
  104. Allocates a memory region of size `size`, aligned on a boundary specified by
  105. `alignment`.
  106. **Inputs**:
  107. - `allocator_data`: Pointer to the allocator data.
  108. - `mode`: `.Alloc` or `.Alloc_Non_Zeroed`.
  109. - `size`: The desired size of the memory region.
  110. - `alignment`: The desired alignmnet of the allocation.
  111. - `old_memory`: Unused, should be `nil`.
  112. - `old_size`: Unused, should be 0.
  113. **Returns**:
  114. 1. The memory region, if allocated successfully, or `nil` otherwise.
  115. 2. An error, if allocation failed.
  116. **Note**: The nil allocator may return `nil`, even if no error is returned.
  117. Always check both the error and the allocated buffer.
  118. **Note**: The `.Alloc` mode is required to be implemented for an allocator
  119. and can not return a `.Mode_Not_Implemented` error.
  120. ## 2. `Free`
  121. Frees a memory region located at the address specified by `old_memory`. If the
  122. allocator does not track sizes of allocations, the size should be specified in
  123. the `old_size` parameter.
  124. **Inputs**:
  125. - `allocator_data`: Pointer to the allocator data.
  126. - `mode`: `.Free`.
  127. - `size`: Unused, should be 0.
  128. - `alignment`: Unused, should be 0.
  129. - `old_memory`: Pointer to the memory region to free.
  130. - `old_size`: The size of the memory region to free. This parameter is optional
  131. if the allocator keeps track of the sizes of allocations.
  132. **Returns**:
  133. 1. `nil`
  134. 2. Error, if freeing failed.
  135. ## 3. `Free_All`
  136. Frees all allocations, associated with the allocator, making it available for
  137. further allocations using the same backing buffers.
  138. **Inputs**:
  139. - `allocator_data`: Pointer to the allocator data.
  140. - `mode`: `.Free_All`.
  141. - `size`: Unused, should be 0.
  142. - `alignment`: Unused, should be 0.
  143. - `old_memory`: Unused, should be `nil`.
  144. - `old_size`: Unused, should be `0`.
  145. **Returns**:
  146. 1. `nil`.
  147. 2. Error, if freeing failed.
  148. ## 4. `Resize`, `Resize_Non_Zeroed`
  149. Resizes the memory region, of the size `old_size` located at the address
  150. specified by `old_memory` to have the new size `size`. The slice of the new
  151. memory region is returned from the procedure. The allocator may attempt to
  152. keep the new memory region at the same address as the previous allocation,
  153. however no such guarantee is made. Do not assume the new memory region will
  154. be at the same address as the old memory region.
  155. If `old_memory` pointer is `nil`, this function acts just like `.Alloc` or
  156. `.Alloc_Non_Zeroed`, using `size` and `alignment` to allocate a new memory
  157. region.
  158. If `new_size` is `nil`, the procedure acts just like `.Free`, freeing the
  159. memory region `old_size` bytes in length, located at the address specified by
  160. `old_memory`.
  161. If the `old_memory` pointer is not aligned to the boundary specified by
  162. `alignment`, the procedure relocates the buffer such that the reallocated
  163. buffer is aligned to the boundary specified by `alignment`.
  164. **Inputs**:
  165. - `allocator_data`: Pointer to the allocator data.
  166. - `mode`: `.Resize` or `.Resize_All`.
  167. - `size`: The desired new size of the memory region.
  168. - `alignment`: The alignment of the new memory region, if its allocated
  169. - `old_memory`: The pointer to the memory region to resize.
  170. - `old_size`: The size of the memory region to resize. If the allocator
  171. keeps track of the sizes of allocations, this parameter is optional.
  172. **Returns**:
  173. 1. The slice of the memory region after resize operation, if successfull,
  174. `nil` otherwise.
  175. 2. An error, if the resize failed.
  176. **Note**: Some allocators may return `nil`, even if no error is returned.
  177. Always check both the error and the allocated buffer.
  178. **Note**: if `old_size` is `0` and `old_memory` is `nil`, this operation is a
  179. no-op, and should not return errors.
  180. */
  181. Allocator_Proc :: runtime.Allocator_Proc
  182. /*
  183. Allocator.
  184. This type represents generic interface for all allocators. Currently this type
  185. is defined as follows:
  186. Allocator :: struct {
  187. procedure: Allocator_Proc,
  188. data: rawptr,
  189. }
  190. - `procedure`: Pointer to the allocation procedure.
  191. - `data`: Pointer to the allocator data.
  192. */
  193. Allocator :: runtime.Allocator
  194. /*
  195. Default alignment.
  196. This value is the default alignment for all platforms that is used, if the
  197. alignment is not specified explicitly.
  198. */
  199. DEFAULT_ALIGNMENT :: 2*align_of(rawptr)
  200. /*
  201. Default page size.
  202. This value is the default page size for the current platform.
  203. */
  204. DEFAULT_PAGE_SIZE ::
  205. 64 * 1024 when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 else
  206. 16 * 1024 when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 else
  207. 4 * 1024
  208. /*
  209. Allocate memory.
  210. This function allocates `size` bytes of memory, aligned to a boundary specified
  211. by `alignment` using the allocator specified by `allocator`.
  212. If the `size` parameter is `0`, the operation is a no-op.
  213. **Inputs**:
  214. - `size`: The desired size of the allocated memory region.
  215. - `alignment`: The desired alignment of the allocated memory region.
  216. - `allocator`: The allocator to allocate from.
  217. **Returns**:
  218. 1. Pointer to the allocated memory, or `nil` if allocation failed.
  219. 2. Error, if the allocation failed.
  220. **Errors**:
  221. - `None`: If no error occurred.
  222. - `Out_Of_Memory`: Occurs when the allocator runs out of space in any of its
  223. backing buffers, the backing allocator has ran out of space, or an operating
  224. system failure occurred.
  225. - `Invalid_Argument`: If the supplied `size` is negative, alignment is not a
  226. power of two.
  227. */
  228. @(require_results)
  229. alloc :: proc(
  230. size: int,
  231. alignment: int = DEFAULT_ALIGNMENT,
  232. allocator := context.allocator,
  233. loc := #caller_location,
  234. ) -> (rawptr, Allocator_Error) {
  235. data, err := runtime.mem_alloc(size, alignment, allocator, loc)
  236. return raw_data(data), err
  237. }
  238. /*
  239. Allocate memory.
  240. This function allocates `size` bytes of memory, aligned to a boundary specified
  241. by `alignment` using the allocator specified by `allocator`.
  242. **Inputs**:
  243. - `size`: The desired size of the allocated memory region.
  244. - `alignment`: The desired alignment of the allocated memory region.
  245. - `allocator`: The allocator to allocate from.
  246. **Returns**:
  247. 1. Slice of the allocated memory region, or `nil` if allocation failed.
  248. 2. Error, if the allocation failed.
  249. **Errors**:
  250. - `None`: If no error occurred.
  251. - `Out_Of_Memory`: Occurs when the allocator runs out of space in any of its
  252. backing buffers, the backing allocator has ran out of space, or an operating
  253. system failure occurred.
  254. - `Invalid_Argument`: If the supplied `size` is negative, alignment is not a
  255. power of two.
  256. */
  257. @(require_results)
  258. alloc_bytes :: proc(
  259. size: int,
  260. alignment: int = DEFAULT_ALIGNMENT,
  261. allocator := context.allocator,
  262. loc := #caller_location,
  263. ) -> ([]byte, Allocator_Error) {
  264. return runtime.mem_alloc(size, alignment, allocator, loc)
  265. }
  266. /*
  267. Allocate non-zeroed memory.
  268. This function allocates `size` bytes of memory, aligned to a boundary specified
  269. by `alignment` using the allocator specified by `allocator`. This procedure
  270. does not explicitly zero-initialize allocated memory region.
  271. **Inputs**:
  272. - `size`: The desired size of the allocated memory region.
  273. - `alignment`: The desired alignment of the allocated memory region.
  274. - `allocator`: The allocator to allocate from.
  275. **Returns**:
  276. 1. Slice of the allocated memory region, or `nil` if allocation failed.
  277. 2. Error, if the allocation failed.
  278. **Errors**:
  279. - `None`: If no error occurred.
  280. - `Out_Of_Memory`: Occurs when the allocator runs out of space in any of its
  281. backing buffers, the backing allocator has ran out of space, or an operating
  282. system failure occurred.
  283. - `Invalid_Argument`: If the supplied `size` is negative, alignment is not a
  284. power of two.
  285. */
  286. @(require_results)
  287. alloc_bytes_non_zeroed :: proc(
  288. size: int,
  289. alignment: int = DEFAULT_ALIGNMENT,
  290. allocator := context.allocator,
  291. loc := #caller_location,
  292. ) -> ([]byte, Allocator_Error) {
  293. return runtime.mem_alloc_non_zeroed(size, alignment, allocator, loc)
  294. }
  295. /*
  296. Free memory.
  297. This procedure frees memory region located at the address, specified by `ptr`,
  298. allocated from the allocator specified by `allocator`.
  299. **Inputs**:
  300. - `ptr`: Pointer to the memory region to free.
  301. - `allocator`: The allocator to free to.
  302. **Returns**:
  303. - The error, if freeing failed.
  304. **Errors**:
  305. - `None`: When no error has occurred.
  306. - `Invalid_Pointer`: The specified pointer is not owned by the specified allocator,
  307. or does not point to a valid allocation.
  308. - `Mode_Not_Implemented`: If the specified allocator does not support the `.Free`
  309. mode.
  310. */
  311. free :: proc(
  312. ptr: rawptr,
  313. allocator := context.allocator,
  314. loc := #caller_location,
  315. ) -> Allocator_Error {
  316. return runtime.mem_free(ptr, allocator, loc)
  317. }
  318. /*
  319. Free a memory region.
  320. This procedure frees `size` bytes of memory region located at the address,
  321. specified by `ptr`, allocated from the allocator specified by `allocator`.
  322. If the `size` parameter is `0`, this call is equivalent to `free()`.
  323. **Inputs**:
  324. - `ptr`: Pointer to the memory region to free.
  325. - `size`: The size of the memory region to free.
  326. - `allocator`: The allocator to free to.
  327. **Returns**:
  328. - The error, if freeing failed.
  329. **Errors**:
  330. - `None`: When no error has occurred.
  331. - `Invalid_Pointer`: The specified pointer is not owned by the specified allocator,
  332. or does not point to a valid allocation.
  333. - `Mode_Not_Implemented`: If the specified allocator does not support the `.Free`
  334. mode.
  335. */
  336. free_with_size :: proc(
  337. ptr: rawptr,
  338. size: int,
  339. allocator := context.allocator,
  340. loc := #caller_location,
  341. ) -> Allocator_Error {
  342. return runtime.mem_free_with_size(ptr, size, allocator, loc)
  343. }
  344. /*
  345. Free a memory region.
  346. This procedure frees memory region, specified by `bytes`, allocated from the
  347. allocator specified by `allocator`.
  348. If the length of the specified slice is zero, the `.Invalid_Argument` error
  349. is returned.
  350. **Inputs**:
  351. - `bytes`: The memory region to free.
  352. - `allocator`: The allocator to free to.
  353. **Returns**:
  354. - The error, if freeing failed.
  355. **Errors**:
  356. - `None`: When no error has occurred.
  357. - `Invalid_Pointer`: The specified pointer is not owned by the specified allocator,
  358. or does not point to a valid allocation.
  359. - `Mode_Not_Implemented`: If the specified allocator does not support the `.Free`
  360. mode.
  361. */
  362. free_bytes :: proc(
  363. bytes: []byte,
  364. allocator := context.allocator,
  365. loc := #caller_location,
  366. ) -> Allocator_Error {
  367. return runtime.mem_free_bytes(bytes, allocator, loc)
  368. }
  369. /*
  370. Free all allocations.
  371. This procedure frees all allocations made on the allocator specified by
  372. `allocator` to that allocator, making it available for further allocations.
  373. **Inputs**:
  374. - `allocator`: The allocator to free to.
  375. **Errors**:
  376. - `None`: When no error has occurred.
  377. - `Mode_Not_Implemented`: If the specified allocator does not support the `.Free`
  378. mode.
  379. */
  380. free_all :: proc(allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
  381. return runtime.mem_free_all(allocator, loc)
  382. }
  383. /*
  384. Resize a memory region.
  385. This procedure resizes a memory region, `old_size` bytes in size, located at
  386. the address specified by `ptr`, such that it has a new size, specified by
  387. `new_size` and and is aligned on a boundary specified by `alignment`.
  388. If the `ptr` parameter is `nil`, `resize()` acts just like `alloc()`, allocating
  389. `new_size` bytes, aligned on a boundary specified by `alignment`.
  390. If the `new_size` parameter is `0`, `resize()` acts just like `free()`, freeing
  391. the memory region `old_size` bytes in length, located at the address specified
  392. by `ptr`.
  393. If the `old_memory` pointer is not aligned to the boundary specified by
  394. `alignment`, the procedure relocates the buffer such that the reallocated
  395. buffer is aligned to the boundary specified by `alignment`.
  396. **Inputs**:
  397. - `ptr`: Pointer to the memory region to resize.
  398. - `old_size`: Size of the memory region to resize.
  399. - `new_size`: The desired size of the resized memory region.
  400. - `alignment`: The desired alignment of the resized memory region.
  401. - `allocator`: The owner of the memory region to resize.
  402. **Returns**:
  403. 1. The pointer to the resized memory region, if successfull, `nil` otherwise.
  404. 2. Error, if resize failed.
  405. **Errors**:
  406. - `None`: No error.
  407. - `Out_Of_Memory`: When the allocator's backing buffer or it's backing
  408. allocator does not have enough space to fit in an allocation with the new
  409. size, or an operating system failure occurs.
  410. - `Invalid_Pointer`: The pointer referring to a memory region does not belong
  411. to any of the allocators backing buffers or does not point to a valid start
  412. of an allocation made in that allocator.
  413. - `Invalid_Argument`: When `size` is negative, alignment is not a power of two,
  414. or the `old_size` argument is incorrect.
  415. - `Mode_Not_Implemented`: The allocator does not support the `.Realloc` mode.
  416. **Note**: if `old_size` is `0` and `old_memory` is `nil`, this operation is a
  417. no-op, and should not return errors.
  418. */
  419. @(require_results)
  420. resize :: proc(
  421. ptr: rawptr,
  422. old_size: int,
  423. new_size: int,
  424. alignment: int = DEFAULT_ALIGNMENT,
  425. allocator := context.allocator,
  426. loc := #caller_location,
  427. ) -> (rawptr, Allocator_Error) {
  428. data, err := runtime.mem_resize(ptr, old_size, new_size, alignment, allocator, loc)
  429. return raw_data(data), err
  430. }
  431. /*
  432. Resize a memory region without zero-initialization.
  433. This procedure resizes a memory region, `old_size` bytes in size, located at
  434. the address specified by `ptr`, such that it has a new size, specified by
  435. `new_size` and and is aligned on a boundary specified by `alignment`.
  436. If the `ptr` parameter is `nil`, `resize()` acts just like `alloc()`, allocating
  437. `new_size` bytes, aligned on a boundary specified by `alignment`.
  438. If the `new_size` parameter is `0`, `resize()` acts just like `free()`, freeing
  439. the memory region `old_size` bytes in length, located at the address specified
  440. by `ptr`.
  441. If the `old_memory` pointer is not aligned to the boundary specified by
  442. `alignment`, the procedure relocates the buffer such that the reallocated
  443. buffer is aligned to the boundary specified by `alignment`.
  444. Unlike `resize()`, this procedure does not explicitly zero-initialize any new
  445. memory.
  446. **Inputs**:
  447. - `ptr`: Pointer to the memory region to resize.
  448. - `old_size`: Size of the memory region to resize.
  449. - `new_size`: The desired size of the resized memory region.
  450. - `alignment`: The desired alignment of the resized memory region.
  451. - `allocator`: The owner of the memory region to resize.
  452. **Returns**:
  453. 1. The pointer to the resized memory region, if successfull, `nil` otherwise.
  454. 2. Error, if resize failed.
  455. **Errors**:
  456. - `None`: No error.
  457. - `Out_Of_Memory`: When the allocator's backing buffer or it's backing
  458. allocator does not have enough space to fit in an allocation with the new
  459. size, or an operating system failure occurs.
  460. - `Invalid_Pointer`: The pointer referring to a memory region does not belong
  461. to any of the allocators backing buffers or does not point to a valid start
  462. of an allocation made in that allocator.
  463. - `Invalid_Argument`: When `size` is negative, alignment is not a power of two,
  464. or the `old_size` argument is incorrect.
  465. - `Mode_Not_Implemented`: The allocator does not support the `.Realloc` mode.
  466. **Note**: if `old_size` is `0` and `old_memory` is `nil`, this operation is a
  467. no-op, and should not return errors.
  468. */
  469. @(require_results)
  470. resize_non_zeroed :: proc(
  471. ptr: rawptr,
  472. old_size: int,
  473. new_size: int,
  474. alignment: int = DEFAULT_ALIGNMENT,
  475. allocator := context.allocator,
  476. loc := #caller_location,
  477. ) -> (rawptr, Allocator_Error) {
  478. data, err := runtime.non_zero_mem_resize(ptr, old_size, new_size, alignment, allocator, loc)
  479. return raw_data(data), err
  480. }
  481. /*
  482. Resize a memory region.
  483. This procedure resizes a memory region, specified by `old_data`, such that it
  484. has a new size, specified by `new_size` and and is aligned on a boundary
  485. specified by `alignment`.
  486. If the `old_data` parameter is `nil`, `resize_bytes()` acts just like
  487. `alloc_bytes()`, allocating `new_size` bytes, aligned on a boundary specified
  488. by `alignment`.
  489. If the `new_size` parameter is `0`, `resize_bytes()` acts just like
  490. `free_bytes()`, freeing the memory region specified by `old_data`.
  491. If the `old_memory` pointer is not aligned to the boundary specified by
  492. `alignment`, the procedure relocates the buffer such that the reallocated
  493. buffer is aligned to the boundary specified by `alignment`.
  494. **Inputs**:
  495. - `old_data`: Pointer to the memory region to resize.
  496. - `new_size`: The desired size of the resized memory region.
  497. - `alignment`: The desired alignment of the resized memory region.
  498. - `allocator`: The owner of the memory region to resize.
  499. **Returns**:
  500. 1. The resized memory region, if successfull, `nil` otherwise.
  501. 2. Error, if resize failed.
  502. **Errors**:
  503. - `None`: No error.
  504. - `Out_Of_Memory`: When the allocator's backing buffer or it's backing
  505. allocator does not have enough space to fit in an allocation with the new
  506. size, or an operating system failure occurs.
  507. - `Invalid_Pointer`: The pointer referring to a memory region does not belong
  508. to any of the allocators backing buffers or does not point to a valid start
  509. of an allocation made in that allocator.
  510. - `Invalid_Argument`: When `size` is negative, alignment is not a power of two,
  511. or the `old_size` argument is incorrect.
  512. - `Mode_Not_Implemented`: The allocator does not support the `.Realloc` mode.
  513. **Note**: if `old_size` is `0` and `old_memory` is `nil`, this operation is a
  514. no-op, and should not return errors.
  515. */
  516. @(require_results)
  517. resize_bytes :: proc(
  518. old_data: []byte,
  519. new_size: int,
  520. alignment: int = DEFAULT_ALIGNMENT,
  521. allocator := context.allocator,
  522. loc := #caller_location,
  523. ) -> ([]byte, Allocator_Error) {
  524. return runtime.mem_resize(raw_data(old_data), len(old_data), new_size, alignment, allocator, loc)
  525. }
  526. /*
  527. Resize a memory region.
  528. This procedure resizes a memory region, specified by `old_data`, such that it
  529. has a new size, specified by `new_size` and and is aligned on a boundary
  530. specified by `alignment`.
  531. If the `old_data` parameter is `nil`, `resize_bytes()` acts just like
  532. `alloc_bytes()`, allocating `new_size` bytes, aligned on a boundary specified
  533. by `alignment`.
  534. If the `new_size` parameter is `0`, `resize_bytes()` acts just like
  535. `free_bytes()`, freeing the memory region specified by `old_data`.
  536. If the `old_memory` pointer is not aligned to the boundary specified by
  537. `alignment`, the procedure relocates the buffer such that the reallocated
  538. buffer is aligned to the boundary specified by `alignment`.
  539. Unlike `resize_bytes()`, this procedure does not explicitly zero-initialize
  540. any new memory.
  541. **Inputs**:
  542. - `old_data`: Pointer to the memory region to resize.
  543. - `new_size`: The desired size of the resized memory region.
  544. - `alignment`: The desired alignment of the resized memory region.
  545. - `allocator`: The owner of the memory region to resize.
  546. **Returns**:
  547. 1. The resized memory region, if successfull, `nil` otherwise.
  548. 2. Error, if resize failed.
  549. **Errors**:
  550. - `None`: No error.
  551. - `Out_Of_Memory`: When the allocator's backing buffer or it's backing
  552. allocator does not have enough space to fit in an allocation with the new
  553. size, or an operating system failure occurs.
  554. - `Invalid_Pointer`: The pointer referring to a memory region does not belong
  555. to any of the allocators backing buffers or does not point to a valid start
  556. of an allocation made in that allocator.
  557. - `Invalid_Argument`: When `size` is negative, alignment is not a power of two,
  558. or the `old_size` argument is incorrect.
  559. - `Mode_Not_Implemented`: The allocator does not support the `.Realloc` mode.
  560. **Note**: if `old_size` is `0` and `old_memory` is `nil`, this operation is a
  561. no-op, and should not return errors.
  562. */
  563. @(require_results)
  564. resize_bytes_non_zeroed :: proc(
  565. old_data: []byte,
  566. new_size: int,
  567. alignment: int = DEFAULT_ALIGNMENT,
  568. allocator := context.allocator,
  569. loc := #caller_location,
  570. ) -> ([]byte, Allocator_Error) {
  571. return runtime.non_zero_mem_resize(raw_data(old_data), len(old_data), new_size, alignment, allocator, loc)
  572. }
  573. /*
  574. Query allocator features.
  575. */
  576. @(require_results)
  577. query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: Allocator_Mode_Set) {
  578. if allocator.procedure != nil {
  579. allocator.procedure(allocator.data, .Query_Features, 0, 0, &set, 0, loc)
  580. return set
  581. }
  582. return nil
  583. }
  584. /*
  585. Query allocator information.
  586. */
  587. @(require_results)
  588. query_info :: proc(
  589. pointer: rawptr,
  590. allocator: Allocator,
  591. loc := #caller_location,
  592. ) -> (props: Allocator_Query_Info) {
  593. props.pointer = pointer
  594. if allocator.procedure != nil {
  595. allocator.procedure(allocator.data, .Query_Info, 0, 0, &props, 0, loc)
  596. }
  597. return
  598. }
  599. /*
  600. Free a string.
  601. */
  602. delete_string :: proc(
  603. str: string,
  604. allocator := context.allocator,
  605. loc := #caller_location,
  606. ) -> Allocator_Error {
  607. return runtime.delete_string(str, allocator, loc)
  608. }
  609. /*
  610. Free a cstring.
  611. */
  612. delete_cstring :: proc(
  613. str: cstring,
  614. allocator := context.allocator,
  615. loc := #caller_location,
  616. ) -> Allocator_Error {
  617. return runtime.delete_cstring(str, allocator, loc)
  618. }
  619. /*
  620. Free a dynamic array.
  621. */
  622. delete_dynamic_array :: proc(
  623. array: $T/[dynamic]$E,
  624. loc := #caller_location,
  625. ) -> Allocator_Error {
  626. return runtime.delete_dynamic_array(array, loc)
  627. }
  628. /*
  629. Free a slice.
  630. */
  631. delete_slice :: proc(
  632. array: $T/[]$E,
  633. allocator := context.allocator,
  634. loc := #caller_location,
  635. ) -> Allocator_Error {
  636. return runtime.delete_slice(array, allocator, loc)
  637. }
  638. /*
  639. Free a map.
  640. */
  641. delete_map :: proc(
  642. m: $T/map[$K]$V,
  643. loc := #caller_location,
  644. ) -> Allocator_Error {
  645. return runtime.delete_map(m, loc)
  646. }
  647. /*
  648. Free.
  649. */
  650. delete :: proc{
  651. delete_string,
  652. delete_cstring,
  653. delete_dynamic_array,
  654. delete_slice,
  655. delete_map,
  656. }
  657. /*
  658. Allocate a new object.
  659. This procedure allocates a new object of type `T` using an allocator specified
  660. by `allocator`, and returns a pointer to the allocated object, if allocated
  661. successfully, or `nil` otherwise.
  662. */
  663. @(require_results)
  664. new :: proc(
  665. $T: typeid,
  666. allocator := context.allocator,
  667. loc := #caller_location,
  668. ) -> (^T, Allocator_Error) {
  669. return new_aligned(T, align_of(T), allocator, loc)
  670. }
  671. /*
  672. Allocate a new object with alignment.
  673. This procedure allocates a new object of type `T` using an allocator specified
  674. by `allocator`, and returns a pointer, aligned on a boundary specified by
  675. `alignment` to the allocated object, if allocated successfully, or `nil`
  676. otherwise.
  677. */
  678. @(require_results)
  679. new_aligned :: proc(
  680. $T: typeid,
  681. alignment: int,
  682. allocator := context.allocator,
  683. loc := #caller_location,
  684. ) -> (t: ^T, err: Allocator_Error) {
  685. return runtime.new_aligned(T, alignment, allocator, loc)
  686. }
  687. /*
  688. Allocate a new object and initialize it with a value.
  689. This procedure allocates a new object of type `T` using an allocator specified
  690. by `allocator`, and returns a pointer, aligned on a boundary specified by
  691. `alignment` to the allocated object, if allocated successfully, or `nil`
  692. otherwise. The allocated object is initialized with `data`.
  693. */
  694. @(require_results)
  695. new_clone :: proc(
  696. data: $T,
  697. allocator := context.allocator,
  698. loc := #caller_location,
  699. ) -> (t: ^T, err: Allocator_Error) {
  700. return runtime.new_clone(data, allocator, loc)
  701. }
  702. /*
  703. Allocate a new slice with alignment.
  704. This procedure allocates a new slice of type `T` with length `len`, aligned
  705. on a boundary specified by `alignment` from an allocator specified by
  706. `allocator`, and returns the allocated slice.
  707. */
  708. @(require_results)
  709. make_aligned :: proc(
  710. $T: typeid/[]$E,
  711. #any_int len: int,
  712. alignment: int,
  713. allocator := context.allocator,
  714. loc := #caller_location,
  715. ) -> (slice: T, err: Allocator_Error) {
  716. return runtime.make_aligned(T, len, alignment, allocator, loc)
  717. }
  718. /*
  719. Allocate a new slice.
  720. This procedure allocates a new slice of type `T` with length `len`, from an
  721. allocator specified by `allocator`, and returns the allocated slice.
  722. */
  723. @(require_results)
  724. make_slice :: proc(
  725. $T: typeid/[]$E,
  726. #any_int len: int,
  727. allocator := context.allocator,
  728. loc := #caller_location,
  729. ) -> (T, Allocator_Error) {
  730. return runtime.make_slice(T, len, allocator, loc)
  731. }
  732. /*
  733. Allocate a dynamic array.
  734. This procedure creates a dynamic array of type `T`, with `allocator` as its
  735. backing allocator, and initial length and capacity of `0`.
  736. */
  737. @(require_results)
  738. make_dynamic_array :: proc(
  739. $T: typeid/[dynamic]$E,
  740. allocator := context.allocator,
  741. loc := #caller_location,
  742. ) -> (T, Allocator_Error) {
  743. return runtime.make_dynamic_array(T, allocator, loc)
  744. }
  745. /*
  746. Allocate a dynamic array with initial length.
  747. This procedure creates a dynamic array of type `T`, with `allocator` as its
  748. backing allocator, and initial capacity of `0`, and initial length specified by
  749. `len`.
  750. */
  751. @(require_results)
  752. make_dynamic_array_len :: proc(
  753. $T: typeid/[dynamic]$E,
  754. #any_int len: int,
  755. allocator := context.allocator,
  756. loc := #caller_location,
  757. ) -> (T, Allocator_Error) {
  758. return runtime.make_dynamic_array_len_cap(T, len, len, allocator, loc)
  759. }
  760. /*
  761. Allocate a dynamic array with initial length and capacity.
  762. This procedure creates a dynamic array of type `T`, with `allocator` as its
  763. backing allocator, and initial capacity specified by `cap`, and initial length
  764. specified by `len`.
  765. */
  766. @(require_results)
  767. make_dynamic_array_len_cap :: proc(
  768. $T: typeid/[dynamic]$E,
  769. #any_int len: int,
  770. #any_int cap: int,
  771. allocator := context.allocator,
  772. loc := #caller_location,
  773. ) -> (array: T, err: Allocator_Error) {
  774. return runtime.make_dynamic_array_len_cap(T, len, cap, allocator, loc)
  775. }
  776. /*
  777. Allocate a map.
  778. This procedure creates a map of type `T` with initial capacity specified by
  779. `cap`, that is using an allocator specified by `allocator` as its backing
  780. allocator.
  781. */
  782. @(require_results)
  783. make_map :: proc(
  784. $T: typeid/map[$K]$E,
  785. #any_int cap: int = 1<<runtime.MAP_MIN_LOG2_CAPACITY,
  786. allocator := context.allocator,
  787. loc := #caller_location,
  788. ) -> (m: T, err: Allocator_Error) {
  789. return runtime.make_map(T, cap, allocator, loc)
  790. }
  791. /*
  792. Allocate a multi pointer.
  793. This procedure allocates a multipointer of type `T` pointing to `len` elements,
  794. from an allocator specified by `allocator`.
  795. */
  796. @(require_results)
  797. make_multi_pointer :: proc(
  798. $T: typeid/[^]$E,
  799. #any_int len: int,
  800. allocator := context.allocator,
  801. loc := #caller_location
  802. ) -> (mp: T, err: Allocator_Error) {
  803. return runtime.make_multi_pointer(T, len, allocator, loc)
  804. }
  805. /*
  806. Allocate.
  807. */
  808. make :: proc{
  809. make_slice,
  810. make_dynamic_array,
  811. make_dynamic_array_len,
  812. make_dynamic_array_len_cap,
  813. make_map,
  814. make_multi_pointer,
  815. }
  816. /*
  817. Default resize procedure.
  818. When allocator does not support resize operation, but supports `.Alloc` and
  819. `.Free`, this procedure is used to implement allocator's default behavior on
  820. resize.
  821. The behavior of the function is as follows:
  822. - If `new_size` is `0`, the function acts like `free()`, freeing the memory
  823. region of `old_size` bytes located at `old_memory`.
  824. - If `old_memory` is `nil`, the function acts like `alloc()`, allocating
  825. `new_size` bytes of memory aligned on a boundary specified by `alignment`.
  826. - Otherwise, a new memory region of size `new_size` is allocated, then the
  827. data from the old memory region is copied and the old memory region is
  828. freed.
  829. */
  830. @(require_results)
  831. default_resize_align :: proc(
  832. old_memory: rawptr,
  833. old_size: int,
  834. new_size: int,
  835. alignment: int,
  836. allocator := context.allocator,
  837. loc := #caller_location,
  838. ) -> (res: rawptr, err: Allocator_Error) {
  839. data: []byte
  840. data, err = default_resize_bytes_align(
  841. ([^]byte) (old_memory)[:old_size],
  842. new_size,
  843. alignment,
  844. allocator,
  845. loc,
  846. )
  847. res = raw_data(data)
  848. return
  849. }
  850. /*
  851. Default resize procedure.
  852. When allocator does not support resize operation, but supports
  853. `.Alloc_Non_Zeroed` and `.Free`, this procedure is used to implement allocator's
  854. default behavior on resize.
  855. Unlike `default_resize_align` no new memory is being explicitly
  856. zero-initialized.
  857. The behavior of the function is as follows:
  858. - If `new_size` is `0`, the function acts like `free()`, freeing the memory
  859. region of `old_size` bytes located at `old_memory`.
  860. - If `old_memory` is `nil`, the function acts like `alloc()`, allocating
  861. `new_size` bytes of memory aligned on a boundary specified by `alignment`.
  862. - Otherwise, a new memory region of size `new_size` is allocated, then the
  863. data from the old memory region is copied and the old memory region is
  864. freed.
  865. */
  866. @(require_results)
  867. default_resize_bytes_align_non_zeroed :: proc(
  868. old_data: []byte,
  869. new_size: int,
  870. alignment: int,
  871. allocator := context.allocator,
  872. loc := #caller_location,
  873. ) -> ([]byte, Allocator_Error) {
  874. return _default_resize_bytes_align(old_data, new_size, alignment, false, allocator, loc)
  875. }
  876. /*
  877. Default resize procedure.
  878. When allocator does not support resize operation, but supports `.Alloc` and
  879. `.Free`, this procedure is used to implement allocator's default behavior on
  880. resize.
  881. The behavior of the function is as follows:
  882. - If `new_size` is `0`, the function acts like `free()`, freeing the memory
  883. region specified by `old_data`.
  884. - If `old_data` is `nil`, the function acts like `alloc()`, allocating
  885. `new_size` bytes of memory aligned on a boundary specified by `alignment`.
  886. - Otherwise, a new memory region of size `new_size` is allocated, then the
  887. data from the old memory region is copied and the old memory region is
  888. freed.
  889. */
  890. @(require_results)
  891. default_resize_bytes_align :: proc(
  892. old_data: []byte,
  893. new_size: int,
  894. alignment: int,
  895. allocator := context.allocator,
  896. loc := #caller_location,
  897. ) -> ([]byte, Allocator_Error) {
  898. return _default_resize_bytes_align(old_data, new_size, alignment, true, allocator, loc)
  899. }
  900. @(require_results)
  901. _default_resize_bytes_align :: #force_inline proc(
  902. old_data: []byte,
  903. new_size: int,
  904. alignment: int,
  905. should_zero: bool,
  906. allocator := context.allocator,
  907. loc := #caller_location,
  908. ) -> ([]byte, Allocator_Error) {
  909. old_memory := raw_data(old_data)
  910. old_size := len(old_data)
  911. if old_memory == nil {
  912. if should_zero {
  913. return alloc_bytes(new_size, alignment, allocator, loc)
  914. } else {
  915. return alloc_bytes_non_zeroed(new_size, alignment, allocator, loc)
  916. }
  917. }
  918. if new_size == 0 {
  919. err := free_bytes(old_data, allocator, loc)
  920. return nil, err
  921. }
  922. if new_size == old_size && is_aligned(old_memory, alignment) {
  923. return old_data, .None
  924. }
  925. new_memory : []byte
  926. err : Allocator_Error
  927. if should_zero {
  928. new_memory, err = alloc_bytes(new_size, alignment, allocator, loc)
  929. } else {
  930. new_memory, err = alloc_bytes_non_zeroed(new_size, alignment, allocator, loc)
  931. }
  932. if new_memory == nil || err != nil {
  933. return nil, err
  934. }
  935. runtime.copy(new_memory, old_data)
  936. free_bytes(old_data, allocator, loc)
  937. return new_memory, err
  938. }