CacheMemoryAllocator.cs 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics.CodeAnalysis;
  4. namespace ARMeilleure.Translation.Cache
  5. {
  6. class CacheMemoryAllocator
  7. {
  8. private readonly struct MemoryBlock : IComparable<MemoryBlock>
  9. {
  10. public int Offset { get; }
  11. public int Size { get; }
  12. public MemoryBlock(int offset, int size)
  13. {
  14. Offset = offset;
  15. Size = size;
  16. }
  17. public int CompareTo([AllowNull] MemoryBlock other)
  18. {
  19. return Offset.CompareTo(other.Offset);
  20. }
  21. }
  22. private readonly List<MemoryBlock> _blocks = new List<MemoryBlock>();
  23. public CacheMemoryAllocator(int capacity)
  24. {
  25. _blocks.Add(new MemoryBlock(0, capacity));
  26. }
  27. public int Allocate(int size)
  28. {
  29. for (int i = 0; i < _blocks.Count; i++)
  30. {
  31. MemoryBlock block = _blocks[i];
  32. if (block.Size > size)
  33. {
  34. _blocks[i] = new MemoryBlock(block.Offset + size, block.Size - size);
  35. return block.Offset;
  36. }
  37. else if (block.Size == size)
  38. {
  39. _blocks.RemoveAt(i);
  40. return block.Offset;
  41. }
  42. }
  43. // We don't have enough free memory to perform the allocation.
  44. return -1;
  45. }
  46. public void Free(int offset, int size)
  47. {
  48. Insert(new MemoryBlock(offset, size));
  49. }
  50. private void Insert(MemoryBlock block)
  51. {
  52. int index = _blocks.BinarySearch(block);
  53. if (index < 0)
  54. {
  55. index = ~index;
  56. }
  57. if (index < _blocks.Count)
  58. {
  59. MemoryBlock next = _blocks[index];
  60. int endOffs = block.Offset + block.Size;
  61. if (next.Offset == endOffs)
  62. {
  63. block = new MemoryBlock(block.Offset, block.Size + next.Size);
  64. _blocks.RemoveAt(index);
  65. }
  66. }
  67. if (index > 0)
  68. {
  69. MemoryBlock prev = _blocks[index - 1];
  70. if (prev.Offset + prev.Size == block.Offset)
  71. {
  72. block = new MemoryBlock(block.Offset - prev.Size, block.Size + prev.Size);
  73. _blocks.RemoveAt(--index);
  74. }
  75. }
  76. _blocks.Insert(index, block);
  77. }
  78. }
  79. }