The Labs \ Source Viewer \ SSCLI \ System.Xml.Schema \ ConstraintStruct

  1. //------------------------------------------------------------------------------
  2. // <copyright file="ConstraintStruct.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. // <owner current="true" primary="true">priyal</owner>
  15. //------------------------------------------------------------------------------
  16. namespace System.Xml.Schema
  17. {
  18.     using System;
  19.     using System.Text;
  20.     using System.Collections;
  21.     using System.Globalization;
  22.     using System.Diagnostics;
  23.     using System.Xml.XPath;
  24.     using MS.Internal.Xml.XPath;
  25.    
  26.     internal sealed class ConstraintStruct
  27.     {
  28.         // for each constraint
  29.         internal CompiledIdentityConstraint constraint;
  30.         // pointer to constraint
  31.         internal SelectorActiveAxis axisSelector;
  32.         internal ArrayList axisFields;
  33.         // Add tableDim * LocatedActiveAxis in a loop
  34.         internal Hashtable qualifiedTable;
  35.         // Checking confliction
  36.         internal Hashtable keyrefTable;
  37.         // several keyref tables having connections to this one is possible
  38.         private int tableDim;
  39.         // dimension of table = numbers of fields;
  40.         internal int TableDim {
  41.             get { return this.tableDim; }
  42.         }
  43.        
  44.         internal ConstraintStruct(CompiledIdentityConstraint constraint)
  45.         {
  46.             this.constraint = constraint;
  47.             this.tableDim = constraint.Fields.Length;
  48.             this.axisFields = new ArrayList();
  49.             // empty fields
  50.             this.axisSelector = new SelectorActiveAxis(constraint.Selector, this);
  51.             if (this.constraint.Role != CompiledIdentityConstraint.ConstraintRole.Keyref) {
  52.                 this.qualifiedTable = new Hashtable();
  53.             }
  54.         }
  55.        
  56.     }
  57.    
  58.     // ActiveAxis plus the location plus the state of matching in the constraint table : only for field
  59.     internal class LocatedActiveAxis : ActiveAxis
  60.     {
  61.         private int column;
  62.         // the column in the table (the field sequence)
  63.         internal bool isMatched;
  64.         // if it's matched, then fill value in the validator later
  65.         internal KeySequence Ks;
  66.         // associated with a keysequence it will fills in
  67.         internal int Column {
  68.             get { return this.column; }
  69.         }
  70.        
  71.         internal LocatedActiveAxis(Asttree astfield, KeySequence ks, int column) : base(astfield)
  72.         {
  73.             this.Ks = ks;
  74.             this.column = column;
  75.             this.isMatched = false;
  76.         }
  77.        
  78.         internal void Reactivate(KeySequence ks)
  79.         {
  80.             Reactivate();
  81.             this.Ks = ks;
  82.         }
  83.        
  84.     }
  85.    
  86.     // exist for optimization purpose
  87.     // ActiveAxis plus
  88.     // 1. overload endelement function from parent to return result
  89.     // 2. combine locatedactiveaxis and keysequence more closely
  90.     // 3. enable locatedactiveaxis reusing (the most important optimization point)
  91.     // 4. enable ks adding to hashtable right after moving out selector node (to enable 3)
  92.     // 5. will modify locatedactiveaxis class accordingly
  93.     // 6. taking care of updating ConstraintStruct.axisFields
  94.     // 7. remove constraintTable from ConstraintStruct
  95.     // 8. still need centralized locatedactiveaxis for movetoattribute purpose
  96.     internal class SelectorActiveAxis : ActiveAxis
  97.     {
  98.         private ConstraintStruct cs;
  99.         // pointer of constraintstruct, to enable 6
  100.         private ArrayList KSs;
  101.         // stack of KSStruct, will not become less
  102.         private int KSpointer = 0;
  103.         // indicate current stack top (next available element);
  104.         public bool EmptyStack {
  105.             get { return KSpointer == 0; }
  106.         }
  107.        
  108.         public int lastDepth {
  109.             get { return (KSpointer == 0) ? -1 : ((KSStruct)KSs[KSpointer - 1]).depth; }
  110.         }
  111.        
  112.         public SelectorActiveAxis(Asttree axisTree, ConstraintStruct cs) : base(axisTree)
  113.         {
  114.             this.KSs = new ArrayList();
  115.             this.cs = cs;
  116.         }
  117.        
  118.         public override bool EndElement(string localname, string URN)
  119.         {
  120.             base.EndElement(localname, URN);
  121.             if (KSpointer > 0 && this.CurrentDepth == lastDepth) {
  122.                 return true;
  123.                 // next step PopPS, and insert into hash
  124.             }
  125.             return false;
  126.         }
  127.        
  128.         // update constraintStruct.axisFields as well, if it's new LocatedActiveAxis
  129.         public int PushKS(int errline, int errcol)
  130.         {
  131.             // new KeySequence each time
  132.             KeySequence ks = new KeySequence(cs.TableDim, errline, errcol);
  133.            
  134.             // needs to clear KSStruct before using
  135.             KSStruct kss;
  136.             if (KSpointer < KSs.Count) {
  137.                 // reuse, clear up KSs.KSpointer
  138.                 kss = (KSStruct)KSs[KSpointer];
  139.                 kss.ks = ks;
  140.                 // reactivate LocatedActiveAxis
  141.                 for (int i = 0; i < cs.TableDim; i++) {
  142.                     kss.fields[i].Reactivate(ks);
  143.                     // reassociate key sequence
  144.                 }
  145.             }
  146.             else {
  147.                 // "==", new
  148.                 kss = new KSStruct(ks, cs.TableDim);
  149.                 for (int i = 0; i < cs.TableDim; i++) {
  150.                     kss.fields[i] = new LocatedActiveAxis(cs.constraint.Fields[i], ks, i);
  151.                     cs.axisFields.Add(kss.fields[i]);
  152.                     // new, add to axisFields
  153.                 }
  154.                 KSs.Add(kss);
  155.             }
  156.            
  157.             kss.depth = this.CurrentDepth - 1;
  158.            
  159.             return (KSpointer++);
  160.         }
  161.        
  162.         public KeySequence PopKS()
  163.         {
  164.             return ((KSStruct)KSs[--KSpointer]).ks;
  165.         }
  166.        
  167.     }
  168.    
  169.     internal class KSStruct
  170.     {
  171.         public int depth;
  172.         // depth of selector when it matches
  173.         public KeySequence ks;
  174.         // ks of selector when it matches and assigned -- needs to new each time
  175.         public LocatedActiveAxis[] fields;
  176.         // array of fields activeaxis when it matches and assigned
  177.         public KSStruct(KeySequence ks, int dim)
  178.         {
  179.             this.ks = ks;
  180.             this.fields = new LocatedActiveAxis[dim];
  181.         }
  182.     }
  183.    
  184.     internal class TypedObject
  185.     {
  186.        
  187.         private class DecimalStruct
  188.         {
  189.             bool isDecimal = false;
  190.             // rare case it will be used...
  191.             decimal[] dvalue;
  192.             // to accelerate equals operation. array <-> list
  193.             public bool IsDecimal {
  194.                 get { return this.isDecimal; }
  195.                 set { this.isDecimal = value; }
  196.             }
  197.            
  198.             public decimal[] Dvalue {
  199.                 get { return this.dvalue; }
  200.             }
  201.            
  202.             public DecimalStruct()
  203.             {
  204.                 this.dvalue = new decimal[1];
  205.             }
  206.             //list
  207.             public DecimalStruct(int dim)
  208.             {
  209.                 this.dvalue = new decimal[dim];
  210.             }
  211.         }
  212.        
  213.         DecimalStruct dstruct = null;
  214.         object ovalue;
  215.         string svalue;
  216.         // only for output
  217.         XmlSchemaDatatype xsdtype;
  218.         int dim = 1;
  219.         bool isList = false;
  220.        
  221.         public int Dim {
  222.             get { return this.dim; }
  223.         }
  224.        
  225.         public bool IsList {
  226.             get { return this.isList; }
  227.         }
  228.        
  229.         public bool IsDecimal {
  230.             get {
  231.                 Debug.Assert(this.dstruct != null);
  232.                 return this.dstruct.IsDecimal;
  233.             }
  234.         }
  235.         public decimal[] Dvalue {
  236.             get {
  237.                 Debug.Assert(this.dstruct != null);
  238.                 return this.dstruct.Dvalue;
  239.             }
  240.         }
  241.        
  242.         public object Value {
  243.             get { return ovalue; }
  244.             set { ovalue = value; }
  245.         }
  246.        
  247.         public XmlSchemaDatatype Type {
  248.             get { return xsdtype; }
  249.             set { xsdtype = value; }
  250.         }
  251.        
  252.         public TypedObject(object obj, string svalue, XmlSchemaDatatype xsdtype)
  253.         {
  254.             this.ovalue = obj;
  255.             this.svalue = svalue;
  256.             this.xsdtype = xsdtype;
  257.             if (xsdtype.Variety == XmlSchemaDatatypeVariety.List || xsdtype is Datatype_base64Binary || xsdtype is Datatype_hexBinary) {
  258.                 this.isList = true;
  259.                 this.dim = ((Array)obj).Length;
  260.             }
  261.         }
  262.        
  263.         public override string ToString()
  264.         {
  265.             // only for exception
  266.             return this.svalue;
  267.         }
  268.        
  269.         public void SetDecimal()
  270.         {
  271.            
  272.             if (this.dstruct != null) {
  273.                 return;
  274.             }
  275.            
  276.             // Debug.Assert(!this.IsDecimal);
  277.             switch (xsdtype.TypeCode) {
  278.                 case XmlTypeCode.Byte:
  279.                 case XmlTypeCode.UnsignedByte:
  280.                 case XmlTypeCode.Short:
  281.                 case XmlTypeCode.UnsignedShort:
  282.                 case XmlTypeCode.Int:
  283.                 case XmlTypeCode.UnsignedInt:
  284.                 case XmlTypeCode.Long:
  285.                 case XmlTypeCode.UnsignedLong:
  286.                 case XmlTypeCode.Decimal:
  287.                 case XmlTypeCode.Integer:
  288.                 case XmlTypeCode.PositiveInteger:
  289.                 case XmlTypeCode.NonNegativeInteger:
  290.                 case XmlTypeCode.NegativeInteger:
  291.                 case XmlTypeCode.NonPositiveInteger:
  292.                    
  293.                     if (this.isList) {
  294.                         this.dstruct = new DecimalStruct(this.dim);
  295.                         for (int i = 0; i < this.dim; i++) {
  296.                             this.dstruct.Dvalue[i] = Convert.ToDecimal(((Array)this.ovalue).GetValue(i), NumberFormatInfo.InvariantInfo);
  297.                         }
  298.                     }
  299.                     else {
  300.                         //not list
  301.                         this.dstruct = new DecimalStruct();
  302.                         //possibility of list of length 1.
  303.                         this.dstruct.Dvalue[0] = Convert.ToDecimal(this.ovalue, NumberFormatInfo.InvariantInfo);
  304.                     }
  305.                     this.dstruct.IsDecimal = true;
  306.                     break;
  307.                 default:
  308.                    
  309.                     if (this.isList) {
  310.                         this.dstruct = new DecimalStruct(this.dim);
  311.                     }
  312.                     else {
  313.                         this.dstruct = new DecimalStruct();
  314.                     }
  315.                     break;
  316.                
  317.             }
  318.         }
  319.        
  320.         private bool ListDValueEquals(TypedObject other)
  321.         {
  322.             for (int i = 0; i < this.Dim; i++) {
  323.                 if (this.Dvalue[i] != other.Dvalue[i]) {
  324.                     return false;
  325.                 }
  326.             }
  327.             return true;
  328.         }
  329.        
  330.         public bool Equals(TypedObject other)
  331.         {
  332.             // ? one is list with one member, another is not list -- still might be equal
  333.             if (this.Dim != other.Dim) {
  334.                 return false;
  335.             }
  336.            
  337.             if (this.Type != other.Type) {
  338.                 //Check if types are comparable
  339.                 if (!(this.Type.IsComparable(other.Type))) {
  340.                     return false;
  341.                 }
  342.                 other.SetDecimal();
  343.                 // can't use cast and other.Type.IsEqual (value1, value2)
  344.                 this.SetDecimal();
  345.                 if (this.IsDecimal && other.IsDecimal) {
  346.                     //Both are decimal / derived types
  347.                     return this.ListDValueEquals(other);
  348.                 }
  349.             }
  350.            
  351.             // not-Decimal derivation or type equal
  352.             if (this.IsList) {
  353.                 if (other.IsList) {
  354.                     //Both are lists and values are XmlAtomicValue[] or clrvalue[]. So use Datatype_List.Compare
  355.                     return this.Type.Compare(this.Value, other.Value) == 0;
  356.                 }
  357.                 else {
  358.                     //this is a list and other is a single value
  359.                     Array arr1 = this.Value as System.Array;
  360.                     XmlAtomicValue[] atomicValues1 = arr1 as XmlAtomicValue[];
  361.                     if (atomicValues1 != null) {
  362.                         // this is a list of union
  363.                         return atomicValues1.Length == 1 && atomicValues1.GetValue(0).Equals(other.Value);
  364.                     }
  365.                     else {
  366.                         return arr1.Length == 1 && arr1.GetValue(0).Equals(other.Value);
  367.                     }
  368.                 }
  369.             }
  370.             else if (other.IsList) {
  371.                 Array arr2 = other.Value as System.Array;
  372.                 XmlAtomicValue[] atomicValues2 = arr2 as XmlAtomicValue[];
  373.                 if (atomicValues2 != null) {
  374.                     // other is a list of union
  375.                     return atomicValues2.Length == 1 && atomicValues2.GetValue(0).Equals(this.Value);
  376.                 }
  377.                 else {
  378.                     return arr2.Length == 1 && arr2.GetValue(0).Equals(this.Value);
  379.                 }
  380.             }
  381.             else {
  382.                 //Both are not lists
  383.                 return this.Value.Equals(other.Value);
  384.             }
  385.         }
  386.     }
  387.    
  388.     internal class KeySequence
  389.     {
  390.         TypedObject[] ks;
  391.         int dim;
  392.         int hashcode = -1;
  393.         int posline, poscol;
  394.         // for error reporting
  395.         internal KeySequence(int dim, int line, int col)
  396.         {
  397.             Debug.Assert(dim > 0);
  398.             this.dim = dim;
  399.             this.ks = new TypedObject[dim];
  400.             this.posline = line;
  401.             this.poscol = col;
  402.         }
  403.        
  404.         public int PosLine {
  405.             get { return this.posline; }
  406.         }
  407.        
  408.         public int PosCol {
  409.             get { return this.poscol; }
  410.         }
  411.        
  412.         public KeySequence(TypedObject[] ks)
  413.         {
  414.             this.ks = ks;
  415.             this.dim = ks.Length;
  416.             this.posline = this.poscol = 0;
  417.         }
  418.        
  419.         public object this[int index]
  420.         {
  421.             get {
  422.                 object result = ks[index];
  423.                 return result;
  424.             }
  425.             set { ks[index] = (TypedObject)value; }
  426.         }
  427.        
  428.         // return true if no null field
  429.         internal bool IsQualified()
  430.         {
  431.             foreach (TypedObject tobj in this.ks) {
  432.                 if ((tobj == null) || (tobj.Value == null))
  433.                     return false;
  434.             }
  435.             return true;
  436.         }
  437.        
  438.         // it's not directly suit for hashtable, because it's always calculating address
  439.         public override int GetHashCode()
  440.         {
  441.             if (hashcode != -1) {
  442.                 return hashcode;
  443.             }
  444.             hashcode = 0;
  445.             // indicate it's changed. even the calculated hashcode below is 0
  446.             for (int i = 0; i < this.ks.Length; i++) {
  447.                 // extract its primitive value to calculate hashcode
  448.                 // decimal is handled differently to enable among different CLR types
  449.                 this.ks[i].SetDecimal();
  450.                 if (this.ks[i].IsDecimal) {
  451.                     for (int j = 0; j < this.ks[i].Dim; j++) {
  452.                         hashcode += this.ks[i].Dvalue[j].GetHashCode();
  453.                     }
  454.                 }
  455.                 else {
  456.                     Array arr = this.ks[i].Value as System.Array;
  457.                     if (arr != null) {
  458.                         XmlAtomicValue[] atomicValues = arr as XmlAtomicValue[];
  459.                         if (atomicValues != null) {
  460.                             for (int j = 0; j < atomicValues.Length; j++) {
  461.                                 hashcode += ((XmlAtomicValue)atomicValues.GetValue(j)).TypedValue.GetHashCode();
  462.                             }
  463.                         }
  464.                         else {
  465.                             for (int j = 0; j < ((Array)this.ks[i].Value).Length; j++) {
  466.                                 hashcode += ((Array)this.ks[i].Value).GetValue(j).GetHashCode();
  467.                             }
  468.                         }
  469.                     }
  470.                     else {
  471.                         //not a list
  472.                         hashcode += this.ks[i].Value.GetHashCode();
  473.                     }
  474.                 }
  475.             }
  476.             return hashcode;
  477.         }
  478.        
  479.         // considering about derived type
  480.         public override bool Equals(object other)
  481.         {
  482.             // each key sequence member can have different type
  483.             KeySequence keySequence = (KeySequence)other;
  484.             for (int i = 0; i < this.ks.Length; i++) {
  485.                 if (!this.ks[i].Equals(keySequence.ks[i])) {
  486.                     return false;
  487.                 }
  488.             }
  489.             return true;
  490.         }
  491.        
  492.         public override string ToString()
  493.         {
  494.             StringBuilder sb = new StringBuilder();
  495.             sb.Append(this.ks[0].ToString());
  496.             for (int i = 1; i < this.ks.Length; i++) {
  497.                 sb.Append(" ");
  498.                 sb.Append(this.ks[i].ToString());
  499.             }
  500.             return sb.ToString();
  501.         }
  502.     }
  503.    
  504. }

Developer Fusion