Created S# .sln and moved project to src folder

This commit is contained in:
jeff.thompson
2017-06-21 22:41:54 -04:00
commit 52948a6e7e
93 changed files with 10647 additions and 0 deletions

View File

@@ -0,0 +1,227 @@
using System;
using System.Collections.Generic;
using System.Linq;
#if SIMPLSHARP
using Crestron.SimplSharp.Reflection;
#else
using System.Reflection;
#endif
using ICD.Common.Properties;
using ICD.Common.Services;
using ICD.Common.Services.Logging;
using ICD.Common.Utils.Collections;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils
{
/// <summary>
/// Utility methods for browsing code attributes.
/// Provides some basic caching for faster subsequent searches.
/// </summary>
public static class AttributeUtils
{
// Avoid caching the same assembly multiple times.
private static readonly IcdHashSet<Assembly> s_CachedAssemblies;
private static readonly IcdHashSet<Type> s_CachedTypes;
private static readonly Dictionary<Attribute, MethodInfo> s_AttributeToMethodCache;
private static readonly Dictionary<Type, IcdHashSet<Attribute>> s_TypeToAttributesCache;
/// <summary>
/// Constructor.
/// </summary>
static AttributeUtils()
{
s_CachedAssemblies = new IcdHashSet<Assembly>();
s_CachedTypes = new IcdHashSet<Type>();
s_AttributeToMethodCache = new Dictionary<Attribute, MethodInfo>();
s_TypeToAttributesCache = new Dictionary<Type, IcdHashSet<Attribute>>();
}
#region Caching
/// <summary>
/// Pre-emptively caches the given assemblies for lookup.
/// </summary>
/// <param name="assemblies"></param>
public static void CacheAssemblies(IEnumerable<Assembly> assemblies)
{
if (assemblies == null)
throw new ArgumentNullException("assemblies");
foreach (Assembly assembly in assemblies)
CacheAssembly(assembly);
}
/// <summary>
/// Pre-emptively caches the given assembly for lookup.
/// </summary>
/// <param name="assembly"></param>
public static void CacheAssembly(Assembly assembly)
{
if (assembly == null)
throw new ArgumentNullException("assembly");
if (s_CachedAssemblies.Contains(assembly))
return;
s_CachedAssemblies.Add(assembly);
#if SIMPLSHARP
CType[] types = new CType[0];
#else
Type[] types = new Type[0];
#endif
try
{
types = assembly.GetTypes();
}
catch (TypeLoadException e)
{
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Error, e, "Failed to cache assembly {0} - {1}", assembly.GetName().Name,
e.Message);
}
foreach (var type in types)
CacheType(type);
}
/// <summary>
/// Pre-emptively caches the given type for lookup.
/// </summary>
/// <param name="type"></param>
#if SIMPLSHARP
public static void CacheType(CType type)
#else
public static void CacheType(Type type)
#endif
{
if (type == null)
throw new ArgumentNullException("type");
if (s_CachedTypes.Contains(type))
return;
s_CachedTypes.Add(type);
MethodInfo[] methods;
try
{
#if SIMPLSHARP
s_TypeToAttributesCache[type] = new IcdHashSet<Attribute>(type.GetCustomAttributes<Attribute>(false));
methods = type.GetMethods();
#else
s_TypeToAttributesCache[type] = new IcdHashSet<Attribute>(type.GetTypeInfo().GetCustomAttributes<Attribute>(false));
methods = type.GetTypeInfo().GetMethods();
#endif
}
// GetMethods for Open Generic Types is not supported.
catch (NotSupportedException)
{
return;
}
// Not sure why this happens :/
catch (InvalidProgramException)
{
return;
}
foreach (MethodInfo method in methods)
CacheMethod(method);
}
/// <summary>
/// Caches the method.
/// </summary>
/// <param name="method"></param>
private static void CacheMethod(MethodInfo method)
{
if (method == null)
throw new ArgumentNullException("method");
foreach (Attribute attribute in method.GetCustomAttributes<Attribute>(false))
s_AttributeToMethodCache[attribute] = method;
}
#endregion
#region Lookup
/// <summary>
/// Gets the first attribute on the given class type matching the generic type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="type"></param>
/// <returns></returns>
[CanBeNull]
public static T GetClassAttribute<T>(Type type)
where T : Attribute
{
if (type == null)
throw new ArgumentNullException("type");
return GetClassAttributes<T>(type).FirstOrDefault();
}
/// <summary>
/// Gets the attributes on the given class type matching the generic type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<T> GetClassAttributes<T>(Type type)
where T : Attribute
{
if (type == null)
throw new ArgumentNullException("type");
return GetClassAttributes(type).OfType<T>();
}
/// <summary>
/// Gets the attributes on the given class.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<Attribute> GetClassAttributes(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
CacheType(type);
return s_TypeToAttributesCache.ContainsKey(type)
? s_TypeToAttributesCache[type].ToArray()
: Enumerable.Empty<Attribute>();
}
/// <summary>
/// Gets all of the cached method attributes of the given type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<T> GetMethodAttributes<T>()
where T : Attribute
{
return s_AttributeToMethodCache.Select(p => p.Key)
.OfType<T>()
.ToArray();
}
/// <summary>
/// Gets the cached method for the given attribute.
/// </summary>
/// <param name="attribute"></param>
/// <returns></returns>
public static MethodInfo GetMethod(Attribute attribute)
{
if (attribute == null)
throw new ArgumentNullException("attribute");
return s_AttributeToMethodCache[attribute];
}
#endregion
}
}

View File

@@ -0,0 +1,269 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Collections
{
/// <summary>
/// A collection containing only unique items.
/// </summary>
/// <typeparam name="T"></typeparam>
public sealed class IcdHashSet<T> : ICollection<T>
{
private readonly Dictionary<T, object> m_Dict;
#region Properties
/// <summary>
/// Returns a new, empty hashset.
/// </summary>
[PublicAPI]
public static IcdHashSet<T> NullSet { get { return new IcdHashSet<T>(); } }
/// <summary>
/// Gets the number of items contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </summary>
/// <returns>
/// The number of items contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </returns>
public int Count { get { return m_Dict.Count; } }
/// <summary>
/// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
/// </summary>
/// <returns>
/// true if the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only; otherwise, false.
/// </returns>
public bool IsReadOnly { get { return false; } }
#endregion
#region Constructors
/// <summary>
/// Constructor.
/// </summary>
public IcdHashSet()
{
m_Dict = new Dictionary<T, object>();
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="items"></param>
public IcdHashSet(IEnumerable<T> items)
: this()
{
if (items == null)
return;
AddRange(items);
}
#endregion
#region Methods
[PublicAPI]
public IcdHashSet<T> Union(IEnumerable<T> set)
{
IcdHashSet<T> unionSet = new IcdHashSet<T>(this);
if (set == null)
return unionSet;
unionSet.AddRange(set);
return unionSet;
}
[PublicAPI]
public IcdHashSet<T> Subtract(IEnumerable<T> set)
{
IcdHashSet<T> subtractSet = new IcdHashSet<T>(this);
if (set == null)
return subtractSet;
foreach (T item in set)
subtractSet.Remove(item);
return subtractSet;
}
[PublicAPI]
public bool IsSubsetOf(IcdHashSet<T> set)
{
IcdHashSet<T> setToCompare = set ?? NullSet;
return this.All(setToCompare.Contains);
}
[PublicAPI]
public IcdHashSet<T> Intersection(IcdHashSet<T> set)
{
IcdHashSet<T> intersectionSet = NullSet;
if (set == null)
return intersectionSet;
foreach (T item in this.Where(set.Contains))
intersectionSet.Add(item);
foreach (T item in set.Where(Contains))
intersectionSet.Add(item);
return intersectionSet;
}
/// <summary>
/// Returns items that are not common between both sets.
/// </summary>
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public IcdHashSet<T> NonIntersection(IcdHashSet<T> set)
{
return Subtract(set).Union(set.Subtract(this));
}
[PublicAPI]
public bool IsProperSubsetOf(IcdHashSet<T> set)
{
IcdHashSet<T> setToCompare = set ?? NullSet;
// Is a proper subset if A is a subset of B and A != B
return (IsSubsetOf(setToCompare) && !setToCompare.IsSubsetOf(this));
}
[PublicAPI]
public bool IsSupersetOf(IcdHashSet<T> set)
{
IcdHashSet<T> setToCompare = set ?? NullSet;
return setToCompare.IsSubsetOf(this);
}
[PublicAPI]
public bool IsProperSupersetOf(IcdHashSet<T> set)
{
IcdHashSet<T> setToCompare = set ?? NullSet;
// B is a proper superset of A if B is a superset of A and A != B
return (IsSupersetOf(setToCompare) && !setToCompare.IsSupersetOf(this));
}
#endregion
#region ICollection<T> Members
/// <summary>
/// Adds the item to the collection. Returns false if the item already exists.
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Add(T item)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (item == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("item");
if (m_Dict.ContainsKey(item))
return false;
m_Dict[item] = null;
return true;
}
/// <summary>
/// Adds the item to the collection.
/// </summary>
/// <param name="item"></param>
void ICollection<T>.Add(T item)
{
Add(item);
}
/// <summary>
/// Adds each of the items in the sequence to the collection.
/// </summary>
/// <param name="items"></param>
public void AddRange(IEnumerable<T> items)
{
foreach (T item in items)
Add(item);
}
/// <summary>
/// Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </summary>
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only. </exception>
public void Clear()
{
m_Dict.Clear();
}
/// <summary>
/// Returns true if the IcdHashSet contains the given item.
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Contains(T item)
{
return m_Dict.ContainsKey(item);
}
/// <summary>
/// Copies the items of the <see cref="T:System.Collections.Generic.ICollection`1"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index.
/// </summary>
/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the items copied from <see cref="T:System.Collections.Generic.ICollection`1"/>. The <see cref="T:System.Array"/> must have zero-based indexing.</param><param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is null.</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="arrayIndex"/> is less than 0.</exception><exception cref="T:System.ArgumentException"><paramref name="array"/> is multidimensional.-or-<paramref name="arrayIndex"/> is equal to or greater than the length of <paramref name="array"/>.-or-The number of items in the source <see cref="T:System.Collections.Generic.ICollection`1"/> is greater than the available space from <paramref name="arrayIndex"/> to the end of the destination <paramref name="array"/>.-or-Type T cannot be cast automatically to the type of the destination <paramref name="array"/>.</exception>
public void CopyTo(T[] array, int arrayIndex)
{
m_Dict.Keys.CopyTo(array, arrayIndex);
}
/// <summary>
/// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </summary>
/// <returns>
/// true if <paramref name="item"/> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. This method also returns false if <paramref name="item"/> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </returns>
/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
public bool Remove(T item)
{
return m_Dict.Remove(item);
}
#endregion
#region Implementation of IEnumerable
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
/// </returns>
/// <filterpriority>1</filterpriority>
public IEnumerator<T> GetEnumerator()
{
return m_Dict.Keys.GetEnumerator();
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
/// </returns>
/// <filterpriority>2</filterpriority>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
}

View File

@@ -0,0 +1,180 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Collections
{
/// <summary>
/// ScrollQueue is a queue that never exceeds a predefined length. Old items
/// are removed as new items are added.
/// </summary>
/// <typeparam name="TContents"></typeparam>
public sealed class ScrollQueue<TContents> : IEnumerable<TContents>, ICollection
{
private readonly LinkedList<TContents> m_Collection;
private int m_MaxSize;
private readonly SafeCriticalSection m_CollectionLock;
#region Properties
/// <summary>
/// Gets/sets the maximum size of the queue.
/// </summary>
[PublicAPI]
public int MaxSize
{
get { return m_MaxSize; }
set
{
if (value == m_MaxSize)
return;
m_MaxSize = value;
Trim();
}
}
/// <summary>
/// Gets the number of items in the collection.
/// </summary>
public int Count { get { return m_CollectionLock.Execute(() => m_Collection.Count); } }
/// <summary>
/// The IsSynchronized Boolean property returns True if the
/// collection is designed to be thread safe; otherwise, it returns False.
/// </summary>
public bool IsSynchronized { get { return true; } }
/// <summary>
/// The SyncRoot property returns an object, which is used for synchronizing
/// the collection. This returns the instance of the object or returns the
/// SyncRoot of other collections if the collection contains other collections.
/// </summary>
public object SyncRoot { get { return this; } }
#endregion
/// <summary>
/// Constructor.
/// </summary>
/// <param name="maxSize"></param>
public ScrollQueue(int maxSize)
{
m_CollectionLock = new SafeCriticalSection();
m_Collection = new LinkedList<TContents>();
MaxSize = maxSize;
}
#region Queue Methods
/// <summary>
/// Clears all items from the queue.
/// </summary>
public void Clear()
{
m_CollectionLock.Execute(() => m_Collection.Clear());
}
/// <summary>
/// Appends the item to the queue, trims old items that exceed max length.
/// </summary>
/// <param name="item"></param>
[PublicAPI]
public void Enqueue(TContents item)
{
m_CollectionLock.Execute(() => m_Collection.AddLast(item));
Trim();
}
/// <summary>
/// Removes the oldest item from the queue.
/// </summary>
/// <returns></returns>
[PublicAPI]
public TContents Dequeue()
{
m_CollectionLock.Enter();
try
{
TContents output = m_Collection.First.Value;
m_Collection.RemoveFirst();
return output;
}
finally
{
m_CollectionLock.Leave();
}
}
/// <summary>
/// Returns the oldest item in the queue.
/// </summary>
/// <returns></returns>
[PublicAPI]
public TContents Peek()
{
return m_CollectionLock.Execute(() => m_Collection.First.Value);
}
#endregion
#region Implemented Methods
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<TContents> GetEnumerator()
{
return m_CollectionLock.Execute(() => m_Collection.ToList().GetEnumerator());
}
void ICollection.CopyTo(Array myArr, int index)
{
m_CollectionLock.Enter();
try
{
foreach (TContents item in m_Collection)
{
myArr.SetValue(item, index);
index++;
}
}
finally
{
m_CollectionLock.Leave();
}
}
#endregion
#region Private Methods
/// <summary>
/// Removes items that fall outside of the max size.
/// </summary>
private void Trim()
{
m_CollectionLock.Enter();
try
{
while (Count > MaxSize)
m_Collection.RemoveFirst();
}
finally
{
m_CollectionLock.Leave();
}
}
#endregion
}
}

View File

@@ -0,0 +1,245 @@
#if SIMPLSHARP
using System;
using System.Text.RegularExpressions;
using Crestron.SimplSharp;
using ICD.Common.Properties;
using ICD.Common.Services;
using ICD.Common.Services.Logging;
namespace ICD.Common.Utils
{
public static class CrestronUtils
{
private const string MODEL_NAME_REGEX = @"^(\S*)";
private const string MODEL_VERSION_REGEX = @" [[]v(\S*)";
private const string RAMFREE_COMMAND = "ramfree";
private const string RAMFREE_DIGITS_REGEX = @"^(\d*)";
private static string s_VersionResult;
#region Properties
/// <summary>
/// Gets the default mac address of the processor.
/// </summary>
[PublicAPI]
public static string DefaultMacAddress
{
get
{
const CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET param =
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS;
const EthernetAdapterType type = EthernetAdapterType.EthernetLANAdapter;
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(type);
return CrestronEthernetHelper.GetEthernetParameter(param, id);
}
}
/// <summary>
/// Gets the version text from the console.
/// </summary>
private static string VersionResult
{
get
{
if (string.IsNullOrEmpty(s_VersionResult))
{
if (!CrestronConsole.SendControlSystemCommand("version", ref s_VersionResult))
{
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Warning, "{0} - Failed to send console command \"{1}\"",
typeof(CrestronUtils).Name, "version");
}
}
return s_VersionResult;
}
}
/// <summary>
/// Gets the model name of the processor.
/// </summary>
[PublicAPI]
public static string ModelName
{
get
{
Regex regex = new Regex(MODEL_NAME_REGEX);
Match match = regex.Match(VersionResult);
if (match.Success)
return match.Groups[1].Value;
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Warning, "Unable to get model name from \"{0}\"", VersionResult);
return string.Empty;
}
}
/// <summary>
/// Gets the processor firmware version.
/// </summary>
[PublicAPI]
public static Version ModelVersion
{
get
{
Regex regex = new Regex(MODEL_VERSION_REGEX);
Match match = regex.Match(VersionResult);
if (match.Success)
return new Version(match.Groups[1].Value);
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Warning, "Unable to get model version from \"{0}\"", VersionResult);
return new Version(0, 0);
}
}
/// <summary>
/// Gets the ram usage in the range 0 - 1.
/// </summary>
public static float RamUsagePercent
{
get
{
string ramFree = GetRamFree();
string digits = Regex.Matches(ramFree, RAMFREE_DIGITS_REGEX, RegexOptions.Multiline)[0].Groups[1].Value;
return float.Parse(digits) / 100.0f;
}
}
/// <summary>
/// Gets the total number of bytes of physical memory.
/// </summary>
public static ulong RamTotalBytes
{
get
{
string ramFree = GetRamFree();
string digits = Regex.Matches(ramFree, RAMFREE_DIGITS_REGEX, RegexOptions.Multiline)[1].Groups[1].Value;
return ulong.Parse(digits);
}
}
/// <summary>
/// Gets the total number of bytes of physical memory being used by the control system.
/// </summary>
public static ulong RamUsedBytes
{
get
{
string ramFree = GetRamFree();
string digits = Regex.Matches(ramFree, RAMFREE_DIGITS_REGEX, RegexOptions.Multiline)[2].Groups[1].Value;
return ulong.Parse(digits);
}
}
/// <summary>
/// Gets the total number of bytes of physical memory not being used by the control system.
/// </summary>
public static ulong RamBytesFree
{
get
{
string ramFree = GetRamFree();
string digits = Regex.Matches(ramFree, RAMFREE_DIGITS_REGEX, RegexOptions.Multiline)[3].Groups[1].Value;
return ulong.Parse(digits);
}
}
/// <summary>
/// Gets the total number of bytes that can be reclaimed.
/// </summary>
public static ulong RamBytesReclaimable
{
get
{
string ramFree = GetRamFree();
string digits = Regex.Matches(ramFree, RAMFREE_DIGITS_REGEX, RegexOptions.Multiline)[4].Groups[1].Value;
return ulong.Parse(digits);
}
}
#endregion
#region Methods
/// <summary>
/// Restarts this program.
/// </summary>
[PublicAPI]
public static void RestartProgram()
{
string consoleResult = string.Empty;
string command = string.Format("progreset -p:{0:D2}", ProgramUtils.ProgramNumber);
CrestronConsole.SendControlSystemCommand(command, ref consoleResult);
}
/// <summary>
/// Reboots the processor.
/// </summary>
[PublicAPI]
public static void Reboot()
{
string consoleResult = string.Empty;
CrestronConsole.SendControlSystemCommand("reboot", ref consoleResult);
}
/// <summary>
/// Runs CrestronInvoke but catches any unhandled exceptions to prevent the program from terminating.
/// http://www.crestronlabs.com/showthread.php?12205-Exception-in-CrestronInvoke-thread-crashes-the-program
/// </summary>
/// <param name="callback"></param>
[PublicAPI]
public static object SafeInvoke(Action callback)
{
return SafeInvoke<object>(unused => callback(), null);
}
/// <summary>
/// Runs CrestronInvoke but catches any unhandled exceptions to prevent the program from terminating.
/// http://www.crestronlabs.com/showthread.php?12205-Exception-in-CrestronInvoke-thread-crashes-the-program
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="callback"></param>
/// <param name="param"></param>
[PublicAPI]
public static object SafeInvoke<T>(Action<T> callback, T param)
{
return CrestronInvoke.BeginInvoke(unused =>
{
try
{
callback(param);
}
catch (Exception e)
{
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Error, e, e.Message);
}
}, null);
}
#endregion
/// <summary>
/// Gets the result from the ramfree console command.
/// </summary>
/// <returns></returns>
private static string GetRamFree()
{
string ramfree = null;
if (!CrestronConsole.SendControlSystemCommand(RAMFREE_COMMAND, ref ramfree))
{
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Warning, "{0} - Failed to send console command \"{1}\"",
typeof(CrestronUtils).Name, RAMFREE_COMMAND);
}
return ramfree;
}
}
}
#endif

