mem.odin 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. package mem
  2. import "core:runtime"
  3. foreign _ {
  4. @(link_name = "llvm.bswap.i16") swap16 :: proc(b: u16) -> u16 ---;
  5. @(link_name = "llvm.bswap.i32") swap32 :: proc(b: u32) -> u32 ---;
  6. @(link_name = "llvm.bswap.i64") swap64 :: proc(b: u64) -> u64 ---;
  7. }
  8. swap :: proc[swap16, swap32, swap64];
  9. set :: proc "contextless" (data: rawptr, value: i32, len: int) -> rawptr {
  10. if data == nil do return nil;
  11. foreign _ {
  12. when size_of(rawptr) == 8 {
  13. @(link_name="llvm.memset.p0i8.i64")
  14. llvm_memset :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) ---;
  15. } else {
  16. @(link_name="llvm.memset.p0i8.i32")
  17. llvm_memset :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) ---;
  18. }
  19. }
  20. llvm_memset(data, byte(value), len, 1, false);
  21. return data;
  22. }
  23. zero :: proc "contextless" (data: rawptr, len: int) -> rawptr {
  24. return set(data, 0, len);
  25. }
  26. copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
  27. if src == nil do return dst;
  28. // NOTE(bill): This _must_ be implemented like C's memmove
  29. foreign _ {
  30. when size_of(rawptr) == 8 {
  31. @(link_name="llvm.memmove.p0i8.p0i8.i64")
  32. llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
  33. } else {
  34. @(link_name="llvm.memmove.p0i8.p0i8.i32")
  35. llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
  36. }
  37. }
  38. llvm_memmove(dst, src, len, 1, false);
  39. return dst;
  40. }
  41. copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
  42. if src == nil do return dst;
  43. // NOTE(bill): This _must_ be implemented like C's memcpy
  44. foreign _ {
  45. when size_of(rawptr) == 8 {
  46. @(link_name="llvm.memcpy.p0i8.p0i8.i64")
  47. llvm_memcpy :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
  48. } else {
  49. @(link_name="llvm.memcpy.p0i8.p0i8.i32")
  50. llvm_memcpy :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
  51. }
  52. }
  53. llvm_memcpy(dst, src, len, 1, false);
  54. return dst;
  55. }
  56. compare :: proc "contextless" (a, b: []byte) -> int {
  57. return compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b)));
  58. }
  59. compare_byte_ptrs :: proc "contextless" (a, b: ^byte, n: int) -> int {
  60. pa :: ptr_offset;
  61. for i in 0..n-1 do switch {
  62. case pa(a, i)^ < pa(b, i)^: return -1;
  63. case pa(a, i)^ > pa(b, i)^: return +1;
  64. }
  65. return 0;
  66. }
  67. compare_ptrs :: inline proc "contextless" (a, b: rawptr, n: int) -> int {
  68. return compare_byte_ptrs((^byte)(a), (^byte)(b), n);
  69. }
  70. ptr_offset :: proc "contextless" (ptr: $P/^$T, n: int) -> P {
  71. new := int(uintptr(ptr)) + size_of(T)*n;
  72. return P(uintptr(new));
  73. }
  74. ptr_sub :: proc "contextless" (a, b: $P/^$T) -> int {
  75. return (int(uintptr(a)) - int(uintptr(b)))/size_of(T);
  76. }
  77. slice_ptr :: proc "contextless" (ptr: ^$T, len: int) -> []T {
  78. assert(len >= 0);
  79. slice := Raw_Slice{data = ptr, len = len};
  80. return transmute([]T)slice;
  81. }
  82. slice_to_bytes :: proc "contextless" (slice: $E/[]$T) -> []byte {
  83. s := transmute(Raw_Slice)slice;
  84. s.len *= size_of(T);
  85. return transmute([]byte)s;
  86. }
  87. buffer_from_slice :: proc(backing: $T/[]$E) -> [dynamic]E {
  88. s := transmute(Raw_Slice)backing;
  89. d := Raw_Dynamic_Array{
  90. data = s.data,
  91. len = 0,
  92. cap = s.len,
  93. allocator = nil_allocator(),
  94. };
  95. return transmute([dynamic]E)d;
  96. }
  97. ptr_to_bytes :: proc "contextless" (ptr: ^$T, len := 1) -> []byte {
  98. assert(len >= 0);
  99. return transmute([]byte)Raw_Slice{ptr, len*size_of(T)};
  100. }
  101. any_to_bytes :: proc "contextless" (val: any) -> []byte {
  102. ti := type_info_of(val.typeid);
  103. size := ti != nil ? ti.size : 0;
  104. return transmute([]byte)Raw_Slice{val.data, size};
  105. }
  106. kilobytes :: inline proc "contextless" (x: int) -> int do return (x) * 1024;
  107. megabytes :: inline proc "contextless" (x: int) -> int do return kilobytes(x) * 1024;
  108. gigabytes :: inline proc "contextless" (x: int) -> int do return megabytes(x) * 1024;
  109. terabytes :: inline proc "contextless" (x: int) -> int do return gigabytes(x) * 1024;
  110. is_power_of_two :: proc(x: uintptr) -> bool {
  111. if x <= 0 do return false;
  112. return (x & (x-1)) == 0;
  113. }
  114. align_forward :: proc(ptr: rawptr, align: uintptr) -> rawptr {
  115. assert(is_power_of_two(align));
  116. a := uintptr(align);
  117. p := uintptr(ptr);
  118. modulo := p & (a-1);
  119. if modulo != 0 do p += a - modulo;
  120. return rawptr(p);
  121. }
  122. AllocationHeader :: struct {size: int};
  123. allocation_header_fill :: proc(header: ^AllocationHeader, data: rawptr, size: int) {
  124. header.size = size;
  125. ptr := cast(^uint)(ptr_offset(header, 1));
  126. n := ptr_sub(cast(^uint)data, ptr);
  127. for i in 0..n-1 {
  128. ptr_offset(ptr, i)^ = ~uint(0);
  129. }
  130. }
  131. allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
  132. if data == nil do return nil;
  133. p := cast(^uint)data;
  134. for ptr_offset(p, -1)^ == ~uint(0) do p = ptr_offset(p, -1);
  135. return (^AllocationHeader)(ptr_offset(p, -1));
  136. }
  137. Fixed_Byte_Buffer :: distinct [dynamic]byte;
  138. make_fixed_byte_buffer :: proc(backing: []byte) -> Fixed_Byte_Buffer {
  139. s := transmute(Raw_Slice)backing;
  140. d: Raw_Dynamic_Array;
  141. d.data = s.data;
  142. d.len = 0;
  143. d.cap = s.len;
  144. d.allocator = nil_allocator();
  145. return transmute(Fixed_Byte_Buffer)d;
  146. }
  147. // Custom allocators
  148. Arena :: struct {
  149. backing: Allocator,
  150. memory: Fixed_Byte_Buffer,
  151. temp_count: int,
  152. }
  153. ArenaTempMemory :: struct {
  154. arena: ^Arena,
  155. original_count: int,
  156. }
  157. init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
  158. backing = Allocator{};
  159. memory = make_fixed_byte_buffer(data);
  160. temp_count = 0;
  161. }
  162. init_arena_from_context :: proc(using a: ^Arena, size: int) {
  163. backing = context.allocator;
  164. memory = make_fixed_byte_buffer(make([]byte, size));
  165. temp_count = 0;
  166. }
  167. context_from_allocator :: proc(a: Allocator) -> runtime.Context {
  168. c := context;
  169. c.allocator = a;
  170. return c;
  171. }
  172. destroy_arena :: proc(using a: ^Arena) {
  173. if backing.procedure != nil {
  174. context = context_from_allocator(backing);
  175. if memory != nil {
  176. free(&memory[0]);
  177. }
  178. memory = nil;
  179. }
  180. }
  181. arena_allocator :: proc(arena: ^Arena) -> Allocator {
  182. return Allocator{
  183. procedure = arena_allocator_proc,
  184. data = arena,
  185. };
  186. }
  187. arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
  188. size, alignment: int,
  189. old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr {
  190. using Allocator_Mode;
  191. arena := cast(^Arena)allocator_data;
  192. switch mode {
  193. case Alloc:
  194. total_size := size + alignment;
  195. if len(arena.memory) + total_size > cap(arena.memory) {
  196. return nil;
  197. }
  198. #no_bounds_check end := &arena.memory[len(arena.memory)];
  199. ptr := align_forward(end, uintptr(alignment));
  200. (^Raw_Slice)(&arena.memory).len += total_size;
  201. return zero(ptr, size);
  202. case Free:
  203. // NOTE(bill): Free all at once
  204. // Use ArenaTempMemory if you want to free a block
  205. case Free_All:
  206. (^Raw_Slice)(&arena.memory).len = 0;
  207. case Resize:
  208. return default_resize_align(old_memory, old_size, size, alignment);
  209. }
  210. return nil;
  211. }
  212. begin_arena_temp_memory :: proc(a: ^Arena) -> ArenaTempMemory {
  213. tmp: ArenaTempMemory;
  214. tmp.arena = a;
  215. tmp.original_count = len(a.memory);
  216. a.temp_count += 1;
  217. return tmp;
  218. }
  219. end_arena_temp_memory :: proc(using tmp: ArenaTempMemory) {
  220. assert(len(arena.memory) >= original_count);
  221. assert(arena.temp_count > 0);
  222. (^Raw_Dynamic_Array)(&arena.memory).len = original_count;
  223. arena.temp_count -= 1;
  224. }
  225. align_formula :: proc(size, align: int) -> int {
  226. result := size + align-1;
  227. return result - result%align;
  228. }