// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. // // Copyright (c) 2010-2012 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. #pragma warning disable SA1405 // Debug.Assert must provide message text using att; using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; using System.Text; using System.Threading; namespace lib { /// /// Utility class. /// public static class Util { /* #if XENKO_PLATFORM_UWP public static unsafe void CopyMemory(IntPtr dest, IntPtr src, int sizeInBytesToCopy) { Interop.memcpy((void*)dest, (void*)src, sizeInBytesToCopy); } #else #if XENKO_PLATFORM_WINDOWS_DESKTOP private const string MemcpyDll = "msvcrt.dll"; #elif XENKO_PLATFORM_ANDROID private const string MemcpyDll = "libc.so"; #elif XENKO_PLATFORM_UNIX // We do not specifiy the .so extension as libc.so on Linux // is actually not a .so files but a script. Using just libc // will automatically find the corresponding .so. private const string MemcpyDll = "libc"; #elif XENKO_PLATFORM_IOS private const string MemcpyDll = ObjCRuntime.Constants.SystemLibrary; #else # error Unsupported platform #endif [DllImport(MemcpyDll, EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)] #if !XENKO_RUNTIME_CORECLR [SuppressUnmanagedCodeSecurity] #endif private static extern IntPtr CopyMemory(IntPtr dest, IntPtr src, ulong sizeInBytesToCopy); /// /// Copy memory. /// /// The destination memory location /// The source memory location. /// The count. public static void CopyMemory(IntPtr dest, IntPtr src, int sizeInBytesToCopy) { CopyMemory(dest, src, (ulong)sizeInBytesToCopy); } #endif */ public static void checkAndAddDirectory( string path ) { if( !Directory.Exists( path ) ) { lib.Log.info( "Creating directory {0}", path ); Directory.CreateDirectory( path ); } } /// /// Compares two block of memory. /// /// The pointer to compare from. /// The pointer to compare against. /// The size in bytes to compare. /// True if the buffers are equivalent, false otherwise. public static unsafe bool CompareMemory(IntPtr from, IntPtr against, int sizeToCompare) { var pSrc = (byte*)from; var pDst = (byte*)against; // Compare 8 bytes. var 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; } /// /// Clears the memory. /// /// The dest. /// The value. /// The size in bytes to clear. public static void ClearMemory(IntPtr dest, byte value, int sizeInBytesToClear) { unsafe { Interop.memset((void*)dest, value, sizeInBytesToClear); } } /// /// Return the sizeof a struct from a CLR. Equivalent to sizeof operator but works on generics too. /// /// a struct to evaluate /// sizeof this struct public static int SizeOf() where T : struct { return Interop.SizeOf(); } /// /// Return the sizeof an array of struct. Equivalent to sizeof operator but works on generics too. /// /// a struct /// The array of struct to evaluate. /// sizeof in bytes of this array of struct public static int SizeOf(T[] array) where T : struct { return array == null ? 0 : array.Length * Interop.SizeOf(); } /// /// Pins the specified source and call an action with the pinned pointer. /// /// The type of the structure to pin /// The source. /// The pin action to perform on the pinned pointer. public static void Pin(ref T source, Action pinAction) where T : struct { unsafe { pinAction((IntPtr)Interop.Fixed(ref source)); } } /// /// Pins the specified source and call an action with the pinned pointer. /// /// The type of the structure to pin /// The source array. /// The pin action to perform on the pinned pointer. public static void Pin(T[] source, [NotNull] Action pinAction) where T : struct { unsafe { pinAction(source == null ? IntPtr.Zero : (IntPtr)Interop.Fixed(source)); } } /// /// Covnerts a structured array to an equivalent byte array. /// /// The source. /// The byte array. public static byte[] ToByteArray(T[] source) where T : struct { if (source == null) return null; var buffer = new byte[SizeOf() * source.Length]; if (source.Length == 0) return buffer; unsafe { fixed (void* pBuffer = buffer) Interop.Write(pBuffer, source, 0, source.Length); } return buffer; } /// /// Reads the specified T data from a memory location. /// /// Type of a data to read /// Memory location to read from. /// The data read from the memory location public static T Read(IntPtr source) where T : struct { unsafe { return Interop.ReadInline((void*)source); } } /// /// Reads the specified T data from a memory location. /// /// Type of a data to read /// Memory location to read from. /// The data write to. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Read(IntPtr source, ref T data) where T : struct { unsafe { Interop.CopyInline(ref data, (void*)source); } } /// /// Reads the specified T data from a memory location. /// /// Type of a data to read /// Memory location to read from. /// The data write to. public static void ReadOut(IntPtr source, out T data) where T : struct { unsafe { Interop.CopyInlineOut(out data, (void*)source); } } /// /// Reads the specified T data from a memory location. /// /// Type of a data to read /// Memory location to read from. /// The data write to. /// source pointer + sizeof(T) public static IntPtr ReadAndPosition(IntPtr source, ref T data) where T : struct { unsafe { return (IntPtr)Interop.Read((void*)source, ref data); } } /// /// Reads the specified array T[] data from a memory location. /// /// Type of a data to read /// Memory location to read from. /// The data write to. /// The offset in the array to write to. /// The number of T element to read from the memory location /// source pointer + sizeof(T) * count public static IntPtr Read(IntPtr source, T[] data, int offset, int count) where T : struct { unsafe { return (IntPtr)Interop.Read((void*)source, data, offset, count); } } /// /// Writes the specified T data to a memory location. /// /// Type of a data to write /// Memory location to write to. /// The data to write. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Write(IntPtr destination, ref T data) where T : struct { unsafe { Interop.CopyInline((void*)destination, ref data); } } /// /// Writes the specified T data to a memory location. /// /// Type of a data to write /// Memory location to write to. /// The data to write. /// destination pointer + sizeof(T) public static IntPtr WriteAndPosition(IntPtr destination, ref T data) where T : struct { unsafe { return (IntPtr)Interop.Write((void*)destination, ref data); } } /// /// Writes the specified array T[] data to a memory location. /// /// Type of a data to write /// Memory location to write to. /// The array of T data to write. /// The offset in the array to read from. /// The number of T element to write to the memory location public static void Write(byte[] destination, T[] data, int offset, int count) where T : struct { unsafe { fixed (void* pDest = destination) { Write((IntPtr)pDest, data, offset, count); } } } /// /// Writes the specified array T[] data to a memory location. /// /// Type of a data to write /// Memory location to write to. /// The array of T data to write. /// The offset in the array to read from. /// The number of T element to write to the memory location /// destination pointer + sizeof(T) * count public static IntPtr Write(IntPtr destination, T[] data, int offset, int count) where T : struct { unsafe { return (IntPtr)Interop.Write((void*)destination, data, offset, count); } } /// /// Allocate an aligned memory buffer. /// /// Size of the buffer to allocate. /// Alignment, a positive value which is a power of 2. 16 bytes by default. /// A pointer to a buffer aligned. /// /// To free this buffer, call /// public static unsafe IntPtr AllocateMemory(int sizeInBytes, int align = 16) { var mask = align - 1; if ((align & mask) != 0) { throw new ArgumentException("Alignment is not power of 2", nameof(align)); } var memPtr = Marshal.AllocHGlobal(sizeInBytes + mask + sizeof(void*)); var ptr = (byte*)((ulong)(memPtr.ToInt32() + sizeof(void*) + mask) & ~(ulong)mask); ((IntPtr*)ptr)[-1] = memPtr; return new IntPtr(ptr); } /// /// Allocate an aligned memory buffer and clear it with a specified value (0 by defaault). /// /// Size of the buffer to allocate. /// Default value used to clear the buffer. /// Alignment, 16 bytes by default. /// A pointer to a buffer aligned. /// /// To free this buffer, call /// public static IntPtr AllocateClearedMemory(int sizeInBytes, byte clearValue = 0, int align = 16) { var ptr = AllocateMemory(sizeInBytes, align); ClearMemory(ptr, clearValue, sizeInBytes); return ptr; } /// /// Determines whether the specified memory pointer is aligned in memory. /// /// The memory pointer. /// The align. /// true if the specified memory pointer is aligned in memory; otherwise, false. public static bool IsMemoryAligned(IntPtr memoryPtr, int align = 16) { return (memoryPtr.ToInt64() & (align - 1)) == 0; } /// /// Allocate an aligned memory buffer. /// /// /// The buffer must have been allocated with /// public static unsafe void FreeMemory(IntPtr alignedBuffer) { Marshal.FreeHGlobal(((IntPtr*)alignedBuffer)[-1]); } /// /// If non-null, disposes the specified object and set it to null, otherwise do nothing. /// /// The disposable. public static void Dispose(ref T disposable) where T : class, IDisposable { if (disposable != null) { disposable.Dispose(); disposable = null; } } /// /// String helper join method to display an array of object as a single string. /// /// The separator. /// The array. /// a string with array elements serparated by the seperator [NotNull] public static string Join(string separator, T[] array) { var text = new StringBuilder(); if (array != null) { for (var i = 0; i < array.Length; i++) { if (i > 0) text.Append(separator); text.Append(array[i]); } } return text.ToString(); } /// /// String helper join method to display an enumrable of object as a single string. /// /// The separator. /// The enumerable. /// a string with array elements serparated by the seperator [NotNull] public static string Join(string separator, [NotNull] IEnumerable elements) { var elementList = new List(); foreach (var element in elements) elementList.Add(element.ToString()); var text = new StringBuilder(); for (var i = 0; i < elementList.Count; i++) { var element = elementList[i]; if (i > 0) text.Append(separator); text.Append(element); } return text.ToString(); } /// /// String helper join method to display an enumrable of object as a single string. /// /// The separator. /// The enumerable. /// a string with array elements serparated by the seperator [NotNull] public static string Join(string separator, [NotNull] IEnumerator elements) { var elementList = new List(); while (elements.MoveNext()) elementList.Add(elements.Current.ToString()); var text = new StringBuilder(); for (var i = 0; i < elementList.Count; i++) { var element = elementList[i]; if (i > 0) text.Append(separator); text.Append(element); } return text.ToString(); } /// /// Read stream to a byte[] buffer /// /// input stream /// a byte[] buffer [NotNull] public static byte[] ReadStream([NotNull] Stream stream) { var readLength = 0; return ReadStream(stream, ref readLength); } /// /// Read stream to a byte[] buffer /// /// input stream /// length to read /// a byte[] buffer [NotNull] public static byte[] ReadStream([NotNull] Stream stream, ref int readLength) { System.Diagnostics.Debug.Assert(stream != null); System.Diagnostics.Debug.Assert(stream.CanRead); var num = readLength; System.Diagnostics.Debug.Assert(num <= (stream.Length - stream.Position)); if (num == 0) readLength = (int)(stream.Length - stream.Position); num = readLength; System.Diagnostics.Debug.Assert(num >= 0); if (num == 0) return new byte[0]; var buffer = new byte[num]; var bytesRead = 0; if (num > 0) { do { bytesRead += stream.Read(buffer, bytesRead, readLength - bytesRead); } while (bytesRead < readLength); } return buffer; } /// /// Computes a hashcode for a dictionary. /// /// Hashcode for the list. public static int GetHashCode(IDictionary dict) { if (dict == null) return 0; var hashCode = 0; foreach (DictionaryEntry keyValue in dict) { hashCode = (hashCode * 397) ^ keyValue.Key.GetHashCode(); hashCode = (hashCode * 397) ^ (keyValue.Value?.GetHashCode() ?? 0); } return hashCode; } /// /// Computes a hashcode for an enumeration /// /// An enumerator. /// Hashcode for the list. public static int GetHashCode(IEnumerable it) { if (it == null) return 0; var hashCode = 0; foreach (var current in it) { hashCode = (hashCode * 397) ^ (current?.GetHashCode() ?? 0); } return hashCode; } /// /// Computes a hashcode for an enumeration /// /// An enumerator. /// Hashcode for the list. public static int GetHashCode(IEnumerator it) { if (it == null) return 0; var hashCode = 0; while (it.MoveNext()) { var current = it.Current; hashCode = (hashCode * 397) ^ (current?.GetHashCode() ?? 0); } return hashCode; } /// /// Compares two collection, element by elements. /// /// A "from" enumerator. /// A "to" enumerator. /// True if lists are identical. False otherwise. 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()); } /// /// Compares two collection, element by elements. /// /// A "from" enumerator. /// A "to" enumerator. /// True if lists are identical. False otherwise. 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; } /// /// Compares two collection, element by elements. /// /// The collection to compare from. /// The colllection to compare to. /// True if lists are identical (but no necessarely of the same time). False otherwise. public static bool Compare(IDictionary first, IDictionary second) { if (ReferenceEquals(first, second)) return true; if (ReferenceEquals(first, null) || ReferenceEquals(second, null)) return false; if (first.Count != second.Count) return false; var comparer = EqualityComparer.Default; foreach (var keyValue in first) { TValue secondValue; if (!second.TryGetValue(keyValue.Key, out secondValue)) return false; if (!comparer.Equals(keyValue.Value, secondValue)) return false; } // Check that all keys in second are in first return second.Keys.All(first.ContainsKey); } public static bool Compare(T[] left, T[] right) { if (ReferenceEquals(left, right)) return true; if (ReferenceEquals(left, null) || ReferenceEquals(right, null)) return false; if (left.Length != right.Length) return false; var comparer = EqualityComparer.Default; for (var i = 0; i < left.Length; ++i) { if (!comparer.Equals(left[i], right[i])) return false; } return true; } /// /// Compares two collection, element by elements. /// /// The collection to compare from. /// The colllection to compare to. /// True if lists are identical (but no necessarely of the same time). False otherwise. 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; var count = 0; var leftIt = left.GetEnumerator(); var rightIt = right.GetEnumerator(); var comparer = EqualityComparer.Default; while (leftIt.MoveNext() && rightIt.MoveNext()) { if (!comparer.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; } /// /// Swaps the value between two references. /// /// Type of a data to swap. /// The left value. /// The right value. public static void Swap(ref T left, ref T right) { var temp = left; left = right; right = temp; } /// /// Suspends current thread for a . /// /// The duration of sleep. public static void Sleep(TimeSpan sleepTime) { var ms = (long)sleepTime.TotalMilliseconds; if (ms < 0 || ms > int.MaxValue) { throw new ArgumentOutOfRangeException(nameof(sleepTime), "Sleep time must be a duration less than '2^31 - 1' milliseconds."); } // MH PORTED NativeInvoke.Sleep((int)ms); Thread.Sleep( (int)ms ); } /// /// Suspends current thread for a . /// /// The duration of sleep in milliseconds. public static void Sleep(int sleepTimeInMillis) { // MH PORTED NativeInvoke.Sleep(sleepTimeInMillis); Thread.Sleep( sleepTimeInMillis ); } /// /// Writes the specified T data to a memory location. /// /// Type of a data to write /// Memory location to write to. /// The data to write. internal static void UnsafeWrite(IntPtr destination, ref T data) { unsafe { Interop.CopyInline((void*)destination, ref data); } } /// /// Reads the specified T data from a memory location. /// /// Type of a data to read /// Memory location to read from. /// The data write to. internal static void UnsafeReadOut(IntPtr source, out T data) { unsafe { Interop.CopyInlineOut(out data, (void*)source); } } /// /// Return the sizeof a struct from a CLR. Equivalent to sizeof operator but works on generics too. /// /// a struct to evaluate /// sizeof this struct internal static int UnsafeSizeOf() { return Interop.SizeOf(); } /// /// Linq assisted full tree iteration and collection in a single line. /// Warning, could be slow. /// /// The type to iterate. /// The root item /// The function to retrieve a child public static IEnumerable IterateTree(T root, Func> childrenF) { var q = new List { root }; while (q.Any()) { var c = q[0]; q.RemoveAt(0); q.AddRange(childrenF(c) ?? Enumerable.Empty()); yield return c; } } /// /// Converts a raw time to a . /// /// The delta. /// The . public static TimeSpan ConvertRawToTimestamp(long delta) { return new TimeSpan(delta == 0 ? 0 : (delta * TimeSpan.TicksPerSecond) / Stopwatch.Frequency); } } }