alloc.odin 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  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. Allocator_Mode :: runtime.Allocator_Mode
  5. /*
  6. Allocator_Mode :: enum byte {
  7. Alloc,
  8. Free,
  9. Free_All,
  10. Resize,
  11. Query_Features,
  12. Alloc_Non_Zeroed,
  13. Resize_Non_Zeroed,
  14. }
  15. */
  16. Allocator_Mode_Set :: runtime.Allocator_Mode_Set
  17. /*
  18. Allocator_Mode_Set :: distinct bit_set[Allocator_Mode];
  19. */
  20. Allocator_Query_Info :: runtime.Allocator_Query_Info
  21. /*
  22. Allocator_Query_Info :: struct {
  23. pointer: rawptr,
  24. size: Maybe(int),
  25. alignment: Maybe(int),
  26. }
  27. */
  28. Allocator_Error :: runtime.Allocator_Error
  29. /*
  30. Allocator_Error :: enum byte {
  31. None = 0,
  32. Out_Of_Memory = 1,
  33. Invalid_Pointer = 2,
  34. Invalid_Argument = 3,
  35. Mode_Not_Implemented = 4,
  36. }
  37. */
  38. Allocator_Proc :: runtime.Allocator_Proc
  39. /*
  40. Allocator_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode,
  41. size, alignment: int,
  42. old_memory: rawptr, old_size: int, location: Source_Code_Location = #caller_location) -> ([]byte, Allocator_Error);
  43. */
  44. Allocator :: runtime.Allocator
  45. /*
  46. Allocator :: struct {
  47. procedure: Allocator_Proc,
  48. data: rawptr,
  49. }
  50. */
  51. DEFAULT_ALIGNMENT :: 2*align_of(rawptr)
  52. DEFAULT_PAGE_SIZE ::
  53. 64 * 1024 when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 else
  54. 16 * 1024 when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 else
  55. 4 * 1024
  56. @(require_results)
  57. alloc :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (rawptr, Allocator_Error) {
  58. data, err := runtime.mem_alloc(size, alignment, allocator, loc)
  59. return raw_data(data), err
  60. }
  61. @(require_results)
  62. alloc_bytes :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
  63. return runtime.mem_alloc(size, alignment, allocator, loc)
  64. }
  65. @(require_results)
  66. alloc_bytes_non_zeroed :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
  67. return runtime.mem_alloc_non_zeroed(size, alignment, allocator, loc)
  68. }
  69. free :: proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
  70. return runtime.mem_free(ptr, allocator, loc)
  71. }
  72. free_with_size :: proc(ptr: rawptr, byte_count: int, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
  73. return runtime.mem_free_with_size(ptr, byte_count, allocator, loc)
  74. }
  75. free_bytes :: proc(bytes: []byte, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
  76. return runtime.mem_free_bytes(bytes, allocator, loc)
  77. }
  78. free_all :: proc(allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
  79. return runtime.mem_free_all(allocator, loc)
  80. }
  81. @(require_results)
  82. resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (rawptr, Allocator_Error) {
  83. data, err := runtime.mem_resize(ptr, old_size, new_size, alignment, allocator, loc)
  84. return raw_data(data), err
  85. }
  86. @(require_results)
  87. resize_bytes :: proc(old_data: []byte, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
  88. return runtime.mem_resize(raw_data(old_data), len(old_data), new_size, alignment, allocator, loc)
  89. }
  90. @(require_results)
  91. query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: Allocator_Mode_Set) {
  92. if allocator.procedure != nil {
  93. allocator.procedure(allocator.data, .Query_Features, 0, 0, &set, 0, loc)
  94. return set
  95. }
  96. return nil
  97. }
  98. @(require_results)
  99. query_info :: proc(pointer: rawptr, allocator: Allocator, loc := #caller_location) -> (props: Allocator_Query_Info) {
  100. props.pointer = pointer
  101. if allocator.procedure != nil {
  102. allocator.procedure(allocator.data, .Query_Info, 0, 0, &props, 0, loc)
  103. }
  104. return
  105. }
  106. delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
  107. return runtime.delete_string(str, allocator, loc)
  108. }
  109. delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
  110. return runtime.delete_cstring(str, allocator, loc)
  111. }
  112. delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) -> Allocator_Error {
  113. return runtime.delete_dynamic_array(array, loc)
  114. }
  115. delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
  116. return runtime.delete_slice(array, allocator, loc)
  117. }
  118. delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error {
  119. return runtime.delete_map(m, loc)
  120. }
  121. delete :: proc{
  122. delete_string,
  123. delete_cstring,
  124. delete_dynamic_array,
  125. delete_slice,
  126. delete_map,
  127. }
  128. @(require_results)
  129. new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) {
  130. return new_aligned(T, align_of(T), allocator, loc)
  131. }
  132. @(require_results)
  133. new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) {
  134. return runtime.new_aligned(T, alignment, allocator, loc)
  135. }
  136. @(require_results)
  137. new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) {
  138. return runtime.new_clone(data, allocator, loc)
  139. }
  140. @(require_results)
  141. make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (slice: T, err: Allocator_Error) {
  142. return runtime.make_aligned(T, len, alignment, allocator, loc)
  143. }
  144. @(require_results)
  145. make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
  146. return runtime.make_slice(T, len, allocator, loc)
  147. }
  148. @(require_results)
  149. make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
  150. return runtime.make_dynamic_array(T, allocator, loc)
  151. }
  152. @(require_results)
  153. make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
  154. return runtime.make_dynamic_array(T, len, allocator, loc)
  155. }
  156. @(require_results)
  157. 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) {
  158. return runtime.make_dynamic_array(T, len, cap, allocator, loc)
  159. }
  160. @(require_results)
  161. make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = 1<<runtime.MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> (m: T, err: Allocator_Error) {
  162. return runtime.make_map(T, cap, allocator, loc)
  163. }
  164. @(require_results)
  165. make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) {
  166. return runtime.make_multi_pointer(T, len, allocator, loc)
  167. }
  168. make :: proc{
  169. make_slice,
  170. make_dynamic_array,
  171. make_dynamic_array_len,
  172. make_dynamic_array_len_cap,
  173. make_map,
  174. make_multi_pointer,
  175. }
  176. @(require_results)
  177. default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> (res: rawptr, err: Allocator_Error) {
  178. data: []byte
  179. data, err = default_resize_bytes_align(([^]byte)(old_memory)[:old_size], new_size, alignment, allocator, loc)
  180. res = raw_data(data)
  181. return
  182. }
  183. @(require_results)
  184. default_resize_bytes_align_non_zeroed :: proc(old_data: []byte, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
  185. return _default_resize_bytes_align(old_data, new_size, alignment, false, allocator, loc)
  186. }
  187. @(require_results)
  188. default_resize_bytes_align :: proc(old_data: []byte, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
  189. return _default_resize_bytes_align(old_data, new_size, alignment, true, allocator, loc)
  190. }
  191. @(require_results)
  192. _default_resize_bytes_align :: #force_inline proc(old_data: []byte, new_size, alignment: int, should_zero: bool, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
  193. old_memory := raw_data(old_data)
  194. old_size := len(old_data)
  195. if old_memory == nil {
  196. if should_zero {
  197. return alloc_bytes(new_size, alignment, allocator, loc)
  198. } else {
  199. return alloc_bytes_non_zeroed(new_size, alignment, allocator, loc)
  200. }
  201. }
  202. if new_size == 0 {
  203. err := free_bytes(old_data, allocator, loc)
  204. return nil, err
  205. }
  206. if new_size == old_size {
  207. return old_data, .None
  208. }
  209. new_memory : []byte
  210. err : Allocator_Error
  211. if should_zero {
  212. new_memory, err = alloc_bytes(new_size, alignment, allocator, loc)
  213. } else {
  214. new_memory, err = alloc_bytes_non_zeroed(new_size, alignment, allocator, loc)
  215. }
  216. if new_memory == nil || err != nil {
  217. return nil, err
  218. }
  219. runtime.copy(new_memory, old_data)
  220. free_bytes(old_data, allocator, loc)
  221. return new_memory, err
  222. }