Files
Project-M/Packages/com.rukhanka.animation/Rukhanka.Toolbox/BitFieldN.cs
T
2026-05-31 14:27:52 -07:00

121 lines
3.8 KiB
C#

using System;
using System.Diagnostics;
using Unity.Assertions;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Toolbox
{
// This struct intended to be used as bitfield over existing memory
public unsafe struct BitFieldN
{
uint* ptr;
int sizeInInts;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public BitFieldN(uint* ptr, int sizeInInts, NativeArrayOptions options = NativeArrayOptions.ClearMemory)
{
this.ptr = ptr;
this.sizeInInts = sizeInInts;
if (options == NativeArrayOptions.ClearMemory)
Clear();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public BitFieldN Clone(uint* ptr)
{
var rv = new BitFieldN(ptr, sizeInInts, NativeArrayOptions.UninitializedMemory);
rv.CopyFrom(this);
return rv;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void CopyFrom(BitFieldN o)
{
UnsafeUtility.MemCpy(ptr, o.ptr, sizeInInts * sizeof(int));
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public static int CalculateUIntsCountForGivenBitCount(int bitCount)
{
var rv = (bitCount >> 5);
var k = math.min(bitCount & 0x1f, 1);
return rv + k;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public bool IsSet(int pos)
{
CheckArgs(pos, 1);
var intIdx = GetIntIndexForBitPos(pos);
var rv = Bitwise.ExtractBits(ptr[intIdx], pos, 1);
return rv != 0u;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void Set(int pos, bool value)
{
CheckArgs(pos, 1);
var intIdx = GetIntIndexForBitPos(pos);
ptr[intIdx] = Bitwise.SetBits(ptr[intIdx], pos, 1, value);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void Clear()
{
UnsafeUtility.MemClear(ptr, sizeInInts * 4);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public bool TestAny()
{
var v = 0u;
for (var i = 0; i < sizeInInts; ++i)
{
v |= ptr[i];
}
return v != 0;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int GetIntIndexForBitPos(int pos) => pos >> 5;
public bool IsCreated => ptr != null;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public int SizeInInts() => sizeInInts;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public int Length
{
get => sizeInInts << 3;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
void CheckArgs(int pos, int numBits)
{
if (pos + numBits < 0 || pos + numBits > sizeInInts * 32)
{
throw new ArgumentException($"BitFieldN invalid arguments: pos {pos} and numBits {numBits} must be within array capacity {sizeInInts * 32}");
}
}
}
}