-
Notifications
You must be signed in to change notification settings - Fork 0
/
Program.cs
276 lines (237 loc) · 11.4 KB
/
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
namespace ConsoleApp7
{
class Program
{
static void Main(string[] args)
{
var summary = BenchmarkRunner.Run<ValueTuplePerformance>(
ManualConfig.Create(DefaultConfig.Instance));
}
}
public class ValueTuplePerformance
{
private IEqualityComparer<ValueTuple<int, float, bool, decimal>> comparer = EqualityComparer<ValueTuple<int, float, bool, decimal>>.Default;
private IEqualityComparer<ValueTupleCached<int, float, bool, decimal>> comparerCached = EqualityComparer<ValueTupleCached<int, float, bool, decimal>>.Default;
private ValueTuple<int, float, bool, decimal> a = ValueTuple.Create(10, 1, true, 0.1m);
private ValueTuple<int, float, bool, decimal> b = ValueTuple.Create(11, 2, false, 0.2m);
private ValueTupleCached<int, float, bool, decimal> a1 = new ValueTupleCached<int, float, bool, decimal>(10, 1, true, 0.1m);
private ValueTupleCached<int, float, bool, decimal> b1 = new ValueTupleCached<int, float, bool, decimal>(11, 2, false, 0.2m);
public ValueTuplePerformance()
{
}
[Benchmark]
public void Equals()
{
comparer.Equals(a, b);
}
[Benchmark]
public void GetHashCode()
{
comparer.GetHashCode(b);
}
[Benchmark]
public void EqualsCached()
{
comparerCached.Equals(a1, b1);
}
[Benchmark]
public void GetHashCodeCached()
{
comparerCached.GetHashCode(a1);
}
}
/// <summary>
/// Represents a 4-tuple, or quadruple, as a value type.
/// </summary>
/// <typeparam name="T1">The type of the tuple's first component.</typeparam>
/// <typeparam name="T2">The type of the tuple's second component.</typeparam>
/// <typeparam name="T3">The type of the tuple's third component.</typeparam>
/// <typeparam name="T4">The type of the tuple's fourth component.</typeparam>
[StructLayout(LayoutKind.Auto)]
public struct ValueTupleCached<T1, T2, T3, T4>
: IEquatable<ValueTupleCached<T1, T2, T3, T4>>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTupleCached<T1, T2, T3, T4>>
{
internal static readonly EqualityComparer<T1> T1Comparer = EqualityComparer<T1>.Default;
internal static readonly EqualityComparer<T2> T2Comparer = EqualityComparer<T2>.Default;
internal static readonly EqualityComparer<T3> T3Comparer = EqualityComparer<T3>.Default;
internal static readonly EqualityComparer<T4> T4Comparer = EqualityComparer<T4>.Default;
/// <summary>
/// The current <see cref="ValueTupleCached{T1, T2, T3, T4}"/> instance's first component.
/// </summary>
public T1 Item1;
/// <summary>
/// The current <see cref="ValueTupleCached{T1, T2, T3, T4}"/> instance's second component.
/// </summary>
public T2 Item2;
/// <summary>
/// The current <see cref="ValueTupleCached{T1, T2, T3, T4}"/> instance's third component.
/// </summary>
public T3 Item3;
/// <summary>
/// The current <see cref="ValueTupleCached{T1, T2, T3, T4}"/> instance's fourth component.
/// </summary>
public T4 Item4;
/// <summary>
/// Initializes a new instance of the <see cref="ValueTupleCached{T1, T2, T3, T4}"/> value type.
/// </summary>
/// <param name="item1">The value of the tuple's first component.</param>
/// <param name="item2">The value of the tuple's second component.</param>
/// <param name="item3">The value of the tuple's third component.</param>
/// <param name="item4">The value of the tuple's fourth component.</param>
public ValueTupleCached(T1 item1, T2 item2, T3 item3, T4 item4)
{
Item1 = item1;
Item2 = item2;
Item3 = item3;
Item4 = item4;
}
/// <summary>
/// Returns a value that indicates whether the current <see cref="ValueTupleCached{T1, T2, T3, T4}"/> instance is equal to a specified object.
/// </summary>
/// <param name="obj">The object to compare with this instance.</param>
/// <returns><see langword="true"/> if the current instance is equal to the specified object; otherwise, <see langword="false"/>.</returns>
/// <remarks>
/// The <paramref name="obj"/> parameter is considered to be equal to the current instance under the following conditions:
/// <list type="bullet">
/// <item><description>It is a <see cref="ValueTupleCached{T1, T2, T3, T4}"/> value type.</description></item>
/// <item><description>Its components are of the same types as those of the current instance.</description></item>
/// <item><description>Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component.</description></item>
/// </list>
/// </remarks>
public override bool Equals(object obj)
{
return obj is ValueTupleCached<T1, T2, T3, T4> && Equals((ValueTupleCached<T1, T2, T3, T4>)obj);
}
/// <summary>
/// Returns a value that indicates whether the current <see cref="ValueTupleCached{T1, T2, T3, T4}"/>
/// instance is equal to a specified <see cref="ValueTupleCached{T1, T2, T3, T4}"/>.
/// </summary>
/// <param name="other">The tuple to compare with this instance.</param>
/// <returns><see langword="true"/> if the current instance is equal to the specified tuple; otherwise, <see langword="false"/>.</returns>
/// <remarks>
/// The <paramref name="other"/> parameter is considered to be equal to the current instance if each of its fields
/// are equal to that of the current instance, using the default comparer for that field's type.
/// </remarks>
public bool Equals(ValueTupleCached<T1, T2, T3, T4> other)
{
return T1Comparer.Equals(Item1, other.Item1)
&& T2Comparer.Equals(Item2, other.Item2)
&& T3Comparer.Equals(Item3, other.Item3)
&& T4Comparer.Equals(Item4, other.Item4);
}
bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer)
{
if (other == null || !(other is ValueTupleCached<T1, T2, T3, T4>)) return false;
var objTuple = (ValueTupleCached<T1, T2, T3, T4>)other;
return comparer.Equals(Item1, objTuple.Item1)
&& comparer.Equals(Item2, objTuple.Item2)
&& comparer.Equals(Item3, objTuple.Item3)
&& comparer.Equals(Item4, objTuple.Item4);
}
int IComparable.CompareTo(object other)
{
if (other == null) return 1;
if (!(other is ValueTupleCached<T1, T2, T3, T4>))
{
throw new ArgumentException("", nameof(other));
}
return CompareTo((ValueTupleCached<T1, T2, T3, T4>)other);
}
/// <summary>Compares this instance to a specified instance and returns an indication of their relative values.</summary>
/// <param name="other">An instance to compare.</param>
/// <returns>
/// A signed number indicating the relative values of this instance and <paramref name="other"/>.
/// Returns less than zero if this instance is less than <paramref name="other"/>, zero if this
/// instance is equal to <paramref name="other"/>, and greater than zero if this instance is greater
/// than <paramref name="other"/>.
/// </returns>
public int CompareTo(ValueTupleCached<T1, T2, T3, T4> other)
{
int c = Comparer<T1>.Default.Compare(Item1, other.Item1);
if (c != 0) return c;
c = Comparer<T2>.Default.Compare(Item2, other.Item2);
if (c != 0) return c;
c = Comparer<T3>.Default.Compare(Item3, other.Item3);
if (c != 0) return c;
return Comparer<T4>.Default.Compare(Item4, other.Item4);
}
int IStructuralComparable.CompareTo(object other, IComparer comparer)
{
if (other == null) return 1;
if (!(other is ValueTupleCached<T1, T2, T3, T4>))
{
throw new ArgumentException("");
}
var objTuple = (ValueTupleCached<T1, T2, T3, T4>)other;
int c = comparer.Compare(Item1, objTuple.Item1);
if (c != 0) return c;
c = comparer.Compare(Item2, objTuple.Item2);
if (c != 0) return c;
c = comparer.Compare(Item3, objTuple.Item3);
if (c != 0) return c;
return comparer.Compare(Item4, objTuple.Item4);
}
/// <summary>
/// Returns the hash code for the current <see cref="ValueTupleCached{T1, T2, T3, T4}"/> instance.
/// </summary>
/// <returns>A 32-bit signed integer hash code.</returns>
public override int GetHashCode()
{
return CombineHashCodes(T1Comparer.GetHashCode(Item1), T2Comparer.GetHashCode(Item2), T3Comparer.GetHashCode(Item3), T4Comparer.GetHashCode(Item4));
}
int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
{
return GetHashCodeCore(comparer);
}
private int GetHashCodeCore(IEqualityComparer comparer)
{
return CombineHashCodes(comparer.GetHashCode(Item1),
comparer.GetHashCode(Item2),
comparer.GetHashCode(Item3),
comparer.GetHashCode(Item4));
}
/// <summary>
/// Returns a string that represents the value of this <see cref="ValueTupleCached{T1, T2, T3, T4}"/> instance.
/// </summary>
/// <returns>The string representation of this <see cref="ValueTupleCached{T1, T2, T3, T4}"/> instance.</returns>
/// <remarks>
/// The string returned by this method takes the form <c>(Item1, Item2, Item3, Item4)</c>.
/// If any field value is <see langword="null"/>, it is represented as <see cref="String.Empty"/>.
/// </remarks>
public override string ToString()
{
return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ")";
}
internal static int CombineHashCodes(int h1, int h2)
{
return HashHelpers.Combine(h1, h2);
}
internal static int CombineHashCodes(int h1, int h2, int h3)
{
return CombineHashCodes(CombineHashCodes(h1, h2), h3);
}
internal static int CombineHashCodes(int h1, int h2, int h3, int h4)
{
return CombineHashCodes(CombineHashCodes(h1, h2, h3), h4);
}
}
internal static class HashHelpers
{
public static int Combine(int h1, int h2)
{
uint num = (uint)(h1 << 5 | (int)((uint)h1 >> 27));
return (int)(num + (uint)h1 ^ (uint)h2);
}
}
}