Comme l'a suggéré Christophe Lambrechts, BitVector32 offre une solution. Les performances devraient être suffisantes, mais je n'en suis pas sûr. Voici le code illustrant cette solution :
public struct rcSpan
{
//C# Spec 10.4.5.1: The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration.
internal static readonly BitVector32.Section sminSection = BitVector32.CreateSection(0x1FFF);
internal static readonly BitVector32.Section smaxSection = BitVector32.CreateSection(0x1FFF, sminSection);
internal static readonly BitVector32.Section areaSection = BitVector32.CreateSection(0x3F, smaxSection);
internal BitVector32 data;
//public uint smin : 13;
public uint smin
{
get { return (uint)data[sminSection]; }
set { data[sminSection] = (int)value; }
}
//public uint smax : 13;
public uint smax
{
get { return (uint)data[smaxSection]; }
set { data[smaxSection] = (int)value; }
}
//public uint area : 6;
public uint area
{
get { return (uint)data[areaSection]; }
set { data[areaSection] = (int)value; }
}
}
Vous pouvez faire beaucoup de choses de cette façon. Vous pouvez même faire mieux sans utiliser BitVector32, en fournissant des accesseurs artisanaux pour chaque champ :
public struct rcSpan2
{
internal uint data;
//public uint smin : 13;
public uint smin
{
get { return data & 0x1FFF; }
set { data = (data & ~0x1FFFu ) | (value & 0x1FFF); }
}
//public uint smax : 13;
public uint smax
{
get { return (data >> 13) & 0x1FFF; }
set { data = (data & ~(0x1FFFu << 13)) | (value & 0x1FFF) << 13; }
}
//public uint area : 6;
public uint area
{
get { return (data >> 26) & 0x3F; }
set { data = (data & ~(0x3F << 26)) | (value & 0x3F) << 26; }
}
}
Étonnamment, cette dernière solution artisanale semble être la plus pratique, la moins compliquée et la plus courte. Il ne s'agit bien sûr que de ma préférence personnelle.