123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- using System;
- using System.Threading;
- using Unity.Collections.LowLevel.Unsafe;
- using Unity.Mathematics;
-
- #pragma warning disable 0649
-
- namespace Unity.Collections
- {
- internal struct Long8
- {
- internal long f0,f1,f2,f3,f4,f5,f6,f7;
- }
-
- internal struct Long64
- {
- internal Long8 f0,f1,f2,f3,f4,f5,f6,f7;
- }
-
- internal struct Long512
- {
- internal Long64 f0,f1,f2,f3,f4,f5,f6,f7;
- }
-
- internal struct Long1024 : IIndexable<long>
- {
- internal Long512 f0,f1;
- public int Length { get { return 1024;} set {} }
- public ref long ElementAt(int index)
- {
- unsafe { fixed(Long512* p = &f0) {
- return ref UnsafeUtility.AsRef<long>((long*)p + index);
- } }
- }
- }
-
- internal class ConcurrentMask
- {
- internal static long AtomicOr(ref long destination, long source)
- {
- var readValue = Interlocked.Read(ref destination);
- long oldReadValue, writtenValue;
- do
- {
- writtenValue = readValue | source;
- oldReadValue = readValue;
- readValue = Interlocked.CompareExchange(ref destination, writtenValue, oldReadValue);
- } while(readValue != oldReadValue);
- return writtenValue;
- }
-
- internal static long AtomicAnd(ref long destination, long source)
- {
- var readValue = Interlocked.Read(ref destination);
- long oldReadValue, writtenValue;
- do
- {
- writtenValue = readValue & source;
- oldReadValue = readValue;
- readValue = Interlocked.CompareExchange(ref destination, writtenValue, oldReadValue);
- } while(readValue != oldReadValue);
- return writtenValue;
- }
-
- internal static void longestConsecutiveOnes(long value, out int offset, out int count)
- {
- count = 0;
- var newvalue = value;
- while(newvalue != 0)
- {
- value = newvalue;
- newvalue = value & (long)((ulong)value >> 1);
- ++count;
- }
- offset = math.tzcnt(value);
- }
-
- internal static bool foundAtLeastThisManyConsecutiveOnes(long value, int minimum, out int offset, out int count)
- {
- if(minimum == 1)
- {
- offset = math.tzcnt(value); // find offset of first 1 bit
- count = 1;
- return offset != 64;
- }
- longestConsecutiveOnes(value, out offset, out count);
- return count >= minimum;
- }
-
- internal static bool foundAtLeastThisManyConsecutiveZeroes(long value, int minimum, out int offset, out int count)
- {
- return foundAtLeastThisManyConsecutiveOnes(~value, minimum, out offset, out count);
- }
-
- internal const int ErrorFailedToFree = -1;
- internal const int ErrorFailedToAllocate = -2;
- internal const int ErrorAllocationCrossesWordBoundary = -3;
- internal const int EmptyBeforeAllocation = 0;
- internal const int EmptyAfterFree = 0;
-
- internal static bool Succeeded(int error)
- {
- return error >= 0;
- }
-
- internal static long MakeMask(int offset, int bits)
- {
- return (long)(~0UL >> (64-bits)) << offset;
- }
-
- internal static int TryAllocate(ref long l, int offset, int bits)
- {
- var mask = MakeMask(offset, bits);
- var readValue = Interlocked.Read(ref l);
- long oldReadValue, writtenValue;
- do
- {
- if((readValue & mask) != 0)
- return ErrorFailedToAllocate;
- writtenValue = readValue | mask;
- oldReadValue = readValue;
- readValue = Interlocked.CompareExchange(ref l, writtenValue, oldReadValue);
- } while(readValue != oldReadValue);
- return math.countbits(readValue); // how many bits were set, before i allocated? sometimes if 0, do something special (allocate chunk?)
- }
-
- internal static int TryFree(ref long l, int offset, int bits)
- {
- var mask = MakeMask(offset, bits);
- var readValue = Interlocked.Read(ref l);
- long oldReadValue, writtenValue;
- do
- {
- if((readValue & mask) != mask)
- return ErrorFailedToFree;
- writtenValue = readValue & ~mask;
- oldReadValue = readValue;
- readValue = Interlocked.CompareExchange(ref l, writtenValue, oldReadValue);
- } while(readValue != oldReadValue);
- return math.countbits(writtenValue); // how many bits are set, after i freed? sometimes if 0, do something special (free chunk?)
- }
-
- internal static int TryAllocate(ref long l, out int offset, int bits)
- {
- var readValue = Interlocked.Read(ref l);
- long oldReadValue, writtenValue;
- do
- {
- if(!foundAtLeastThisManyConsecutiveZeroes(readValue, bits, out offset, out int _))
- return ErrorFailedToAllocate;
- var mask = MakeMask(offset, bits);
- writtenValue = readValue | mask;
- oldReadValue = readValue;
- readValue = Interlocked.CompareExchange(ref l, writtenValue, oldReadValue);
- } while(readValue != oldReadValue);
- return math.countbits(readValue); // how many bits were set, before i allocated? sometimes if 0, do something special (allocate chunk?)
- }
-
- internal static int TryAllocate<T>(ref T t, int offset, int bits) where T : IIndexable<long>
- {
- var wordOffset = offset >> 6;
- var bitOffset = offset & 63;
- if(bitOffset + bits > 64)
- return ErrorAllocationCrossesWordBoundary;
- return TryAllocate(ref t.ElementAt(wordOffset), bitOffset, bits);
- }
-
- internal static int TryFree<T>(ref T t, int offset, int bits) where T : IIndexable<long>
- {
- var wordOffset = offset >> 6;
- var bitOffset = offset & 63;
- return TryFree(ref t.ElementAt(wordOffset), bitOffset, bits);
- }
-
- internal static int TryAllocate<T>(ref T t, out int offset, int begin, int end, int bits) where T : IIndexable<long>
- {
- var wordOffset = begin;
- for(; wordOffset < end; ++wordOffset)
- if(t.ElementAt(wordOffset) != ~0L)
- break;
- for(; wordOffset < end; ++wordOffset)
- {
- int error, bitOffset;
- error = TryAllocate(ref t.ElementAt(wordOffset), out bitOffset, bits);
- if(Succeeded(error))
- {
- offset = wordOffset * 64 + bitOffset;
- return error;
- }
- }
- offset = -1;
- return ErrorFailedToAllocate;
- }
-
- internal static int TryAllocate<T>(ref T t, out int offset, int begin, int bits) where T : IIndexable<long>
- {
- var error = TryAllocate(ref t, out offset, begin, t.Length, bits);
- if(Succeeded(error))
- return error;
- return TryAllocate(ref t, out offset, 0, begin, bits);
- }
-
- internal static int TryAllocate<T>(ref T t, out int offset, int bits) where T : IIndexable<long>
- {
- return TryAllocate(ref t, out offset, 0, t.Length, bits);
- }
-
- }
- }
|