316 lines
No EOL
8.1 KiB
C#
316 lines
No EOL
8.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace JD.Kernel.Structs
|
|
{
|
|
/// <summary>
|
|
/// Encapsulate a flag enum and contains helper functions to manipulate it.
|
|
/// </summary>
|
|
public struct Flags<T> : IEquatable<T>
|
|
where T : IComparable, IFormattable
|
|
{
|
|
#region Variables
|
|
|
|
private T m_value;
|
|
|
|
#endregion
|
|
|
|
#region Constructor
|
|
|
|
static Flags()
|
|
{
|
|
Type type = typeof (T);
|
|
|
|
if (!type.IsEnum)
|
|
{
|
|
throw new InvalidCastException($"The flags type cannot be used with the non enum type {typeof(T).Name}");
|
|
}
|
|
|
|
if (!type.IsDefined(typeof(FlagsAttribute), true))
|
|
{
|
|
throw new InvalidCastException($"The enum type {typeof(T).Name} should be decorated with the flags attribute. Consider using a BitArray");
|
|
}
|
|
|
|
if (Enum.GetUnderlyingType(type) != typeof(int))
|
|
{
|
|
throw new NotSupportedException("Flags class only support int enums.");
|
|
}
|
|
}
|
|
|
|
public Flags(T value)
|
|
{
|
|
m_value = value;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
/// <summary>
|
|
/// Returns the actual wrapped value.
|
|
/// </summary>
|
|
public T Value
|
|
{
|
|
get { return m_value; }
|
|
}
|
|
|
|
private int IntValue
|
|
{
|
|
get { return ToInt(m_value); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets/Sets the value of the given flagKey.
|
|
/// </summary>
|
|
/// <param name="flagKey">Flag to access.</param>
|
|
/// <returns>The value of the flag.</returns>
|
|
public bool this[T flagKey]
|
|
{
|
|
get { return Contains(flagKey); }
|
|
set
|
|
{
|
|
if (value)
|
|
{
|
|
Add(flagKey);
|
|
}
|
|
else
|
|
{
|
|
Remove(flagKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Functions
|
|
|
|
private static int ToInt(T value)
|
|
{
|
|
return (int)(object)value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes the given flag from the enum value.
|
|
/// </summary>
|
|
/// <param name="flag"></param>
|
|
/// <returns>True if the flag has been removed.</returns>
|
|
public bool Remove(T flag)
|
|
{
|
|
int value = IntValue;
|
|
int flagToExtract = ToInt(flag);
|
|
int newValue = value & ~flagToExtract;
|
|
|
|
m_value = (T)(object)newValue;
|
|
|
|
return value != newValue;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds the given flag to the internal value.
|
|
/// </summary>
|
|
/// <param name="flag"></param>
|
|
/// <returns>True if the flag has been added. (false if it was already present)</returns>
|
|
public bool Add(T flag)
|
|
{
|
|
int value = IntValue;
|
|
int flagToAdd = ToInt(flag);
|
|
int newValue = value | flagToAdd;
|
|
|
|
m_value = (T)(object)newValue;
|
|
|
|
return value != newValue;
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if the flag contains that given value.
|
|
/// </summary>
|
|
/// <param name="value">Value to test for</param>
|
|
/// <returns>True if the flag contains that given value.</returns>
|
|
public bool Contains(T value)
|
|
{
|
|
int flag = ToInt(value);
|
|
return (IntValue & flag) == flag;
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if the flag contains EVERY values.
|
|
/// </summary>
|
|
/// <param name="value">First value to test for</param>
|
|
/// <param name="otherValues">Additional values to test for.</param>
|
|
/// <returns>True if the flag contains EVERY values.</returns>
|
|
public bool Contains(T value, params T[] otherValues)
|
|
{
|
|
if (!Contains(value))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
foreach (T t in otherValues)
|
|
{
|
|
if (!Contains(t))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if any of the given values are contained in the flag.
|
|
/// </summary>
|
|
/// <param name="value">First value to test for</param>
|
|
/// <param name="otherValues">Additional values to test for.</param>
|
|
/// <returns>True if any of the given values are contained in the flag.</returns>
|
|
public bool ContainsAny(T value, params T[] otherValues)
|
|
{
|
|
if (Contains(value))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
foreach (T other in otherValues)
|
|
{
|
|
if (Contains(other))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if the flag has any overlap with the given <paramref name="value"/>.
|
|
/// </summary>
|
|
/// <param name="value">Value to test for.</param>
|
|
/// <returns>True if the flag has any overlap with the given <paramref name="value"/>.</returns>
|
|
public bool Intersects(T value)
|
|
{
|
|
int flag = ToInt(value);
|
|
return (IntValue & flag) != 0;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Comparison
|
|
|
|
/// <summary>
|
|
/// True if the enum equals our value.
|
|
/// </summary>
|
|
/// <param name="other"></param>
|
|
/// <returns></returns>
|
|
public bool Equals(T other)
|
|
{
|
|
return Equals(m_value, other);
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if the enum equals our value.
|
|
/// </summary>
|
|
public override bool Equals(object obj)
|
|
{
|
|
if (obj is Flags<T>)
|
|
{
|
|
return Equals(((Flags<T>)obj).m_value, m_value);
|
|
}
|
|
|
|
return Equals(m_value, obj);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hashcode.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override int GetHashCode()
|
|
{
|
|
return m_value.GetHashCode();
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if the flag value is any of the given values.
|
|
/// </summary>
|
|
/// <param name="first"></param>
|
|
/// <param name="other"></param>
|
|
/// <returns>True if the flag value is any of the given values.</returns>
|
|
public bool EqualsAny(T first, params T[] other)
|
|
{
|
|
if (Equals(first))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return other.Any(Equals);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Operators
|
|
|
|
/// <summary>
|
|
/// == Operator.
|
|
/// </summary>
|
|
public static bool operator ==(Flags<T> a, Flags<T> b)
|
|
{
|
|
return Equals((T)a, (T)b);
|
|
}
|
|
|
|
/// <summary>
|
|
/// != Operator.
|
|
/// </summary>
|
|
public static bool operator !=(Flags<T> a, Flags<T> b)
|
|
{
|
|
return !Equals((T)a, (T)b);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Implicit cast Operator.
|
|
/// </summary>
|
|
public static implicit operator T(Flags<T> value)
|
|
{
|
|
return value.m_value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Implicit cast Operator.
|
|
/// </summary>
|
|
public static implicit operator Flags<T>(T value)
|
|
{
|
|
return new Flags<T>(value);
|
|
}
|
|
|
|
public static Flags<T> operator |(Flags<T> a, Flags<T> b)
|
|
{
|
|
a.Add(b);
|
|
return a;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ToString
|
|
|
|
/// <summary>
|
|
/// Returns the display of the inner Value.
|
|
/// </summary>
|
|
|
|
public override string ToString()
|
|
{
|
|
return $"Flags '{m_value}'";
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Utilities
|
|
|
|
/// <summary>
|
|
/// All the defined flags defined in the enum.
|
|
/// </summary>
|
|
public static IEnumerable<T> Values
|
|
{
|
|
get { return Enum.GetValues(typeof (T)).Cast<T>(); }
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
} |