public void TestEqual() { // Define variables and constants const string DOG_STRING_A = "Dog"; const string DOG_STRING_B = "Dog"; const string CAT_STRING = "Cat"; // Set up context // Execute Assure.Equal(DOG_STRING_A, DOG_STRING_B); try { Assure.Equal(DOG_STRING_A, CAT_STRING); Assert.Fail(); } catch (AssuranceFailedException) { } Assure.Equal(1, 1); try { Assure.Equal(1, 2); Assert.Fail(); } catch (AssuranceFailedException) { } // Assert outcome }
public static TOut Reinterpret <TIn, TOut>(TIn curValue, int sizeBytes) where TIn : struct where TOut : struct { Assure.Equal(SizeOf <TIn>(), SizeOf <TOut>(), "TOut must be a type of identical byte size to TIn."); Assure.Equal( sizeBytes, SizeOf <TIn>(), "Provided sizeBytes value (" + sizeBytes + ") is incorrect (sizeof(TIn) == " + SizeOf <TIn>() + ")" ); Assure.True(typeof(TIn).IsBlittable(), "TIn type is not blittable."); Assure.True(typeof(TOut).IsBlittable(), "TOut type is not blittable."); TOut result = default(TOut); /* What I'm doing is using TypedReference as { IntPtr, IntPtr }; * where the first IntPtr is a pointer to the __makeref referenced value type */ TypedReference resultRef = __makeref(result); byte * resultPtr = (byte *)*((IntPtr *)&resultRef); // Now do the same with curValue TypedReference curValueRef = __makeref(curValue); byte * curValuePtr = (byte *)*((IntPtr *)&curValueRef); // Finally, copy for (int i = 0; i < sizeBytes; ++i) { resultPtr[i] = curValuePtr[i]; } return(result); }
/// <summary> /// Builds a matrix from the values in the given array. The array slice <see cref="ArraySlice{T}.Length"/> must be /// exactly <c>16</c>. /// </summary> /// <param name="values">The values to build this Matrix from. The values will be interpreted in row-by-row order, /// i.e. the first four values will constitute <see cref="RowA"/>, the second four <see cref="RowB"/>, etc.</param> public Matrix(ArraySlice <float> values) { Assure.Equal(values.Length, 16); RowA = new Vector4(values[0], values[1], values[2], values[3]); RowB = new Vector4(values[4], values[5], values[6], values[7]); RowC = new Vector4(values[8], values[9], values[10], values[11]); RowD = new Vector4(values[12], values[13], values[14], values[15]); }
public void MasterWaitOnExternalLock(object lockObj, Func <bool> completionPredicate) { Assure.NotNull(lockObj); Assure.NotNull(completionPredicate); Assure.True(Monitor.IsEntered(lockObj)); Assure.Equal(Thread.CurrentThread, LosgapSystem.MasterThread); Monitor.Enter(externalLockObjLock); externalLockObj = lockObj; try { while (!completionPredicate()) { while (masterInvocationQueue.Count > 0) { PipelineMasterInvocation pmi; if (!masterInvocationQueue.TryDequeue(out pmi)) { continue; } try { if (pmi.IsSynchronousCall) { Monitor.Enter(pmi.InvocationCompleteMonitor); pmi.Action(); } else { pmi.Action(); } } catch (Exception e) { if (pmi.IsSynchronousCall) { pmi.RaisedException = e; } else { LosgapSystem.ExitWithError("Exception raised in asynchronous pipeline master invocation.", e); } } finally { if (pmi.IsSynchronousCall) { Monitor.Pulse(pmi.InvocationCompleteMonitor); Monitor.Exit(pmi.InvocationCompleteMonitor); } } } Monitor.Exit(externalLockObjLock); Monitor.Wait(lockObj); Monitor.Enter(externalLockObjLock); } } finally { externalLockObj = null; Monitor.Exit(externalLockObjLock); } }
/// <summary> /// Freeze mutations to sensitive state, blocking any callers to <see cref="AcquirePermit()"/>. /// This method will block if mutations are currently ongoing on another thread; and will return once all active <see cref="MutationPermit"/>s /// have been disposed. /// </summary> public void FreezeMutations() { Assure.False(Monitor.IsEntered(freezeLock), "MutationPermits have not been disposed on current thread or mutations are already frozen."); Monitor.Enter(freezeLock); var msb = LosgapSystem.ActiveMSB; if (msb != null) { msb.MasterWaitOnExternalLock(freezeLock, freezeMasterBlockPredicate); } Assure.Equal(activeMutatorsCounter, 0); }
public void MasterOpenBarrier() { Assure.Equal(Thread.CurrentThread, LosgapSystem.MasterThread); Monitor.Enter(barrierClosedLock); if (numSlaves > 0U) { barrierOpen = true; slavesRemaining = numSlaves; } Monitor.PulseAll(barrierClosedLock); Monitor.Exit(barrierClosedLock); }
public static void WriteGenericToPtr <T>(IntPtr dest, T value, int sizeOfT) where T : struct { Assure.False(dest == IntPtr.Zero); Assure.True(typeof(T).IsBlittable()); Assure.Equal(sizeOfT, (uint)SizeOf <T>()); byte * bytePtr = (byte *)dest; TypedReference valueref = __makeref(value); byte * valuePtr = (byte *)*((IntPtr *)&valueref); for (uint i = 0U; i < sizeOfT; ++i) { bytePtr[i] = valuePtr[i]; } }
public void MasterWaitForClose() { Assure.Equal(Thread.CurrentThread, LosgapSystem.MasterThread); Monitor.Enter(barrierOpenLock); hydrateInvocationQueue: while (masterInvocationQueue.Count > 0) { PipelineMasterInvocation pmi; if (!masterInvocationQueue.TryDequeue(out pmi)) { continue; } try { if (pmi.IsSynchronousCall) { Monitor.Enter(pmi.InvocationCompleteMonitor); pmi.Action(); } else { pmi.Action(); } } catch (Exception e) { if (pmi.IsSynchronousCall) { pmi.RaisedException = e; } else { LosgapSystem.ExitWithError("Exception raised in asynchronous pipeline master invocation.", e); } } finally { if (pmi.IsSynchronousCall) { Monitor.Pulse(pmi.InvocationCompleteMonitor); Monitor.Exit(pmi.InvocationCompleteMonitor); } } } if (barrierOpen) { Monitor.Wait(barrierOpenLock); goto hydrateInvocationQueue; } Monitor.Exit(barrierOpenLock); }
/// <summary> /// Copies data from the <paramref name="source"/> pointer to the <paramref name="destination"/> array. /// </summary> /// <typeparam name="T">The array element type. Must be a <see cref="Extensions.IsBlittable">blittable</see> struct.</typeparam> /// <param name="source">The pointer to the source data. Must not be <see cref="IntPtr.Zero"/>.</param> /// <param name="destination">The destination array to which the data will be copied. This method will copy /// <see cref="ArraySlice{T}.Length"/> elements' worth of data, starting at the <see cref="ArraySlice{T}.Offset"/>.</param> /// <param name="arrayElementSizeBytes">The size of <typeparamref name="T"/>. Use either sizeof() (preferred), or /// <see cref="SizeOf{T}"/> if the type is not known at compile-time.</param> public static unsafe void CopyGenericArray <T>(IntPtr source, ArraySlice <T> destination, uint arrayElementSizeBytes) where T : struct { Assure.False(source == IntPtr.Zero); Assure.True(typeof(T).IsBlittable()); Assure.Equal((int)arrayElementSizeBytes, SizeOf <T>()); GCHandle pinnedArrayHandle = GCHandle.Alloc(destination.ContainingArray, GCHandleType.Pinned); try { MemCopy(source, pinnedArrayHandle.AddrOfPinnedObject() + (int)(arrayElementSizeBytes * destination.Offset), destination.Length * arrayElementSizeBytes); } finally { pinnedArrayHandle.Free(); } }
public static T ReadGenericFromPtr <T>(IntPtr source, int sizeOfT) where T : struct { Assure.False(source == IntPtr.Zero); Assure.True(typeof(T).IsBlittable()); Assure.Equal(sizeOfT, (uint)SizeOf <T>()); byte *bytePtr = (byte *)source; T result = default(T); TypedReference resultRef = __makeref(result); byte * resultPtr = (byte *)*((IntPtr *)&resultRef); for (uint i = 0U; i < sizeOfT; ++i) { resultPtr[i] = bytePtr[i]; } return(result); }
public void Execute(int numAtomics, int blockSize, Action <int> atomicAction) { Assure.Equal(Thread.CurrentThread, LosgapSystem.MasterThread, "Execution of parallel processor should be from master thread."); Assure.NotNull(atomicAction); currentAction = atomicAction; currentBlockSize = blockSize; int numFullBlocks = numAtomics / blockSize; numReservableBlocks = numFullBlocks; currentWorkIsInvokeAllAction = false; bool singleThreadedMode = ForceSingleThreadedMode; if (!singleThreadedMode) { WorkBarrier.MasterOpenBarrier(); } // Do the 'odd-sized' ending block for (int i = blockSize * numFullBlocks; i < numAtomics; ++i) { atomicAction(i); } for (int blockIndex = Interlocked.Decrement(ref numReservableBlocks); blockIndex >= 0; blockIndex = Interlocked.Decrement(ref numReservableBlocks)) { int blockStartInc = currentBlockSize * blockIndex; int blockEndEx = currentBlockSize * (blockIndex + 1); for (int i = blockStartInc; i < blockEndEx; ++i) { currentAction(i); } } if (!singleThreadedMode) { WorkBarrier.MasterWaitForClose(); } }
/// <summary> /// Invokes the given <paramref name="action"/> on all slave threads, and also the master thread (invoking thread) if /// <paramref name="includeMaster"/> is <c>true</c>. /// </summary> /// <remarks>This method can only be invoked from the <see cref="LosgapSystem.MasterThread"/>.</remarks> /// <param name="action">The action to invoke on all threads. Must not be null.</param> /// <param name="includeMaster">True if this action should be executed by the calling (master) thread as well.</param> public void InvokeOnAll(Action action, bool includeMaster) { Assure.Equal(Thread.CurrentThread, LosgapSystem.MasterThread, "Invocation of parallel processor should be from master thread."); Assure.NotNull(action); currentInvokeAllAction = action; currentWorkIsInvokeAllAction = true; bool singleThreadedMode = ForceSingleThreadedMode; if (!singleThreadedMode) { WorkBarrier.MasterOpenBarrier(); } if (includeMaster) { currentInvokeAllAction(); } if (!singleThreadedMode) { WorkBarrier.MasterWaitForClose(); } }
private bool FreezeMasterBlockPredicate() { Assure.True(Monitor.IsEntered(freezeLock)); Assure.Equal(Thread.CurrentThread, LosgapSystem.MasterThread); return(activeMutatorsCounter == 0); }
/// <summary> /// Determines the first point on the cuboid that is touched by this ray. /// </summary> /// <param name="other">The cuboid to test for intersection with this ray.</param> /// <returns>A <see cref="Vector3"/> indicating the first point on the cuboid edge touched by this ray, /// or <c>null</c> if no intersection occurs.</returns> // Based on "Fast Ray-Box Intersection" algorithm by Andrew Woo, "Graphics Gems", Academic Press, 1990 public unsafe Vector3?IntersectionWith(Cuboid other) { const int NUM_DIMENSIONS = 3; Assure.Equal(NUM_DIMENSIONS, 3); // If that value is ever changed, this algorithm will need some maintenance const byte QUADRANT_MIN = 0; const byte QUADRANT_MAX = 1; const byte QUADRANT_BETWEEN = 2; // Step 1: Work out which direction from the start point to test for intersection for all 3 dimensions, and the distance byte * quadrants = stackalloc byte[NUM_DIMENSIONS]; float *candidatePlanes = stackalloc float[NUM_DIMENSIONS]; float *cuboidMinPoints = stackalloc float[NUM_DIMENSIONS]; float *cuboidMaxPoints = stackalloc float[NUM_DIMENSIONS]; bool startPointIsInsideCuboid = true; cuboidMinPoints[0] = other.FrontBottomLeft.X; cuboidMinPoints[1] = other.FrontBottomLeft.Y; cuboidMinPoints[2] = other.FrontBottomLeft.Z; cuboidMaxPoints[0] = other.FrontBottomLeft.X + other.Width; cuboidMaxPoints[1] = other.FrontBottomLeft.Y + other.Height; cuboidMaxPoints[2] = other.FrontBottomLeft.Z + other.Depth; for (byte i = 0; i < NUM_DIMENSIONS; ++i) { if (StartPoint[i] < cuboidMinPoints[i]) { quadrants[i] = QUADRANT_MIN; candidatePlanes[i] = cuboidMinPoints[i]; startPointIsInsideCuboid = false; } else if (StartPoint[i] > cuboidMaxPoints[i]) { quadrants[i] = QUADRANT_MAX; candidatePlanes[i] = cuboidMaxPoints[i]; startPointIsInsideCuboid = false; } else { quadrants[i] = QUADRANT_BETWEEN; } } if (startPointIsInsideCuboid) { return(StartPoint); } // Step 2: Find farthest dimension from cuboid float maxDistance = Single.NegativeInfinity; byte maxDistanceDimension = 0; for (byte i = 0; i < NUM_DIMENSIONS; ++i) { // ReSharper disable once CompareOfFloatsByEqualityOperator Exact check is desired here: Anything other than 0f is usable if (quadrants[i] != QUADRANT_BETWEEN && Orientation[i] != 0f) { float thisDimensionDist = (candidatePlanes[i] - StartPoint[i]) / Orientation[i]; if (thisDimensionDist > maxDistance) { maxDistance = thisDimensionDist; maxDistanceDimension = i; } } } float errorMargin = MathUtils.FlopsErrorMargin; if (maxDistance < 0f || maxDistance - Length > errorMargin) { return(null); } // Step 3: Find potential intersection point float *intersectionPoint = stackalloc float[NUM_DIMENSIONS]; for (byte i = 0; i < NUM_DIMENSIONS; ++i) { if (maxDistanceDimension == i) { intersectionPoint[i] = StartPoint[i] + maxDistance * Orientation[i]; if (cuboidMinPoints[i] - intersectionPoint[i] > errorMargin || intersectionPoint[i] - cuboidMaxPoints[i] > errorMargin) { return(null); } } else { intersectionPoint[i] = candidatePlanes[i]; } } Vector3 result = new Vector3(intersectionPoint[0], intersectionPoint[1], intersectionPoint[2]); if (!IsInfiniteLength && Vector3.DistanceSquared(StartPoint, result) > Length * Length + errorMargin * errorMargin) { return(null); } else if (!Contains(result)) { return(null); } else { return(result); } }