Skip to content

Instantly share code, notes, and snippets.

@juliusfriedman
Created July 19, 2020 16:42
Show Gist options
  • Save juliusfriedman/51877ed34a9cf874e700ead77e57a782 to your computer and use it in GitHub Desktop.
Save juliusfriedman/51877ed34a9cf874e700ead77e57a782 to your computer and use it in GitHub Desktop.
Chirality
```cs
/// <summary>
/// A packed data structure which stored various attributes and can be used to determine how similar or diferrent a something is to something else
/// It achieves this by containing 32 bytes (2 <see cref="decimal"/>'s) with overlapped parts which are bit packed.
/// All values are stored in <see cref="Common.Binary.IsLittleEndian"/> so are only reversed when reading or writing <see cref="Common.Binary.IsBigEndian"/>.
/// </summary>
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit, Size = 32)]
public ref struct Chirality
{
#region Fields
//0-31
[System.Runtime.InteropServices.FieldOffset(0)]
System.Runtime.Intrinsics.Vector256<byte> Vector256;
//0-15
[System.Runtime.InteropServices.FieldOffset(0)]
System.Runtime.Intrinsics.Vector128<byte> Vector;
//0-15
[System.Runtime.InteropServices.FieldOffset(0)]
#pragma warning disable CA1051 // Do not declare visible instance fields
public decimal Value;
#pragma warning restore CA1051 // Do not declare visible instance fields
//0-15
[System.Runtime.InteropServices.FieldOffset(0)]
Guid Overlapped;
//0-3
[System.Runtime.InteropServices.FieldOffset(0)]
uint A;
//4-7
[System.Runtime.InteropServices.FieldOffset(4)]
uint B;
//8-11
[System.Runtime.InteropServices.FieldOffset(8)]
uint C;
//12-15
[System.Runtime.InteropServices.FieldOffset(12)]
uint D;
//0-7
[System.Runtime.InteropServices.FieldOffset(0)]
ulong LowOverlapped;
//0-7
[System.Runtime.InteropServices.FieldOffset(0)]
double OverlappedLow;
//8-15
[System.Runtime.InteropServices.FieldOffset(8)]
ulong HighOverlapped;
[System.Runtime.InteropServices.FieldOffset(8)]
double OverlappedHigh;
//16-31
[System.Runtime.InteropServices.FieldOffset(16)]
System.Runtime.Intrinsics.Vector128<byte> Vector2;
//16-31
[System.Runtime.InteropServices.FieldOffset(16)]
#pragma warning disable CA1051 // Do not declare visible instance fields
public decimal Value2;
#pragma warning restore CA1051 // Do not declare visible instance fields
//16-31
[System.Runtime.InteropServices.FieldOffset(16)]
Guid Overlapped2;
//16-19
[System.Runtime.InteropServices.FieldOffset(16)]
uint E;
//20-23
[System.Runtime.InteropServices.FieldOffset(20)]
uint F;
//24-28
[System.Runtime.InteropServices.FieldOffset(24)]
uint G;
//28-32
[System.Runtime.InteropServices.FieldOffset(28)]
uint H;
//16-31
[System.Runtime.InteropServices.FieldOffset(16)]
ulong LowOverlapped2;
//16-31
[System.Runtime.InteropServices.FieldOffset(16)]
double OverlappedLow2;
//24-31
[System.Runtime.InteropServices.FieldOffset(24)]
ulong HighOverlapped2;
//24-31
[System.Runtime.InteropServices.FieldOffset(24)]
double OverlappedHigh2;
#endregion
#region Properties
/// <summary>
/// Gets or Sets the Raw Binary data assoicated with the instance (32 bytes)
/// </summary>
public Span<byte> RawBytes
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return System.Runtime.InteropServices.MemoryMarshal.CreateSpan(ref System.Runtime.CompilerServices.Unsafe.As<decimal, byte>(ref Value), 32); } //Must be updated from Size in declaration
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set { value.CopyTo(RawBytes); }
}
//Values 0-6 occupies only 3 bits
/// <summary>
/// The <see cref="System.DayOfWeek"/>
/// </summary>
public DayOfWeek DayOfWeek
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return (DayOfWeek)Common.Binary.ReadBits(RawBytes, 0, 3, Common.Binary.IsBigEndian); }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set
{
if (value < 0 || (int)value > 6) throw new ArgumentOutOfRangeException($"{nameof(value)},{value} cannot be less than 0 or exceed 6.");
Common.Binary.WriteBits(RawBytes, 0, 3, (int)value, Common.Binary.IsBigEndian);
}
}
//5 bits remain in the byte at 0
//0-24 occupies 5 bits, max value 31
/// <summary>
/// The hour of <see cref="DayOfMonth"/>
/// </summary>
public byte HourOfDay
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return (byte)Common.Binary.ReadBits(RawBytes, 3, 5, Common.Binary.IsBigEndian); }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set
{
//31 is max value here technically
if (value < 0 || value > 24) throw new ArgumentOutOfRangeException($"{nameof(value)},{value} cannot be less than 0 or exceed 24.");
Common.Binary.WriteBits(RawBytes, 3, 5, value, Common.Binary.IsBigEndian);
}
}
//0 bits remain in byte at 0.
//Value 0-60 occupy 6 bits so this can be packed further
/// <summary>
/// The minute in the hour of <see cref="HourOfDay"/>
/// </summary>
public byte MinuteOfHour
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return (byte)Common.Binary.ReadBits(RawBytes, 8, 6, Common.Binary.IsBigEndian); }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set
{
if (value < 0 || value > 60) throw new ArgumentOutOfRangeException($"{nameof(value)},{value} cannot be less than 0 or exceed 60.");
Common.Binary.WriteBits(RawBytes, 8, 6, value, Common.Binary.IsBigEndian);
}
}
//2 bits remain in the byte at 1
//0-3 can be stored in the 2 bits that remain
/// <summary>
/// Values 0-3
/// </summary>
public byte ComponentA
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return (byte)Common.Binary.ReadBits(RawBytes, 14, 2, Common.Binary.IsBigEndian); }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set
{
if (value < 0 || value > 3) throw new ArgumentOutOfRangeException($"{nameof(value)},{value} cannot be less than 0 or exceed 3.");
Common.Binary.WriteBits(RawBytes, 14, 2, value, Common.Binary.IsBigEndian);
}
}
//0 bits remain in the byte at 1
//0-31 occupy 5 bits (max value)
/// <summary>
/// The month
/// </summary>
public byte Month
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return (byte)Common.Binary.ReadBits(RawBytes, 16, 5, Common.Binary.IsBigEndian); }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set
{
//31 is techincally the max
if (value < 0 || value > 12) throw new ArgumentOutOfRangeException($"{nameof(value)},{value} cannot be less than 0 or exceed 12.");
Common.Binary.WriteBits(RawBytes, 16, 5, value, Common.Binary.IsBigEndian);
}
}
//3 bits remain in the byte at 2
//0-5 can be stored in the 3 bits that remain
/// <summary>
/// Values 0-5
/// </summary>
public byte ComponentB
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return (byte)Common.Binary.ReadBits(RawBytes, 21, 3, Common.Binary.IsBigEndian); }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set
{
if (value < 0 || value > 5) throw new ArgumentOutOfRangeException($"{nameof(value)},{value} cannot be less than 0 or exceed 5.");
Common.Binary.WriteBits(RawBytes, 21, 3, value, Common.Binary.IsBigEndian);
}
}
//0 bits remain in the byte at 2
//12 bytes remain in the structure
//8191 is the max value which can be stored in the remaining bits (1111111111111) 13 bits
/// <summary>
/// The year
/// </summary>
public ushort Year
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return (ushort)Common.Binary.ReadBits(RawBytes, 24, 13, Common.Binary.IsBigEndian); }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set
{
if (value < 0 || value > 8191) throw new ArgumentOutOfRangeException($"{nameof(value)},{value} cannot be less than 0 or exceed 8191.");
Common.Binary.WriteBits(RawBytes, 24, 13, value, Common.Binary.IsBigEndian);
}
}
/// <summary>
/// </summary>
public DateTime UtcStartDate
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return new DateTime(Year, Month, DayOfMonth, HourOfDay, MinuteOfHour, 0, DateTimeKind.Utc); }
}
/// <summary>
/// </summary>
public DateTime UtcEndDate
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return UtcStartDate.AddHours(TotalHours); }
}
//3 bits remain in the byte at 5
//0-5 can be stored in the 3 bits that remain
/// <summary>
/// Values 0-5
/// </summary>
public byte ComponentC
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return (byte)Common.Binary.ReadBits(RawBytes, 37, 3, Common.Binary.IsBigEndian); }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set
{
if (value < 0 || value > 5) throw new ArgumentOutOfRangeException($"{nameof(value)},{value} cannot be less than 0 or exceed 5.");
Common.Binary.WriteBits(RawBytes, 37, 3, value, Common.Binary.IsBigEndian);
}
}
//0 bits remain in byte 5
//10 bytes remain in the structure
//32 bits (4 bytes)
public float FPL
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return BitConverter.ToUInt32(RawBytes.Slice(6)); }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set { BitConverter.GetBytes(value).CopyTo(RawBytes.Slice(6)); }
}
//6 bytes remain
//0- 255 8 bits (1 byte)
/// <summary>
/// </summary>
public byte SomeByte
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return RawBytes[10]; }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set { RawBytes[10] = value; }
}
//5 bytes remain
//0-255 8 bits (1 byte)
/// <summary>
/// </summary>
public byte AnotherByte
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return RawBytes[11]; }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set { RawBytes[11] = value; }
}
//4 bytes remain
//32 bits (4 bytes)
/// <summary>
/// </summary>
public float SomethingElse
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return BitConverter.ToUInt32(RawBytes.Slice(12)); }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set { BitConverter.GetBytes(value).CopyTo(RawBytes.Slice(12)); }
}
//16 bytes remains
/// </summary>
ushort AnotherThing
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return (ushort)Common.Binary.ReadBits(RawBytes, 128, 9, Common.Binary.IsBigEndian); }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set
{
if (value < byte.MinValue || value > 360) throw new ArgumentOutOfRangeException($"{nameof(value)},{value} cannot be less than 0 or exceed 360.");
Common.Binary.WriteBits(RawBytes, 128, 9, value, false);
}
}
//7 bits remains in byte at 16( used 1 bit out of byte 16 )
//0-127 can be stored in the 7 bits that remain
/// <summary>
/// Values 0-127
/// </summary>
public ushort ComponentD
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return (ushort)Common.Binary.ReadBits(RawBytes, 137, 7, false); }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set
{
if (value < byte.MinValue || value > sbyte.MaxValue) throw new ArgumentOutOfRangeException($"{nameof(value)},{value} cannot be less than 0 or exceed 127.");
Common.Binary.WriteBits(RawBytes, 137, 7, value, Common.Binary.IsBigEndian);
}
}
//14 bytes remain in the structure
////0 - 255 8 bits (1 byte)
byte ByteAgain
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return RawBytes[19]; }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set { RawBytes[19] = value; }
}
/// <summary>
/// The day of the <see cref="Month"/>
/// </summary>
byte DayOfMonth
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return (byte)Common.Binary.ReadBits(RawBytes, 5, 160, Common.Binary.IsBigEndian); }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set
{
if (value < 0 || value > 31) throw new ArgumentOutOfRangeException($"{nameof(value)},{value} cannot be less than 0 or exceed 31.");
Common.Binary.WriteBits(RawBytes, 5, 160, value, Common.Binary.IsBigEndian);
}
}
//3 bits remain in the byte at 20
/// <summary>
/// Values 0-3
/// </summary>
public byte ComponentE
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get { return (byte)Common.Binary.ReadBits(RawBytes, 3, 165, Common.Binary.IsBigEndian); }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set
{
if (value < 0 || value > 3) throw new ArgumentOutOfRangeException($"{nameof(value)},{value} cannot be less than 0 or exceed 3.");
Common.Binary.WriteBits(RawBytes, 3, 165, value, Common.Binary.IsBigEndian);
}
}
/// <summary>
/// The version of this structure
/// </summary>
/// <remarks>
/// Needs constant and shared constructor to set from.
/// </remarks>
public ushort Version
{
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get
{
if (Common.Binary.IsLittleEndian)
{
return BitConverter.ToUInt16(RawBytes.Slice(21, 2));
}
return BinaryPrimitives.ReverseEndianness(BitConverter.ToUInt16(RawBytes.Slice(21, 2)));
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set { Common.Binary.Write16(RawBytes, 21, Common.Binary.IsBigEndian, value); }
}
//14 bytes remain in the structure
//2 bytes version = 10 bytes = 80 bits
//enough for (8 bytes, 4 shorts/ushorts, 2 ints, 1 double/long/ulong), (2 bytes, 1 ushort).
#endregion
#region Constructors
/// <summary>
/// From a <see cref="decimal"/> value in the same <see cref="Common.Binary.ByteOrder"/>
/// </summary>
/// <param name="value"></param>
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public Chirality(decimal value) : this()
{
Value = value;
}
/// <summary>
/// From a <see cref="Guid"/> in the same <see cref="Common.Binary.ByteOrder"/>
/// </summary>
/// <param name="value"></param>
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public Chirality(Guid value) : this()
{
Overlapped = value;
}
#endregion
#region Methods
/// <summary>
/// Indicates if the <paramref name="chirality"/> has the same <see cref="DayOfWeek"/>.
/// </summary>
/// <param name="chirality">The <see cref="Chirality"/></param>
/// <returns><see langword="true"/> when <see cref="DayOfWeek"/> is equal to the given <paramref name="chirality"/></returns>
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public bool IsAchircalToDayOfWeek(Chirality chirality)
{
return DayOfWeek == chirality.DayOfWeek;
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public bool IsAchiralToDayOfMonth(Chirality chirality)
{
return DayOfMonth == chirality.DayOfMonth;
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public bool IsAchiralToMonth(Chirality chirality)
{
return Month == chirality.Month;
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public bool IsAchiralToHourOfDay(Chirality chirality)
{
return HourOfDay == chirality.HourOfDay;
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public bool IsAchiralToYear(Chirality chirality)
{
return Year == chirality.Year;
}
#endregion
#region Operators
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
#pragma warning disable CA2225 // Operator overloads have named alternates
public static implicit operator decimal(Chirality chirality) { return chirality.Value; }
#pragma warning restore CA2225 // Operator overloads have named alternates
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
#pragma warning disable CA2225 // Operator overloads have named alternates
public static implicit operator Chirality(decimal value) { return new Chirality(value); }
#pragma warning restore CA2225 // Operator overloads have named alternates
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
#pragma warning disable CA2225 // Operator overloads have named alternates
public static implicit operator Guid(Chirality chirality) { return chirality.Overlapped; }
#pragma warning restore CA2225 // Operator overloads have named alternates
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
#pragma warning disable CA2225 // Operator overloads have named alternates
public static implicit operator Chirality(Guid value) { return new Chirality(value); }
#pragma warning restore CA2225 // Operator overloads have named alternates
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
#pragma warning disable CA2225 // Operator overloads have named alternates
public static implicit operator DayOfWeek(Chirality chirality) { return chirality.DayOfWeek; }
#pragma warning restore CA2225 // Operator overloads have named alternates
#endregion
#region Overrides
//https://github.com/dotnet/roslyn/issues/45799#event-3531001732
public override bool Equals(object other) => throw null;
//Not override but ref struct cannot be boxes and cannot implement a equals object overload.
public bool Equals(ref Chirality other)
{
return Vector.Equals(other.Vector256);
}
public override int GetHashCode()
{
return Vector256.GetHashCode();
}
public static bool operator ==(Chirality left, Chirality right)
{
return left.Equals(ref right);
}
public static bool operator !=(Chirality left, Chirality right)
{
return !(left == right);
}
#endregion
}
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment