using System; using System.Collections.Generic; using System.Linq; namespace JD.Kernel.Structs { /// /// Encapsulate a flag enum and contains helper functions to manipulate it. /// public struct Flags : IEquatable 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 /// /// Returns the actual wrapped value. /// public T Value { get { return m_value; } } private int IntValue { get { return ToInt(m_value); } } /// /// Gets/Sets the value of the given flagKey. /// /// Flag to access. /// The value of the flag. 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; } /// /// Removes the given flag from the enum value. /// /// /// True if the flag has been removed. public bool Remove(T flag) { int value = IntValue; int flagToExtract = ToInt(flag); int newValue = value & ~flagToExtract; m_value = (T)(object)newValue; return value != newValue; } /// /// Adds the given flag to the internal value. /// /// /// True if the flag has been added. (false if it was already present) public bool Add(T flag) { int value = IntValue; int flagToAdd = ToInt(flag); int newValue = value | flagToAdd; m_value = (T)(object)newValue; return value != newValue; } /// /// True if the flag contains that given value. /// /// Value to test for /// True if the flag contains that given value. public bool Contains(T value) { int flag = ToInt(value); return (IntValue & flag) == flag; } /// /// True if the flag contains EVERY values. /// /// First value to test for /// Additional values to test for. /// True if the flag contains EVERY values. 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; } /// /// True if any of the given values are contained in the flag. /// /// First value to test for /// Additional values to test for. /// True if any of the given values are contained in the flag. 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; } /// /// True if the flag has any overlap with the given . /// /// Value to test for. /// True if the flag has any overlap with the given . public bool Intersects(T value) { int flag = ToInt(value); return (IntValue & flag) != 0; } #endregion #region Comparison /// /// True if the enum equals our value. /// /// /// public bool Equals(T other) { return Equals(m_value, other); } /// /// True if the enum equals our value. /// public override bool Equals(object obj) { if (obj is Flags) { return Equals(((Flags)obj).m_value, m_value); } return Equals(m_value, obj); } /// /// Hashcode. /// /// public override int GetHashCode() { return m_value.GetHashCode(); } /// /// True if the flag value is any of the given values. /// /// /// /// True if the flag value is any of the given values. public bool EqualsAny(T first, params T[] other) { if (Equals(first)) { return true; } return other.Any(Equals); } #endregion #region Operators /// /// == Operator. /// public static bool operator ==(Flags a, Flags b) { return Equals((T)a, (T)b); } /// /// != Operator. /// public static bool operator !=(Flags a, Flags b) { return !Equals((T)a, (T)b); } /// /// Implicit cast Operator. /// public static implicit operator T(Flags value) { return value.m_value; } /// /// Implicit cast Operator. /// public static implicit operator Flags(T value) { return new Flags(value); } public static Flags operator |(Flags a, Flags b) { a.Add(b); return a; } #endregion #region ToString /// /// Returns the display of the inner Value. /// public override string ToString() { return $"Flags '{m_value}'"; } #endregion #region Utilities /// /// All the defined flags defined in the enum. /// public static IEnumerable Values { get { return Enum.GetValues(typeof (T)).Cast(); } } #endregion } }