//******************************
// Written by Peter Golde
// Copyright (c) 2004-2005, Wintellect
//
// Use and restribution of this code is subject to the license agreement
// contained in the file "License.txt" accompanying this file.
//******************************
using System;
using System.Collections.Generic;
namespace Wintellect.PowerCollections
{
///
/// Stores a triple of objects within a single struct. This struct is useful to use as the
/// T of a collection, or as the TKey or TValue of a dictionary.
///
[Serializable]
public struct Triple : IComparable, IComparable>
{
///
/// Comparers for the first and second type that are used to compare
/// values.
///
private static IComparer firstComparer = Comparer.Default;
private static IComparer secondComparer = Comparer.Default;
private static IComparer thirdComparer = Comparer.Default;
private static IEqualityComparer firstEqualityComparer = EqualityComparer.Default;
private static IEqualityComparer secondEqualityComparer = EqualityComparer.Default;
private static IEqualityComparer thirdEqualityComparer = EqualityComparer.Default;
///
/// The first element of the triple.
///
public TFirst First;
///
/// The second element of the triple.
///
public TSecond Second;
///
/// The thrid element of the triple.
///
public TThird Third;
///
/// Creates a new triple with given elements.
///
/// The first element of the triple.
/// The second element of the triple.
/// The third element of the triple.
public Triple(TFirst first, TSecond second, TThird third)
{
this.First = first;
this.Second = second;
this.Third = third;
}
///
/// Determines if this triple is equal to another object. The triple is equal to another object
/// if that object is a Triple, all element types are the same, and the all three elements
/// compare equal using object.Equals.
///
/// Object to compare for equality.
/// True if the objects are equal. False if the objects are not equal.
public override bool Equals(object obj)
{
if (obj != null && obj is Triple) {
Triple other = (Triple)obj;
return Equals(other);
}
else {
return false;
}
}
///
/// Determines if this triple is equal to another triple. Two triples are equal if the all three elements
/// compare equal using IComparable<T>.Equals or object.Equals.
///
/// Triple to compare with for equality.
/// True if the triples are equal. False if the triples are not equal.
public bool Equals(Triple other)
{
return firstEqualityComparer.Equals(First, other.First) &&
secondEqualityComparer.Equals(Second, other.Second) &&
thirdEqualityComparer.Equals(Third, other.Third);
}
///
/// Returns a hash code for the triple, suitable for use in a hash-table or other hashed collection.
/// Two triples that compare equal (using Equals) will have the same hash code. The hash code for
/// the triple is derived by combining the hash codes for each of the two elements of the triple.
///
/// The hash code.
public override int GetHashCode()
{
// Build the hash code from the hash codes of First and Second.
int hashFirst = (First == null) ? 0x61E04917 : First.GetHashCode();
int hashSecond = (Second == null) ? 0x198ED6A3 : Second.GetHashCode();
int hashThird = (Third == null) ? 0x40FC1877 : Third.GetHashCode();
return hashFirst ^ hashSecond ^ hashThird;
}
///
/// Compares this triple to another triple of the some type. The triples are compared by using
/// the IComparable<T> or IComparable interface on TFirst, TSecond, and TThird. The triples
/// are compared by their first elements first, if their first elements are equal, then they
/// are compared by their second elements. If their second elements are also equal, then they
/// are compared by their third elements.
/// If TFirst, TSecond, or TThird does not implement IComparable<T> or IComparable, then
/// an NotSupportedException is thrown, because the triples cannot be compared.
///
/// The triple to compare to.
/// An integer indicating how this triple compares to . Less
/// than zero indicates this triple is less than . Zero indicate this triple is
/// equals to . Greater than zero indicates this triple is greater than
/// .
/// Either FirstSecond, TSecond, or TThird is not comparable
/// via the IComparable<T> or IComparable interfaces.
public int CompareTo(Triple other)
{
try {
int firstCompare = firstComparer.Compare(First, other.First);
if (firstCompare != 0)
return firstCompare;
int secondCompare = secondComparer.Compare(Second, other.Second);
if (secondCompare != 0)
return secondCompare;
else
return thirdComparer.Compare(Third, other.Third);
}
catch (ArgumentException) {
// Determine which type caused the problem for a better error message.
if (!typeof(IComparable).IsAssignableFrom(typeof(TFirst)) &&
!typeof(System.IComparable).IsAssignableFrom(typeof(TFirst))) {
throw new NotSupportedException(string.Format(Strings.UncomparableType, typeof(TFirst).FullName));
}
else if (!typeof(IComparable).IsAssignableFrom(typeof(TSecond)) &&
!typeof(System.IComparable).IsAssignableFrom(typeof(TSecond))) {
throw new NotSupportedException(string.Format(Strings.UncomparableType, typeof(TSecond).FullName));
}
else if (!typeof(IComparable).IsAssignableFrom(typeof(TThird)) &&
!typeof(System.IComparable).IsAssignableFrom(typeof(TThird))) {
throw new NotSupportedException(string.Format(Strings.UncomparableType, typeof(TThird).FullName));
}
else
throw; // Hmmm. Unclear why we got the ArgumentException.
}
}
///
/// Compares this triple to another triple of the some type. The triples are compared by using
/// the IComparable<T> or IComparable interface on TFirst, TSecond, and TThird. The triples
/// are compared by their first elements first, if their first elements are equal, then they
/// are compared by their second elements. If their second elements are also equal, then they
/// are compared by their third elements.
/// If TFirst, TSecond, or TThird does not implement IComparable<T> or IComparable, then
/// an NotSupportedException is thrown, because the triples cannot be compared.
///
/// The triple to compare to.
/// An integer indicating how this triple compares to . Less
/// than zero indicates this triple is less than . Zero indicate this triple is
/// equals to . Greater than zero indicates this triple is greater than
/// .
/// is not of the correct type.
/// Either FirstSecond, TSecond, or TThird is not comparable
/// via the IComparable<T> or IComparable interfaces.
int IComparable.CompareTo(object obj)
{
if (obj is Triple)
return CompareTo((Triple)obj);
else
throw new ArgumentException(Strings.BadComparandType, "obj");
}
///
/// Returns a string representation of the triple. The string representation of the triple is
/// of the form:
/// First: {0}, Second: {1}, Third: {2}
/// where {0} is the result of First.ToString(), {1} is the result of Second.ToString(), and
/// {2} is the result of Third.ToString() (or "null" if they are null.)
///
/// The string representation of the triple.
public override string ToString()
{
return string.Format("First: {0}, Second: {1}, Third: {2}",
(First == null) ? "null" : First.ToString(),
(Second == null) ? "null" : Second.ToString(),
(Third == null) ? "null" : Third.ToString());
}
///
/// Determines if two triples are equal. Two triples are equal if the all three elements
/// compare equal using IComparable<T>.Equals or object.Equals.
///
/// First triple to compare.
/// Second triple to compare.
/// True if the triples are equal. False if the triples are not equal.
public static bool operator ==(Triple pair1, Triple pair2)
{
return pair1.Equals(pair2);
}
///
/// Determines if two triples are not equal. Two triples are equal if the all three elements
/// compare equal using IComparable<T>.Equals or object.Equals.
///
/// First triple to compare.
/// Second triple to compare.
/// True if the triples are not equal. False if the triples are equal.
public static bool operator !=(Triple pair1, Triple pair2)
{
return ! pair1.Equals(pair2);
}
}
}