alloc.odin 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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: Maybe(rawptr),
  22. size: Maybe(int),
  23. alignment: Maybe(int),
  24. }
  25. */
  26. Allocator_Proc :: runtime.Allocator_Proc;
  27. /*
  28. Allocator_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode,
  29. size, alignment: int,
  30. old_memory: rawptr, old_size: int, flags: u64 = 0, location := #caller_location) -> rawptr;
  31. */
  32. Allocator :: runtime.Allocator;
  33. /*
  34. Allocator :: struct {
  35. procedure: Allocator_Proc,
  36. data: rawptr,
  37. }
  38. */
  39. DEFAULT_ALIGNMENT :: 2*align_of(rawptr);
  40. alloc :: inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr {
  41. if size == 0 do return nil;
  42. if allocator.procedure == nil do return nil;
  43. return allocator.procedure(allocator.data, Allocator_Mode.Alloc, size, alignment, nil, 0, 0, loc);
  44. }
  45. free :: inline proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) {
  46. if ptr == nil do return;
  47. if allocator.procedure == nil do return;
  48. allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, 0, 0, loc);
  49. }
  50. free_all :: inline proc(allocator := context.allocator, loc := #caller_location) {
  51. if allocator.procedure != nil {
  52. allocator.procedure(allocator.data, Allocator_Mode.Free_All, 0, 0, nil, 0, 0, loc);
  53. }
  54. }
  55. resize :: inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr {
  56. if allocator.procedure == nil {
  57. return nil;
  58. }
  59. if new_size == 0 {
  60. if ptr != nil {
  61. allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, 0, 0, loc);
  62. }
  63. return nil;
  64. } else if ptr == nil {
  65. return allocator.procedure(allocator.data, Allocator_Mode.Alloc, new_size, alignment, nil, 0, 0, loc);
  66. }
  67. return allocator.procedure(allocator.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, 0, loc);
  68. }
  69. query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: Allocator_Mode_Set) {
  70. if allocator.procedure != nil {
  71. allocator.procedure(allocator.data, Allocator_Mode.Query_Features, 0, 0, &set, 0, 0, loc);
  72. return set;
  73. }
  74. return nil;
  75. }
  76. query_info :: proc(pointer: rawptr, allocator: Allocator, loc := #caller_location) -> (props: Allocator_Query_Info) {
  77. props.pointer = pointer;
  78. if allocator.procedure != nil {
  79. allocator.procedure(allocator.data, Allocator_Mode.Query_Info, 0, 0, &props, 0, 0, loc);
  80. }
  81. return;
  82. }
  83. delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) {
  84. free(raw_data(str), allocator, loc);
  85. }
  86. delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) {
  87. free((^byte)(str), allocator, loc);
  88. }
  89. delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) {
  90. free(raw_data(array), array.allocator, loc);
  91. }
  92. delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) {
  93. free(raw_data(array), allocator, loc);
  94. }
  95. delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) {
  96. raw := transmute(Raw_Map)m;
  97. delete_slice(raw.hashes);
  98. free(raw.entries.data, raw.entries.allocator, loc);
  99. }
  100. delete :: proc{
  101. delete_string,
  102. delete_cstring,
  103. delete_dynamic_array,
  104. delete_slice,
  105. delete_map,
  106. };
  107. new :: inline proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> ^T {
  108. return new_aligned(T, align_of(T), allocator, loc);
  109. }
  110. new_aligned :: inline proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> ^T {
  111. ptr := (^T)(alloc(size_of(T), alignment, allocator, loc));
  112. if ptr != nil do ptr^ = T{};
  113. return ptr;
  114. }
  115. new_clone :: inline proc(data: $T, allocator := context.allocator, loc := #caller_location) -> ^T {
  116. ptr := (^T)(alloc(size_of(T), align_of(T), allocator, loc));
  117. if ptr != nil do ptr^ = data;
  118. return ptr;
  119. }
  120. make_slice :: inline proc($T: typeid/[]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> T {
  121. return make_aligned(T, len, align_of(E), allocator, loc);
  122. }
  123. make_aligned :: proc($T: typeid/[]$E, auto_cast len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> T {
  124. runtime.make_slice_error_loc(loc, len);
  125. data := alloc(size_of(E)*len, alignment, allocator, loc);
  126. if data == nil && size_of(E) != 0 {
  127. return nil;
  128. }
  129. zero(data, size_of(E)*len);
  130. s := Raw_Slice{data, len};
  131. return transmute(T)s;
  132. }
  133. make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> T {
  134. return make_dynamic_array_len_cap(T, 0, 16, allocator, loc);
  135. }
  136. make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> T {
  137. return make_dynamic_array_len_cap(T, len, len, allocator, loc);
  138. }
  139. make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, auto_cast len: int, auto_cast cap: int, allocator := context.allocator, loc := #caller_location) -> T {
  140. runtime.make_dynamic_array_error_loc(loc, len, cap);
  141. data := alloc(size_of(E)*cap, align_of(E), allocator, loc);
  142. s := Raw_Dynamic_Array{data, len, cap, allocator};
  143. if data == nil && size_of(E) != 0 {
  144. s.len, s.cap = 0, 0;
  145. }
  146. zero(data, size_of(E)*len);
  147. return transmute(T)s;
  148. }
  149. make_map :: proc($T: typeid/map[$K]$E, auto_cast cap: int = 16, allocator := context.allocator, loc := #caller_location) -> T {
  150. runtime.make_map_expr_error_loc(loc, cap);
  151. context.allocator = allocator;
  152. m: T;
  153. reserve_map(&m, cap);
  154. return m;
  155. }
  156. make :: proc{
  157. make_slice,
  158. make_dynamic_array,
  159. make_dynamic_array_len,
  160. make_dynamic_array_len_cap,
  161. make_map,
  162. };
  163. default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> rawptr {
  164. if old_memory == nil do return alloc(new_size, alignment, allocator, loc);
  165. if new_size == 0 {
  166. free(old_memory, allocator, loc);
  167. return nil;
  168. }
  169. if new_size == old_size do return old_memory;
  170. new_memory := alloc(new_size, alignment, allocator, loc);
  171. if new_memory == nil do return nil;
  172. copy(new_memory, old_memory, min(old_size, new_size));
  173. free(old_memory, allocator, loc);
  174. return new_memory;
  175. }