123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- using System.Threading;
- using Unity.Mathematics;
-
- namespace Unity.Collections.LowLevel.Unsafe
- {
- /// <summary>
- /// A 32-bit atomic counter.
- /// </summary>
- /// <remarks>Rather than have its own int, a counter *points* to an int. This arrangement lets counters in different jobs share reference to the same underlying int.</remarks>
- [GenerateTestsForBurstCompatibility]
- public unsafe struct UnsafeAtomicCounter32
- {
- /// <summary>
- /// The int that is modified by this counter.
- /// </summary>
- /// <value>The int that is modified by this counter.</value>
- public int* Counter;
-
- /// <summary>
- /// Initializes and returns an instance of UnsafeAtomicCounter32.
- /// </summary>
- /// <param name="ptr">A pointer to the int to be modified by this counter.</param>
- public UnsafeAtomicCounter32(void* ptr)
- {
- Counter = (int*)ptr;
- }
-
- /// <summary>
- /// Non-atomically sets this counter to a value.
- /// </summary>
- /// <param name="value">The value to set. Defaults to 0</param>
- public void Reset(int value = 0)
- {
- *Counter = value;
- }
-
- /// <summary>
- /// Atomically adds a value to this counter.
- /// </summary>
- /// <param name="value">The value to add.</param>
- /// <returns>The original value before the add.</returns>
- public int Add(int value)
- {
- return Interlocked.Add(ref UnsafeUtility.AsRef<int>(Counter), value) - value;
- }
-
- /// <summary>
- /// Atomically subtracts a value from this counter.
- /// </summary>
- /// <param name="value">The value to subtract.</param>
- /// <returns>The original value before the subtract.</returns>
- public int Sub(int value) => Add(-value);
-
- /// <summary>
- /// Atomically adds a value to this counter. The result will not be greater than a maximum value.
- /// </summary>
- /// <param name="value">The value to add to this counter.</param>
- /// <param name="max">The maximum which the result will not be greater than.</param>
- /// <returns>The original value before the add.</returns>
- public int AddSat(int value, int max = int.MaxValue)
- {
- int oldVal;
- int newVal = *Counter;
- do
- {
- oldVal = newVal;
- newVal = newVal >= max ? max : math.min(max, newVal + value);
- newVal = Interlocked.CompareExchange(ref UnsafeUtility.AsRef<int>(Counter), newVal, oldVal);
- }
- while (oldVal != newVal && oldVal != max);
-
- return oldVal;
- }
-
- /// <summary>
- /// Atomically subtracts a value from this counter. The result will not be less than a minimum value.
- /// </summary>
- /// <param name="value">The value to subtract from this counter.</param>
- /// <param name="min">The minimum which the result will not be less than.</param>
- /// <returns>The original value before the subtract.</returns>
- public int SubSat(int value, int min = int.MinValue)
- {
- int oldVal;
- int newVal = *Counter;
- do
- {
- oldVal = newVal;
- newVal = newVal <= min ? min : math.max(min, newVal - value);
- newVal = Interlocked.CompareExchange(ref UnsafeUtility.AsRef<int>(Counter), newVal, oldVal);
- }
- while (oldVal != newVal && oldVal != min);
-
- return oldVal;
- }
- }
-
- /// <summary>
- /// A 64-bit atomic counter.
- /// </summary>
- /// <remarks>Rather than have its own long, a counter *points* to a long. This arrangement lets counters in different jobs share reference to the same underlying long.</remarks>
- [GenerateTestsForBurstCompatibility]
- public unsafe struct UnsafeAtomicCounter64
- {
- /// <summary>
- /// The long that is modified by this counter.
- /// </summary>
- /// <value>The long that is modified by this counter.</value>
- public long* Counter;
-
- /// <summary>
- /// Initializes and returns an instance of UnsafeAtomicCounter64.
- /// </summary>
- /// <param name="ptr">A pointer to the long to be modified by this counter.</param>
- public UnsafeAtomicCounter64(void* ptr)
- {
- Counter = (long*)ptr;
- }
-
- /// <summary>
- /// Non-atomically sets this counter to a value.
- /// </summary>
- /// <param name="value">The value to set. Defaults to 0</param>
- public void Reset(long value = 0)
- {
- *Counter = value;
- }
-
- /// <summary>
- /// Atomically adds a value to this counter.
- /// </summary>
- /// <param name="value">The value to add.</param>
- /// <returns>The original value before the add.</returns>
- public long Add(long value)
- {
- return Interlocked.Add(ref UnsafeUtility.AsRef<long>(Counter), value) - value;
- }
-
- /// <summary>
- /// Atomically subtracts a value from this counter.
- /// </summary>
- /// <param name="value">The value to subtract.</param>
- /// <returns>The original value before the subtract.</returns>
- public long Sub(long value) => Add(-value);
-
- /// <summary>
- /// Atomically adds a value to this counter. The result will not be greater than a maximum value.
- /// </summary>
- /// <param name="value">The value to add to this counter.</param>
- /// <param name="max">The maximum which the result will not be greater than.</param>
- /// <returns>The original value before the add.</returns>
- public long AddSat(long value, long max = long.MaxValue)
- {
- long oldVal;
- long newVal = *Counter;
- do
- {
- oldVal = newVal;
- newVal = newVal >= max ? max : math.min(max, newVal + value);
- newVal = Interlocked.CompareExchange(ref UnsafeUtility.AsRef<long>(Counter), newVal, oldVal);
- }
- while (oldVal != newVal && oldVal != max);
-
- return oldVal;
- }
-
- /// <summary>
- /// Atomically subtracts a value from this counter. The result will not be less than a minimum value.
- /// </summary>
- /// <param name="value">The value to subtract from this counter.</param>
- /// <param name="min">The minimum which the result will not be less than.</param>
- /// <returns>The original value before the subtract.</returns>
- public long SubSat(long value, long min = long.MinValue)
- {
- long oldVal;
- long newVal = *Counter;
- do
- {
- oldVal = newVal;
- newVal = newVal <= min ? min : math.max(min, newVal - value);
- newVal = Interlocked.CompareExchange(ref UnsafeUtility.AsRef<long>(Counter), newVal, oldVal);
- }
- while (oldVal != newVal && oldVal != min);
-
- return oldVal;
- }
- }
- }
|