A game about forced loneliness, made by TACStudios
at master 209 lines 7.7 kB view raw
1using System; 2using System.Threading; 3using Unity.Collections.LowLevel.Unsafe; 4using Unity.Mathematics; 5 6#pragma warning disable 0649 7 8namespace Unity.Collections 9{ 10 internal struct Long8 11 { 12 internal long f0,f1,f2,f3,f4,f5,f6,f7; 13 } 14 15 internal struct Long64 16 { 17 internal Long8 f0,f1,f2,f3,f4,f5,f6,f7; 18 } 19 20 internal struct Long512 21 { 22 internal Long64 f0,f1,f2,f3,f4,f5,f6,f7; 23 } 24 25 internal struct Long1024 : IIndexable<long> 26 { 27 internal Long512 f0,f1; 28 public int Length { get { return 1024;} set {} } 29 public ref long ElementAt(int index) 30 { 31 unsafe { fixed(Long512* p = &f0) { 32 return ref UnsafeUtility.AsRef<long>((long*)p + index); 33 } } 34 } 35 } 36 37 internal class ConcurrentMask 38 { 39 internal static long AtomicOr(ref long destination, long source) 40 { 41 var readValue = Interlocked.Read(ref destination); 42 long oldReadValue, writtenValue; 43 do 44 { 45 writtenValue = readValue | source; 46 oldReadValue = readValue; 47 readValue = Interlocked.CompareExchange(ref destination, writtenValue, oldReadValue); 48 } while(readValue != oldReadValue); 49 return writtenValue; 50 } 51 52 internal static long AtomicAnd(ref long destination, long source) 53 { 54 var readValue = Interlocked.Read(ref destination); 55 long oldReadValue, writtenValue; 56 do 57 { 58 writtenValue = readValue & source; 59 oldReadValue = readValue; 60 readValue = Interlocked.CompareExchange(ref destination, writtenValue, oldReadValue); 61 } while(readValue != oldReadValue); 62 return writtenValue; 63 } 64 65 internal static void longestConsecutiveOnes(long value, out int offset, out int count) 66 { 67 count = 0; 68 var newvalue = value; 69 while(newvalue != 0) 70 { 71 value = newvalue; 72 newvalue = value & (long)((ulong)value >> 1); 73 ++count; 74 } 75 offset = math.tzcnt(value); 76 } 77 78 internal static bool foundAtLeastThisManyConsecutiveOnes(long value, int minimum, out int offset, out int count) 79 { 80 if(minimum == 1) 81 { 82 offset = math.tzcnt(value); // find offset of first 1 bit 83 count = 1; 84 return offset != 64; 85 } 86 longestConsecutiveOnes(value, out offset, out count); 87 return count >= minimum; 88 } 89 90 internal static bool foundAtLeastThisManyConsecutiveZeroes(long value, int minimum, out int offset, out int count) 91 { 92 return foundAtLeastThisManyConsecutiveOnes(~value, minimum, out offset, out count); 93 } 94 95 internal const int ErrorFailedToFree = -1; 96 internal const int ErrorFailedToAllocate = -2; 97 internal const int ErrorAllocationCrossesWordBoundary = -3; 98 internal const int EmptyBeforeAllocation = 0; 99 internal const int EmptyAfterFree = 0; 100 101 internal static bool Succeeded(int error) 102 { 103 return error >= 0; 104 } 105 106 internal static long MakeMask(int offset, int bits) 107 { 108 return (long)(~0UL >> (64-bits)) << offset; 109 } 110 111 internal static int TryAllocate(ref long l, int offset, int bits) 112 { 113 var mask = MakeMask(offset, bits); 114 var readValue = Interlocked.Read(ref l); 115 long oldReadValue, writtenValue; 116 do 117 { 118 if((readValue & mask) != 0) 119 return ErrorFailedToAllocate; 120 writtenValue = readValue | mask; 121 oldReadValue = readValue; 122 readValue = Interlocked.CompareExchange(ref l, writtenValue, oldReadValue); 123 } while(readValue != oldReadValue); 124 return math.countbits(readValue); // how many bits were set, before i allocated? sometimes if 0, do something special (allocate chunk?) 125 } 126 127 internal static int TryFree(ref long l, int offset, int bits) 128 { 129 var mask = MakeMask(offset, bits); 130 var readValue = Interlocked.Read(ref l); 131 long oldReadValue, writtenValue; 132 do 133 { 134 if((readValue & mask) != mask) 135 return ErrorFailedToFree; 136 writtenValue = readValue & ~mask; 137 oldReadValue = readValue; 138 readValue = Interlocked.CompareExchange(ref l, writtenValue, oldReadValue); 139 } while(readValue != oldReadValue); 140 return math.countbits(writtenValue); // how many bits are set, after i freed? sometimes if 0, do something special (free chunk?) 141 } 142 143 internal static int TryAllocate(ref long l, out int offset, int bits) 144 { 145 var readValue = Interlocked.Read(ref l); 146 long oldReadValue, writtenValue; 147 do 148 { 149 if(!foundAtLeastThisManyConsecutiveZeroes(readValue, bits, out offset, out int _)) 150 return ErrorFailedToAllocate; 151 var mask = MakeMask(offset, bits); 152 writtenValue = readValue | mask; 153 oldReadValue = readValue; 154 readValue = Interlocked.CompareExchange(ref l, writtenValue, oldReadValue); 155 } while(readValue != oldReadValue); 156 return math.countbits(readValue); // how many bits were set, before i allocated? sometimes if 0, do something special (allocate chunk?) 157 } 158 159 internal static int TryAllocate<T>(ref T t, int offset, int bits) where T : IIndexable<long> 160 { 161 var wordOffset = offset >> 6; 162 var bitOffset = offset & 63; 163 if(bitOffset + bits > 64) 164 return ErrorAllocationCrossesWordBoundary; 165 return TryAllocate(ref t.ElementAt(wordOffset), bitOffset, bits); 166 } 167 168 internal static int TryFree<T>(ref T t, int offset, int bits) where T : IIndexable<long> 169 { 170 var wordOffset = offset >> 6; 171 var bitOffset = offset & 63; 172 return TryFree(ref t.ElementAt(wordOffset), bitOffset, bits); 173 } 174 175 internal static int TryAllocate<T>(ref T t, out int offset, int begin, int end, int bits) where T : IIndexable<long> 176 { 177 var wordOffset = begin; 178 for(; wordOffset < end; ++wordOffset) 179 if(t.ElementAt(wordOffset) != ~0L) 180 break; 181 for(; wordOffset < end; ++wordOffset) 182 { 183 int error, bitOffset; 184 error = TryAllocate(ref t.ElementAt(wordOffset), out bitOffset, bits); 185 if(Succeeded(error)) 186 { 187 offset = wordOffset * 64 + bitOffset; 188 return error; 189 } 190 } 191 offset = -1; 192 return ErrorFailedToAllocate; 193 } 194 195 internal static int TryAllocate<T>(ref T t, out int offset, int begin, int bits) where T : IIndexable<long> 196 { 197 var error = TryAllocate(ref t, out offset, begin, t.Length, bits); 198 if(Succeeded(error)) 199 return error; 200 return TryAllocate(ref t, out offset, 0, begin, bits); 201 } 202 203 internal static int TryAllocate<T>(ref T t, out int offset, int bits) where T : IIndexable<long> 204 { 205 return TryAllocate(ref t, out offset, 0, t.Length, bits); 206 } 207 208 } 209}