Counter.cs 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. using System;
  2. namespace ARMeilleure.Common
  3. {
  4. /// <summary>
  5. /// Represents a numeric counter which can be used for instrumentation of compiled code.
  6. /// </summary>
  7. /// <typeparam name="T">Type of the counter</typeparam>
  8. class Counter<T> : IDisposable where T : unmanaged
  9. {
  10. private bool _disposed;
  11. /// <summary>
  12. /// Index in the <see cref="EntryTable{T}"/>
  13. /// </summary>
  14. private readonly int _index;
  15. private readonly EntryTable<T> _countTable;
  16. /// <summary>
  17. /// Initializes a new instance of the <see cref="Counter{T}"/> class from the specified
  18. /// <see cref="EntryTable{T}"/> instance and index.
  19. /// </summary>
  20. /// <param name="countTable"><see cref="EntryTable{T}"/> instance</param>
  21. /// <exception cref="ArgumentNullException"><paramref name="countTable"/> is <see langword="null"/></exception>
  22. /// <exception cref="ArgumentException"><typeparamref name="T"/> is unsupported</exception>
  23. public Counter(EntryTable<T> countTable)
  24. {
  25. if (typeof(T) != typeof(byte) && typeof(T) != typeof(sbyte) &&
  26. typeof(T) != typeof(short) && typeof(T) != typeof(ushort) &&
  27. typeof(T) != typeof(int) && typeof(T) != typeof(uint) &&
  28. typeof(T) != typeof(long) && typeof(T) != typeof(ulong) &&
  29. typeof(T) != typeof(nint) && typeof(T) != typeof(nuint) &&
  30. typeof(T) != typeof(float) && typeof(T) != typeof(double))
  31. {
  32. throw new ArgumentException("Counter does not support the specified type.");
  33. }
  34. _countTable = countTable ?? throw new ArgumentNullException(nameof(countTable));
  35. _index = countTable.Allocate();
  36. }
  37. /// <summary>
  38. /// Gets a reference to the value of the counter.
  39. /// </summary>
  40. /// <exception cref="ObjectDisposedException"><see cref="Counter{T}"/> instance was disposed</exception>
  41. /// <remarks>
  42. /// This can refer to freed memory if the owning <see cref="EntryTable{TEntry}"/> is disposed.
  43. /// </remarks>
  44. public ref T Value
  45. {
  46. get
  47. {
  48. ObjectDisposedException.ThrowIf(_disposed, this);
  49. return ref _countTable.GetValue(_index);
  50. }
  51. }
  52. /// <summary>
  53. /// Releases all resources used by the <see cref="Counter{T}"/> instance.
  54. /// </summary>
  55. public void Dispose()
  56. {
  57. Dispose(true);
  58. GC.SuppressFinalize(this);
  59. }
  60. /// <summary>
  61. /// Releases all unmanaged and optionally managed resources used by the <see cref="Counter{T}"/> instance.
  62. /// </summary>
  63. /// <param name="disposing"><see langword="true"/> to dispose managed resources also; otherwise just unmanaged resources</param>
  64. protected virtual void Dispose(bool disposing)
  65. {
  66. if (!_disposed)
  67. {
  68. try
  69. {
  70. // The index into the EntryTable is essentially an unmanaged resource since we allocate and free the
  71. // resource ourselves.
  72. _countTable.Free(_index);
  73. }
  74. catch (ObjectDisposedException)
  75. {
  76. // Can happen because _countTable may be disposed before the Counter instance.
  77. }
  78. _disposed = true;
  79. }
  80. }
  81. /// <summary>
  82. /// Frees resources used by the <see cref="Counter{T}"/> instance.
  83. /// </summary>
  84. ~Counter()
  85. {
  86. Dispose(false);
  87. }
  88. }
  89. }