Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / mscorlib / system / security / util / tokenbasedset.cs
blobcbbb43c63984baa65507769a7b8b389b8e84536a
1 // ==++==
2 //
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 //
5 // ==--==
6 // <OWNER>Microsoft</OWNER>
7 //
9 //
10 // TokenBasedSet.cs
13 namespace System.Security.Util
15 using System;
16 using System.Collections;
17 using System.Security.Permissions;
18 using System.Runtime.Serialization;
19 using System.Threading;
20 using System.Diagnostics.Contracts;
21 using System.Diagnostics.CodeAnalysis;
23 [Serializable]
24 internal class TokenBasedSet
28 // Following 3 fields are used only for serialization compat purposes: DO NOT USE THESE EVER!
29 #pragma warning disable 414
30 private int m_initSize = 24;
31 private int m_increment = 8;
32 #pragma warning restore 414
33 private Object[] m_objSet;
34 // END -> Serialization only fields
36 [OptionalField(VersionAdded = 2)]
37 private volatile Object m_Obj;
38 [OptionalField(VersionAdded = 2)]
39 private volatile Object[] m_Set;
41 private int m_cElt;
42 private volatile int m_maxIndex;
45 [OnDeserialized]
46 private void OnDeserialized(StreamingContext ctx)
48 OnDeserializedInternal();
50 private void OnDeserializedInternal()
52 if (m_objSet != null) //v1.x case
54 if (m_cElt == 1)
55 m_Obj = m_objSet[m_maxIndex];
56 else
57 m_Set = m_objSet;
58 m_objSet = null;
60 // Nothing to do for the v2.0 and beyond case
63 [OnSerializing]
64 private void OnSerializing(StreamingContext ctx)
67 if ((ctx.State & ~(StreamingContextStates.Clone|StreamingContextStates.CrossAppDomain)) != 0)
69 //Nothing special for the v2 and beyond case
71 // for the v1.x case, we need to create m_objSet if necessary
72 if (m_cElt == 1)
74 m_objSet = new Object[m_maxIndex+1];
75 m_objSet[m_maxIndex] = m_Obj;
77 else if (m_cElt > 0)
79 // Array case:
80 m_objSet = m_Set;
85 [OnSerialized]
86 private void OnSerialized(StreamingContext ctx)
88 if ((ctx.State & ~(StreamingContextStates.Clone|StreamingContextStates.CrossAppDomain)) != 0)
90 m_objSet = null;
96 internal bool MoveNext(ref TokenBasedSetEnumerator e)
98 switch (m_cElt)
100 case 0:
101 return false;
103 case 1:
104 if (e.Index == -1)
106 e.Index = m_maxIndex;
107 e.Current = m_Obj;
108 return true;
110 else
112 e.Index = (short)(m_maxIndex+1);
113 e.Current = null;
114 return false;
117 default:
118 while (++e.Index <= m_maxIndex)
120 e.Current = Volatile.Read(ref m_Set[e.Index]);
122 if (e.Current != null)
123 return true;
126 e.Current = null;
127 return false;
131 internal TokenBasedSet()
133 Reset();
136 [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "Reviewed for thread safety")]
137 internal TokenBasedSet(TokenBasedSet tbSet)
139 if (tbSet == null)
141 Reset();
142 return;
145 if (tbSet.m_cElt > 1)
147 Object[] aObj = tbSet.m_Set;
148 int aLen = aObj.Length;
150 Object[] aNew = new Object[aLen];
151 System.Array.Copy(aObj, 0, aNew, 0, aLen);
153 m_Set = aNew;
155 else
157 m_Obj = tbSet.m_Obj;
160 m_cElt = tbSet.m_cElt;
161 m_maxIndex = tbSet.m_maxIndex;
164 internal void Reset()
166 m_Obj = null;
167 m_Set = null;
168 m_cElt = 0;
169 m_maxIndex = -1;
172 internal void SetItem(int index, Object item)
174 Object[] aObj = null;
176 if (item == null)
178 RemoveItem(index);
179 return;
182 switch (m_cElt)
184 case 0:
185 // on the first item, we don't create an array, we merely remember it's index and value
186 // this this the 99% case
187 m_cElt = 1;
188 m_maxIndex = (short)index;
189 m_Obj = item;
190 break;
192 case 1:
193 // we have to decide if a 2nd item has indeed been added and create the array
194 // if it has
195 if (index == m_maxIndex)
197 // replacing the one existing item
198 m_Obj = item;
200 else
202 // adding a second distinct permission
203 Object objSaved = m_Obj;
204 int iMax = Math.Max(m_maxIndex, index);
206 aObj = new Object[iMax+1];
207 aObj[m_maxIndex] = objSaved;
208 aObj[index] = item;
209 m_maxIndex = (short)iMax;
210 m_cElt = 2;
211 m_Set = aObj;
212 m_Obj = null;
214 break;
216 default:
217 // this is the general case code for when there is really an array
219 aObj = m_Set;
221 // we are now adding an item, check if we need to grow
223 if (index >= aObj.Length)
225 Object[] newset = new Object[index+1];
226 System.Array.Copy(aObj, 0, newset, 0, m_maxIndex+1);
227 m_maxIndex = (short)index;
228 newset[index] = item;
229 m_Set = newset;
230 m_cElt++;
232 else
234 if (aObj[index] == null)
235 m_cElt++;
237 aObj[index] = item;
239 if (index > m_maxIndex)
240 m_maxIndex = (short)index;
242 break;
246 [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "Reviewed for thread-safety")]
247 internal Object GetItem(int index)
249 switch (m_cElt)
251 case 0:
252 return null;
254 case 1:
255 if (index == m_maxIndex)
256 return m_Obj;
257 else
258 return null;
259 default:
260 if (index < m_Set.Length)
261 return Volatile.Read(ref m_Set[index]);
262 else
263 return null;
267 internal Object RemoveItem(int index)
269 Object ret = null;
271 switch (m_cElt)
273 case 0:
274 ret = null;
275 break;
277 case 1:
278 if (index != m_maxIndex)
280 // removing a permission we don't have ignore it
281 ret = null;
283 else
285 // removing the permission we have at the moment
286 ret = m_Obj;
287 Reset();
289 break;
291 default:
292 // this is the general case code for when there is really an array
294 // we are removing an item
295 if (index < m_Set.Length && (ret = Volatile.Read(ref m_Set[index])) != null)
297 // ok we really deleted something at this point
299 Volatile.Write(ref m_Set[index], null);
300 m_cElt--;
302 if (index == m_maxIndex)
303 ResetMaxIndex(m_Set);
305 // collapse the array
306 if (m_cElt == 1)
308 m_Obj = Volatile.Read(ref m_Set[m_maxIndex]);
309 m_Set = null;
312 break;
315 return ret;
318 private void ResetMaxIndex(Object[] aObj)
320 int i;
322 // Start at the end of the array, and
323 // scan backwards for the first non-null
324 // slot. That is the new maxIndex.
325 for (i = aObj.Length - 1; i >= 0; i--)
327 if (aObj[i] != null)
329 m_maxIndex = (short)i;
330 return;
334 m_maxIndex = -1;
336 internal int GetStartingIndex()
338 if (m_cElt <= 1)
339 return m_maxIndex;
340 return 0;
342 internal int GetCount()
344 return m_cElt;
347 internal int GetMaxUsedIndex()
349 return m_maxIndex;
352 internal bool FastIsEmpty()
354 return m_cElt == 0;
357 // Used to merge two distinct TokenBasedSets (used currently only in PermissionSet Deserialization)
358 internal TokenBasedSet SpecialUnion(TokenBasedSet other)
360 // This gets called from PermissionSet.OnDeserialized and it's possible that the TokenBasedSets have
361 // not been subjected to VTS callbacks yet
362 OnDeserializedInternal();
363 TokenBasedSet unionSet = new TokenBasedSet();
364 int maxMax;
365 if (other != null)
367 other.OnDeserializedInternal();
368 maxMax = this.GetMaxUsedIndex() > other.GetMaxUsedIndex() ? this.GetMaxUsedIndex() : other.GetMaxUsedIndex();
370 else
371 maxMax = this.GetMaxUsedIndex();
373 for (int i = 0; i <= maxMax; ++i)
375 Object thisObj = this.GetItem( i );
376 IPermission thisPerm = thisObj as IPermission;
377 #if FEATURE_CAS_POLICY
378 ISecurityElementFactory thisElem = thisObj as ISecurityElementFactory;
379 #endif // FEATURE_CAS_POLICY
381 Object otherObj = (other != null)?other.GetItem( i ):null;
382 IPermission otherPerm = otherObj as IPermission;
383 #if FEATURE_CAS_POLICY
384 ISecurityElementFactory otherElem = otherObj as ISecurityElementFactory;
385 #endif // FEATURE_CAS_POLICY
387 if (thisObj == null && otherObj == null)
388 continue;
391 if (thisObj == null)
393 #if FEATURE_CAS_POLICY
394 if (otherElem != null)
396 otherPerm = PermissionSet.CreatePerm(otherElem, false);
398 #endif // FEATURE_CAS_POLICY
400 PermissionToken token = PermissionToken.GetToken(otherPerm);
402 if (token == null)
404 throw new SerializationException(Environment.GetResourceString("Serialization_InsufficientState"));
407 unionSet.SetItem(token.m_index, otherPerm);
409 else if (otherObj == null)
411 #if FEATURE_CAS_POLICY
412 if (thisElem != null)
414 thisPerm = PermissionSet.CreatePerm(thisElem, false);
416 #endif // FEATURE_CAS_POLICY
418 PermissionToken token = PermissionToken.GetToken(thisPerm);
419 if (token == null)
421 throw new SerializationException(Environment.GetResourceString("Serialization_InsufficientState"));
423 unionSet.SetItem( token.m_index, thisPerm);
425 else
427 Contract.Assert( (thisObj == null || otherObj == null), "Permission cannot be in both TokenBasedSets" );
430 return unionSet;
433 internal void SpecialSplit(ref TokenBasedSet unrestrictedPermSet, ref TokenBasedSet normalPermSet, bool ignoreTypeLoadFailures)
435 int maxIndex = GetMaxUsedIndex();
437 for (int i = GetStartingIndex(); i <= maxIndex; ++i)
439 Object obj = GetItem( i );
440 if (obj != null)
442 IPermission perm = obj as IPermission;
443 #if FEATURE_CAS_POLICY
444 if (perm == null)
445 perm = PermissionSet.CreatePerm(obj, ignoreTypeLoadFailures);
446 #endif // FEATURE_CAS_POLICY
447 PermissionToken token = PermissionToken.GetToken(perm);
449 if (perm == null || token == null)
450 continue;
452 if (perm is IUnrestrictedPermission)
454 // Add to unrestrictedPermSet
455 if (unrestrictedPermSet == null)
456 unrestrictedPermSet = new TokenBasedSet();
457 unrestrictedPermSet.SetItem(token.m_index, perm);
459 else
461 // Add to normalPermSet
462 if (normalPermSet == null)
463 normalPermSet = new TokenBasedSet();
464 normalPermSet.SetItem(token.m_index, perm);