mem.odin 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. #import "fmt.odin";
  2. #import "os.odin";
  3. swap :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bswap.i16";
  4. swap :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bswap.i32";
  5. swap :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bswap.i64";
  6. set :: proc(data: rawptr, value: i32, len: int) -> rawptr {
  7. return __mem_set(data, value, len);
  8. }
  9. zero :: proc(data: rawptr, len: int) -> rawptr {
  10. return __mem_zero(data, len);
  11. }
  12. copy :: proc(dst, src: rawptr, len: int) -> rawptr {
  13. return __mem_copy(dst, src, len);
  14. }
  15. copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr {
  16. return __mem_copy_non_overlapping(dst, src, len);
  17. }
  18. compare :: proc(a, b: []byte) -> int {
  19. return __mem_compare(a.data, b.data, min(a.count, b.count));
  20. }
  21. kilobytes :: proc(x: int) -> int #inline { return (x) * 1024; }
  22. megabytes :: proc(x: int) -> int #inline { return kilobytes(x) * 1024; }
  23. gigabytes :: proc(x: int) -> int #inline { return megabytes(x) * 1024; }
  24. terabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024; }
  25. is_power_of_two :: proc(x: int) -> bool {
  26. if x <= 0 {
  27. return false;
  28. }
  29. return (x & (x-1)) == 0;
  30. }
  31. align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
  32. assert(is_power_of_two(align));
  33. a := cast(uint)align;
  34. p := cast(uint)ptr;
  35. modulo := p & (a-1);
  36. if modulo != 0 {
  37. p += a - modulo;
  38. }
  39. return cast(rawptr)p;
  40. }
  41. Allocation_Header :: struct {
  42. size: int,
  43. }
  44. allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: int) {
  45. header.size = size;
  46. ptr := cast(^int)(header+1);
  47. for i := 0; cast(rawptr)ptr < data; i++ {
  48. (ptr+i)^ = -1;
  49. }
  50. }
  51. allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
  52. if data == nil {
  53. return nil;
  54. }
  55. p := cast(^int)data;
  56. for (p-1)^ == -1 {
  57. p = (p-1);
  58. }
  59. return cast(^Allocation_Header)p-1;
  60. }
  61. // Custom allocators
  62. Arena :: struct {
  63. backing: Allocator,
  64. offset: int,
  65. memory: []byte,
  66. temp_count: int,
  67. }
  68. Arena_Temp_Memory :: struct {
  69. arena: ^Arena,
  70. original_count: int,
  71. }
  72. init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
  73. backing = Allocator{};
  74. memory = data[..0];
  75. temp_count = 0;
  76. }
  77. init_arena_from_context :: proc(using a: ^Arena, size: int) {
  78. backing = context.allocator;
  79. memory = new_slice(byte, size);
  80. temp_count = 0;
  81. }
  82. free_arena :: proc(using a: ^Arena) {
  83. if backing.procedure != nil {
  84. push_allocator backing {
  85. free(memory);
  86. memory = nil;
  87. offset = 0;
  88. }
  89. }
  90. }
  91. arena_allocator :: proc(arena: ^Arena) -> Allocator {
  92. return Allocator{
  93. procedure = arena_allocator_proc,
  94. data = arena,
  95. };
  96. }
  97. arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
  98. size, alignment: int,
  99. old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
  100. using Allocator_Mode;
  101. arena := cast(^Arena)allocator_data;
  102. match mode {
  103. case ALLOC:
  104. total_size := size + alignment;
  105. if arena.offset + total_size > arena.memory.count {
  106. fmt.fprintln(os.stderr, "Arena out of memory");
  107. return nil;
  108. }
  109. #no_bounds_check end := ^arena.memory[arena.offset];
  110. ptr := align_forward(end, alignment);
  111. arena.offset += total_size;
  112. return zero(ptr, size);
  113. case FREE:
  114. // NOTE(bill): Free all at once
  115. // Use Arena_Temp_Memory if you want to free a block
  116. case FREE_ALL:
  117. arena.offset = 0;
  118. case RESIZE:
  119. return default_resize_align(old_memory, old_size, size, alignment);
  120. }
  121. return nil;
  122. }
  123. begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory {
  124. tmp: Arena_Temp_Memory;
  125. tmp.arena = a;
  126. tmp.original_count = a.memory.count;
  127. a.temp_count++;
  128. return tmp;
  129. }
  130. end_arena_temp_memory :: proc(using tmp: Arena_Temp_Memory) {
  131. assert(arena.memory.count >= original_count);
  132. assert(arena.temp_count > 0);
  133. arena.memory.count = original_count;
  134. arena.temp_count--;
  135. }
  136. align_of_type_info :: proc(type_info: ^Type_Info) -> int {
  137. prev_pow2 :: proc(n: i64) -> i64 {
  138. if n <= 0 {
  139. return 0;
  140. }
  141. n |= n >> 1;
  142. n |= n >> 2;
  143. n |= n >> 4;
  144. n |= n >> 8;
  145. n |= n >> 16;
  146. n |= n >> 32;
  147. return n - (n >> 1);
  148. }
  149. WORD_SIZE :: size_of(int);
  150. MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
  151. using Type_Info;
  152. match info in type_info {
  153. case Named:
  154. return align_of_type_info(info.base);
  155. case Integer:
  156. return info.size;
  157. case Float:
  158. return info.size;
  159. case String:
  160. return WORD_SIZE;
  161. case Boolean:
  162. return 1;
  163. case Any:
  164. return WORD_SIZE;
  165. case Pointer:
  166. return WORD_SIZE;
  167. case Procedure:
  168. return WORD_SIZE;
  169. case Array:
  170. return align_of_type_info(info.elem);
  171. case Dynamic_Array:
  172. return WORD_SIZE;
  173. case Slice:
  174. return WORD_SIZE;
  175. case Vector:
  176. size := size_of_type_info(info.elem);
  177. count := cast(int)max(prev_pow2(cast(i64)info.count), 1);
  178. total := size * count;
  179. return clamp(total, 1, MAX_ALIGN);
  180. case Tuple:
  181. return info.align;
  182. case Struct:
  183. return info.align;
  184. case Union:
  185. return info.align;
  186. case Raw_Union:
  187. return info.align;
  188. case Enum:
  189. return align_of_type_info(info.base);
  190. case Map:
  191. return align_of_type_info(info.generated_struct);
  192. }
  193. return 0;
  194. }
  195. align_formula :: proc(size, align: int) -> int {
  196. result := size + align-1;
  197. return result - result%align;
  198. }
  199. size_of_type_info :: proc(type_info: ^Type_Info) -> int {
  200. WORD_SIZE :: size_of(int);
  201. using Type_Info;
  202. match info in type_info {
  203. case Named:
  204. return size_of_type_info(info.base);
  205. case Integer:
  206. return info.size;
  207. case Float:
  208. return info.size;
  209. case String:
  210. return 2*WORD_SIZE;
  211. case Boolean:
  212. return 1;
  213. case Any:
  214. return 2*WORD_SIZE;
  215. case Pointer:
  216. return WORD_SIZE;
  217. case Procedure:
  218. return WORD_SIZE;
  219. case Array:
  220. count := info.count;
  221. if count == 0 {
  222. return 0;
  223. }
  224. size := size_of_type_info(info.elem);
  225. align := align_of_type_info(info.elem);
  226. alignment := align_formula(size, align);
  227. return alignment*(count-1) + size;
  228. case Dynamic_Array:
  229. return size_of(rawptr) + 2*size_of(int) + size_of(Allocator);
  230. case Slice:
  231. return 2*WORD_SIZE;
  232. case Vector:
  233. count := info.count;
  234. if count == 0 {
  235. return 0;
  236. }
  237. size := size_of_type_info(info.elem);
  238. align := align_of_type_info(info.elem);
  239. alignment := align_formula(size, align);
  240. return alignment*(count-1) + size;
  241. case Struct:
  242. return info.size;
  243. case Union:
  244. return info.size;
  245. case Raw_Union:
  246. return info.size;
  247. case Enum:
  248. return size_of_type_info(info.base);
  249. case Map:
  250. return size_of_type_info(info.generated_struct);
  251. }
  252. return 0;
  253. }