ArenaAllocator.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. using System.Collections.Generic;
  2. namespace Ryujinx.HLE.Memory
  3. {
  4. class ArenaAllocator
  5. {
  6. private class Region
  7. {
  8. public long Position { get; set; }
  9. public long Size { get; set; }
  10. public Region(long Position, long Size)
  11. {
  12. this.Position = Position;
  13. this.Size = Size;
  14. }
  15. }
  16. private LinkedList<Region> FreeRegions;
  17. public long TotalAvailableSize { get; private set; }
  18. public long TotalUsedSize { get; private set; }
  19. public ArenaAllocator(long ArenaSize)
  20. {
  21. TotalAvailableSize = ArenaSize;
  22. FreeRegions = new LinkedList<Region>();
  23. FreeRegions.AddFirst(new Region(0, ArenaSize));
  24. }
  25. public bool TryAllocate(long Size, out long Position)
  26. {
  27. LinkedListNode<Region> Node = FreeRegions.First;
  28. while (Node != null)
  29. {
  30. Region Rg = Node.Value;
  31. if ((ulong)Rg.Size >= (ulong)Size)
  32. {
  33. Position = Rg.Position;
  34. Rg.Position += Size;
  35. Rg.Size -= Size;
  36. if (Rg.Size == 0)
  37. {
  38. //Region is empty, just remove it.
  39. FreeRegions.Remove(Node);
  40. }
  41. else if (Node.Previous != null)
  42. {
  43. //Re-sort based on size (smaller first).
  44. Node = Node.Previous;
  45. FreeRegions.Remove(Node.Next);
  46. while (Node != null && (ulong)Node.Value.Size > (ulong)Rg.Size)
  47. {
  48. Node = Node.Previous;
  49. }
  50. if (Node != null)
  51. {
  52. FreeRegions.AddAfter(Node, Rg);
  53. }
  54. else
  55. {
  56. FreeRegions.AddFirst(Rg);
  57. }
  58. }
  59. TotalUsedSize += Size;
  60. return true;
  61. }
  62. Node = Node.Next;
  63. }
  64. Position = 0;
  65. return false;
  66. }
  67. public void Free(long Position, long Size)
  68. {
  69. long End = Position + Size;
  70. Region NewRg = new Region(Position, Size);
  71. LinkedListNode<Region> Node = FreeRegions.First;
  72. LinkedListNode<Region> PrevSz = null;
  73. while (Node != null)
  74. {
  75. LinkedListNode<Region> NextNode = Node.Next;
  76. Region Rg = Node.Value;
  77. long RgEnd = Rg.Position + Rg.Size;
  78. if (Rg.Position == End)
  79. {
  80. //Current region position matches the end of the freed region,
  81. //just merge the two and remove the current region from the list.
  82. NewRg.Size += Rg.Size;
  83. FreeRegions.Remove(Node);
  84. }
  85. else if (RgEnd == Position)
  86. {
  87. //End of the current region matches the position of the freed region,
  88. //just merge the two and remove the current region from the list.
  89. NewRg.Position = Rg.Position;
  90. NewRg.Size += Rg.Size;
  91. FreeRegions.Remove(Node);
  92. }
  93. else
  94. {
  95. if (PrevSz == null)
  96. {
  97. PrevSz = Node;
  98. }
  99. else if ((ulong)Rg.Size < (ulong)NewRg.Size &&
  100. (ulong)Rg.Size > (ulong)PrevSz.Value.Size)
  101. {
  102. PrevSz = Node;
  103. }
  104. }
  105. Node = NextNode;
  106. }
  107. if (PrevSz != null && (ulong)PrevSz.Value.Size < (ulong)Size)
  108. {
  109. FreeRegions.AddAfter(PrevSz, NewRg);
  110. }
  111. else
  112. {
  113. FreeRegions.AddFirst(NewRg);
  114. }
  115. TotalUsedSize -= Size;
  116. }
  117. }
  118. }