using System;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
namespace Unity.Netcode
{
///
/// This is a simple resizable bit vector - i.e., a list of flags that use 1 bit each and can
/// grow to an indefinite size. This is backed by a NativeList<byte> instead of a single
/// integer value, allowing it to contain any size of memory. Contains built-in serialization support.
///
internal struct ResizableBitVector : INetworkSerializable, IDisposable
{
private NativeList m_Bits;
private const int k_Divisor = sizeof(byte) * 8;
public ResizableBitVector(Allocator allocator)
{
m_Bits = new NativeList(allocator);
}
public void Dispose()
{
m_Bits.Dispose();
}
public int GetSerializedSize()
{
return sizeof(int) + m_Bits.Length;
}
private (int, int) GetBitData(int i)
{
var index = i / k_Divisor;
var bitWithinIndex = i % k_Divisor;
return (index, bitWithinIndex);
}
///
/// Set bit 'i' - i.e., bit 0 is 00000001, bit 1 is 00000010, and so on.
/// There is no upper bound on i except for the memory available in the system.
///
///
public void Set(int i)
{
var (index, bitWithinIndex) = GetBitData(i);
if (index >= m_Bits.Length)
{
m_Bits.Resize(index + 1, NativeArrayOptions.ClearMemory);
}
m_Bits[index] |= (byte)(1 << bitWithinIndex);
}
///
/// Unset bit 'i' - i.e., bit 0 is 00000001, bit 1 is 00000010, and so on.
/// There is no upper bound on i except for the memory available in the system.
/// Note that once a BitVector has grown to a certain size, it will not shrink back down,
/// so if you set and unset every bit, it will still serialize at its high watermark size.
///
///
public void Unset(int i)
{
var (index, bitWithinIndex) = GetBitData(i);
if (index >= m_Bits.Length)
{
return;
}
m_Bits[index] &= (byte)~(1 << bitWithinIndex);
}
///
/// Check if bit 'i' is set - i.e., bit 0 is 00000001, bit 1 is 00000010, and so on.
/// There is no upper bound on i except for the memory available in the system.
///
///
public bool IsSet(int i)
{
var (index, bitWithinIndex) = GetBitData(i);
if (index >= m_Bits.Length)
{
return false;
}
return (m_Bits[index] & (byte)(1 << bitWithinIndex)) != 0;
}
public unsafe void NetworkSerialize(BufferSerializer serializer) where T : IReaderWriter
{
var length = m_Bits.Length;
serializer.SerializeValue(ref length);
m_Bits.ResizeUninitialized(length);
var ptr = m_Bits.GetUnsafePtr();
{
if (serializer.IsReader)
{
serializer.GetFastBufferReader().ReadBytesSafe((byte*)ptr, length);
}
else
{
serializer.GetFastBufferWriter().WriteBytesSafe((byte*)ptr, length);
}
}
}
}
}