Skip to content

Commit

Permalink
Remove idic usage from manual projections (#1068)
Browse files Browse the repository at this point in the history
Remove IDIC usage from manual projections
  • Loading branch information
ujjwalchadha authored Jan 19, 2022
1 parent 14d7c3a commit e78db0e
Show file tree
Hide file tree
Showing 14 changed files with 2,196 additions and 964 deletions.
15 changes: 15 additions & 0 deletions src/Benchmarks/ReflectionPerf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,5 +121,20 @@ public object ExistingDictionaryLookup3()
var dict = instance.ExistingDictionary;
return dict["a"];
}

[Benchmark]
public string CreateAndIterateList()
{
var list = instance.NewList();
list.Add("How");
list.Add("Are");
list.Add("You");
var sentence = "";
for (int i = 0; i < list.Count; i++)
{
sentence += list[i];
}
return sentence;
}
}
}
3 changes: 3 additions & 0 deletions src/Tests/UnitTest/TestComponentCSharp_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,9 @@ public void TestStringMap()
{
Assert.Equal(stringMap[item.Key], item.Value);
}
KeyValuePair<string, string>[] pairs = new KeyValuePair<string, string>[2];
stringMap.CopyTo(pairs, 0);
Assert.Equal(2, pairs.Length);
}

[Fact]
Expand Down
121 changes: 114 additions & 7 deletions src/Tests/UnitTest/TestComponent_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,34 @@ public void Collections_Dictionary()
IDictionary<string, string> b = null;
var c = Tests.Collection3(a, out b);
Assert.True(SequencesEqual(a, b, c));
RunDictionaryTests(c);
}

#if NET
[Fact]
public void Collections_Dictionary_IDIC()
{
var a = new Dictionary<string, string>()
{
["apples"] = "1",
["oranges"] = "2",
["pears"] = "3"
};
var c = Tests.Collection3(a, out _);
var inspectable = new IInspectable(((IWinRTObject)c).NativeObject);
var dictCreatedWithIDIC = (IDictionary<string, string>)inspectable;
RunDictionaryTests(dictCreatedWithIDIC);
}
#endif
private void RunDictionaryTests(IDictionary<string, string> c)
{
Assert.True(SequencesEqual(c.Keys, new List<string> { "apples", "oranges", "pears" }));
Assert.True(SequencesEqual(c.Values, new List<string> { "1", "2", "3" }));
Assert.True(SequencesEqual(c, new List<KeyValuePair<string, string>> {
new KeyValuePair<string, string>("apples", "1"),
new KeyValuePair<string, string>("oranges", "2"),
new KeyValuePair<string, string>("pears", "3")
}));

c["bananas"] = "4";
Assert.Equal("4", c["bananas"]);
Expand All @@ -623,8 +651,12 @@ public void Collections_Dictionary()
Assert.Equal(4, c.Keys.Count());
Assert.Equal(4, c.Values.Count());

c.Remove(new KeyValuePair<string, string>("apples", "1"));
Assert.ThrowsAny<Exception>(() => c["apples"]);

c.Clear();
Assert.Empty(c);

}

[Fact]
Expand All @@ -639,9 +671,39 @@ public void Collections_ReadOnly_Dictionary()
IReadOnlyDictionary<string, string> b = null;
var c = Tests.Collection4(a, out b);
Assert.True(SequencesEqual(a, b, c));
RunReadOnlyDictionaryTests(c);
}

#if NET
[Fact]
public void Collections_ReadOnly_Dictionary_IDIC()
{
var a = new Dictionary<string, string>()
{
["apples"] = "1",
["oranges"] = "2",
["pears"] = "3"
};
IReadOnlyDictionary<string, string> b = null;
var c = Tests.Collection4(a, out b);
var inspectable = new IInspectable(((IWinRTObject)c).NativeObject);
var dictCreatedWithIDIC = (IReadOnlyDictionary<string, string>)inspectable;
RunReadOnlyDictionaryTests(dictCreatedWithIDIC);
}
#endif

