dynamic_array_internal.odin 3.7 KB

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