163 lines
4.6 KiB
Text
163 lines
4.6 KiB
Text
/// ArrayAppend pushes values to the end of an array, resizing if necessary.
|
|
/// A pointer to the first value appended will be returned.
|
|
///
|
|
/// Note: If no allocator has been set, ArrayAppend will use the current context allocator.
|
|
/// Note: Calls to Append may invalidate pre-existing pointers.
|
|
ArrayAppend :: inline (arr: *[..]$T, values: ..T) -> *T {
|
|
TrySetAllocator(arr,, allocator = ArenaToAllocator(*context.arena));
|
|
|
|
if values.count == 0 {
|
|
return basic.array_add(arr);
|
|
}
|
|
|
|
count := arr.count;
|
|
basic.array_add(arr, ..values);
|
|
return *arr.data[count];
|
|
}
|
|
|
|
/// ArrayGrow resizes the memory associated with an array to hold new_count values.
|
|
///
|
|
/// Note: If the array has enough allocated memory to accomodate new_count, ArrayGrow does nothing.
|
|
/// Note: ArrayGrow does not guarantee pointer stability.
|
|
ArrayGrow :: inline (arr: *[..]$T, new_count: int) {
|
|
if new_count <= arr.allocated
|
|
{ return; }
|
|
|
|
TrySetAllocator(arr,, allocator = ArenaToAllocator(*context.arena));
|
|
basic.array_reserve(arr, new_count,, allocator = arr.allocator);
|
|
}
|
|
|
|
/// ArraySlice returns a subsection of an array.
|
|
ArraySlice :: (arr: []$T, start_idx: int, count := -1, loc := #caller_location) -> []T {
|
|
AssertCallsite(start_idx >= +0 && start_idx < arr.count, "jc: incorrect slice bounds");
|
|
AssertCallsite(count >= -1 && count < arr.count, "jc: incorrect slice length");
|
|
|
|
if count == -1
|
|
{ count = arr.count - start_idx; }
|
|
|
|
return .{ data = arr.data + start_idx, count = count };
|
|
}
|
|
|
|
/// ArrayReset sets an array's length to 0, but leaves its memory intact.
|
|
/// Note: To reset the associated memory as well, see ArrayClear.
|
|
ArrayReset :: (arr: *[]$T) {
|
|
arr.count = 0;
|
|
}
|
|
|
|
/// ArrayClear zeroes an array's memory and sets its length to 0.
|
|
/// Note: To leave the associated memory intact, see ArrayReset.
|
|
ArrayClear :: (arr: *[]$T) {
|
|
MemZero(arr.data, arr.count * size_of(T));
|
|
arr.count = 0;
|
|
}
|
|
|
|
/// ArrayEquals checks equality between two arrays.
|
|
ArrayEquals :: (lhs: []$T, rhs: []T) -> bool {
|
|
if lhs.count != rhs.count
|
|
{ return false; }
|
|
return MemEqual(lhs.data, rhs.data, lhs.count * size_of(T));
|
|
}
|
|
|
|
ArrayIndex :: struct(T: Type) {
|
|
value: T = ---;
|
|
index: int;
|
|
}
|
|
|
|
ArrayFindFlags :: enum_flags {
|
|
Last; // Return the last matching element.
|
|
FromEnd; // Search in reverse.
|
|
}
|
|
|
|
/// ArrayFind searches through an array, returning the first element that matches the given value.
|
|
ArrayFind :: (view: []$T, value: T, $flags: ArrayFindFlags = 0) -> (bool, ArrayIndex(T)) {
|
|
found: bool;
|
|
|
|
result: ArrayIndex(T);
|
|
result.index = -1;
|
|
|
|
REVERSE :: #run (flags & .FromEnd).(bool);
|
|
for #v2 <=REVERSE view if it == value {
|
|
found = true;
|
|
result.index = it_index;
|
|
result.value = it;
|
|
#if !(flags & .Last) break;
|
|
}
|
|
|
|
return found, result;
|
|
}
|
|
|
|
/// ArrayContains checks if the given value exists in an array.
|
|
ArrayContains :: (view: []$T, value: T) -> bool {
|
|
return ArrayFind(view, value);
|
|
}
|
|
|
|
|
|
ArrayTrimFlags :: enum_flags {
|
|
FromStart; // ArrayTrim the start of the array.
|
|
FromEnd; // ArrayTrim the end of the array.
|
|
MatchInFull; // Only trim when the cutset matches exactly.
|
|
}
|
|
|
|
/// ArrayTrim returns a subsection of an array with all leading/trailing values
|
|
/// from cutset removed.
|
|
ArrayTrim :: (view: []$T, cutset: []T, $flags: ArrayTrimFlags = .FromStart) -> []T {
|
|
result := view;
|
|
if cutset.count == 0 || cutset.count > view.count {
|
|
return result;
|
|
}
|
|
|
|
#if flags & .FromStart {
|
|
#if flags & .MatchInFull {
|
|
if ArrayEquals(ArraySlice(view, 0, cutset.count), cutset) {
|
|
result = ArraySlice(view, cutset.count, -1);
|
|
}
|
|
}
|
|
else {
|
|
while result.count > 0 {
|
|
if !ArrayContains(cutset, result[0]) {
|
|
break;
|
|
}
|
|
|
|
result.data += 1;
|
|
result.count -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if flags & .FromEnd {
|
|
#if flags & .MatchInFull {
|
|
if ArrayEquals(ArraySlice(view, view.count - cutset.count), cutset) {
|
|
result.count -= cutset.count;
|
|
}
|
|
}
|
|
else {
|
|
while result.count > 0 {
|
|
if !ArrayContains(cutset, result[result.count - 1]) {
|
|
break;
|
|
}
|
|
|
|
result.count -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
CheckBounds :: ($$index: $T, $$count: T, loc := #caller_location) #expand {
|
|
Message :: "bounds check failed!";
|
|
#if is_constant(index) && is_constant(count) {
|
|
if index < 0 || index >= count {
|
|
CompileError(Message, loc = loc);
|
|
}
|
|
}
|
|
else if index < 0 || index > count {
|
|
Panic(Message, loc = loc);
|
|
}
|
|
}
|
|
|
|
|
|
#scope_file
|
|
|
|
basic :: #import "Basic"; // @future
|