private void RunReadOnlyDictionaryTests(IReadOnlyDictionary<string, string> c)
{
Assert.True(SequencesEqual(c.Keys, new List<string> { "apples", "oranges", "pears" }));
Assert.True(SequencesEqual(c.Values, new List<string> { "1", "2", "3" }));
Assert.True(SequencesEqual(c, new List<KeyValuePair<string, string>> {
new KeyValuePair<string, string>("apples", "1"),
new KeyValuePair<string, string>("oranges", "2"),
new KeyValuePair<string, string>("pears", "3")
}));

Assert.Equal("2", c["oranges"]);
Assert.Equal(3, c.Count());
Assert.Equal(3, c.Count);
Assert.True(c.ContainsKey("pears"));
Assert.Equal(3, c.Values.Count());
Assert.Equal(3, c.Keys.Count());
Expand All @@ -654,26 +716,53 @@ public void Collections_List()
IList<string> b = null;
var c = Tests.Collection5(a, out b);
Assert.True(SequencesEqual(a, b, c));
RunListTests(c);
}

#if NET
[Fact]
public void Collections_List_IDIC()
{
string[] a = new string[] { "apples", "oranges", "pears" };
IList<string> b = null;
var c = Tests.Collection5(a, out b);
Assert.True(SequencesEqual(a, b, c));
var inspectable = new IInspectable(((IWinRTObject)c).NativeObject);
var listCreatedWithIDIC = (IList<string>)inspectable;
RunListTests(listCreatedWithIDIC);
}
#endif

private void RunListTests(IList<string> c)
{
Assert.Equal(3, c.Count);
Assert.Equal(1, c.IndexOf("oranges"));
Assert.NotNull(c.AsAgile());

Assert.False(c.IsReadOnly);

c.Add("bananas");

c[3] = "strawberries";
Assert.Equal("strawberries", c[3]);
Assert.False(c.Contains("bananas"));

c.Insert(3, "kiwis");
Assert.True(c.Remove("kiwis"));
c.RemoveAt(3);

string[] copied = new string[c.Count];
c.CopyTo(copied, 0);
Assert.True(SequencesEqual<string>(new string[] { "apples", "oranges", "pears" }, copied));

var enumerator = c.GetEnumerator();
Assert.True(enumerator.MoveNext());
Assert.NotNull(enumerator.Current);
}

c.Clear();
Assert.Empty(c);
Assert.Equal(0, c.Count);
}

[Fact]
public void CastListToEnum_String()
Expand All @@ -692,11 +781,29 @@ public void Collections_ReadOnly_List()
IReadOnlyList<string> b = null;
var c = Tests.Collection6(a, out b);
Assert.True(SequencesEqual(a, b, c));
RunReadonlyListTests(c);
}

Assert.Equal("oranges", a[1]);
Assert.Equal(3, a.Count());
Assert.NotNull(a.GetEnumerator());
}
#if NET
[Fact]
public void Collections_ReadOnly_List_IDIC()
{
string[] a = new string[] { "apples", "oranges", "pears" };
IReadOnlyList<string> b = null;
var c = Tests.Collection6(a, out b);
Assert.True(SequencesEqual(a, b, c));
var inspectable = new IInspectable(((IWinRTObject)c).NativeObject);
var listCreatedWithIDIC = (IReadOnlyList<string>)inspectable;
RunReadonlyListTests(listCreatedWithIDIC);
}
#endif
private void RunReadonlyListTests(IReadOnlyList<string> c)
{
Assert.Equal("oranges", c[1]);
Assert.Equal(3, c.Count());
Assert.Equal(3, c.Count);
Assert.NotNull(c.GetEnumerator());
}

[Fact]
public void Collections_IEnumerable_Call()
Expand Down
4 changes: 2 additions & 2 deletions src/WinRT.Runtime/ComWrappersSupport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -378,8 +378,8 @@ internal static Func<IInspectable, object> CreateTypedRcwFactory(Type implementa
}

