ff82368dd7fe67ee653c6372a7ddf3f8495895a5
[mono.git] / mcs / class / referencesource / System.Xml / System / Xml / Schema / XmlSchemaObjectTable.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="XmlSchemaObjectTable.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>                                                                 
6 //------------------------------------------------------------------------------
7
8 namespace System.Xml.Schema {
9
10     using System.Collections;
11     using System.Collections.Generic;
12     using System.Diagnostics;
13
14     /// <include file='doc\XmlSchemaObjectTable.uex' path='docs/doc[@for="XmlSchemaObjectTable"]/*' />
15     public class XmlSchemaObjectTable {
16         Dictionary<XmlQualifiedName, XmlSchemaObject> table = new Dictionary<XmlQualifiedName,XmlSchemaObject>();
17         List<XmlSchemaObjectEntry> entries = new List<XmlSchemaObjectEntry>();
18         
19         internal XmlSchemaObjectTable() {
20         }
21
22         internal void Add(XmlQualifiedName name,  XmlSchemaObject value) {
23             Debug.Assert(!table.ContainsKey(name), "XmlSchemaObjectTable.Add: entry already exists");
24             table.Add(name, value);
25             entries.Add(new XmlSchemaObjectEntry(name, value));
26         }
27
28         internal void Insert(XmlQualifiedName name,  XmlSchemaObject value) {
29             XmlSchemaObject oldValue = null;
30             if (table.TryGetValue(name, out oldValue)) {
31                 table[name] = value; //set new value
32                 Debug.Assert(oldValue != null);
33                 int matchedIndex = FindIndexByValue(oldValue);
34                 Debug.Assert(matchedIndex >= 0);
35                 //set new entry
36                 Debug.Assert(entries[matchedIndex].qname == name);
37                 entries[matchedIndex] = new XmlSchemaObjectEntry(name, value);
38             }
39             else {
40                 Add(name, value);
41             }
42             
43         }
44
45         internal void Replace(XmlQualifiedName name,  XmlSchemaObject value) {
46             XmlSchemaObject oldValue;
47             if (table.TryGetValue(name, out oldValue)) {
48                 table[name] = value; //set new value
49                 Debug.Assert(oldValue != null);
50                 int matchedIndex = FindIndexByValue(oldValue);
51                 Debug.Assert(entries[matchedIndex].qname == name);
52                 entries[matchedIndex] = new XmlSchemaObjectEntry(name, value);
53             }
54         }
55
56         internal void Clear() {
57             table.Clear();
58             entries.Clear();
59         }
60
61         internal void Remove(XmlQualifiedName name) {
62             XmlSchemaObject value;
63             if (table.TryGetValue(name, out value)) {
64                 table.Remove(name);
65                 int matchedIndex = FindIndexByValue(value);
66                 Debug.Assert(matchedIndex >= 0);
67                 Debug.Assert(entries[matchedIndex].qname == name);
68                 entries.RemoveAt(matchedIndex);                    
69             }
70         }
71
72         private int FindIndexByValue(XmlSchemaObject xso) {
73             int index;
74             for(index = 0; index < entries.Count; index++) {
75                 if((object)entries[index].xso == (object)xso) {
76                     return index;
77                 }    
78             }
79             return -1;
80         }
81         /// <include file='doc\XmlSchemaObjectTable.uex' path='docs/doc[@for="XmlSchemaObjectTable.Count"]/*' />
82         public int Count {
83             get {
84                 Debug.Assert(table.Count == entries.Count);
85                 return table.Count;
86             }
87         }
88
89         /// <include file='doc\XmlSchemaObjectTable.uex' path='docs/doc[@for="XmlSchemaObjectTable.Contains"]/*' />
90         public bool Contains(XmlQualifiedName name) {
91             return table.ContainsKey(name);
92         }
93
94         /// <include file='doc\XmlSchemaObjectTable.uex' path='docs/doc[@for="XmlSchemaObjectTable.this"]/*' />
95         public XmlSchemaObject this[XmlQualifiedName name] {
96             get { 
97                 XmlSchemaObject value;
98                 if (table.TryGetValue(name, out value)) {
99                     return value;
100                 }
101                 return null;
102             }
103         }
104         
105         /// <include file='doc\XmlSchemaObjectTable.uex' path='docs/doc[@for="XmlSchemaObjectTable.Names"]/*' />
106         public ICollection Names {
107             get { 
108                 return new NamesCollection(entries, table.Count);
109             }
110         }
111
112         /// <include file='doc\XmlSchemaObjectTable.uex' path='docs/doc[@for="XmlSchemaObjectTable.Values"]/*' />
113         public ICollection Values {
114             get { 
115                 return new ValuesCollection(entries, table.Count);
116             }
117         }
118         
119         /// <include file='doc\XmlSchemaObjectTable.uex' path='docs/doc[@for="XmlSchemaObjectTable.GetEnumerator"]/*' />
120         public IDictionaryEnumerator GetEnumerator() {
121             return new XSODictionaryEnumerator(this.entries, table.Count, EnumeratorType.DictionaryEntry); 
122         }
123
124         internal enum EnumeratorType {
125             Keys,
126             Values,
127             DictionaryEntry,
128         }
129
130         internal struct XmlSchemaObjectEntry {
131             internal XmlQualifiedName qname;
132             internal XmlSchemaObject xso;
133
134             public XmlSchemaObjectEntry(XmlQualifiedName name, XmlSchemaObject value) {
135                 qname = name;
136                 xso = value;
137             }
138
139             public XmlSchemaObject IsMatch(string localName, string ns) {
140                 if (localName == qname.Name && ns == qname.Namespace) {
141                     return xso;
142                 }
143                 return null;
144             }
145
146             public void Reset() {
147                 qname = null;
148                 xso = null;
149             }
150         }
151
152         internal class NamesCollection : ICollection {
153             private List<XmlSchemaObjectEntry> entries;
154             int size;
155         
156             internal NamesCollection(List<XmlSchemaObjectEntry> entries, int size) {
157                 this.entries = entries;
158                 this.size = size;
159             }
160             
161             public int Count { 
162                 get { return size; }
163             }
164
165             public Object SyncRoot {
166                 get {
167                     return ((ICollection)entries).SyncRoot;
168                 }
169             }
170
171             public bool IsSynchronized {
172                 get {
173                     return ((ICollection)entries).IsSynchronized;
174                 }
175             }
176
177             public void CopyTo(Array array, int arrayIndex) {
178                 if (array == null)
179                     throw new ArgumentNullException("array");
180
181                             if (arrayIndex < 0) 
182                     throw new ArgumentOutOfRangeException("arrayIndex");
183
184                 Debug.Assert(array.Length >= size, "array is not big enough to hold all the items in the ICollection");
185
186                 for (int i = 0; i < size; i++) {
187                     array.SetValue(entries[i].qname, arrayIndex++);
188                 }
189             }
190
191             public IEnumerator GetEnumerator() {
192                 return new XSOEnumerator(this.entries, this.size, EnumeratorType.Keys);
193             }
194         }
195
196         //ICollection for Values 
197         internal class ValuesCollection : ICollection {
198             private List<XmlSchemaObjectEntry> entries;
199             int size;
200         
201             internal ValuesCollection(List<XmlSchemaObjectEntry> entries, int size) {
202                 this.entries = entries;
203                 this.size = size;
204             }
205             
206             public int Count { 
207                 get { return size; }
208             }
209
210             public Object SyncRoot {
211                 get {
212                     return ((ICollection)entries).SyncRoot;
213                 }
214             }
215
216             public bool IsSynchronized {
217                 get {
218                     return ((ICollection)entries).IsSynchronized;
219                 }
220             }
221
222             public void CopyTo(Array array, int arrayIndex) {
223                 if (array == null)
224                     throw new ArgumentNullException("array");
225
226                             if (arrayIndex < 0) 
227                     throw new ArgumentOutOfRangeException("arrayIndex");
228
229                 Debug.Assert(array.Length >= size, "array is not big enough to hold all the items in the ICollection");
230
231                 for (int i = 0; i < size; i++) {
232                     array.SetValue(entries[i].xso, arrayIndex++);
233                 }
234             }
235             
236             public IEnumerator GetEnumerator() {
237                 return new XSOEnumerator(this.entries, this.size, EnumeratorType.Values);
238             }
239         }
240
241         internal class XSOEnumerator : IEnumerator {
242             private List<XmlSchemaObjectEntry> entries;
243             private EnumeratorType enumType;
244
245             protected int currentIndex;
246             protected int size;
247             protected XmlQualifiedName currentKey;
248             protected XmlSchemaObject currentValue;
249             
250
251             internal XSOEnumerator(List<XmlSchemaObjectEntry> entries, int size, EnumeratorType enumType) {
252                 this.entries = entries;
253                 this.size = size;
254                 this.enumType = enumType;
255                 currentIndex = -1;
256             }
257
258             public Object Current {
259                 get {
260                     if (currentIndex == -1) {
261                         throw new InvalidOperationException(Res.GetString(Res.Sch_EnumNotStarted, string.Empty));
262                     }
263                     if (currentIndex >= size) {
264                         throw new InvalidOperationException(Res.GetString(Res.Sch_EnumFinished, string.Empty));
265                     }
266                     switch(enumType) {
267                         case EnumeratorType.Keys:
268                             return currentKey;
269                     
270                         case EnumeratorType.Values:
271                             return currentValue;
272
273                         case EnumeratorType.DictionaryEntry:
274                             return new DictionaryEntry(currentKey, currentValue);
275
276                         default:
277                             break;
278                     }
279                     return null;
280                 }
281             }
282
283             public bool MoveNext() {
284                 if (currentIndex >= size - 1) {
285                     currentValue = null;
286                     currentKey = null;
287                     return false;
288                 }
289                 currentIndex++;
290                 currentValue = entries[currentIndex].xso;
291                 currentKey = entries[currentIndex].qname;
292                 return true;
293             }
294
295             public void Reset() {
296                 currentIndex = -1;
297                 currentValue = null;
298                 currentKey = null;
299             }
300         }
301
302         internal class XSODictionaryEnumerator : XSOEnumerator, IDictionaryEnumerator {
303            
304             internal XSODictionaryEnumerator(List<XmlSchemaObjectEntry> entries, int size, EnumeratorType enumType) : base(entries, size, enumType) {
305             }
306             
307             //IDictionaryEnumerator members
308             public DictionaryEntry Entry {
309                 get {
310                     if (currentIndex == -1) {
311                         throw new InvalidOperationException(Res.GetString(Res.Sch_EnumNotStarted, string.Empty));
312                     }
313                     if (currentIndex >= size) {
314                         throw new InvalidOperationException(Res.GetString(Res.Sch_EnumFinished, string.Empty));
315                     }
316                     return new DictionaryEntry(currentKey, currentValue);
317                 }
318             }
319
320             public object Key {
321                 get {
322                     if (currentIndex == -1) {
323                         throw new InvalidOperationException(Res.GetString(Res.Sch_EnumNotStarted, string.Empty));
324                     }
325                     if (currentIndex >= size) {
326                         throw new InvalidOperationException(Res.GetString(Res.Sch_EnumFinished, string.Empty));
327                     }
328                     return currentKey;
329                 }
330             }
331
332             public object Value {
333                 get {
334                     if (currentIndex == -1) {
335                         throw new InvalidOperationException(Res.GetString(Res.Sch_EnumNotStarted, string.Empty));
336                     }
337                     if (currentIndex >= size) {
338                         throw new InvalidOperationException(Res.GetString(Res.Sch_EnumFinished, string.Empty));
339                     }
340                     return currentValue;
341                 }
342             }
343         }
344
345     }
346 }