dynamic_array_internal.odin 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package runtime
  2. __dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int, loc := #caller_location) {
  3. array := (^Raw_Dynamic_Array)(array_)
  4. array.allocator = context.allocator
  5. assert(array.allocator.procedure != nil)
  6. if cap > 0 {
  7. __dynamic_array_reserve(array_, elem_size, elem_align, cap, loc)
  8. array.len = len
  9. }
  10. }
  11. __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int, loc := #caller_location) -> bool {
  12. array := (^Raw_Dynamic_Array)(array_)
  13. // NOTE(tetra, 2020-01-26): We set the allocator before earlying-out below, because user code is usually written
  14. // assuming that appending/reserving will set the allocator, if it is not already set.
  15. if array.allocator.procedure == nil {
  16. array.allocator = context.allocator
  17. }
  18. assert(array.allocator.procedure != nil)
  19. if cap <= array.cap {
  20. return true
  21. }
  22. old_size := array.cap * elem_size
  23. new_size := cap * elem_size
  24. allocator := array.allocator
  25. new_data, err := mem_resize(array.data, old_size, new_size, elem_align, allocator, loc)
  26. if err != nil {
  27. return false
  28. }
  29. if elem_size == 0 {
  30. array.data = raw_data(new_data)
  31. array.cap = cap
  32. return true
  33. } else if new_data != nil {
  34. array.data = raw_data(new_data)
  35. array.cap = min(cap, len(new_data)/elem_size)
  36. return true
  37. }
  38. return false
  39. }
  40. __dynamic_array_shrink :: proc(array_: rawptr, elem_size, elem_align: int, new_cap: int, loc := #caller_location) -> (did_shrink: bool) {
  41. array := (^Raw_Dynamic_Array)(array_)
  42. // NOTE(tetra, 2020-01-26): We set the allocator before earlying-out below, because user code is usually written
  43. // assuming that appending/reserving will set the allocator, if it is not already set.
  44. if array.allocator.procedure == nil {
  45. array.allocator = context.allocator
  46. }
  47. assert(array.allocator.procedure != nil)
  48. if new_cap > array.cap {
  49. return
  50. }
  51. new_cap := new_cap
  52. new_cap = max(new_cap, 0)
  53. old_size := array.cap * elem_size
  54. new_size := new_cap * elem_size
  55. allocator := array.allocator
  56. new_data, err := mem_resize(array.data, old_size, new_size, elem_align, allocator, loc)
  57. if err != nil {
  58. return
  59. }
  60. array.data = raw_data(new_data)
  61. array.len = min(new_cap, array.len)
  62. array.cap = new_cap
  63. return true
  64. }
  65. __dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: int, loc := #caller_location) -> bool {
  66. array := (^Raw_Dynamic_Array)(array_)
  67. ok := __dynamic_array_reserve(array_, elem_size, elem_align, len, loc)
  68. if ok {
  69. array.len = len
  70. }
  71. return ok
  72. }
  73. __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
  74. items: rawptr, item_count: int, loc := #caller_location) -> int {
  75. array := (^Raw_Dynamic_Array)(array_)
  76. if items == nil {
  77. return 0
  78. }
  79. if item_count <= 0 {
  80. return 0
  81. }
  82. ok := true
  83. if array.cap < array.len+item_count {
  84. cap := 2 * array.cap + max(8, item_count)
  85. ok = __dynamic_array_reserve(array, elem_size, elem_align, cap, loc)
  86. }
  87. // TODO(bill): Better error handling for failed reservation
  88. if !ok {
  89. return array.len
  90. }
  91. assert(array.data != nil)
  92. data := uintptr(array.data) + uintptr(elem_size*array.len)
  93. mem_copy(rawptr(data), items, elem_size * item_count)
  94. array.len += item_count
  95. return array.len
  96. }
  97. __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int, loc := #caller_location) -> int {
  98. array := (^Raw_Dynamic_Array)(array_)
  99. ok := true
  100. if array.cap < array.len+1 {
  101. cap := 2 * array.cap + max(8, 1)
  102. ok = __dynamic_array_reserve(array, elem_size, elem_align, cap, loc)
  103. }
  104. // TODO(bill): Better error handling for failed reservation
  105. if !ok {
  106. return array.len
  107. }
  108. assert(array.data != nil)
  109. data := uintptr(array.data) + uintptr(elem_size*array.len)
  110. mem_zero(rawptr(data), elem_size)
  111. array.len += 1
  112. return array.len
  113. }