internal static Func<IInspectable, object> CreateTypedRcwFactory(string runtimeClassName)
{
// If runtime class name is empty or "Object", then just use IInspectable.
{
// If runtime class name is empty or "Object", then just use IInspectable.
if (string.IsNullOrEmpty(runtimeClassName) ||
string.CompareOrdinal(runtimeClassName, "Object") == 0)
{
Expand Down
43 changes: 41 additions & 2 deletions src/WinRT.Runtime/ComWrappersSupport.net5.cs
Original file line number Diff line number Diff line change
Expand Up @@ -217,12 +217,51 @@ public static void InitializeComWrappers(ComWrappers wrappers = null)

private static Func<IInspectable, object> CreateFactoryForImplementationType(string runtimeClassName, Type implementationType)
{
ParameterExpression[] parms = new[] { Expression.Parameter(typeof(IInspectable), "inspectable") };

if (implementationType.IsGenericType)
{
var genericType = implementationType.GetGenericTypeDefinition();
if (genericType == typeof(IList<>))
{
return Expression.Lambda<Func<IInspectable, object>>(
Expression.New(typeof(IListImpl<>).MakeGenericType(new[] { implementationType.GetGenericArguments()[0] }).GetConstructor(BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance, null, new[] { typeof(IObjectReference) }, null),
Expression.Property(parms[0], nameof(WinRT.IInspectable.ObjRef))),
parms).Compile();
}
if (genericType == typeof(IDictionary<,>))
{
return Expression.Lambda<Func<IInspectable, object>>(
Expression.New(typeof(IDictionaryImpl<,>).MakeGenericType(new[] { implementationType.GetGenericArguments()[0], implementationType.GetGenericArguments()[1] }).GetConstructor(BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance, null, new[] { typeof(IObjectReference) }, null),
Expression.Property(parms[0], nameof(WinRT.IInspectable.ObjRef))),
parms).Compile();
}
if (genericType == typeof(IReadOnlyDictionary<,>))
{
return Expression.Lambda<Func<IInspectable, object>>(
Expression.New(typeof(IReadOnlyDictionaryImpl<,>).MakeGenericType(new[] { implementationType.GetGenericArguments()[0], implementationType.GetGenericArguments()[1] }).GetConstructor(BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance, null, new[] { typeof(IObjectReference) }, null),
Expression.Property(parms[0], nameof(WinRT.IInspectable.ObjRef))),
parms).Compile();
}
if (genericType == typeof(IReadOnlyList<>))
{
return Expression.Lambda<Func<IInspectable, object>>(
Expression.New(typeof(IReadOnlyListImpl<>).MakeGenericType(new[] { implementationType.GetGenericArguments()[0] }).GetConstructor(BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance, null, new[] { typeof(IObjectReference) }, null),
Expression.Property(parms[0], nameof(WinRT.IInspectable.ObjRef))),
parms).Compile();
}
if (genericType == typeof(IEnumerable<>))
{
return Expression.Lambda<Func<IInspectable, object>>(
Expression.New(typeof(IEnumerableImpl<>).MakeGenericType(new[] { implementationType.GetGenericArguments()[0] }).GetConstructor(BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance, null, new[] { typeof(IObjectReference) }, null),
Expression.Property(parms[0], nameof(WinRT.IInspectable.ObjRef))),
parms).Compile();
}
}
if (implementationType.IsInterface)
{
return obj => obj;
}

ParameterExpression[] parms = new[] { Expression.Parameter(typeof(IInspectable), "inspectable") };

return Expression.Lambda<Func<IInspectable, object>>(
Expression.New(implementationType.GetConstructor(BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance, null, new[] { typeof(IObjectReference) }, null),
Expand Down
7 changes: 6 additions & 1 deletion src/WinRT.Runtime/MatchingRefApiCompatBaseline.net5.0.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
Compat issues with assembly WinRT.Runtime:
TypesMustExist : Type 'ABI.System.Collections.Generic.IDictionaryMethods<K, V>' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'ABI.System.Collections.Generic.IEnumerableMethods<T>' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'ABI.System.Collections.Generic.IListMethods<T>' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'ABI.System.Collections.Generic.IReadOnlyDictionaryMethods<K, V>' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'ABI.System.Collections.Generic.IReadOnlyListMethods<T>' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'ABI.WinRT.Interop.IWeakReferenceSourceMethods' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'System.Numerics.VectorExtensions' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'WinRT.ComWrappersHelper' does not exist in the reference but it does exist in the implementation.
Expand All @@ -13,4 +18,4 @@ MembersMustExist : Member 'public System.IntPtr WinRT.MarshalString.GetAbi(WinRT
TypesMustExist : Type 'WinRT.MarshalString.Pinnable' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'WinRT.Interop.IWeakReference' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'WinRT.Interop.IWeakReferenceSource' does not exist in the reference but it does exist in the implementation.
Total Issues: 15
Total Issues: 19
25 changes: 12 additions & 13 deletions src/WinRT.Runtime/Projections/CollectionHybrid.net5.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections;
using System.Reflection;
using System.Runtime.InteropServices;
using WinRT;

Expand All @@ -22,18 +23,17 @@ interface IReadOnlyCollection<T> : global::System.Collections.Generic.IReadOnlyC
var iReadOnlyDictionary = typeof(global::System.Collections.Generic.IReadOnlyDictionary<,>).MakeGenericType(genericType.GetGenericArguments());
if (_this.IsInterfaceImplemented(iReadOnlyDictionary.TypeHandle, false))
{
return (global::System.Collections.Generic.IReadOnlyCollection<T>)
iReadOnlyDictionary.FindHelperType().GetMethod(
"_FromMapView",
global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static
).Invoke(null, global::System.Reflection.BindingFlags.Default, null, new object[] { _this }, null);
var iReadOnlyDictionaryImpl = typeof(global::System.Collections.Generic.IReadOnlyDictionaryImpl<,>).MakeGenericType(genericType.GetGenericArguments());
return (global::System.Collections.Generic.IReadOnlyCollection<T>)
iReadOnlyDictionaryImpl.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new global::System.Type[] { typeof(IObjectReference) }, null)
.Invoke(new object[] { _this.NativeObject });
}
}

var iReadOnlyList = typeof(global::System.Collections.Generic.IReadOnlyList<T>);
if (_this.IsInterfaceImplemented(iReadOnlyList.TypeHandle, false))
{
return IReadOnlyList<T>._FromVectorView(_this);
return new global::System.Collections.Generic.IReadOnlyListImpl<T>(_this.NativeObject);
}

throw new InvalidOperationException("IReadOnlyCollection helper can not determine derived type.");
Expand Down Expand Up @@ -67,18 +67,17 @@ interface ICollection<T> : global::System.Collections.Generic.ICollection<T>
var iDictionary = typeof(global::System.Collections.Generic.IDictionary<,>).MakeGenericType(genericType.GetGenericArguments());
if (_this.IsInterfaceImplemented(iDictionary.TypeHandle, false))
{
var iDictionaryImpl = typeof(global::System.Collections.Generic.IDictionaryImpl<,>).MakeGenericType(genericType.GetGenericArguments());
return (global::System.Collections.Generic.ICollection<T>)
iDictionary.FindHelperType().GetMethod(
"_FromMap",
global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static
).Invoke(null, global::System.Reflection.BindingFlags.Default, null, new object[] { _this }, null);
iDictionaryImpl.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new global::System.Type[] { typeof(IObjectReference) }, null)
.Invoke(new object[] { _this.NativeObject });
}
}

var iList = typeof(global::System.Collections.Generic.IList<T>);
if (_this.IsInterfaceImplemented(iList.TypeHandle, false))
{
return IList<T>._FromVector(_this);
return new global::System.Collections.Generic.IListImpl<T>(_this.NativeObject);
}

throw new InvalidOperationException("ICollection helper can not determine derived type.");
Expand All @@ -91,7 +90,7 @@ interface ICollection<T> : global::System.Collections.Generic.ICollection<T>
() => CreateHelper(_this));
}

int global::System.Collections.Generic.ICollection<T>.Count
int global::System.Collections.Generic.ICollection<T>.Count
=> GetHelper((IWinRTObject)this).Count;

bool global::System.Collections.Generic.ICollection<T>.IsReadOnly
Expand Down
Loading

0 comments on commit e78db0e

Please sign in to comment.