Counter.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  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. if (_disposed)
  49. {
  50. throw new ObjectDisposedException(null);
  51. }
  52. return ref _countTable.GetValue(_index);
  53. }
  54. }
  55. /// <summary>
  56. /// Releases all resources used by the <see cref="Counter{T}"/> instance.
  57. /// </summary>
  58. public void Dispose()
  59. {
  60. Dispose(true);
  61. GC.SuppressFinalize(this);
  62. }
  63. /// <summary>
  64. /// Releases all unmanaged and optionally managed resources used by the <see cref="Counter{T}"/> instance.
  65. /// </summary>
  66. /// <param name="disposing"><see langword="true"/> to dispose managed resources also; otherwise just unmanaged resources</param>
  67. protected virtual void Dispose(bool disposing)
  68. {
  69. if (!_disposed)
  70. {
  71. try
  72. {
  73. // The index into the EntryTable is essentially an unmanaged resource since we allocate and free the
  74. // resource ourselves.
  75. _countTable.Free(_index);
  76. }
  77. catch (ObjectDisposedException)
  78. {
  79. // Can happen because _countTable may be disposed before the Counter instance.
  80. }
  81. _disposed = true;
  82. }
  83. }
  84. /// <summary>
  85. /// Frees resources used by the <see cref="Counter{T}"/> instance.
  86. /// </summary>
  87. ~Counter()
  88. {
  89. Dispose(false);
  90. }
  91. }
  92. }