alloc.odin 5.5 KB

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