Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 66 additions & 1 deletion src/Benchmarks/Benchmarks/CollectionsPerf.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using BenchmarkComponent;
using BenchmarkDotNet.Attributes;

Expand All @@ -19,34 +20,55 @@ public class CollectionsPerf
private IList<int> vector;
private IList<int> bulkVector;
private int[] bulkBuffer;
private int[] managedBulkVector;
private ClassWithMarshalingRoutines instance;
private IList<string> bulkStringVector;
private string[] bulkStringBuffer;
private IDictionary<string, int> stringMap;
private IReadOnlyList<int> vectorView;
private IReadOnlyList<int> bulkVectorView;
private IReadOnlyDictionary<int, int> mapView;

private IList<WrappedClass> objectVector;
private IList<WrappedClass> bulkObjectVector;
private WrappedClass[] bulkObjectBuffer;
private IDictionary<string, WrappedClass> objectMap;
private IReadOnlyList<WrappedClass> objectVectorView;
private IReadOnlyList<WrappedClass> bulkObjectVectorView;
private IReadOnlyDictionary<string, WrappedClass> objectMapView;

[GlobalSetup]
public void Setup()
{
ClassWithMarshalingRoutines instance = new();
instance = new();

vector = instance.Items(VectorLen);
bulkVector = instance.Items(BulkCount);
bulkBuffer = new int[BulkCount];
managedBulkVector = new int[BulkCount];
for (int i = 0; i < BulkCount; i++)
{
managedBulkVector[i] = i;
}
// Will be uncommented once the TestWinRT change is done.
// _ = instance.GetManyFromManagedList(managedBulkVector);
bulkStringVector = instance.NewList();
bulkStringBuffer = new string[BulkCount];
for (int i = 0; i < BulkCount; i++)
{
bulkStringVector.Add(i.ToString());
}
stringMap = instance.StringMap(MapLen);
vectorView = instance.ItemsView(VectorLen);
bulkVectorView = instance.ItemsView(BulkCount);
mapView = instance.MapView(MapLen);

objectVector = instance.ObjectItems(VectorLen);
bulkObjectVector = instance.ObjectItems(BulkCount);
bulkObjectBuffer = new WrappedClass[BulkCount];
objectMap = instance.ObjectMap(MapLen);
objectVectorView = instance.ObjectItemsView(VectorLen);
bulkObjectVectorView = instance.ObjectItemsView(BulkCount);
objectMapView = instance.ObjectMapView(MapLen);
}

Expand Down Expand Up @@ -89,12 +111,55 @@ public void GetMany()
bulkVector.CopyTo(bulkBuffer, 0);
}

// Will be uncommented once the TestWinRT change is done.
// [Benchmark(OperationsPerInvoke = BulkCount)]
// public uint GetManyFromManagedList()
// {
// return instance.GetManyFromManagedList(managedBulkVector);
// }

[Benchmark(OperationsPerInvoke = BulkCount)]
public void GetManyStrings()
{
bulkStringVector.CopyTo(bulkStringBuffer, 0);
}

[Benchmark(OperationsPerInvoke = BulkCount)]
public void GetManyObjects()
{
bulkObjectVector.CopyTo(bulkObjectBuffer, 0);
}

[Benchmark(OperationsPerInvoke = BulkCount)]
public int[] ToArray()
{
return bulkVector.ToArray();
}

[Benchmark(OperationsPerInvoke = BulkCount)]
public string[] ToArrayStrings()
{
return bulkStringVector.ToArray();
}

[Benchmark(OperationsPerInvoke = BulkCount)]
public WrappedClass[] ToArrayObjects()
{
return bulkObjectVector.ToArray();
}

[Benchmark(OperationsPerInvoke = BulkCount)]
public int[] ToArrayView()
{
return bulkVectorView.ToArray();
}

[Benchmark(OperationsPerInvoke = BulkCount)]
public WrappedClass[] ToArrayViewObjects()
{
return bulkObjectVectorView.ToArray();
}

