using UnityEngine;
using System.Linq;
namespace Crosstales
{
/// Various extension methods.
public static class ExtensionMethods
{
#region Strings
///
/// Extension method for strings.
/// Converts a string to title case (first letter uppercase).
///
/// String-instance.
/// Converted string in title case.
public static string CTToTitleCase(this string str)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
#if UNITY_WSA
return toTitleCase(str);
#else
return System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(str.ToLower());
#endif
}
#if UNITY_WSA
///
/// Converts to title case: each word starts with an upper case.
///
private static string toTitleCase(string str)
{
if (str.Length == 0)
return str;
System.Text.StringBuilder result = new System.Text.StringBuilder(str);
result[0] = char.ToUpper(result[0]);
for (int ii = 1; ii < result.Length; ii++)
{
if (char.IsWhiteSpace(result[ii - 1]))
result[ii] = char.ToUpper(result[ii]);
else
result[ii] = char.ToLower(result[ii]);
}
return result.ToString();
}
#endif
///
/// Extension method for strings.
/// Reverses a string.
///
/// String-instance.
/// Reversed string.
public static string CTReverse(this string str)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
char[] charArray = str.ToCharArray();
System.Array.Reverse(charArray);
return new string(charArray);
}
///
/// Extension method for strings.
/// Case insensitive 'Replace'.
///
/// String-instance.
/// String to replace.
/// New replacement string.
/// StringComparison-method (default: StringComparison.OrdinalIgnoreCase, optional)
/// Replaced string.
public static string CTReplace(this string str, string oldString, string newString, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
if (oldString == null)
throw new System.ArgumentNullException(nameof(oldString));
if (newString == null)
throw new System.ArgumentNullException(nameof(newString));
int index = str.IndexOf(oldString, comp);
bool MatchFound = index >= 0;
if (MatchFound)
{
str = str.Remove(index, oldString.Length);
str = str.Insert(index, newString);
}
return str;
}
///
/// Extension method for strings.
/// Case insensitive 'Equals'.
///
/// String-instance.
/// String to check.
/// StringComparison-method (default: StringComparison.OrdinalIgnoreCase, optional)
/// True if the string contains the given string.
public static bool CTEquals(this string str, string toCheck, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
//if (toCheck == null)
// throw new System.ArgumentNullException("toCheck");
return str.Equals(toCheck, comp);
}
///
/// Extension method for strings.
/// Case insensitive 'Contains'.
///
/// String-instance.
/// String to check.
/// StringComparison-method (default: StringComparison.OrdinalIgnoreCase, optional)
/// True if the string contains the given string.
public static bool CTContains(this string str, string toCheck, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
//if (toCheck == null)
// throw new System.ArgumentNullException("toCheck");
return str.IndexOf(toCheck, comp) >= 0;
}
///
/// Extension method for strings.
/// Contains any given string.
///
/// String-instance.
/// Search terms separated by the given split-character.
/// Split-character (default: ' ', optional)
/// True if the string contains any parts of the given string.
public static bool CTContainsAny(this string str, string searchTerms, char splitChar = ' ')
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
if (string.IsNullOrEmpty(searchTerms))
return true;
char[] split = {splitChar};
return searchTerms.Split(split, System.StringSplitOptions.RemoveEmptyEntries).Any(searchTerm => str.CTContains(searchTerm));
}
///
/// Extension method for strings.
/// Contains all given strings.
///
/// String-instance.
/// Search terms separated by the given split-character.
/// Split-character (default: ' ', optional)
/// True if the string contains all parts of the given string.
public static bool CTContainsAll(this string str, string searchTerms, char splitChar = ' ')
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
if (string.IsNullOrEmpty(searchTerms))
return true;
char[] split = {splitChar};
return searchTerms.Split(split, System.StringSplitOptions.RemoveEmptyEntries).All(searchTerm => str.CTContains(searchTerm));
}
///
/// Extension method for strings.
/// Checks if the string is numeric.
///
/// String-instance.
/// True if the string is numeric.
public static bool CTisNumeric(this string str)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
return double.TryParse(str, out double output);
}
///
/// Extension method for strings.
/// Checks if the string is integer.
///
/// String-instance.
/// True if the string is integer.
public static bool CTisInteger(this string str)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
return !str.Contains(".") && long.TryParse(str, out long output);
}
///
/// Extension method for strings.
/// Checks if the string starts with another string.
///
/// String-instance.
/// String to check.
/// StringComparison-method (default: StringComparison.OrdinalIgnoreCase, optional)
/// True if the string is integer.
public static bool CTStartsWith(this string str, string toCheck, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
return string.IsNullOrEmpty(toCheck) || str.StartsWith(toCheck, comp);
}
///
/// Extension method for strings.
/// Checks if the string ends with another string.
///
/// String-instance.
/// String to check.
/// StringComparison-method (default: StringComparison.OrdinalIgnoreCase, optional)
/// True if the string is integer.
public static bool CTEndsWith(this string str, string toCheck, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
return string.IsNullOrEmpty(toCheck) || str.EndsWith(toCheck, comp);
}
///
/// Extension method for strings.
/// Returns the index of the last occurence of a given string.
///
/// String-instance.
/// String for the index.
/// StringComparison-method (default: StringComparison.OrdinalIgnoreCase, optional)
/// The index of the last occurence of the given string if the string is integer.
public static int CTLastIndexOf(this string str, string toCheck, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
return string.IsNullOrEmpty(toCheck) ? 0 : str.LastIndexOf(toCheck, comp);
}
///
/// Extension method for strings.
/// Returns the index of the first occurence of a given string.
///
/// String-instance.
/// String for the index.
/// StringComparison-method (default: StringComparison.OrdinalIgnoreCase, optional)
/// The index of the first occurence of the given string if the string is integer.
public static int CTIndexOf(this string str, string toCheck, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
return string.IsNullOrEmpty(toCheck) ? 0 : str.IndexOf(toCheck, comp);
}
///
/// Extension method for strings.
/// Returns the index of the first occurence of a given string.
///
/// String-instance.
/// String for the index.
/// Start index for the check.
/// StringComparison-method (default: StringComparison.OrdinalIgnoreCase, optional)
/// The index of the first occurence of the given string if the string is integer.
public static int CTIndexOf(this string str, string toCheck, int startIndex, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
return string.IsNullOrEmpty(toCheck) ? 0 : str.IndexOf(toCheck, startIndex, comp);
}
#endregion
#region Arrays
///
/// Extension method for Arrays.
/// Shuffles an Array.
///
/// Array-instance to shuffle.
/// Seed for the PRNG (default: 0 (=standard), optional)
public static void CTShuffle(this T[] array, int seed = 0)
{
if (array == null || array.Length <= 0)
throw new System.ArgumentNullException(nameof(array));
System.Random rnd = seed == 0 ? new System.Random() : new System.Random(seed);
int n = array.Length;
while (n > 1)
{
int k = rnd.Next(n--);
T temp = array[n];
array[n] = array[k];
array[k] = temp;
}
}
///
/// Extension method for Arrays.
/// Dumps an array to a string.
///
/// Array-instance to dump.
/// Prefix for every element (default: empty, optional).
/// Postfix for every element (default: empty, optional).
/// String with lines for all array entries.
public static string CTDump(this T[] array, string prefix = "", string postfix = "")
{
if (array == null) // || array.Length <= 0)
throw new System.ArgumentNullException(nameof(array));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (T element in array)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(prefix);
sb.Append(element);
sb.Append(postfix);
}
return sb.ToString();
}
///
/// Extension method for Quaternion-Arrays.
/// Dumps an array to a string.
///
/// Quaternion-Array-instance to dump.
/// String with lines for all array entries.
public static string CTDump(this Quaternion[] array)
{
if (array == null) // || array.Length <= 0)
throw new System.ArgumentNullException(nameof(array));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (Quaternion element in array)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(element.x);
sb.Append(", ");
sb.Append(element.y);
sb.Append(", ");
sb.Append(element.z);
sb.Append(", ");
sb.Append(element.w);
}
return sb.ToString();
}
///
/// Extension method for Vector2-Arrays.
/// Dumps an array to a string.
///
/// Vector2-Array-instance to dump.
/// String with lines for all array entries.
public static string CTDump(this Vector2[] array)
{
if (array == null) // || array.Length <= 0)
throw new System.ArgumentNullException(nameof(array));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (Vector2 element in array)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(element.x);
sb.Append(", ");
sb.Append(element.y);
}
return sb.ToString();
}
///
/// Extension method for Vector3-Arrays.
/// Dumps an array to a string.
///
/// Vector3-Array-instance to dump.
/// String with lines for all array entries.
public static string CTDump(this Vector3[] array)
{
if (array == null) // || array.Length <= 0)
throw new System.ArgumentNullException(nameof(array));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (Vector3 element in array)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(element.x);
sb.Append(", ");
sb.Append(element.y);
sb.Append(", ");
sb.Append(element.z);
}
return sb.ToString();
}
///
/// Extension method for Vector4-Arrays.
/// Dumps an array to a string.
///
/// Vector4-Array-instance to dump.
/// String with lines for all array entries.
public static string CTDump(this Vector4[] array)
{
if (array == null) // || array.Length <= 0)
throw new System.ArgumentNullException(nameof(array));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (Vector4 element in array)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(element.x);
sb.Append(", ");
sb.Append(element.y);
sb.Append(", ");
sb.Append(element.z);
sb.Append(", ");
sb.Append(element.w);
}
return sb.ToString();
}
///
/// Extension method for Arrays.
/// Generates a string array with all entries (via ToString).
///
/// Array-instance to ToString.
/// String array with all entries (via ToString).
public static string[] CTToString(this T[] array)
{
if (array == null) // || array.Length <= 0)
throw new System.ArgumentNullException(nameof(array));
string[] result = new string[array.Length];
for (int ii = 0; ii < array.Length; ii++)
{
result[ii] = null == array[ii] ? "null" : array[ii].ToString();
}
return result;
}
#endregion
#region Lists
///
/// Extension method for IList.
/// Shuffles a List.
///
/// IList-instance to shuffle.
/// Seed for the PRNG (default: 0 (=standard), optional)
public static void CTShuffle(this System.Collections.Generic.IList list, int seed = 0)
{
if (list == null)
throw new System.ArgumentNullException(nameof(list));
System.Random rnd = seed == 0 ? new System.Random() : new System.Random(seed);
int n = list.Count;
while (n > 1)
{
int k = rnd.Next(n--);
T temp = list[n];
list[n] = list[k];
list[k] = temp;
}
}
///
/// Extension method for IList.
/// Dumps a list to a string.
///
/// IList-instance to dump.
/// Prefix for every element (default: empty, optional).
/// Postfix for every element (default: empty, optional).
/// String with lines for all list entries.
public static string CTDump(this System.Collections.Generic.IList list, string prefix = "", string postfix = "")
{
if (list == null)
throw new System.ArgumentNullException(nameof(list));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (T element in list)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(prefix);
sb.Append(element);
sb.Append(postfix);
}
return sb.ToString();
}
///
/// Extension method for Quaternion-IList.
/// Dumps a list to a string.
///
/// Quaternion-IList-instance to dump.
/// String with lines for all list entries.
public static string CTDump(this System.Collections.Generic.IList list)
{
if (list == null)
throw new System.ArgumentNullException(nameof(list));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (Quaternion element in list)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(element.x);
sb.Append(", ");
sb.Append(element.y);
sb.Append(", ");
sb.Append(element.z);
sb.Append(", ");
sb.Append(element.w);
}
return sb.ToString();
}
///
/// Extension method for Vector2-IList.
/// Dumps a list to a string.
///
/// Vector2-IList-instance to dump.
/// String with lines for all list entries.
public static string CTDump(this System.Collections.Generic.IList list)
{
if (list == null)
throw new System.ArgumentNullException(nameof(list));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (Vector2 element in list)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(element.x);
sb.Append(", ");
sb.Append(element.y);
}
return sb.ToString();
}
///
/// Extension method for Vector3-IList.
/// Dumps a list to a string.
///
/// Vector3-IList-instance to dump.
/// String with lines for all list entries.
public static string CTDump(this System.Collections.Generic.IList list)
{
if (list == null)
throw new System.ArgumentNullException(nameof(list));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (Vector3 element in list)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(element.x);
sb.Append(", ");
sb.Append(element.y);
sb.Append(", ");
sb.Append(element.z);
}
return sb.ToString();
}
///
/// Extension method for Vector4-IList.
/// Dumps a list to a string.
///
/// Vector4-IList-instance to dump.
/// String with lines for all list entries.
public static string CTDump(this System.Collections.Generic.IList list)
{
if (list == null)
throw new System.ArgumentNullException(nameof(list));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (Vector4 element in list)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(element.x);
sb.Append(", ");
sb.Append(element.y);
sb.Append(", ");
sb.Append(element.z);
sb.Append(", ");
sb.Append(element.w);
}
return sb.ToString();
}
///
/// Extension method for IList.
/// Generates a string list with all entries (via ToString).
///
/// IList-instance to ToString.
/// String list with all entries (via ToString).
public static System.Collections.Generic.List CTToString(this System.Collections.Generic.IList list)
{
if (list == null)
throw new System.ArgumentNullException(nameof(list));
System.Collections.Generic.List result = new System.Collections.Generic.List(list.Count);
result.AddRange(list.Select(element => null == element ? "null" : element.ToString()));
return result;
}
#endregion
#region Dictionaries
///
/// Extension method for IDictionary.
/// Dumps a dictionary to a string.
///
/// IDictionary-instance to dump.
/// Prefix for every element (default: empty, optional).
/// Postfix for every element (default: empty, optional).
/// String with lines for all dictionary entries.
public static string CTDump(this System.Collections.Generic.IDictionary dict, string prefix = "", string postfix = "")
{
if (dict == null)
throw new System.ArgumentNullException(nameof(dict));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (System.Collections.Generic.KeyValuePair kvp in dict)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(prefix);
sb.Append("Key = ");
sb.Append(kvp.Key);
sb.Append(", Value = ");
sb.Append(kvp.Value);
sb.Append(postfix);
}
return sb.ToString();
}
///
/// Extension method for IDictionary.
/// Adds a dictionary to an existing one.
///
/// IDictionary-instance.
/// Dictionary to add.
public static void CTAddRange(this System.Collections.Generic.IDictionary dict, System.Collections.Generic.IDictionary collection)
{
if (dict == null)
throw new System.ArgumentNullException(nameof(dict));
if (collection == null)
throw new System.ArgumentNullException(nameof(collection));
foreach (System.Collections.Generic.KeyValuePair item in collection)
{
if (!dict.ContainsKey(item.Key))
{
dict.Add(item.Key, item.Value);
}
else
{
// handle duplicate key issue here
Debug.LogWarning($"Duplicate key found: {item.Key}");
}
}
}
#endregion
#region Unity specific
///
/// Extension method for Renderer.
/// Determines if the renderer is visible from a certain camera.
///
/// Renderer to test the visibility.
/// Camera for the test.
/// True if the renderer is visible by the given camera.
public static bool CTIsVisibleFrom(this Renderer renderer, Camera camera)
{
if (renderer == null)
throw new System.ArgumentNullException(nameof(renderer));
if (camera == null)
throw new System.ArgumentNullException(nameof(camera));
Plane[] planes = GeometryUtility.CalculateFrustumPlanes(camera);
return GeometryUtility.TestPlanesAABB(planes, renderer.bounds);
}
///
/// Extension method for Transform.
/// Recursively searches all children of a parent transform for specific named transform
///
/// Parent of the current children.
/// Name of the transform.
/// True if the renderer is visible by the given camera.
public static Transform CTDeepSearch(Transform parent, string name)
{
if (parent == null)
throw new System.ArgumentNullException(nameof(parent));
if (name == null)
throw new System.ArgumentNullException(nameof(name));
Transform tf = parent.Find(name);
if (tf != null)
return tf;
foreach (Transform child in parent)
{
tf = CTDeepSearch(child, name);
if (tf != null)
return tf;
}
return null;
}
#endregion
#region Streams
///
/// Extension method for Stream.
/// Reads the full content of a Stream.
///
/// Stream-instance to read.
/// Buffer size in bytes (default: 16384, optional).
/// Byte-array of the Stream content.
public static byte[] CTReadFully(this System.IO.Stream input, int bufferSize = 16384)
{
if (input == null)
throw new System.ArgumentNullException(nameof(input));
byte[] buffer = new byte[bufferSize];
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
#endregion
/*
///
/// Perform a deep Copy of the object.
///
/// The type of object being copied.
/// The object instance to copy.
/// The copied object.
public static T Clone(this T source)
{
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", "source");
}
// Don't serialize a null object, simply return the default for that object
if (Object.ReferenceEquals(source, null))
{
return default(T);
}
IFormatter formatter = new BinaryFormatter();
Stream stream = new MemoryStream();
using (stream)
{
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
*/
/*
///
/// Clone a List with elememts containing a copy constructor.
///
/// List-instance to clone.
/// Clones list.
public static List CTClone(this List listToClone) where T : ICopyable
{
List newList = new List(listToClone.Count);
listToClone.ForEach((item) =>
{
newList.Add(new T(item));
});
return newList;
//return listToClone.Select(item => (T)item.Clone()).ToList();
}
*/
/*
public static string[] CTToUppercase(string[] array)
{
if (array == null || array.Length <= 0)
throw new ArgumentNullException("array");
string[] result = new string[array.Length];
for (int ii = 0; ii < array.Length; ii++)
{
result[ii] = array[ii].ToUpper();
}
return result;
}
public static string[] CTToLowercase(string[] array)
{
if (array == null || array.Length <= 0)
throw new ArgumentNullException("array");
string[] result = new string[array.Length];
for (int ii = 0; ii < array.Length; ii++)
{
result[ii] = array[ii].ToLower();
}
return result;
}
*/
}
}
// © 2016-2020 crosstales LLC (https://www.crosstales.com)