alloc.odin 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  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. if ptr == nil || allocator.procedure == nil {
  74. return nil
  75. }
  76. _, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, byte_count, loc)
  77. return err
  78. }
  79. free_bytes :: proc(bytes: []byte, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
  80. return runtime.mem_free_bytes(bytes, allocator, loc)
  81. }
  82. free_all :: proc(allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
  83. return runtime.mem_free_all(allocator, loc)
  84. }
  85. @(require_results)
  86. resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (rawptr, Allocator_Error) {
  87. data, err := runtime.mem_resize(ptr, old_size, new_size, alignment, allocator, loc)
  88. return raw_data(data), err
  89. }
  90. @(require_results)
  91. resize_bytes :: proc(old_data: []byte, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
  92. return runtime.mem_resize(raw_data(old_data), len(old_data), new_size, alignment, allocator, loc)
  93. }
  94. @(require_results)
  95. query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: Allocator_Mode_Set) {
  96. if allocator.procedure != nil {
  97. allocator.procedure(allocator.data, .Query_Features, 0, 0, &set, 0, loc)
  98. return set
  99. }
  100. return nil
  101. }
  102. @(require_results)
  103. query_info :: proc(pointer: rawptr, allocator: Allocator, loc := #caller_location) -> (props: Allocator_Query_Info) {
  104. props.pointer = pointer
  105. if allocator.procedure != nil {
  106. allocator.procedure(allocator.data, .Query_Info, 0, 0, &props, 0, loc)
  107. }
  108. return
  109. }
  110. delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
  111. return free_with_size(raw_data(str), len(str), allocator, loc)
  112. }
  113. delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
  114. return free((^byte)(str), allocator, loc)
  115. }
  116. delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) -> Allocator_Error {
  117. return free_with_size(raw_data(array), cap(array)*size_of(E), array.allocator, loc)
  118. }
  119. delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
  120. return free_with_size(raw_data(array), len(array)*size_of(E), allocator, loc)
  121. }
  122. delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error {
  123. return runtime.map_free_dynamic(transmute(Raw_Map)m, runtime.map_info(T), loc)
  124. }
  125. delete :: proc{
  126. delete_string,
  127. delete_cstring,
  128. delete_dynamic_array,
  129. delete_slice,
  130. delete_map,
  131. }
  132. @(require_results)
  133. new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) {
  134. return new_aligned(T, align_of(T), allocator, loc)
  135. }
  136. @(require_results)
  137. new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) {
  138. data := alloc_bytes(size_of(T), alignment, allocator, loc) or_return
  139. t = (^T)(raw_data(data))
  140. return
  141. }
  142. @(require_results)
  143. new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) {
  144. backing := alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return
  145. t = (^T)(raw_data(backing))
  146. if t != nil {
  147. t^ = data
  148. return t, nil
  149. }
  150. return nil, .Out_Of_Memory
  151. }
  152. @(require_results)
  153. make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (slice: T, err: Allocator_Error) {
  154. runtime.make_slice_error_loc(loc, len)
  155. data := alloc_bytes(size_of(E)*len, alignment, allocator, loc) or_return
  156. if data == nil && size_of(E) != 0 {
  157. return
  158. }
  159. slice = transmute(T)Raw_Slice{raw_data(data), len}
  160. return
  161. }
  162. @(require_results)
  163. make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
  164. return make_aligned(T, len, align_of(E), allocator, loc)
  165. }
  166. @(require_results)
  167. make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
  168. return make_dynamic_array_len_cap(T, 0, 16, allocator, loc)
  169. }
  170. @(require_results)
  171. make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
  172. return make_dynamic_array_len_cap(T, len, len, allocator, loc)
  173. }
  174. @(require_results)
  175. 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) {
  176. runtime.make_dynamic_array_error_loc(loc, len, cap)
  177. data := alloc_bytes(size_of(E)*cap, align_of(E), allocator, loc) or_return
  178. s := Raw_Dynamic_Array{raw_data(data), len, cap, allocator}
  179. if data == nil && size_of(E) != 0 {
  180. s.len, s.cap = 0, 0
  181. }
  182. array = transmute(T)s
  183. return
  184. }
  185. @(require_results)
  186. 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) {
  187. runtime.make_map_expr_error_loc(loc, cap)
  188. context.allocator = allocator
  189. err = reserve_map(&m, cap, loc)
  190. return
  191. }
  192. @(require_results)
  193. make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) {
  194. runtime.make_slice_error_loc(loc, len)
  195. data := alloc_bytes(size_of(E)*len, align_of(E), allocator, loc) or_return
  196. if data == nil && size_of(E) != 0 {
  197. return
  198. }
  199. mp = cast(T)raw_data(data)
  200. return
  201. }
  202. make :: proc{
  203. make_slice,
  204. make_dynamic_array,
  205. make_dynamic_array_len,
  206. make_dynamic_array_len_cap,
  207. make_map,
  208. make_multi_pointer,
  209. }
  210. @(require_results)
  211. default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> (res: rawptr, err: Allocator_Error) {
  212. data: []byte
  213. data, err = default_resize_bytes_align(([^]byte)(old_memory)[:old_size], new_size, alignment, allocator, loc)
  214. res = raw_data(data)
  215. return
  216. }
  217. @(require_results)
  218. default_resize_bytes_align_non_zeroed :: proc(old_data: []byte, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
  219. return _default_resize_bytes_align(old_data, new_size, alignment, false, allocator, loc)
  220. }
  221. @(require_results)
  222. default_resize_bytes_align :: proc(old_data: []byte, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
  223. return _default_resize_bytes_align(old_data, new_size, alignment, true, allocator, loc)
  224. }
  225. @(require_results)
  226. _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) {
  227. old_memory := raw_data(old_data)
  228. old_size := len(old_data)
  229. if old_memory == nil {
  230. if should_zero {
  231. return alloc_bytes(new_size, alignment, allocator, loc)
  232. } else {
  233. return alloc_bytes_non_zeroed(new_size, alignment, allocator, loc)
  234. }
  235. }
  236. if new_size == 0 {
  237. err := free_bytes(old_data, allocator, loc)
  238. return nil, err
  239. }
  240. if new_size == old_size {
  241. return old_data, .None
  242. }
  243. new_memory : []byte
  244. err : Allocator_Error
  245. if should_zero {
  246. new_memory, err = alloc_bytes(new_size, alignment, allocator, loc)
  247. } else {
  248. new_memory, err = alloc_bytes_non_zeroed(new_size, alignment, allocator, loc)
  249. }
  250. if new_memory == nil || err != nil {
  251. return nil, err
  252. }
  253. runtime.copy(new_memory, old_data)
  254. free_bytes(old_data, allocator, loc)
  255. return new_memory, err
  256. }