using System;
using System.Collections;
using System.Collections.Generic;
using System.Numerics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using NumSharp.Backends;
namespace NumSharp.Utilities
{
public static class Arrays
{
///
/// Slice an array.
///
/// Supports negative index
public static T[] Slice(this T[] source, int start, int end)
{
// Handles negative ends.
if (end < 0) end = source.Length + end;
var len = end - start;
// Return new array.
var res = new T[len];
if (len > 700_000)
for (int i = 0; i < len; i++) res[i] = source[i + start];
else
for (int i = 0; i < len; i++)
res[i] = source[i + start];
return res;
}
///
/// Slice an array.
///
/// Supports negative index
public static T[] Slice(this T[] source, long start, long end)
{
// Handles negative ends.
if (end < 0) end = source.Length + end;
var len = end - start;
// Return new array.
var res = new T[len];
if (len > 700_000)
for (int i = 0; i < len; i++) res[i] = source[i + start];
else
for (long i = 0; i < len; i++)
res[i] = source[i + start];
return res;
}
///
/// Inserts item into a specific index.
///
/// The array to insert the value to.
/// The index to insert to.
///
public static void Insert(ref T[] source, int index, T value)
{
if (index < 0 || index > source.Length)
throw new ArgumentOutOfRangeException(nameof(index));
Array.Resize(ref source, source.Length + 1);
Array.Copy(source, index, source, index + 1, source.Length - index - 1);
source[index] = value;
}
///
/// Inserts item into a specific index.
///
/// The array to insert the value to.
/// The index to insert to.
///
public static T[] Insert(T[] source, int index, T value) where T : unmanaged
{
if (index < 0 || index > source.Length)
throw new ArgumentOutOfRangeException(nameof(index));
unsafe
{
var ret = new T[source.Length + 1];
fixed (T* src = source)
{
fixed (T* dst = ret)
{
new Span(src, index).CopyTo(new Span(dst, index));
*(dst + index) = value;
var left = source.Length - index;
new Span(src + index, left).CopyTo(new Span(dst + index + 1, left));
}
}
return ret;
}
}
///
/// Inserts item into a specific index.
///
/// The array to insert copy and insert value to.
/// The index to insert to.
/// a copy of with the appended value.
public static T[] AppendAt(T[] source, int index, T value)
{
var ret = (T[])source.Clone();
Insert(ref source, index, value);
return ret;
}
///
/// Removes a specific index from given array.
///
/// The array to remove from.
/// The index to remove.
/// A copy of without given
[MethodImpl(MethodImplOptions.AggressiveInlining | (MethodImplOptions)512)]
public static T[] RemoveAt(this T[] source, int index)
{
var dest = new T[source.Length - 1];
CopyToExceptAt(source, index, dest, 0);
return dest;
}
///
/// Copies an array contents except for a specific index.
///
/// The array to copy from.
/// The index to ignore.
/// The copying destinition
/// The 's offset
/// A copy of without given
[MethodImpl(MethodImplOptions.AggressiveInlining | (MethodImplOptions)512)]
public static void CopyToExceptAt(this T[] source, int index, T[] destinition, int destOffset = 0)
{
if (index > 0)
Array.Copy(source, 0, destinition, destOffset, index);
if (index < source.Length - 1)
Array.Copy(source, index + 1, destinition, destOffset + index, source.Length - index - 1);
}
///
/// Copies an array contents except for a specific index.
///
/// The array to copy from.
///
/// The index to ignore.
/// The copying destinition
/// The 's offset
/// A copy of without given
[MethodImpl(MethodImplOptions.AggressiveInlining | (MethodImplOptions)512)]
public static void CopyToExceptAt(this T[] source, int sourceOffset, int index, T[] destinition, int destOffset = 0)
{
if (sourceOffset + index > 0)
Array.Copy(source, sourceOffset, destinition, destOffset, index);
if (sourceOffset + index < source.Length - 1)
Array.Copy(source, sourceOffset + index + 1, destinition, destOffset + index, source.Length - index - 1);
}
///
/// Flattens any type of .
///
/// Supports both jagged array and multi-dim arrays.
public static Array Flatten(Array array)
{
if (array == null)
throw new ArgumentNullException(nameof(array));
IEnumerable _flat(IEnumerable @this)
{
foreach (var item in @this)
{
if (item is IEnumerable enumerable)
{
foreach (var subitem in _flat(enumerable))
{
yield return subitem;
}
}
else yield return item;
}
}
return Arrays.Create(array.ResolveElementType(), _flat(array));
}
///
/// Performs fast concatenation of multiple arrays
///
///
///
///
[MethodImpl((MethodImplOptions)512)]
public static T[] Concat(params T[][] arrays)
{
int sum = 0;
foreach (var array in arrays)
{
sum += array.Length;
}
T[] ret = new T[sum];
int offset = 0;
for (int i = 0; i < arrays.Length; i++)
{
var arr = arrays[i];
var arrlen = arr.Length;
Array.Copy(arr, 0, ret, offset, arrlen);
offset += arrlen;
}
return ret;
}
///
/// Performs fast concatenation of multiple arrays
///
///
///
///
[MethodImpl((MethodImplOptions)768)]
public static T[] Concat(T[] left, T[] right)
{
T[] ret = new T[left.Length + right.Length];
Array.Copy(left, 0, ret, 0, left.Length);
Array.Copy(right, 0, ret, left.Length, right.Length);
return ret;
}
///
/// Resolves element type recusivly.
///
///
///
[MethodImpl((MethodImplOptions)768)]
public static Type ResolveElementType(this Array arr)
{
if (arr == null)
throw new ArgumentNullException(nameof(arr));
var t = arr.GetType().GetElementType();
// ReSharper disable once PossibleNullReferenceException
while (t.IsArray)
t = t.GetElementType();
return t;
}
///
/// Resolves 's rank, supports both jagged array and multidim array.
///
/// The number of ranks has
[MethodImpl((MethodImplOptions)768)]
public static int ResolveRank(this Array arr)
{
if (arr == null)
throw new ArgumentNullException(nameof(arr));
var nestedArraysRenk = 1;
var t = arr.GetType().GetElementType();
// ReSharper disable once PossibleNullReferenceException
while (t.IsArray)
{
t = t.GetElementType();
nestedArraysRenk++;
}
return Math.Max(arr.Rank, nestedArraysRenk);
}
///
/// Resolves the shape of this given array.
///
///
/// Supports multi-dim and jagged arrays.
[MethodImpl((MethodImplOptions)768)]
public static (Shape Shape, Type Type) ResolveShapeAndType(this Array array)
{
//get lengths incase it is multi-dimensional
if (array.Rank > 1)
{
//is multidim
int[] dim = new int[array.Rank];
for (int idx = 0; idx < dim.Length; idx++)
dim[idx] = array.GetLength(idx);
return (new Shape(dim), array.GetType().GetElementType());
}
else
{
if (array.GetType().GetElementType()?.IsArray == true)
{
//is jagged
Array curr = array;
var dimList = new List(16);
do
{
var child = (Array)curr.GetValue(0);
dimList.Add(child.Length);
curr = child;
} while (curr.GetType().GetElementType()?.IsArray == true);
return (new Shape(dimList.ToArray()), curr.GetType().GetElementType());
}
//is 1d
return (new Shape(array.Length), array.GetType().GetElementType());
}
}
///
/// Resolves the shape of this given array.
///
///
/// Supports multi-dim and jagged arrays.
[MethodImpl((MethodImplOptions)768)]
public static Shape ResolveShape(this Array array)
{
Shape shape;
//get lengths incase it is multi-dimensional
if (array.Rank > 1)
{
int[] dim = new int[array.Rank];
for (int idx = 0; idx < dim.Length; idx++)
dim[idx] = array.GetLength(idx);
shape = new Shape(dim);
}
else
{
if (array.GetType().GetElementType()?.IsArray == true)
{
//is jagged
Array curr = array;
var dimList = new List(16);
do
{
var child = (Array)curr.GetValue(0);
dimList.Add(child.Length);
curr = child;
} while (curr.GetType().GetElementType()?.IsArray == true);
return new Shape(dimList.ToArray());
}
shape = new Shape(array.Length);
}
return shape;
}
///
/// Creates an array of 1D of type .
///
/// The type of the array
/// The type to create this array.
/// The length of the array
/// Do not use this if you are trying to create jagged or multidimensional array.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Array Create(Type type, IEnumerable enumerable)
{
// ReSharper disable once PossibleNullReferenceException
while (type.IsArray)
type = type.GetElementType();
var l = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(type));
foreach (var v in enumerable)
l.Add(v);
return (Array)l.GetType().GetMethod("ToArray", BindingFlags.Public | BindingFlags.Instance).Invoke(l, null);
}
///
/// Creates an array of 1D of type .
///
/// The type of the array
/// The type to create this array.
/// The length of the array
/// Do not use this if you are trying to create jagged or multidimensional array.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Array Create(Type type, int length)
{
// ReSharper disable once PossibleNullReferenceException
while (type.IsArray)
type = type.GetElementType();
return Array.CreateInstance(type, length);
}
///
/// Creates an array of specific of type .
///
/// The type to create this array.
/// The length of the array
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Array Create(Type type, int[] length)
{
// ReSharper disable once PossibleNullReferenceException
while (type.IsArray)
type = type.GetElementType();
return Array.CreateInstance(type, length);
}
///
/// Creates an array 1D of type .
///
/// The type of the array
/// The length of the array
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T[] Create(int length)
{
return new T[length];
}
///
/// Creates an array of 1D of type .
///
/// The type to create this array.
/// The length of the array
/// Do not use this if you are trying to create jagged or multidimensional array.
public static Array Create(NPTypeCode typeCode, int length)
{
switch (typeCode)
{
#if _REGEN
%foreach all_dtypes,all_dtypes_lowercase%
case NPTypeCode.#1:
{
return new #2[length];
}
%
default:
throw new NotImplementedException();
#else
case NPTypeCode.Complex:
{
return new Complex[length];
}
case NPTypeCode.Boolean:
{
return new bool[length];
}
case NPTypeCode.Byte:
{
return new byte[length];
}
case NPTypeCode.Int16:
{
return new short[length];
}
case NPTypeCode.UInt16:
{
return new ushort[length];
}
case NPTypeCode.Int32:
{
return new int[length];
}
case NPTypeCode.UInt32:
{
return new uint[length];
}
case NPTypeCode.Int64:
{
return new long[length];
}
case NPTypeCode.UInt64:
{
return new ulong[length];
}
case NPTypeCode.Char:
{
return new char[length];
}
case NPTypeCode.Double:
{
return new double[length];
}
case NPTypeCode.Single:
{
return new float[length];
}
case NPTypeCode.Decimal:
{
return new decimal[length];
}
case NPTypeCode.String:
{
return new string[length];
}
default:
throw new NotImplementedException();
#endif
}
}
///
/// Creates an array of 1D of type with length of 1 and a single inside.
///
/// The type to create this array.
/// The value to insert
/// Do not use this if you are trying to create jagged or multidimensional array.
public static Array Wrap(NPTypeCode typeCode, object value)
{
switch (typeCode)
{
#if _REGEN
%foreach all_dtypes,all_dtypes_lowercase%
case NPTypeCode.#1:
{
return new #2[1] {(#1)value};
}
%
default:
throw new NotImplementedException();
#else
case NPTypeCode.Complex:
{
return new Complex[1] {(Complex)value};
}
case NPTypeCode.Boolean:
{
return new bool[1] {(Boolean)value};
}
case NPTypeCode.Byte:
{
return new byte[1] {(Byte)value};
}
case NPTypeCode.Int16:
{
return new short[1] {(Int16)value};
}
case NPTypeCode.UInt16:
{
return new ushort[1] {(UInt16)value};
}
case NPTypeCode.Int32:
{
return new int[1] {(Int32)value};
}
case NPTypeCode.UInt32:
{
return new uint[1] {(UInt32)value};
}
case NPTypeCode.Int64:
{
return new long[1] {(Int64)value};
}
case NPTypeCode.UInt64:
{
return new ulong[1] {(UInt64)value};
}
case NPTypeCode.Char:
{
return new char[1] {(Char)value};
}
case NPTypeCode.Double:
{
return new double[1] {(Double)value};
}
case NPTypeCode.Single:
{
return new float[1] {(Single)value};
}
case NPTypeCode.Decimal:
{
return new decimal[1] {(Decimal)value};
}
case NPTypeCode.String:
{
return new string[1] {(String)value};
}
default:
throw new NotImplementedException();
#endif
}
}
///
/// Extracts shape and type from given .
///
/// The array to extract D and from.
public static (Shape Shape, Type DType) ExtractStructure(Array array)
{
if (array == null)
throw new ArgumentNullException(nameof(array));
//get lengths incase it is multi-dimensional
if (array.Rank > 1)
{
int[] dim = new int[array.Rank];
for (int idx = 0; idx < dim.Length; idx++)
dim[idx] = array.GetLength(idx);
var shape = new Shape(dim);
Type elementType = array.GetType();
// ReSharper disable once PossibleNullReferenceException
while (elementType.IsArray)
elementType = elementType.GetElementType();
return (shape, elementType);
}
// single dimension.
return (new Shape(array.Length), array.GetType().GetElementType());
}
///
/// Extracts shape and type from given .
///
/// The array to extract D and from.
public static (Shape Shape, Type DType) ExtractStructure(T[] array)
{
if (array == null)
{
throw new ArgumentNullException(nameof(array));
}
//this is single dimensional array.
var shape = new Shape(array.Length);
Type elementType = array.GetType().GetElementType();
return (shape, elementType);
}
}
}