[Benchmark(OperationsPerInvoke = MapLen)]
public int Map()
{
Expand Down
48 changes: 47 additions & 1 deletion src/Tests/TestComponentCSharp/Class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,39 @@ namespace winrt::TestComponentCSharp::implementation
});
}

IVector<hstring> Class::GetStringVector2()
{
std::vector<hstring> values;
values.reserve(130);

for (int32_t i = 0; i < 130; i++)
{
values.push_back(to_hstring(i));
}

return winrt::single_threaded_vector(std::move(values));
}

IVector<DateTime> Class::GetDateTimeVector2()
{
auto now = winrt::clock::now();
return winrt::single_threaded_vector(std::vector{ now, now + std::chrono::seconds{ 1 } });
}

IVector<TestComponentCSharp::Class> Class::GetClassVector2()
{
return winrt::single_threaded_vector(std::vector
{
winrt::make<implementation::Class>(),
winrt::make<implementation::Class>(),
});
}

IVector<winrt::hresult> Class::GetExceptionVector2()
{
return winrt::single_threaded_vector(std::vector{ winrt::hresult{ -2147467259 }, winrt::hresult{ -2147024809 } });
}

// Test IIDOptimizer
IVectorView<Microsoft::UI::Xaml::Data::DataErrorsChangedEventArgs> Class::GetEventArgsVector()
{
Expand Down Expand Up @@ -2034,6 +2067,20 @@ namespace winrt::TestComponentCSharp::implementation
return sum;
}

int64_t Class::SumIntsWithGetMany(IVector<int32_t> const& values, uint32_t startIndex, uint32_t capacity)
{
std::vector<int32_t> items(capacity);
uint32_t retrieved = values.GetMany(startIndex, items);
int64_t sum = 0;

for (uint32_t i = 0; i < retrieved; i++)
{
sum += items[i];
}

return sum;
}

int32_t Class::CountKeyValuePairsWithGetMany(winrt::Windows::Foundation::Collections::IIterable<winrt::Windows::Foundation::Collections::IKeyValuePair<winrt::hstring, winrt::hstring>> const& pairs)
{
auto iterator = pairs.First();
Expand Down Expand Up @@ -2210,4 +2257,3 @@ namespace winrt::TestComponentCSharp::implementation
return winrt::make<NonProjectedDerivedCustomEquals>();
}
}

5 changes: 5 additions & 0 deletions src/Tests/TestComponentCSharp/Class.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,10 @@ namespace winrt::TestComponentCSharp::implementation
Windows::Foundation::Collections::IVector<int32_t> GetIntVector2();
Windows::Foundation::Collections::IVector<TestComponentCSharp::ComposedBlittableStruct> GetBlittableStructVector2();
Windows::Foundation::Collections::IVector<TestComponentCSharp::ComposedNonBlittableStruct> GetNonBlittableStructVector2();
Windows::Foundation::Collections::IVector<hstring> GetStringVector2();
Windows::Foundation::Collections::IVector<Windows::Foundation::DateTime> GetDateTimeVector2();
Windows::Foundation::Collections::IVector<TestComponentCSharp::Class> GetClassVector2();
Windows::Foundation::Collections::IVector<hresult> GetExceptionVector2();

Windows::Foundation::Collections::IMap<int32_t, int32_t> GetIntToIntDictionary();
Windows::Foundation::Collections::IMap<hstring, TestComponentCSharp::ComposedBlittableStruct> GetStringToBlittableDictionary();
Expand Down Expand Up @@ -427,6 +431,7 @@ namespace winrt::TestComponentCSharp::implementation
double Calculate(winrt::Windows::Foundation::Collections::IVector<winrt::Windows::Foundation::IReference<double>> const& values);
winrt::Windows::Foundation::Collections::IVector<winrt::Windows::Foundation::IReference<int32_t>> GetNullableIntList();
int32_t SumNullableIntsWithGetMany(winrt::Windows::Foundation::Collections::IVector<winrt::Windows::Foundation::IReference<int32_t>> const& values);
int64_t SumIntsWithGetMany(winrt::Windows::Foundation::Collections::IVector<int32_t> const& values, uint32_t startIndex, uint32_t capacity);
int32_t CountKeyValuePairsWithGetMany(winrt::Windows::Foundation::Collections::IIterable<winrt::Windows::Foundation::Collections::IKeyValuePair<winrt::hstring, winrt::hstring>> const& pairs);

