A game about forced loneliness, made by TACStudios
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}