// 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); } } /// /// 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); } /// /// Gets a random double. /// /// The random. /// The maximum value /// A random double public static double NextDouble(this Random random, double maxValue) { return random.NextDouble() * maxValue; } /// /// Gets a random double. /// /// The random. /// The minimum value /// The maximum value /// A random double public static double NextDouble(this Random random, double minValue, double maxValue) { return random.NextDouble() * (maxValue - minValue) + minValue; } /// /// Gets a random float. /// /// The random. /// A random float public static float NextFloat(this Random random) { return (float)random.NextDouble(); } /// /// Gets a random float. /// /// The random. /// The maximum value /// A random float public static float NextFloat(this Random random, float maxValue) { return (float)random.NextDouble() * maxValue; } /// /// Gets a random float. /// /// The random. /// The minimum value /// The maximum value /// public static float NextFloat(this Random random, float minValue, float maxValue) { return (float)random.NextDouble() * (maxValue - minValue) + minValue; } /// /// Gets a random Color. /// /// The random. /// public static Color NextColor(this Random random) { return new Color(NextFloat(random, 1.0f), NextFloat(random, 1.0f), NextFloat(random, 1.0f), NextFloat(random, 1.0f)); } /// /// Gets a random Vector2 with components in range [0;1]. /// /// The random. /// public static Vector2 NextVector2(this Random random) { return new Vector2(NextFloat(random, 1.0f), NextFloat(random, 1.0f)); } /// /// Gets a random Vector3 with components in range [0;1]. /// /// The random. /// public static Vector3 NextVector3(this Random random) { return new Vector3(NextFloat(random, 1.0f), NextFloat(random, 1.0f), NextFloat(random, 1.0f)); } /// /// Gets a random Vector4 with components in range [0;1]. /// /// The random. /// public static Vector4 NextVector4(this Random random) { return new Vector4(NextFloat(random, 1.0f), NextFloat(random, 1.0f), NextFloat(random, 1.0f), NextFloat(random, 1.0f)); } /// /// Gets a random Quaternion. /// /// The random. /// public static Quaternion NextQuaternion(this Random random) { return Quaternion.Euler(NextFloat(random, -180, 180), NextFloat(random, -180, 180), NextFloat(random, -180, 180)); } /// /// Gets a random 64-bit signed integer value. /// /// The random. /// internal static long NextLong(this Random random) { var numArray = new byte[8]; random.NextBytes(numArray); return (long)(BitConverter.ToUInt64(numArray, 0) & 9223372036854775807L); } /// /// Generates a random normalized 2D direction vector. /// /// An instance of . /// A random normalized 2D direction vector. public static Vector2 NextDirection2D(this Random random) { return Vector2.Normalize(new Vector2((float)random.NextDouble(), (float)random.NextDouble())); } /// /// Generates a random normalized 3D direction vector. /// /// An instance of . /// A random normalized 3D direction vector. public static Vector3 NextDirection3D(this Random random) { return Vector3.Normalize(new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble())); } /// /// Generates a random point in a circle of a given radius. /// /// An instance of . /// Radius of circle. Default 1.0f. /// A random point in a circle of a given radius. public static Vector2 PointInACircle(this Random random, float radius = 1.0f) { var randomRadius = (float)random.NextDouble() * radius; return new Vector2 { X = (float)Math.Cos(random.NextDouble()) * randomRadius, Y = (float)Math.Sin(random.NextDouble()) * randomRadius, }; } /// /// 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; } } } }