static int GetPropertyType(Windows::Foundation::IInspectable const& obj);
Expand Down
5 changes: 5 additions & 0 deletions src/Tests/TestComponentCSharp/TestComponentCSharp.idl
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,10 @@ namespace TestComponentCSharp
Windows.Foundation.Collections.IVector<Int32> GetIntVector2();
Windows.Foundation.Collections.IVector<ComposedBlittableStruct> GetBlittableStructVector2();
Windows.Foundation.Collections.IVector<ComposedNonBlittableStruct> GetNonBlittableStructVector2();
Windows.Foundation.Collections.IVector<String> GetStringVector2();
Windows.Foundation.Collections.IVector<Windows.Foundation.DateTime> GetDateTimeVector2();
Windows.Foundation.Collections.IVector<Class> GetClassVector2();
Windows.Foundation.Collections.IVector<Windows.Foundation.HResult> GetExceptionVector2();

Windows.Foundation.Collections.IMap<Int32, Int32> GetIntToIntDictionary();
Windows.Foundation.Collections.IMap<String, ComposedBlittableStruct> GetStringToBlittableDictionary();
Expand Down Expand Up @@ -480,6 +484,7 @@ namespace TestComponentCSharp
Double Calculate(Windows.Foundation.Collections.IVector<Windows.Foundation.IReference<Double> > values);
Windows.Foundation.Collections.IVector<Windows.Foundation.IReference<Int32> > GetNullableIntList();
Int32 SumNullableIntsWithGetMany(Windows.Foundation.Collections.IVector<Windows.Foundation.IReference<Int32> > values);
Int64 SumIntsWithGetMany(Windows.Foundation.Collections.IVector<Int32> values, UInt32 startIndex, UInt32 capacity);
Int32 CountKeyValuePairsWithGetMany(Windows.Foundation.Collections.IIterable<Windows.Foundation.Collections.IKeyValuePair<String, String> > pairs);

// Boxing
Expand Down
95 changes: 95 additions & 0 deletions src/Tests/UnitTest/TestComponentCSharp_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3964,6 +3964,101 @@ public void TestListOfTypes()
Assert.AreEqual(2, types.Count);
Assert.AreEqual(typeof(Class), types[0]);
Assert.AreEqual(typeof(int?), types[1]);

Type[] copied = new Type[3];
types.CopyTo(copied, 1);
Assert.IsNull(copied[0]);
Assert.AreEqual(typeof(Class), copied[1]);
Assert.AreEqual(typeof(int?), copied[2]);
}

