dynamic_array_internal.odin 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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. old_size := array.cap * elem_size
  52. new_size := new_cap * elem_size
  53. allocator := array.allocator
  54. new_data, err := mem_resize(array.data, old_size, new_size, elem_align, allocator, loc)
  55. if err != nil {
  56. return
  57. }
  58. array.data = raw_data(new_data)
  59. array.len = min(new_cap, array.len)
  60. array.cap = new_cap
  61. return true
  62. }
  63. __dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: int, loc := #caller_location) -> bool {
  64. array := (^Raw_Dynamic_Array)(array_)
  65. ok := __dynamic_array_reserve(array_, elem_size, elem_align, len, loc)
  66. if ok {
  67. array.len = len
  68. }
  69. return ok
  70. }
  71. __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
  72. items: rawptr, item_count: int, loc := #caller_location) -> int {
  73. array := (^Raw_Dynamic_Array)(array_)
  74. if items == nil {
  75. return 0
  76. }
  77. if item_count <= 0 {
  78. return 0
  79. }
  80. ok := true
  81. if array.cap < array.len+item_count {
  82. cap := 2 * array.cap + max(8, item_count)
  83. ok = __dynamic_array_reserve(array, elem_size, elem_align, cap, loc)
  84. }
  85. // TODO(bill): Better error handling for failed reservation
  86. if !ok {
  87. return array.len
  88. }
  89. assert(array.data != nil)
  90. data := uintptr(array.data) + uintptr(elem_size*array.len)
  91. mem_copy(rawptr(data), items, elem_size * item_count)
  92. array.len += item_count
  93. return array.len
  94. }
  95. __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int, loc := #caller_location) -> int {
  96. array := (^Raw_Dynamic_Array)(array_)
  97. ok := true
  98. if array.cap < array.len+1 {
  99. cap := 2 * array.cap + max(8, 1)
  100. ok = __dynamic_array_reserve(array, elem_size, elem_align, cap, loc)
  101. }
  102. // TODO(bill): Better error handling for failed reservation
  103. if !ok {
  104. return array.len
  105. }
  106. assert(array.data != nil)
  107. data := uintptr(array.data) + uintptr(elem_size*array.len)
  108. mem_zero(rawptr(data), elem_size)
  109. array.len += 1
  110. return array.len
  111. }