View File

@@ -0,0 +1,400 @@
using System;
using System.Collections.Generic;
using System.Linq;
#if SIMPLSHARP
using System.Globalization;
using Crestron.SimplSharp.Reflection;
#else
using System.Reflection;
#endif
using ICD.Common.Utils.Collections;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils
{
public static class EnumUtils
{
private static readonly Dictionary<Type, IcdHashSet<object>> s_EnumValuesCache =
new Dictionary<Type, IcdHashSet<object>>();
/// <summary>
/// Returns true if the given type is an enum.
/// </summary>
/// <returns></returns>
private static bool IsEnum(Type type)
{
return type == typeof(Enum) || type
#if !SIMPLSHARP
.GetTypeInfo()
#endif
.IsEnum;
}
/// <summary>
/// Returns true if the given type is an enum.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
private static bool IsEnum<T>()
{
return IsEnum(typeof(T));
}
#region Values
/// <summary>
/// Gets the underlying value of the enum.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static object GetUnderlyingValue<T>(T value)
{
if (!IsEnum(typeof(T)))
throw new InvalidOperationException(string.Format("{0} is not an enum", value.GetType().Name));
#if SIMPLSHARP
return Convert.ChangeType(value, ToEnum(value).GetTypeCode(), CultureInfo.InvariantCulture);
#else
return Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType()));
#endif
}
/// <summary>
/// Gets the values from an enumeration.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<T> GetValues<T>()
{
return GetValues(typeof(T)).Cast<T>();
}
/// <summary>
/// Gets the values from an enumeration.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<object> GetValues(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
// Reflection is slow and this method is called a lot, so we cache the results.
if (!s_EnumValuesCache.ContainsKey(type))
s_EnumValuesCache[type] = GetValuesUncached(type).ToHashSet();
return s_EnumValuesCache[type];
}
/// <summary>
/// Gets the values from an enumeration without performing any caching. This is slow because of reflection.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private static IEnumerable<object> GetValuesUncached(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
if (!IsEnum(type))
throw new InvalidOperationException(string.Format("{0} is not an enum", type.Name));
return type
#if SIMPLSHARP
.GetCType()
#else
.GetTypeInfo()
#endif
.GetFields(BindingFlags.Static | BindingFlags.Public)
.Select(x => x.GetValue(null));
}
/// <summary>
/// Gets the 0 value for the given enum type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetNoneValue<T>()
{
if (!IsEnum(typeof(T)))
throw new InvalidOperationException(string.Format("{0} is not an enum", typeof(T).Name));
return (T)(object)0;
}
/// <summary>
/// Gets the values from an enumeration except the 0 value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<T> GetValuesExceptNone<T>()
{
if (!IsEnum(typeof(T)))
throw new InvalidOperationException(string.Format("{0} is not an enum", typeof(T).Name));
return GetValuesExceptNone(typeof(T)).Cast<T>();
}
/// <summary>
/// Gets the values from an enumeration except the 0 value.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<object> GetValuesExceptNone(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
if (!IsEnum(type))
throw new InvalidOperationException(string.Format("{0} is not an enum", type.Name));
return GetValues(type).Where(v => (int)v != 0);
}
#endregion
#region Flags
/// <summary>
/// Returns true if the given enum type has the Flags attribute set.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static bool IsFlagsEnum<T>()
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
return IsFlagsEnum(typeof(T));
}
/// <summary>
/// Returns true if the given enum type has the Flags attribute set.
/// </summary>
/// <returns></returns>
public static bool IsFlagsEnum(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
if (!IsEnum(type))
throw new InvalidOperationException(string.Format("{0} is not an enum", type.Name));
return type
#if !SIMPLSHARP
.GetTypeInfo()
#endif
.IsDefined(typeof(FlagsAttribute), false);
}
/// <summary>
/// Gets the overlapping values of the given enum flags.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="values"></param>
/// <returns></returns>
public static T GetFlagsIntersection<T>(params T[] values)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
if (values.Length == 0)
return GetNoneValue<T>();
int output = (int)(object)values.First();
foreach (T item in values.Skip(1))
output &= (int)(object)item;
return (T)Enum.ToObject(typeof(T), output);
}
/// <summary>
/// Gets all of the set flags on the given enum.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <returns></returns>
public static IEnumerable<T> GetFlags<T>(T value)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
return GetValues<T>().Where(e => HasFlag(value, e));
}
/// <summary>
/// Gets all of the set flags on the given enum except 0.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <returns></returns>
public static IEnumerable<T> GetFlagsExceptNone<T>(T value)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
T none = GetNoneValue<T>();
return GetFlags(value).Except(none);
}
/// <summary>
/// Gets an enum value of the given type with every flag set.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetFlagsAllValue<T>()
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
int output = GetValues<T>().Aggregate(0, (current, value) => current | (int)(object)value);
return (T)Enum.ToObject(typeof(T), output);
}
/// <summary>
/// Returns true if the enum contains the given flag.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <param name="flag"></param>
/// <returns></returns>
public static bool HasFlag<T>(T value, T flag)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
return ToEnum(value).HasFlag(ToEnum(flag));
}
/// <summary>
/// Returns true if the enum contains all of the given flags.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <param name="flags"></param>
/// <returns></returns>
public static bool HasFlags<T>(T value, T flags)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
return ToEnum(value).HasFlags(ToEnum(flags));
}
/// <summary>
/// Returns true if only a single flag is set on the given enum value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <returns></returns>
public static bool HasSingleFlag<T>(T value)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
return (int)(object)value != (int)(object)GetNoneValue<T>() && !HasMultipleFlags(value);
}
/// <summary>
/// Returns true if the enum has more than 1 flag set.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static bool HasMultipleFlags<T>(T value)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
return HasMultipleFlags((int)(object)value);
}
/// <summary>
/// Returns true if the enum has more than 1 flag set.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private static bool HasMultipleFlags(int value)
{
return ((value & (value - 1)) != 0);
}
#endregion
#region Conversion
/// <summary>
/// Shorthand for parsing string to enum.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <param name="ignoreCase"></param>
/// <returns></returns>
public static T Parse<T>(string data, bool ignoreCase)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
try
{
return (T)Enum.Parse(typeof(T), data, ignoreCase);
}
catch (Exception e)
{
throw new FormatException(
string.Format("Failed to parse {0} as {1}", StringUtils.ToRepresentation(data), typeof(T).Name), e);
}
}
/// <summary>
/// Shorthand for parsing a string to enum. Returns false if the parse failed.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <param name="ignoreCase"></param>
/// <param name="result"></param>
/// <returns></returns>
public static bool TryParse<T>(string data, bool ignoreCase, out T result)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
result = default(T);
try
{
result = Parse<T>(data, ignoreCase);
return true;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// Converts the given enum value to an Enum.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <returns></returns>
public static Enum ToEnum<T>(T value)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
return ToEnum((object)value);
}
/// <summary>
/// Converts the given enum value to an Enum.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static Enum ToEnum(object value)
{
return (Enum)value;
}
#endregion
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace ICD.Common.Utils.Extensions
{
/// <summary>
/// Extension methods for working with ICollections.
/// </summary>
public static class CollectionExtensions
{
/// <summary>
/// Removes items matching the predicate.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="predicate"></param>
public static void RemoveAll<T>(this ICollection<T> extends, Func<T, bool> predicate)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (predicate == null)
throw new ArgumentNullException("predicate");
extends.RemoveAll(extends.Where(predicate).ToArray());
}
/// <summary>
/// Removes all of the items from the other collection.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="other"></param>
public static void RemoveAll<T>(this ICollection<T> extends, IEnumerable<T> other)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (other == null)
throw new ArgumentNullException("other");
foreach (T item in other)
extends.Remove(item);
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
namespace ICD.Common.Utils.Extensions
{
/// <summary>
/// Extension methods for DateTime.
/// </summary>
public static class DateTimeExtensions
{
/// <summary>
/// Gets a string representation of the DateTime with millisecond precision.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static string ToLongTimeStringWithMilliseconds(this DateTime extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
// Todo - Better handle different cultures
return extends.ToString("HH:mm:ss:fff");
}
}
}

View File

@@ -0,0 +1,340 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Extensions
{
public static class DictionaryExtensions
{
/// <summary>
/// Removes the first key with a value matching the given value.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="value"></param>
/// <returns>False if value is not found in the dictionary.</returns>
[PublicAPI]
public static bool RemoveValue<TKey, TValue>(this IDictionary<TKey, TValue> extends, TValue value)
{
if (extends == null)
throw new ArgumentNullException("extends");
try
{
TKey key = extends.GetKey(value);
return extends.Remove(key);
}
catch (ArgumentOutOfRangeException)
{
return false;
}
}
/// <summary>
/// Removes all keys with the given value.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="value"></param>
[PublicAPI]
public static void RemoveAllValues<TKey, TValue>(this IDictionary<TKey, TValue> extends, TValue value)
{
if (extends == null)
throw new ArgumentNullException("extends");
foreach (TKey key in extends.GetKeys(value).ToArray())
extends.Remove(key);
}
/// <summary>
/// If the key is present in the dictionary return the value, otherwise returns default value.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="key"></param>
/// <returns></returns>
[PublicAPI]
public static TValue GetDefault<TKey, TValue>(this IDictionary<TKey, TValue> extends, TKey key)
{
if (extends == null)
throw new ArgumentNullException("extends");
// ReSharper disable once CompareNonConstrainedGenericWithNull
if (key == null)
throw new ArgumentNullException("key");
return extends.GetDefault(key, default(TValue));
}
/// <summary>
/// If the key is present in the dictionary return the value, otherwise return the default value.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="key"></param>
/// <param name="defaultValue"></param>
/// <returns></returns>
[PublicAPI]
public static TValue GetDefault<TKey, TValue>(this IDictionary<TKey, TValue> extends, TKey key, TValue defaultValue)
{
if (extends == null)
throw new ArgumentNullException("extends");
// ReSharper disable once CompareNonConstrainedGenericWithNull
if (key == null)
throw new ArgumentNullException("key");
return extends.ContainsKey(key) ? extends[key] : defaultValue;
}
/// <summary>
/// If the key is present in the dictionary return the value, otherwise add the default value to the dictionary and return it.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="key"></param>
/// <param name="defaultValue"></param>
/// <returns></returns>
[PublicAPI]
public static TValue GetOrAddDefault<TKey, TValue>(this IDictionary<TKey, TValue> extends, TKey key,
TValue defaultValue)
{
if (extends == null)
throw new ArgumentNullException("extends");
// ReSharper disable once CompareNonConstrainedGenericWithNull
if (key == null)
throw new ArgumentNullException("key");
extends[key] = extends.GetDefault(key, defaultValue);
return extends[key];
}
/// <summary>
/// Gets a key for the given value.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="value"></param>
/// <returns></returns>
/// <exception cref="ArgumentOutOfRangeException">The value does not exist in the dictionary.</exception>
[PublicAPI]
public static TKey GetKey<TKey, TValue>(this IDictionary<TKey, TValue> extends, TValue value)
{
if (extends == null)
throw new ArgumentNullException("extends");
try
{
return extends.GetKeys(value).First();
}
catch (InvalidOperationException)
{
string message = string.Format("Unable to find Key with Value matching {0}", value);
throw new KeyNotFoundException(message);
}
}
/// <summary>
/// Gets the keys that match the given value.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="value"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<TKey> GetKeys<TKey, TValue>(this IDictionary<TKey, TValue> extends, TValue value)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.Where(kvp => EqualityComparer<TValue>.Default.Equals(kvp.Value, value))
.Select(kvp => kvp.Key);
}
/// <summary>
/// Updates the dictionary with items from the other dictionary.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="other"></param>
[PublicAPI]
public static void Update<TKey, TValue>(this IDictionary<TKey, TValue> extends, IDictionary<TKey, TValue> other)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (other == null)
throw new ArgumentNullException("other");
foreach (KeyValuePair<TKey, TValue> pair in other)
extends[pair.Key] = pair.Value;
}
/// <summary>
/// Adds the sequence of items to the dictionary.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="items"></param>
/// <param name="getKey"></param>
[PublicAPI]
public static void AddRange<TKey, TValue>(this IDictionary<TKey, TValue> extends, IEnumerable<TValue> items,
Func<TValue, TKey> getKey)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (items == null)
throw new ArgumentNullException("items");
if (getKey == null)
throw new ArgumentNullException("getKey");
foreach (TValue item in items)
extends.Add(getKey(item), item);
}
/// <summary>
/// Adds the sequence of items to the dictionary.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="items"></param>
/// <param name="getValue"></param>
[PublicAPI]
public static void AddRange<TKey, TValue>(this IDictionary<TKey, TValue> extends, IEnumerable<TKey> items,
Func<TKey, TValue> getValue)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (items == null)
throw new ArgumentNullException("items");
if (getValue == null)
throw new ArgumentNullException("getValue");
foreach (TKey item in items)
extends.Add(item, getValue(item));
}
/// <summary>
/// Adds the sequence of items to the dictionary.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="items"></param>
[PublicAPI]
public static void AddRange<TKey, TValue>(this Dictionary<TKey, TValue> extends,
IEnumerable<KeyValuePair<TKey, TValue>> items)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (items == null)
throw new ArgumentNullException("items");
foreach (KeyValuePair<TKey, TValue> item in items)
extends.Add(item.Key, item.Value);
}
/// <summary>
/// Compares the keys and values of the dictionary to determine equality.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="other"></param>
/// <returns></returns>
[PublicAPI]
public static bool DictionaryEqual<TKey, TValue>(this IDictionary<TKey, TValue> extends,
IDictionary<TKey, TValue> other)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.DictionaryEqual(other, EqualityComparer<TValue>.Default);
}
/// <summary>
/// Compares the keys and values of the dictionary to determine equality.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="other"></param>
/// <param name="valueComparer"></param>
/// <returns></returns>
[PublicAPI]
public static bool DictionaryEqual<TKey, TValue>(this IDictionary<TKey, TValue> extends,
IDictionary<TKey, TValue> other,
IEqualityComparer<TValue> valueComparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends == other)
return true;
if (other == null)
return false;
if (extends.Count != other.Count)
return false;
foreach (KeyValuePair<TKey, TValue> kvp in extends)
{
TValue secondValue;
if (!other.TryGetValue(kvp.Key, out secondValue))
return false;
if (!valueComparer.Equals(kvp.Value, secondValue))
return false;
}
return true;
}
/// <summary>
/// Returns the KeyValuePairs in key order.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<KeyValuePair<TKey, TValue>> OrderByKey<TKey, TValue>(
this IEnumerable<KeyValuePair<TKey, TValue>> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.OrderBy(kvp => kvp.Key);
}
/// <summary>
/// Returns a sequence of values ordered by the dictionary keys.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<TValue> OrderValuesByKey<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value);
}
}
}

View File

@@ -0,0 +1,71 @@
using System;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Extensions
{
public static class EnumExtensions
{
/// <summary>
/// Check to see if a flags enumeration has a specific flag set.
/// </summary>
/// <param name="extends">Flags enumeration to check</param>
/// <param name="value">Flag to check for</param>
/// <returns></returns>
[PublicAPI]
public static bool HasFlag(this Enum extends, Enum value)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (value == null)
throw new ArgumentNullException("value");
if (EnumUtils.HasMultipleFlags(value))
throw new ArgumentException("Value has multiple flags", "value");
return extends.HasFlags(value);
}
/// <summary>
/// Check to see if a flags enumeration has all of the given flags set.
/// </summary>
/// <param name="extends"></param>
/// <param name="value"></param>
/// <returns></returns>
[PublicAPI]
public static bool HasFlags(this Enum extends, Enum value)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (value == null)
throw new ArgumentNullException("value");
// Not as good as the .NET 4 version of this function, but should be good enough
if (extends.GetType() != value.GetType())
{
string message = string.Format("Enumeration type mismatch. The flag is of type '{0}', was expecting '{1}'.",
value.GetType(), extends.GetType());
throw new ArgumentException(message);
}
ulong num = Convert.ToUInt64(value);
return (Convert.ToUInt64(extends) & num) == num;
}
/// <summary>
/// Casts the enum to the given type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static T Cast<T>(this Enum extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return (T)Enum.ToObject(typeof(T), extends);
}
}
}

View File

