From 34114f7aa7097a4e2da2b36d7e93a9b3a0576aec Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Thu, 14 Jul 2016 14:13:49 -0700 Subject: [PATCH 1/4] Adding ITuple implementation --- .../src/System/ValueTuple/ValueTuple.cs | 307 ++++++++++++++++-- .../tests/ValueTuple/UnitTests.cs | 84 +++++ 2 files changed, 362 insertions(+), 29 deletions(-) diff --git a/src/System.ValueTuple/src/System/ValueTuple/ValueTuple.cs b/src/System.ValueTuple/src/System/ValueTuple/ValueTuple.cs index e8fd6dd28cbe..c265f623d58a 100644 --- a/src/System.ValueTuple/src/System/ValueTuple/ValueTuple.cs +++ b/src/System.ValueTuple/src/System/ValueTuple/ValueTuple.cs @@ -8,13 +8,28 @@ namespace System { + /// + /// This interface is required for types that want to be indexed into by dynamic patterns. + /// + public interface ITuple + { + /// + /// The number of positions in this data structure. + /// + int Size { get; } + + /// + /// Get the element at position . + /// + object this[int index] { get; } + } + /// /// Helper so we can call some tuple methods recursively without knowing the underlying types. /// - internal interface ITupleInternal + internal interface ITupleInternal : ITuple { int GetHashCode(IEqualityComparer comparer); - int Size { get; } string ToStringEnd(); } @@ -27,7 +42,7 @@ internal interface ITupleInternal /// - their members (such as Item1, Item2, etc) are fields rather than properties. /// public struct ValueTuple - : IEquatable, IStructuralEquatable, IStructuralComparable, IComparable, IComparable, ITupleInternal + : IEquatable, IStructuralEquatable, IStructuralComparable, IComparable, IComparable, ITupleInternal, ITuple { /// /// Returns a value that indicates whether the current instance is equal to a specified object. @@ -69,7 +84,7 @@ int IComparable.CompareTo(object other) /// /// A signed number indicating the relative values of this instance and . /// Returns less than zero if this instance is less than , zero if this - /// instance is equal to , and greater than zero if this instance is greater + /// instance is equal to , and greater than zero if this instance is greater /// than . /// public int CompareTo(ValueTuple other) @@ -123,7 +138,21 @@ string ITupleInternal.ToStringEnd() return ")"; } - int ITupleInternal.Size => 0; + /// + /// The number of positions in this data structure. + /// + public int Size => 0; + + /// + /// Get the element at position . + /// + public object this[int index] + { + get + { + throw new IndexOutOfRangeException(); + } + } /// Creates a new struct 0-tuple. /// A 0-tuple. @@ -282,7 +311,7 @@ internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int /// Represents a 1-tuple, or singleton, as a value type. /// The type of the tuple's only component. public struct ValueTuple - : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal + : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal, ITuple { /// /// The current instance's first component. @@ -359,7 +388,7 @@ int IComparable.CompareTo(object other) /// /// A signed number indicating the relative values of this instance and . /// Returns less than zero if this instance is less than , zero if this - /// instance is equal to , and greater than zero if this instance is greater + /// instance is equal to , and greater than zero if this instance is greater /// than . /// public int CompareTo(ValueTuple other) @@ -419,7 +448,25 @@ string ITupleInternal.ToStringEnd() return Item1?.ToString() + ")"; } - int ITupleInternal.Size => 1; + /// + /// The number of positions in this data structure. + /// + public int Size => 1; + + /// + /// Get the element at position . + /// + public object this[int index] + { + get + { + if (index != 0) + { + throw new IndexOutOfRangeException(); + } + return Item1; + } + } } /// @@ -428,7 +475,7 @@ string ITupleInternal.ToStringEnd() /// The type of the tuple's first component. /// The type of the tuple's second component. public struct ValueTuple - : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal + : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal, ITuple { /// /// The current instance's first component. @@ -530,7 +577,7 @@ int IComparable.CompareTo(object other) /// /// A signed number indicating the relative values of this instance and . /// Returns less than zero if this instance is less than , zero if this - /// instance is equal to , and greater than zero if this instance is greater + /// instance is equal to , and greater than zero if this instance is greater /// than . /// public int CompareTo(ValueTuple other) @@ -604,7 +651,29 @@ string ITupleInternal.ToStringEnd() return Item1?.ToString() + ", " + Item2?.ToString() + ")"; } - int ITupleInternal.Size => 2; + /// + /// The number of positions in this data structure. + /// + public int Size => 2; + + /// + /// Get the element at position . + /// + public object this[int index] + { + get + { + switch (index) + { + case 0: + return Item1; + case 1: + return Item2; + default: + throw new IndexOutOfRangeException(); + } + } + } } /// @@ -614,7 +683,7 @@ string ITupleInternal.ToStringEnd() /// The type of the tuple's second component. /// The type of the tuple's third component. public struct ValueTuple - : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal + : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal, ITuple { /// /// The current instance's first component. @@ -705,7 +774,7 @@ int IComparable.CompareTo(object other) /// /// A signed number indicating the relative values of this instance and . /// Returns less than zero if this instance is less than , zero if this - /// instance is equal to , and greater than zero if this instance is greater + /// instance is equal to , and greater than zero if this instance is greater /// than . /// public int CompareTo(ValueTuple other) @@ -785,7 +854,31 @@ string ITupleInternal.ToStringEnd() return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ")"; } - int ITupleInternal.Size => 3; + /// + /// The number of positions in this data structure. + /// + public int Size => 3; + + /// + /// Get the element at position . + /// + public object this[int index] + { + get + { + switch (index) + { + case 0: + return Item1; + case 1: + return Item2; + case 2: + return Item3; + default: + throw new IndexOutOfRangeException(); + } + } + } } /// @@ -796,7 +889,7 @@ string ITupleInternal.ToStringEnd() /// The type of the tuple's third component. /// The type of the tuple's fourth component. public struct ValueTuple - : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal + : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal, ITuple { /// /// The current instance's first component. @@ -895,7 +988,7 @@ int IComparable.CompareTo(object other) /// /// A signed number indicating the relative values of this instance and . /// Returns less than zero if this instance is less than , zero if this - /// instance is equal to , and greater than zero if this instance is greater + /// instance is equal to , and greater than zero if this instance is greater /// than . /// public int CompareTo(ValueTuple other) @@ -983,7 +1076,33 @@ string ITupleInternal.ToStringEnd() return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ")"; } - int ITupleInternal.Size => 4; + /// + /// The number of positions in this data structure. + /// + public int Size => 4; + + /// + /// Get the element at position . + /// + public object this[int index] + { + get + { + switch (index) + { + case 0: + return Item1; + case 1: + return Item2; + case 2: + return Item3; + case 3: + return Item4; + default: + throw new IndexOutOfRangeException(); + } + } + } } /// @@ -995,7 +1114,7 @@ string ITupleInternal.ToStringEnd() /// The type of the tuple's fourth component. /// The type of the tuple's fifth component. public struct ValueTuple - : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal + : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal, ITuple { /// /// The current instance's first component. @@ -1102,7 +1221,7 @@ int IComparable.CompareTo(object other) /// /// A signed number indicating the relative values of this instance and . /// Returns less than zero if this instance is less than , zero if this - /// instance is equal to , and greater than zero if this instance is greater + /// instance is equal to , and greater than zero if this instance is greater /// than . /// public int CompareTo(ValueTuple other) @@ -1198,7 +1317,35 @@ string ITupleInternal.ToStringEnd() return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ")"; } - int ITupleInternal.Size => 5; + /// + /// The number of positions in this data structure. + /// + public int Size => 5; + + /// + /// Get the element at position . + /// + public object this[int index] + { + get + { + switch (index) + { + case 0: + return Item1; + case 1: + return Item2; + case 2: + return Item3; + case 3: + return Item4; + case 4: + return Item5; + default: + throw new IndexOutOfRangeException(); + } + } + } } /// @@ -1211,7 +1358,7 @@ string ITupleInternal.ToStringEnd() /// The type of the tuple's fifth component. /// The type of the tuple's sixth component. public struct ValueTuple - : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal + : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal, ITuple { /// /// The current instance's first component. @@ -1326,7 +1473,7 @@ int IComparable.CompareTo(object other) /// /// A signed number indicating the relative values of this instance and . /// Returns less than zero if this instance is less than , zero if this - /// instance is equal to , and greater than zero if this instance is greater + /// instance is equal to , and greater than zero if this instance is greater /// than . /// public int CompareTo(ValueTuple other) @@ -1430,7 +1577,37 @@ string ITupleInternal.ToStringEnd() return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ")"; } - int ITupleInternal.Size => 6; + /// + /// The number of positions in this data structure. + /// + public int Size => 6; + + /// + /// Get the element at position . + /// + public object this[int index] + { + get + { + switch (index) + { + case 0: + return Item1; + case 1: + return Item2; + case 2: + return Item3; + case 3: + return Item4; + case 4: + return Item5; + case 5: + return Item6; + default: + throw new IndexOutOfRangeException(); + } + } + } } /// @@ -1444,7 +1621,7 @@ string ITupleInternal.ToStringEnd() /// The type of the tuple's sixth component. /// The type of the tuple's seventh component. public struct ValueTuple - : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal + : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal, ITuple { /// /// The current instance's first component. @@ -1567,7 +1744,7 @@ int IComparable.CompareTo(object other) /// /// A signed number indicating the relative values of this instance and . /// Returns less than zero if this instance is less than , zero if this - /// instance is equal to , and greater than zero if this instance is greater + /// instance is equal to , and greater than zero if this instance is greater /// than . /// public int CompareTo(ValueTuple other) @@ -1679,7 +1856,39 @@ string ITupleInternal.ToStringEnd() return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ")"; } - int ITupleInternal.Size => 7; + /// + /// + /// + public int Size => 7; + + /// + /// + /// + public object this[int index] + { + get + { + switch (index) + { + case 0: + return Item1; + case 1: + return Item2; + case 2: + return Item3; + case 3: + return Item4; + case 4: + return Item5; + case 5: + return Item6; + case 6: + return Item7; + default: + throw new IndexOutOfRangeException(); + } + } + } } /// @@ -1694,7 +1903,7 @@ string ITupleInternal.ToStringEnd() /// The type of the tuple's seventh component. /// The type of the tuple's eigth component. public struct ValueTuple - : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal + : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal, ITuple where TRest : struct { /// @@ -1831,7 +2040,7 @@ int IComparable.CompareTo(object other) /// /// A signed number indicating the relative values of this instance and . /// Returns less than zero if this instance is less than , zero if this - /// instance is equal to , and greater than zero if this instance is greater + /// instance is equal to , and greater than zero if this instance is greater /// than . /// public int CompareTo(ValueTuple other) @@ -2060,7 +2269,10 @@ string ITupleInternal.ToStringEnd() } } - int ITupleInternal.Size + /// + /// The number of positions in this data structure. + /// + public int Size { get { @@ -2068,5 +2280,42 @@ int ITupleInternal.Size return rest == null ? 8 : 7 + rest.Size; } } + + /// + /// Get the element at position . + /// + public object this[int index] + { + get + { + switch (index) + { + case 0: + return Item1; + case 1: + return Item2; + case 2: + return Item3; + case 3: + return Item4; + case 4: + return Item5; + case 5: + return Item6; + case 6: + return Item7; + } + + ITupleInternal rest = Rest as ITupleInternal; + if (index > 0 && index < Size && rest != null) + { + return rest[index - 7]; + } + else + { + throw new IndexOutOfRangeException(); + } + } + } } } \ No newline at end of file diff --git a/src/System.ValueTuple/tests/ValueTuple/UnitTests.cs b/src/System.ValueTuple/tests/ValueTuple/UnitTests.cs index 3ebe247158a7..a2bbafd8251e 100644 --- a/src/System.ValueTuple/tests/ValueTuple/UnitTests.cs +++ b/src/System.ValueTuple/tests/ValueTuple/UnitTests.cs @@ -724,6 +724,11 @@ public static void ZeroTuples() Assert.Throws(() => ((IStructuralComparable)a).CompareTo("string", DummyTestComparer.Instance)); Assert.Equal("(1, 2, 3, 4, 5, 6, 7, )", CreateLong(1, 2, 3, 4, 5, 6, 7, new ValueTuple()).ToString()); + + ITuple it = ValueTuple.Create(); + Assert.Throws(() => it[-1]); + Assert.Throws(() => it[0]); + Assert.Throws(() => it[1]); } [Fact] @@ -748,6 +753,11 @@ public static void OneTuples() var tupleWithNull = new Tuple(null); Assert.Equal("()", vtWithNull.ToString()); Assert.Equal(tupleWithNull.ToString(), vtWithNull.ToString()); + + ITuple it = ValueTuple.Create(1); + Assert.Throws(() => it[-1]); + Assert.Equal(1, it[0]); + Assert.Throws(() => it[1]); } [Fact] @@ -773,6 +783,12 @@ public static void TwoTuples() var tupleWithNull = new Tuple(null, null); Assert.Equal("(, )", vtWithNull.ToString()); Assert.Equal(tupleWithNull.ToString(), vtWithNull.ToString()); + + ITuple it = ValueTuple.Create(1, 2); + Assert.Throws(() => it[-1]); + Assert.Equal(1, it[0]); + Assert.Equal(2, it[1]); + Assert.Throws(() => it[2]); } [Fact] @@ -800,6 +816,13 @@ public static void ThreeTuples() var tupleWithNull = new Tuple(null, null, null); Assert.Equal("(, , )", vtWithNull.ToString()); Assert.Equal(tupleWithNull.ToString(), vtWithNull.ToString()); + + ITuple it = ValueTuple.Create(1, 2, 3); + Assert.Throws(() => it[-1]); + Assert.Equal(1, it[0]); + Assert.Equal(2, it[1]); + Assert.Equal(3, it[2]); + Assert.Throws(() => it[3]); } [Fact] @@ -830,6 +853,14 @@ public static void FourTuples() var tupleWithNull = new Tuple(null, null, null, null); Assert.Equal("(, , , )", vtWithNull.ToString()); Assert.Equal(tupleWithNull.ToString(), vtWithNull.ToString()); + + ITuple it = ValueTuple.Create(1, 2, 3, 4); + Assert.Throws(() => it[-1]); + Assert.Equal(1, it[0]); + Assert.Equal(2, it[1]); + Assert.Equal(3, it[2]); + Assert.Equal(4, it[3]); + Assert.Throws(() => it[4]); } [Fact] @@ -862,6 +893,15 @@ public static void FiveTuples() var tupleWithNull = new Tuple(null, null, null, null, null); Assert.Equal("(, , , , )", vtWithNull.ToString()); Assert.Equal(tupleWithNull.ToString(), vtWithNull.ToString()); + + ITuple it = ValueTuple.Create(1, 2, 3, 4, 5); + Assert.Throws(() => it[-1]); + Assert.Equal(1, it[0]); + Assert.Equal(2, it[1]); + Assert.Equal(3, it[2]); + Assert.Equal(4, it[3]); + Assert.Equal(5, it[4]); + Assert.Throws(() => it[5]); } [Fact] @@ -896,6 +936,16 @@ public static void SixTuples() var tupleWithNull = new Tuple(null, null, null, null, null, null); Assert.Equal("(, , , , , )", vtWithNull.ToString()); Assert.Equal(tupleWithNull.ToString(), vtWithNull.ToString()); + + ITuple it = ValueTuple.Create(1, 2, 3, 4, 5, 6); + Assert.Throws(() => it[-1]); + Assert.Equal(1, it[0]); + Assert.Equal(2, it[1]); + Assert.Equal(3, it[2]); + Assert.Equal(4, it[3]); + Assert.Equal(5, it[4]); + Assert.Equal(6, it[5]); + Assert.Throws(() => it[6]); } [Fact] @@ -932,6 +982,17 @@ public static void SevenTuples() var tupleWithNull = new Tuple(null, null, null, null, null, null, null); Assert.Equal("(, , , , , , )", vtWithNull.ToString()); Assert.Equal(tupleWithNull.ToString(), vtWithNull.ToString()); + + ITuple it = ValueTuple.Create(1, 2, 3, 4, 5, 6, 7); + Assert.Throws(() => it[-1]); + Assert.Equal(1, it[0]); + Assert.Equal(2, it[1]); + Assert.Equal(3, it[2]); + Assert.Equal(4, it[3]); + Assert.Equal(5, it[4]); + Assert.Equal(6, it[5]); + Assert.Equal(7, it[6]); + Assert.Throws(() => it[7]); } public static ValueTuple CreateLong(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) where TRest : struct => @@ -1009,6 +1070,18 @@ public static void EightTuples() var tupleWithNull = new Tuple>(null, null, null, null, null, null, null, new Tuple(null)); Assert.Equal("(, , , , , , , )", vtWithNull.ToString()); Assert.Equal(tupleWithNull.ToString(), vtWithNull.ToString()); + + ITuple it = CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8)); + Assert.Throws(() => it[-1]); + Assert.Equal(1, it[0]); + Assert.Equal(2, it[1]); + Assert.Equal(3, it[2]); + Assert.Equal(4, it[3]); + Assert.Equal(5, it[4]); + Assert.Equal(6, it[5]); + Assert.Equal(7, it[6]); + Assert.Equal(8, it[7]); + Assert.Throws(() => it[8]); } [Fact] @@ -1088,6 +1161,17 @@ public static void EightTuplesWithBadRest() Assert.Equal(((IStructuralEquatable)ValueTuple.Create(1, 0, 0, 0, 0, 0, 0)).GetHashCode(TestEqualityComparer.Instance), ((IStructuralEquatable)d).GetHashCode(TestEqualityComparer.Instance)); Assert.Equal("(1, 2, 3, 4, 5, 6, 7, 1, 0, 0, 0, 0, 0, 0, 42)", CreateLong(1, 2, 3, 4, 5, 6, 7, d).ToString()); + + ITuple it = d; + Assert.Throws(() => it[-1]); + Assert.Equal(1, it[0]); + Assert.Equal(0, it[1]); + Assert.Equal(0, it[2]); + Assert.Equal(0, it[3]); + Assert.Equal(0, it[4]); + Assert.Equal(0, it[5]); + Assert.Equal(0, it[6]); + Assert.Throws(() => it[7]); } private class TestClass : IComparable From 176a739d7170369d089535df032a87374265b376 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Thu, 14 Jul 2016 14:26:31 -0700 Subject: [PATCH 2/4] Renaming from Size to Length --- .../src/System/ValueTuple/ValueTuple.cs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/System.ValueTuple/src/System/ValueTuple/ValueTuple.cs b/src/System.ValueTuple/src/System/ValueTuple/ValueTuple.cs index c265f623d58a..2558d1b32f86 100644 --- a/src/System.ValueTuple/src/System/ValueTuple/ValueTuple.cs +++ b/src/System.ValueTuple/src/System/ValueTuple/ValueTuple.cs @@ -16,7 +16,7 @@ public interface ITuple /// /// The number of positions in this data structure. /// - int Size { get; } + int Length { get; } /// /// Get the element at position . @@ -141,7 +141,7 @@ string ITupleInternal.ToStringEnd() /// /// The number of positions in this data structure. /// - public int Size => 0; + public int Length => 0; /// /// Get the element at position . @@ -451,7 +451,7 @@ string ITupleInternal.ToStringEnd() /// /// The number of positions in this data structure. /// - public int Size => 1; + public int Length => 1; /// /// Get the element at position . @@ -654,7 +654,7 @@ string ITupleInternal.ToStringEnd() /// /// The number of positions in this data structure. /// - public int Size => 2; + public int Length => 2; /// /// Get the element at position . @@ -857,7 +857,7 @@ string ITupleInternal.ToStringEnd() /// /// The number of positions in this data structure. /// - public int Size => 3; + public int Length => 3; /// /// Get the element at position . @@ -1079,7 +1079,7 @@ string ITupleInternal.ToStringEnd() /// /// The number of positions in this data structure. /// - public int Size => 4; + public int Length => 4; /// /// Get the element at position . @@ -1320,7 +1320,7 @@ string ITupleInternal.ToStringEnd() /// /// The number of positions in this data structure. /// - public int Size => 5; + public int Length => 5; /// /// Get the element at position . @@ -1580,7 +1580,7 @@ string ITupleInternal.ToStringEnd() /// /// The number of positions in this data structure. /// - public int Size => 6; + public int Length => 6; /// /// Get the element at position . @@ -1857,12 +1857,12 @@ string ITupleInternal.ToStringEnd() } /// - /// + /// The number of positions in this data structure. /// - public int Size => 7; + public int Length => 7; /// - /// + /// Get the element at position . /// public object this[int index] { @@ -2123,7 +2123,7 @@ public override int GetHashCode() EqualityComparer.Default.GetHashCode(Item7)); } - int size = rest.Size; + int size = rest.Length; if (size >= 8) { return rest.GetHashCode(); } // In this case, the rest member has less than 8 elements so we need to combine some our elements with the elements in rest @@ -2195,7 +2195,7 @@ private int GetHashCodeCore(IEqualityComparer comparer) comparer.GetHashCode(Item7)); } - int size = rest.Size; + int size = rest.Length; if (size >= 8) { return rest.GetHashCode(comparer); } // In this case, the rest member has less than 8 elements so we need to combine some our elements with the elements in rest @@ -2272,12 +2272,12 @@ string ITupleInternal.ToStringEnd() /// /// The number of positions in this data structure. /// - public int Size + public int Length { get { ITupleInternal rest = Rest as ITupleInternal; - return rest == null ? 8 : 7 + rest.Size; + return rest == null ? 8 : 7 + rest.Length; } } @@ -2307,7 +2307,7 @@ public object this[int index] } ITupleInternal rest = Rest as ITupleInternal; - if (index > 0 && index < Size && rest != null) + if (index > 0 && index < Length && rest != null) { return rest[index - 7]; } From 7589bb6910f191d37935e60d2ebe58f94fbaa2f5 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Thu, 14 Jul 2016 15:07:06 -0700 Subject: [PATCH 3/4] Using ITuple as constraint on TRest --- .../src/System/ValueTuple/TupleExtensions.cs | 2 +- .../src/System/ValueTuple/ValueTuple.cs | 51 ++++++++----------- .../tests/ValueTuple/UnitTests.cs | 41 ++++++++++++--- 3 files changed, 57 insertions(+), 37 deletions(-) diff --git a/src/System.ValueTuple/src/System/ValueTuple/TupleExtensions.cs b/src/System.ValueTuple/src/System/ValueTuple/TupleExtensions.cs index 096df957124a..9cd91201fc2d 100644 --- a/src/System.ValueTuple/src/System/ValueTuple/TupleExtensions.cs +++ b/src/System.ValueTuple/src/System/ValueTuple/TupleExtensions.cs @@ -920,7 +920,7 @@ public static Tuple CreateLong(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) where TRest : struct => + private static ValueTuple CreateLong(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) where TRest : struct, ITuple => new ValueTuple(item1, item2, item3, item4, item5, item6, item7, rest); private static Tuple CreateLongRef(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) => diff --git a/src/System.ValueTuple/src/System/ValueTuple/ValueTuple.cs b/src/System.ValueTuple/src/System/ValueTuple/ValueTuple.cs index 2558d1b32f86..7fd60e42321c 100644 --- a/src/System.ValueTuple/src/System/ValueTuple/ValueTuple.cs +++ b/src/System.ValueTuple/src/System/ValueTuple/ValueTuple.cs @@ -141,12 +141,12 @@ string ITupleInternal.ToStringEnd() /// /// The number of positions in this data structure. /// - public int Length => 0; + int ITuple.Length => 0; /// /// Get the element at position . /// - public object this[int index] + object ITuple.this[int index] { get { @@ -451,12 +451,12 @@ string ITupleInternal.ToStringEnd() /// /// The number of positions in this data structure. /// - public int Length => 1; + int ITuple.Length => 1; /// /// Get the element at position . /// - public object this[int index] + object ITuple.this[int index] { get { @@ -654,12 +654,12 @@ string ITupleInternal.ToStringEnd() /// /// The number of positions in this data structure. /// - public int Length => 2; + int ITuple.Length => 2; /// /// Get the element at position . /// - public object this[int index] + object ITuple.this[int index] { get { @@ -857,12 +857,12 @@ string ITupleInternal.ToStringEnd() /// /// The number of positions in this data structure. /// - public int Length => 3; + int ITuple.Length => 3; /// /// Get the element at position . /// - public object this[int index] + object ITuple.this[int index] { get { @@ -1079,12 +1079,12 @@ string ITupleInternal.ToStringEnd() /// /// The number of positions in this data structure. /// - public int Length => 4; + int ITuple.Length => 4; /// /// Get the element at position . /// - public object this[int index] + object ITuple.this[int index] { get { @@ -1320,12 +1320,12 @@ string ITupleInternal.ToStringEnd() /// /// The number of positions in this data structure. /// - public int Length => 5; + int ITuple.Length => 5; /// /// Get the element at position . /// - public object this[int index] + object ITuple.this[int index] { get { @@ -1580,12 +1580,12 @@ string ITupleInternal.ToStringEnd() /// /// The number of positions in this data structure. /// - public int Length => 6; + int ITuple.Length => 6; /// /// Get the element at position . /// - public object this[int index] + object ITuple.this[int index] { get { @@ -1859,12 +1859,12 @@ string ITupleInternal.ToStringEnd() /// /// The number of positions in this data structure. /// - public int Length => 7; + int ITuple.Length => 7; /// /// Get the element at position . /// - public object this[int index] + object ITuple.this[int index] { get { @@ -1904,7 +1904,7 @@ public object this[int index] /// The type of the tuple's eigth component. public struct ValueTuple : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal, ITuple - where TRest : struct + where TRest : struct, ITuple { /// /// The current instance's first component. @@ -2272,19 +2272,18 @@ string ITupleInternal.ToStringEnd() /// /// The number of positions in this data structure. /// - public int Length + int ITuple.Length { get { - ITupleInternal rest = Rest as ITupleInternal; - return rest == null ? 8 : 7 + rest.Length; + return 7 + ((ITuple)Rest).Length; } } /// /// Get the element at position . /// - public object this[int index] + object ITuple.this[int index] { get { @@ -2306,15 +2305,7 @@ public object this[int index] return Item7; } - ITupleInternal rest = Rest as ITupleInternal; - if (index > 0 && index < Length && rest != null) - { - return rest[index - 7]; - } - else - { - throw new IndexOutOfRangeException(); - } + return ((ITuple)Rest)[index - 7]; } } } diff --git a/src/System.ValueTuple/tests/ValueTuple/UnitTests.cs b/src/System.ValueTuple/tests/ValueTuple/UnitTests.cs index a2bbafd8251e..3d4bfc708616 100644 --- a/src/System.ValueTuple/tests/ValueTuple/UnitTests.cs +++ b/src/System.ValueTuple/tests/ValueTuple/UnitTests.cs @@ -995,7 +995,7 @@ public static void SevenTuples() Assert.Throws(() => it[7]); } - public static ValueTuple CreateLong(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) where TRest : struct => + public static ValueTuple CreateLong(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) where TRest : struct, ITuple => new ValueTuple(item1, item2, item3, item4, item5, item6, item7, rest); public static Tuple CreateLongRef(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) => @@ -1147,12 +1147,11 @@ public static void LongTuplesWithNull() [Fact] public static void EightTuplesWithBadRest() { - var d = default(ValueTuple); + var d = default(ValueTuple); d.Item1 = 1; - d.Rest = 42; Assert.Equal(35937, d.GetHashCode()); Assert.Equal(35937, ((IStructuralEquatable)d).GetHashCode()); - Assert.Equal("(1, 0, 0, 0, 0, 0, 0, 42)", d.ToString()); + Assert.Equal("(1, 0, 0, 0, 0, 0, 0, BadTuple)", d.ToString()); Assert.Equal(35937, CreateLong(1, 2, 3, 4, 5, 6, 7, d).GetHashCode()); @@ -1160,7 +1159,9 @@ public static void EightTuplesWithBadRest() Assert.Equal(ValueTuple.Create(1, 0, 0, 0, 0, 0, 0).GetHashCode(), d.GetHashCode()); Assert.Equal(((IStructuralEquatable)ValueTuple.Create(1, 0, 0, 0, 0, 0, 0)).GetHashCode(TestEqualityComparer.Instance), ((IStructuralEquatable)d).GetHashCode(TestEqualityComparer.Instance)); - Assert.Equal("(1, 2, 3, 4, 5, 6, 7, 1, 0, 0, 0, 0, 0, 0, 42)", CreateLong(1, 2, 3, 4, 5, 6, 7, d).ToString()); + Assert.Equal("(1, 2, 3, 4, 5, 6, 7, 1, 0, 0, 0, 0, 0, 0, BadTuple)", CreateLong(1, 2, 3, 4, 5, 6, 7, d).ToString()); + + Assert.Throws(() => CreateLong(1, 2, 3, 4, 5, 6, 7, new BadTuple())); ITuple it = d; Assert.Throws(() => it[-1]); @@ -1171,7 +1172,35 @@ public static void EightTuplesWithBadRest() Assert.Equal(0, it[4]); Assert.Equal(0, it[5]); Assert.Equal(0, it[6]); - Assert.Throws(() => it[7]); + Assert.Equal(42, it[7]); + Assert.Throws(() => it[8]); + } + + private struct BadTuple : ITuple + { + // doesn't implement ITupleInternal + + int ITuple.Length => 1; + + object ITuple.this[int index] + { + get + { + if (index == 0) + { + return 42; + } + else + { + throw new IndexOutOfRangeException(); + } + } + } + + public override string ToString() + { + return "BadTuple"; + } } private class TestClass : IComparable From c02d8372e2b68dd7359db76401ebe3de2d8dcbc0 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Fri, 15 Jul 2016 13:21:16 -0700 Subject: [PATCH 4/4] Removing boxing cast to ITuple --- src/System.ValueTuple/src/System/ValueTuple/ValueTuple.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/System.ValueTuple/src/System/ValueTuple/ValueTuple.cs b/src/System.ValueTuple/src/System/ValueTuple/ValueTuple.cs index 7fd60e42321c..4f68b9a17e16 100644 --- a/src/System.ValueTuple/src/System/ValueTuple/ValueTuple.cs +++ b/src/System.ValueTuple/src/System/ValueTuple/ValueTuple.cs @@ -2276,7 +2276,7 @@ int ITuple.Length { get { - return 7 + ((ITuple)Rest).Length; + return 7 + Rest.Length; } } @@ -2305,7 +2305,7 @@ object ITuple.this[int index] return Item7; } - return ((ITuple)Rest)[index - 7]; + return Rest[index - 7]; } } }