-
-
Save DenL/1324b1706b714dc14f62 to your computer and use it in GitHub Desktop.
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
// ---------------------------------------------------------------------------- | |
// Tuple structs for use in .NET Not-Quite-3.5 (e.g. Unity3D). | |
// | |
// Used Chapter 3 in http://functional-programming.net/ as a starting point. | |
// | |
// Note: .NET 4.0 Tuples are immutable classes so they're *slightly* different. | |
// ---------------------------------------------------------------------------- | |
using UnityEngine; | |
using System; | |
namespace MochiLabs { | |
/// <summary> | |
/// Utility class that simplifies cration of tuples by using | |
/// method calls instead of constructor calls | |
/// </summary> | |
public static class Tuple { | |
/// <summary> | |
/// Creates a new tuple value with the specified elements. The method | |
/// can be used without specifying the generic parameters, because C# | |
/// compiler can usually infer the actual types. | |
/// </summary> | |
/// <param name="item1">First element of the tuple</param> | |
/// <param name="second">Second element of the tuple</param> | |
/// <returns>A newly created tuple</returns> | |
public static Tuple<T1, T2> Create<T1, T2>(T1 item1, T2 second) { | |
return new Tuple<T1, T2>(item1, second); | |
} | |
/// <summary> | |
/// Creates a new tuple value with the specified elements. The method | |
/// can be used without specifying the generic parameters, because C# | |
/// compiler can usually infer the actual types. | |
/// </summary> | |
/// <param name="item1">First element of the tuple</param> | |
/// <param name="second">Second element of the tuple</param> | |
/// <param name="third">Third element of the tuple</param> | |
/// <returns>A newly created tuple</returns> | |
public static Tuple<T1, T2, T3> Create<T1, T2, T3>(T1 item1, T2 second, T3 third) { | |
return new Tuple<T1, T2, T3>(item1, second, third); | |
} | |
/// <summary> | |
/// Creates a new tuple value with the specified elements. The method | |
/// can be used without specifying the generic parameters, because C# | |
/// compiler can usually infer the actual types. | |
/// </summary> | |
/// <param name="item1">First element of the tuple</param> | |
/// <param name="second">Second element of the tuple</param> | |
/// <param name="third">Third element of the tuple</param> | |
/// <param name="fourth">Fourth element of the tuple</param> | |
/// <returns>A newly created tuple</returns> | |
public static Tuple<T1, T2, T3, T4> Create<T1, T2, T3, T4>(T1 item1, T2 second, T3 third, T4 fourth) { | |
return new Tuple<T1, T2, T3, T4>(item1, second, third, fourth); | |
} | |
public static bool TryConvert<T>(object obj, out T converted) { | |
// quick check | |
if (obj is T) { | |
converted = (T)obj; | |
return true; | |
} | |
converted = default(T); | |
try { | |
if (typeof(T).IsEnum) { | |
if (obj is int) | |
converted = (T)obj; | |
else | |
converted = (T)Enum.Parse(typeof(T), obj.ToString()); | |
} | |
else | |
converted = (T)Convert.ChangeType(obj, typeof(T)); | |
} | |
catch (Exception e) { | |
return false; | |
} | |
return true; | |
} | |
} | |
/// <summary> | |
/// Represents a functional tuple that can be used to store | |
/// two values of different types inside one object. | |
/// </summary> | |
/// <typeparam name="T1">The type of the first element</typeparam> | |
/// <typeparam name="T2">The type of the second element</typeparam> | |
[Serializable] | |
public class Tuple<T1, T2> { | |
[SerializeField] | |
protected readonly T1 item1; | |
[SerializeField] | |
protected readonly T2 item2; | |
/// <summary> | |
/// Retyurns the first element of the tuple | |
/// </summary> | |
public T1 Item1 { | |
get { return item1; } | |
} | |
/// <summary> | |
/// Returns the second element of the tuple | |
/// </summary> | |
public T2 Item2 { | |
get { return item2; } | |
} | |
/// <summary> | |
/// Create a new tuple value | |
/// </summary> | |
/// <param name="item1">First element of the tuple</param> | |
/// <param name="second">Second element of the tuple</param> | |
public Tuple(T1 item1, T2 item2) { | |
this.item1 = item1; | |
this.item2 = item2; | |
} | |
public override string ToString() { | |
return string.Format("({0}, {1})", item1, item2); | |
} | |
public static Tuple<T1, T2> Parse(string s) { | |
Tuple<T1, T2> result; | |
if (!TryParse(s, out result)) | |
throw new ArgumentException("Cannot parse: " + s); | |
return result; | |
} | |
public static bool TryParse(string s, out Tuple<T1, T2> result) { | |
result = null; | |
if (s == null || s.Length <= 4) { | |
return false; | |
} | |
s = s.Remove(0,1); // remove "(" | |
s = s.Remove(s.Length-1); // remove ")" | |
string[] iStr = (new System.Text.RegularExpressions.Regex(", ")).Split(s); | |
if (iStr.Length != 2) { | |
return false; | |
} | |
T1 item1; | |
T2 item2; | |
if (!Tuple.TryConvert(iStr[0], out item1) || !Tuple.TryConvert(iStr[1], out item2)) { | |
return false; | |
} | |
result = Tuple.Create(item1, item2); | |
return true; | |
} | |
public override int GetHashCode() { | |
int hash = (item1 == null ? 0 : item1.GetHashCode()); | |
hash = (hash << 3) ^ (item2 == null ? 0 : item2.GetHashCode()); | |
return hash; | |
} | |
public override bool Equals(object o) { | |
if (!(o is Tuple<T1, T2>)) { | |
return false; | |
} | |
var other = (Tuple<T1, T2>)o; | |
return this == other; | |
} | |
public bool Equals(Tuple<T1, T2> other) { | |
return this == other; | |
} | |
public static bool operator==(Tuple<T1, T2> a, Tuple<T1, T2> b) { | |
if (object.ReferenceEquals(a, null)) { | |
return object.ReferenceEquals(b, null); | |
} | |
if (a.item1 == null && b.item1 != null) | |
return false; | |
if (a.item2 == null && b.item2 != null) | |
return false; | |
return a.item1.Equals(b.item1) && | |
a.item2.Equals(b.item2); | |
} | |
public static bool operator!=(Tuple<T1, T2> a, Tuple<T1, T2> b) { | |
return !(a == b); | |
} | |
} | |
/// <summary> | |
/// Represents a functional tuple that can be used to store | |
/// two values of different types inside one object. | |
/// </summary> | |
/// <typeparam name="T1">The type of the first element</typeparam> | |
/// <typeparam name="T2">The type of the second element</typeparam> | |
/// <typeparam name="T3">The type of the third element</typeparam> | |
[Serializable] | |
public class Tuple<T1, T2, T3> : Tuple<T1, T2> { | |
[SerializeField] | |
protected readonly T3 item3; | |
/// <summary> | |
/// Returns the third element of the tuple | |
/// </summary> | |
public T3 Item3 { | |
get { return item3; } | |
} | |
/// <summary> | |
/// Create a new tuple value | |
/// </summary> | |
/// <param name="item1">First element of the tuple</param> | |
/// <param name="second">Second element of the tuple</param> | |
/// <param name="third">Third element of the tuple</param> | |
public Tuple(T1 item1, T2 item2, T3 item3) : base(item1, item2) { | |
this.item3 = item3; | |
} | |
public override string ToString() { | |
return string.Format("({0}, {1}, {2})", item1, item2, item3); | |
} | |
public static Tuple<T1, T2, T3> Parse(string s) { | |
Tuple<T1, T2, T3> result; | |
if (!TryParse(s, out result)) | |
throw new ArgumentException("Cannot parse: " + s); | |
return result; | |
} | |
public static bool TryParse(string s, out Tuple<T1, T2, T3> result) { | |
result = null; | |
if (s == null || s.Length <= 6) { | |
return false; | |
} | |
s = s.Remove(0,1); // remove "(" | |
s = s.Remove(s.Length-1); // remove ")" | |
string[] iStr = (new System.Text.RegularExpressions.Regex(", ")).Split(s); | |
if (iStr.Length != 3) { | |
return false; | |
} | |
T1 item1; | |
T2 item2; | |
T3 item3; | |
if (!Tuple.TryConvert(iStr[0], out item1) || !Tuple.TryConvert(iStr[1], out item2) || | |
!Tuple.TryConvert(iStr[2], out item3)) { | |
return false; | |
} | |
result = Tuple.Create(item1, item2, item3); | |
return true; | |
} | |
public override int GetHashCode() { | |
int hash = base.GetHashCode(); | |
hash = (hash << 3) ^ (item3 == null ? 0 : item3.GetHashCode()); | |
return hash; | |
} | |
public override bool Equals(object o) { | |
if (!(o is Tuple<T1, T2, T3>)) { | |
return false; | |
} | |
var other = (Tuple<T1, T2, T3>)o; | |
return this == other; | |
} | |
public static bool operator==(Tuple<T1, T2, T3> a, Tuple<T1, T2, T3> b) { | |
if (object.ReferenceEquals(a, null)) { | |
return object.ReferenceEquals(b, null); | |
} | |
if (a.item1 == null && b.item1 != null) | |
return false; | |
if (a.item2 == null && b.item2 != null) | |
return false; | |
if (a.item3 == null && b.item3 != null) | |
return false; | |
return a.item1.Equals(b.item1) && | |
a.item2.Equals(b.item2) && | |
a.item3.Equals(b.item3); | |
} | |
public static bool operator!=(Tuple<T1, T2, T3> a, Tuple<T1, T2, T3> b) { | |
return !(a == b); | |
} | |
} | |
/// <summary> | |
/// Represents a functional tuple that can be used to store | |
/// two values of different types inside one object. | |
/// </summary> | |
/// <typeparam name="T1">The type of the first element</typeparam> | |
/// <typeparam name="T2">The type of the second element</typeparam> | |
/// <typeparam name="T3">The type of the third element</typeparam> | |
/// <typeparam name="T4">The type of the fourth element</typeparam> | |
[Serializable] | |
public class Tuple<T1, T2, T3, T4> : Tuple<T1, T2, T3> { | |
[SerializeField] | |
protected readonly T4 item4; | |
/// <summary> | |
/// Returns the fourth element of the tuple | |
/// </summary> | |
public T4 Item4 { | |
get { return item4; } | |
} | |
/// <summary> | |
/// Create a new tuple value | |
/// </summary> | |
/// <param name="item1">First element of the tuple</param> | |
/// <param name="second">Second element of the tuple</param> | |
/// <param name="third">Third element of the tuple</param> | |
/// <param name="fourth">Fourth element of the tuple</param> | |
public Tuple(T1 item1, T2 item2, T3 item3, T4 item4) : base(item1, item2, item3) { | |
this.item4 = item4; | |
} | |
public override string ToString() { | |
return string.Format("({0}, {1}, {2}, {3})", item1, item2, item3, item4); | |
} | |
public static Tuple<T1, T2, T3, T4> Parse(string s) { | |
Tuple<T1, T2, T3, T4> result; | |
if (!TryParse(s, out result)) | |
throw new ArgumentException("Cannot parse: " + s); | |
return result; | |
} | |
public static bool TryParse(string s, out Tuple<T1, T2, T3, T4> result) { | |
result = null; | |
if (s == null || s.Length <= 8) { | |
return false; | |
} | |
s = s.Remove(0,1); // remove "(" | |
s = s.Remove(s.Length-1); // remove ")" | |
string[] iStr = (new System.Text.RegularExpressions.Regex(", ")).Split(s); | |
if (iStr.Length != 4) { | |
return false; | |
} | |
T1 item1; | |
T2 item2; | |
T3 item3; | |
T4 item4; | |
if (!Tuple.TryConvert(iStr[0], out item1) || !Tuple.TryConvert(iStr[1], out item2) || | |
!Tuple.TryConvert(iStr[2], out item3) || !Tuple.TryConvert(iStr[3], out item4)) { | |
return false; | |
} | |
result = Tuple.Create(item1, item2, item3, item4); | |
return true; | |
} | |
public override int GetHashCode() { | |
int hash = base.GetHashCode(); | |
hash = (hash << 3) ^ (item4 == null ? 0 : item4.GetHashCode()); | |
return hash; | |
} | |
public override bool Equals(object o) { | |
if (o.GetType() != typeof(Tuple<T1, T2, T3, T4>)) { | |
return false; | |
} | |
var other = (Tuple<T1, T2, T3, T4>)o; | |
return this == other; | |
} | |
public static bool operator==(Tuple<T1, T2, T3, T4> a, Tuple<T1, T2, T3, T4> b) { | |
if (object.ReferenceEquals(a, null)) { | |
return object.ReferenceEquals(b, null); | |
} | |
if (a.item1 == null && b.item1 != null) | |
return false; | |
if (a.item2 == null && b.item2 != null) | |
return false; | |
if (a.item3 == null && b.item3 != null) | |
return false; | |
if (a.item4 == null && b.item4 != null) | |
return false; | |
return a.item1.Equals(b.item1) && | |
a.item2.Equals(b.item2) && | |
a.item3.Equals(b.item3) && | |
a.item4.Equals(b.item4); | |
} | |
public static bool operator!=(Tuple<T1, T2, T3, T4> a, Tuple<T1, T2, T3, T4> b) { | |
return !(a == b); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment