IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
CustomModifiers.cs
Go to the documentation of this file.
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*/
24using System;
25using System.Collections.Generic;
26using System.Diagnostics;
27using System.Text;
28
31
32namespace IKVM.Reflection
33{
34
35 internal readonly struct CustomModifiers : IEquatable<CustomModifiers>, IEnumerable<CustomModifiers.Entry>
36 {
37
38 public readonly record struct Entry(Type Type, bool IsRequired);
39
40 public struct Enumerator : IEnumerator<Entry>
41 {
42
43 readonly Type[] types;
44 int index;
46
51 internal Enumerator(Type[] types)
52 {
53 this.types = types;
54 this.index = -1;
55 this.required = Initial == MarkerType.ModReq;
56 }
57
58 void System.Collections.IEnumerator.Reset()
59 {
60 this.index = -1;
61 this.required = Initial == MarkerType.ModReq;
62 }
63
64 public Entry Current => new Entry(types[index], required);
65
66 public bool MoveNext()
67 {
68 if (types == null || index == types.Length)
69 return false;
70
71 index++;
72
73 if (index == types.Length)
74 {
75 return false;
76 }
77 else if (types[index] == MarkerType.ModOpt)
78 {
79 required = false;
80 index++;
81 }
82 else if (types[index] == MarkerType.ModReq)
83 {
84 required = true;
85 index++;
86 }
87
88 return true;
89 }
90
91 object System.Collections.IEnumerator.Current => Current;
92
93 void IDisposable.Dispose()
94 {
95
96 }
97
98 }
99
100 static Type Initial => MarkerType.ModOpt; // note that FromReqOpt assumes that Initial == ModOpt
101
102 readonly Type[] types;
103
108 internal CustomModifiers(List<CustomModifiersBuilder.Item> list)
109 {
110 var required = Initial == MarkerType.ModReq;
111
112 var count = list.Count;
113 foreach (var item in list)
114 {
115 if (item.required != required)
116 {
117 required = item.required;
118 count++;
119 }
120 }
121
122 types = new Type[count];
123 required = Initial == MarkerType.ModReq;
124 int index = 0;
125 foreach (var item in list)
126 {
127 if (item.required != required)
128 {
129 required = item.required;
130 types[index++] = required ? MarkerType.ModReq : MarkerType.ModOpt;
131 }
132
133 types[index++] = item.type;
134 }
135 }
136
141 CustomModifiers(Type[] types)
142 {
143 Debug.Assert(types == null || types.Length != 0);
144 this.types = types;
145 }
146
147 public Enumerator GetEnumerator()
148 {
149 return new Enumerator(types);
150 }
151
152 IEnumerator<Entry> IEnumerable<Entry>.GetEnumerator()
153 {
154 return GetEnumerator();
155 }
156
157 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
158 {
159 return GetEnumerator();
160 }
161
162 public bool IsEmpty
163 {
164 get { return types == null; }
165 }
166
167 public bool Equals(CustomModifiers other)
168 {
169 return Util.ArrayEquals(types, other.types);
170 }
171
172 public override bool Equals(object obj)
173 {
174 var other = obj as CustomModifiers?;
175 return other != null && Equals(other.Value);
176 }
177
178 public override int GetHashCode()
179 {
180 return Util.GetHashCode(types);
181 }
182
183 public override string ToString()
184 {
185 if (types == null)
186 return string.Empty;
187
188 var sb = new StringBuilder();
189 var sep = "";
190 foreach (var e in this)
191 {
192 sb.Append(sep).Append(e.IsRequired ? "modreq(" : "modopt(").Append(e.Type.FullName).Append(')');
193 sep = " ";
194 }
195
196 return sb.ToString();
197 }
198
199 public bool ContainsMissingType
200 {
201 get { return Type.ContainsMissingType(types); }
202 }
203
204 Type[] GetRequiredOrOptional(bool required)
205 {
206 if (types == null)
207 return Type.EmptyTypes;
208
209 int count = 0;
210 foreach (var e in this)
211 if (e.IsRequired == required)
212 count++;
213
214 var result = new Type[count];
215 foreach (var e in this)
216 if (e.IsRequired == required)
217 result[--count] = e.Type; // FXBUG reflection (and ildasm) return custom modifiers in reverse order while SRE writes them in the specified order
218
219 return result;
220 }
221
222 internal Type[] GetRequired()
223 {
224 return GetRequiredOrOptional(true);
225 }
226
227 internal Type[] GetOptional()
228 {
229 return GetRequiredOrOptional(false);
230 }
231
232 internal CustomModifiers Bind(IGenericBinder binder)
233 {
234 if (types == null)
235 return this;
236
237 var result = types;
238 for (var i = 0; i < types.Length; i++)
239 {
240 if (types[i] == MarkerType.ModOpt || types[i] == MarkerType.ModReq)
241 continue;
242
243 var type = types[i].BindTypeParameters(binder);
244 if (!ReferenceEquals(type, types[i]))
245 {
246 if (result == types)
247 result = (Type[])types.Clone();
248
249 result[i] = type;
250 }
251 }
252
253 return new CustomModifiers(result);
254 }
255
256 internal static CustomModifiers Read(ModuleReader module, ByteReader br, IGenericContext context)
257 {
258 var b = br.PeekByte();
259 if (!IsCustomModifier(b))
260 return new CustomModifiers();
261
262 var list = new List<Type>();
263 var mode = Initial;
264 do
265 {
266 var cmod = br.ReadByte() == Signature.ELEMENT_TYPE_CMOD_REQD ? MarkerType.ModReq : MarkerType.ModOpt;
267 if (mode != cmod)
268 {
269 mode = cmod;
270 list.Add(mode);
271 }
272
273 list.Add(Signature.ReadTypeDefOrRefEncoded(module, br, context));
274 b = br.PeekByte();
275 }
276 while (IsCustomModifier(b));
277
278 return new CustomModifiers(list.ToArray());
279 }
280
281 internal static void Skip(ByteReader br)
282 {
283 var b = br.PeekByte();
284 while (IsCustomModifier(b))
285 {
286 br.ReadByte();
287 br.ReadCompressedUInt();
288 b = br.PeekByte();
289 }
290 }
291
292 internal static CustomModifiers FromReqOpt(Type[] req, Type[] opt)
293 {
294 List<Type> list = null;
295
296 if (opt != null && opt.Length != 0)
297 {
298 Debug.Assert(Initial == MarkerType.ModOpt);
299 list = new List<Type>(opt);
300 }
301
302 if (req != null && req.Length != 0)
303 {
304 list ??= new List<Type>();
305 list.Add(MarkerType.ModReq);
306 list.AddRange(req);
307 }
308
309 if (list == null)
310 return new CustomModifiers();
311 else
312 return new CustomModifiers(list.ToArray());
313 }
314
315 static bool IsCustomModifier(byte b)
316 {
317 return b == Signature.ELEMENT_TYPE_CMOD_OPT || b == Signature.ELEMENT_TYPE_CMOD_REQD;
318 }
319
320 internal static CustomModifiers Combine(CustomModifiers mods1, CustomModifiers mods2)
321 {
322 if (mods1.IsEmpty)
323 {
324 return mods2;
325 }
326 else if (mods2.IsEmpty)
327 {
328 return mods1;
329 }
330 else
331 {
332 var combo = new Type[mods1.types.Length + mods2.types.Length];
333 Array.Copy(mods1.types, combo, mods1.types.Length);
334 Array.Copy(mods2.types, 0, combo, mods1.types.Length, mods2.types.Length);
335 return new CustomModifiers(combo);
336 }
337 }
338
339 }
340
341}
IKVM.Reflection.Type Type
object System.Collections.IEnumerator. Current