Files
spark/src/client/spark_core/utils/ArrayUtils.cs
T

178 lines
6.9 KiB
C#

using mbts.utils;
using System;
using System.Collections;
using System.Collections.Generic;
namespace bts.utils {
public static class ArrayHelper {
public static void trim<T>(ref T[] array, int size) {
if (array.Length > size) {
T[] trimmed = new T[size];
Array.Copy(array, trimmed, size);
array = trimmed;
}
}
public static void ensure_capacity<T>(ref T[] array, int min) {
if (array.Length < min) {
int twice_cap = array.Length * 2;
expand(ref array, min > twice_cap ? min : twice_cap);
}
}
public static void expand<T>(ref T[] array) => expand(ref array, array.Length * 2);
public static void expand<T>(ref T[] array, int new_capacity) {
if (array.Length < new_capacity) {
T[] expanded = new T[new_capacity];
Array.Copy(array, expanded, array.Length);
array = expanded;
}
}
public static TResult[] safe_convert<T, TResult>(T[] array, Func<T, TResult> convert) =>
array == null ? Array.Empty<TResult>() : Array.ConvertAll(array, new Converter<T, TResult>(convert));
public static TResult[] convert<T, TResult>(ICollection<T> source, Func<T, TResult> convert) {
var array = new TResult[source.Count];
int i = 0;
foreach (var v in source)
array[i++] = convert(v);
return array;
}
public static T[] clone<T>(T[] array) {
T[] rv = new T[array.Length];
Array.Copy(array, rv, array.Length);
return rv;
}
/// <summary>
/// Attemps to get an exact item count (to initialize the resultant array with an exact length, thus avoiding unneccessary allocations) by checking if the specified source implements <see cref="ICollection{T}"/>, <see cref="IReadOnlyCollection{T}"/>, or <see cref="ICollection"/>.
/// </summary>
/// <typeparam name="T">The type of elements.</typeparam>
/// <param name="source">The source that will be copied to the resultant array.</param>
/// <returns>An array containing the elements from the specified source.</returns>
public static T[] clone_optimized<T>(IEnumerable<T> source) {
if (source == null)
return Array.Empty<T>();
T[] result;
if (source is ICollection<T> collection) {
result = new T[collection.Count];
collection.CopyTo(result, 0);
} else if (source is IReadOnlyCollection<T> ro_collection) {
result = new T[ro_collection.Count];
int i = 0;
foreach (var v in ro_collection)
result[i++] = v;
} else if (source is ICollection ng_collection) {
result = new T[ng_collection.Count];
int i = 0;
foreach (var v in source)
result[i++] = v;
} else {
int i = 0;
using (var en = source.GetEnumerator()) {
if (en.MoveNext()) {
result = new[] { en.Current };
i = 1;
while (en.MoveNext()) {
ensure_capacity(ref result, i + 1);
result[i++] = en.Current;
}
trim(ref result, i);
} else {
return Array.Empty<T>();
}
}
}
return result;
}
public static void insert<T>(ref T[] array, int index, T value, ref int size) {
// validate size/index
if (size < 0)
throw ExceptionBuilder.ArgumentOutOfRange.lt_zero(nameof(size));
if (size > array.Length)
throw ExceptionBuilder.ArgumentOutOfRange.gt_length(nameof(size));
if (index < 0)
throw ExceptionBuilder.IndexOutOfRange.lt_zero();
if (index > size)
throw ExceptionBuilder.IndexOutOfRange.gt_length();
T[] old_array = array;
checked {
if (size == array.Length) {
array = new T[array.Length * 2];
Array.Copy(old_array, 0, array, 0, index);
}
if (index < size)
Array.Copy(old_array, index, array, index + 1, size - index);
array[index] = value;
size++;
}
}
public static void remove_at<T>(ref T[] array, int index) {
int sz = array.Length;
remove_at(ref array, ref sz, index);
}
public static void remove_at<T>(ref T[] array, ref int size, int index) {
// validate size/index
if (size < 0)
throw ExceptionBuilder.ArgumentOutOfRange.lt_zero(nameof(size));
if (size > array.Length)
throw ExceptionBuilder.ArgumentOutOfRange.gte_length(nameof(size));
if (index < 0)
throw ExceptionBuilder.IndexOutOfRange.lt_zero();
if (index >= size)
throw ExceptionBuilder.IndexOutOfRange.gte_length();
// shift [any]items right of 'index' left 1 pos.
if (index < size - 1) {
Array.Copy(array, index + 1, array, index, size - index - 1);
}
// clear last item, and decrement size
Array.Clear(array, --size, 1);
}
public static void remove_sorted<T>(ref T[] array, ref int size, T value, IComparer<T> comparer) =>
remove_sorted(ref array, ref size, value, comparer);
public static void remove_sorted<T>(ref T[] array, ref int size, T value, IComparer<T> comparer, out int? pos) {
int p = Array.BinarySearch(array, 0, size, value, comparer);
if (p < 0) {
pos = null;
} else {
pos = p;
size--;
Array.Copy(array, p + 1, array, p, size - p);
array[size] = default;
}
}
public static T[] add<T>(T[] array, T value) {
T[] clone = new T[array.Length + 1];
Array.Copy(array, clone, array.Length);
clone[array.Length] = value;
return clone;
}
public static void add_sorted<T>(ref T[] array, ref int size, T value, IComparer<T> comparer) =>
add_sorted(ref array, ref size, value, comparer, out int pos);
public static void add_sorted<T>(ref T[] array, ref int size, T value, IComparer<T> comparer, out int pos) {
pos = peek_sorted_index(array, size, value, comparer);
ensure_capacity(ref array, size + 1);
Array.Copy(array, pos, array, pos + 1, size - pos);
array[pos] = value;
size++;
}
public static int peek_sorted_index<T>(T[] array, int size, T value, IComparer<T> comparer) {
int index = Array.BinarySearch(array, 0, size, value, comparer);
if (index < 0)
index = ~index;
return index;
}
}
}