rj-action-library/Runtime/Bits/BitView__.cs

266 lines
5.9 KiB
C#
Raw Normal View History

2025-01-08 18:46:17 +00:00
using Godot;
using System.Collections.Generic;
using System.Text;
namespace Rokojori
{
public partial class BitView
{
byte[] _data;
int _internalViewOffset = 0;
public int bitOffset => _internalViewOffset;
int _internalViewSize = 0;
public int numBits => _internalViewSize;
public int numBytes => Mathf.CeilToInt( _internalViewSize / 8f );
int _externalPointer = 0;
public int pointerPosition => _externalPointer;
public void SetPointer( int bitPosition )
{
_externalPointer = bitPosition;
}
public byte[] GetBytes()
{
var numBytes = this.numBytes;
var data = new byte[ numBytes ];
System.Array.Fill( data, (byte)0 );
for ( int i = 0; i < _internalViewSize; i++ )
{
var isSet = GetValueInternal( i + _internalViewOffset );
if ( ! isSet )
{
continue;
}
var shift = i % 8;
var index = i / 8;
var value = 1 << shift;
data[ index ] = (byte) ( data[ index ] | value );
}
return data;
}
public BitView Clone()
{
var clone = new BitView();
clone._data = _data;
clone._internalViewOffset = _internalViewOffset;
clone._internalViewSize = _internalViewSize;
clone._externalPointer = _externalPointer;
return clone;
}
public string GetBitString()
{
var output = new StringBuilder();
for ( int i = 0; i < _internalViewSize; i++ )
{
var mod = i % 8;
if ( i != 0 && mod == 0 )
{
output.Append( " " );
}
var reverseIndex = 7 - mod * 2;
var value = GetValueInternal( reverseIndex + i + _internalViewOffset ) ? "1" : "0";
output.Append( value );
}
return output.ToString();
}
void SetValueInternal( int position, bool value )
{
var byteIndex = position / 8;
var bitOffset = position - byteIndex * 8;
if ( value )
{
_data[ byteIndex ] = Bytes.SetBit( _data[ byteIndex ], bitOffset );
}
else
{
_data[ byteIndex ] = Bytes.UnsetBit( _data[ byteIndex ], bitOffset );
}
}
bool GetValueInternal( int bitPosition )
{
var byteIndex = bitPosition / 8;
var bitOffset = bitPosition - byteIndex * 8;
return Bytes.IsBitSet( _data[ byteIndex ], bitOffset );
}
int GetShiftedValueInternal( int bitPosition, int shift )
{
if ( ! GetValueInternal( bitPosition ) )
{
return 0;
}
return 1 << shift;
}
void EnsureInternalSize( int bitPosition )
{
var byteIndex = bitPosition / 8;
if ( byteIndex >= _data.Length )
{
var newData = new byte[ _data.Length + 1 ];
System.Array.Fill( newData, (byte) 0 );
System.Array.Copy( _data, 0, newData, 0, _data.Length );
_data = newData;
}
}
public void Clear()
{
_externalPointer = 0;
for ( int i = 0; i < _internalViewSize; i++ )
{
SetValueInternal( i + _internalViewOffset, false );
}
}
public void ResetPointerAndSize()
{
_externalPointer = 0;
_internalViewSize = 0;
}
public void WriteBit( bool value )
{
var position = _externalPointer + _internalViewOffset;
EnsureInternalSize( position );
SetValueInternal( position, value );
_externalPointer ++;
_internalViewSize = Mathf.Max( _externalPointer, _internalViewSize );
}
public bool GetBitAt( int bitPosition )
{
var internalBitPosition = bitPosition + _internalViewOffset;
return GetValueInternal( bitPosition );
}
public bool ReadBit()
{
var bitPosition = _externalPointer + _internalViewOffset;
if ( bitPosition < 0 || bitPosition >= numBits )
{
RJLog.Log( "Can't read: >> ", bitPosition, "in", numBits, "p:", _externalPointer, "o:", _internalViewOffset );
return false;
}
var value = GetValueInternal( bitPosition );
_externalPointer ++;
return value;
}
public void SetPointerPosition( int position )
{
_externalPointer = Mathf.Clamp( position, 0, _internalViewSize );
}
public static BitView CreateEmpty()
{
var view = new BitView();
view._data = new byte[]{};
view._internalViewOffset = 0;
view._internalViewSize = 0;
view._externalPointer = 0;
return view;
}
public static BitView From( byte[] data)
{
var view = new BitView();
view._data = data;
view._internalViewOffset = 0;
view._internalViewSize = data.Length * 8;
view._externalPointer = 0;
return view;
}
public static BitView From( byte[] data, int bitSize = -1 )
{
var view = new BitView();
view._data = data;
view._internalViewOffset = 0;
view._internalViewSize = bitSize == -1 ? data.Length * 8 : bitSize;
view._externalPointer = 0;
return view;
}
public static BitView PrependBytes( byte[] before, BitView after )
{
var data = new byte[ before.Length + after.numBytes ];
System.Array.Copy( before, 0, data, 0, before.Length );
var view = BitView.From( data, before.Length * 8 + after.numBits );
if ( after.bitOffset == 0 )
{
System.Array.Copy( after._data, 0, data, 0, after.numBytes );
view.SetPointer( after.pointerPosition + before.Length * 8 );
return view;
}
view.SetPointer( before.Length * 8 );
for ( int i = 0; i < after.numBits; i++ )
{
view.WriteBit( after.GetBitAt( i ) );
}
view.SetPointer( after.pointerPosition + before.Length * 8 );
return view;
}
public static BitView PrependID( int id, BitView after )
{
var idView = BitView.CreateEmpty();
idView.WriteUIntVL8( id );
return BitView.PrependBytes( idView.GetBytes(), after );
}
}
}