// 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 {path}" ); Directory.CreateDirectory( path ); } else { lib.Log.debug( $"{path} already exists." ); } } /// /// 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 ); } } }