2024-02-13 23:29:28 -08:00
|
|
|
// Based on gencpp's and thus zpl's Array implementation
|
|
|
|
// Made becasue of the map issue with fonts during hot-reload.
|
2024-02-27 04:50:57 -08:00
|
|
|
// I didn't want to make the HMapZPL impl with the [dynamic] array for now to isolate
|
2024-02-13 23:29:28 -08:00
|
|
|
// what in the world is going on with the memory...
|
|
|
|
package sectr
|
|
|
|
|
|
|
|
import "core:c/libc"
|
|
|
|
import "core:mem"
|
2024-02-22 20:15:29 -08:00
|
|
|
import "core:slice"
|
2024-02-13 23:29:28 -08:00
|
|
|
|
|
|
|
Array :: struct ( $ Type : typeid ) {
|
|
|
|
allocator : Allocator,
|
|
|
|
capacity : u64,
|
|
|
|
num : u64,
|
|
|
|
data : [^]Type,
|
|
|
|
}
|
|
|
|
|
2024-03-02 15:19:27 -08:00
|
|
|
array_underlying_slice :: proc(slice: []($ Type)) -> Array(Type) {
|
|
|
|
if len(slice) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
array_size := size_of( Array(Type))
|
|
|
|
raw_data := & slice[0]
|
|
|
|
array_ptr := cast( ^Array(Type)) ( uintptr(first_element_ptr) - uintptr(array_size))
|
|
|
|
return array_ptr ^
|
|
|
|
}
|
|
|
|
|
2024-03-02 17:22:28 -08:00
|
|
|
array_to_slice_num :: proc( using self : Array($ Type) ) -> []Type {
|
2024-03-02 15:19:27 -08:00
|
|
|
return slice_ptr( data, int(num) )
|
2024-02-13 23:29:28 -08:00
|
|
|
}
|
|
|
|
|
2024-03-02 17:22:28 -08:00
|
|
|
array_to_slice :: proc( using self : Array($ Type) ) -> []Type {
|
|
|
|
return slice_ptr( data, int(capacity))
|
|
|
|
}
|
|
|
|
|
2024-02-13 23:29:28 -08:00
|
|
|
array_grow_formula :: proc( value : u64 ) -> u64 {
|
|
|
|
return 2 * value + 8
|
|
|
|
}
|
|
|
|
|
|
|
|
array_init :: proc( $ Type : typeid, allocator : Allocator ) -> ( Array(Type), AllocatorError ) {
|
|
|
|
return array_init_reserve( Type, allocator, array_grow_formula(0) )
|
|
|
|
}
|
|
|
|
|
|
|
|
array_init_reserve :: proc( $ Type : typeid, allocator : Allocator, capacity : u64 ) -> ( Array(Type), AllocatorError )
|
|
|
|
{
|
2024-03-02 15:19:27 -08:00
|
|
|
raw_data, result_code := alloc( size_of(Array) + int(capacity) * size_of(Type), allocator = allocator )
|
|
|
|
result := cast(^Array(Type)) raw_data;
|
2024-03-02 17:22:28 -08:00
|
|
|
result.data = cast( [^]Type ) (cast( [^]Array(Type)) result)[ 1:]
|
2024-02-13 23:29:28 -08:00
|
|
|
result.allocator = allocator
|
|
|
|
result.capacity = capacity
|
2024-03-02 15:19:27 -08:00
|
|
|
return (result ^), result_code
|
2024-02-13 23:29:28 -08:00
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
array_append :: proc( using self : ^ Array( $ Type), value : Type ) -> AllocatorError
|
2024-02-13 23:29:28 -08:00
|
|
|
{
|
|
|
|
if num == capacity
|
|
|
|
{
|
2024-02-27 04:50:57 -08:00
|
|
|
grow_result := array_grow( self, capacity )
|
2024-02-13 23:29:28 -08:00
|
|
|
if grow_result != AllocatorError.None {
|
|
|
|
return grow_result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
data[ num ] = value
|
|
|
|
num += 1
|
|
|
|
return AllocatorError.None
|
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
array_append_slice :: proc( using self : ^ Array( $ Type ), items : []Type ) -> AllocatorError
|
2024-02-13 23:29:28 -08:00
|
|
|
{
|
|
|
|
if num + len(items) > capacity
|
|
|
|
{
|
2024-02-27 04:50:57 -08:00
|
|
|
grow_result := array_grow( self, capacity )
|
2024-02-13 23:29:28 -08:00
|
|
|
if grow_result != AllocatorError.None {
|
|
|
|
return grow_result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note(Ed) : Original code from gencpp
|
|
|
|
// libc.memcpy( ptr_offset(data, num), raw_data(items), len(items) * size_of(Type) )
|
|
|
|
|
|
|
|
// TODO(Ed) : VERIFY VIA DEBUG THIS COPY IS FINE.
|
|
|
|
target := ptr_offset( data, num )
|
|
|
|
copy( slice_ptr(target, capacity - num), items )
|
|
|
|
|
|
|
|
num += len(items)
|
|
|
|
return AllocatorError.None
|
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
array_append_at :: proc( using self : ^ Array( $ Type ), item : Type, id : u64 ) -> AllocatorError
|
2024-02-13 23:29:28 -08:00
|
|
|
{
|
|
|
|
id := id
|
|
|
|
if id >= num {
|
|
|
|
id = num - 1
|
|
|
|
}
|
|
|
|
if id < 0 {
|
|
|
|
id = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
if capacity < num + 1
|
|
|
|
{
|
2024-02-27 04:50:57 -08:00
|
|
|
grow_result := array_grow( self, capacity )
|
2024-02-13 23:29:28 -08:00
|
|
|
if grow_result != AllocatorError.None {
|
|
|
|
return grow_result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
target := & data[id]
|
|
|
|
|
|
|
|
// TODO(Ed) : VERIFY VIA DEBUG THIS COPY IS FINE.
|
|
|
|
dst = slice_ptr( ptr_offset(target) + 1, num - id - 1 )
|
|
|
|
src = slice_ptr( target, num - id )
|
|
|
|
copy( dst, src )
|
|
|
|
|
|
|
|
// Note(Ed) : Original code from gencpp
|
|
|
|
// libc.memmove( ptr_offset(target, 1), target, (num - idx) * size_of(Type) )
|
|
|
|
data[id] = item
|
|
|
|
num += 1
|
|
|
|
return AllocatorError.None
|
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
array_append_at_slice :: proc( using self : ^ Array( $ Type ), items : []Type, id : u64 ) -> AllocatorError
|
2024-02-13 23:29:28 -08:00
|
|
|
{
|
|
|
|
id := id
|
|
|
|
if id >= num {
|
|
|
|
return array_append_slice( items )
|
|
|
|
}
|
|
|
|
if len(items) > capacity
|
|
|
|
{
|
2024-02-27 04:50:57 -08:00
|
|
|
grow_result := array_grow( self, capacity )
|
2024-02-13 23:29:28 -08:00
|
|
|
if grow_result != AllocatorError.None {
|
|
|
|
return grow_result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note(Ed) : Original code from gencpp
|
|
|
|
// target := ptr_offset( data, id + len(items) )
|
|
|
|
// src := ptr_offset( data, id )
|
|
|
|
// libc.memmove( target, src, num - id * size_of(Type) )
|
|
|
|
// libc.memcpy ( src, raw_data(items), len(items) * size_of(Type) )
|
|
|
|
|
|
|
|
// TODO(Ed) : VERIFY VIA DEBUG THIS COPY IS FINE
|
|
|
|
target := & data[id + len(items)]
|
|
|
|
dst := slice_ptr( target, num - id - len(items) )
|
|
|
|
src := slice_ptr( & data[id], num - id )
|
|
|
|
copy( dst, src )
|
|
|
|
copy( src, items )
|
|
|
|
|
|
|
|
num += len(items)
|
|
|
|
return AllocatorError.None
|
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
array_back :: proc( using self : ^ Array( $ Type ) ) -> ^ Type {
|
|
|
|
return & data[ num - 1 ]
|
2024-02-13 23:29:28 -08:00
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
array_clear :: proc( using self : ^ Array( $ Type ), zero_data : b32 ) {
|
|
|
|
if zero_data {
|
|
|
|
mem.set( raw_data( data ), 0, num )
|
|
|
|
}
|
|
|
|
num = 0
|
2024-02-13 23:29:28 -08:00
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
array_fill :: proc( using self : ^ Array( $ Type ), begin, end : u64, value : Type ) -> b32
|
2024-02-13 23:29:28 -08:00
|
|
|
{
|
|
|
|
if begin < 0 || end >= num {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2024-02-22 20:15:29 -08:00
|
|
|
// TODO(Ed) : Bench this?
|
|
|
|
// data_slice := slice_ptr( ptr_offset( data, begin ), end - begin )
|
|
|
|
// slice.fill( data_slice, cast(int) value )
|
|
|
|
|
2024-02-13 23:29:28 -08:00
|
|
|
for id := begin; id < end; id += 1 {
|
|
|
|
data[ id ] = value
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
array_free :: proc( using self : ^ Array( $ Type ) ) {
|
2024-02-13 23:29:28 -08:00
|
|
|
free( data, allocator )
|
|
|
|
data = nil
|
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
array_grow :: proc( using self : ^ Array( $ Type ), min_capacity : u64 ) -> AllocatorError
|
2024-02-13 23:29:28 -08:00
|
|
|
{
|
2024-02-22 20:15:29 -08:00
|
|
|
new_capacity := array_grow_formula( capacity )
|
2024-02-13 23:29:28 -08:00
|
|
|
|
|
|
|
if new_capacity < min_capacity {
|
|
|
|
new_capacity = min_capacity
|
|
|
|
}
|
2024-02-27 04:50:57 -08:00
|
|
|
return array_set_capacity( self, new_capacity )
|
2024-02-13 23:29:28 -08:00
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
array_pop :: proc( using self : ^ Array( $ Type ) ) {
|
|
|
|
verify( num != 0, "Attempted to pop an array with no elements" )
|
|
|
|
num -= 1
|
2024-02-13 23:29:28 -08:00
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
array_remove_at :: proc( using self : ^ Array( $ Type ), id : u64 )
|
2024-02-13 23:29:28 -08:00
|
|
|
{
|
|
|
|
verify( id >= num, "Attempted to remove from an index larger than the array" )
|
|
|
|
|
|
|
|
left = slice_ptr( data, id )
|
|
|
|
right = slice_ptr( ptr_offset( memory_after(left), 1), num - len(left) - 1 )
|
|
|
|
copy( left, right )
|
|
|
|
|
|
|
|
num -= 1
|
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
array_reserve :: proc( using self : ^ Array( $ Type ), new_capacity : u64 ) -> AllocatorError
|
2024-02-13 23:29:28 -08:00
|
|
|
{
|
|
|
|
if capacity < new_capacity {
|
2024-02-27 04:50:57 -08:00
|
|
|
return array_set_capacity( self, new_capacity )
|
2024-02-13 23:29:28 -08:00
|
|
|
}
|
|
|
|
return AllocatorError.None
|
|
|
|
}
|
|
|
|
|
2024-02-23 06:36:23 -08:00
|
|
|
array_resize :: proc( array : ^ Array( $ Type ), num : u64 ) -> AllocatorError
|
2024-02-13 23:29:28 -08:00
|
|
|
{
|
|
|
|
if array.capacity < num
|
|
|
|
{
|
2024-02-22 20:15:29 -08:00
|
|
|
grow_result := array_grow( array, array.capacity )
|
2024-02-13 23:29:28 -08:00
|
|
|
if grow_result != AllocatorError.None {
|
|
|
|
return grow_result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
array.num = num
|
|
|
|
return AllocatorError.None
|
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
array_set_capacity :: proc( using self : ^ Array( $ Type ), new_capacity : u64 ) -> AllocatorError
|
2024-02-13 23:29:28 -08:00
|
|
|
{
|
|
|
|
if new_capacity == capacity {
|
2024-02-22 20:15:29 -08:00
|
|
|
return AllocatorError.None
|
2024-02-13 23:29:28 -08:00
|
|
|
}
|
|
|
|
if new_capacity < num {
|
|
|
|
num = new_capacity
|
2024-02-22 20:15:29 -08:00
|
|
|
return AllocatorError.None
|
2024-02-13 23:29:28 -08:00
|
|
|
}
|
|
|
|
|
2024-03-02 07:24:09 -08:00
|
|
|
new_data, result_code := alloc( cast(int) new_capacity * size_of(Type), allocator = allocator )
|
|
|
|
if result_code != AllocatorError.None {
|
|
|
|
ensure( false, "Failed to allocate for new array capacity" )
|
|
|
|
return result_code
|
|
|
|
}
|
2024-03-02 15:19:27 -08:00
|
|
|
free( data )
|
2024-03-02 07:24:09 -08:00
|
|
|
data = cast( [^] Type ) new_data
|
2024-02-13 23:29:28 -08:00
|
|
|
capacity = new_capacity
|
|
|
|
return result_code
|
|
|
|
}
|