alloc.odin 4.8 KB

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