@@ -0,0 +1,717 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Utils.Collections;
namespace ICD.Common.Utils.Extensions
{
public static class EnumerableExtensions
{
/// <summary>
/// Returns the first item in the sequence. Returns the provided default item if there
/// are no elements in the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="defaultItem"></param>
/// <returns></returns>
public static T FirstOrDefault<T>(this IEnumerable<T> extends, T defaultItem)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.FirstOrDefault(i => true, defaultItem);
}
/// <summary>
/// Returns the first element in the sequence matching the predicate. Returns the provided
/// default item if there are no elements matching the predicate in the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="predicate"></param>
/// <param name="defaultItem"></param>
/// <returns></returns>
public static T FirstOrDefault<T>(this IEnumerable<T> extends, Func<T, bool> predicate, T defaultItem)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (predicate == null)
throw new ArgumentNullException("predicate");
foreach (T item in extends.Where(predicate))
return item;
return defaultItem;
}
/// <summary>
/// Returns true if there is at least 1 item in the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="item">Outputs the first item in the sequence.</param>
/// <returns></returns>
public static bool TryFirstOrDefault<T>(this IEnumerable<T> extends, out T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.TryFirstOrDefault(i => true, out item);
}
/// <summary>
/// Returns true if there is at least 1 item in the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="predicate"></param>
/// <param name="item">Outputs the first item in the sequence.</param>
/// <returns></returns>
public static bool TryFirstOrDefault<T>(this IEnumerable<T> extends, Func<T, bool> predicate, out T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (predicate == null)
throw new ArgumentNullException("predicate");
item = default(T);
using (IEnumerator<T> iterator = extends.GetEnumerator())
{
while (iterator.MoveNext())
{
if (!predicate(iterator.Current))
continue;
item = iterator.Current;
return true;
}
}
return false;
}
/// <summary>
/// Returns the true if an element with the given index is in the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="index"></param>
/// <param name="item"></param>
/// <returns></returns>
public static bool TryElementAt<T>(this IEnumerable<T> extends, int index, out T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
item = default(T);
if (index < 0)
return false;
T[] itemArray = extends as T[] ?? extends.ToArray();
if (index >= itemArray.Length)
return false;
item = itemArray[index];
return true;
}
/// <summary>
/// Compares two sequences for identical values, ignoring order.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="other"></param>
/// <returns></returns>
public static bool ScrambledEquals<T>(this IEnumerable<T> extends, IEnumerable<T> other)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends == null)
throw new ArgumentNullException("other");
return extends.ScrambledEquals(other, EqualityComparer<T>.Default);
}
/// <summary>
/// Compares two sequences for identical values, ignoring order.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="other"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public static bool ScrambledEquals<T>(this IEnumerable<T> extends, IEnumerable<T> other, IEqualityComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends == null)
throw new ArgumentNullException("other");
if (comparer == null)
throw new ArgumentNullException("comparer");
Dictionary<T, int> count = new Dictionary<T, int>(comparer);
foreach (T item in extends)
{
if (count.ContainsKey(item))
count[item]++;
else
count.Add(item, 1);
}
foreach (T item in other)
{
if (count.ContainsKey(item))
count[item]--;
else
return false;
}
return count.Values.All(c => c == 0);
}
/// <summary>
/// Returns the index that matches the predicate.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="match"></param>
/// <returns></returns>
public static int FindIndex<T>(this IEnumerable<T> extends, Predicate<T> match)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (match == null)
throw new ArgumentNullException("match");
int index = 0;
foreach (T item in extends)
{
if (match(item))
return index;
index++;
}
return -1;
}
/// <summary>
/// Allows for selection of multiple results for each item in the sequence.
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="extends"></param>
/// <param name="selectors"></param>
/// <returns></returns>
public static IEnumerable<TResult> SelectMulti<TSource, TResult>(this IEnumerable<TSource> extends,
params Func<TSource, TResult>[] selectors)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (selectors == null)
throw new ArgumentNullException("selectors");
return extends.SelectMany(source => selectors, (source, selector) => selector(source));
}
/// <summary>
/// Enumerates each item in the sequence.
/// Useful for processing a LINQ query without creating a new collection.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
[PublicAPI]
public static void Execute<T>(this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
extends.ForEach(item => { });
}
/// <summary>
/// Performs the action for each item in the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="action"></param>
[PublicAPI]
public static void ForEach<T>(this IEnumerable<T> extends, Action<T> action)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (action == null)
throw new ArgumentNullException("action");
extends.ForEach((item, index) => action(item));
}
/// <summary>
/// Performs the action for each item in the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="action"></param>
[PublicAPI]
public static void ForEach<T>(this IEnumerable<T> extends, Action<T, int> action)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (action == null)
throw new ArgumentNullException("action");
int index = 0;
foreach (T item in extends)
action(item, index++);
}
#if SIMPLSHARP
/// <summary>
/// Prepends the item to the start of the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="item"></param>
/// <returns></returns>
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> extends, T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.PrependMany(new[] {item});
}
#endif
/// <summary>
/// Prepends the items to the start of the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="items"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<T> PrependMany<T>(this IEnumerable<T> extends, params T[] items)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (items == null)
throw new ArgumentNullException("items");
foreach (T item in items)
yield return item;
foreach (T each in extends)
yield return each;
}
#if SIMPLSHARP
/// <summary>
/// Appends the item to the end of the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="item"></param>
/// <returns></returns>
public static IEnumerable<T> Append<T>(this IEnumerable<T> extends, T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.AppendMany(new[] {item});
}
#endif
/// <summary>
/// Appends the items to the end of the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="items"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<T> AppendMany<T>(this IEnumerable<T> extends, params T[] items)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (items == null)
throw new ArgumentNullException("items");
foreach (T each in extends)
yield return each;
foreach (T item in items)
yield return item;
}
/// <summary>
/// Default ordering for the items in the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
public static IEnumerable<T> Order<T>(this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.OrderBy(i => i);
}
/// <summary>
/// Returns every item in the sequence except the given item.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="item"></param>
/// <returns></returns>
public static IEnumerable<T> Except<T>(this IEnumerable<T> extends, T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.Except(new[] {item});
}
/// <summary>
/// Returns the sequence as a IcdHashSet.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
public static IcdHashSet<T> ToHashSet<T>(this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return new IcdHashSet<T>(extends);
}
/// <summary>
/// Returns the sequence as an index:value dictionary.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static Dictionary<int, T> ToDictionary<T>(this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
Dictionary<int, T> output = new Dictionary<int, T>();
extends.ForEach((item, index) => output.Add(index, item));
return output;
}
/// <summary>
/// Returns the sequence as an index:value dictionary.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static Dictionary<uint, T> ToDictionaryUInt<T>(this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
Dictionary<uint, T> output = new Dictionary<uint, T>();
extends.ForEach((item, index) => output.Add((uint)index, item));
return output;
}
/// <summary>
/// Turns an enumerable of KeyValuePairs back into a dictionary
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.ToDictionary(x => x.Key, x => x.Value);
}
/// <summary>
/// Returns other if the list is empty.
/// Returns other if the list is non-empty and there are two different elements.
/// Returns the element of the list if it is non-empty and all elements are the same.
/// </summary>
/// <param name="extends"></param>
/// <param name="other"></param>
/// <returns></returns>
[PublicAPI]
public static T Unanimous<T>(this IEnumerable<T> extends, T other)
{
if (extends == null)
throw new ArgumentNullException("extends");
T[] array = extends as T[] ?? extends.ToArray();
return array.Unanimous() ? array.First() : other;
}
/// <summary>
/// Returns false if the list is empty.
/// Returns false if the list is non-empty and there are two different elements.
/// Returns true if the list is non-empty and all elements are the same.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static bool Unanimous<T>(this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
T[] array = extends as T[] ?? extends.ToArray();
if (array.Length == 0)
return false;
T val = array.First();
return array.All(x => EqualityComparer<T>.Default.Equals(x, val));
}
/// <summary>
/// Partitions a sequence into sequences of the given length.
/// </summary>
/// <param name="extends"></param>
/// <param name="partitionSize"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> extends, int partitionSize)
{
if (extends == null)
throw new ArgumentNullException("extends");
using (IEnumerator<T> enumerator = extends.GetEnumerator())
{
while (enumerator.MoveNext())
yield return YieldBatchElements(enumerator, partitionSize - 1);
}
}
private static IEnumerable<T> YieldBatchElements<T>(IEnumerator<T> source, int partitionSize)
{
if (source == null)
throw new ArgumentNullException("source");
// Important to enumerate through partitionSize items before returning
// Otherwise enumerable.Partition(3).Skip(1) will do unwanted things.
List<T> output = new List<T> {source.Current};
for (int i = 0; i < partitionSize && source.MoveNext(); i++)
output.Add(source.Current);
return output;
}
/// <summary>
/// Returns the minimal element of the given sequence, based on
/// the given projection.
/// </summary>
/// <remarks>
/// If more than one element has the minimal projected value, the first
/// one encountered will be returned. This overload uses the default comparer
/// for the projected type. This operator uses immediate execution, but
/// only buffers a single result (the current minimal element).
/// </remarks>
/// <typeparam name="TSource">Type of the source sequence</typeparam>
/// <typeparam name="TKey">Type of the projected element</typeparam>
/// <param name="source">Source sequence</param>
/// <param name="selector">Selector to use to pick the results to compare</param>
/// <returns>The minimal element, according to the projection.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="selector"/> is null</exception>
/// <exception cref="InvalidOperationException"><paramref name="source"/> is empty</exception>
[PublicAPI]
public static TSource MinBy<TSource, TKey>(this IEnumerable<TSource> source,
Func<TSource, TKey> selector)
{
if (source == null)
throw new ArgumentNullException("source");
if (selector == null)
throw new ArgumentNullException("selector");
return source.MinBy(selector, Comparer<TKey>.Default);
}
/// <summary>
/// Returns the minimal element of the given sequence, based on
/// the given projection and the specified comparer for projected values.
/// </summary>
/// <remarks>
/// If more than one element has the minimal projected value, the first
/// one encountered will be returned. This operator uses immediate execution, but
/// only buffers a single result (the current minimal element).
/// </remarks>
/// <typeparam name="TSource">Type of the source sequence</typeparam>
/// <typeparam name="TKey">Type of the projected element</typeparam>
/// <param name="source">Source sequence</param>
/// <param name="selector">Selector to use to pick the results to compare</param>
/// <param name="comparer">Comparer to use to compare projected values</param>
/// <returns>The minimal element, according to the projection.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/>, <paramref name="selector"/>
/// or <paramref name="comparer"/> is null</exception>
/// <exception cref="InvalidOperationException"><paramref name="source"/> is empty</exception>
[PublicAPI]
public static TSource MinBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector,
IComparer<TKey> comparer)
{
if (source == null)
throw new ArgumentNullException("source");
if (selector == null)
throw new ArgumentNullException("selector");
if (comparer == null)
throw new ArgumentNullException("comparer");
using (IEnumerator<TSource> sourceIterator = source.GetEnumerator())
{
if (!sourceIterator.MoveNext())
throw new InvalidOperationException("Sequence contains no elements");
TSource min = sourceIterator.Current;
TKey minKey = selector(min);
while (sourceIterator.MoveNext())
{
TSource candidate = sourceIterator.Current;
TKey candidateProjected = selector(candidate);
if (comparer.Compare(candidateProjected, minKey) >= 0)
continue;
min = candidate;
minKey = candidateProjected;
}
return min;
}
}
/// <summary>
/// Removes any null elements from an enumerable of nullable value types
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<T> ExceptNulls<T>(this IEnumerable<T?> extends)
where T : struct
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.Where(e => e.HasValue).Select(e => e.Value);
}
/// <summary>
/// Computes the sum of a sequence of byte values.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static byte Sum(this IEnumerable<byte> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return (byte)extends.Select(i => (int)i).Sum();
}
/// <summary>
/// Skips duplicate, consecutive items.
/// E.g.
/// [1, 2, 2, 3, 1, 1]
/// Becomes
/// [1, 2, 3, 1]
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<T> Consolidate<T>(IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return Consolidate(extends, Comparer<T>.Default);
}
/// <summary>
/// Skips duplicate, consecutive items.
/// E.g.
/// [1, 2, 2, 3, 1, 1]
/// Becomes
/// [1, 2, 3, 1]
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="comparer"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<T> Consolidate<T>(IEnumerable<T> extends, IComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (comparer == null)
throw new ArgumentNullException("comparer");
bool first = true;
T last = default(T);
foreach (T item in extends)
{
if (!first && comparer.Compare(last, item) != 0)
continue;
first = false;
last = item;
yield return item;
}
}
/// <summary>
/// Returns true if all items in the sequence match the predicate.
/// Returns false if the sequence is empty.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="predicate"></param>
/// <returns></returns>
[PublicAPI]
public static bool AnyAndAll<T>(this IEnumerable<T> extends, Func<T, bool> predicate)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (predicate == null)
throw new ArgumentNullException("predicate");
bool any = false;
foreach (T item in extends)
{
any = true;
if (!predicate(item))
return false;
}
return any;
}
}
}

View File

@@ -0,0 +1,35 @@
using System;
namespace ICD.Common.Utils.Extensions
{
/// <summary>
/// Extension methods for EventHandlers.
/// </summary>
public static class EventHandlerExtensions
{
/// <summary>
/// Raises the event safely. Simply skips if the handler is null.
/// </summary>
/// <param name="extends"></param>
/// <param name="sender"></param>
public static void Raise(this EventHandler extends, object sender)
{
if (extends != null)
extends(sender, EventArgs.Empty);
}
/// <summary>
/// Raises the event safely. Simply skips if the handler is null.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="sender"></param>
/// <param name="args"></param>
public static void Raise<T>(this EventHandler<T> extends, object sender, T args)
where T : EventArgs
{
if (extends != null)
extends(sender, args);
}
}
}

View File

@@ -0,0 +1,87 @@
#if STANDARD
using ICD.Common.Properties;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ICD.NetStandard.Common.Utils.Extensions
{
public static class HashSetExtensions
{
[PublicAPI]
public static HashSet<T> Subtract<T>(this HashSet<T> extends, IEnumerable<T> set)
{
HashSet<T> subtractSet = new HashSet<T>(extends);
if (set == null)
return subtractSet;
foreach (T item in set)
subtractSet.Remove(item);
return subtractSet;
}
[PublicAPI]
public static bool IsSubsetOf<T>(this HashSet<T> extends, HashSet<T> set)
{
HashSet<T> setToCompare = set ?? new HashSet<T>();
return extends.All(setToCompare.Contains);
}
[PublicAPI]
public static HashSet<T> Intersection<T>(this HashSet<T> extends, HashSet<T> set)
{
HashSet<T> intersectionSet = new HashSet<T>();
if (set == null)
return intersectionSet;
foreach (T item in extends.Where(set.Contains))
intersectionSet.Add(item);
foreach (T item in set.Where(extends.Contains))
intersectionSet.Add(item);
return intersectionSet;
}
/// <summary>
/// Returns items that are not common between both sets.
/// </summary>
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public static HashSet<T> NonIntersection<T>(this HashSet<T> extends, HashSet<T> set)
{
return new HashSet<T>(extends.Subtract(set).Union(set.Subtract(extends)));
}
[PublicAPI]
public static bool IsProperSubsetOf<T>(this HashSet<T> extends, HashSet<T> set)
{
HashSet<T> setToCompare = set ?? new HashSet<T>();
// Is a proper subset if A is a subset of B and A != B
return (extends.IsSubsetOf(setToCompare) && !setToCompare.IsSubsetOf(extends));
}
[PublicAPI]
public static bool IsSupersetOf<T>(this HashSet<T> extends, HashSet<T> set)
{
HashSet<T> setToCompare = set ?? new HashSet<T>();
return setToCompare.IsSubsetOf(extends);
}
[PublicAPI]
public static bool IsProperSupersetOf<T>(this HashSet<T> extends, HashSet<T> set)
{
HashSet<T> setToCompare = set ?? new HashSet<T>();
// B is a proper superset of A if B is a superset of A and A != B
return (extends.IsSupersetOf(setToCompare) && !setToCompare.IsSupersetOf(extends));
}
}
}
#endif

View File

@@ -0,0 +1,107 @@
using System;
using ICD.Common.Properties;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace ICD.Common.Utils.Extensions
{
/// <summary>
/// Extension methods for working with JSON.
/// </summary>
public static class JsonExtensions
{
/// <summary>
/// Writes the object value.
/// </summary>
/// <param name="extends"></param>
/// <param name="value"></param>
/// <param name="serializer"></param>
/// <param name="converter"></param>
[PublicAPI]
public static void WriteObject(this JsonWriter extends, object value, JsonSerializer serializer,
JsonConverter converter)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (serializer == null)
throw new ArgumentNullException("serializer");
if (converter == null)
throw new ArgumentNullException("converter");
JObject jObject = JObject.FromObject(value, serializer);
jObject.WriteTo(extends, converter);
}
/// <summary>
/// Gets the current value as an integer.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static int GetValueAsInt(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.Integer)
return (int)(long)extends.Value;
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.Integer);
throw new InvalidCastException(message);
}
/// <summary>
/// Gets the current value as a string.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static string GetValueAsString(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.String || extends.TokenType == JsonToken.Null)
return extends.Value as string;
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.String);
throw new InvalidCastException(message);
}
/// <summary>
/// Gets the current value as a bool.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static bool GetValueAsBool(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.Boolean)
return (bool)extends.Value;
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.Boolean);
throw new InvalidCastException(message);
}
/// <summary>
/// Gets the current value as an enum.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static T GetValueAsEnum<T>(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.String)
return EnumUtils.Parse<T>(extends.GetValueAsString(), true);
return (T)(object)extends.GetValueAsInt();
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
namespace ICD.Common.Utils.Extensions
{
public static class QueueExtensions
{
/// <summary>
/// Enqueues each item in the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="items"></param>
public static void EnqueueRange<T>(this Queue<T> extends, IEnumerable<T> items)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (items == null)
throw new ArgumentNullException("items");
foreach (T item in items)
extends.Enqueue(item);
}
/// <summary>
/// Dequeues the next item in the queue. Returns false if the queue is empty.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="item"></param>
/// <returns></returns>
public static bool Dequeue<T>(this Queue<T> extends, out T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
item = default(T);
if (extends.Count == 0)
return false;
item = extends.Dequeue();
return true;
}
}
}

View File

@@ -0,0 +1,32 @@
#if SIMPLSHARP
using System;
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharp.Reflection;
namespace ICD.Common.Utils.Extensions
{
/// <summary>
/// Extension methods for use with reflection objects.
/// </summary>
public static class ReflectionExtensions
{
/// <summary>
/// Returns the custom attributes attached to the member.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="inherits"></param>
/// <returns></returns>
public static IEnumerable<T> GetCustomAttributes<T>(this MemberInfo extends, bool inherits)
where T : Attribute
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.GetCustomAttributes(typeof(T), inherits).Cast<T>();
}
}
}
#endif

View File

@@ -0,0 +1,36 @@
using System;
using System.Text;
namespace ICD.Common.Utils.Extensions
{
public static class StringBuilderExtensions
{
/// <summary>
/// Empties the StringBuilder.
/// </summary>
/// <param name="extends"></param>
public static void Clear(this StringBuilder extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
extends.Remove(0, extends.Length);
}
/// <summary>
/// Returns the current string value of the StringBuilder and clears the
/// StringBuilder for further use.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static string Pop(this StringBuilder extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string output = extends.ToString();
extends.Clear();
return output;
}
}
}

View File

@@ -0,0 +1,256 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Extensions
{
public static class StringExtensions
{
/// <summary>
/// Returns the first appearance of an item from the given sequence.
/// </summary>
/// <param name="extends"></param>
/// <param name="items"></param>
/// <param name="first"></param>
/// <returns></returns>
[PublicAPI]
public static int IndexOf(this string extends, IEnumerable<string> items, out string first)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (items == null)
throw new ArgumentNullException("items");
int index = -1;
first = null;
foreach (string item in items)
{
int thisIndex = extends.IndexOf(item, StringComparison.Ordinal);
if (thisIndex == -1)
continue;
if (index != -1 && thisIndex >= index)
continue;
index = thisIndex;
first = item;
}
return index;
}
/// <summary>
/// Returns true if the string starts with the given character.
/// </summary>
/// <param name="extends"></param>
/// <param name="character"></param>
/// <returns></returns>
[PublicAPI]
public static bool StartsWith(this string extends, char character)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.StartsWith(character.ToString());
}
/// <summary>
/// Returns true if the string ends with the given character.
/// </summary>
/// <param name="extends"></param>
/// <param name="character"></param>
/// <returns></returns>
[PublicAPI]
public static bool EndsWith(this string extends, char character)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.EndsWith(character.ToString());
}
/// <summary>
/// Splits the string by the given delimiter, returning up to the given number of substrings.
/// E.g. "a:b:c".Split(':', 2) returns ["a", "b:c"]
/// </summary>
/// <param name="extends"></param>
/// <param name="delimeter"></param>
/// <param name="count"></param>
/// <returns></returns>
public static IEnumerable<string> Split(this string extends, char delimeter, int count)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (count < 2)
{
yield return extends;
yield break;
}
int index = extends.IndexOf(delimeter);
if (index < 0)
{
yield return extends;
yield break;
}
string first = extends.Substring(0, index);
string second = extends.Substring(index + 1);
count--;
yield return first;
foreach (string item in second.Split(delimeter, count))
yield return item;
}
/// <summary>
/// Splits a string into chunks of the given length.
/// </summary>
/// <param name="extends"></param>
/// <param name="chunkSize"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<string> Split(this string extends, int chunkSize)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (chunkSize <= 0)
throw new InvalidOperationException("chunkSize must be greater than 0");
return Enumerable.Range(0, extends.Length / chunkSize)
.Select(i => extends.Substring(i * chunkSize, chunkSize));
}
/// <summary>
/// Splits a string by a given substring.
/// Taken from
/// https://social.msdn.microsoft.com/Forums/en-US/914a350f-e0e9-45e0-91a4-6b4b2168e780/string-split-function
/// </summary>
/// <param name="extends"></param>
/// <param name="delimeter"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<string> Split(this string extends, string delimeter)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (delimeter == null)
throw new ArgumentNullException("delimeter");
int dSum = 0;
int sSum = 0;
int length = extends.Length;
int delimiterLength = delimeter.Length;
if (delimiterLength == 0 || length == 0 || length < delimiterLength)
{
yield return extends;
yield break;
}
char[] cd = delimeter.ToCharArray();
char[] cs = extends.ToCharArray();
for (int i = 0; i < delimiterLength; i++)
{
dSum += cd[i];
sSum += cs[i];
}
int start = 0;
for (int i = start; i < length - delimiterLength; i++)
{
if (i >= start && dSum == sSum && extends.Substring(i, delimiterLength) == delimeter)
{
yield return extends.Substring(start, i - start);
start = i + delimiterLength;
}
sSum += cs[i + delimiterLength] - cs[i];
}
if (dSum == sSum && extends.Substring(length - delimiterLength, delimiterLength) == delimeter)
{
yield return extends.Substring(start, length - delimiterLength - start);
yield return string.Empty;
}
else
yield return extends.Substring(start, length - start);
}
/// <summary>
/// Splits a string by the given substrings.
/// </summary>
/// <param name="extends"></param>
/// <param name="delimeters"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<string> Split(this string extends, IEnumerable<string> delimeters)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (delimeters == null)
throw new ArgumentNullException("delimeters");
string[] delimitersArray = delimeters as string[] ?? delimeters.ToArray();
return delimitersArray.Length == 0
? new[] {extends}
: extends.Split(delimitersArray.First())
.SelectMany(s => s.Split(delimitersArray.Skip(1)))
.Where(s => !string.IsNullOrEmpty(s));
}
/// <summary>
/// Removes whitespace from the string.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static string RemoveWhitespace(this string extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return new string(extends.Where(c => !Char.IsWhiteSpace(c)).ToArray());
}
/// <summary>
/// Removes the given characters from the string.
/// </summary>
/// <param name="extends"></param>
/// <param name="characters"></param>
/// <returns></returns>
[PublicAPI]
public static string Remove(this string extends, IEnumerable<char> characters)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (characters == null)
throw new ArgumentNullException("characters");
return new string(extends.Where(c => !characters.Contains(c)).ToArray());
}
/// <summary>
/// Returns true if the string only contains numbers.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static bool IsNumeric(this string extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.All(char.IsDigit);
}
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Text;
namespace ICD.Common.Utils.Extensions
{
public static class TimeSpanExtensions
{
public static string ToReadableString(this TimeSpan extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
StringBuilder builder = new StringBuilder();
if (extends.Days > 0)
builder.AppendFormat("{0} days, ", extends.Days);
if (extends.Hours > 0)
builder.AppendFormat("{0} hours, ", extends.Hours);
if (extends.Minutes > 0)
builder.AppendFormat("{0} minutes, ", extends.Minutes);
if (extends.Seconds > 0)
builder.AppendFormat("{0} seconds, ", extends.Seconds);
if (extends.Milliseconds > 0)
{
builder.AppendFormat("{0}.{1} ms", extends.Milliseconds,
((double)extends.Ticks / TimeSpan.TicksPerMillisecond) - extends.TotalMilliseconds);
}
return builder.ToString();
}
}
}

