Array

#import "std/array"

Compiler builtin dynamic array is automatically growing memory storage allocated on heap. The array allocated memory block groves over time when we push new values to the array. It's guaranteed that all pushed elements are stored in single continuous block of memory. When there is no space reminding in currently allocated block, new one is allocated and all already pushed data are copied from old block to the new one.

array :: struct {
    len:             s64;
    ptr:            *u8;
    allocated_elems: usize;
    allocator:      *Allocator;
}

Dynamic array is represented as [..]T type.

Example

// First of all we must load API functions for dynamic array. The #load hash
// directive can be used to "include" other source files.
#import "std/array"
#import "std/print"

main :: fn () s32 {
	// Now we create new dynamic array to store numbers. No heap alloacation
	// is done here, we only specify element type of the array. As it's with
	// regular static arrays or slices, we can access the element count via
	// .len and allocated memory block via .ptr member. Compared to static
	// arrays, there is additional member .allocated telling us how many
	// elements could array handle till next allocation is needed.
	nums: [..]s32;

	// Fill the dynamic array with some values.
	loop i := 0; i < 100; i += 1 {
		// To append new value at the end of the array we can use 'array_push'
		// function.
		array_push(&nums, i);

		// We can push only numbers of s32 type into the array (based on
		// declaration type), you can try to push something else and see what
		// happens.
	}

	// Dynamic arrays can be printed as usual...
	print("nums = %\n", nums);

	// We can use [N] operator to access single array elements like this:
	print("nums[10] = %\n", nums[10]);
	print("nums[20] = %\n", nums[20]);

	// Since dynamic array will allocate memory on heap, we must free this
	// memory by 'array_terminate' call when array is no longer needed.
	array_terminate(&nums);

	// There is lot of other ways to modify dynamic array content, check out
	// API documentation.

	return 0;
}

Preallocation Rules

Underlying array buffer is allocated using provided allocator or application_context.allocator by default.

ARRAY_ALLOC_BLOCK_SIZE

ARRAY_ALLOC_BLOCK_SIZE : usize = 32

File: array.bl

ARRAY_GROW_FACTOR

ARRAY_GROW_FACTOR : f32 = 1.500000

File: array.bl

array_init

array_init :: fn (_arr: *[..]?T, capacity : s64: 0, allocator : *Allocator: null)  #inline

Sets dynamic array to default state. If array contains already allocated memory array_terminate must be called first.

Initial capacity can be specified by capacity (count of elements). If capacity is greater than 0, needed memory is preallocated using specified allocator; otherwise no allocation is done.

It's usually enough to rely on default implicit initialization in case we don't need specify custom allocator or preallocate storage to specified capacity of entries.

File: array.bl

array_terminate

array_terminate :: fn (_arr: *[..]?T)  #inline

Release memory allocated by dynamic array. This function is supposed to be called when dynamic array is no longer needed. Passed dynamic array is reset to default state. Calling array_terminate on already terminated or non-initialized array is allowed.

File: array.bl

array_push

array_push :: fn { 
    impl_push_empty; 
    impl_push; 
}

Append new value at the dynamic array end. New heap allocation is done here only in cases when there is not enough memory allocated to store all values. Returns pointer to the new appended element.

Note: When there is no element to push provided, function will just allocate memory for a new empty element without any initialization.

File: array.bl

array_push_all

array_push_all :: fn (_arr: *[..]?T, data: []T) 

Append array with a new data. Underlying preallocated memory block might grow in case there is not enough space (See Preallocation Rules).

Does nothing in case the input data is empty.

File: array.bl

array_pop

array_pop :: fn (_arr: *[..]?T, out : *T: null) bool #inline

Duplicate the last array element into out argument (if not null) and reduce the array length by one. Returns true in case the element was erased.

File: array.bl

array_pop_first

array_pop_first :: fn (_arr: *[..]?T, out : *T: null) bool #inline

Duplicate first array element into out location (if not null) and shift all other elements by one slot left (the ordeing is kept). Returns true in case the element was erased.

File: array.bl

array_reserve

array_reserve :: fn (_arr: *[..]?T, n: s64)  #inline

Reserve heap memory for n elements in array. Does nothing in case the already allocated block is large enough to hold n elements, the allocated memory block might be bigger then requested size.

In case n is 0 function immediately returns without any allocations.

File: array.bl

array_resize

array_resize :: fn (_arr: *[..]?T, len: s64) s64 #inline

Resize array to required len. Behaviour of this function is similar to array_reserve except the array length is changed.

Buffer reallocation occours in case the current allocated buffer it not capable to handle requested length.

Setting the length to smaller values then length of current array content will shrink the array content, minimal possible length value is zero; setting negative value will cause panic. On the other hand, when array content is smaller then required length, the array is extended, but newly occupied buffer range remains uninitialized.

Returns original length.

#import "std/array"
#import "std/print"

main :: fn () s32 {
	arr: [..]s32;
	defer array_terminate(&arr);
	array_push_all(&arr, [_]s32.{ 0, 1, 2 });

	NEW_SIZE :: 10;

	loop i := array_resize(&arr, NEW_SIZE); i < arr.len; i += 1 {
		arr[i] = auto i;
	}

	print("%\n", arr);

	return 0;
}

File: array.bl

array_erase

array_erase :: fn (_arr: *[..]?T, i: s64) 

Erase element on index i. Call to this function may cause reordering of an dynamic array. Allocated memory is kept even if we erase entire dynamic array. Function invoke panic in case of index being out of array valid range <0, arr.len).

File: array.bl

array_erase_keep_order

array_erase_keep_order :: fn (_arr: *[..]?T, i: s64) 

Erase element on index i and move all following elements left using memmove. This might be slow in case the array is large. Function invoke panic in case of index being out of array valid range <0, arr.len).

File: array.bl

array_erase_value

array_erase_value :: fn (arr: *[..]?T, v: T) bool

Erase element of the value v and return true in case element was erased. Note this might be expensive since all elements in array might be visited in the worst case.

File: array.bl

array_insert

array_insert :: fn (_arr: *[..]?T, before_index: s64, value: T) s64

Insert a new element into the array before position before_index and return index of the new inserted element. All elements after the new one are moved in the memory by one slot.

Value of before_index must be in range <0, arr.len>. Inserting at before_index = 0 basically adds a new element at the array begin; insering at before_index = arr.len is the same as array_push.

Order of already existing elements is preserved.

Panic is issued in case the before_index is out of range <0, arr.len>.

Returns index of newly inserted element.

File: array.bl

array_insert_all

array_insert_all :: fn (_arr: *[..]?T, before_index: s64, values: []T) s64

Inserts values at desired position. The position is defined as before_index pointing to the element in the input array before which the new content will be inserted, or simply defining position of the first element of the inserted values in the original array after the modification is done.

Valid range for the before_index is <0, arr.len>, values out of the range cause panic.

Function does nothing in case values slice is empty.

Returns index of the first element of inserted values.

File: array.bl

array_clear

Warning: Function is marked as obsolete. Since 0.13.0; Use 'arr.len = 0' instead.

array_clear :: fn (_arr: *[..]?T)  #inline

Erase all elements in dynamic array but keep allocated memory.

File: array.bl

array_allocated_bytes

array_allocated_bytes :: fn (_arr: *[..]?T) usize #inline

Returns total number of allocated bytes used by the array.

File: array.bl