alloc.odin 9.1 KB

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