using System; namespace ARMeilleure.Common { /// /// Represents a numeric counter which can be used for instrumentation of compiled code. /// /// Type of the counter class Counter : IDisposable where T : unmanaged { private bool _disposed; /// /// Index in the /// private readonly int _index; private readonly EntryTable _countTable; /// /// Initializes a new instance of the class from the specified /// instance and index. /// /// instance /// is /// is unsupported public Counter(EntryTable countTable) { if (typeof(T) != typeof(byte) && typeof(T) != typeof(sbyte) && typeof(T) != typeof(short) && typeof(T) != typeof(ushort) && typeof(T) != typeof(int) && typeof(T) != typeof(uint) && typeof(T) != typeof(long) && typeof(T) != typeof(ulong) && typeof(T) != typeof(nint) && typeof(T) != typeof(nuint) && typeof(T) != typeof(float) && typeof(T) != typeof(double)) { throw new ArgumentException("Counter does not support the specified type."); } _countTable = countTable ?? throw new ArgumentNullException(nameof(countTable)); _index = countTable.Allocate(); } /// /// Gets a reference to the value of the counter. /// /// instance was disposed /// /// This can refer to freed memory if the owning is disposed. /// public ref T Value { get { ObjectDisposedException.ThrowIf(_disposed, this); return ref _countTable.GetValue(_index); } } /// /// Releases all resources used by the instance. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// Releases all unmanaged and optionally managed resources used by the instance. /// /// to dispose managed resources also; otherwise just unmanaged resources protected virtual void Dispose(bool disposing) { if (!_disposed) { try { // The index into the EntryTable is essentially an unmanaged resource since we allocate and free the // resource ourselves. _countTable.Free(_index); } catch (ObjectDisposedException) { // Can happen because _countTable may be disposed before the Counter instance. } _disposed = true; } } /// /// Frees resources used by the instance. /// ~Counter() { Dispose(false); } } }