[TestMethod]
public void NativeVectorCopyTo_ValueTypes()
{
IList<int> ints = TestObject.GetIntVector2();
int[] copiedInts = new int[ints.Count + 1];
ints.CopyTo(copiedInts, 1);
CollectionAssert.AreEqual(new[] { 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, copiedInts);

IList<ComposedBlittableStruct> blittableStructs = TestObject.GetBlittableStructVector2();
ComposedBlittableStruct[] copiedBlittableStructs = new ComposedBlittableStruct[blittableStructs.Count];
blittableStructs.CopyTo(copiedBlittableStructs, 0);
Assert.AreEqual(4, copiedBlittableStructs[4].blittable.i32);

IList<ComposedNonBlittableStruct> nonBlittableStructs = TestObject.GetNonBlittableStructVector2();
ComposedNonBlittableStruct[] copiedNonBlittableStructs = new ComposedNonBlittableStruct[nonBlittableStructs.Count];
nonBlittableStructs.CopyTo(copiedNonBlittableStructs, 0);
Assert.AreEqual("String1", copiedNonBlittableStructs[1].strings.str);
Assert.IsTrue(copiedNonBlittableStructs[2].bools.w);

IList<DateTimeOffset> dateTimes = TestObject.GetDateTimeVector2();
DateTimeOffset[] copiedDateTimes = new DateTimeOffset[dateTimes.Count];
dateTimes.CopyTo(copiedDateTimes, 0);
Assert.AreEqual(TimeSpan.FromSeconds(1), copiedDateTimes[1] - copiedDateTimes[0]);
}

[TestMethod]
public void NativeVectorCopyTo_ReferenceTypes()
{
IList<Class> classes = TestObject.GetClassVector2();
Class[] copiedClasses = new Class[classes.Count + 1];
classes.CopyTo(copiedClasses, 1);
Assert.IsNull(copiedClasses[0]);
Assert.IsNotNull(copiedClasses[1]);
Assert.IsNotNull(copiedClasses[2]);

IList<object> objects = TestObject.GetUriVectorAsIInspectableVector();
object[] copiedObjects = new object[objects.Count];
objects.CopyTo(copiedObjects, 0);
Assert.IsTrue(copiedObjects.All(static item => item is Uri));
}

[TestMethod]
public void NativeVectorCopyTo_StringTypeAcrossChunks()
{
IList<string> strings = TestObject.GetStringVector2();
string[] copiedStrings = new string[strings.Count + 2];
strings.CopyTo(copiedStrings, 1);
Assert.IsNull(copiedStrings[0]);
Assert.AreEqual("0", copiedStrings[1]);
Assert.AreEqual("64", copiedStrings[65]);
Assert.AreEqual("129", copiedStrings[130]);
Assert.IsNull(copiedStrings[131]);
}

[TestMethod]
public void NativeVectorCopyTo_NullableType()
{
IList<int?> nullableInts = TestObject.GetNullableIntList();
int?[] copiedNullableInts = new int?[nullableInts.Count];
nullableInts.CopyTo(copiedNullableInts, 0);
CollectionAssert.AreEqual(new int?[] { 1, null, 2 }, copiedNullableInts);
}

[TestMethod]
public void NativeVectorCopyTo_ExceptionType()
{
IList<Exception> exceptions = TestObject.GetExceptionVector2();
Exception[] copiedExceptions = new Exception[exceptions.Count];
exceptions.CopyTo(copiedExceptions, 0);
Assert.AreEqual(unchecked((int)0x80004005), copiedExceptions[0].HResult);
Assert.AreEqual(unchecked((int)0x80070057), copiedExceptions[1].HResult);
}

[TestMethod]
public void ManagedVectorGetMany_BlittableFastPathsAndFallback()
{
int[] array = [10, 20, 30, 40, 50];
Assert.AreEqual(90L, TestObject.SumIntsWithGetMany(array, 1, 3));

List<int> list = [10, 20, 30, 40, 50];
Assert.AreEqual(90L, TestObject.SumIntsWithGetMany(list, 1, 3));

Collection<int> collection = [10, 20, 30, 40, 50];
Assert.AreEqual(90L, TestObject.SumIntsWithGetMany(collection, 1, 3));

Assert.AreEqual(0L, TestObject.SumIntsWithGetMany(array, (uint)array.Length, 3));
Assert.AreEqual(0L, TestObject.SumIntsWithGetMany(array, 0, 0));
}

[TestMethod]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,17 @@ public static void IVectorMethods(
declaration: interopReferences.IVectorMethodsImpl1GetAt(elementType),
method: getAtMethod);

// Define the 'GetMany' method
MethodDefinition getManyMethod = InteropMethodDefinitionFactory.IVectorMethods.GetMany(
listType: listType,
interopReferences: interopReferences,
emitState: emitState);

// Add and implement the 'GetMany' method
vectorMethodsType.AddMethodImplementation(
declaration: interopReferences.IVectorMethodsImpl1GetMany(elementType),
method: getManyMethod);

// Define the 'SetAt' method
MethodDefinition setAtMethod = InteropMethodDefinitionFactory.IVectorMethods.SetAt(
listType: listType,
Expand Down
Loading