Skip to content

Instantly share code, notes, and snippets.

@DenL
Forked from michaelbartnett/LICENSE.txt
Last active August 29, 2015 14:19
Show Gist options
  • Save DenL/1324b1706b714dc14f62 to your computer and use it in GitHub Desktop.
Save DenL/1324b1706b714dc14f62 to your computer and use it in GitHub Desktop.
// ----------------------------------------------------------------------------
// 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