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.
6 using System.Collections.Generic;
7 using System.Diagnostics;
8 using Internal.Runtime.CompilerServices;
10 namespace System.Runtime.InteropServices.WindowsRuntime
12 // This is a set of stub methods implementing the support for the IVectorView`1 interface on managed
13 // objects that implement IReadOnlyList`1. Used by the interop mashaling infrastructure.
15 // The methods on this class must be written VERY carefully to avoid introducing security holes.
16 // That's because they are invoked with special "this"! The "this" object
17 // for all of these methods are not IReadOnlyListToIVectorViewAdapter objects. Rather, they are of type
18 // IReadOnlyList<T>. No actual IReadOnlyListToIVectorViewAdapter object is ever instantiated. Thus, you will
19 // see a lot of expressions that cast "this" to "IReadOnlyList<T>".
20 [DebuggerDisplay("Size = {Size}")]
21 internal sealed class IReadOnlyListToIVectorViewAdapter
23 private IReadOnlyListToIVectorViewAdapter()
25 Debug.Fail("This class is never instantiated");
28 // T GetAt(uint index)
29 internal T GetAt<T>(uint index)
31 IReadOnlyList<T> _this = Unsafe.As<IReadOnlyList<T>>(this);
32 EnsureIndexInt32(index, _this.Count);
36 return _this[(int)index];
38 catch (ArgumentOutOfRangeException ex)
40 ex.HResult = HResults.E_BOUNDS;
46 internal uint Size<T>()
48 IReadOnlyList<T> _this = Unsafe.As<IReadOnlyList<T>>(this);
49 return (uint)_this.Count;
52 // bool IndexOf(T value, out uint index)
53 internal bool IndexOf<T>(T value, out uint index)
55 IReadOnlyList<T> _this = Unsafe.As<IReadOnlyList<T>>(this);
58 int max = _this.Count;
59 for (int i = 0; i < max; i++)
61 if (EqualityComparer<T>.Default.Equals(value, _this[i]))
78 // uint GetMany(uint startIndex, T[] items)
79 internal uint GetMany<T>(uint startIndex, T[] items)
81 IReadOnlyList<T> _this = Unsafe.As<IReadOnlyList<T>>(this);
83 // REX spec says "calling GetMany with startIndex equal to the length of the vector
84 // (last valid index + 1) and any specified capacity will succeed and return zero actual
86 if (startIndex == _this.Count)
89 EnsureIndexInt32(startIndex, _this.Count);
96 uint itemCount = Math.Min((uint)items.Length, (uint)_this.Count - startIndex);
98 for (uint i = 0; i < itemCount; ++i)
100 items[i] = _this[(int)(i + startIndex)];
103 if (typeof(T) == typeof(string))
105 string[] stringItems = (items as string[])!;
107 // Fill in the rest of the array with string.Empty to avoid marshaling failure
108 for (uint i = itemCount; i < items.Length; ++i)
109 stringItems[i] = string.Empty;
117 private static void EnsureIndexInt32(uint index, int listCapacity)
119 // We use '<=' and not '<' because int.MaxValue == index would imply
120 // that Size > int.MaxValue:
121 if (((uint)int.MaxValue) <= index || index >= (uint)listCapacity)
123 Exception e = new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_IndexLargerThanMaxValue);
124 e.HResult = HResults.E_BOUNDS;