Skip to content

aka-nse/EfficientUnionGenerator

Repository files navigation

EfficientUnionGenerator

Based on C# 15's Union type support, EfficientUnionGenerator provides highly efficient Union type support that avoids boxing.

  • The unions which are generated by EfficientUnionGenerator can contain both of unmanaged types and managed types.
  • Managed types are erasured its type information into object field and they are casted by type checking when read.
  • Unmanaged types are convolved into single field and they are identified by an enum identifier.
  • For unmanaged types, also the type identifier can be convolved into the value field. In this case, specified bit mask is used to set or read type identifier.

How to use

EfficientUnionGenerator regards structs which are annotated with EfficientUnion.EfficientUnionAttribute as union types and generates union type support for them. Also it regards public partial constructors with single parameter as the members of the union.

Simple union

Following code is the most simple example of how to use EfficientUnionGenerator.

using EfficientUnion;

[EfficientUnion]
public readonly partial struct Int32OrString
{
    public partial Int32OrString(int x);
    public partial Int32OrString(string x);
}
generation result
// <auto-generated/>
#nullable enable
namespace EfficientUnionGenerator.SampleApp.SimpleUnionOfInt32OrString;


partial struct Int32OrString
{
    private enum __TypeSpecifier : byte
    {
        __int = 1,

        __Undefined = 0,
    }

    private const bool __defaultTypeSpecifierHasType = false;
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)]
    private struct __UnmanagedField
    {
        [System.Runtime.InteropServices.FieldOffset(0)] public int __int;
    }

    private readonly __UnmanagedField __unmanagedField;
    private readonly __TypeSpecifier __typeSpecifier;

    private bool HasUnmanagedValue => __typeSpecifier != __TypeSpecifier.__Undefined || __defaultTypeSpecifierHasType;
    private object? UnmanagedValue => __typeSpecifier switch
    {
        __TypeSpecifier.__int => __unmanagedField.__int,
        _ => null,
    };

    public partial Int32OrString(int x)
    {
        __unmanagedField = new()
        {
            __int = x,
        };
        __typeSpecifier = __TypeSpecifier.__int;
    }
    public bool TryGetValue(out int value)
    {
        if (__typeSpecifier == __TypeSpecifier.__int)
        {
            value = __unmanagedField.__int;
            return true;
        }
        else
        {
            value = default;
            return false;
        }
    }

    private readonly object? __managedField;

    public partial Int32OrString(string x)
    {
        __managedField = x;
    }

    public bool TryGetValue([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out string? value)
    {
        if (__managedField is string __casted)
        {
            value = __casted;
            return true;
        }
        else
        {
            value = default;
            return false;
        }
    }

    public bool HasValue => HasUnmanagedValue || __managedField is not null;
    public object? Value => HasUnmanagedValue ? UnmanagedValue : __managedField;
}

Make as an unmanaged

If all of the members of the union are unmanaged types, the union type gets also unmanaged type.

using EfficientUnion;

// This struct is also unmanaged type because all of its members are unmanaged types.
[EfficientUnion]
public readonly partial struct SignedInteger
{
    public partial SignedInteger(sbyte x);
    public partial SignedInteger(short x);
    public partial SignedInteger(int x);
    public partial SignedInteger(long x);
}
generation result
// <auto-generated/>
#nullable enable
namespace EfficientUnionGenerator.SampleApp.SimpleUnionOfSignedInteger;


partial struct SignedInteger
{
    private enum __TypeSpecifier : byte
    {
        __sbyte = 1,
        __short = 2,
        __int = 3,
        __long = 4,

        __Undefined = 0,
    }

