Update mcs/class/Commons.Xml.Relaxng/Commons.Xml.Relaxng/RelaxngPattern.cs
[mono.git] / mcs / class / IKVM.Reflection / CustomModifiers.cs
1 /*
2   Copyright (C) 2011 Jeroen Frijters
3
4   This software is provided 'as-is', without any express or implied
5   warranty.  In no event will the authors be held liable for any damages
6   arising from the use of this software.
7
8   Permission is granted to anyone to use this software for any purpose,
9   including commercial applications, and to alter it and redistribute it
10   freely, subject to the following restrictions:
11
12   1. The origin of this software must not be misrepresented; you must not
13      claim that you wrote the original software. If you use this software
14      in a product, an acknowledgment in the product documentation would be
15      appreciated but is not required.
16   2. Altered source versions must be plainly marked as such, and must not be
17      misrepresented as being the original software.
18   3. This notice may not be removed or altered from any source distribution.
19
20   Jeroen Frijters
21   jeroen@frijters.net
22   
23 */
24 using System;
25 using System.Collections.Generic;
26 using System.Diagnostics;
27 using System.Text;
28 using IKVM.Reflection.Emit;
29 using IKVM.Reflection.Reader;
30
31 namespace IKVM.Reflection
32 {
33         public struct CustomModifiers : IEquatable<CustomModifiers>, IEnumerable<CustomModifiers.Entry>
34         {
35                 // note that FromReqOpt assumes that Initial == ModOpt
36                 private static Type Initial { get { return MarkerType.ModOpt; } }
37                 private readonly Type[] types;
38
39                 internal CustomModifiers(List<CustomModifiersBuilder.Item> list)
40                 {
41                         bool required = Initial == MarkerType.ModReq;
42                         int count = list.Count;
43                         foreach (CustomModifiersBuilder.Item item in list)
44                         {
45                                 if (item.required != required)
46                                 {
47                                         required = item.required;
48                                         count++;
49                                 }
50                         }
51                         types = new Type[count];
52                         required = Initial == MarkerType.ModReq;
53                         int index = 0;
54                         foreach (CustomModifiersBuilder.Item item in list)
55                         {
56                                 if (item.required != required)
57                                 {
58                                         required = item.required;
59                                         types[index++] = required ? MarkerType.ModReq : MarkerType.ModOpt;
60                                 }
61                                 types[index++] = item.type;
62                         }
63                 }
64
65                 private CustomModifiers(Type[] types)
66                 {
67                         Debug.Assert(types == null || types.Length != 0);
68                         this.types = types;
69                 }
70
71                 public struct Enumerator : IEnumerator<Entry>
72                 {
73                         private readonly Type[] types;
74                         private int index;
75                         private bool required;
76
77                         internal Enumerator(Type[] types)
78                         {
79                                 this.types = types;
80                                 this.index = -1;
81                                 this.required = Initial == MarkerType.ModReq;
82                         }
83
84                         void System.Collections.IEnumerator.Reset()
85                         {
86                                 this.index = -1;
87                                 this.required = Initial == MarkerType.ModReq;
88                         }
89
90                         public Entry Current
91                         {
92                                 get { return new Entry(types[index], required); }
93                         }
94
95                         public bool MoveNext()
96                         {
97                                 if (types == null || index == types.Length)
98                                 {
99                                         return false;
100                                 }
101                                 index++;
102                                 if (index == types.Length)
103                                 {
104                                         return false;
105                                 }
106                                 else if (types[index] == MarkerType.ModOpt)
107                                 {
108                                         required = false;
109                                         index++;
110                                 }
111                                 else if (types[index] == MarkerType.ModReq)
112                                 {
113                                         required = true;
114                                         index++;
115                                 }
116                                 return true;
117                         }
118
119                         object System.Collections.IEnumerator.Current
120                         {
121                                 get { return Current; }
122                         }
123
124                         void IDisposable.Dispose()
125                         {
126                         }
127                 }
128
129                 public struct Entry
130                 {
131                         private readonly Type type;
132                         private readonly bool required;
133
134                         internal Entry(Type type, bool required)
135                         {
136                                 this.type = type;
137                                 this.required = required;
138                         }
139
140                         public Type Type
141                         {
142                                 get { return type; }
143                         }
144
145                         public bool IsRequired
146                         {
147                                 get { return required; }
148                         }
149                 }
150
151                 public Enumerator GetEnumerator()
152                 {
153                         return new Enumerator(types);
154                 }
155
156                 IEnumerator<Entry> IEnumerable<Entry>.GetEnumerator()
157                 {
158                         return GetEnumerator();
159                 }
160
161                 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
162                 {
163                         return GetEnumerator();
164                 }
165
166                 public bool IsEmpty
167                 {
168                         get { return types == null; }
169                 }
170
171                 public bool Equals(CustomModifiers other)
172                 {
173                         return Util.ArrayEquals(types, other.types);
174                 }
175
176                 public override bool Equals(object obj)
177                 {
178                         CustomModifiers? other = obj as CustomModifiers?;
179                         return other != null && Equals(other.Value);
180                 }
181
182                 public override int GetHashCode()
183                 {
184                         return Util.GetHashCode(types);
185                 }
186
187                 public override string ToString()
188                 {
189                         if (types == null)
190                         {
191                                 return string.Empty;
192                         }
193                         StringBuilder sb = new StringBuilder();
194                         string sep = "";
195                         foreach (Entry e in this)
196                         {
197                                 sb.Append(sep).Append(e.IsRequired ? "modreq(" : "modopt(").Append(e.Type.FullName).Append(')');
198                                 sep = " ";
199                         }
200                         return sb.ToString();
201                 }
202
203                 private Type[] GetRequiredOrOptional(bool required)
204                 {
205                         if (types == null)
206                         {
207                                 return Type.EmptyTypes;
208                         }
209                         int count = 0;
210                         foreach (Entry e in this)
211                         {
212                                 if (e.IsRequired == required)
213                                 {
214                                         count++;
215                                 }
216                         }
217                         Type[] result = new Type[count];
218                         foreach (Entry e in this)
219                         {
220                                 if (e.IsRequired == required)
221                                 {
222                                         // FXBUG reflection (and ildasm) return custom modifiers in reverse order
223                                         // while SRE writes them in the specified order
224                                         result[--count] = e.Type;
225                                 }
226                         }
227                         return result;
228                 }
229
230                 internal Type[] GetRequired()
231                 {
232                         return GetRequiredOrOptional(true);
233                 }
234
235                 internal Type[] GetOptional()
236                 {
237                         return GetRequiredOrOptional(false);
238                 }
239
240                 internal CustomModifiers Bind(IGenericBinder binder)
241                 {
242                         if (types == null)
243                         {
244                                 return this;
245                         }
246                         Type[] result = types;
247                         for (int i = 0; i < types.Length; i++)
248                         {
249                                 if (types[i] == MarkerType.ModOpt || types[i] == MarkerType.ModReq)
250                                 {
251                                         continue;
252                                 }
253                                 Type type = types[i].BindTypeParameters(binder);
254                                 if (!ReferenceEquals(type, types[i]))
255                                 {
256                                         if (result == types)
257                                         {
258                                                 result = (Type[])types.Clone();
259                                         }
260                                         result[i] = type;
261                                 }
262                         }
263                         return new CustomModifiers(result);
264                 }
265
266                 internal static CustomModifiers Read(ModuleReader module, ByteReader br, IGenericContext context)
267                 {
268                         byte b = br.PeekByte();
269                         if (!IsCustomModifier(b))
270                         {
271                                 return new CustomModifiers();
272                         }
273                         List<Type> list = new List<Type>();
274                         Type mode = Initial;
275                         do
276                         {
277                                 Type cmod = br.ReadByte() == Signature.ELEMENT_TYPE_CMOD_REQD ? MarkerType.ModReq : MarkerType.ModOpt;
278                                 if (mode != cmod)
279                                 {
280                                         mode = cmod;
281                                         list.Add(mode);
282                                 }
283                                 list.Add(Signature.ReadTypeDefOrRefEncoded(module, br, context));
284                                 b = br.PeekByte();
285                         }
286                         while (IsCustomModifier(b));
287                         return new CustomModifiers(list.ToArray());
288                 }
289
290                 internal static void Skip(ByteReader br)
291                 {
292                         byte b = br.PeekByte();
293                         while (IsCustomModifier(b))
294                         {
295                                 br.ReadByte();
296                                 br.ReadCompressedInt();
297                                 b = br.PeekByte();
298                         }
299                 }
300
301                 internal static CustomModifiers FromReqOpt(Type[] req, Type[] opt)
302                 {
303                         List<Type> list = null;
304                         if (opt != null && opt.Length != 0)
305                         {
306                                 Debug.Assert(Initial == MarkerType.ModOpt);
307                                 list = new List<Type>(opt);
308                         }
309                         if (req != null && req.Length != 0)
310                         {
311                                 if (list == null)
312                                 {
313                                         list = new List<Type>();
314                                 }
315                                 list.Add(MarkerType.ModReq);
316                                 list.AddRange(req);
317                         }
318                         if (list == null)
319                         {
320                                 return new CustomModifiers();
321                         }
322                         else
323                         {
324                                 return new CustomModifiers(list.ToArray());
325                         }
326                 }
327
328                 private static bool IsCustomModifier(byte b)
329                 {
330                         return b == Signature.ELEMENT_TYPE_CMOD_OPT || b == Signature.ELEMENT_TYPE_CMOD_REQD;
331                 }
332
333                 internal static CustomModifiers Combine(CustomModifiers mods1, CustomModifiers mods2)
334                 {
335                         if (mods1.IsEmpty)
336                         {
337                                 return mods2;
338                         }
339                         else if (mods2.IsEmpty)
340                         {
341                                 return mods1;
342                         }
343                         else
344                         {
345                                 Type[] combo = new Type[mods1.types.Length + mods2.types.Length];
346                                 Array.Copy(mods1.types, combo, mods1.types.Length);
347                                 Array.Copy(mods2.types, 0, combo, mods1.types.Length, mods2.types.Length);
348                                 return new CustomModifiers(combo);
349                         }
350                 }
351         }
352 }