A game about forced loneliness, made by TACStudios
at master 187 lines 7.2 kB view raw
1using System.Threading; 2using Unity.Mathematics; 3 4namespace Unity.Collections.LowLevel.Unsafe 5{ 6 /// <summary> 7 /// A 32-bit atomic counter. 8 /// </summary> 9 /// <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> 10 [GenerateTestsForBurstCompatibility] 11 public unsafe struct UnsafeAtomicCounter32 12 { 13 /// <summary> 14 /// The int that is modified by this counter. 15 /// </summary> 16 /// <value>The int that is modified by this counter.</value> 17 public int* Counter; 18 19 /// <summary> 20 /// Initializes and returns an instance of UnsafeAtomicCounter32. 21 /// </summary> 22 /// <param name="ptr">A pointer to the int to be modified by this counter.</param> 23 public UnsafeAtomicCounter32(void* ptr) 24 { 25 Counter = (int*)ptr; 26 } 27 28 /// <summary> 29 /// Non-atomically sets this counter to a value. 30 /// </summary> 31 /// <param name="value">The value to set. Defaults to 0</param> 32 public void Reset(int value = 0) 33 { 34 *Counter = value; 35 } 36 37 /// <summary> 38 /// Atomically adds a value to this counter. 39 /// </summary> 40 /// <param name="value">The value to add.</param> 41 /// <returns>The original value before the add.</returns> 42 public int Add(int value) 43 { 44 return Interlocked.Add(ref UnsafeUtility.AsRef<int>(Counter), value) - value; 45 } 46 47 /// <summary> 48 /// Atomically subtracts a value from this counter. 49 /// </summary> 50 /// <param name="value">The value to subtract.</param> 51 /// <returns>The original value before the subtract.</returns> 52 public int Sub(int value) => Add(-value); 53 54 /// <summary> 55 /// Atomically adds a value to this counter. The result will not be greater than a maximum value. 56 /// </summary> 57 /// <param name="value">The value to add to this counter.</param> 58 /// <param name="max">The maximum which the result will not be greater than.</param> 59 /// <returns>The original value before the add.</returns> 60 public int AddSat(int value, int max = int.MaxValue) 61 { 62 int oldVal; 63 int newVal = *Counter; 64 do 65 { 66 oldVal = newVal; 67 newVal = newVal >= max ? max : math.min(max, newVal + value); 68 newVal = Interlocked.CompareExchange(ref UnsafeUtility.AsRef<int>(Counter), newVal, oldVal); 69 } 70 while (oldVal != newVal && oldVal != max); 71 72 return oldVal; 73 } 74 75 /// <summary> 76 /// Atomically subtracts a value from this counter. The result will not be less than a minimum value. 77 /// </summary> 78 /// <param name="value">The value to subtract from this counter.</param> 79 /// <param name="min">The minimum which the result will not be less than.</param> 80 /// <returns>The original value before the subtract.</returns> 81 public int SubSat(int value, int min = int.MinValue) 82 { 83 int oldVal; 84 int newVal = *Counter; 85 do 86 { 87 oldVal = newVal; 88 newVal = newVal <= min ? min : math.max(min, newVal - value); 89 newVal = Interlocked.CompareExchange(ref UnsafeUtility.AsRef<int>(Counter), newVal, oldVal); 90 } 91 while (oldVal != newVal && oldVal != min); 92 93 return oldVal; 94 } 95 } 96 97 /// <summary> 98 /// A 64-bit atomic counter. 99 /// </summary> 100 /// <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> 101 [GenerateTestsForBurstCompatibility] 102 public unsafe struct UnsafeAtomicCounter64 103 { 104 /// <summary> 105 /// The long that is modified by this counter. 106 /// </summary> 107 /// <value>The long that is modified by this counter.</value> 108 public long* Counter; 109 110 /// <summary> 111 /// Initializes and returns an instance of UnsafeAtomicCounter64. 112 /// </summary> 113 /// <param name="ptr">A pointer to the long to be modified by this counter.</param> 114 public UnsafeAtomicCounter64(void* ptr) 115 { 116 Counter = (long*)ptr; 117 } 118 119 /// <summary> 120 /// Non-atomically sets this counter to a value. 121 /// </summary> 122 /// <param name="value">The value to set. Defaults to 0</param> 123 public void Reset(long value = 0) 124 { 125 *Counter = value; 126 } 127 128 /// <summary> 129 /// Atomically adds a value to this counter. 130 /// </summary> 131 /// <param name="value">The value to add.</param> 132 /// <returns>The original value before the add.</returns> 133 public long Add(long value) 134 { 135 return Interlocked.Add(ref UnsafeUtility.AsRef<long>(Counter), value) - value; 136 } 137 138 /// <summary> 139 /// Atomically subtracts a value from this counter. 140 /// </summary> 141 /// <param name="value">The value to subtract.</param> 142 /// <returns>The original value before the subtract.</returns> 143 public long Sub(long value) => Add(-value); 144 145 /// <summary> 146 /// Atomically adds a value to this counter. The result will not be greater than a maximum value. 147 /// </summary> 148 /// <param name="value">The value to add to this counter.</param> 149 /// <param name="max">The maximum which the result will not be greater than.</param> 150 /// <returns>The original value before the add.</returns> 151 public long AddSat(long value, long max = long.MaxValue) 152 { 153 long oldVal; 154 long newVal = *Counter; 155 do 156 { 157 oldVal = newVal; 158 newVal = newVal >= max ? max : math.min(max, newVal + value); 159 newVal = Interlocked.CompareExchange(ref UnsafeUtility.AsRef<long>(Counter), newVal, oldVal); 160 } 161 while (oldVal != newVal && oldVal != max); 162 163 return oldVal; 164 } 165 166 /// <summary> 167 /// Atomically subtracts a value from this counter. The result will not be less than a minimum value. 168 /// </summary> 169 /// <param name="value">The value to subtract from this counter.</param> 170 /// <param name="min">The minimum which the result will not be less than.</param> 171 /// <returns>The original value before the subtract.</returns> 172 public long SubSat(long value, long min = long.MinValue) 173 { 174 long oldVal; 175 long newVal = *Counter; 176 do 177 { 178 oldVal = newVal; 179 newVal = newVal <= min ? min : math.max(min, newVal - value); 180 newVal = Interlocked.CompareExchange(ref UnsafeUtility.AsRef<long>(Counter), newVal, oldVal); 181 } 182 while (oldVal != newVal && oldVal != min); 183 184 return oldVal; 185 } 186 } 187}