    private const bool __defaultTypeSpecifierHasType = false;
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)]
    private struct __UnmanagedField
    {
        [System.Runtime.InteropServices.FieldOffset(0)] public sbyte __sbyte;
        [System.Runtime.InteropServices.FieldOffset(0)] public short __short;
        [System.Runtime.InteropServices.FieldOffset(0)] public int __int;
        [System.Runtime.InteropServices.FieldOffset(0)] public long __long;
    }

    private readonly __UnmanagedField __unmanagedField;
    private readonly __TypeSpecifier __typeSpecifier;

    private bool HasUnmanagedValue => __typeSpecifier != __TypeSpecifier.__Undefined || __defaultTypeSpecifierHasType;
    private object? UnmanagedValue => __typeSpecifier switch
    {
        __TypeSpecifier.__sbyte => __unmanagedField.__sbyte,
        __TypeSpecifier.__short => __unmanagedField.__short,
        __TypeSpecifier.__int => __unmanagedField.__int,
        __TypeSpecifier.__long => __unmanagedField.__long,
        _ => null,
    };

    public partial SignedInteger(sbyte x)
    {
        __unmanagedField = new()
        {
            __sbyte = x,
        };
        __typeSpecifier = __TypeSpecifier.__sbyte;
    }
    public bool TryGetValue(out sbyte value)
    {
        if (__typeSpecifier == __TypeSpecifier.__sbyte)
        {
            value = __unmanagedField.__sbyte;
            return true;
        }
        else
        {
            value = default;
            return false;
        }
    }

    public partial SignedInteger(short x)
    {
        __unmanagedField = new()
        {
            __short = x,
        };
        __typeSpecifier = __TypeSpecifier.__short;
    }
    public bool TryGetValue(out short value)
    {
        if (__typeSpecifier == __TypeSpecifier.__short)
        {
            value = __unmanagedField.__short;
            return true;
        }
        else
        {
            value = default;
            return false;
        }
    }

    public partial SignedInteger(int x)
    {
        __unmanagedField = new()
        {
            __int = x,
        };
        __typeSpecifier = __TypeSpecifier.__int;
    }
    public bool TryGetValue(out int value)
    {
        if (__typeSpecifier == __TypeSpecifier.__int)
        {
            value = __unmanagedField.__int;
            return true;
        }
        else
        {
            value = default;
            return false;
        }
    }

    public partial SignedInteger(long x)
    {
        __unmanagedField = new()
        {
            __long = x,
        };
        __typeSpecifier = __TypeSpecifier.__long;
    }
    public bool TryGetValue(out long value)
    {
        if (__typeSpecifier == __TypeSpecifier.__long)
        {
            value = __unmanagedField.__long;
            return true;
        }
        else
        {
            value = default;
            return false;
        }
    }

    public bool HasValue => HasUnmanagedValue;
    public object? Value => UnmanagedValue;
}

Field mask

You can specify the bit mask for type identifier by unmanagedFieldMask property of EfficientUnionAttribute.

using System.Runtime.CompilerServices;
using EfficientUnion;

// If it handles only positive value, the 31-th bit can be used as type identifier.
// This optimization can embed the type identifier in the value field, and eliminate the need to allocate a separate identifier field.
[EfficientUnion(unmanagedFieldMask: 0x80_00_00_00u)]
public readonly partial struct PositiveOnlyIntOrFloat
{
    public partial PositiveOnlyIntOrFloat(int value);
    public partial PositiveOnlyIntOrFloat(float value);
}

public static class Program
{
    public static void Main()
    {
        Console.WriteLine(Unsafe.SizeOf<PositiveOnlyIntOrFloat>());  // output: 4
    }
}
generation result
// <auto-generated/>
#nullable enable
namespace EfficientUnionGenerator.SampleApp.PositiveOnlyIntOrFloat;


partial struct PositiveOnlyIntOrFloat
{
    private enum __TypeSpecifier : uint
    {
        __int = 0,
        __float = 2147483648,

        __Undefined = 0,
    }

    private const bool __defaultTypeSpecifierHasType = true;
    private const __TypeSpecifier __typeSpecifierBitMask = unchecked((__TypeSpecifier)2147483648);

    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)]
    private struct __UnmanagedField
    {
        [System.Runtime.InteropServices.FieldOffset(0)] public __TypeSpecifier __typeSpecifier;
        [System.Runtime.InteropServices.FieldOffset(0)] public int __int;
        [System.Runtime.InteropServices.FieldOffset(0)] public float __float;
    }

    private readonly __UnmanagedField __unmanagedField;
    private readonly __TypeSpecifier __typeSpecifier
    {
        get => __unmanagedField.__typeSpecifier & __typeSpecifierBitMask;
        init => __unmanagedField.__typeSpecifier |= value;
    }

    private bool HasUnmanagedValue => __typeSpecifier != __TypeSpecifier.__Undefined || __defaultTypeSpecifierHasType;
    private object? UnmanagedValue
    {
        get
        {
            var maskedField = __unmanagedField;
            maskedField.__typeSpecifier &= ~__typeSpecifierBitMask;
            return __typeSpecifier switch
            {
                __TypeSpecifier.__int => maskedField.__int,
                __TypeSpecifier.__float => maskedField.__float,
                _ => null,
            };
        }
    }

    public partial PositiveOnlyIntOrFloat(int value)
    {
        __unmanagedField = new()
        {
            __int = value,
        };
        __typeSpecifier = __TypeSpecifier.__int;
    }
    public bool TryGetValue(out int value)
    {
        if (__typeSpecifier == __TypeSpecifier.__int)
        {
            var maskedField = __unmanagedField;
            maskedField.__typeSpecifier &= ~__typeSpecifierBitMask;
            value = maskedField.__int;
            return true;
        }
        else
        {
            value = default;
            return false;
        }
    }

    public partial PositiveOnlyIntOrFloat(float value)
    {
        __unmanagedField = new()
        {
            __float = value,
        };
        __typeSpecifier = __TypeSpecifier.__float;
    }
    public bool TryGetValue(out float value)
    {
        if (__typeSpecifier == __TypeSpecifier.__float)
        {
            var maskedField = __unmanagedField;
            maskedField.__typeSpecifier &= ~__typeSpecifierBitMask;
            value = maskedField.__float;
            return true;
        }
        else
        {
            value = default;
            return false;
        }
    }

    public bool HasValue => HasUnmanagedValue;
    public object? Value => UnmanagedValue;
}