View File

@@ -0,0 +1,17 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp;
#else
using System.Reflection;
#endif
namespace ICD.Common.Utils.Extensions
{
public static class TypeExtensions
{
public static bool IsAssignableTo(this Type from, Type to)
{
return to.IsAssignableFrom(from);
}
}
}

View File

@@ -0,0 +1,69 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public static class IcdDirectory
{
public static string GetApplicationDirectory()
{
#if SIMPLSHARP
return Directory.GetApplicationDirectory();
#else
return Directory.GetCurrentDirectory();
#endif
}
public static bool Exists(string path)
{
if (path == null)
throw new ArgumentNullException("path");
return Directory.Exists(path);
}
public static string[] GetFiles(string path)
{
if (path == null)
throw new ArgumentNullException("path");
return Directory.GetFiles(path);
}
public static string[] GetDirectories(string path)
{
if (path == null)
throw new ArgumentNullException("path");
return Directory.GetDirectories(path);
}
public static void Delete(string path, bool recursive)
{
if (path == null)
throw new ArgumentNullException("path");
Directory.Delete(path, recursive);
}
public static void CreateDirectory(string path)
{
if (path == null)
throw new ArgumentNullException("path");
Directory.CreateDirectory(path);
}
public static string GetDirectoryRoot(string path)
{
if (path == null)
throw new ArgumentNullException("path");
return Directory.GetDirectoryRoot(path);
}
}
}

View File

@@ -0,0 +1,39 @@
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
using System;
using System.Text;
namespace ICD.Common.Utils.IO
{
public sealed class IcdEncodingStringWriter : IcdStringWriter
{
public IcdEncodingStringWriter(StringBuilder output, Encoding encoding)
: base(new EncodingStringWriter(output, encoding))
{
}
private sealed class EncodingStringWriter : StringWriter
{
private readonly Encoding m_Encoding;
public override Encoding Encoding { get { return m_Encoding; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="builder"></param>
/// <param name="encoding"></param>
public EncodingStringWriter(StringBuilder builder, Encoding encoding)
: base(builder)
{
if (encoding == null)
throw new ArgumentNullException("encoding");
m_Encoding = encoding;
}
}
}
}

View File

@@ -0,0 +1,60 @@
using ICD.Common.Properties;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
using System;
using System.Text;
namespace ICD.Common.Utils.IO
{
public static class IcdFile
{
[PublicAPI]
public static string ReadToEnd(string path, Encoding encoding)
{
if (path == null)
throw new ArgumentNullException("path");
if (encoding == null)
throw new ArgumentNullException("encoding");
#if SIMPLSHARP
return File.ReadToEnd(path, encoding);
#else
return File.ReadAllText(path, encoding);
#endif
}
[PublicAPI]
public static bool Exists(string path)
{
if (path == null)
throw new ArgumentNullException("path");
return File.Exists(path);
}
[PublicAPI]
public static void Copy(string pathFrom, string pathTo)
{
if (pathFrom == null)
throw new ArgumentNullException("pathFrom");
if (pathTo == null)
throw new ArgumentNullException("pathTo");
File.Copy(pathFrom, pathTo);
}
[PublicAPI]
public static void Delete(string path)
{
if (path == null)
throw new ArgumentNullException("path");
File.Delete(path);
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public sealed class IcdFileStream : IcdStream
{
public int Position { get; set; }
public FileStream WrappedFileStream { get { return WrappedStream as FileStream; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="fileStrean"></param>
public IcdFileStream(FileStream fileStrean)
: base(fileStrean)
{
}
public static IcdFileStream OpenWrite(string path)
{
if (path == null)
throw new ArgumentNullException("path");
return new IcdFileStream(File.OpenWrite(path));
}
public void Flush()
{
WrappedFileStream.Flush();
}
public void Close()
{
#if SIMPLSHARP
WrappedFileStream.Close();
#else
WrappedFileStream.Dispose();
#endif
}
}
}

View File

@@ -0,0 +1,47 @@
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public sealed class IcdMemoryStream : IcdStream
{
public int Position { get; set; }
public MemoryStream WrappedMemoryStream { get { return WrappedStream as MemoryStream; } }
/// <summary>
/// Constructor.
/// </summary>
public IcdMemoryStream()
: this(new MemoryStream())
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="memoryStream"></param>
public IcdMemoryStream(MemoryStream memoryStream)
: base(memoryStream)
{
}
public void Flush()
{
WrappedMemoryStream.Flush();
}
public void Close()
{
#if SIMPLSHARP
WrappedMemoryStream.Close();
#else
WrappedMemoryStream.Dispose();
#endif
}
}
}

View File

@@ -0,0 +1,58 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public static class IcdPath
{
public static string GetFileNameWithoutExtension(string path)
{
if (path == null)
throw new ArgumentNullException("path");
return Path.GetFileNameWithoutExtension(path);
}
public static string GetDirectoryName(string path)
{
if (path == null)
throw new ArgumentNullException("path");
return Path.GetDirectoryName(path);
}
public static string GetExtension(string path)
{
if (path == null)
throw new ArgumentNullException("path");
return Path.GetExtension(path);
}
public static string Combine(string a, string b)
{
if (a == null)
throw new ArgumentNullException("a");
if (b == null)
throw new ArgumentNullException("b");
return Path.Combine(a, b);
}
public static string ChangeExtension(string path, string ext)
{
if (path == null)
throw new ArgumentNullException("path");
if (ext == null)
throw new ArgumentNullException("ext");
return Path.ChangeExtension(path, ext);
}
}
}

View File

@@ -0,0 +1,33 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public class IcdStream : IDisposable
{
private readonly Stream m_Stream;
public Stream WrappedStream { get { return m_Stream; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="stream"></param>
public IcdStream(Stream stream)
{
if (stream == null)
throw new ArgumentNullException("stream");
m_Stream = stream;
}
public void Dispose()
{
m_Stream.Dispose();
}
}
}

View File

@@ -0,0 +1,41 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#elif STANDARD
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public sealed class IcdStreamReader : IDisposable
{
private readonly StreamReader m_StreamReader;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="memoryStream"></param>
public IcdStreamReader(IcdMemoryStream memoryStream)
{
if (memoryStream == null)
throw new ArgumentNullException("memoryStream");
m_StreamReader = new StreamReader(memoryStream.WrappedMemoryStream);
}
~IcdStreamReader()
{
Dispose();
}
public string ReadToEnd()
{
return m_StreamReader.ReadToEnd();
}
public void Dispose()
{
m_StreamReader.Dispose();
}
}
}

View File

@@ -0,0 +1,24 @@
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public sealed class IcdStringReader : IcdTextReader
{
public StringReader WrappedStringReader { get { return WrappedTextReader as StringReader; } }
public IcdStringReader(string value)
: this(new StringReader(value))
{
}
private IcdStringReader(StringReader stringReader)
: base(stringReader)
{
}
}
}

View File

@@ -0,0 +1,32 @@
using System.Text;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public class IcdStringWriter : IcdTextWriter
{
public StringWriter WrappedStringWriter { get { return WrappedTextWriter as StringWriter; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="stringWriter"></param>
public IcdStringWriter(StringWriter stringWriter)
: base(stringWriter)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="stringBuilder"></param>
public IcdStringWriter(StringBuilder stringBuilder)
: this(new StringWriter(stringBuilder))
{
}
}
}

View File

@@ -0,0 +1,21 @@
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public class IcdTextReader
{
private readonly TextReader m_TextReader;
public TextReader WrappedTextReader { get { return m_TextReader; } }
protected IcdTextReader(TextReader textReader)
{
m_TextReader = textReader;
}
}
}

View File

@@ -0,0 +1,38 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public class IcdTextWriter : IDisposable
{
private readonly TextWriter m_TextWriter;
public TextWriter WrappedTextWriter { get { return m_TextWriter; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="textWriter"></param>
protected IcdTextWriter(TextWriter textWriter)
{
if (textWriter == null)
throw new ArgumentNullException("textWriter");
m_TextWriter = textWriter;
}
~IcdTextWriter()
{
Dispose();
}
public void Dispose()
{
m_TextWriter.Dispose();
}
}
}

View File

@@ -0,0 +1,15 @@
using System;
namespace ICD.Common.Utils
{
/// <summary>
/// Provides features for managing the disposed state of an IDisposable.
/// </summary>
public interface IStateDisposable : IDisposable
{
/// <summary>
/// Returns true if this instance has been disposed.
/// </summary>
bool IsDisposed { get; }
}
}

View File

@@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
#if SIMPLSHARP
using Crestron.SimplSharp;
#endif
using ICD.Common.Properties;
namespace ICD.Common.Utils
{
public sealed class IcdConsole
{
public enum eAccessLevel
{
Operator = 0,
Programmer = 1,
Administrator = 2
}
/// <summary>
/// Wraps CrestronConsole.ConsoleCommandResponse for S+ compatibility.
/// </summary>
/// <param name="message"></param>
/// <param name="args"></param>
[PublicAPI]
public static void ConsoleCommandResponseLine(string message, params object[] args)
{
ConsoleCommandResponse(message + IcdEnvironment.NewLine, args);
}
/// <summary>
/// Wraps CrestronConsole.ConsoleCommandResponse for S+ compatibility.
/// </summary>
/// <param name="message"></param>
/// <param name="args"></param>
[PublicAPI]
public static void ConsoleCommandResponse(string message, params object[] args)
{
message = string.Format(message, args);
#if SIMPLSHARP
try
{
CrestronConsole.ConsoleCommandResponse(message);
}
catch (NotSupportedException)
{
CrestronConsole.Print(message);
}
#else
System.Console.Write(message, args);
#endif
}
public static void PrintLine(string message)
{
#if SIMPLSHARP
CrestronConsole.PrintLine(message);
#else
System.Console.WriteLine(message);
#endif
}
public static void PrintLine(string message, params object[] args)
{
#if SIMPLSHARP
CrestronConsole.PrintLine(message, args);
#else
System.Console.WriteLine(message, args);
#endif
}
public static void Print(string message)
{
#if SIMPLSHARP
CrestronConsole.Print(message);
#else
System.Console.Write(message);
#endif
}
public static void Print(string message, params object[] args)
{
#if SIMPLSHARP
CrestronConsole.Print(message, args);
#else
System.Console.Write(message, args);
#endif
}
public static bool SendControlSystemCommand(string command, ref string result)
{
#if SIMPLSHARP
return CrestronConsole.SendControlSystemCommand(command, ref result);
#else
result = string.Empty;
return false;
#endif
}
public static void AddNewConsoleCommand(Action<string> callback, string command, string help, eAccessLevel accessLevel)
{
#if SIMPLSHARP
CrestronConsole.AddNewConsoleCommand(str => callback(str), command, help, (ConsoleAccessLevelEnum)(int)accessLevel);
#endif
}
}
}

View File

@@ -0,0 +1,118 @@
#if SIMPLSHARP
using System;
using System.Collections.Generic;
using Crestron.SimplSharp;
using ICD.Common.Properties;
namespace ICD.Common.Utils
{
public static partial class IcdEnvironment
{
public static string NewLine { get { return CrestronEnvironment.NewLine; } }
public static eRuntimeEnvironment RuntimeEnvironment
{
get { return GetRuntimeEnvironment(CrestronEnvironment.RuntimeEnvironment); }
}
/// <summary>
/// Static constructor.
/// </summary>
static IcdEnvironment()
{
CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironmentOnProgramStatusEventHandler;
CrestronEnvironment.EthernetEventHandler += CrestronEnvironmentOnEthernetEventHandler;
}
/// <summary>
/// Gets the network address(es) of the processor.
/// </summary>
[PublicAPI]
public static IEnumerable<string> NetworkAddresses
{
get
{
const CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET param =
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS;
const EthernetAdapterType type = EthernetAdapterType.EthernetLANAdapter;
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(type);
yield return CrestronEthernetHelper.GetEthernetParameter(param, id);
}
}
#region Methods
public static DateTime GetLocalTime()
{
return CrestronEnvironment.GetLocalTime();
}
public static eEthernetEventType GetEthernetEventType(Crestron.SimplSharp.eEthernetEventType type)
{
switch (type)
{
case Crestron.SimplSharp.eEthernetEventType.LinkDown:
return eEthernetEventType.LinkDown;
case Crestron.SimplSharp.eEthernetEventType.LinkUp:
return eEthernetEventType.LinkUp;
default:
throw new ArgumentOutOfRangeException("type");
}
}
public static eEthernetAdapterType GetEthernetAdapterType(EthernetAdapterType ethernetAdapter)
{
return (eEthernetAdapterType)(int)ethernetAdapter;
}
public static eProgramStatusEventType GetProgramStatusEventType(Crestron.SimplSharp.eProgramStatusEventType type)
{
switch (type)
{
case Crestron.SimplSharp.eProgramStatusEventType.Stopping:
return eProgramStatusEventType.Stopping;
case Crestron.SimplSharp.eProgramStatusEventType.Paused:
return eProgramStatusEventType.Paused;
case Crestron.SimplSharp.eProgramStatusEventType.Resumed:
return eProgramStatusEventType.Resumed;
default:
throw new ArgumentOutOfRangeException("type");
}
}
public static eRuntimeEnvironment GetRuntimeEnvironment(Crestron.SimplSharp.eRuntimeEnvironment runtimeEnvironment)
{
switch (runtimeEnvironment)
{
case Crestron.SimplSharp.eRuntimeEnvironment.SIMPL:
return eRuntimeEnvironment.SimplSharp;
case Crestron.SimplSharp.eRuntimeEnvironment.SimplSharpPro:
return eRuntimeEnvironment.SimplSharpPro;
default:
throw new ArgumentOutOfRangeException("runtimeEnvironment");
}
}
#endregion
#region Private Methods
private static void CrestronEnvironmentOnEthernetEventHandler(EthernetEventArgs args)
{
EthernetEventCallback handler = OnEthernetEvent;
if (handler != null)
handler(GetEthernetAdapterType(args.EthernetAdapter), GetEthernetEventType(args.EthernetEventType));
}
private static void CrestronEnvironmentOnProgramStatusEventHandler(Crestron.SimplSharp.eProgramStatusEventType type)
{
ProgramStatusCallback handler = OnProgramStatusEvent;
if (handler != null)
handler(GetProgramStatusEventType(type));
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,34 @@
#if STANDARD
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Net.Sockets;
namespace ICD.Common.Utils
{
public static partial class IcdEnvironment
{
public static string NewLine { get { return Environment.NewLine; } }
public static DateTime GetLocalTime()
{
return DateTime.Now;
}
public static eRuntimeEnvironment RuntimeEnvironment { get { return eRuntimeEnvironment.Standard; } }
public static IEnumerable<string> NetworkAddresses
{
get
{
return NetworkInterface.GetAllNetworkInterfaces()
.Where(ni => ni.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 || ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
.SelectMany(ni => ni.GetIPProperties().UnicastAddresses
.Where(ua => ua.Address.AddressFamily == AddressFamily.InterNetwork)
.Select(ua => ua.Address.ToString()));
}
}
}
}
#endif

View File

@@ -0,0 +1,57 @@
using System;
namespace ICD.Common.Utils
{
public static partial class IcdEnvironment
{
/// <summary>
/// Enumeration to define the various runtime environments a SIMPL# module can run in.
/// </summary>
public enum eRuntimeEnvironment
{
SimplSharp,
SimplSharpPro,
Standard
}
/// <summary>
/// Enum for the Program Event Types
/// </summary>
public enum eProgramStatusEventType
{
Stopping,
Paused,
Resumed,
}
/// <summary>
/// Enum for the Ethernet Event Types
/// </summary>
public enum eEthernetEventType
{
LinkDown,
LinkUp,
}
/// <summary>
/// Enums for the Ethernet Adapter Type
/// </summary>
[Flags]
public enum eEthernetAdapterType
{
EthernetUnknownAdapter = 0,
EthernetLanAdapter = 1,
EthernetCsAdapter = 2,
EthernetWifiAdapter = 4,
EthernetLan2Adapter = 8,
}
public delegate void ProgramStatusCallback(eProgramStatusEventType type);
public delegate void EthernetEventCallback(eEthernetAdapterType adapter, eEthernetEventType type);
public static event ProgramStatusCallback OnProgramStatusEvent;
public static event EthernetEventCallback OnEthernetEvent;
}
}

View File

@@ -0,0 +1,210 @@
using System;
using ICD.Common.Properties;
namespace ICD.Common.Utils
{
public static class IcdErrorLog
{
private const string CONSOLE_RED = "\x1B[31;1m";
private const string CONSOLE_GREEN = "\x1B[32;1m";
private const string CONSOLE_YELLOW = "\x1B[33;1m";
private const string CONSOLE_BLUE = "\x1B[34;1m";
//private const string CONSOLE_MAGENTA = "\x1B[35;1m";
private const string CONSOLE_CYAN = "\x1B[36;1m";
//private const string CONSOLE_WHITE = "\x1B[37;1m";
private const string CONSOLE_YELLOW_ON_RED_BACKGROUND = "\x1B[93;41m";
private const string CONSOLE_RESET = "\x1B[0m";
private static readonly SafeCriticalSection s_LoggingSection;
/// <summary>
/// Static constructor.
/// </summary>
static IcdErrorLog()
{
s_LoggingSection = new SafeCriticalSection();
}
[PublicAPI]
public static void Error(string message)
{
s_LoggingSection.Enter();
try
{
#if SIMPLSHARP
message = FormatConsoleColor(message, CONSOLE_RED);
Crestron.SimplSharp.ErrorLog.Error(message);
#else
System.Console.ForegroundColor = ConsoleColor.Red;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
#endif
}
finally
{
s_LoggingSection.Leave();
}
}
[PublicAPI]
public static void Error(string message, params object[] args)
{
Error(string.Format(message, args));
}
[PublicAPI]
public static void Warn(string message)
{
s_LoggingSection.Enter();
try
{
#if SIMPLSHARP
message = FormatConsoleColor(message, CONSOLE_YELLOW);
Crestron.SimplSharp.ErrorLog.Warn(message);
#else
System.Console.ForegroundColor = ConsoleColor.Yellow;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
#endif
}
finally
{
s_LoggingSection.Leave();
}
}
[PublicAPI]
public static void Warn(string message, params object[] args)
{
Warn(string.Format(message, args));
}
[PublicAPI]
public static void Notice(string message)
{
s_LoggingSection.Enter();
try
{
#if SIMPLSHARP
message = FormatConsoleColor(message, CONSOLE_BLUE);
Crestron.SimplSharp.ErrorLog.Notice(message);
#else
System.Console.ForegroundColor = ConsoleColor.Blue;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
#endif
}
finally
{
s_LoggingSection.Leave();
}
}
[PublicAPI]
public static void Notice(string message, params object[] args)
{
Notice(string.Format(message, args));
}
[PublicAPI]
public static void Ok(string message)
{
s_LoggingSection.Enter();
try
{
#if SIMPLSHARP
message = FormatConsoleColor(message, CONSOLE_GREEN);
Crestron.SimplSharp.ErrorLog.Ok(message);
#else
System.Console.ForegroundColor = ConsoleColor.Green;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
#endif
}
finally
{
s_LoggingSection.Leave();
}
}
[PublicAPI]
public static void Ok(string message, params object[] args)
{
Ok(string.Format(message, args));
}
[PublicAPI]
public static void Exception(Exception ex, string message)
{
s_LoggingSection.Enter();
try
{
#if SIMPLSHARP
message = FormatConsoleColor(message, CONSOLE_YELLOW_ON_RED_BACKGROUND);
Crestron.SimplSharp.ErrorLog.Exception(message, ex);
#else
System.Console.ForegroundColor = ConsoleColor.Yellow;
System.Console.BackgroundColor = ConsoleColor.Red;
System.Console.Error.WriteLine("{0}: {1}", ex.GetType().Name, message);
System.Console.ResetColor();
System.Console.Error.WriteLine(ex.StackTrace);
#endif
}
finally
{
s_LoggingSection.Leave();
}
}
[PublicAPI]
public static void Exception(Exception ex, string message, params object[] args)
{
message = string.Format(message, args);
Exception(ex, message);
}
[PublicAPI]
public static void Info(string message)
{
s_LoggingSection.Enter();
try
{
#if SIMPLSHARP
message = FormatConsoleColor(message, CONSOLE_CYAN);
Crestron.SimplSharp.ErrorLog.Info(message);
#else
System.Console.ForegroundColor = ConsoleColor.Cyan;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
#endif
}
finally
{
s_LoggingSection.Leave();
}
}
[PublicAPI]
public static void Info(string message, params object[] args)
{
Info(string.Format(message, args));
}
/// <summary>
/// Formats the text with the given console color.
/// </summary>
/// <param name="text"></param>
/// <param name="color"></param>
/// <returns></returns>
private static string FormatConsoleColor(string text, string color)
{
return string.Format("{0}{1}{2}", color, text, CONSOLE_RESET);
}
}
}

View File

@@ -0,0 +1,40 @@
#if SIMPLSHARP
using Crestron.SimplSharp;
#else
using System;
using System.IO.Compression;
#endif
namespace ICD.Common.Utils
{
/// <summary>
/// Utils for managing archives.
/// </summary>
public static class IcdZip
{
/// <summary>
/// Unzips the archive at the given path.
/// </summary>
/// <param name="path"></param>
/// <param name="outputPath"></param>
public static bool Unzip(string path, string outputPath)
{
#if SIMPLSHARP
return CrestronZIP.Unzip(path, outputPath) == CrestronZIP.ResultCode.ZR_OK;
#else
try
{
using (ZipArchive archive = ZipFile.Open(path, ZipArchiveMode.Read))
archive.ExtractToDirectory(outputPath);
}
catch (Exception)
{
return false;
}
return true;
#endif
}
}
}

View File

@@ -0,0 +1,78 @@
using System;
using ICD.Common.Properties;
using Newtonsoft.Json;
namespace ICD.Common.Utils.Json
{
public abstract class AbstractGenericJsonConverter<T> : JsonConverter
{
/// <summary>
/// Writes the JSON representation of the object.
/// </summary>
/// <param name="writer">The <see cref="T:Newtonsoft.Json.JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
/// <param name="serializer">The calling serializer.</param>
public override sealed void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
{
writer.WriteNull();
return;
}
WriteJson(writer, (T)value, serializer);
}
/// <summary>
/// Writes the JSON representation of the object.
/// </summary>
/// <param name="writer">The <see cref="T:Newtonsoft.Json.JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
/// <param name="serializer">The calling serializer.</param>
[PublicAPI]
public abstract void WriteJson(JsonWriter writer, T value, JsonSerializer serializer);
/// <summary>
/// Reads the JSON representation of the object.
/// </summary>
/// <param name="reader">The <see cref="T:Newtonsoft.Json.JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
/// <param name="existingValue">The existing value of object being read.</param>
/// <param name="serializer">The calling serializer.</param>
/// <returns>
/// The object value.
/// </returns>
public override sealed object ReadJson(JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
return ReadJson(reader, (T)existingValue, serializer);
}
/// <summary>
/// Reads the JSON representation of the object.
/// </summary>
/// <param name="reader">The <see cref="T:Newtonsoft.Json.JsonReader"/> to read from.</param>
/// <param name="existingValue">The existing value of object being read.</param>
/// <param name="serializer">The calling serializer.</param>
/// <returns>
/// The object value.
/// </returns>
[PublicAPI]
public abstract T ReadJson(JsonReader reader, T existingValue, JsonSerializer serializer);
/// <summary>
/// Determines whether this instance can convert the specified object type.
/// </summary>
/// <param name="objectType">Type of the object.</param>
/// <returns>
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
/// </returns>
public override bool CanConvert(Type objectType)
{
return objectType == typeof(T);
}
}
}

View File

@@ -0,0 +1,86 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace ICD.Common.Utils.Json
{
/// <summary>
/// Simple wrapper for serialization of an object and its type.
/// </summary>
public sealed class JsonItemWrapper
{
private const string TYPE_TOKEN = "t";
private const string ITEM_TOKEN = "i";
private readonly string m_ItemTypeString;
private readonly object m_Item;
/// <summary>
/// Gets the string representation of the item type. Returns null if the item is null.
/// </summary>
public string ItemTypeString { get { return m_ItemTypeString; } }
/// <summary>
/// Gets the Type of the item. Returns null if the item is null.
/// </summary>
public Type ItemType
{
get { return string.IsNullOrEmpty(m_ItemTypeString) ? null : Type.GetType(m_ItemTypeString); }
}
/// <summary>
/// Gets the wrapped item.
/// </summary>
public object Item { get { return string.IsNullOrEmpty(m_ItemTypeString) ? null : m_Item; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="item"></param>
public JsonItemWrapper(object item)
{
m_ItemTypeString = item == null ? null : item.GetType().FullName;
m_Item = item;
}
/// <summary>
/// Writes the JsonItemWrapper as a JObject.
/// </summary>
/// <param name="writer"></param>
public void Write(JsonWriter writer)
{
if (writer == null)
throw new ArgumentNullException("writer");
writer.WriteStartObject();
writer.WritePropertyName(TYPE_TOKEN);
writer.WriteValue(m_ItemTypeString);
writer.WritePropertyName(ITEM_TOKEN);
writer.WriteValue(JsonConvert.SerializeObject(m_Item));
writer.WriteEndObject();
}
/// <summary>
/// Reads the JToken back to the wrapped object.
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
public static object ReadToObject(JToken token)
{
if (token == null)
throw new ArgumentNullException("token");
string typeString = (string)token.SelectToken(TYPE_TOKEN);
if (string.IsNullOrEmpty(typeString))
return null;
string itemString = (string)token.SelectToken(ITEM_TOKEN);
Type type = Type.GetType(typeString);
return JsonConvert.DeserializeObject(itemString, type);
}
}
}

View File

@@ -0,0 +1,79 @@
using System.Linq;
using System.Text;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.Json
{
/// <summary>
/// Utility methods for working with JSON.
/// </summary>
[PublicAPI]
public static class JsonUtils
{
/// <summary>
/// Pretty-prints the JSON document.
/// </summary>
/// <param name="json"></param>
[PublicAPI]
public static void Print(string json)
{
int indent = 0;
bool quoted = false;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < json.Length; i++)
{
char ch = json[i];
switch (ch)
{
case '{':
case '[':
sb.Append(ch);
if (!quoted)
{
sb.Append(IcdEnvironment.NewLine);
Enumerable.Range(0, ++indent).ForEach(item => sb.Append('\t'));
}
break;
case '}':
case ']':
if (!quoted)
{
sb.Append(IcdEnvironment.NewLine);
Enumerable.Range(0, --indent).ForEach(item => sb.Append('\t'));
}
sb.Append(ch);
break;
case '"':
sb.Append(ch);
bool escaped = false;
int index = i;
while (index > 0 && json[--index] == '\\')
escaped = !escaped;
if (!escaped)
quoted = !quoted;
break;
case ',':
sb.Append(ch);
if (!quoted)
{
sb.Append(IcdEnvironment.NewLine);
Enumerable.Range(0, indent).ForEach(item => sb.Append('\t'));
}
break;
case ':':
sb.Append(ch);
if (!quoted)
sb.Append(" ");
break;
default:
sb.Append(ch);
break;
}
}
IcdConsole.PrintLine(sb.ToString());
}
}
}

View File

@@ -0,0 +1,220 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Utils.Collections;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils
{
/// <summary>
/// Utility methods for math operations.
/// </summary>
public static class MathUtils
{
/// <summary>
/// Clamps the number between the two values.
/// </summary>
/// <param name="number"></param>
/// <param name="min"></param>
/// <param name="max"></param>
/// <returns></returns>
public static int Clamp(int number, int min, int max)
{
return (int)Clamp((double)number, min, max);
}
/// <summary>
/// Clamps the number between the two values.
/// </summary>
/// <param name="number"></param>
/// <param name="min"></param>
/// <param name="max"></param>
/// <returns></returns>
public static ushort Clamp(ushort number, ushort min, ushort max)
{
return (ushort)Clamp((double)number, min, max);
}
/// <summary>
/// Clamps the number between the two values.
/// </summary>
/// <param name="number"></param>
/// <param name="min"></param>
/// <param name="max"></param>
/// <returns></returns>
public static float Clamp(float number, float min, float max)
{
return (float)Clamp((double)number, min, max);
}
/// <summary>
/// Clamps the number between the two values.
/// </summary>
/// <param name="number"></param>
/// <param name="min"></param>
/// <param name="max"></param>
/// <returns></returns>
public static double Clamp(double number, double min, double max)
{
return min < max
? Math.Min(Math.Max(number, min), max)
: Math.Min(Math.Max(number, max), min);
}
/// <summary>
/// Returns the value after the input range has been mapped to a new range
/// </summary>
/// <param name="inputStart">Input start.</param>
/// <param name="inputEnd">Input end.</param>
/// <param name="outputStart">Output start.</param>
/// <param name="outputEnd">Output end.</param>
/// <param name="value">Value.</param>
/// <returns>The newly mapped value</returns>
public static double MapRange(double inputStart, double inputEnd, double outputStart, double outputEnd, double value)
{
double slope = (outputEnd - outputStart) / (inputEnd - inputStart);
return outputStart + slope * (value - inputStart);
}
/// <summary>
/// Returns the value after the input range has been mapped to a new range
/// </summary>
/// <param name="inputStart">Input start.</param>
/// <param name="inputEnd">Input end.</param>
/// <param name="outputStart">Output start.</param>
/// <param name="outputEnd">Output end.</param>
/// <param name="value">Value.</param>
/// <returns>The newly mapped value</returns>
public static float MapRange(float inputStart, float inputEnd, float outputStart, float outputEnd, float value)
{
return (float)MapRange((double)inputStart, inputEnd, outputStart, outputEnd, value);
}
/// <summary>
/// Returns the value after the input range has been mapped to a new range
/// </summary>
/// <param name="inputStart">Input start.</param>
/// <param name="inputEnd">Input end.</param>
/// <param name="outputStart">Output start.</param>
/// <param name="outputEnd">Output end.</param>
/// <param name="value">Value.</param>
/// <returns>The newly mapped value</returns>
public static int MapRange(int inputStart, int inputEnd, int outputStart, int outputEnd, int value)
{
return (int)MapRange((double)inputStart, inputEnd, outputStart, outputEnd, value);
}
/// <summary>
/// Returns the value after the input range has been mapped to a new range
/// </summary>
/// <param name="inputStart">Input start.</param>
/// <param name="inputEnd">Input end.</param>
/// <param name="outputStart">Output start.</param>
/// <param name="outputEnd">Output end.</param>
/// <param name="value">Value.</param>
/// <returns>The newly mapped value</returns>
public static ushort MapRange(ushort inputStart, ushort inputEnd, ushort outputStart, ushort outputEnd, ushort value)
{
return (ushort)MapRange((double)inputStart, inputEnd, outputStart, outputEnd, value);
}
/// <summary>
/// Maps the date in the given range to the float range 0.0f to 1.0f.
/// 0.5f - The date is half way between the end points.
/// less than 0.0f - the date is before the start.
/// greater than 1.0f - the date is after the end.
/// </summary>
/// <param name="start"></param>
/// <param name="end"></param>
/// <param name="value"></param>
/// <returns></returns>
public static double MapRange(DateTime start, DateTime end, DateTime value)
{
return MapRange(new TimeSpan(start.Ticks).TotalSeconds,
new TimeSpan(end.Ticks).TotalSeconds,
0.0f, 1.0f, new TimeSpan(value.Ticks).TotalSeconds);
}
/// <summary>
/// Gets the digit count for the given number.
/// </summary>
/// <param name="number"></param>
/// <returns></returns>
public static int GetNumberOfDigits(int number)
{
int output = number.ToString().Length;
if (number < 0)
output--;
return output;
}
/// <summary>
/// Gets the digit count for the given number.
/// </summary>
/// <param name="number"></param>
/// <returns></returns>
public static int GetNumberOfDigits(uint number)
{
return number.ToString().Length;
}
/// <summary>
/// Takes a sequence of numbers:
/// 1, 3, 5, 6, 7, 8, 9, 10, 12
/// And calculates the continuous ranges:
/// (1, 1), (3, 3), (5, 10), (12, 12)
/// </summary>
public static IEnumerable<int[]> GetRanges(IEnumerable<int> numbers)
{
if (numbers == null)
throw new ArgumentNullException("numbers");
int[] currentRange = null;
foreach (int number in numbers.Order())
{
if (currentRange == null)
currentRange = new[] {number, number};
else if (currentRange[1] == number - 1)
currentRange = new[] {currentRange[0], number};
else
{
yield return currentRange;
currentRange = new[] {number, number};
}
}
if (currentRange != null)
yield return currentRange;
}
/// <summary>
/// Rounds the given number to the nearest item in the given sequence.
/// </summary>
/// <param name="number"></param>
/// <param name="nearest"></param>
/// <returns></returns>
public static int RoundToNearest(int number, IEnumerable<int> nearest)
{
if (nearest == null)
throw new ArgumentNullException("nearest");
return nearest.Aggregate((x, y) => Math.Abs(x - number) < Math.Abs(y - number) ? x : y);
}
/// <summary>
/// Gets a new, unique id given a sequence of existing ids.
/// </summary>
/// <param name="existingIds"></param>
/// <returns></returns>
public static int GetNewId(IEnumerable<int> existingIds)
{
if (existingIds == null)
throw new ArgumentNullException("existingIds");
IcdHashSet<int> existing = existingIds.ToHashSet();
return Enumerable.Range(1, int.MaxValue).First(i => !existing.Contains(i));
}
}
}

View File

@@ -0,0 +1,232 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Services;
using ICD.Common.Services.Logging;
using ICD.Common.Utils.Extensions;
using ICD.Common.Utils.IO;
namespace ICD.Common.Utils
{
/// <summary>
/// Provides util methods for working with file/directory paths.
/// </summary>
public static class PathUtils
{
#region Properties
/// <summary>
/// Gets the path to the root directory of the processor.
/// </summary>
[PublicAPI]
public static string RootPath { get { return IcdDirectory.GetDirectoryRoot("\\"); } }
/// <summary>
/// Gets the path to the NVRAM directory.
/// </summary>
[PublicAPI]
public static string NvramPath { get { return Join(RootPath, "NVRAM"); } }
/// <summary>
/// Returns the absolute path to the configuration directory.
/// </summary>
/// <value></value>
[PublicAPI]
public static string ProgramConfigPath
{
get
{
string directoryName = string.Format("Program{0:D2}Config", ProgramUtils.ProgramNumber);
return Join(NvramPath, directoryName);
}
}
/// <summary>
/// Returns the absolute path to the common configuration directory.
/// </summary>
[PublicAPI]
public static string CommonConfigPath { get { return Join(NvramPath, "CommonConfig"); } }
/// <summary>
/// Returns the absolute path to the common config library directory.
/// </summary>
[PublicAPI]
public static string CommonLibPath { get { return Join(CommonConfigPath, "Lib"); } }
/// <summary>
/// Returns the absolute path to the program config library directory.
/// </summary>
[PublicAPI]
public static string ProgramLibPath { get { return Join(ProgramConfigPath, "Lib"); } }
#endregion
#region Methods
/// <summary>
/// Creates a path from the given path nodes.
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
public static string Join(params string[] items)
{
try
{
return items.Skip(1).Aggregate(items.First(), IcdPath.Combine);
}
catch (ArgumentException e)
{
throw new ArgumentException("Failed to join path: " + StringUtils.ArrayFormat(items), e);
}
}
/// <summary>
/// Gets the full path for the given path.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static string GetFullPath(string path)
{
return Join(IcdDirectory.GetApplicationDirectory(), path);
}
/// <summary>
/// Replaces the filename while leaving the directory and extension intact.
/// </summary>
/// <param name="path"></param>
/// <param name="newName"></param>
/// <returns></returns>
public static string ChangeFilenameWithoutExt(string path, string newName)
{
string dir = IcdPath.GetDirectoryName(path);
string ext = IcdPath.GetExtension(path);
return Join(dir, newName + ext);
}
/// <summary>
/// Removes the extension from the given path.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static string GetPathWithoutExtension(string path)
{
string dir = IcdPath.GetDirectoryName(path);
string filename = IcdPath.GetFileNameWithoutExtension(path);
return Join(dir, filename);
}
/// <summary>
/// Recurses over the file paths at the given directory.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static IEnumerable<string> RecurseFilePaths(string path)
{
if (!IcdDirectory.Exists(path))
yield break;
Queue<string> queue = new Queue<string>();
queue.Enqueue(path);
while (queue.Count > 0)
{
path = queue.Dequeue();
// Get the subdirectories
try
{
foreach (string subDir in IcdDirectory.GetDirectories(path))
queue.Enqueue(subDir);
}
catch (Exception e)
{
ServiceProvider.TryGetService<ILoggerService>().AddEntry(eSeverity.Error, e, e.Message);
}
// Get the files
string[] files;
try
{
files = IcdDirectory.GetFiles(path);
}
catch (Exception e)
{
ServiceProvider.TryGetService<ILoggerService>().AddEntry(eSeverity.Error, e, e.Message);
continue;
}
foreach (string filePath in files)
yield return filePath;
}
}
/// <summary>
/// Searches the program config path, common config path, and application path to
/// find the first config that exists with the given local path.
/// </summary>
/// <param name="localPath"></param>
/// <returns></returns>
public static string GetDefaultConfigPath(params string[] localPath)
{
string local = Join(localPath);
// Program slot configuration
string programPath = Join(ProgramConfigPath, local);
if (PathExists(programPath))
return programPath;
// Common program configuration
string commonPath = Join(CommonConfigPath, local);
return PathExists(commonPath)
? commonPath
: Join(IcdDirectory.GetApplicationDirectory(), local); // Installation defaults
}
/// <summary>
/// Appends the local path to the program config path.
/// </summary>
/// <returns></returns>
public static string GetProgramConfigPath(params string[] localPath)
{
string local = Join(localPath);
return Join(ProgramConfigPath, local);
}
/// <summary>
/// Searches the application path, program config path and common config path to
/// find the first IR driver that exists with the given local path.
/// </summary>
/// <param name="localPath"></param>
/// <returns></returns>
public static string GetIrDriversPath(params string[] localPath)
{
return GetDefaultConfigPath(localPath.Prepend("IRDrivers").ToArray());
}
/// <summary>
/// Searches the application path, program config path and common config path to
/// find the first SSL Driver that exists with the given local path.
/// </summary>
/// <param name="localPath"></param>
/// <returns></returns>
public static string GetSslCertificatesPath(params string[] localPath)
{
return GetDefaultConfigPath(localPath.Prepend("SSLCertificates").ToArray());
}
/// <summary>
/// Returns true if the given path exists.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static bool PathExists(string path)
{
return IcdFile.Exists(path) || IcdDirectory.Exists(path);
}
#endregion
}
}

View File

@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Text;
using ICD.Common.Properties;
namespace ICD.Common.Utils
{
/// <summary>
/// Utils for printing various data types in human readable structures.
/// </summary>
public static class PrettyPrint
{
#region Methods
[PublicAPI]
public static void PrintLine<TKey, TValue>(IDictionary<TKey, TValue> dictionary)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
IcdConsole.PrintLine(ToString(dictionary));
}
[PublicAPI]
public static void PrintLine<T>(IEnumerable<T> sequence)
{
if (sequence == null)
throw new ArgumentNullException("sequence");
IcdConsole.PrintLine(ToString(sequence));
}
[PublicAPI]
public static string ToString<TKey, TValue>(IDictionary<TKey, TValue> dictionary)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
StringBuilder builder = new StringBuilder();
builder.AppendLine("{");
foreach (KeyValuePair<TKey, TValue> kvp in dictionary)
{
builder.Append('\t');
builder.Append(ToString(kvp.Key));
builder.Append(" : ");
builder.Append(ToString(kvp.Value));
builder.Append(',');
builder.AppendLine();
}
builder.Append("}");
return builder.ToString();
}
[PublicAPI]
public static string ToString<T>(IEnumerable<T> sequence)
{
if (sequence == null)
throw new ArgumentNullException("sequence");
StringBuilder builder = new StringBuilder();
builder.AppendLine("[");
foreach (T item in sequence)
{
builder.Append('\t');
builder.Append(ToString(item));
builder.Append(',');
builder.AppendLine();
}
builder.Append("]");
return builder.ToString();
}
[PublicAPI]
public static string ToString<T>(T value)
{
// ReSharper disable once CompareNonConstrainedGenericWithNull
return StringUtils.ToRepresentation(value == null ? null : value.ToString());
}
#endregion
}
}

View File

@@ -0,0 +1,178 @@
using System;
using System.Collections.Generic;
using System.Linq;
#if SIMPLSHARP
using Crestron.SimplSharp;
#endif
using ICD.Common.Properties;
using ICD.Common.Services;
using ICD.Common.Services.Logging;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils
{
public static class ProgramUtils
{
private const string APPLICATION_NAME_KEY = "Application Name";
private const string APPLICATION_NAME_SIMPL_KEY = "System Name";
private const string PROGRAM_FILE_KEY = "Program File";
private const string COMPILED_ON_KEY = "Compiled On";
private const string COMPILER_REVISION_KEY = "Compiler Revision";
private const string COMPILER_REVISION_SIMPL_KEY = "Compiler Rev";
private static Dictionary<string, string> s_ProgComments;
#region Properties
/// <summary>
/// Lazy-load the prog-comments map.
/// </summary>
private static Dictionary<string, string> ProgComments
{
get { return s_ProgComments ?? (s_ProgComments = ParseProgComments()); }
}
/// <summary>
/// Gets the program number.
/// </summary>
[PublicAPI]
public static uint ProgramNumber
{
get
{
#if SIMPLSHARP
return InitialParametersClass.ApplicationNumber;
#else
return 1;
#endif
}
}
/// <summary>
/// Gets the program number in the format XX, eg slot 1 is 01.
/// </summary>
[PublicAPI]
public static string ProgramNumberFormatted { get { return string.Format("{0:D2}", ProgramNumber); } }
/// <summary>
/// Gets the compile date of the program.
/// </summary>
[PublicAPI]
public static string CompiledDate { get { return ProgComments.GetDefault(COMPILED_ON_KEY, null); } }
/// <summary>
/// Gets the compiler revision version.
/// </summary>
[PublicAPI]
public static Version CompilerRevision
{
get
{
string output;
if (ProgComments.TryGetValue(COMPILER_REVISION_KEY, out output))
return new Version(output);
if (ProgComments.TryGetValue(COMPILER_REVISION_SIMPL_KEY, out output))
return new Version(output);
return new Version(0, 0);
}
}
/// <summary>
/// Gets the name of the program dll.
/// </summary>
[PublicAPI]
public static string ProgramFile { get { return ProgComments.GetDefault(PROGRAM_FILE_KEY, null); } }
/// <summary>
/// Gets the name of the application.
/// </summary>
[PublicAPI]
public static string ApplicationName
{
get
{
string output;
if (ProgComments.TryGetValue(APPLICATION_NAME_KEY, out output))
return output;
ProgComments.TryGetValue(APPLICATION_NAME_SIMPL_KEY, out output);
return output;
}
}
#endregion
/// <summary>
/// Fakes program info, e.g. "Min Firmware Version : 1.009.0029"
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
[PublicAPI]
public static void PrintProgramInfoLine(string name, object value)
{
name = (name ?? string.Empty).Trim();
switch (IcdEnvironment.RuntimeEnvironment)
{
case IcdEnvironment.eRuntimeEnvironment.SimplSharp:
int length = Math.Min(13, name.Length);
name = name.Substring(0, length).PadRight(13);
break;
case IcdEnvironment.eRuntimeEnvironment.SimplSharpPro:
int proLength = Math.Min(26 - 1, name.Length);
name = name.Substring(0, proLength).PadRight(26);
break;
case IcdEnvironment.eRuntimeEnvironment.Standard:
name += ' ';
break;
default:
throw new ArgumentOutOfRangeException();
}
IcdConsole.PrintLine("{0}: {1}", name, value);
}
/// <summary>
/// Parses the prog comments and pulls program information.
/// </summary>
private static Dictionary<string, string> ParseProgComments()
{
Dictionary<string, string> output = new Dictionary<string, string>();
try
{
string progInfo = string.Empty;
string command = string.Format("progcomments:{0}", ProgramNumber);
if (!IcdConsole.SendControlSystemCommand(command, ref progInfo))
{
ServiceProvider.TryGetService<ILoggerService>().AddEntry(eSeverity.Warning, "Failed to parse prog comments");
return output;
}
foreach (string line in progInfo.Split(new[] {"\n\r", "\r\n", "\n", "\r"}))
{
string[] pair = line.Split(':', 2).ToArray();
string key = pair[0].Trim();
string value = pair[1].Trim();
output[key] = value;
}
}
catch (Exception e)
{
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Error, e, "Failed to parse prog comments - {0}", e.Message);
}
return output;
}
}
}

View File

@@ -0,0 +1,232 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
#if SIMPLSHARP
using Crestron.SimplSharp.Reflection;
using Activator = Crestron.SimplSharp.Reflection.Activator;
#else
using System.IO;
using System.Reflection;
using Microsoft.Extensions.DependencyModel;
using System.Runtime.Loader;
using Activator = System.Activator;
#endif
namespace ICD.Common.Utils
{
public static class ReflectionUtils
{
/// <summary>
/// Instantiates the given type using the constructor matching the given values.
/// </summary>
/// <param name="type"></param>
/// <param name="values"></param>
/// <returns></returns>
[PublicAPI]
public static object Instantiate(Type type, params object[] values)
{
if (type == null)
throw new ArgumentNullException("type");
#if SIMPLSHARP
CType[] types = values.Select(v => (CType)v.GetType())
.ToArray();
ConstructorInfo constructor = ((CType)type).GetConstructor(types);
#else
Type[] types = values.Select(v => v.GetType())
.ToArray();
ConstructorInfo constructor = type.GetTypeInfo().GetConstructor(types);
#endif
if (constructor != null)
return constructor.Invoke(values);
string message = string.Format("Unable to find constructor for {0}", type.Name);
throw new InvalidOperationException(message);
}
/// <summary>
/// Returns true if the parameters match the method parameters.
/// </summary>
/// <param name="method"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public static bool MatchesMethodParameters(MethodBase method, IEnumerable<object> parameters)
{
if (method == null)
throw new ArgumentNullException("method");
if (parameters == null)
throw new ArgumentNullException("parameters");
#if SIMPLSHARP
CType[] methodTypes
#else
Type[] methodTypes
#endif
= method.GetParameters().Select(p => p.ParameterType).ToArray();
return ParametersMatchTypes(methodTypes, parameters);
}
/// <summary>
/// Returns true if the if the parameter match the property parameter.
/// </summary>
/// <param name="property"></param>
/// <param name="parameter"></param>
/// <returns></returns>
public static bool MatchesPropertyParameter(PropertyInfo property, object parameter)
{
if (property == null)
throw new ArgumentNullException("property");
#if SIMPLSHARP
CType propertyType
#else
Type propertyType
#endif
= property.PropertyType;
return ParametersMatchTypes(new[] {propertyType}, new[] {parameter});
}
/// <summary>
/// Returns true if the parameters array is compatible with the given property types array.
/// </summary>
/// <param name="types"></param>
/// <param name="parameters"></param>
/// <returns></returns>
#if SIMPLSHARP
private static bool ParametersMatchTypes(IEnumerable<CType> types, IEnumerable<object> parameters)
{
if (types == null)
throw new ArgumentNullException("types");
CType[] typesArray = types as CType[] ?? types.ToArray();
#else
private static bool ParametersMatchTypes(IEnumerable<Type> types, IEnumerable<object> parameters)
{
if (types == null)
throw new ArgumentNullException("types");
Type[] typesArray = types as Type[] ?? types.ToArray();
#endif
if (parameters == null)
throw new ArgumentNullException("parameters");
object[] parametersArray = parameters as object[] ?? parameters.ToArray();
if (parametersArray.Length != typesArray.Length)
return false;
// Compares each pair of items in the two arrays.
return !parametersArray.Where((t, index) => !ParameterMatchesType(typesArray[index], t)).Any();
}
/// <summary>
/// Returns true if the parameter can be assigned to the given type.
/// </summary>
/// <param name="type"></param>
/// <param name="parameter"></param>
/// <returns></returns>
#if SIMPLSHARP
private static bool ParameterMatchesType(CType type, object parameter)
{
if (type == null)
throw new ArgumentNullException("type");
// Can the parameter be assigned a null value?
if (parameter == null)
return (type.IsClass || !type.IsValueType || Nullable.GetUnderlyingType(type) != null);
return type.IsInstanceOfType(parameter);
}
#else
private static bool ParameterMatchesType(Type type, object parameter)
{
if (type == null)
throw new ArgumentNullException("type");
TypeInfo info = type.GetTypeInfo();
// Can the parameter be assigned a null value?
if (parameter == null)
return (info.IsClass || !info.IsValueType || Nullable.GetUnderlyingType(type) != null);
return info.IsInstanceOfType(parameter);
}
#endif
/// <summary>
/// Same as doing default(Type).
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
#if SIMPLSHARP
public static object GetDefaultValue(CType type)
#else
public static object GetDefaultValue(Type type)
#endif
{
if (type == null)
throw new ArgumentNullException("type");
return type
#if !SIMPLSHARP
.GetTypeInfo()
#endif
.IsValueType
? Activator.CreateInstance(type)
: null;
}
/// <summary>
/// Creates an instance of the given type, calling the default constructor.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T CreateInstance<T>()
where T : new()
{
return Activator.CreateInstance<T>();
}
/// <summary>
/// Gets the custom attributes added to the given assembly.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="assembly"></param>
/// <returns></returns>
public static IEnumerable<object> GetCustomAttributes<T>(Assembly assembly)
where T : Attribute
{
if (assembly == null)
throw new ArgumentNullException("assembly");
#if SIMPLSHARP
return assembly.GetCustomAttributes(typeof(T), false);
#else
return assembly.GetCustomAttributes<T>();
#endif
}
/// <summary>
/// Loads the assembly at the given path.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static Assembly LoadAssemblyFromPath(string path)
{
#if SIMPLSHARP
return Assembly.LoadFrom(path);
#else
string fileNameWithOutExtension = Path.GetFileNameWithoutExtension(path);
bool inCompileLibraries = DependencyContext.Default.CompileLibraries.Any(l => l.Name.Equals(fileNameWithOutExtension, StringComparison.OrdinalIgnoreCase));
bool inRuntimeLibraries = DependencyContext.Default.RuntimeLibraries.Any(l => l.Name.Equals(fileNameWithOutExtension, StringComparison.OrdinalIgnoreCase));
return inCompileLibraries || inRuntimeLibraries
? Assembly.Load(new AssemblyName(fileNameWithOutExtension))
: AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
#endif
}
}
}

View File

@@ -0,0 +1,65 @@
#if SIMPLSHARP
using Crestron.SimplSharp;
namespace ICD.Common.Utils
{
/// <summary>
/// CCriticalSection tends to get disposed before the parent is done with it.
/// This class is an attempt to gracefully handle the ObjectDisposedExceptions we see on
/// program termination, ocassionally causing the program to restart instead of stop.
/// </summary>
public sealed partial class SafeCriticalSection
{
private readonly CCriticalSection m_CriticalSection;
/// <summary>
/// Constructor.
/// </summary>
public SafeCriticalSection()
{
m_CriticalSection = new CCriticalSection();
}
#region Methods
/// <summary>
/// Block until ownership of the critical section can be obtained.
/// </summary>
public void Enter()
{
if (m_CriticalSection == null || m_CriticalSection.Disposed)
return;
m_CriticalSection.Enter();
}
/// <summary>
/// Release ownership of the critical section.
/// </summary>
public void Leave()
{
if (m_CriticalSection == null || m_CriticalSection.Disposed)
return;
m_CriticalSection.Leave();
}
/// <summary>
/// Attempt to enter the critical section without blocking.
/// </summary>
/// <returns>
/// True, calling thread has ownership of the critical section; otherwise, false.
/// </returns>
public bool TryEnter()
{
if (m_CriticalSection == null || m_CriticalSection.Disposed)
return false;
return m_CriticalSection.TryEnter();
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,51 @@
#if !SIMPLSHARP
using System.Threading;
namespace ICD.Common.Utils
{
public sealed partial class SafeCriticalSection
{
private readonly Mutex m_Mutex;
/// <summary>
/// Constructor.
/// </summary>
public SafeCriticalSection()
{
m_Mutex = new Mutex();
}
#region Methods
/// <summary>
/// Block until ownership of the critical section can be obtained.
/// </summary>
public void Enter()
{
m_Mutex.WaitOne();
}
/// <summary>
/// Release ownership of the critical section.
/// </summary>
public void Leave()
{
m_Mutex.ReleaseMutex();
}
/// <summary>
/// Attempt to enter the critical section without blocking.
/// </summary>
/// <returns>
/// True, calling thread has ownership of the critical section; otherwise, false.
/// </returns>
public bool TryEnter()
{
return m_Mutex.WaitOne(0);
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,49 @@
using System;
namespace ICD.Common.Utils
{
public sealed partial class SafeCriticalSection
{
/// <summary>
/// Enters the critical section, executes the callback and leaves the section.
/// </summary>
/// <param name="callback"></param>
public void Execute(Action callback)
{
if (callback == null)
throw new ArgumentNullException("callback");
try
{
Enter();
callback();
}
finally
{
Leave();
}
}
/// <summary>
/// Enters the critical section, executes the callback and leaves the section.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="callback"></param>
/// <returns></returns>
public T Execute<T>(Func<T> callback)
{
if (callback == null)
throw new ArgumentNullException("callback");
try
{
Enter();
return callback();
}
finally
{
Leave();
}
}
}
}

View File

@@ -0,0 +1,74 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp;
#else
using System.Threading;
#endif
namespace ICD.Common.Utils
{
/// <summary>
/// Like the CCriticalSection, the CMutex tends to get disposed before the parent is
/// done with it. This class is an attempt to gracefully handle the ObjectDisposedExceptions
/// we see on program termination, ocassionally causing the program to restart instead of stop.
/// </summary>
public sealed class SafeMutex
{
#if SIMPLSHARP
private readonly CMutex m_Mutex;
#else
private readonly Mutex m_Mutex;
#endif
/// <summary>
/// Constructor.
/// </summary>
public SafeMutex()
{
#if SIMPLSHARP
m_Mutex = new CMutex();
#else
m_Mutex = new Mutex();
#endif
}
#region Methods
/// <summary>
/// Waits the given number of milliseconds to aquire the mutex.
/// </summary>
/// <param name="timeout"></param>
/// <returns>True if the mutex was aquired.</returns>
public bool WaitForMutex(int timeout)
{
try
{
#if SIMPLSHARP
return m_Mutex.WaitForMutex(timeout);
#else
return m_Mutex.WaitOne(timeout);
#endif
}
catch (ObjectDisposedException)
{
return false;
}
}
/// <summary>
/// Releases the mutex.
/// </summary>
public void ReleaseMutex()
{
try
{
m_Mutex.ReleaseMutex();
}
catch (ObjectDisposedException)
{
}
}
#endregion
}
}

View File

@@ -0,0 +1,477 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils
{
public static class StringUtils
{
private const ushort ASCII_READABLE_START = 32;
private const ushort ASCII_READABLE_END = 126;
/// <summary>
/// Returns the number as a string in the format "\\x00"
/// </summary>
/// <param name="numeric"></param>
/// <returns></returns>
[PublicAPI]
public static string ToHexLiteral(int numeric)
{
return string.Format("\\x{0:X2}", numeric);
}
/// <summary>
/// Returns the character as a string in the format "\\x00"
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
[PublicAPI]
public static string ToHexLiteral(char c)
{
return ToHexLiteral(Convert.ToInt32(c));
}
/// <summary>
/// Returns a string as a string in the format "\\x00\\x00..."
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[PublicAPI]
public static string ToHexLiteral(string input)
{
string[] strings = input.Select(c => ToHexLiteral(c)).ToArray();
return string.Join("", strings);
}
/// <summary>
/// Converts a character in the string format "\\x00" to char.
/// </summary>
/// <param name="character"></param>
/// <returns></returns>
[PublicAPI]
public static char FromHexLiteralCharacter(string character)
{
string hexValue = character.Substring(2);
return (char)Convert.ToByte(hexValue, 16);
}
/// <summary>
/// Converts a string in the format "\\x00\\x00..." to hex representation.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
[PublicAPI]
public static string FromHexLiteral(string data)
{
return string.Join("", data.Split(4).Select(s => FromHexLiteralCharacter(s).ToString()).ToArray());
}
/// <summary>
/// Converts the char to a human readable character, otherwise returns a hex string
/// in the format "\x00"
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
[PublicAPI]
public static string ToMixedReadableHexLiteral(char c)
{
int numeric = Convert.ToInt32(c);
if (numeric >= ASCII_READABLE_START && numeric <= ASCII_READABLE_END)
return c.ToString();
return ToHexLiteral(c);
}
/// <summary>
/// Converts the input string to a string in the format "\x00\x00" with human
/// readable characters where possible e.g. "Hello World!x\0D"
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[PublicAPI]
public static string ToMixedReadableHexLiteral(string input)
{
string[] strings = input.Select(c => ToMixedReadableHexLiteral(c)).ToArray();
return string.Join("", strings);
}
/// <summary>
/// Converts bytes to an ascii string.
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
[PublicAPI]
public static string ToString(IEnumerable<byte> bytes)
{
byte[] cast = bytes as byte[] ?? bytes.ToArray();
return Encoding.UTF8.GetString(cast, 0, cast.Length);
}
/// <summary>
/// Converts bytes to an ascii string.
/// </summary>
/// <param name="bytes"></param>
/// <param name="length"></param>
/// <returns></returns>
[PublicAPI]
public static string ToString(IEnumerable<byte> bytes, int length)
{
byte[] cast = bytes as byte[] ?? bytes.ToArray();
return Encoding.UTF8.GetString(cast, 0, length);
}
/// <summary>
/// Converts an ascii string to bytes.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[PublicAPI]
public static byte[] ToBytes(string input)
{
return Encoding.UTF8.GetBytes(input);
}
/// <summary>
/// Attempts to parse the string as an integer.
/// </summary>
/// <param name="value"></param>
/// <param name="result"></param>
/// <returns></returns>
[PublicAPI]
public static bool TryParse(string value, out int result)
{
return TryConvert(Convert.ToInt32, value, out result);
}
/// <summary>
/// Attempts to parse the string as an unsigned integer.
/// </summary>
/// <param name="value"></param>
/// <param name="result"></param>
/// <returns></returns>
[PublicAPI]
public static bool TryParse(string value, out uint result)
{
return TryConvert(Convert.ToUInt32, value, out result);
}
/// <summary>
/// Attempts to parse the string as a float.
/// </summary>
/// <param name="value"></param>
/// <param name="result"></param>
/// <returns></returns>
[PublicAPI]
public static bool TryParse(string value, out float result)
{
return TryConvert(Convert.ToSingle, value, out result);
}
/// <summary>
/// Attempts to parse the string as a bool.
/// </summary>
/// <param name="value"></param>
/// <param name="result"></param>
/// <returns></returns>
[PublicAPI]
public static bool TryParse(string value, out bool result)
{
return TryConvert(Convert.ToBoolean, value, out result);
}
/// <summary>
/// Attempts to parse the string via the given conversion function.
/// </summary>
/// <param name="convertFunc"></param>
/// <param name="value"></param>
/// <param name="result"></param>
/// <returns></returns>
private static bool TryConvert<T>(Func<string, T> convertFunc, string value, out T result)
{
if (convertFunc == null)
throw new ArgumentNullException("convertFunc");
result = default(T);
bool retVal = false;
try
{
result = convertFunc(value);
retVal = true;
}
catch (FormatException)
{
}
catch (InvalidCastException)
{
}
return retVal;
}
/// <summary>
/// Returns the object.ToString() with spaces before capital letters.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static string NiceName(object obj)
{
return NiceName(obj.ToString());
}
/// <summary>
/// Inserts spaces before capital letters.
///
/// http://stackoverflow.com/questions/4488969/split-a-string-by-capital-letters
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public static string NiceName(string name)
{
Regex regex = new Regex(@"
(?<=[A-Z])(?=[A-Z][a-z]) |
(?<=[^A-Z])(?=[A-Z]) |
(?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace);
return regex.Replace(name, " ");
}
/// <summary>
/// String.Format({0:######}) is unreliable if the number starts with a 0.
/// This method fills an input pattern #### from right to left with characters
/// from the number.
/// </summary>
/// <param name="phoneFormat"></param>
/// <param name="number"></param>
/// <returns></returns>
public static string SafeNumericFormat(string phoneFormat, string number)
{
phoneFormat = Reverse(phoneFormat);
number = Reverse(number);
StringBuilder builder = new StringBuilder();
int index = 0;
foreach (char c in phoneFormat)
{
if (index >= number.Length)
{
if (c == '#')
break;
builder.Append(c);
continue;
}
if (c == '#')
{
builder.Append(number[index]);
index++;
}
else
builder.Append(c);
}
return Reverse(builder.ToString()).TrimStart();
}
/// <summary>
/// Reverses the string.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[PublicAPI]
public static string Reverse(string input)
{
char[] charArray = input.ToCharArray();
Array.Reverse(charArray);
return new string(charArray);
}
/// <summary>
/// Repeats the char the given number of times.
/// </summary>
/// <param name="input"></param>
/// <param name="count"></param>
/// <returns></returns>
public static string Repeat(char input, int count)
{
return Repeat(input.ToString(), count);
}
/// <summary>
/// Repeats the string the given number of times.
/// </summary>
/// <param name="input"></param>
/// <param name="count"></param>
/// <returns></returns>
[PublicAPI]
public static string Repeat(string input, int count)
{
return count == 0 ? string.Empty : new StringBuilder().Insert(0, input, count).ToString();
}
/// <summary>
/// Returns each item.ToString() in the format "[item1, item2, item3...]"
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
[PublicAPI]
public static string ArrayFormat<T>(IEnumerable<T> items)
{
if (items == null)
throw new ArgumentNullException("items");
return string.Format("[{0}]", string.Join(", ", items.Select(i => i.ToString()).ToArray()));
}
/// <summary>
/// Given a sequence of numbers, generates a human readable list of numeric ranges.
/// E.g. [1, 2, 3, 5, 6] becomes "[1-3, 5-6]".
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
[PublicAPI]
public static string ArrayRangeFormat(IEnumerable<int> items)
{
if (items == null)
throw new ArgumentNullException("items");
string[] ranges = MathUtils.GetRanges(items)
.Select(r => r[0] == r[1]
? r[0].ToString()
: string.Format("{0}-{1}", r[0], r[1]))
.ToArray();
return ArrayFormat(ranges);
}
/// <summary>
/// Given a sequence of numbers, generates a human readable list of numeric ranges.
/// E.g. [1, 2, 3, 5, 6] becomes "[1-3, 5-6]".
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
[PublicAPI]
public static string ArrayRangeFormat(IEnumerable<ushort> items)
{
if (items == null)
throw new ArgumentNullException("items");
return ArrayRangeFormat(items.Select(i => (int)i));
}
/// <summary>
/// Returns a pair of numbers in the format [a - b]
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
[PublicAPI]
public static string RangeFormat(object a, object b)
{
return string.Format("[{0} - {1}]", a, b);
}
/// <summary>
/// Capitalizes the first character of the string.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[PublicAPI]
public static string UppercaseFirst(string input)
{
if (string.IsNullOrEmpty(input))
return input;
return char.ToUpper(input[0]) + input.Substring(1);
}
/// <summary>
/// Formats an IPID to "0xFF"
/// </summary>
/// <param name="ipid"></param>
/// <returns></returns>
public static string ToIpIdString(byte ipid)
{
return string.Format("0x{0:X2}", ipid);
}
/// <summary>
/// Formats "0xFF" to an IPID.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static byte FromIpIdString(string value)
{
value = value.Replace("0x", "");
return Convert.ToByte(value, 16);
}
/// <summary>
/// Removes all whitespace from the string.
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public static string RemoveWhitespace(string text)
{
return text == null ? null : new string(text.Where(c => !Char.IsWhiteSpace(c)).ToArray());
}
/// <summary>
/// Returns the password as a series of *s
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
public static string PasswordFormat(string password)
{
return password == null ? null : Repeat('*', password.Length);
}
/// <summary>
/// Pads the given string with quotations for readable type clarity. If the string is null, returns "NULL".
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static string ToRepresentation(string value)
{
return value == null ? "NULL" : string.Format("\"{0}\"", value);
}
/// <summary>
/// Returns the items in the format "x, y, and z"
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
public static string SerialComma(IEnumerable<string> items)
{
if (items == null)
throw new ArgumentNullException("items");
string previous = null;
StringBuilder builder = new StringBuilder();
foreach (string item in items)
{
if (previous != null)
builder.AppendFormat("{0}, ", previous);
previous = item;
}
if (previous != null)
{
if (builder.Length > 0)
builder.AppendFormat("and {0}", previous);
else
builder.Append(previous);
}
return builder.ToString();
}
}
}

View File

@@ -0,0 +1,193 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils
{
/// <summary>
/// TableBuilder provides a way to format a collection of strings to a table.
/// </summary>
public sealed class TableBuilder
{
private const char HORIZONTAL = '-';
private const char VERTICAL = '|';
private readonly List<string[]> m_Rows;
private readonly SafeCriticalSection m_RowsSection;
private readonly string[] m_Columns;
/// <summary>
/// Gets the columns.
/// </summary>
[PublicAPI]
public string[] Columns { get { return m_Columns; } }
/// <summary>
/// Gets the number of columns.
/// </summary>
[PublicAPI]
public int ColumnsCount { get { return m_Columns.Length; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="columns"></param>
public TableBuilder(params string[] columns)
{
m_Rows = new List<string[]>();
m_RowsSection = new SafeCriticalSection();
m_Columns = columns;
}
#region Methods
/// <summary>
/// Clears all of the rows.
/// </summary>
[PublicAPI]
public void ClearRows()
{
m_RowsSection.Execute(() => m_Rows.Clear());
}
/// <summary>
/// Calls ToString() for each item and adds the row to the builder.
/// </summary>
/// <param name="row"></param>
[PublicAPI]
public void AddRow(params object[] row)
{
string[] stringRow = row.Select(o => string.Format("{0}", o))
.ToArray();
AddRow(stringRow);
}
/// <summary>
/// Adds the row to the builder.
/// </summary>
/// <param name="row"></param>
[PublicAPI]
public void AddRow(params string[] row)
{
if (row != null && row.Length != m_Columns.Length)
throw new ArgumentException("Row must match columns length.");
m_RowsSection.Execute(() => m_Rows.Add(row));
}
/// <summary>
/// Adds an empty row to the builder.
/// </summary>
[PublicAPI]
public void AddEmptyRow()
{
AddRow(new string[m_Columns.Length]);
}
[PublicAPI]
public void AddSeparator()
{
AddRow(null);
}
[PublicAPI]
public void AddHeader(params string[] row)
{
if (row.Length != m_Columns.Length)
throw new ArgumentException("Row must match columns length.");
AddSeparator();
AddRow(row);
AddSeparator();
}
/// <summary>
/// Gets the output string.
/// </summary>
public override string ToString()
{
StringBuilder sb = new StringBuilder();
m_RowsSection.Enter();
try
{
int[] columnWidths = GetColumnWidths();
AppendRow(sb, m_Columns, columnWidths);
AppendSeparator(sb, columnWidths);
foreach (string[] row in m_Rows)
{
if (row == null)
AppendSeparator(sb, columnWidths);
else
AppendRow(sb, row, columnWidths);
}
AppendSeparator(sb, columnWidths);
}
finally
{
m_RowsSection.Leave();
}
return sb.ToString();
}
#endregion
#region Private Methods
private int[] GetColumnWidths()
{
int[] columnWidths = new int[m_Columns.Length];
for (int index = 0; index < m_Columns.Length; index++)
columnWidths[index] = GetColumnWidth(index);
return columnWidths;
}
private int GetColumnWidth(int index)
{
int titleLength = m_Columns[index].Length + 1;
if (m_Rows.Count == 0)
return titleLength;
int maxColumnWidth = m_Rows.Except((string[])null)
.Max(x => x[index] != null ? x[index].Length : 0) + 1;
return (titleLength > maxColumnWidth) ? titleLength : maxColumnWidth;
}
private static void AppendRow(StringBuilder builder, IList<string> row, IList<int> columnWidths)
{
for (int index = 0; index < row.Count; index++)
{
if (index > 0)
builder.Append(' ');
string value = row[index] ?? string.Empty;
builder.Append(value.PadRight(columnWidths[index]));
if (index < row.Count - 1)
builder.Append(VERTICAL);
}
builder.AppendLine();
}
private static void AppendSeparator(StringBuilder sb, ICollection<int> columnWidths)
{
int length = columnWidths.Sum() + (columnWidths.Count - 1) * 2;
string line = new string(HORIZONTAL, length);
sb.AppendLine(line);
}
#endregion
}
}

View File

@@ -0,0 +1,67 @@
#if SIMPLSHARP
using Crestron.SimplSharp;
#else
using System.Diagnostics;
#endif
namespace ICD.Common.Utils.Timers
{
public sealed class IcdStopwatch
{
private readonly Stopwatch m_Stopwatch;
#region Properties
public long ElapsedMilliseconds { get { return m_Stopwatch.ElapsedMilliseconds; } }
public bool IsRunning { get { return m_Stopwatch.IsRunning; } }
#endregion
#region Constructors
/// <summary>
/// Constructor.
/// </summary>
public IcdStopwatch()
: this(new Stopwatch())
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="stopwatch"></param>
public IcdStopwatch(Stopwatch stopwatch)
{
m_Stopwatch = stopwatch;
}
public static IcdStopwatch StartNew()
{
return new IcdStopwatch(Stopwatch.StartNew());
}
#endregion
#region Methods
public void Stop()
{
m_Stopwatch.Stop();
}
public void Start()
{
m_Stopwatch.Start();
}
public void Reset()
{
m_Stopwatch.Reset();
}
#endregion
}
}

View File

@@ -0,0 +1,166 @@
using System;
using ICD.Common.EventArguments;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.Timers
{
/// <summary>
/// IcdTimer provides events for time increments as well as timer elapsed.
/// </summary>
public sealed class IcdTimer : IDisposable
{
private const long DEFAULT_HEARTBEAT_INTERVAL = 500;
/// <summary>
/// Called when the timer is restarted/stopped.
/// </summary>
public event EventHandler<BoolEventArgs> OnIsRunningChanged;
/// <summary>
/// Called when the timer has elapsed.
/// </summary>
public event EventHandler OnElapsed;
/// <summary>
/// Called when the milliseconds count changes. Useful for updating UIs.
/// </summary>
public event EventHandler OnMillisecondsChanged;
private readonly IcdStopwatch m_Stopwatch;
private readonly SafeTimer m_Heartbeat;
private long m_LastHeartbeatMilliseconds;
#region Properties
/// <summary>
/// Returns true if the timer is stopped.
/// </summary>
public bool IsStopped { get { return !m_Stopwatch.IsRunning; } }
/// <summary>
/// Returns true if the timer is running.
/// </summary>
public bool IsRunning { get { return m_Stopwatch.IsRunning; } }
/// <summary>
/// Returns true if the timer has elapsed.
/// </summary>
public bool IsElapsed { get { return Milliseconds > Length; } }
/// <summary>
/// Returns the number of milliseconds that have passed since the timer started.
/// </summary>
public long Milliseconds { get { return m_Stopwatch.ElapsedMilliseconds; } }
/// <summary>
/// The number of milliseconds before the timer is elapsed.
/// </summary>
public long Length { get; private set; }
/// <summary>
/// Gets the remaining number of milliseconds until the timer is elapsed. Returns 0 if the timer has elapsed.
/// </summary>
public long Remaining { get { return Math.Max(Length - Milliseconds, 0); } }
/// <summary>
/// Gets the remaining number of seconds until the timer is elapsed. Returns 0 if the timer has elapsed.
/// </summary>
public long RemainingSeconds { get { return (long)Math.Ceiling(Remaining / 1000.0f); } }
#endregion
#region Constructors
/// <summary>
/// Constructor.
/// </summary>
public IcdTimer()
: this(DEFAULT_HEARTBEAT_INTERVAL)
{
}
/// <summary>
/// Creates an IcdTimer with the specified heartbeat interval for the internal timer.
/// This allows a finer resolution for timing than the default 500ms.
/// </summary>
/// <param name="heartbeatInterval"></param>
public IcdTimer(long heartbeatInterval)
{
m_Heartbeat = new SafeTimer(HeartbeatCallback, heartbeatInterval, heartbeatInterval);
m_Stopwatch = new IcdStopwatch();
Stop();
}
#endregion
#region Methods
/// <summary>
/// Release resources.
/// </summary>
public void Dispose()
{
OnIsRunningChanged = null;
OnElapsed = null;
OnMillisecondsChanged = null;
m_Stopwatch.Stop();
m_Heartbeat.Dispose();
}
/// <summary>
/// Restarts the timer.
/// </summary>
public void Restart(long length)
{
Length = length;
m_Stopwatch.Reset();
m_Stopwatch.Start();
RaiseOnIsRunningChanged();
}
/// <summary>
/// Stops the timer.
/// </summary>
public void Stop()
{
m_Stopwatch.Stop();
RaiseOnIsRunningChanged();
}
#endregion
#region Private Methods
/// <summary>
/// Called when the heartbeat timer elapses.
/// </summary>
private void HeartbeatCallback()
{
if (Milliseconds == m_LastHeartbeatMilliseconds)
return;
OnMillisecondsChanged.Raise(this);
if (m_LastHeartbeatMilliseconds <= Length && IsElapsed)
OnElapsed.Raise(this);
m_LastHeartbeatMilliseconds = Milliseconds;
}
/// <summary>
/// Raises the OnIsRunningChanged event.
/// </summary>
private void RaiseOnIsRunningChanged()
{
OnIsRunningChanged.Raise(this, new BoolEventArgs(IsRunning));
}
#endregion
}
}

View File

@@ -0,0 +1,100 @@
using System;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.Timers
{
/// <summary>
/// Simple class for implementing things like volume ramps, where a button has an
/// immediate effect, and then begins ramping after a brief delay.
/// </summary>
[PublicAPI]
public sealed class Repeater : IDisposable
{
/// <summary>
/// Raised on the initial repeat.
/// </summary>
[PublicAPI]
public event EventHandler OnInitialRepeat;
/// <summary>
/// Raised on each subsequent repeat.
/// </summary>
[PublicAPI]
public event EventHandler OnRepeat;
private readonly SafeTimer m_RepeatTimer;
private readonly long m_BeforeRepeat;
private readonly long m_BetweenRepeat;
#region Constructor
/// <summary>
/// Constructor.
/// </summary>
/// <param name="beforeRepeat">The delay before the second increment</param>
/// <param name="betweenRepeat">The delay between each subsequent repeat</param>
public Repeater(long beforeRepeat, long betweenRepeat)
{
m_RepeatTimer = SafeTimer.Stopped(RepeatCallback);
m_BeforeRepeat = beforeRepeat;
m_BetweenRepeat = betweenRepeat;
}
/// <summary>
/// Destructor.
/// </summary>
~Repeater()
{
Dispose();
}
#endregion
#region Methods
/// <summary>
/// Release resources.
/// </summary>
public void Dispose()
{
m_RepeatTimer.Dispose();
}
/// <summary>
/// Begin repeating.
/// </summary>
[PublicAPI]
public void Start()
{
OnInitialRepeat.Raise(this);
m_RepeatTimer.Reset(m_BeforeRepeat, m_BetweenRepeat);
}
/// <summary>
/// Stop repeating volume.
/// </summary>
[PublicAPI]
public void Stop()
{
m_RepeatTimer.Stop();
}
#endregion
#region Private Methods
/// <summary>
/// Called for every repeat.
/// </summary>
private void RepeatCallback()
{
OnRepeat.Raise(this);
}
#endregion
}
}

View File

@@ -0,0 +1,180 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp;
#else
using System.Threading;
#endif
using ICD.Common.Services;
using ICD.Common.Services.Logging;
namespace ICD.Common.Utils.Timers
{
/// <summary>
/// SafeTimer wraps CTimer to hide some of the jank.
/// </summary>
public sealed class SafeTimer : IStateDisposable
{
#if SIMPLSHARP
private readonly CTimer m_Timer;
#else
private readonly Timer m_Timer;
private int m_DueTime, m_RepeatPeriod;
#endif
private readonly Action m_Callback;
/// <summary>
/// Returns true if this instance has been disposed.
/// </summary>
public bool IsDisposed { get; private set; }
#region Constructors
/// <summary>
/// Creates a timer that is called every repeatPeriod in milliseconds.
/// </summary>
/// <param name="callback"></param>
/// <param name="repeatPeriod"></param>
public SafeTimer(Action callback, long repeatPeriod)
: this(callback, 0, repeatPeriod)
{
}
/// <summary>
/// Creates a timer that is called in dueTime milliseconds and then every
/// repeatPeriod milliseconds afterwards.
/// </summary>
/// <param name="callback"></param>
/// <param name="dueTime"></param>
/// <param name="repeatPeriod"></param>
public SafeTimer(Action callback, long dueTime, long repeatPeriod)
{
m_Callback = callback;
#if SIMPLSHARP
m_Timer = new CTimer(SafeCallback, null, dueTime, repeatPeriod);
#else
m_DueTime = (int)dueTime;
m_RepeatPeriod = (int)repeatPeriod;
m_Timer = new Timer(SafeCallback, null, m_DueTime, m_RepeatPeriod);
#endif
}
/// <summary>
/// Creates a timer that is initially stopped.
/// </summary>
/// <param name="callback"></param>
/// <returns></returns>
public static SafeTimer Stopped(Action callback)
{
SafeTimer output = new SafeTimer(callback, 0);
output.Stop();
return output;
}
#endregion
#region Methods
/// <summary>
/// Release resources.
/// </summary>
public void Dispose()
{
Stop();
m_Timer.Dispose();
IsDisposed = true;
}
/// <summary>
/// Stops the timer.
/// </summary>
public void Stop()
{
#if SIMPLSHARP
m_Timer.Stop();
#else
m_Timer.Change(Timeout.Infinite, Timeout.Infinite);
#endif
}
/// <summary>
/// Immediately calls the callback and resets the timer
/// </summary>
public void Trigger()
{
#if SIMPLSHARP
m_Timer.Reset();
#else
m_Timer.Change(0, m_RepeatPeriod);
#endif
}
/// <summary>
/// Callback is called after the dueTime milliseconds.
/// </summary>
/// <param name="dueTime"></param>
public void Reset(long dueTime)
{
#if SIMPLSHARP
m_Timer.Reset(dueTime);
#else
m_DueTime = (int)dueTime;
m_Timer.Change(m_DueTime, m_RepeatPeriod);
#endif
}
/// <summary>
/// Callback is called after the dueTime milliseconds and every repeatPeriod milliseconds.
/// </summary>
/// <param name="dueTime"></param>
/// <param name="repeatPeriod"></param>
public void Reset(long dueTime, long repeatPeriod)
{
#if SIMPLSHARP
m_Timer.Reset(dueTime, repeatPeriod);
#else
m_DueTime = (int)dueTime;
m_RepeatPeriod = (int)repeatPeriod;
m_Timer.Change(m_DueTime, m_RepeatPeriod);
#endif
}
#endregion
#region Private Methods
/// <summary>
/// Only executes the callback if the timer has not been disposed.
/// Catches any exceptions and logs them.
/// </summary>
/// <param name="unused"></param>
private void SafeCallback(object unused)
{
// Essentially the meat of this class. There's some weirdness with the garbage collector where
// the reference to the timer will be cleared, and eventually the CTimer will call the callback
// despite being stopped/disposed.
if (m_Timer == null
#if SIMPLSHARP
|| m_Timer.Disposed
#endif
)
return;
try
{
m_Callback();
}
catch (Exception e)
{
LogException(e);
}
}
private void LogException(Exception e)
{
string message = string.Format("{0} failed to execute callback - {1}", GetType().Name, e.Message);
ServiceProvider.TryGetService<ILoggerService>().AddEntry(eSeverity.Error, e, message);
}
#endregion
}
}

View File

@@ -0,0 +1,56 @@
using System;
namespace ICD.Common.Utils
{
public static class TryUtils
{
/// <summary>
///
/// </summary>
/// <typeparam name="TResult">return type</typeparam>
/// <param name="function"></param>
/// <param name="val"></param>
/// <returns></returns>
public static bool Try<TResult>(Func<TResult> function, out TResult val)
{
if (function == null)
throw new ArgumentNullException("function");
try
{
val = function();
return true;
}
catch (Exception)
{
val = default(TResult);
return false;
}
}
public static bool Try<T1, TResult>(Func<T1, TResult> function, T1 param1, out TResult val)
{
if (function == null)
throw new ArgumentNullException("function");
return Try(() => function(param1), out val);
}
public static bool Try<T1, T2, TResult>(Func<T1, T2, TResult> function, T1 param1, T2 param2, out TResult val)
{
if (function == null)
throw new ArgumentNullException("function");
return Try(() => function(param1, param2), out val);
}
public static bool Try<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> function, T1 param1, T2 param2, T3 param3,
out TResult val)
{
if (function == null)
throw new ArgumentNullException("function");
return Try(() => function(param1, param2, param3), out val);
}
}
}

View File

@@ -0,0 +1,75 @@
namespace ICD.Common.Utils.Xml
{
/// <summary>
/// IcdXmlAttribute represents an attribute="value" pair from xml.
/// </summary>
public struct IcdXmlAttribute
{
private readonly string m_Name;
private readonly string m_Value;
public string Name { get { return m_Name; } }
public string Value { get { return m_Value; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
public IcdXmlAttribute(string name, string value)
{
m_Name = name;
m_Value = value;
}
/// <summary>
/// Implementing default equality.
/// </summary>
/// <param name="a1"></param>
/// <param name="a2"></param>
/// <returns></returns>
public static bool operator ==(IcdXmlAttribute a1, IcdXmlAttribute a2)
{
return a1.Equals(a2);
}
/// <summary>
/// Implementing default inequality.
/// </summary>
/// <param name="a1"></param>
/// <param name="a2"></param>
/// <returns></returns>
public static bool operator !=(IcdXmlAttribute a1, IcdXmlAttribute a2)
{
return !(a1 == a2);
}
/// <summary>
/// Returns true if this instance is equal to the given object.
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
public override bool Equals(object other)
{
if (other == null || GetType() != other.GetType())
return false;
return GetHashCode() == ((IcdXmlAttribute)other).GetHashCode();
}
/// <summary>
/// Gets the hashcode for this instance.
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = hash * 23 + (m_Name == null ? 0 : m_Name.GetHashCode());
hash = hash * 23 + (m_Value == null ? 0 : m_Value.GetHashCode());
return hash;
}
}
}
}

View File

@@ -0,0 +1,101 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronXml;
#else
using System.Xml;
#endif
namespace ICD.Common.Utils.Xml
{
public static class IcdXmlConvert
{
public static string ToString(int value)
{
return XmlConvert.ToString(value);
}
public static string ToString(bool value)
{
return XmlConvert.ToString(value);
}
public static string ToString(float value)
{
return XmlConvert.ToString(value);
}
public static string ToString(double value)
{
return XmlConvert.ToString(value);
}
public static string ToString(decimal value)
{
return XmlConvert.ToString(value);
}
public static string ToString(long value)
{
return XmlConvert.ToString(value);
}
public static string ToString(ulong value)
{
return XmlConvert.ToString(value);
}
public static string ToString(Guid value)
{
return XmlConvert.ToString(value);
}
public static string ToString(TimeSpan value)
{
return XmlConvert.ToString(value);
}
public static string ToString(int? value)
{
return value.HasValue ? ToString(value.Value) : null;
}
public static string ToString(object child)
{
if (child == null)
return null;
if (child is bool)
return ToString((bool)child);
if (child is byte)
return ToString((byte)child);
if (child is decimal)
return ToString((decimal)child);
if (child is char)
return ToString((char)child);
if (child is double)
return ToString((double)child);
if (child is Guid)
return ToString((Guid)child);
if (child is float)
return ToString((float)child);
if (child is int)
return ToString((int)child);
if (child is long)
return ToString((long)child);
if (child is sbyte)
return ToString((sbyte)child);
if (child is short)
return ToString((short)child);
if (child is TimeSpan)
return ToString((TimeSpan)child);
if (child is uint)
return ToString((uint)child);
if (child is ulong)
return ToString((ulong)child);
if (child is ushort)
return ToString((ushort)child);
return child.ToString();
}
}
}

View File

@@ -0,0 +1,40 @@
#if SIMPLSHARP
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronXml;
#else
using System.Xml;
#endif
namespace ICD.Common.Utils.Xml
{
public sealed class IcdXmlDocument
{
private readonly XmlDocument m_Document;
/// <summary>
/// Constructor.
/// </summary>
public IcdXmlDocument()
{
m_Document = new XmlDocument();
}
public void LoadXml(string xml)
{
try
{
m_Document.LoadXml(xml);
}
catch (XmlException e)
{
throw new IcdXmlException(e.Message, e, e.LineNumber, e.LinePosition);
}
}
public void WriteContentTo(IcdXmlTextWriter writer)
{
m_Document.WriteContentTo(writer.WrappedWriter);
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
namespace ICD.Common.Utils.Xml
{
public sealed class IcdXmlException : Exception
{
private int m_LineNumber;
private int m_LinePosition;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="message"></param>
/// <param name="inner"></param>
/// <param name="lineNumber"></param>
/// <param name="linePosition"></param>
public IcdXmlException(string message, Exception inner, int lineNumber, int linePosition)
: base(message, inner)
{
m_LineNumber = lineNumber;
m_LinePosition = linePosition;
}
}
}

View File

@@ -0,0 +1,128 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronXml;
#else
using System.Xml;
using System.IO;
#endif
namespace ICD.Common.Utils.Xml
{
public sealed class IcdXmlReader : IDisposable
{
private readonly XmlReader m_Reader;
#region Properties
public bool HasAttributes { get { return m_Reader.HasAttributes; } }
public string Name { get { return m_Reader.Name; } }
public string Value { get { return m_Reader.Value; } }
public XmlNodeType NodeType { get { return m_Reader.NodeType; } }
#endregion
/// <summary>
/// Constructor.
/// </summary>
/// <param name="xml"></param>
public IcdXmlReader(string xml)
{
if (xml == null)
throw new ArgumentNullException("xml");
#if SIMPLSHARP
m_Reader = new XmlReader(xml);
#else
m_Reader = XmlReader.Create(new StringReader(xml));
#endif
}
~IcdXmlReader()
{
Dispose();
}
#region Methods
public bool MoveToNextAttribute()
{
return m_Reader.MoveToNextAttribute();
}
public void MoveToElement()
{
m_Reader.MoveToElement();
}
public string GetAttribute(string name)
{
return m_Reader.GetAttribute(name);
}
public string ReadString()
{
#if SIMPLSHARP
return m_Reader.ReadString();
#else
return m_Reader.ReadElementContentAsString();
#endif
}
public bool Read()
{
try
{
return m_Reader.Read();
}
catch (XmlException e)
{
throw new IcdXmlException(e.Message, e, e.LineNumber, e.LinePosition);
}
}
public void Dispose()
{
#if SIMPLSHARP
m_Reader.Dispose(true);
#else
m_Reader.Dispose();
#endif
}
public void Skip()
{
m_Reader.Skip();
}
public string ReadElementContentAsString()
{
return m_Reader.ReadElementContentAsString();
}
public string ReadOuterXml()
{
return m_Reader.ReadOuterXml();
}
public string ReadInnerXml()
{
return m_Reader.ReadInnerXml();
}
public long ReadElementContentAsLong()
{
return m_Reader.ReadElementContentAsLong();
}
public float ReadElementContentAsFloat()
{
return m_Reader.ReadElementContentAsFloat();
}
#endregion
}
}

View File

@@ -0,0 +1,94 @@
#if SIMPLSHARP
using System.Text;
using Crestron.SimplSharp.CrestronXml;
using ICD.Common.Utils.IO;
namespace ICD.Common.Utils.Xml
{
public sealed partial class IcdXmlTextWriter
{
private readonly XmlTextWriter m_Writer;
public XmlWriter WrappedWriter { get { return m_Writer; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="stream"></param>
/// <param name="encoding"></param>
public IcdXmlTextWriter(IcdStream stream, Encoding encoding)
: this(new XmlTextWriter(stream.WrappedStream, encoding))
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="textWriter"></param>
public IcdXmlTextWriter(IcdTextWriter textWriter)
: this(new XmlTextWriter(textWriter.WrappedTextWriter))
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="writer"></param>
public IcdXmlTextWriter(XmlTextWriter writer)
{
m_Writer = writer;
m_Writer.Formatting = Crestron.SimplSharp.CrestronXml.Formatting.Indented;
}
#region Methods
public void WriteStartElement(string elementName)
{
m_Writer.WriteStartElement(elementName);
}
public void WriteElementString(string elementName, string value)
{
m_Writer.WriteElementString(elementName, value);
}
public void WriteEndElement()
{
m_Writer.WriteEndElement();
}
public void WriteComment(string comment)
{
m_Writer.WriteComment(comment);
}
public void Dispose()
{
m_Writer.Dispose(true);
}
public void WriteAttributeString(string attributeName, string value)
{
m_Writer.WriteAttributeString(attributeName, value);
}
public void Flush()
{
m_Writer.Flush();
}
public void Close()
{
m_Writer.Close();
}
public void WriteRaw(string xml)
{
m_Writer.WriteRaw(xml);
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,102 @@
using System.Text;
using System.Xml;
using ICD.Common.Utils.IO;
namespace ICD.Common.Utils.Xml
{
public sealed partial class IcdXmlTextWriter
{
private readonly XmlWriter m_Writer;
public XmlWriter WrappedWriter { get { return m_Writer; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="stream"></param>
/// <param name="encoding"></param>
public IcdXmlTextWriter(IcdStream stream, Encoding encoding)
: this(XmlWriter.Create(stream.WrappedStream, GetSettings(encoding)))
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="textWriter"></param>
public IcdXmlTextWriter(IcdTextWriter textWriter)
: this(XmlWriter.Create(textWriter.WrappedTextWriter))
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="writer"></param>
public IcdXmlTextWriter(XmlWriter writer)
{
m_Writer = writer;
}
#region Methods
public void WriteStartElement(string elementName)
{
m_Writer.WriteStartElement(elementName);
}
public void WriteElementString(string elementName, string value)
{
m_Writer.WriteElementString(elementName, value);
}
public void WriteEndElement()
{
m_Writer.WriteEndElement();
}
public void WriteComment(string comment)
{
m_Writer.WriteComment(comment);
}
public void Dispose()
{
m_Writer.Dispose();
}
public void WriteAttributeString(string attributeName, string value)
{
m_Writer.WriteAttributeString(attributeName, value);
}
public void Flush()
{
m_Writer.Flush();
}
public void Close()
{
}
public void WriteRaw(string xml)
{
m_Writer.WriteRaw(xml);
}
#endregion
#region Private Methods
private static XmlWriterSettings GetSettings(Encoding encoding)
{
return new XmlWriterSettings
{
Encoding = encoding,
Indent = true
};
}
#endregion
}
}

View File

@@ -0,0 +1,8 @@
using System;
namespace ICD.Common.Utils.Xml
{
public sealed partial class IcdXmlTextWriter : IDisposable
{
}
}

View File

@@ -0,0 +1,315 @@
using System;
using System.Collections.Generic;
using System.Linq;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronXml;
#else
using System.Xml;
#endif
using ICD.Common.EventArguments;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Xml
{
public static class XmlReaderExtensions
{
#region Attributes
/// <summary>
/// Returns true if the attribute exists.
/// </summary>
/// <param name="extends"></param>
/// <param name="name"></param>
/// <returns></returns>
[PublicAPI]
public static bool HasAttribute(this IcdXmlReader extends, string name)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.GetAttribute(name) != null;
}
/// <summary>
/// Gets the attributes for the current element without moving the reader.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<IcdXmlAttribute> GetAttributes(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (!extends.HasAttributes)
return new IcdXmlAttribute[0];
List<IcdXmlAttribute> attributes = new List<IcdXmlAttribute>();
while (extends.MoveToNextAttribute())
attributes.Add(new IcdXmlAttribute(extends.Name, extends.Value));
// Move back to element.
extends.MoveToElement();
return attributes.ToArray();
}
/// <summary>
/// Gets the value of the attribute with the given name.
/// </summary>
/// <param name="extends"></param>
/// <param name="name"></param>
/// <returns></returns>
[PublicAPI]
public static string GetAttributeAsString(this IcdXmlReader extends, string name)
{
if (extends == null)
throw new ArgumentNullException("extends");
string output = extends.GetAttribute(name);
if (output == null)
throw new FormatException(string.Format("Missing attribute \"{0}\"", name));
return output;
}
/// <summary>
/// Gets the value of the attribute with the given name and returns as an integer.
/// </summary>
/// <param name="extends"></param>
/// <param name="name"></param>
/// <returns></returns>
[PublicAPI]
public static int GetAttributeAsInt(this IcdXmlReader extends, string name)
{
if (extends == null)
throw new ArgumentNullException("extends");
string value = extends.GetAttributeAsString(name);
return int.Parse(value);
}
/// <summary>
/// Gets the value of the attribute with the given name and returns as a bool.
/// </summary>
/// <param name="extends"></param>
/// <param name="name"></param>
/// <returns></returns>
[PublicAPI]
public static bool GetAttributeAsBool(this IcdXmlReader extends, string name)
{
if (extends == null)
throw new ArgumentNullException("extends");
string value = extends.GetAttributeAsString(name);
return bool.Parse(value);
}
#endregion
#region Recurse
/// <summary>
/// Recurses through the entire XML, calling the callback for each Element/Text node.
/// </summary>
/// <param name="extends"></param>
/// <param name="callback"></param>
[PublicAPI]
public static void Recurse(this IcdXmlReader extends, Action<XmlRecursionEventArgs> callback)
{
if (extends == null)
throw new ArgumentNullException("extends");
XmlUtils.Recurse(extends.ReadString(), callback);
}
#endregion
#region Skip
/// <summary>
/// Skips over insignificant whitespace.
/// </summary>
/// <param name="extends"></param>
[PublicAPI]
public static void SkipInsignificantWhitespace(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
while (extends.NodeType == XmlNodeType.Whitespace && extends.Read())
{
}
}
/// <summary>
/// Skips the current node to the next element.
/// </summary>
/// <param name="extends"></param>
[PublicAPI]
public static bool SkipToNextElement(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
while (extends.Read() && extends.NodeType != XmlNodeType.Element)
{
}
return extends.NodeType == XmlNodeType.Element;
}
#endregion
#region Get Child Element
/// <summary>
/// Returns true if the current node has child elements.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static bool HasChildElements(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
while (extends.Read() && extends.NodeType != XmlNodeType.EndElement)
{
if (extends.NodeType == XmlNodeType.Element)
return true;
}
return false;
}
/// <summary>
/// Gets the child elements for the current element.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static IEnumerable<IcdXmlReader> GetChildElements(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
foreach (IcdXmlReader output in extends.GetChildElementsAsString().Select(child => new IcdXmlReader(child)))
{
output.SkipToNextElement();
yield return output;
}
}
/// <summary>
/// Gets the child elements for the current element.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<string> GetChildElementsAsString(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
// Step into the first child.
extends.SkipToNextElement();
while (extends.NodeType == XmlNodeType.Element || extends.NodeType == XmlNodeType.Comment)
{
switch (extends.NodeType)
{
case XmlNodeType.Comment:
extends.Skip();
break;
case XmlNodeType.Element:
yield return extends.ReadOuterXml();
break;
}
extends.SkipInsignificantWhitespace();
}
}
#endregion
#region Read Element Content
/// <summary>
/// Parses the element content in the format 0xXX as a byte.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static byte ReadElementContentAsByte(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string content = extends.ReadElementContentAsString();
return (byte)Convert.ToInt64(content, 16);
}
/// <summary>
/// Parses the element content as a uint.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static uint ReadElementContentAsUint(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string content = extends.ReadElementContentAsString();
return uint.Parse(content);
}
/// <summary>
/// Parses the element content as a uint.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static int ReadElementContentAsInt(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string content = extends.ReadElementContentAsString();
return int.Parse(content);
}
/// <summary>
/// Parses the element content as a ushort.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static ushort ReadElementContentAsUShort(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string content = extends.ReadElementContentAsString();
return ushort.Parse(content);
}
/// <summary>
/// Parses the element content as an enum.
/// </summary>
/// <param name="extends"></param>
/// <param name="ignoreCase"></param>
/// <returns></returns>
[PublicAPI]
public static T ReadElementContentAsEnum<T>(this IcdXmlReader extends, bool ignoreCase)
{
if (extends == null)
throw new ArgumentNullException("extends");
string content = extends.ReadElementContentAsString();
return EnumUtils.Parse<T>(content, ignoreCase);
}
#endregion
}
}

File diff suppressed because it is too large Load Diff