void PerformMerge(GLPoolResourceNode left, GLPoolResourceTicket ticket, GLPoolResourceNode right) { bool leftMerge = left != null && (ticket.First == (left.Last + 1)); bool rightMerge = right != null && ((ticket.Last + 1) == right.First); ValidateTicket(ticket); ValidateLocation(left, ticket, right); if (leftMerge && rightMerge) { Debug.Assert(ReferenceEquals(left.Next, right)); var finalCount = left.Count + ticket.Count + right.Count; Debug.Assert(finalCount == (right.Last - left.First + 1)); left.Count = finalCount; left.Last = right.Last; left.Next = right.Next; } else if (leftMerge) { var finalCount = left.Count + ticket.Count; Debug.Assert(finalCount == (ticket.Last - left.First + 1)); left.Count = finalCount; left.Last = ticket.Last; } else if (rightMerge) { var finalCount = right.Count + ticket.Count; Debug.Assert(finalCount == (right.Last - ticket.First + 1)); right.Count = finalCount; right.First = ticket.First; } else { var inBetween = new GLPoolResourceNode { First = ticket.First, Last = ticket.Last, Count = ticket.Count, }; // REPLACE HEAD if (left == null) { Debug.Assert(ReferenceEquals(right, Head)); inBetween.Next = Head; Head = inBetween; } else { left.Next = inBetween; inBetween.Next = right; } } }
void ValidateLocation(GLPoolResourceNode previous, GLPoolResourceTicket ticket, GLPoolResourceNode current) { if (previous != null && previous.Last >= ticket.First) { throw new InvalidOperationException(); } if (current != null && current.First <= ticket.Last) { throw new InvalidOperationException(); } }
public bool Free(GLPoolResourceTicket ticket) { if (Head == null) { Head = new GLPoolResourceNode { First = ticket.First, Last = ticket.Last, Count = ticket.Count, }; return(true); } else { GLPoolResourceNode previous = null; GLPoolResourceNode current = Head; while (current != null) { // SAME TICKET RANGE RECOVERY if (ticket.First == current.First) { // DO NOTHING IF INSIDE RANGE if (ticket.Last <= current.Last && ticket.Count <= current.Count) { return(true); } else { AdjustTicketsSpan(ticket, current); return(true); } } // GAP-BASED SLOT RECOVERY else if (ticket.First < current.First) { PerformMerge(previous, ticket, current); return(true); } previous = current; current = current.Next; } // At end of linked list PerformMerge(previous, ticket, null); return(true); } }
public void RightMerge() { GLPoolResourceTicket ticket_0; var initialCheck = PoolResource.Allocate(NO_OF_ITEMS, out ticket_0); Assert.IsTrue(initialCheck); Assert.IsNull(PoolResource.Head); { var ticket_1 = new GLPoolResourceTicket { First = 2, Last = 2, Count = 1, }; var actual_1 = PoolResource.Free(ticket_1); Assert.IsTrue(actual_1); var head = PoolResource.Head; Assert.IsNotNull(head); Assert.IsNull(head.Next); Assert.AreEqual(ticket_1.First, head.First); Assert.AreEqual(ticket_1.Last, head.Last); Assert.AreEqual(ticket_1.Count, head.Count); } { var ticket_2 = new GLPoolResourceTicket { First = 1, Last = 1, Count = 1, }; var actual_2 = PoolResource.Free(ticket_2); Assert.IsTrue(actual_2); var head = PoolResource.Head; Assert.IsNotNull(head); Assert.IsNull(head.Next); Assert.AreEqual(1, head.First); Assert.AreEqual(2, head.Last); Assert.AreEqual(2, head.Count); } }
public void TwoNodesAppended() { GLPoolResourceTicket ticket_0; var initialCheck = PoolResource.Allocate(NO_OF_ITEMS, out ticket_0); Assert.IsTrue(initialCheck); Assert.IsNull(PoolResource.Head); var ticket_1 = new GLPoolResourceTicket { First = 0, Last = 0, Count = 1, }; var actual_1 = PoolResource.Free(ticket_1); Assert.IsTrue(actual_1); var head = PoolResource.Head; Assert.IsNotNull(head); Assert.IsNull(head.Next); Assert.AreEqual(ticket_1.First, head.First); Assert.AreEqual(ticket_1.Last, head.Last); Assert.AreEqual(ticket_1.Count, head.Count); var ticket_2 = new GLPoolResourceTicket { First = 2, Last = 2, Count = 1, }; var actual_2 = PoolResource.Free(ticket_2); Assert.IsTrue(actual_2); head = PoolResource.Head; Assert.IsNotNull(head); var next = head.Next; Assert.IsNotNull(next); Assert.AreEqual(ticket_2.First, next.First); Assert.AreEqual(ticket_2.Last, next.Last); Assert.AreEqual(ticket_2.Count, next.Count); }
public void SpamTest_OutsideRange_0() { GLPoolResourceTicket ticket_0; var initialCheck = PoolResource.Allocate(NO_OF_ITEMS, out ticket_0); Assert.IsTrue(initialCheck); Assert.IsNull(PoolResource.Head); var ticket_1 = new GLPoolResourceTicket { First = 0, Last = 2, Count = 3, }; { var actual = PoolResource.Free(ticket_1); Assert.IsTrue(actual); var head = PoolResource.Head; Assert.IsNotNull(head); Assert.IsNull(head.Next); Assert.AreEqual(ticket_1.First, head.First); Assert.AreEqual(ticket_1.Last, head.Last); Assert.AreEqual(ticket_1.Count, head.Count); } { var ticket_2 = new GLPoolResourceTicket { First = 0, Last = 3, Count = 4, }; var actual = PoolResource.Free(ticket_2); Assert.IsTrue(actual); var head = PoolResource.Head; Assert.IsNotNull(head); Assert.IsNull(head.Next); Assert.AreEqual(ticket_2.First, head.First); Assert.AreEqual(ticket_2.Last, head.Last); Assert.AreEqual(ticket_2.Count, head.Count); } }
void ValidateTicket(GLPoolResourceTicket ticket) { if ((ticket.First + ticket.Count) > Count) { throw new InvalidOperationException(); } if (ticket.Count == 0) { throw new InvalidOperationException(); } if ((ticket.First + ticket.Count - 1) != ticket.Last) { throw new InvalidOperationException(); } if (ticket.Last > Count) { throw new InvalidOperationException(); } }
void AdjustTicketsSpan(GLPoolResourceTicket ticket, GLPoolResourceNode parent) { GLPoolResourceNode lastNode = null; bool intercepts = false; GLPoolResourceNode current = parent.Next; while (current != null) { lastNode = current; if (current.Last > ticket.Last) { intercepts = (current.First <= ticket.Last); break; } // remove from the list parent.Next = current.Next; current = current.Next; } parent.Last = (lastNode != null && intercepts) ? lastNode.Last : ticket.Last; parent.Count = parent.Last - parent.First + 1; if (current == null) { // ITERATED THRU THEN POINT TO END parent.Next = null; } else if (lastNode != null && intercepts) { // INCLUDE LAST NODE parent.Next = lastNode.Next; } else { // OUTSIDE OF LAST NODE parent.Next = lastNode; } }
public bool Free(GLPoolResourceTicket ticket) { throw new NotImplementedException(); }
public bool Allocate(uint request, out GLPoolResourceTicket ticket) { throw new NotImplementedException(); }
public void SpamTest_OutsideRange_2() { GLPoolResourceTicket ticket_0; var initialCheck = PoolResource.Allocate(NO_OF_ITEMS, out ticket_0); Assert.IsTrue(initialCheck); Assert.IsNull(PoolResource.Head); var ticket_1 = new GLPoolResourceTicket { First = 0, Last = 0, Count = 1, }; { var actual = PoolResource.Free(ticket_1); Assert.IsTrue(actual); var head = PoolResource.Head; Assert.IsNotNull(head); Assert.IsNull(head.Next); Assert.AreEqual(ticket_1.First, head.First); Assert.AreEqual(ticket_1.Last, head.Last); Assert.AreEqual(ticket_1.Count, head.Count); } var ticket_2 = new GLPoolResourceTicket { First = 2, Last = 3, Count = 2, }; { var actual = PoolResource.Free(ticket_2); Assert.IsTrue(actual); var head = PoolResource.Head; Assert.IsNotNull(head); Assert.AreEqual(ticket_1.First, head.First); Assert.AreEqual(ticket_1.Last, head.Last); Assert.AreEqual(ticket_1.Count, head.Count); var next_0 = head.Next; Assert.IsNotNull(next_0); Assert.AreEqual(ticket_2.First, next_0.First); Assert.AreEqual(ticket_2.Last, next_0.Last); Assert.AreEqual(ticket_2.Count, next_0.Count); } var ticket_3 = new GLPoolResourceTicket { First = 5, Last = 5, Count = 1, }; { var actual = PoolResource.Free(ticket_3); Assert.IsTrue(actual); var head = PoolResource.Head; Assert.IsNotNull(head); Assert.AreEqual(ticket_1.First, head.First); Assert.AreEqual(ticket_1.Last, head.Last); Assert.AreEqual(ticket_1.Count, head.Count); var next_0 = head.Next; Assert.IsNotNull(next_0); Assert.AreEqual(ticket_2.First, next_0.First); Assert.AreEqual(ticket_2.Last, next_0.Last); Assert.AreEqual(ticket_2.Count, next_0.Count); var next_1 = next_0.Next; Assert.IsNotNull(next_1); Assert.AreEqual(ticket_3.First, next_1.First); Assert.AreEqual(ticket_3.Last, next_1.Last); Assert.AreEqual(ticket_3.Count, next_1.Count); } { var ticket_4 = new GLPoolResourceTicket { First = 0, Last = 2, Count = 3, }; var actual = PoolResource.Free(ticket_4); Assert.IsTrue(actual); var head = PoolResource.Head; Assert.IsNotNull(head); Assert.AreEqual(0, head.First); Assert.AreEqual(3, head.Last); Assert.AreEqual(4, head.Count); var next = head.Next; Assert.IsNotNull(next); Assert.AreEqual(ticket_3.First, next.First); Assert.AreEqual(ticket_3.Last, next.Last); Assert.AreEqual(ticket_3.Count, next.Count); } }
public bool Allocate(uint request, out GLPoolResourceTicket range) { if (request == 0) { throw new ArgumentOutOfRangeException(nameof(request) + " must be greater than 0"); } { // FIRST LOOP : SCAN FOR EXACT MATCHES GLPoolResourceNode current = Head; GLPoolResourceNode previous = null; while (current != null) { if (current.Count == request) { range = new GLPoolResourceTicket { First = current.First, Last = current.Last, Count = current.Count, }; // remove current from linked list if (previous != null) { previous.Next = current.Next; } // remove from head if (ReferenceEquals(Head, current)) { Head = current.Next; } return(true); } previous = current; current = current.Next; } } { // SECOND LOOP : FIND FIRST BLOCK LARGE ENOUGH AND SPLIT GLPoolResourceNode current = Head; while (current != null) { if (current.Count > request) { range = new GLPoolResourceTicket { First = current.First, Last = request + current.First - 1, Count = request, }; // adjust current current.First += request; current.Count -= request; return(true); } current = current.Next; } } // NOT FOUND range = null; return(false); }