3a8086096b7c5f364e6e1f04b8bc3a0af25f9f68
[platform/upstream/dotnet/runtime.git] /
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 //
6
7 using System;
8 using System.Security;
9 using System.Collections;
10 using System.Collections.Generic;
11 using System.Diagnostics;
12 using System.Runtime.InteropServices;
13 using System.Runtime.CompilerServices;
14 using Internal.Runtime.CompilerServices;
15
16 namespace System.Runtime.InteropServices.WindowsRuntime
17 {
18     // This is a set of stub methods implementing the support for the IReadOnlyDictionary`2 interface on WinRT
19     // objects that support IMapView`2. Used by the interop mashaling infrastructure.
20     //
21     // The methods on this class must be written VERY carefully to avoid introducing security holes.
22     // That's because they are invoked with special "this"! The "this" object
23     // for all of these methods are not IMapViewToIReadOnlyDictionaryAdapter objects. Rather, they are of type
24     // IMapView<K, V>. No actual IMapViewToIReadOnlyDictionaryAdapter object is ever instantiated. Thus, you will see
25     // a lot of expressions that cast "this" to "IMapView<K, V>".
26     [DebuggerDisplay("Count = {Count}")]
27     internal sealed class IMapViewToIReadOnlyDictionaryAdapter
28     {
29         private IMapViewToIReadOnlyDictionaryAdapter()
30         {
31             Debug.Fail("This class is never instantiated");
32         }
33
34         // V this[K key] { get }
35         internal V Indexer_Get<K, V>(K key)
36         {
37             if (key == null)
38                 throw new ArgumentNullException(nameof(key));
39
40             IMapView<K, V> _this = Unsafe.As<IMapView<K, V>>(this);
41             return Lookup(_this, key);
42         }
43
44         // IEnumerable<K> Keys { get }
45         internal IEnumerable<K> Keys<K, V>()
46         {
47             IMapView<K, V> _this = Unsafe.As<IMapView<K, V>>(this);
48             IReadOnlyDictionary<K, V> roDictionary = (IReadOnlyDictionary<K, V>)_this;
49             return new ReadOnlyDictionaryKeyCollection<K, V>(roDictionary);
50         }
51
52         // IEnumerable<V> Values { get }
53         internal IEnumerable<V> Values<K, V>()
54         {
55             IMapView<K, V> _this = Unsafe.As<IMapView<K, V>>(this);
56             IReadOnlyDictionary<K, V> roDictionary = (IReadOnlyDictionary<K, V>)_this;
57             return new ReadOnlyDictionaryValueCollection<K, V>(roDictionary);
58         }
59
60         // bool ContainsKey(K key)
61         internal bool ContainsKey<K, V>(K key)
62         {
63             if (key == null)
64                 throw new ArgumentNullException(nameof(key));
65
66             IMapView<K, V> _this = Unsafe.As<IMapView<K, V>>(this);
67             return _this.HasKey(key);
68         }
69
70         // bool TryGetValue(TKey key, out TValue value)
71         internal bool TryGetValue<K, V>(K key, out V value)
72         {
73             if (key == null)
74                 throw new ArgumentNullException(nameof(key));
75
76             IMapView<K, V> _this = Unsafe.As<IMapView<K, V>>(this);
77
78             // It may be faster to call HasKey then Lookup.  On failure, we would otherwise
79             // throw an exception from Lookup.
80             if (!_this.HasKey(key))
81             {
82                 value = default;
83                 return false;
84             }
85
86             try
87             {
88                 value = _this.Lookup(key);
89                 return true;
90             }
91             catch (Exception ex)  // Still may hit this case due to a race condition
92             {
93                 if (HResults.E_BOUNDS == ex.HResult)
94                 {
95                     value = default;
96                     return false;
97                 }
98                 throw;
99             }
100         }
101
102         #region Helpers
103
104         private static V Lookup<K, V>(IMapView<K, V> _this, K key)
105         {
106             Debug.Assert(null != key);
107
108             try
109             {
110                 return _this.Lookup(key);
111             }
112             catch (Exception ex)
113             {
114                 if (HResults.E_BOUNDS == ex.HResult)
115                     throw new KeyNotFoundException(SR.Format(SR.Arg_KeyNotFoundWithKey, key.ToString()));
116                 throw;
117             }
118         }
119
120         #endregion Helpers
121     }
122
123     // Note: One day we may make these return IReadOnlyCollection<T>
124     [DebuggerDisplay("Count = {Count}")]
125     internal sealed class ReadOnlyDictionaryKeyCollection<TKey, TValue> : IEnumerable<TKey>
126     {
127         private readonly IReadOnlyDictionary<TKey, TValue> dictionary;
128
129         public ReadOnlyDictionaryKeyCollection(IReadOnlyDictionary<TKey, TValue> dictionary)
130         {
131             if (dictionary == null)
132                 throw new ArgumentNullException(nameof(dictionary));
133
134             this.dictionary = dictionary;
135         }
136
137         /*
138         public void CopyTo(TKey[] array, int index)
139         {
140             if (array == null)
141                 throw new ArgumentNullException(nameof(array));
142             if (index < 0)
143                 throw new ArgumentOutOfRangeException(nameof(index));
144             if (array.Length <= index && this.Count > 0)
145                 throw new ArgumentException(SR.Arg_IndexOutOfRangeException);
146             if (array.Length - index < dictionary.Count)
147                 throw new ArgumentException(SR.Argument_InsufficientSpaceToCopyCollection);
148
149             int i = index;
150             foreach (KeyValuePair<TKey, TValue> mapping in dictionary)
151             {
152                 array[i++] = mapping.Key;
153             }
154         }
155         
156         public int Count {
157             get { return dictionary.Count; }
158         }
159
160         public bool Contains(TKey item)
161         {
162             return dictionary.ContainsKey(item);
163         }
164         */
165
166         IEnumerator IEnumerable.GetEnumerator()
167         {
168             return ((IEnumerable<TKey>)this).GetEnumerator();
169         }
170
171         public IEnumerator<TKey> GetEnumerator()
172         {
173             return new ReadOnlyDictionaryKeyEnumerator<TKey, TValue>(dictionary);
174         }
175     }  // public class ReadOnlyDictionaryKeyCollection<TKey, TValue>
176
177
178     internal sealed class ReadOnlyDictionaryKeyEnumerator<TKey, TValue> : IEnumerator<TKey>
179     {
180         private readonly IReadOnlyDictionary<TKey, TValue> dictionary;
181         private IEnumerator<KeyValuePair<TKey, TValue>> enumeration;
182
183         public ReadOnlyDictionaryKeyEnumerator(IReadOnlyDictionary<TKey, TValue> dictionary)
184         {
185             if (dictionary == null)
186                 throw new ArgumentNullException(nameof(dictionary));
187
188             this.dictionary = dictionary;
189             enumeration = dictionary.GetEnumerator();
190         }
191
192         void IDisposable.Dispose()
193         {
194             enumeration.Dispose();
195         }
196
197         public bool MoveNext()
198         {
199             return enumeration.MoveNext();
200         }
201
202         object IEnumerator.Current
203         {
204             get { return ((IEnumerator<TKey>)this).Current; }
205         }
206
207         public TKey Current
208         {
209             get { return enumeration.Current.Key; }
210         }
211
212         public void Reset()
213         {
214             enumeration = dictionary.GetEnumerator();
215         }
216     }  // class ReadOnlyDictionaryKeyEnumerator<TKey, TValue>
217
218
219     [DebuggerDisplay("Count = {Count}")]
220     internal sealed class ReadOnlyDictionaryValueCollection<TKey, TValue> : IEnumerable<TValue>
221     {
222         private readonly IReadOnlyDictionary<TKey, TValue> dictionary;
223
224         public ReadOnlyDictionaryValueCollection(IReadOnlyDictionary<TKey, TValue> dictionary)
225         {
226             if (dictionary == null)
227                 throw new ArgumentNullException(nameof(dictionary));
228
229             this.dictionary = dictionary;
230         }
231
232         /*
233         public void CopyTo(TValue[] array, int index)
234         {
235             if (array == null)
236                 throw new ArgumentNullException(nameof(array));
237             if (index < 0)
238                 throw new ArgumentOutOfRangeException(nameof(index));
239             if (array.Length <= index && this.Count > 0)
240                 throw new ArgumentException(SR.Arg_IndexOutOfRangeException);
241             if (array.Length - index < dictionary.Count)
242                 throw new ArgumentException(SR.Argument_InsufficientSpaceToCopyCollection);
243
244             int i = index;
245             foreach (KeyValuePair<TKey, TValue> mapping in dictionary)
246             {
247                 array[i++] = mapping.Value;
248             }
249         }
250
251         public int Count {
252             get { return dictionary.Count; }
253         }
254
255         public bool Contains(TValue item)
256         {
257             EqualityComparer<TValue> comparer = EqualityComparer<TValue>.Default;
258             foreach (TValue value in this)
259                 if (comparer.Equals(item, value))
260                     return true;
261             return false;
262         }
263         */
264
265         IEnumerator IEnumerable.GetEnumerator()
266         {
267             return ((IEnumerable<TValue>)this).GetEnumerator();
268         }
269
270         public IEnumerator<TValue> GetEnumerator()
271         {
272             return new ReadOnlyDictionaryValueEnumerator<TKey, TValue>(dictionary);
273         }
274     }  // public class ReadOnlyDictionaryValueCollection<TKey, TValue>
275
276
277     internal sealed class ReadOnlyDictionaryValueEnumerator<TKey, TValue> : IEnumerator<TValue>
278     {
279         private readonly IReadOnlyDictionary<TKey, TValue> dictionary;
280         private IEnumerator<KeyValuePair<TKey, TValue>> enumeration;
281
282         public ReadOnlyDictionaryValueEnumerator(IReadOnlyDictionary<TKey, TValue> dictionary)
283         {
284             if (dictionary == null)
285                 throw new ArgumentNullException(nameof(dictionary));
286
287             this.dictionary = dictionary;
288             enumeration = dictionary.GetEnumerator();
289         }
290
291         void IDisposable.Dispose()
292         {
293             enumeration.Dispose();
294         }
295
296         public bool MoveNext()
297         {
298             return enumeration.MoveNext();
299         }
300
301         object IEnumerator.Current
302         {
303             get { return ((IEnumerator<TValue>)this).Current; }
304         }
305
306         public TValue Current
307         {
308             get { return enumeration.Current.Value; }
309         }
310
311         public void Reset()
312         {
313             enumeration = dictionary.GetEnumerator();
314         }
315     }  // class ReadOnlyDictionaryValueEnumerator<TKey, TValue>
316 }