Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using BenchmarkDotNet.Attributes;
- using BenchmarkDotNet.Running;
- using System;
- using System.Runtime.InteropServices;
- // A: int, string, bool の Union
- // B: int, long, DateTime, string, Uri の Union
- public enum AType
- {
- Int32,
- String,
- Bool,
- }
- public enum BType
- {
- Int32,
- Int64,
- DateTime,
- String,
- Uri,
- }
- namespace SubClass
- {
- public abstract class A
- {
- public abstract AType Type { get; }
- protected A() { }
- public class AInt32 : A { public int Value; public override AType Type => AType.Int32; }
- public class AString : A { public string Value; public override AType Type => AType.String; }
- public class ABool : A { public bool Value; public override AType Type => AType.Bool; }
- public static A New(int x) => new AInt32 { Value = x };
- public static A New(string x) => new AString { Value = x };
- public static A New(bool x) => new ABool { Value = x };
- public static explicit operator int(A x) => ((AInt32)x).Value;
- public static explicit operator string(A x) => ((AString)x).Value;
- public static explicit operator bool(A x) => ((ABool)x).Value;
- }
- public abstract class B
- {
- public abstract BType Type { get; }
- protected B() { }
- public class BInt32 : B { public int Value; public override BType Type => BType.Int32; }
- public class BInt64 : B { public long Value; public override BType Type => BType.Int64; }
- public class BDateTime : B { public DateTime Value; public override BType Type => BType.DateTime; }
- public class BString : B { public string Value; public override BType Type => BType.String; }
- public class BUri : B { public Uri Value; public override BType Type => BType.Uri; }
- public static B New(int x) => new BInt32 { Value = x };
- public static B New(long x) => new BInt64 { Value = x };
- public static B New(DateTime x) => new BDateTime { Value = x };
- public static B New(string x) => new BString { Value = x };
- public static B New(Uri x) => new BUri { Value = x };
- public static explicit operator int(B x) => ((BInt32)x).Value;
- public static explicit operator long(B x) => ((BInt64)x).Value;
- public static explicit operator DateTime(B x) => ((BDateTime)x).Value;
- public static explicit operator string(B x) => ((BString)x).Value;
- public static explicit operator Uri(B x) => ((BUri)x).Value;
- }
- }
- namespace ObjectOnly
- {
- public struct A
- {
- private object _value;
- public AType Type
- => _value is int ? AType.Int32 :
- _value is string ? AType.String :
- AType.Bool;
- public static A New(int x) => new A { _value = x };
- public static A New(string x) => new A { _value = x };
- public static A New(bool x) => new A { _value = x };
- public static explicit operator int(A x) => (int)x._value;
- public static explicit operator string(A x) => (string)x._value;
- public static explicit operator bool(A x) => (bool)x._value;
- }
- public struct B
- {
- private object _value;
- public BType Type
- => _value is int ? BType.Int32 :
- _value is long ? BType.Int64 :
- _value is DateTime ? BType.DateTime :
- _value is string ? BType.String :
- BType.Uri;
- public static B New(int x) => new B { _value = x };
- public static B New(long x) => new B { _value = x };
- public static B New(DateTime x) => new B { _value = x };
- public static B New(string x) => new B { _value = x };
- public static B New(Uri x) => new B { _value = x };
- public static explicit operator int(B x) => (int)x._value;
- public static explicit operator long(B x) => (long)x._value;
- public static explicit operator DateTime(B x) => (DateTime)x._value;
- public static explicit operator string(B x) => (string)x._value;
- public static explicit operator Uri(B x) => (Uri)x._value;
- }
- }
- namespace ObjectEnum
- {
- public struct A
- {
- private object _value;
- public AType Type { get; }
- public A(object value, AType type)
- {
- _value = value;
- Type = type;
- }
- public static A New(int x) => new A(x, AType.Int32);
- public static A New(string x) => new A(x, AType.String);
- public static A New(bool x) => new A(x, AType.Bool);
- public static explicit operator int(A x) => (int)x._value;
- public static explicit operator string(A x) => (string)x._value;
- public static explicit operator bool(A x) => (bool)x._value;
- }
- public struct B
- {
- private object _value;
- public BType Type { get; }
- public B(object value, BType type) : this()
- {
- _value = value;
- Type = type;
- }
- public static B New(int x) => new B(x, BType.Int32);
- public static B New(long x) => new B(x, BType.Int64);
- public static B New(DateTime x) => new B(x, BType.DateTime);
- public static B New(string x) => new B(x, BType.String);
- public static B New(Uri x) => new B(x, BType.Uri);
- public static explicit operator int(B x) => (int)x._value;
- public static explicit operator long(B x) => (long)x._value;
- public static explicit operator DateTime(B x) => (DateTime)x._value;
- public static explicit operator string(B x) => (string)x._value;
- public static explicit operator Uri(B x) => (Uri)x._value;
- }
- }
- namespace UnionLayout
- {
- public struct A
- {
- [StructLayout(LayoutKind.Explicit)]
- struct Union
- {
- [FieldOffset(0)]
- public int Int32;
- [FieldOffset(0)]
- public bool Bool;
- }
- private object _obj;
- private Union _union;
- public AType Type { get; }
- private A(int x)
- {
- _obj = null;
- _union = default;
- _union.Int32 = x;
- Type = AType.Int32;
- }
- private A(string x)
- {
- _obj = x;
- _union = default;
- Type = AType.String;
- }
- private A(bool x)
- {
- _obj = null;
- _union = default;
- _union.Bool = x;
- Type = AType.Bool;
- }
- public static A New(int x) => new A(x);
- public static A New(string x) => new A(x);
- public static A New(bool x) => new A(x);
- public static explicit operator int(A x) => x._union.Int32;
- public static explicit operator string(A x) => (string)x._obj;
- public static explicit operator bool(A x) => x._union.Bool;
- }
- public struct B
- {
- [StructLayout(LayoutKind.Explicit)]
- struct Union
- {
- [FieldOffset(0)]
- public int Int32;
- [FieldOffset(0)]
- public long Int64;
- [FieldOffset(0)]
- public DateTime DateTime;
- }
- private object _obj;
- private Union _union;
- public BType Type { get; }
- private B(int x)
- {
- _obj = null;
- _union = default;
- _union.Int32 = x;
- Type = BType.Int32;
- }
- private B(long x)
- {
- _obj = null;
- _union = default;
- _union.Int64 = x;
- Type = BType.Int64;
- }
- private B(DateTime x)
- {
- _obj = null;
- _union = default;
- _union.DateTime = x;
- Type = BType.DateTime;
- }
- private B(string x)
- {
- _obj = x;
- _union = default;
- Type = BType.String;
- }
- private B(Uri x)
- {
- _obj = x;
- _union = default;
- Type = BType.Uri;
- }
- public static B New(int x) => new B(x);
- public static B New(long x) => new B(x);
- public static B New(DateTime x) => new B(x);
- public static B New(string x) => new B(x);
- public static B New(Uri x) => new B(x);
- public static explicit operator int(B x) => x._union.Int32;
- public static explicit operator long(B x) => x._union.Int64;
- public static explicit operator DateTime(B x) => x._union.DateTime;
- public static explicit operator string(B x) => (string)x._obj;
- public static explicit operator Uri(B x) => (Uri)x._obj;
- }
- }
- namespace Bench
- {
- #if true
- using UnionLayout;
- /*
- Method | Mean | Error | StdDev |
- ------- |---------:|----------:|----------:|
- ForA | 48.47 us | 0.1606 us | 0.1502 us |
- ForB | 90.49 us | 0.5514 us | 0.4888 us |
- */
- #elif true
- using ObjectEnum;
- /*
- Method | Mean | Error | StdDev |
- ------- |---------:|----------:|----------:|
- ForA | 34.73 us | 0.1568 us | 0.1467 us |
- ForB | 75.75 us | 0.6201 us | 0.5800 us |
- */
- #elif true
- using ObjectOnly;
- /*
- Method | Mean | Error | StdDev |
- ------- |---------:|----------:|----------:|
- ForA | 35.08 us | 0.7959 us | 0.8846 us |
- ForB | 81.83 us | 0.2413 us | 0.2015 us |
- */
- #elif true
- using SubClass;
- /*
- Method | Mean | Error | StdDev |
- ------- |---------:|----------:|----------:|
- ForA | 35.50 us | 0.1092 us | 0.0968 us |
- ForB | 80.06 us | 0.4380 us | 0.3658 us |
- */
- #endif
- public class Bench
- {
- private static readonly string[] Strings = new[]
- {
- "",
- "abc",
- "qawsertyuikolp",
- "あwせdrftgyふじこlp",
- "🐁🐂🐅🐇🐉🐍🐎🐑🐒🐓🐕🐗",
- "",
- "12345678901234567890",
- };
- private static A NewA(Random r)
- {
- var v = r.Next(0, 3);
- switch (v)
- {
- default:
- case 0: return A.New(r.Next());
- case 1: return A.New(Strings[r.Next(0, Strings.Length)]);
- case 2: return A.New(r.Next(0, 1) != 0);
- }
- }
- private static B NewB(Random r)
- {
- var v = r.Next(0, 5);
- switch (v)
- {
- default:
- case 0: return B.New(r.Next());
- case 1: return B.New((long)r.Next());
- case 2: return B.New(new DateTime((long)r.Next()));
- case 3: return B.New(Strings[r.Next(0, Strings.Length)]);
- case 4: return B.New(new Uri(Strings[r.Next(0, Strings.Length)], UriKind.Relative));
- }
- }
- [Benchmark]
- public void ForA()
- {
- var r = new Random(0);
- for (int i = 0; i < 1000; i++)
- {
- var a = NewA(r);
- var sum = 0;
- switch (a.Type)
- {
- case AType.Int32:
- sum += (int)a;
- break;
- case AType.String:
- sum += ((string)a).Length;
- break;
- case AType.Bool:
- sum += (bool)a ? 1 : -1;
- break;
- default:
- break;
- }
- }
- }
- [Benchmark]
- public void ForB()
- {
- var r = new Random(0);
- for (int i = 0; i < 1000; i++)
- {
- var a = NewB(r);
- var sum = 0L;
- switch (a.Type)
- {
- case BType.Int32:
- sum += (int)a;
- break;
- case BType.Int64:
- sum += (long)a;
- break;
- case BType.DateTime:
- sum += ((DateTime)a).Ticks;
- break;
- case BType.String:
- sum += ((string)a).Length;
- break;
- case BType.Uri:
- sum += ((Uri)a).OriginalString.Length;
- break;
- default:
- break;
- }
- }
- }
- }
- }
- namespace ConsoleApp
- {
- class Program
- {
- static void Main()
- {
- #if false
- var x = new Bench.Bench();
- x.ForA();
- x.ForB();
- #else
- BenchmarkRunner.Run<Bench.Bench>();
- #endif
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement