NodeStates.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. using Ryujinx.Audio.Renderer.Utils;
  2. using System;
  3. using System.Diagnostics;
  4. namespace Ryujinx.Audio.Renderer.Common
  5. {
  6. public class NodeStates
  7. {
  8. private class Stack
  9. {
  10. private Memory<int> _storage;
  11. private int _index;
  12. private int _nodeCount;
  13. public void Reset(Memory<int> storage, int nodeCount)
  14. {
  15. Debug.Assert(storage.Length * sizeof(int) >= CalcBufferSize(nodeCount));
  16. _storage = storage;
  17. _index = 0;
  18. _nodeCount = nodeCount;
  19. }
  20. public int GetCurrentCount()
  21. {
  22. return _index;
  23. }
  24. public void Push(int data)
  25. {
  26. Debug.Assert(_index + 1 <= _nodeCount);
  27. _storage.Span[_index++] = data;
  28. }
  29. public int Pop()
  30. {
  31. Debug.Assert(_index > 0);
  32. return _storage.Span[--_index];
  33. }
  34. public int Top()
  35. {
  36. return _storage.Span[_index - 1];
  37. }
  38. public static int CalcBufferSize(int nodeCount)
  39. {
  40. return nodeCount * sizeof(int);
  41. }
  42. }
  43. private int _nodeCount;
  44. private EdgeMatrix _discovered;
  45. private EdgeMatrix _finished;
  46. private Memory<int> _resultArray;
  47. private Stack _stack;
  48. private int _tsortResultIndex;
  49. private enum NodeState : byte
  50. {
  51. Unknown,
  52. Discovered,
  53. Finished
  54. }
  55. public NodeStates()
  56. {
  57. _stack = new Stack();
  58. _discovered = new EdgeMatrix();
  59. _finished = new EdgeMatrix();
  60. }
  61. public static int GetWorkBufferSize(int nodeCount)
  62. {
  63. return Stack.CalcBufferSize(nodeCount * nodeCount) + 0xC * nodeCount + 2 * EdgeMatrix.GetWorkBufferSize(nodeCount);
  64. }
  65. public void Initialize(Memory<byte> nodeStatesWorkBuffer, int nodeCount)
  66. {
  67. int workBufferSize = GetWorkBufferSize(nodeCount);
  68. Debug.Assert(nodeStatesWorkBuffer.Length >= workBufferSize);
  69. _nodeCount = nodeCount;
  70. int edgeMatrixWorkBufferSize = EdgeMatrix.GetWorkBufferSize(nodeCount);
  71. _discovered.Initialize(nodeStatesWorkBuffer.Slice(0, edgeMatrixWorkBufferSize), nodeCount);
  72. _finished.Initialize(nodeStatesWorkBuffer.Slice(edgeMatrixWorkBufferSize, edgeMatrixWorkBufferSize), nodeCount);
  73. nodeStatesWorkBuffer = nodeStatesWorkBuffer.Slice(edgeMatrixWorkBufferSize * 2);
  74. _resultArray = SpanMemoryManager<int>.Cast(nodeStatesWorkBuffer.Slice(0, sizeof(int) * nodeCount));
  75. nodeStatesWorkBuffer = nodeStatesWorkBuffer.Slice(sizeof(int) * nodeCount);
  76. Memory<int> stackWorkBuffer = SpanMemoryManager<int>.Cast(nodeStatesWorkBuffer.Slice(0, Stack.CalcBufferSize(nodeCount * nodeCount)));
  77. _stack.Reset(stackWorkBuffer, nodeCount * nodeCount);
  78. }
  79. private void Reset()
  80. {
  81. _discovered.Reset();
  82. _finished.Reset();
  83. _tsortResultIndex = 0;
  84. _resultArray.Span.Fill(-1);
  85. }
  86. private NodeState GetState(int index)
  87. {
  88. Debug.Assert(index < _nodeCount);
  89. if (_discovered.Test(index))
  90. {
  91. Debug.Assert(!_finished.Test(index));
  92. return NodeState.Discovered;
  93. }
  94. else if (_finished.Test(index))
  95. {
  96. Debug.Assert(!_discovered.Test(index));
  97. return NodeState.Finished;
  98. }
  99. return NodeState.Unknown;
  100. }
  101. private void SetState(int index, NodeState state)
  102. {
  103. switch (state)
  104. {
  105. case NodeState.Unknown:
  106. _discovered.Reset(index);
  107. _finished.Reset(index);
  108. break;
  109. case NodeState.Discovered:
  110. _discovered.Set(index);
  111. _finished.Reset(index);
  112. break;
  113. case NodeState.Finished:
  114. _finished.Set(index);
  115. _discovered.Reset(index);
  116. break;
  117. }
  118. }
  119. private void PushTsortResult(int index)
  120. {
  121. Debug.Assert(index < _nodeCount);
  122. _resultArray.Span[_tsortResultIndex++] = index;
  123. }
  124. public ReadOnlySpan<int> GetTsortResult()
  125. {
  126. return _resultArray.Span.Slice(0, _tsortResultIndex);
  127. }
  128. public bool Sort(EdgeMatrix edgeMatrix)
  129. {
  130. Reset();
  131. if (_nodeCount <= 0)
  132. {
  133. return true;
  134. }
  135. for (int i = 0; i < _nodeCount; i++)
  136. {
  137. if (GetState(i) == NodeState.Unknown)
  138. {
  139. _stack.Push(i);
  140. }
  141. while (_stack.GetCurrentCount() > 0)
  142. {
  143. int topIndex = _stack.Top();
  144. NodeState topState = GetState(topIndex);
  145. if (topState == NodeState.Discovered)
  146. {
  147. SetState(topIndex, NodeState.Finished);
  148. PushTsortResult(topIndex);
  149. _stack.Pop();
  150. }
  151. else if (topState == NodeState.Finished)
  152. {
  153. _stack.Pop();
  154. }
  155. else
  156. {
  157. if (topState == NodeState.Unknown)
  158. {
  159. SetState(topIndex, NodeState.Discovered);
  160. }
  161. for (int j = 0; j < edgeMatrix.GetNodeCount(); j++)
  162. {
  163. if (edgeMatrix.Connected(topIndex, j))
  164. {
  165. NodeState jState = GetState(j);
  166. if (jState == NodeState.Unknown)
  167. {
  168. _stack.Push(j);
  169. }
  170. // Found a loop, reset and propagate rejection.
  171. else if (jState == NodeState.Discovered)
  172. {
  173. Reset();
  174. return false;
  175. }
  176. }
  177. }
  178. }
  179. }
  180. }
  181. return true;
  182. }
  183. }
  184. }