Last active
June 9, 2021 15:31
-
-
Save WhiteBlackGoose/3e89f88becb0cdc25a167739f777ea46 to your computer and use it in GitHub Desktop.
A T4 template for generating some kind of dynamic for numeric types
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.Runtime.InteropServices; | |
| using System.Runtime.CompilerServices; | |
| <# var typesArray = new[]{ "byte", "sbyte", "ushort", "short", "uint", "int", "ulong", "long", "float", "double" }; #> | |
| <# var types = new System.Collections.Generic.List<(string, int)>(); #> | |
| <# var i = 0; | |
| foreach (var type in typesArray) | |
| { | |
| types.Add((type, i)); | |
| i++; | |
| }#> | |
| <# Func<(string, int), (string, int), string> casted = (a, b) => a.Item2 > b.Item2 ? a.Item1 : b.Item1; #> | |
| namespace DN | |
| { | |
| [StructLayout(LayoutKind.Explicit)] | |
| public struct Number | |
| { | |
| [FieldOffset(0)] | |
| private int index; | |
| <# foreach (var (type, _) in types) { #> | |
| [FieldOffset(4)] | |
| private <#= type #> <#= type #>Value; | |
| <# } #> | |
| <# foreach (var (type, id) in types) { #> | |
| public Number(<#= type #> value) | |
| { | |
| <# foreach (var (typeToSkip, _) in types) { #> | |
| Unsafe.SkipInit(out <#= typeToSkip #>Value); | |
| <# } #> | |
| <#= type #>Value = value; | |
| index = <#= id #>; | |
| } | |
| public static implicit operator Number(<#= type #> value) => new(value); | |
| <# } #> | |
| <# foreach (var op in new[] { "+", "-", "*", "/" }) { #> | |
| public static Number operator <#= op #>(Number a, Number b) | |
| => (a.index, b.index) switch | |
| { | |
| <# foreach (var (type1, id1) in types) { #> | |
| <# foreach (var (type2, id2) in types) { #> | |
| <# var cast = casted((type1, id1), (type2, id2)); #> | |
| <# if (id1 * id2 == (typesArray.Length - 1) * (typesArray.Length - 1)) { #> | |
| _ => new((<#= cast #>)a.<#= type1 #>Value <#= op #> (<#= cast #>)b.<#= type2 #>Value) | |
| <# } else { #> | |
| (<#= id1 #>, <#= id2 #>) => new((<#= cast #>)a.<#= type1 #>Value <#= op #> (<#= cast #>)b.<#= type2 #>Value), | |
| <# } #> | |
| <# } #> | |
| <# } #> | |
| }; | |
| <# } #> | |
| public override string ToString() | |
| => index switch | |
| { | |
| <# foreach (var (type1, id1) in types) { #> | |
| <# if (id1 == typesArray.Length - 1) { #> | |
| _ => <#= type1 #>Value.ToString() | |
| <# } else { #> | |
| <#= id1 #> => <#= type1 #>Value.ToString(), | |
| <# } #> | |
| <# } #> | |
| }; | |
| public string ToString(bool includeType) | |
| => !includeType ? ToString() : | |
| index switch | |
| { | |
| <# foreach (var (type1, id1) in types) { #> | |
| <# if (id1 == typesArray.Length - 1) { #> | |
| _ => "<#= type1 #>: " + <#= type1 #>Value.ToString() | |
| <# } else { #> | |
| <#= id1 #> => "<#= type1 #>: " + <#= type1 #>Value.ToString(), | |
| <# } #> | |
| <# } #> | |
| }; | |
| public static bool TryParse(string s, out Number res) | |
| { | |
| res = default; | |
| <# foreach (var (type, _) in types) { #> | |
| if (<#= type #>.TryParse(s, out var <#= type #>Value)) | |
| { | |
| res = new(<#= type #>Value); | |
| return true; | |
| } | |
| <# } #> | |
| return false; | |
| } | |
| public static Number Parse(string s) | |
| => TryParse(s, out var res) ? res : throw new(); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment