// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace FlaxEngine.Utilities
{
///
/// Collection of various extension methods.
///
public static partial class Extensions
{
///
/// Creates deep clone for a class if all members of this class are marked as serializable (uses Json serialization).
///
/// The input instance of an object.
/// The instance type of an object.
/// Returns new object of provided class.
public static T DeepClone(this T instance)
where T : new()
{
var json = Json.JsonSerializer.Serialize(instance);
return Json.JsonSerializer.Deserialize(json);
}
///
/// Creates raw clone for a structure using memory copy. Valid only for value types.
///
/// The input instance of an object.
/// The instance type of an object.
/// Returns new object of provided structure.
public static T RawClone(this T instance)
{
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(instance));
try
{
Marshal.StructureToPtr(instance, ptr, false);
return (T)Marshal.PtrToStructure(ptr, instance.GetType());
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
///
/// Checks if the text is multiline.
///
/// Text to check.
/// True if text is a multiline, otherwise false.
public static bool IsMultiline(this string str)
{
for (int i = 0; i < str.Length; i++)
{
if (str[i] == '\n')
return true;
}
return false;
}
///
/// Splits string into lines
///
/// Text to split
/// True if remove empty lines, otherwise keep them
/// Array with all lines
public static string[] GetLines(this string str, bool removeEmptyLines = false)
{
return str.Split(new[]
{
"\r\n",
"\r",
"\n"
}, removeEmptyLines ? StringSplitOptions.RemoveEmptyEntries : StringSplitOptions.None);
}
///
/// Adds the elements of the specified collection to the end of the .
///
/// The type of elements in the collection.
/// The to add items to.
/// The collection whose elements should be added to the end of the . It can contain elements that are , if type is a reference type.
/// If or are .
public static void AddRange(this ICollection destination, IEnumerable collection)
{
if (destination == null)
throw new ArgumentNullException(nameof(destination));
if (collection == null)
throw new ArgumentNullException(nameof(collection));
foreach (var item in collection)
{
destination.Add(item);
}
}
///
/// Enqueues the elements of the specified collection to the .
///
/// The type of elements in the collection.
/// The to add items to.
/// The collection whose elements should be added to the . It can contain elements that are , if type is a reference type.
/// If or are .
public static void EnqueueRange(this Queue queue, IEnumerable collection)
{
if (queue == null)
throw new ArgumentNullException(nameof(queue));
if (collection == null)
throw new ArgumentNullException(nameof(collection));
foreach (var item in collection)
{
queue.Enqueue(item);
}
}
///
/// Pushes the elements of the specified collection to the .
///
/// The type of elements in the collection.
/// The to add items to.
/// The collection whose elements should be pushed on to the . It can contain elements that are , if type is a reference type.
/// If or are .
public static void PushRange(this Stack stack, IEnumerable collection)
{
if (stack == null)
throw new ArgumentNullException(nameof(stack));
if (collection == null)
throw new ArgumentNullException(nameof(collection));
foreach (var item in collection)
{
stack.Push(item);
}
}
///
/// Performs the specified action on each element of the .
///
/// The type of the elements of the input sequence.
/// The sequence of elements to execute the .
/// The delegate to perform on each element of the 1.
/// or is .
public static void ForEach(this IEnumerable source, Action action)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (action == null)
throw new ArgumentNullException(nameof(action));
foreach (var item in source)
{
action(item);
}
}
///
/// Chooses a random item from the collection.
///
/// The type of the elements of the input sequence.
/// An instance of .
/// Collection to choose item from.
/// A random item from collection
/// If the random argument is null.
/// If the collection is null.
public static T Choose(this Random random, IList collection)
{
if (random == null)
throw new ArgumentNullException(nameof(random));
if (collection == null)
throw new ArgumentNullException(nameof(collection));
return collection[random.Next(collection.Count)];
}
///
/// Chooses a random item.
///
/// The type of the elements of the input sequence.
/// An instance of .
/// Collection to choose item from.
/// A random item from collection
/// If the random is null.
/// If the collection is null.
public static T Choose(this Random random, params T[] collection)
{
if (random == null)
throw new ArgumentNullException(nameof(random));
if (collection == null)
throw new ArgumentNullException(nameof(collection));
return collection[random.Next(collection.Length)];
}
///
/// Shuffles the collection in place.
///
/// The type of the elements of the input sequence.
/// An instance of .
/// Collection to shuffle.
/// If the random argument is null.
/// If the random collection is null.
public static void Shuffle(this Random random, IList collection)
{
if (random == null)
{
throw new ArgumentNullException(nameof(random));
}
if (collection == null)
{
throw new ArgumentNullException(nameof(collection));
}
int n = collection.Count;
while (n > 1)
{
n--;
int k = random.Next(n + 1);
T value = collection[k];
collection[k] = collection[n];
collection[n] = value;
}
}
///
/// Generates a random .
///
/// An instance of .
/// Normalized value that determines the chance to return true.
/// A thats either true or false.
public static bool NextBool(this Random random, float weight = 0.5f) => random.NextDouble() < weight;
///
/// Generates a random value up until an exclusive maximum.
///
/// An instance of .
/// The maximum value. If it's zero, a maximum of 256 is used
/// A random between min and max.
public static byte NextByte(this Random random, byte max = 0)
{
return max == 0 ? (byte)(random.Next() % 256) : (byte)random.Next(max);
}
///
/// Generates a random value between min and max.
///
/// An instance of .
/// The minimum value.
/// The maximum value.
/// A random between min and max.
public static byte NextByte(this Random random, byte min, byte max)
{
return (byte)random.Next(min, max);
}
///
/// Generates a random value between min and max.
///
/// An instance of .
/// The minimum value.
/// The maximum value.
/// A random between min and max.
public static float NextFloat(this Random random, float min = 0.0f, float max = 1.0f)
{
return (float)random.NextDouble() * (max - min) + min;
}
///
/// Generates a random value between 0 and max.
///
/// An instance of .
/// The maximum value.
/// A random between min and max.
public static float NextFloat(this Random random, float max)
{
return (float)random.NextDouble() * max;
}
///
/// Generates a random .
///
/// An instance of .
/// Should the roll value be randomized.
/// A random .
public static Quaternion NextQuaternion(this Random random, bool randomRoll = false)
{
return Quaternion.Euler(NextFloat(random, -180.0f, 180.0f), NextFloat(random, -180.0f, 180.0f), randomRoll ? NextFloat(random, -180.0f, 180.0f) : 0.0f);
}
///
/// Generates a random point in a circle of a given radius.
///
/// An instance of .
/// Radius of circle. Default 1.0f./>.
/// A random .
public static Vector2 NextUnitVector2(this Random random, float radius = 1.0f)
{
var randomRadius = (float)random.NextDouble() * radius;
return new Vector2((float)Math.Cos(random.NextDouble()) * randomRadius, (float)Math.Sin(random.NextDouble()) * randomRadius);
}
///
/// Generates a uniformly distributed random unit length vector point on a unit sphere.
///
/// An instance of .
/// A random .
public static Vector3 NextUnitVector3(this Random random)
{
Vector3 output;
float l;
do
{
// Create random float with a mean of 0 and deviation of ±1
output.X = NextFloat(random) * 2.0f - 1.0f;
output.Y = NextFloat(random) * 2.0f - 1.0f;
output.Z = NextFloat(random) * 2.0f - 1.0f;
l = output.LengthSquared;
} while (l > 1 || l < Mathf.Epsilon);
output.Normalize();
return output;
}
///
/// Gets a random with components in a given range.
///
/// An instance of .
/// The minimum value.
/// The maximum value.
/// A random .
public static Vector2 NextVector2(this Random random, float min = 0.0f, float max = 1.0f)
{
return new Vector2(NextFloat(random, min, max), NextFloat(random, min, max));
}
///
/// Gets a random with components in a given range.
///
/// An instance of .
/// The minimum value.
/// The maximum value.
/// A random .
public static Vector3 NextVector3(this Random random, float min = 0.0f, float max = 1.0f)
{
return new Vector3(NextFloat(random, min, max), NextFloat(random, min, max), NextFloat(random, min, max));
}
///
/// Gets a random with components in a given range.
///
/// An instance of .
/// The minimum value.
/// The maximum value.
/// A random .
public static Vector4 NextVector4(this Random random, float min = 0.0f, float max = 1.0f)
{
return new Vector4(NextFloat(random, min, max), NextFloat(random, min, max), NextFloat(random, min, max), NextFloat(random, min, max));
}
///
/// Generates a random .
///
/// An instance of .
/// Randomize the alpha value.
/// A nice random .
public static Color NextColor(this Random random, bool randomAlpha = false)
{
return new Color(NextFloat(random), NextFloat(random), NextFloat(random), randomAlpha ? NextFloat(random) : 1.0f);
}
///
/// Generates a random .
///
/// An instance of .
/// Randomize the alpha value.
/// A nice random .
public static ColorHSV NextColorHSV(this Random random, bool randomAlpha = false)
{
return new ColorHSV(NextFloat(random, 0.0f, 360.0f), 1.0f, 1.0f, randomAlpha ? NextFloat(random) : 1.0f);
}
///
/// Gets a random .
///
/// An instance of .
/// The minimum value.
/// The maximum value.
/// A random .
public static double NextDouble(this Random random, double min = 0.0d, double max = 1.0d)
{
return random.NextDouble() * (max - min) + min;
}
///
/// Gets a random .
///
/// An instance of .
/// The maximum value.
/// A random .
public static double NextDouble(this Random random, double max = 1.0d)
{
return random.NextDouble() * max;
}
///
/// Gets a random .
///
/// An instance of .
/// A random .
internal static long NextLong(this Random random)
{
var numArray = new byte[8];
random.NextBytes(numArray);
return (long)(BitConverter.ToUInt64(numArray, 0) & long.MaxValue);
}
///
/// Returns a random value of the given enum.
///
/// The enum to get the value from.
/// An instance of .
/// A random enum value.
public static TEnum NextEnum(this Random random)
{
Array values = Enum.GetValues(typeof(TEnum));
return (TEnum)values.GetValue(random.Next(values.Length));
}
}
}