openclonk/planet/System.ocg/Array.c

252 lines
5.4 KiB
C

/**
Array.c
Global array helper functions.
@author Zapper, Sven2
*/
// Concatenates two arrays and returns a new array.
global func Concatenate(array first, array second)
{
var len_first = GetLength(first);
var result = CreateArray(len_first+GetLength(second));
result[:len_first] = first;
result[len_first:] = second;
return result;
}
// Returns a new array that contains the values of the first array minus the values of the second array.
global func Subtract(array subject, array subtract)
{
var diff = [];
for (var obj in subject)
{
var removed = false;
for (var rem_obj in subtract)
{
if (rem_obj == obj)
{
removed = true;
break;
}
}
if(!removed)
diff[GetLength(diff)] = obj;
}
return diff;
}
// Removes nil values from an array, returns the amount of values removed.
global func RemoveHoles(array leerdammer)
{
var move = 0;
var len = GetLength(leerdammer);
for (var i = 0; i < len; ++i)
{
if(leerdammer[i] == nil)
{
++move;
continue;
}
leerdammer[i - move] = leerdammer[i];
}
SetLength(leerdammer, len - move);
// assert IsGouda(leerdammer)
return move;
}
// Removes duplicate entries - returns the number of entries removed.
global func RemoveDuplicates(array arr)
{
var working = [];
var cnt = 0;
var len = GetLength(arr);
for (var i = 0; i < len; ++i)
{
if (IsValueInArray(working, arr[i]))
{
++cnt;
continue;
}
working[GetLength(working)] = arr[i];
}
SetLength(arr, GetLength(working));
for (var i = GetLength(working); --i >= 0;)
arr[i] = working[i];
return cnt;
}
// Tests whether a value is in an array.
global func IsValueInArray(array arr, /*any*/ value)
{
return GetIndexOf(arr, value) != -1;
}
// Removes a value from an array.
global func RemoveArrayValue(array arr, /*any*/ value, bool unstable)
{
var i = GetIndexOf(arr, value);
if (i == -1)
return false;
if (unstable == true)
return RemoveArrayIndexUnstable(arr, i);
return RemoveArrayIndex(arr, i);
}
// Randomly shuffles an array.
global func ShuffleArray(array arr)
{
var len = GetLength(arr);
var working = arr[:];
while (--len >= 0)
{
var i = Random(len + 1);
arr[len] = working[i];
working[i] = working[len];
}
return;
}
// Takes array of format [[x1,y1], [x2,y2], ...] and returns array [[x1,x2,...],[y1,y2,...]]
global func TransposeArray(array v)
{
var result = [], i = 0;
for (var vc in v)
{
var j = 0;
for (var c in vc)
{
if (!result[j])
result[j] = CreateArray(GetLength(v));
result[j][i] = c;
++j;
}
++i;
}
return result;
}
// Deletes an index from an array, does not change the order of items in the array.
global func RemoveArrayIndex(array arr, int index, bool unstable)
{
if (unstable == true)
return RemoveArrayIndexUnstable(arr, index);
// move all elements right of index to the left
arr[index:] = arr[index+1:];
return true;
}
// Deletes an array item - might change the order of elements, but is faster.
global func RemoveArrayIndexUnstable(array arr, int index)
{
arr[index] = arr[-1];
SetLength(arr, GetLength(arr) - 1);
return true;
}
// Inserts an element at the end of an array.
global func PushBack(array arr, /*any*/ value)
{
arr[GetLength(arr)] = value;
return true;
}
// Inserts an element at the beginning of an array.
global func PushFront(array arr, /*any*/ value)
{
// Move elements one to the right.
arr[1:] = arr;
arr[0] = value;
return true;
}
// Removes the last element from an array and returns it.
global func PopBack(array arr)
{
if (GetLength(arr) == 0)
return nil;
var o = arr[-1];
arr[:] = arr[:-1];
return o;
}
// Removes the first element from an array and returns it.
global func PopFront(array arr)
{
if (GetLength(arr) == 0)
return nil;
var o = arr[0];
arr[:] = arr[1:];
return o;
}
// Returns a random element from an array.
global func RandomElement(array arr)
{
return arr[Random(GetLength(arr))];
}
// Move array of indexes before given element. Called from editor on item move.
global func MoveArrayItems(array arr, array source_indices, int insert_before)
{
if (!arr) return false;
var len = GetLength(arr), off = 0, val;
// make sure source indices are sorted
if (len > 1)
{
source_indices = source_indices[:];
SortArray(source_indices);
}
for (var idx in source_indices)
{
if (idx < 0) idx += (1-(idx+1)/len)*len; // resolve negative indices
if (idx >= len) continue;
if (idx < insert_before)
{
// Move element forward
idx += off; --off; // Adjust for other elements already moved
val = arr[idx];
while (++idx < insert_before) arr[idx-1] = arr[idx];
arr[insert_before - 1] = val;
}
else
{
// Move element backward
val = arr[idx];
while (idx-- >= insert_before) arr[idx+1] = arr[idx];
arr[insert_before] = val;
++insert_before;
}
}
return true;
}
// Deletes multiple indexes from an array, does not change the order of items in the array.
global func RemoveArrayIndices(array arr, array indices)
{
indices = indices[:];
SortArray(indices, true);
for (var idx in indices)
if (idx < GetLength(arr))
RemoveArrayIndex(arr, idx);
return true;
}
// Performs a left fold.
//
// Examples:
// - Reduce([1, 2, 3, 4], Min) == 1
// - func Add(int a, int b) { return a + b; }
// Reduce([1, 2, 3, 4], Add, 100) == 110
global func Reduce(array arr, func fn, initial)
{
var i = 0;
var result = initial ?? arr[i++];
while (i < GetLength(arr))
result = Call(fn, result, arr[i++]);
return result;
}