|
@@ -1,83 +1,62 @@
|
|
using System.Reflection;
|
|
using System.Reflection;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Generic;
|
|
-using System.Runtime.CompilerServices;
|
|
|
|
using System.Diagnostics;
|
|
using System.Diagnostics;
|
|
|
|
|
|
namespace System
|
|
namespace System
|
|
{
|
|
{
|
|
- public struct Nullable<T> where T : struct
|
|
|
|
|
|
+ struct Nullable<T> where T : struct
|
|
{
|
|
{
|
|
- #region Sync with runtime code
|
|
|
|
- internal T mValue;
|
|
|
|
|
|
+ internal T mValue;
|
|
internal bool mHasValue;
|
|
internal bool mHasValue;
|
|
- #endregion
|
|
|
|
-
|
|
|
|
- public this(T value)
|
|
|
|
|
|
+
|
|
|
|
+ public this(T value)
|
|
{
|
|
{
|
|
mHasValue = true;
|
|
mHasValue = true;
|
|
mValue = value;
|
|
mValue = value;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+ [Inline]
|
|
public bool HasValue
|
|
public bool HasValue
|
|
{
|
|
{
|
|
get { return mHasValue; }
|
|
get { return mHasValue; }
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+ [Inline]
|
|
public T Value
|
|
public T Value
|
|
{
|
|
{
|
|
get
|
|
get
|
|
{
|
|
{
|
|
- Debug.Assert(mHasValue, "Value cannot be retrieved on a null nullable.");
|
|
|
|
|
|
+ if (!mHasValue)
|
|
|
|
+ {
|
|
|
|
+ Debug.FatalError("Nullable object must have a value.");
|
|
|
|
+ }
|
|
|
|
+
|
|
return mValue;
|
|
return mValue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- public ref T ValueRef
|
|
|
|
- {
|
|
|
|
- get mut
|
|
|
|
- {
|
|
|
|
- Debug.Assert(mHasValue, "Value cannot be retrieved on a null nullable.");
|
|
|
|
- return ref mValue;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /*public override bool Equals(object other)
|
|
|
|
|
|
+ [Inline]
|
|
|
|
+ public ref T ValueRef
|
|
{
|
|
{
|
|
- if (other == null)
|
|
|
|
- return mHasValue == false;
|
|
|
|
- if (!(other is Nullable<T>))
|
|
|
|
- return false;
|
|
|
|
-
|
|
|
|
- return Equals((Nullable<T>)other);
|
|
|
|
|
|
+ get mut
|
|
|
|
+ {
|
|
|
|
+ if (!mHasValue)
|
|
|
|
+ {
|
|
|
|
+ Debug.FatalError("Nullable object must have a value.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return ref mValue;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- bool Equals(Nullable<T> other)
|
|
|
|
- {
|
|
|
|
- if (other.mHasValue != mHasValue)
|
|
|
|
- return false;
|
|
|
|
-
|
|
|
|
- if (mHasValue == false)
|
|
|
|
- return true;
|
|
|
|
-
|
|
|
|
- return other.mValue.Equals(mValue);
|
|
|
|
- }*/
|
|
|
|
-
|
|
|
|
- /*public override int GetHashCode()
|
|
|
|
- {
|
|
|
|
- if (!mHasValue)
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
- return mValue.GetHashCode();
|
|
|
|
- }*/
|
|
|
|
-
|
|
|
|
public T GetValueOrDefault()
|
|
public T GetValueOrDefault()
|
|
{
|
|
{
|
|
return mValue;
|
|
return mValue;
|
|
}
|
|
}
|
|
|
|
|
|
- public T GetValueOrDefault(T defaultValue)
|
|
|
|
|
|
+ public T GetValueOrDefault(T defaultmValue)
|
|
{
|
|
{
|
|
- return mHasValue ? mValue : defaultValue;
|
|
|
|
|
|
+ return mHasValue ? mValue : defaultmValue;
|
|
}
|
|
}
|
|
|
|
|
|
public override void ToString(String str)
|
|
public override void ToString(String str)
|
|
@@ -87,16 +66,369 @@ namespace System
|
|
else
|
|
else
|
|
str.Clear();
|
|
str.Clear();
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+ [Inline]
|
|
public static implicit operator Nullable<T>(T value)
|
|
public static implicit operator Nullable<T>(T value)
|
|
{
|
|
{
|
|
return Nullable<T>(value);
|
|
return Nullable<T>(value);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+ [Inline]
|
|
public static explicit operator T(Nullable<T> value)
|
|
public static explicit operator T(Nullable<T> value)
|
|
{
|
|
{
|
|
- Debug.Assert(value.mHasValue, "Value cannot be retrieved on a null nullable.");
|
|
|
|
return value.mValue;
|
|
return value.mValue;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ [Inline]
|
|
|
|
+ public static bool operator==(Nullable<T> lhs, T rhs)
|
|
|
|
+ {
|
|
|
|
+ if (!lhs.mHasValue) return false;
|
|
|
|
+ return lhs.mValue == rhs;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ///
|
|
|
|
+
|
|
|
|
+ public static bool operator==<TOther>(Nullable<T> lhs, TOther rhs) where bool : operator T == TOther
|
|
|
|
+ {
|
|
|
|
+ if (!lhs.mHasValue) return false;
|
|
|
|
+ return lhs.mValue == rhs;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static bool operator==<TOther>(TOther lhs, Nullable<T> rhs) where bool : operator TOther == T
|
|
|
|
+ {
|
|
|
|
+ if (!rhs.mHasValue) return false;
|
|
|
|
+ return lhs == rhs;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static bool operator==<TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where bool : operator T == TOther where TOther : struct
|
|
|
|
+ {
|
|
|
|
+ if ((!lhs.mHasValue) || (!rhs.mHasValue)) return false;
|
|
|
|
+ return lhs.mValue == rhs.mValue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ///
|
|
|
|
+
|
|
|
|
+ public static bool operator!=<TOther>(Nullable<T> lhs, TOther rhs) where bool : operator T != TOther
|
|
|
|
+ {
|
|
|
|
+ if (!lhs.mHasValue) return false;
|
|
|
|
+ return lhs.mValue != rhs;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static bool operator!=<TOther>(TOther lhs, Nullable<T> rhs) where bool : operator TOther != T
|
|
|
|
+ {
|
|
|
|
+ if (!rhs.mHasValue) return false;
|
|
|
|
+ return lhs != rhs;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static bool operator!=<TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where bool : operator T != TOther where TOther : struct
|
|
|
|
+ {
|
|
|
|
+ if ((!lhs.mHasValue) || (!rhs.mHasValue)) return false;
|
|
|
|
+ return lhs.mValue != rhs.mValue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ///
|
|
|
|
+
|
|
|
|
+ public static bool operator< <TOther>(Nullable<T> lhs, TOther rhs) where bool : operator T < TOther
|
|
|
|
+ {
|
|
|
|
+ if (!lhs.mHasValue) return false;
|
|
|
|
+ return lhs.mValue < rhs;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static bool operator< <TOther>(TOther lhs, Nullable<T> rhs) where bool : operator TOther < T
|
|
|
|
+ {
|
|
|
|
+ if (!rhs.mHasValue) return false;
|
|
|
|
+ return lhs < rhs;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static bool operator< <TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where bool : operator T < TOther where TOther : struct
|
|
|
|
+ {
|
|
|
|
+ if ((!lhs.mHasValue) || (!rhs.mHasValue)) return false;
|
|
|
|
+ return lhs.mValue < rhs.mValue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ///
|
|
|
|
+
|
|
|
|
+ public static bool operator<=<TOther>(Nullable<T> lhs, TOther rhs) where bool : operator T <= TOther
|
|
|
|
+ {
|
|
|
|
+ if (!lhs.mHasValue) return false;
|
|
|
|
+ return lhs.mValue <= rhs;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static bool operator<=<TOther>(TOther lhs, Nullable<T> rhs) where bool : operator TOther <= T
|
|
|
|
+ {
|
|
|
|
+ if (!rhs.mHasValue) return false;
|
|
|
|
+ return lhs <= rhs;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static bool operator<=<TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where bool : operator T <= TOther where TOther : struct
|
|
|
|
+ {
|
|
|
|
+ if ((!lhs.mHasValue) || (!rhs.mHasValue)) return false;
|
|
|
|
+ return lhs.mValue <= rhs.mValue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ///
|
|
|
|
+
|
|
|
|
+ public static bool operator><TOther>(Nullable<T> lhs, TOther rhs) where bool : operator T > TOther
|
|
|
|
+ {
|
|
|
|
+ if (!lhs.mHasValue) return false;
|
|
|
|
+ return lhs.mValue > rhs;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static bool operator><TOther>(TOther lhs, Nullable<T> rhs) where bool : operator TOther > T
|
|
|
|
+ {
|
|
|
|
+ if (!rhs.mHasValue) return false;
|
|
|
|
+ return lhs > rhs;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static bool operator><TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where bool : operator T > TOther where TOther : struct
|
|
|
|
+ {
|
|
|
|
+ if ((!lhs.mHasValue) || (!rhs.mHasValue)) return false;
|
|
|
|
+ return lhs.mValue > rhs.mValue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ///
|
|
|
|
+
|
|
|
|
+ public static bool operator>=<TOther>(Nullable<T> lhs, TOther rhs) where bool : operator T >= TOther
|
|
|
|
+ {
|
|
|
|
+ if (!lhs.mHasValue) return false;
|
|
|
|
+ return lhs.mValue >= rhs;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static bool operator>=<TOther>(TOther lhs, Nullable<T> rhs) where bool : operator TOther >= T
|
|
|
|
+ {
|
|
|
|
+ if (!rhs.mHasValue) return false;
|
|
|
|
+ return lhs >= rhs;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static bool operator>=<TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where bool : operator T >= TOther where TOther : struct
|
|
|
|
+ {
|
|
|
|
+ if ((!lhs.mHasValue) || (!rhs.mHasValue)) return false;
|
|
|
|
+ return lhs.mValue >= rhs.mValue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ///
|
|
|
|
+
|
|
|
|
+ public static int operator<=><TOther>(Nullable<T> lhs, TOther rhs) where int : operator T <=> TOther
|
|
|
|
+ {
|
|
|
|
+ return lhs.mValue <=> rhs;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static int operator<=><TOther>(TOther lhs, Nullable<T> rhs) where int : operator TOther <=> T
|
|
|
|
+ {
|
|
|
|
+ return lhs <=> rhs;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static int operator<=><TOther>(Nullable<T> lhs, Nullable<TOther> rhs) where int : operator T <=> TOther where TOther : struct
|
|
|
|
+ {
|
|
|
|
+ return lhs.mValue <=> rhs.mValue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ///
|
|
|
|
+
|
|
|
|
+ public static TResult? operator+<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T + TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!lhs.mHasValue) return null;
|
|
|
|
+ return .(lhs.mValue + rhs);
|
|
|
|
+ }
|
|
|
|
+ public static TResult? operator+<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther + T where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!rhs.mHasValue) return null;
|
|
|
|
+ return .(lhs + rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+ public static TResult? operator+<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T + TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
|
|
|
+ return .(lhs.mValue + rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ///
|
|
|
|
+
|
|
|
|
+ public static TResult? operator-<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther - T where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!rhs.mHasValue) return null;
|
|
|
|
+ return .(lhs - rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static TResult? operator-<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T - TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!lhs.mHasValue) return null;
|
|
|
|
+ return .(lhs.mValue - rhs);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static TResult? operator-<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T - TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
|
|
|
+ return .(lhs.mValue - rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //
|
|
|
|
+
|
|
|
|
+ public static TResult? operator*<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther * T where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!rhs.mHasValue) return null;
|
|
|
|
+ return .(lhs * rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static TResult? operator*<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T * TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!lhs.mHasValue) return null;
|
|
|
|
+ return .(lhs.mValue * rhs);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static TResult? operator*<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T * TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
|
|
|
+ return .(lhs.mValue * rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //
|
|
|
|
+
|
|
|
|
+ public static TResult? operator/<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther / T where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!rhs.mHasValue) return null;
|
|
|
|
+ return .(lhs / rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static TResult? operator/<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T / TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!lhs.mHasValue) return null;
|
|
|
|
+ return .(lhs.mValue / rhs);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static TResult? operator/<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T / TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
|
|
|
+ return .(lhs.mValue / rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //
|
|
|
|
+
|
|
|
|
+ public static TResult? operator%<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther % T where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!rhs.mHasValue) return null;
|
|
|
|
+ return .(lhs % rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static TResult? operator%<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T % TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!lhs.mHasValue) return null;
|
|
|
|
+ return .(lhs.mValue % rhs);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static TResult? operator%<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T % TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
|
|
|
+ return .(lhs.mValue % rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //
|
|
|
|
+
|
|
|
|
+ public static TResult? operator^<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther ^ T where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!rhs.mHasValue) return null;
|
|
|
|
+ return .(lhs ^ rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static TResult? operator^<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T ^ TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!lhs.mHasValue) return null;
|
|
|
|
+ return .(lhs.mValue ^ rhs);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static TResult? operator^<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T ^ TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
|
|
|
+ return .(lhs.mValue ^ rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //
|
|
|
|
+
|
|
|
|
+ public static TResult? operator&<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther & T where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!rhs.mHasValue) return null;
|
|
|
|
+ return .(lhs & rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static TResult? operator&<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T & TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!lhs.mHasValue) return null;
|
|
|
|
+ return .(lhs.mValue & rhs);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static TResult? operator&<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T & TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
|
|
|
+ return .(lhs.mValue & rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //
|
|
|
|
+
|
|
|
|
+ public static TResult? operator|<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther | T where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!rhs.mHasValue) return null;
|
|
|
|
+ return .(lhs | rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static TResult? operator|<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T | TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!lhs.mHasValue) return null;
|
|
|
|
+ return .(lhs.mValue | rhs);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static TResult? operator|<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T | TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
|
|
|
+ return .(lhs.mValue | rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //
|
|
|
|
+
|
|
|
|
+ public static TResult? operator??<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther ?? T where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!rhs.mHasValue) return null;
|
|
|
|
+ return .(lhs ?? rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static TResult? operator??<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T ?? TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!lhs.mHasValue) return null;
|
|
|
|
+ return .(lhs.mValue ?? rhs);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static TResult? operator??<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T ?? TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
|
|
|
+ return .(lhs.mValue ?? rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //
|
|
|
|
+
|
|
|
|
+ public static TResult? operator<< <TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult = operator TOther << T where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!rhs.mHasValue) return null;
|
|
|
|
+ return .(lhs << rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static TResult? operator<< <TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult = operator T << TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if (!lhs.mHasValue) return null;
|
|
|
|
+ return .(lhs.mValue << rhs);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static TResult? operator<< <TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult = operator T << TOther where TResult : struct
|
|
|
|
+ {
|
|
|
|
+ if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
|
|
|
+ return .(lhs.mValue << rhs.mValue);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ extension Nullable<T> : IHashable where T : IHashable
|
|
|
|
+ {
|
|
|
|
+ public int GetHashCode()
|
|
|
|
+ {
|
|
|
|
+ if (!mHasValue)
|
|
|
|
+ return 0;
|
|
|
|
+ return mValue.GetHashCode();
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|