//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Microsoft
//------------------------------------------------------------------------------
using System.Diagnostics;
using System.IO;
namespace System.Xml.Xsl {
///
/// Cardinality of part of XmlQueryType
/// struct is being used because enum doesn't allow members
///
internal struct XmlQueryCardinality {
private int value;
#region ctor
///
/// Private constructor
///
private XmlQueryCardinality(int value) {
Debug.Assert(0x00 <= value && value <= 0x07);
this.value = value;
}
#endregion
#region enum
///
/// exactly zero (empty)
///
public static XmlQueryCardinality None {
get { return new XmlQueryCardinality(0x00); }
}
///
/// exactly zero (empty)
///
public static XmlQueryCardinality Zero {
get { return new XmlQueryCardinality(0x01); }
}
///
/// exactly one
///
public static XmlQueryCardinality One {
get { return new XmlQueryCardinality(0x02); }
}
///
/// zero or one (not more)
///
public static XmlQueryCardinality ZeroOrOne {
get { return new XmlQueryCardinality(0x03); }
}
///
/// strictly more than one
///
public static XmlQueryCardinality More {
get { return new XmlQueryCardinality(0x04); }
}
///
/// not one (strictly zero or strictly more)
///
public static XmlQueryCardinality NotOne {
get { return new XmlQueryCardinality(0x05); }
}
///
/// one or more (not empty)
///
public static XmlQueryCardinality OneOrMore {
get { return new XmlQueryCardinality(0x06); }
}
///
/// zero or more (any cardinality)
///
public static XmlQueryCardinality ZeroOrMore {
get { return new XmlQueryCardinality(0x07); }
}
#endregion
#region ==
///
/// Strongly-typed Equals that returns true if this type and "other" type are equivalent.
///
public bool Equals(XmlQueryCardinality other) {
return this.value == other.value;
}
///
/// Overload == operator to call Equals rather than do reference equality.
///
public static bool operator ==(XmlQueryCardinality left, XmlQueryCardinality right) {
return left.value == right.value;
}
///
/// Overload != operator to call Equals rather than do reference inequality.
///
public static bool operator !=(XmlQueryCardinality left, XmlQueryCardinality right) {
return left.value != right.value;
}
///
/// True if "other" is an XmlQueryCardinality, and this type is the exact same static type.
///
public override bool Equals(object other) {
if (other is XmlQueryCardinality) {
return Equals((XmlQueryCardinality)other);
}
return false;
}
///
/// Return hash code of this instance.
///
public override int GetHashCode() {
return value;
}
#endregion
#region algebra
///
/// Return union with other
///
public static XmlQueryCardinality operator |(XmlQueryCardinality left, XmlQueryCardinality right) {
return new XmlQueryCardinality(left.value | right.value);
}
///
/// Return intersection with other
///
public static XmlQueryCardinality operator &(XmlQueryCardinality left, XmlQueryCardinality right) {
return new XmlQueryCardinality(left.value & right.value);
}
///
/// Return this product other
///
public static XmlQueryCardinality operator *(XmlQueryCardinality left, XmlQueryCardinality right) {
return cardinalityProduct[left.value, right.value];
}
///
/// Return sum with other
///
public static XmlQueryCardinality operator +(XmlQueryCardinality left, XmlQueryCardinality right) {
return cardinalitySum[left.value, right.value];
}
#if NEVER
///
/// Returns true if this cardinality is guaranteed to be a subset of "other".
///
private bool IsSubset(XmlQueryCardinality other) {
return (this.value & ~other.value) == 0;
}
#endif
///
/// Returns true is left is subset of right.
///
public static bool operator <=(XmlQueryCardinality left, XmlQueryCardinality right) {
return (left.value & ~right.value) == 0;
}
///
/// Returns true is right is subset of left.
///
public static bool operator >=(XmlQueryCardinality left, XmlQueryCardinality right) {
return (right.value & ~left.value) == 0;
}
///
/// Compute the cardinality of a subset of a set of the given cardinality.
///
/// the cardinality of a set
/// the cardinality of a subset
public XmlQueryCardinality AtMost() {
// Fill downward to zero
return new XmlQueryCardinality(this.value | (this.value >> 1) | (this.value >> 2));
}
///
/// Returns true if every non-None subset of this cardinality is disjoint with "other" cardinality.
/// Here is the behavior for None, which is the inverse of the None behavior for IsSubset:
/// None op None = false
/// None op ~None = false
/// ~None op None = true
///
public bool NeverSubset(XmlQueryCardinality other) {
return this.value != 0 && (this.value & other.value) == 0;
}
///
/// Table of cardinality products.
///
private static readonly XmlQueryCardinality[,] cardinalityProduct = {
// None Zero One ZeroOrOne More NotOne OneOrMore ZeroOrMore
/* None */ { None, Zero, None , Zero , None , Zero , None , Zero },
/* Zero */ { Zero, Zero, Zero , Zero , Zero , Zero , Zero , Zero },
/* One */ { None, Zero, One , ZeroOrOne , More , NotOne, OneOrMore , ZeroOrMore },
/* ZeroOrOne */ { Zero, Zero, ZeroOrOne , ZeroOrOne , NotOne, NotOne, ZeroOrMore, ZeroOrMore },
/* More */ { None, Zero, More , NotOne , More , NotOne, More , NotOne },
/* NotOne */ { Zero, Zero, NotOne , NotOne , NotOne, NotOne, NotOne , NotOne },
/* OneOrMore */ { None, Zero, OneOrMore , ZeroOrMore, More , NotOne, OneOrMore , ZeroOrMore },
/* ZeroOrMore */ { Zero, Zero, ZeroOrMore, ZeroOrMore, NotOne, NotOne, ZeroOrMore, ZeroOrMore }
};
///
/// Table of cardinality sums.
///
private static readonly XmlQueryCardinality[,] cardinalitySum = {
// None Zero One ZeroOrOne More NotOne OneOrMore ZeroOrMore
/* None */ { None , Zero , One , ZeroOrOne , More, NotOne , OneOrMore, ZeroOrMore},
/* Zero */ { Zero , Zero , One , ZeroOrOne , More, NotOne , OneOrMore, ZeroOrMore},
/* One */ { One , One , More , OneOrMore , More, OneOrMore , More , OneOrMore },
/* ZeroOrOne */ { ZeroOrOne , ZeroOrOne , OneOrMore, ZeroOrMore, More, ZeroOrMore, OneOrMore, ZeroOrMore},
/* More */ { More , More , More , More , More, More , More , More },
/* NotOne */ { NotOne , NotOne , OneOrMore, ZeroOrMore, More, NotOne , OneOrMore, ZeroOrMore},
/* OneOrMore */ { OneOrMore , OneOrMore , More , OneOrMore , More, OneOrMore , More , OneOrMore },
/* ZeroOrMore */ { ZeroOrMore, ZeroOrMore, OneOrMore, ZeroOrMore, More, ZeroOrMore, OneOrMore, ZeroOrMore}
};
#endregion
#region Serialization
///
/// String representation.
///
private static readonly string[] toString = {
/* None */ "" ,
/* Zero */ "?" ,
/* One */ "" ,
/* ZeroOrOne */ "?" ,
/* More */ "+" ,
/* NotOne */ "*" ,
/* OneOrMore */ "+" ,
/* ZeroOrMore */ "*"
};
///
/// Serialization
///
private static readonly string[] serialized = {
/* None */ "None",
/* Zero */ "Zero",
/* One */ "One",
/* ZeroOrOne */ "ZeroOrOne",
/* More */ "More",
/* NotOne */ "NotOne",
/* OneOrMore */ "OneOrMore",
/* ZeroOrMore */ "ZeroOrMore"
};
///
/// Return the string representation of a cardinality, normalized to either ?, +, *, or "" (card 1).
///
public string ToString(string format) {
if (format == "S") {
return serialized[this.value];
}
else {
return ToString();
}
}
///
/// Return the string representation of a cardinality, normalized to either ?, +, *, or "" (card 1).
///
public override string ToString() {
return toString[this.value];
}
///
/// Deserialization
///
public XmlQueryCardinality(string s) {
this.value = 0x00;
for (int i = 0; i < serialized.Length; i++) {
if (s == serialized[i]) {
this.value = i;
break;
}
}
}
///
/// Serialize the object to BinaryWriter.
///
public void GetObjectData(BinaryWriter writer) {
writer.Write((byte)value);
}
///
/// Deserialize the object from BinaryReader.
///
public XmlQueryCardinality(BinaryReader reader) : this(reader.ReadByte()) {
}
#endregion
}
}