Skip to content

Instantly share code, notes, and snippets.

@michel-pi
Last active July 17, 2023 20:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save michel-pi/ce639930a7985ff6f9eeb1971ff930b8 to your computer and use it in GitHub Desktop.
Save michel-pi/ce639930a7985ff6f9eeb1971ff930b8 to your computer and use it in GitHub Desktop.
Packing integers
using System;
using System.Runtime.InteropServices;
namespace Data
{
[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct PackedInteger
{
/*
* Use cases:
*
* - Store multiple values in a single database field
* - Send multiple values as a single value over the network
* - Encode data
*
*/
/*
* Packing four 2-byte integers into a 8-byte integer
*
* Adjust the order to your needs
* (logically it would be the other way round)
* (the curent implementation is in the logical order)
*
* Think: From MSB to LSB.
* To change order swap int1 with int4, int2 with int3
*
* Value = (int1 << 48) | (int2 << 32) | (int3 << 16) | int4;
*
* int1 = (Value >> 48) & 0xFFFF
* int2 = (Value >> 32) & 0xFFFF
* int3 = (Value >> 16) & 0xFFFF
* int4 = Value & 0xFFFF
*
* REMEMBER: CAST TO CORRECT TARGET DATATYPE WHEN NEEDED. TEST YOUR CODE!
*
*/
[FieldOffset(0)] public ulong Value;
/*
* MSB vs. LSB
*
* MSB - Most significant bits
* LSB - Least significant bits
*
* 110011
* ^ MSB
*
* 110011
* ^ LSB
*
* Examples:
*
* All fields init to 0
*
* Storing a number in "Left" -> LSB
* Example: Left: 64 == Value: 64
*
* ~
*
* All fields init to 0
*
* Storing a number in "Right" -> MSB
* Example: Right: 64 == Value: 274877906944
*
*/
[FieldOffset(0)] public uint Left;
[FieldOffset(4)] public uint Right;
public PackedInteger(uint left, uint right)
{
Left = left;
Right = right;
}
public static PackedInteger Pack(uint left, uint right)
{
// shift the second integer and store in MSB
// combine the first integer using "OR" and store in LSB
return new PackedInteger
{
// CAST IS IMPORTANT!
Value = ((ulong)right << 32) | left
};
}
public readonly ulong Unpack(out uint left, out uint right)
{
// extract the LSB with a mask
left = (uint)(Value & 0xFFFFFFFF); // CAST IS IMPORTANT!
// extract the MSB by shifting
right = (uint)(Value >> 32); // CAST IS IMPORTANT!
return Value;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment