Counter.cs 3.7 KB

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