Explicit type identifier value

You can specify the type identifier value by using EfficientUnion.EnumBitPatternAttribute. This is useful for such case of struct unions identified by version number field.

using EfficientUnion;

// ELF header is identified into 32-bit ELF header or 64-bit ELF header by the value of e_ident[4].
// NOTE: remind that unmanagedFieldMask is little endianness.
[EfficientUnion(Mode, unmanagedFieldMask: 0x00_00_00_FF_00_00_00_00uL)]
public readonly partial struct ElfHeader
{
    private const TypeIdentifierValueMode Mode =
        TypeIdentifierValueMode.ExplicitAssign
        | TypeIdentifierValueMode.LeaveWhenCreate
        | TypeIdentifierValueMode.LeaveWhenGet;

    [EnumBitPattern(0x00_00_00_01_00_00_00_00uL)] public partial ElfHeader(Elf32Header x);
    [EnumBitPattern(0x00_00_00_02_00_00_00_00uL)] public partial ElfHeader(Elf64Header x);
}
generation result
// <auto-generated/>
#nullable enable
namespace EfficientUnionGenerator.SampleApp.ElfHeader;


partial struct ElfHeader
{
    private enum __TypeSpecifier : ulong
    {
        __EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf32Header = 4294967296,
        __EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf64Header = 8589934592,

        __Undefined = 0,
    }

    private const bool __defaultTypeSpecifierHasType = false;
    private const __TypeSpecifier __typeSpecifierBitMask = unchecked((__TypeSpecifier)1095216660480);

    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)]
    private struct __UnmanagedField
    {
        [System.Runtime.InteropServices.FieldOffset(0)] public __TypeSpecifier __typeSpecifier;
        [System.Runtime.InteropServices.FieldOffset(0)] public EfficientUnionGenerator.SampleApp.ElfHeader.Elf32Header __EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf32Header;
        [System.Runtime.InteropServices.FieldOffset(0)] public EfficientUnionGenerator.SampleApp.ElfHeader.Elf64Header __EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf64Header;
    }

    private readonly __UnmanagedField __unmanagedField;
    private readonly __TypeSpecifier __typeSpecifier
    {
        get => __unmanagedField.__typeSpecifier & __typeSpecifierBitMask;
        init => __unmanagedField.__typeSpecifier |= value;
    }

    private bool HasUnmanagedValue => __typeSpecifier != __TypeSpecifier.__Undefined || __defaultTypeSpecifierHasType;
    private object? UnmanagedValue
    {
        get
        {
            var maskedField = __unmanagedField;
            return __typeSpecifier switch
            {
                __TypeSpecifier.__EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf32Header => maskedField.__EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf32Header,
                __TypeSpecifier.__EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf64Header => maskedField.__EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf64Header,
                _ => null,
            };
        }
    }

    public partial ElfHeader(EfficientUnionGenerator.SampleApp.ElfHeader.Elf32Header x)
    {
        __unmanagedField = new()
        {
            __EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf32Header = x,
        };
    }
    public bool TryGetValue(out EfficientUnionGenerator.SampleApp.ElfHeader.Elf32Header value)
    {
        if (__typeSpecifier == __TypeSpecifier.__EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf32Header)
        {
            value = __unmanagedField.__EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf32Header;
            return true;
        }
        else
        {
            value = default;
            return false;
        }
    }

    public partial ElfHeader(EfficientUnionGenerator.SampleApp.ElfHeader.Elf64Header x)
    {
        __unmanagedField = new()
        {
            __EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf64Header = x,
        };
    }
    public bool TryGetValue(out EfficientUnionGenerator.SampleApp.ElfHeader.Elf64Header value)
    {
        if (__typeSpecifier == __TypeSpecifier.__EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf64Header)
        {
            value = __unmanagedField.__EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf64Header;
            return true;
        }
        else
        {
            value = default;
            return false;
        }
    }

    public bool HasValue => HasUnmanagedValue;
    public object? Value => UnmanagedValue;
}

About

boxing-less union structure generator for C# 15 or later

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages