agrobot_base/Exemplos/SharpDX-master/Source/SharpDX/Utilities.cs

1338 lines
53 KiB
C#

// Copyright (c) 2010-2014 SharpDX - Alexandre Mutel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Threading;
using SharpDX.Direct3D;
using System.Reflection;
using System.Linq;
using System.Linq.Expressions;
using SharpDX.Text;
using SharpDX.Mathematics.Interop;
namespace SharpDX
{
/// <summary>
/// A Delegate to get a property value from an object.
/// </summary>
/// <typeparam name="T">Type of the getter.</typeparam>
/// <param name="obj">The obj to get the property from.</param>
/// <param name="value">The value to get.</param>
public delegate void GetValueFastDelegate<T>(object obj, out T value);
/// <summary>
/// A Delegate to set a property value to an object.
/// </summary>
/// <typeparam name="T">Type of the setter.</typeparam>
/// <param name="obj">The obj to set the property from.</param>
/// <param name="value">The value to set.</param>
public delegate void SetValueFastDelegate<T>(object obj, ref T value);
/// <summary>
/// Utility class.
/// </summary>
public static class Utilities
{
///// <summary>
///// Native memcpy.
///// </summary>
///// <param name="dest">The destination memory location.</param>
///// <param name="src">The source memory location.</param>
///// <param name="sizeInBytesToCopy">The count.</param>
///// <returns></returns>
//[DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl,
// SetLastError = false), SuppressUnmanagedCodeSecurity]
//public static extern IntPtr CopyMemory(IntPtr dest, IntPtr src, ulong sizeInBytesToCopy);
/// <summary>
/// Native memcpy.
/// </summary>
/// <param name="dest">The destination memory location.</param>
/// <param name="src">The source memory location.</param>
/// <param name="sizeInBytesToCopy">The byte count.</param>
public static void CopyMemory(IntPtr dest, IntPtr src, int sizeInBytesToCopy)
{
unsafe
{
// TODO plug in Interop a pluggable CopyMemory using cpblk or memcpy based on architecture
Interop.memcpy((void*)dest, (void*)src, sizeInBytesToCopy);
}
}
/// <summary>
/// Compares two block of memory.
/// </summary>
/// <param name="from">The pointer to compare from.</param>
/// <param name="against">The pointer to compare against.</param>
/// <param name="sizeToCompare">The size in bytes to compare.</param>
/// <returns><c>true</c> if the buffers are equivalent; otherwise, <c>false</c>.</returns>
public unsafe static bool CompareMemory(IntPtr from, IntPtr against, int sizeToCompare)
{
var pSrc = (byte*)@from;
var pDst = (byte*)against;
// Compare 8 bytes.
int numberOf = sizeToCompare >> 3;
while (numberOf > 0)
{
if (*(long*)pSrc != *(long*)pDst)
return false;
pSrc += 8;
pDst += 8;
numberOf--;
}
// Compare remaining bytes.
numberOf = sizeToCompare & 7;
while (numberOf > 0)
{
if (*pSrc != *pDst)
return false;
pSrc++;
pDst++;
numberOf--;
}
return true;
}
/// <summary>
/// Clears the memory.
/// </summary>
/// <param name="dest">The dest.</param>
/// <param name="value">The value.</param>
/// <param name="sizeInBytesToClear">The size in bytes to clear.</param>
public static void ClearMemory(IntPtr dest, byte value, int sizeInBytesToClear)
{
unsafe
{
Interop.memset((void*)dest, value, sizeInBytesToClear);
}
}
/// <summary>
/// Return the sizeof a struct from a CLR. Equivalent to sizeof operator but works on generics too.
/// </summary>
/// <typeparam name="T">A struct to evaluate.</typeparam>
/// <returns>Size of this struct.</returns>
public static int SizeOf<T>() where T : struct
{
return Interop.SizeOf<T>();
}
/// <summary>
/// Return the sizeof an array of struct. Equivalent to sizeof operator but works on generics too.
/// </summary>
/// <typeparam name="T">A struct.</typeparam>
/// <param name="array">The array of struct to evaluate.</param>
/// <returns>Size in bytes of this array of struct.</returns>
public static int SizeOf<T>(T[] array) where T : struct
{
return array == null ? 0 : array.Length * Interop.SizeOf<T>();
}
/// <summary>
/// Pins the specified source and call an action with the pinned pointer.
/// </summary>
/// <typeparam name="T">The type of the structure to pin.</typeparam>
/// <param name="source">The source.</param>
/// <param name="pinAction">The pin action to perform on the pinned pointer.</param>
public static void Pin<T>(ref T source, Action<IntPtr> pinAction) where T : struct
{
unsafe
{
pinAction((IntPtr)Interop.Fixed(ref source));
}
}
/// <summary>
/// Pins the specified source and call an action with the pinned pointer.
/// </summary>
/// <typeparam name="T">The type of the structure to pin.</typeparam>
/// <param name="source">The source array.</param>
/// <param name="pinAction">The pin action to perform on the pinned pointer.</param>
public static void Pin<T>(T[] source, Action<IntPtr> pinAction) where T : struct
{
unsafe
{
pinAction(source == null ? IntPtr.Zero : (IntPtr)Interop.Fixed(source));
}
}
/// <summary>
/// Converts a structured array to an equivalent byte array.
/// </summary>
/// <typeparam name="T">The type of source array.</typeparam>
/// <param name="source">The source array.</param>
/// <returns>Converted byte array.</returns>
public static byte[] ToByteArray<T>(T[] source) where T : struct
{
if (source == null) return null;
var buffer = new byte[SizeOf<T>() * source.Length];
if (source.Length == 0)
return buffer;
unsafe
{
fixed (void* pBuffer = buffer)
Interop.Write(pBuffer, source, 0, source.Length);
}
return buffer;
}
/// <summary>
/// Swaps the value between two references.
/// </summary>
/// <typeparam name="T">Type of a data to swap.</typeparam>
/// <param name="left">The left value.</param>
/// <param name="right">The right value.</param>
public static void Swap<T>(ref T left, ref T right)
{
var temp = left;
left = right;
right = temp;
}
/// <summary>
/// Reads the specified T data from a memory location.
/// </summary>
/// <typeparam name="T">Type of a data to read.</typeparam>
/// <param name="source">Memory location to read from.</param>
/// <returns>The data read from the memory location.</returns>
public static T Read<T>(IntPtr source) where T : struct
{
unsafe
{
return Interop.ReadInline<T>((void*)source);
}
}
/// <summary>
/// Reads the specified T data from a memory location.
/// </summary>
/// <typeparam name="T">Type of a data to read.</typeparam>
/// <param name="source">Memory location to read from.</param>
/// <param name="data">The data write to.</param>
/// <returns>source pointer + sizeof(T).</returns>
public static void Read<T>(IntPtr source, ref T data) where T : struct
{
unsafe
{
Interop.CopyInline(ref data, (void*)source);
}
}
/// <summary>
/// Reads the specified T data from a memory location.
/// </summary>
/// <typeparam name="T">Type of a data to read.</typeparam>
/// <param name="source">Memory location to read from.</param>
/// <param name="data">The data write to.</param>
/// <returns>source pointer + sizeof(T).</returns>
public static void ReadOut<T>(IntPtr source, out T data) where T : struct
{
unsafe
{
Interop.CopyInlineOut(out data, (void*)source);
}
}
/// <summary>
/// Reads the specified T data from a memory location.
/// </summary>
/// <typeparam name="T">Type of a data to read.</typeparam>
/// <param name="source">Memory location to read from.</param>
/// <param name="data">The data write to.</param>
/// <returns>source pointer + sizeof(T).</returns>
public static IntPtr ReadAndPosition<T>(IntPtr source, ref T data) where T : struct
{
unsafe
{
return (IntPtr)Interop.Read((void*)source, ref data);
}
}
/// <summary>
/// Reads the specified array T[] data from a memory location.
/// </summary>
/// <typeparam name="T">Type of a data to read.</typeparam>
/// <param name="source">Memory location to read from.</param>
/// <param name="data">The data write to.</param>
/// <param name="offset">The offset in the array to write to.</param>
/// <param name="count">The number of T element to read from the memory location.</param>
/// <returns>source pointer + sizeof(T) * count.</returns>
public static IntPtr Read<T>(IntPtr source, T[] data, int offset, int count) where T : struct
{
unsafe
{
return (IntPtr)Interop.Read((void*)source, data, offset, count);
}
}
/// <summary>
/// Writes the specified T data to a memory location.
/// </summary>
/// <typeparam name="T">Type of a data to write.</typeparam>
/// <param name="destination">Memory location to write to.</param>
/// <param name="data">The data to write.</param>
/// <returns>destination pointer + sizeof(T).</returns>
public static void Write<T>(IntPtr destination, ref T data) where T : struct
{
unsafe
{
Interop.CopyInline((void*)destination, ref data);
}
}
/// <summary>
/// Writes the specified T data to a memory location.
/// </summary>
/// <typeparam name="T">Type of a data to write.</typeparam>
/// <param name="destination">Memory location to write to.</param>
/// <param name="data">The data to write.</param>
/// <returns>destination pointer + sizeof(T).</returns>
public static IntPtr WriteAndPosition<T>(IntPtr destination, ref T data) where T : struct
{
unsafe
{
return (IntPtr)Interop.Write((void*)destination, ref data);
}
}
/// <summary>
/// Writes the specified array T[] data to a memory location.
/// </summary>
/// <typeparam name="T">Type of a data to write.</typeparam>
/// <param name="destination">Memory location to write to.</param>
/// <param name="data">The array of T data to write.</param>
/// <param name="offset">The offset in the array to read from.</param>
/// <param name="count">The number of T element to write to the memory location.</param>
/// <returns>destination pointer + sizeof(T) * count.</returns>
public static IntPtr Write<T>(IntPtr destination, T[] data, int offset, int count) where T : struct
{
unsafe
{
return (IntPtr)Interop.Write((void*)destination, data, offset, count);
}
}
/// <summary>
/// Converts bool array to integer pointers array.
/// </summary>
/// <param name="array">The bool array.</param>
/// <param name="dest">The destination array of int pointers.</param>
public unsafe static void ConvertToIntArray(bool[] array, int* dest)
{
for (int i = 0; i < array.Length; i++)
dest[i] = array[i] ? 1 : 0;
}
/// <summary>
/// Converts bool array to <see cref="RawBool"/> array.
/// </summary>
/// <param name="array">The bool array.</param>
/// <returns>Converted array of <see cref="RawBool"/>.</returns>
public static RawBool[] ConvertToIntArray(bool[] array)
{
var temp = new RawBool[array.Length];
for (int i = 0; i < temp.Length; i++)
temp[i] = array[i];
return temp;
}
/// <summary>
/// Converts integer pointer array to bool array.
/// </summary>
/// <param name="array">The array of integer pointers.</param>
/// <param name="length">Array size.</param>
/// <returns>Converted array of bool.</returns>
public static unsafe bool[] ConvertToBoolArray(int* array, int length)
{
var temp = new bool[length];
for(int i = 0; i < temp.Length; i++)
temp[i] = array[i] != 0;
return temp;
}
/// <summary>
/// Converts <see cref="RawBool"/> array to bool array.
/// </summary>
/// <param name="array">The array.</param>
/// <returns>Converted array of bool.</returns>
public static bool[] ConvertToBoolArray(RawBool[] array)
{
var temp = new bool[array.Length];
for(int i = 0; i < temp.Length; i++)
temp[i] = array[i];
return temp;
}
/// <summary>
/// Gets the <see cref="System.Guid"/> from a type.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>The guid associated with this type.</returns>
public static Guid GetGuidFromType(Type type)
{
return type.GetTypeInfo().GUID;
}
/// <summary>
/// Determines whether a given type inherits from a generic type.
/// </summary>
/// <param name="givenType">Type of the class to check if it inherits from generic type.</param>
/// <param name="genericType">Type of the generic.</param>
/// <returns><c>true</c> if [is assignable to generic type] [the specified given type]; otherwise, <c>false</c>.</returns>
public static bool IsAssignableToGenericType(Type givenType, Type genericType)
{
// from http://stackoverflow.com/a/1075059/1356325
#if BEFORE_NET45
var interfaceTypes = givenType.GetTypeInfo().GetInterfaces();
#else
var interfaceTypes = givenType.GetTypeInfo().ImplementedInterfaces;
#endif
foreach (var it in interfaceTypes)
{
if (it.GetTypeInfo().IsGenericType && it.GetGenericTypeDefinition() == genericType)
return true;
}
if (givenType.GetTypeInfo().IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
return true;
Type baseType = givenType.GetTypeInfo().BaseType;
if (baseType == null) return false;
return IsAssignableToGenericType(baseType, genericType);
}
/// <summary>
/// Allocate an aligned memory buffer.
/// </summary>
/// <param name="sizeInBytes">Size of the buffer to allocate.</param>
/// <param name="align">Alignment, 16 bytes by default.</param>
/// <returns>A pointer to a buffer aligned.</returns>
/// <remarks>
/// To free this buffer, call <see cref="FreeMemory"/>.
/// </remarks>
public unsafe static IntPtr AllocateMemory(int sizeInBytes, int align = 16)
{
int mask = align - 1;
var memPtr = Marshal.AllocHGlobal(sizeInBytes + mask + IntPtr.Size);
var ptr = (long)((byte*)memPtr + sizeof(void*) + mask) & ~mask;
((IntPtr*)ptr)[-1] = memPtr;
return new IntPtr((void*)ptr);
}
/// <summary>
/// Allocate an aligned memory buffer and clear it with a specified value (0 by default).
/// </summary>
/// <param name="sizeInBytes">Size of the buffer to allocate.</param>
/// <param name="clearValue">Default value used to clear the buffer.</param>
/// <param name="align">Alignment, 16 bytes by default.</param>
/// <returns>A pointer to a buffer aligned.</returns>
/// <remarks>
/// To free this buffer, call <see cref="FreeMemory"/>.
/// </remarks>
public static IntPtr AllocateClearedMemory(int sizeInBytes, byte clearValue = 0, int align = 16)
{
var ptr = AllocateMemory(sizeInBytes, align);
ClearMemory(ptr, clearValue, sizeInBytes);
return ptr;
}
/// <summary>
/// Determines whether the specified memory pointer is aligned in memory.
/// </summary>
/// <param name="memoryPtr">The memory pointer.</param>
/// <param name="align">The align.</param>
/// <returns><c>true</c> if the specified memory pointer is aligned in memory; otherwise, <c>false</c>.</returns>
public static bool IsMemoryAligned(IntPtr memoryPtr, int align = 16)
{
return ((memoryPtr.ToInt64() & (align-1)) == 0);
}
/// <summary>
/// Allocate an aligned memory buffer.
/// </summary>
/// <returns>A pointer to a buffer aligned.</returns>
/// <remarks>
/// The buffer must have been allocated with <see cref="AllocateMemory"/>.
/// </remarks>
public unsafe static void FreeMemory(IntPtr alignedBuffer)
{
if (alignedBuffer == IntPtr.Zero) return;
Marshal.FreeHGlobal(((IntPtr*) alignedBuffer)[-1]);
}
/// <summary>
/// Converts a pointer to a null-terminating string up to maxLength characters to a .Net string.
/// </summary>
/// <param name="pointer">The pointer to an ANSI null string.</param>
/// <param name="maxLength">Maximum length of the string.</param>
/// <returns>The converted string.</returns>
public static string PtrToStringAnsi(IntPtr pointer, int maxLength)
{
string managedString = Marshal.PtrToStringAnsi(pointer); // copy null-terminating unmanaged text from pointer to a managed string
if (managedString != null && managedString.Length > maxLength)
managedString = managedString.Substring(0, maxLength);
return managedString;
}
/// <summary>
/// Converts a pointer to a null-terminating string up to maxLength characters to a .Net string.
/// </summary>
/// <param name="pointer">The pointer to an Unicode null string.</param>
/// <param name="maxLength">Maximum length of the string.</param>
/// <returns>The converted string.</returns>
public static string PtrToStringUni(IntPtr pointer, int maxLength)
{
string managedString = Marshal.PtrToStringUni(pointer); // copy null-terminating unmanaged text from pointer to a managed string
if (managedString != null && managedString.Length > maxLength)
managedString = managedString.Substring(0, maxLength);
return managedString;
}
/// <summary>
/// Copies the contents of a managed String into unmanaged memory, converting into ANSI format as it copies.
/// </summary>
/// <param name="s">A managed string to be copied.</param>
/// <returns>The address, in unmanaged memory, to where s was copied, or IntPtr.Zero if s is null.</returns>
public static unsafe IntPtr StringToHGlobalAnsi(string s)
{
return Marshal.StringToHGlobalAnsi(s);
}
/// <summary>
/// Copies the contents of a managed String into unmanaged memory.
/// </summary>
/// <param name="s">A managed string to be copied.</param>
/// <returns>The address, in unmanaged memory, to where s was copied, or IntPtr.Zero if s is null.</returns>
public static unsafe IntPtr StringToHGlobalUni(string s)
{
return Marshal.StringToHGlobalUni(s);
}
/// <summary>
/// Copies the contents of a managed String into unmanaged memory using <see cref="Marshal.AllocCoTaskMem"/>
/// </summary>
/// <param name="s">A managed string to be copied.</param>
/// <returns>The address, in unmanaged memory, to where s was copied, or IntPtr.Zero if s is null.</returns>
public static unsafe IntPtr StringToCoTaskMemUni(string s)
{
if (s == null)
{
return IntPtr.Zero;
}
int num = (s.Length + 1) * 2;
if (num < s.Length)
{
throw new ArgumentOutOfRangeException("s");
}
IntPtr ptr2 = Marshal.AllocCoTaskMem(num);
if (ptr2 == IntPtr.Zero)
{
throw new OutOfMemoryException();
}
CopyStringToUnmanaged(ptr2, s);
return ptr2;
}
private unsafe static void CopyStringToUnmanaged(IntPtr ptr, string str)
{
fixed (char* pStr = str)
{
CopyMemory(ptr, new IntPtr(pStr), (str.Length + 1 ) * 2);
}
}
/// <summary>
/// Gets the IUnknown from object. Similar to <see cref="Marshal.GetIUnknownForObject"/> but accept null object
/// by returning an IntPtr.Zero IUnknown pointer.
/// </summary>
/// <param name="obj">The managed object.</param>
/// <returns>An IUnknown pointer to a managed object.</returns>
public static IntPtr GetIUnknownForObject(object obj)
{
IntPtr objPtr = obj == null ? IntPtr.Zero : Marshal.GetIUnknownForObject(obj);
//if (obj is ComObject && ((ComObject)obj).NativePointer == IntPtr.Zero)
// (((ComObject)obj).NativePointer) = objPtr;
return objPtr;
}
/// <summary>
/// Gets an object from an IUnknown pointer. Similar to <see cref="Marshal.GetObjectForIUnknown"/> but accept IntPtr.Zero
/// by returning a null object.
/// </summary>
/// <param name="iunknownPtr">an IUnknown pointer to a managed object.</param>
/// <returns>The managed object.</returns>
public static object GetObjectForIUnknown(IntPtr iunknownPtr)
{
return iunknownPtr == IntPtr.Zero ? null : Marshal.GetObjectForIUnknown(iunknownPtr);
}
/// <summary>
/// String helper join method to display an array of object as a single string.
/// </summary>
/// <param name="separator">The separator.</param>
/// <param name="array">The array.</param>
/// <returns>A string with array elements separated by the separator.</returns>
public static string Join<T>(string separator, T[] array)
{
var text = new StringBuilder();
if (array != null)
{
for (int i = 0; i < array.Length; i++)
{
if (i > 0) text.Append(separator);
text.Append(array[i]);
}
}
return text.ToString();
}
/// <summary>
/// String helper join method to display an enumerable of object as a single string.
/// </summary>
/// <param name="separator">The separator.</param>
/// <param name="elements">The enumerable.</param>
/// <returns>A string with array elements separated by the separator.</returns>
public static string Join(string separator, IEnumerable elements)
{
var elementList = new List<string>();
foreach (var element in elements)
elementList.Add(element.ToString());
var text = new StringBuilder();
for (int i = 0; i < elementList.Count; i++)
{
var element = elementList[i];
if (i > 0) text.Append(separator);
text.Append(element);
}
return text.ToString();
}
/// <summary>
/// String helper join method to display an enumerable of object as a single string.
/// </summary>
/// <param name="separator">The separator.</param>
/// <param name="elements">The enumerable.</param>
/// <returns>A string with array elements separated by the separator.</returns>
public static string Join(string separator, IEnumerator elements)
{
var elementList = new List<string>();
while (elements.MoveNext())
elementList.Add(elements.Current.ToString());
var text = new StringBuilder();
for (int i = 0; i < elementList.Count; i++)
{
var element = elementList[i];
if (i > 0) text.Append(separator);
text.Append(element);
}
return text.ToString();
}
/// <summary>
/// Converts a blob to a string.
/// </summary>
/// <param name="blob">A blob.</param>
/// <returns>A string extracted from a blob.</returns>
public static string BlobToString(Blob blob)
{
if (blob == null) return null;
string output;
output = Marshal.PtrToStringAnsi(blob.BufferPointer);
blob.Dispose();
return output;
}
/// <summary>
/// Equivalent to IntPtr.Add method from 3.5+ .NET Framework.
/// Adds an offset to the value of a pointer.
/// </summary>
/// <param name="ptr">A native pointer.</param>
/// <param name="offset">The offset to add (number of bytes).</param>
/// <returns>A new pointer that reflects the addition of offset to pointer.</returns>
public unsafe static IntPtr IntPtrAdd(IntPtr ptr, int offset)
{
return new IntPtr(((byte*) ptr) + offset);
}
/// <summary>
/// Read stream to a byte[] buffer.
/// </summary>
/// <param name="stream">Input stream.</param>
/// <returns>A byte[] buffer.</returns>
public static byte[] ReadStream(Stream stream)
{
int readLength = 0;
return ReadStream(stream, ref readLength);
}
/// <summary>
/// Read stream to a byte[] buffer.
/// </summary>
/// <param name="stream">Input stream.</param>
/// <param name="readLength">Length to read.</param>
/// <returns>A byte[] buffer.</returns>
public static byte[] ReadStream(Stream stream, ref int readLength)
{
Debug.Assert(stream != null);
Debug.Assert(stream.CanRead);
int num = readLength;
Debug.Assert(num <= (stream.Length - stream.Position));
if (num == 0)
readLength = (int) (stream.Length - stream.Position);
num = readLength;
Debug.Assert(num >= 0);
if (num == 0)
return new byte[0];
byte[] buffer = new byte[num];
int bytesRead = 0;
if (num > 0)
{
do
{
bytesRead += stream.Read(buffer, bytesRead, readLength - bytesRead);
} while (bytesRead < readLength);
}
return buffer;
}
/// <summary>
/// Compares two collection, element by elements.
/// </summary>
/// <param name="left">A "from" enumerator.</param>
/// <param name="right">A "to" enumerator.</param>
/// <returns><c>true</c> if lists are identical, <c>false</c> otherwise.</returns>
public static bool Compare(IEnumerable left, IEnumerable right)
{
if (ReferenceEquals(left, right))
return true;
if (ReferenceEquals(left, null) || ReferenceEquals(right, null))
return false;
return Compare(left.GetEnumerator(), right.GetEnumerator());
}
/// <summary>
/// Compares two collection, element by elements.
/// </summary>
/// <param name="leftIt">A "from" enumerator.</param>
/// <param name="rightIt">A "to" enumerator.</param>
/// <returns><c>true</c> if lists are identical; otherwise, <c>false</c>.</returns>
public static bool Compare(IEnumerator leftIt, IEnumerator rightIt)
{
if (ReferenceEquals(leftIt, rightIt))
return true;
if (ReferenceEquals(leftIt, null) || ReferenceEquals(rightIt, null))
return false;
bool hasLeftNext;
bool hasRightNext;
while (true)
{
hasLeftNext = leftIt.MoveNext();
hasRightNext = rightIt.MoveNext();
if (!hasLeftNext || !hasRightNext)
break;
if (!Equals(leftIt.Current, rightIt.Current))
return false;
}
// If there is any left element
if (hasLeftNext != hasRightNext)
return false;
return true;
}
/// <summary>
/// Compares two collection, element by elements.
/// </summary>
/// <param name="left">The collection to compare from.</param>
/// <param name="right">The collection to compare to.</param>
/// <returns><c>true</c> if lists are identical (but not necessarily of the same time); otherwise , <c>false</c>.</returns>
public static bool Compare(ICollection left, ICollection right)
{
if (ReferenceEquals(left, right))
return true;
if (ReferenceEquals(left, null) || ReferenceEquals(right, null))
return false;
if (left.Count != right.Count)
return false;
int count = 0;
var leftIt = left.GetEnumerator();
var rightIt = right.GetEnumerator();
while (leftIt.MoveNext() && rightIt.MoveNext())
{
if (!Equals(leftIt.Current, rightIt.Current))
return false;
count++;
}
// Just double check to make sure that the iterator actually returns
// the exact number of elements
if (count != left.Count)
return false;
return true;
}
/// <summary>
/// Gets the custom attribute.
/// </summary>
/// <typeparam name="T">Type of the custom attribute.</typeparam>
/// <param name="memberInfo">The member info.</param>
/// <param name="inherited">if set to <c>true</c> [inherited].</param>
/// <returns>The custom attribute or null if not found.</returns>
public static T GetCustomAttribute<T>(MemberInfo memberInfo, bool inherited = false) where T : Attribute
{
return memberInfo.GetCustomAttribute<T>(inherited);
}
/// <summary>
/// Gets the custom attributes.
/// </summary>
/// <typeparam name="T">Type of the custom attribute.</typeparam>
/// <param name="memberInfo">The member info.</param>
/// <param name="inherited">if set to <c>true</c> [inherited].</param>
/// <returns>The custom attribute or null if not found.</returns>
public static IEnumerable<T> GetCustomAttributes<T>(MemberInfo memberInfo, bool inherited = false) where T : Attribute
{
return memberInfo.GetCustomAttributes<T>(inherited);
}
/// <summary>
/// Determines whether fromType can be assigned to toType.
/// </summary>
/// <param name="toType">To type.</param>
/// <param name="fromType">From type.</param>
/// <returns>
/// <c>true</c> if [is assignable from] [the specified to type]; otherwise, <c>false</c>.
/// </returns>
public static bool IsAssignableFrom(Type toType, Type fromType)
{
return toType.GetTypeInfo().IsAssignableFrom(fromType.GetTypeInfo());
}
/// <summary>
/// Determines whether the specified type to test is an enum.
/// </summary>
/// <param name="typeToTest">The type to test.</param>
/// <returns>
/// <c>true</c> if the specified type to test is an enum; otherwise, <c>false</c>.
/// </returns>
public static bool IsEnum(Type typeToTest)
{
return typeToTest.GetTypeInfo().IsEnum;
}
/// <summary>
/// Determines whether the specified type to test is a value type.
/// </summary>
/// <param name="typeToTest">The type to test.</param>
/// <returns>
/// <c>true</c> if the specified type to test is a value type; otherwise, <c>false</c>.
/// </returns>
public static bool IsValueType(Type typeToTest)
{
return typeToTest.GetTypeInfo().IsValueType;
}
private static MethodInfo GetMethod(Type type, string name, Type[] typeArgs) {
#if BEFORE_NET45
foreach( var method in type.GetTypeInfo().GetMethods(BindingFlags.Public|BindingFlags.Instance))
{
if(method.Name != name)
{
continue;
}
#else
foreach( var method in type.GetTypeInfo().GetDeclaredMethods(name))
{
#endif
if ( method.GetParameters().Length == typeArgs.Length) {
var parameters = method.GetParameters();
bool methodFound = true;
for (int i = 0; i < typeArgs.Length; i++)
{
if (parameters[i].ParameterType != typeArgs[i]) {
methodFound = false;
break;
}
}
if (methodFound) {
return method;
}
}
}
return null;
}
/// <summary>
/// Builds a fast property getter from a type and a property info.
/// </summary>
/// <typeparam name="T">Type of the getter.</typeparam>
/// <param name="customEffectType">Type of the custom effect.</param>
/// <param name="propertyInfo">The property info to get the value from.</param>
/// <returns>A compiled delegate.</returns>
public static GetValueFastDelegate<T> BuildPropertyGetter<T>(Type customEffectType, PropertyInfo propertyInfo)
{
var valueParam = Expression.Parameter(typeof(T).MakeByRefType());
var objectParam = Expression.Parameter(typeof(object));
var castParam = Expression.Convert(objectParam, customEffectType);
var propertyAccessor = Expression.Property(castParam, propertyInfo);
Expression convertExpression;
if (propertyInfo.PropertyType == typeof(bool))
{
// Convert bool to int: effect.Property ? 1 : 0
convertExpression = Expression.Condition(propertyAccessor, Expression.Constant(1), Expression.Constant(0));
}
else
{
convertExpression = Expression.Convert(propertyAccessor, typeof(T));
}
return Expression.Lambda<GetValueFastDelegate<T>>(Expression.Assign(valueParam, convertExpression), objectParam, valueParam).Compile();
}
/// <summary>
/// Builds a fast property setter from a type and a property info.
/// </summary>
/// <typeparam name="T">Type of the setter.</typeparam>
/// <param name="customEffectType">Type of the custom effect.</param>
/// <param name="propertyInfo">The property info to set the value to.</param>
/// <returns>A compiled delegate.</returns>
public static SetValueFastDelegate<T> BuildPropertySetter<T>(Type customEffectType, PropertyInfo propertyInfo)
{
var valueParam = Expression.Parameter(typeof(T).MakeByRefType());
var objectParam = Expression.Parameter(typeof(object));
var castParam = Expression.Convert(objectParam, customEffectType);
var propertyAccessor = Expression.Property(castParam, propertyInfo);
Expression convertExpression;
if (propertyInfo.PropertyType == typeof(bool))
{
// Convert int to bool: value != 0
convertExpression = Expression.NotEqual(valueParam, Expression.Constant(0));
}
else
{
convertExpression = Expression.Convert(valueParam, propertyInfo.PropertyType);
}
return Expression.Lambda<SetValueFastDelegate<T>>(Expression.Assign(propertyAccessor, convertExpression), objectParam, valueParam).Compile();
}
/// <summary>
/// Finds an explicit conversion between a source type and a target type.
/// </summary>
/// <param name="sourceType">Type of the source.</param>
/// <param name="targetType">Type of the target.</param>
/// <returns>The method to perform the conversion. null if not found.</returns>
private static MethodInfo FindExplicitConverstion(Type sourceType, Type targetType)
{
// No need for cast for similar source and target type
if (sourceType == targetType)
return null;
var methods = new List<MethodInfo>();
var tempType = sourceType;
while (tempType != null)
{
#if BEFORE_NET45
methods.AddRange(tempType.GetTypeInfo().GetMethods(BindingFlags.Public)); //target methods will be favored in the search
#else
methods.AddRange(tempType.GetTypeInfo().DeclaredMethods); //target methods will be favored in the search
#endif
tempType = tempType.GetTypeInfo().BaseType;
}
tempType = targetType;
while (tempType != null)
{
#if BEFORE_NET45
methods.AddRange(tempType.GetTypeInfo().GetMethods(BindingFlags.Public)); //target methods will be favored in the search
#else
methods.AddRange(tempType.GetTypeInfo().DeclaredMethods); //target methods will be favored in the search
#endif
tempType = tempType.GetTypeInfo().BaseType;
}
foreach (MethodInfo mi in methods)
{
if (mi.Name == "op_Explicit") //will return target and take one parameter
if (mi.ReturnType == targetType)
if (IsAssignableFrom(mi.GetParameters()[0].ParameterType, sourceType))
return mi;
}
return null;
}
[Flags]
public enum CLSCTX : uint
{
ClsctxInprocServer = 0x1,
ClsctxInprocHandler = 0x2,
ClsctxLocalServer = 0x4,
ClsctxInprocServer16 = 0x8,
ClsctxRemoteServer = 0x10,
ClsctxInprocHandler16 = 0x20,
ClsctxReserved1 = 0x40,
ClsctxReserved2 = 0x80,
ClsctxReserved3 = 0x100,
ClsctxReserved4 = 0x200,
ClsctxNoCodeDownload = 0x400,
ClsctxReserved5 = 0x800,
ClsctxNoCustomMarshal = 0x1000,
ClsctxEnableCodeDownload = 0x2000,
ClsctxNoFailureLog = 0x4000,
ClsctxDisableAaa = 0x8000,
ClsctxEnableAaa = 0x10000,
ClsctxFromDefaultContext = 0x20000,
ClsctxInproc = ClsctxInprocServer | ClsctxInprocHandler,
ClsctxServer = ClsctxInprocServer | ClsctxLocalServer | ClsctxRemoteServer,
ClsctxAll = ClsctxServer | ClsctxInprocHandler
}
#if WINDOWS_UWP
[StructLayout(LayoutKind.Sequential)]
public struct MultiQueryInterface
{
public IntPtr InterfaceIID;
public IntPtr IUnknownPointer;
public Result ResultCode;
};
[DllImport("api-ms-win-core-com-l1-1-0.dll", ExactSpelling = true, EntryPoint = "CoCreateInstanceFromApp", PreserveSig = true)]
private static extern Result CoCreateInstanceFromApp([In, MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
IntPtr pUnkOuter,
CLSCTX dwClsContext,
IntPtr reserved,
int countMultiQuery,
ref MultiQueryInterface query);
internal unsafe static void CreateComInstance(Guid clsid, CLSCTX clsctx, Guid riid, ComObject comObject)
{
MultiQueryInterface localQuery = new MultiQueryInterface()
{
InterfaceIID = new IntPtr(&riid),
IUnknownPointer = IntPtr.Zero,
ResultCode = 0,
};
var result = CoCreateInstanceFromApp(clsid, IntPtr.Zero, clsctx, IntPtr.Zero, 1, ref localQuery);
result.CheckError();
localQuery.ResultCode.CheckError();
comObject.NativePointer = localQuery.IUnknownPointer;
}
internal unsafe static bool TryCreateComInstance(Guid clsid, CLSCTX clsctx, Guid riid, ComObject comObject)
{
MultiQueryInterface localQuery = new MultiQueryInterface()
{
InterfaceIID = new IntPtr(&riid),
IUnknownPointer = IntPtr.Zero,
ResultCode = 0,
};
var result = CoCreateInstanceFromApp(clsid, IntPtr.Zero, clsctx, IntPtr.Zero, 1, ref localQuery);
comObject.NativePointer = localQuery.IUnknownPointer;
return result.Success && localQuery.ResultCode.Success;
}
#else
[DllImport("ole32.dll", ExactSpelling = true, EntryPoint = "CoCreateInstance", PreserveSig = true)]
private static extern Result CoCreateInstance([In, MarshalAs(UnmanagedType.LPStruct)] Guid rclsid, IntPtr pUnkOuter, CLSCTX dwClsContext, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IntPtr comObject);
internal static void CreateComInstance(Guid clsid, CLSCTX clsctx, Guid riid, ComObject comObject)
{
IntPtr pointer;
var result = CoCreateInstance(clsid, IntPtr.Zero, clsctx, riid, out pointer);
result.CheckError();
comObject.NativePointer = pointer;
}
internal static bool TryCreateComInstance(Guid clsid, CLSCTX clsctx, Guid riid, ComObject comObject)
{
IntPtr pointer;
var result = CoCreateInstance(clsid, IntPtr.Zero, clsctx, riid, out pointer);
comObject.NativePointer = pointer;
return result.Success;
}
#endif
/// <summary>Determines the concurrency model used for incoming calls to objects created by this thread. This concurrency model can be either apartment-threaded or multi-threaded.</summary>
public enum CoInit
{
/// <summary>
/// Initializes the thread for apartment-threaded object concurrency.
/// </summary>
MultiThreaded = 0x0,
/// <summary>
/// Initializes the thread for multi-threaded object concurrency.
/// </summary>
ApartmentThreaded = 0x2,
/// <summary>
/// Disables DDE for OLE1 support.
/// </summary>
DisableOle1Dde = 0x4,
/// <summary>
/// Trade memory for speed.
/// </summary>
SpeedOverMemory = 0x8
}
#if WINDOWS_UWP
[DllImport("api-ms-win-core-handle-l1-1-0.dll", EntryPoint = "CloseHandle", SetLastError = true)]
internal static extern bool CloseHandle(IntPtr handle);
#else
[DllImport("kernel32.dll", EntryPoint = "CloseHandle", SetLastError = true)]
internal static extern bool CloseHandle(IntPtr handle);
#endif
/// <summary>
/// Gets the proc address of a DLL.
/// </summary>
/// <param name="handle">The handle.</param>
/// <param name="dllFunctionToImport">The DLL function to import.</param>
/// <exception cref="SharpDXException">If the function was not found.</exception>
/// <returns>Pointer to address of the exported function or variable.</returns>
public static IntPtr GetProcAddress(IntPtr handle, string dllFunctionToImport)
{
IntPtr result = GetProcAddress_(handle, dllFunctionToImport);
if (result == IntPtr.Zero)
throw new SharpDXException(dllFunctionToImport);
return result;
}
#if WINDOWS_UWP
[DllImport("api-ms-win-core-libraryloader-l1-1-1.dll", EntryPoint = "GetProcAddress", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
static extern IntPtr GetProcAddress_(IntPtr hModule, string procName);
#else
// http://www.pinvoke.net/default.aspx/kernel32.getprocaddress
// http://stackoverflow.com/questions/3754264/c-sharp-getprocaddress-returns-zero
[DllImport("kernel32", EntryPoint = "GetProcAddress", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
static extern IntPtr GetProcAddress_(IntPtr hModule, string procName);
#endif
/// <summary>
/// Compute a FNV1-modified Hash from <a href="http://bretm.home.comcast.net/~bretm/hash/6.html">Fowler/Noll/Vo Hash</a> improved version.
/// </summary>
/// <param name="data">Data to compute the hash from.</param>
/// <returns>A hash value.</returns>
public static int ComputeHashFNVModified(byte[] data)
{
const uint p = 16777619;
uint hash = 2166136261;
foreach (byte b in data)
hash = (hash ^ b) * p;
hash += hash << 13;
hash ^= hash >> 7;
hash += hash << 3;
hash ^= hash >> 17;
hash += hash << 5;
return unchecked((int)hash);
}
/// <summary>
/// Safely dispose a reference if not null, and set it to null after dispose.
/// </summary>
/// <typeparam name="T">The type of COM interface to dispose.</typeparam>
/// <param name="comObject">Object to dispose.</param>
/// <remarks>
/// The reference will be set to null after dispose.
/// </remarks>
public static void Dispose<T>(ref T comObject) where T : class, IDisposable
{
if (comObject != null)
{
comObject.Dispose();
comObject = null;
}
}
/// <summary>
/// Transforms an <see cref="IEnumerable{T}"/> to an array of T.
/// </summary>
/// <typeparam name="T">Type of the element</typeparam>
/// <param name="source">The enumerable source.</param>
/// <returns>an array of T</returns>
public static T[] ToArray<T>(IEnumerable<T> source)
{
return new Buffer<T>(source).ToArray();
}
/// <summary>
/// Test if there is an element in this enumeration.
/// </summary>
/// <typeparam name="T">Type of the element</typeparam>
/// <param name="source">The enumerable source.</param>
/// <returns><c>true</c> if there is an element in this enumeration, <c>false</c> otherwise</returns>
public static bool Any<T>(IEnumerable<T> source)
{
return source.GetEnumerator().MoveNext();
}
/// <summary>
/// Select elements from an enumeration.
/// </summary>
/// <typeparam name="TSource">The type of the T source.</typeparam>
/// <typeparam name="TResult">The type of the T result.</typeparam>
/// <param name="source">The source.</param>
/// <param name="selector">The selector.</param>
/// <returns>A enumeration of selected values</returns>
public static IEnumerable<TResult> SelectMany<TSource, TResult>(IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector)
{
foreach (TSource sourceItem in source)
{
foreach (TResult result in selector(sourceItem))
yield return result;
}
}
/// <summary>
/// Selects distinct elements from an enumeration.
/// </summary>
/// <typeparam name="TSource">The type of the T source.</typeparam>
/// <param name="source">The source.</param>
/// <param name="comparer">The comparer.</param>
/// <returns>A enumeration of selected values</returns>
public static IEnumerable<TSource> Distinct<TSource>(IEnumerable<TSource> source, IEqualityComparer<TSource> comparer = null)
{
if (comparer == null)
comparer = EqualityComparer<TSource>.Default;
// using Dictionary is not really efficient but easy to implement
var values = new Dictionary<TSource, object>(comparer);
foreach (TSource sourceItem in source)
{
if (!values.ContainsKey(sourceItem))
{
values.Add(sourceItem, null);
yield return sourceItem;
}
}
}
internal struct Buffer<TElement>
{
internal TElement[] items;
internal int count;
internal Buffer(IEnumerable<TElement> source)
{
var array = (TElement[])null;
int length = 0;
var collection = source as ICollection<TElement>;
if (collection != null)
{
length = collection.Count;
if (length > 0)
{
array = new TElement[length];
collection.CopyTo(array, 0);
}
}
else
{
foreach (TElement element in source)
{
if (array == null)
array = new TElement[4];
else if (array.Length == length)
{
var elementArray = new TElement[checked(length * 2)];
Array.Copy(array, 0, elementArray, 0, length);
array = elementArray;
}
array[length] = element;
++length;
}
}
items = array;
count = length;
}
internal TElement[] ToArray()
{
if (count == 0)
return new TElement[0];
if (items.Length == count)
return items;
var elementArray = new TElement[count];
Array.Copy(items, 0, elementArray, 0, count);
return elementArray;
}
}
/// <summary>
/// Determines whether the type inherits from the specified type (used to determine a type without using an explicit type instance).
/// </summary>
/// <param name="type">The type.</param>
/// <param name="parentType">Name of the parent type to find in inheritance hierarchy of type.</param>
/// <returns><c>true</c> if the type inherits from the specified type; otherwise, <c>false</c>.</returns>
public static bool IsTypeInheritFrom(Type type, string parentType)
{
while (type != null)
{
if (type.FullName == parentType)
{
return true;
}
type = type.GetTypeInfo().BaseType;
}
return false;
}
}
}