Skip to content

Commit

Permalink
Merge pull request #1363 from microsoft/master
Browse files Browse the repository at this point in the history
Update staging again with latest without squash
  • Loading branch information
manodasanW authored Sep 26, 2023
2 parents 9b6cd7e + 1ee556f commit 3171656
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 82 deletions.
2 changes: 1 addition & 1 deletion nuget/Microsoft.Windows.CsWinRT.targets
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ Copyright (C) Microsoft Corporation. All rights reserved.
<Target Name="CsWinRTGenerateProjection"
DependsOnTargets="CsWinRTPrepareProjection;CsWinRTRemoveWinMDReferences"
Condition="'$(CsWinRTGenerateProjection)' == 'true'"
Inputs="$(MSBuildAllProjects);@(CsWinRTInputs);$(CsWinRTExcludes);$(CsWinRTIncludes);$(CsWinRTExcludesPrivate);$(CsWinRTIncludesPrivate);$(CsWinRTFilters);$(CsWinRTWindowsMetadata)"
Inputs="$(MSBuildAllProjects);@(CsWinRTInputs);$(CsWinRTExe);$(CsWinRTExcludes);$(CsWinRTIncludes);$(CsWinRTExcludesPrivate);$(CsWinRTIncludesPrivate);$(CsWinRTFilters);$(CsWinRTWindowsMetadata)"
Outputs="$(CsWinRTGeneratedFilesDir)cswinrt.rsp">

<PropertyGroup>
Expand Down
43 changes: 43 additions & 0 deletions src/Tests/TestComponentCSharp/Class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1044,6 +1044,49 @@ namespace winrt::TestComponentCSharp::implementation
return winrt::single_threaded_vector_view(std::vector<TestComponentCSharp::Class>{ *this, *this, *this });
}

IMap<int32_t, int32_t> Class::GetIntToIntDictionary()
{
return single_threaded_map<int32_t, int32_t>(std::map<int32_t, int32_t>{ {1, 4}, { 2, 8 }, { 3, 12 } });
}

IMap<hstring, TestComponentCSharp::ComposedBlittableStruct> Class::GetStringToBlittableDictionary()
{
return single_threaded_map<hstring, TestComponentCSharp::ComposedBlittableStruct>(std::map<hstring, TestComponentCSharp::ComposedBlittableStruct>
{
{ L"alpha", ComposedBlittableStruct{ 5 } },
{ L"beta", ComposedBlittableStruct{ 4 } },
{ L"charlie", ComposedBlittableStruct{ 7 } }
});
}

IMap<hstring, TestComponentCSharp::ComposedNonBlittableStruct> Class::GetStringToNonBlittableDictionary()
{
return single_threaded_map<hstring, TestComponentCSharp::ComposedNonBlittableStruct>(std::map<hstring, TestComponentCSharp::ComposedNonBlittableStruct>
{
{ L"String0", ComposedNonBlittableStruct{ { 0 }, { L"String0" }, { true, false, true, false }, { 0 } } },
{ L"String1", ComposedNonBlittableStruct{ { 1 }, { L"String1" }, { false, true, false, true }, { 1 } } },
{ L"String2", ComposedNonBlittableStruct{ { 2 }, { L"String2" }, { true, false, true, false }, { 2 } } }
});
}

struct ComposedBlittableStructComparer
{
bool operator() (const TestComponentCSharp::ComposedBlittableStruct& l, const TestComponentCSharp::ComposedBlittableStruct& r) const
{
return (l.blittable.i32 < r.blittable.i32);
}
};

IMap<TestComponentCSharp::ComposedBlittableStruct, WF::IInspectable> Class::GetBlittableToObjectDictionary()
{
return single_threaded_map<TestComponentCSharp::ComposedBlittableStruct, WF::IInspectable>(std::map<TestComponentCSharp::ComposedBlittableStruct, WF::IInspectable, ComposedBlittableStructComparer>
{
{ ComposedBlittableStruct{ 1 }, winrt::box_value(0) },
{ ComposedBlittableStruct{ 4 }, winrt::box_value(L"box") },
{ ComposedBlittableStruct{ 8 }, *this }
});
}

// Test IIDOptimizer
IVectorView<Microsoft::UI::Xaml::Data::DataErrorsChangedEventArgs> Class::GetEventArgsVector()
{
Expand Down
5 changes: 5 additions & 0 deletions src/Tests/TestComponentCSharp/Class.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,11 @@ namespace winrt::TestComponentCSharp::implementation
Windows::Foundation::Collections::IVectorView<Windows::Foundation::IInspectable> GetObjectVector();
Windows::Foundation::Collections::IVectorView<TestComponentCSharp::IProperties1> GetInterfaceVector();
Windows::Foundation::Collections::IVectorView<TestComponentCSharp::Class> GetClassVector() noexcept;

Windows::Foundation::Collections::IMap<int32_t, int32_t> GetIntToIntDictionary();
Windows::Foundation::Collections::IMap<hstring, TestComponentCSharp::ComposedBlittableStruct> GetStringToBlittableDictionary();
Windows::Foundation::Collections::IMap<hstring, TestComponentCSharp::ComposedNonBlittableStruct> GetStringToNonBlittableDictionary();
Windows::Foundation::Collections::IMap<TestComponentCSharp::ComposedBlittableStruct, Windows::Foundation::IInspectable> GetBlittableToObjectDictionary();

// Test IIDOptimizer -- testing the windows projection covers most code paths, and these two types exercise the rest.
Windows::Foundation::Collections::IVectorView<Microsoft::UI::Xaml::Data::DataErrorsChangedEventArgs> GetEventArgsVector();
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 @@ -315,6 +315,11 @@ namespace TestComponentCSharp
Windows.Foundation.Collections.IVectorView<IProperties1> GetInterfaceVector();
[noexcept] Windows.Foundation.Collections.IVectorView<Class> GetClassVector();

Windows.Foundation.Collections.IMap<Int32, Int32> GetIntToIntDictionary();
Windows.Foundation.Collections.IMap<String, ComposedBlittableStruct> GetStringToBlittableDictionary();
Windows.Foundation.Collections.IMap<String, ComposedNonBlittableStruct> GetStringToNonBlittableDictionary();
Windows.Foundation.Collections.IMap<ComposedBlittableStruct, Object> GetBlittableToObjectDictionary();

// Test IIDOptimizer
Windows.Foundation.Collections.IVectorView<Microsoft.UI.Xaml.Data.DataErrorsChangedEventArgs> GetEventArgsVector();
Windows.Foundation.Collections.IVectorView<ProvideUri> GetNonGenericDelegateVector();
Expand Down
26 changes: 26 additions & 0 deletions src/Tests/UnitTest/TestComponentCSharp_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3069,5 +3069,31 @@ public void TestWeakReferenceEventsFromMultipleContexts()
staThread.Start();
staThread.Join();
}

[Fact]
public void TestDictionary()
{
var intToIntDict = TestObject.GetIntToIntDictionary();
Assert.Equal(8, intToIntDict[2]);
Assert.Equal(8, intToIntDict[2]);
Assert.Equal(12, intToIntDict[3]);

var stringToBlittableDict = TestObject.GetStringToBlittableDictionary();
Assert.Equal(5, stringToBlittableDict["alpha"].blittable.i32);
Assert.Equal(7, stringToBlittableDict["charlie"].blittable.i32);
Assert.Equal(5, stringToBlittableDict["alpha"].blittable.i32);

var stringToNonBlittableDict = TestObject.GetStringToNonBlittableDictionary();
Assert.Equal(1, stringToNonBlittableDict["String1"].blittable.i32);
Assert.Equal("String1", stringToNonBlittableDict["String1"].strings.str);
Assert.False(stringToNonBlittableDict["String1"].bools.w);
Assert.True(stringToNonBlittableDict["String1"].bools.x);

var blittableToObjectDict = TestObject.GetBlittableToObjectDictionary();
ComposedBlittableStruct key;
key.blittable.i32 = 4;
Assert.Equal("box", (string)blittableToObjectDict[key]);
Assert.Equal("box", (string)blittableToObjectDict[key]);
}
}
}
46 changes: 13 additions & 33 deletions src/WinRT.Runtime/Projections/IDictionary.net5.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,10 @@ namespace System.Collections.Generic
internal sealed class IDictionaryImpl<K, V> : IDictionary<K, V>, IWinRTObject
{
private IObjectReference _inner;
private Dictionary<K, (IntPtr, V)> _lookupCache;

internal IDictionaryImpl(IObjectReference _inner)
{
this._inner = _inner;
this._lookupCache = new Dictionary<K, (IntPtr, V)>();
}

public static IDictionaryImpl<K, V> CreateRcw(IInspectable obj) => new(obj.ObjRef);
Expand Down Expand Up @@ -85,7 +83,7 @@ private IObjectReference Make_IEnumerableObjRef()

public V this[K key]
{
get => ABI.System.Collections.Generic.IDictionaryMethods<K, V>.Indexer_Get(iDictionaryObjRef, _lookupCache, key);
get => ABI.System.Collections.Generic.IDictionaryMethods<K, V>.Indexer_Get(iDictionaryObjRef, null, key);
set => ABI.System.Collections.Generic.IDictionaryMethods<K, V>.Indexer_Set(iDictionaryObjRef, key, value);
}

Expand Down Expand Up @@ -114,7 +112,7 @@ public void Clear()

public bool Contains(KeyValuePair<K, V> item)
{
return ABI.System.Collections.Generic.IDictionaryMethods<K, V>.Contains(iDictionaryObjRef, _lookupCache, item);
return ABI.System.Collections.Generic.IDictionaryMethods<K, V>.Contains(iDictionaryObjRef, null, item);
}

public bool ContainsKey(K key)
Expand Down Expand Up @@ -144,7 +142,7 @@ public bool Remove(KeyValuePair<K, V> item)

public bool TryGetValue(K key, [MaybeNullWhen(false)] out V value)
{
return ABI.System.Collections.Generic.IDictionaryMethods<K, V>.TryGetValue(iDictionaryObjRef, _lookupCache, key, out value);
return ABI.System.Collections.Generic.IDictionaryMethods<K, V>.TryGetValue(iDictionaryObjRef, null, key, out value);
}

IEnumerator IEnumerable.GetEnumerator()
Expand All @@ -162,7 +160,7 @@ namespace ABI.Windows.Foundation.Collections

internal static class IMapMethods<K, V>
{
public static unsafe V Lookup(IObjectReference obj, Dictionary<K, (IntPtr, V)> __lookupCache, K key)
public static unsafe V Lookup(IObjectReference obj, K key)
{
var _obj = (ObjectReference<IDictionary<K, V>.Vftbl>)obj;
var ThisPtr = _obj.ThisPtr;
Expand All @@ -174,19 +172,7 @@ public static unsafe V Lookup(IObjectReference obj, Dictionary<K, (IntPtr, V)> _
__params[1] = Marshaler<K>.GetAbi(__key);
_obj.Vftbl.Lookup_0.DynamicInvokeAbi(__params);

if (__lookupCache != null && __lookupCache.TryGetValue(key, out var __cachedRcw) && __cachedRcw.Item1 == (IntPtr)__params[2])
{
return __cachedRcw.Item2;
}
else
{
var value = Marshaler<V>.FromAbi(__params[2]);
if (__lookupCache != null)
{
__lookupCache[key] = ((IntPtr)__params[2], value);
}
return value;
}
return Marshaler<V>.FromAbi(__params[2]);
}
finally
{
Expand Down Expand Up @@ -334,7 +320,7 @@ public static bool Contains(IObjectReference obj, Dictionary<K, (IntPtr, V)> __l
if (!hasKey)
return false;
// todo: toctou
V value = IMapMethods<K, V>.Lookup(obj, __lookupCache, item.Key);
V value = IMapMethods<K, V>.Lookup(obj, item.Key);
return EqualityComparer<V>.Default.Equals(value, item.Value);
}

Expand Down Expand Up @@ -368,7 +354,7 @@ public static V Indexer_Get(IObjectReference obj, Dictionary<K, (IntPtr, V)> __l
{
if (key == null)
throw new ArgumentNullException(nameof(key));
return Lookup(obj, __lookupCache, key);
return Lookup(obj, key);
}

public static void Indexer_Set(IObjectReference obj, K key, V value)
Expand Down Expand Up @@ -435,7 +421,7 @@ public static bool TryGetValue(IObjectReference obj, Dictionary<K, (IntPtr, V)>

try
{
value = Lookup(obj, __lookupCache, key);
value = Lookup(obj, key);
return true;
}
catch (KeyNotFoundException)
Expand All @@ -445,13 +431,13 @@ public static bool TryGetValue(IObjectReference obj, Dictionary<K, (IntPtr, V)>
}
}

private static V Lookup(IObjectReference obj, Dictionary<K, (IntPtr, V)> __lookupCache, K key)
private static V Lookup(IObjectReference obj, K key)
{
Debug.Assert(null != key);

try
{
return IMapMethods<K, V>.Lookup(obj, __lookupCache, key);
return IMapMethods<K, V>.Lookup(obj, key);
}
catch (global::System.Exception ex)
{
Expand Down Expand Up @@ -1013,7 +999,7 @@ public static ObjectReference<Vftbl> ObjRefFromAbi(IntPtr thisPtr)
get
{
var _obj = ((ObjectReference<Vftbl>)((IWinRTObject)this).GetObjectReferenceForType(typeof(global::System.Collections.Generic.IDictionary<K, V>).TypeHandle));
return IDictionaryMethods<K, V>.Indexer_Get(_obj, GetLookupCache((IWinRTObject)this), key);
return IDictionaryMethods<K, V>.Indexer_Get(_obj, null, key);
}
set
{
Expand All @@ -1040,16 +1026,10 @@ public static ObjectReference<Vftbl> ObjRefFromAbi(IntPtr thisPtr)
return IDictionaryMethods<K, V>.Remove(_obj, key);
}

internal static global::System.Collections.Generic.Dictionary<K, (IntPtr, V)> GetLookupCache(IWinRTObject _this)
{
return (Dictionary<K, (IntPtr, V)>)_this.GetOrCreateTypeHelperData(typeof(global::System.Collections.Generic.IDictionary<K, V>).TypeHandle,
() => new Dictionary<K, (IntPtr, V)>());
}

bool global::System.Collections.Generic.IDictionary<K, V>.TryGetValue(K key, out V value)
{
var _obj = ((ObjectReference<Vftbl>)((IWinRTObject)this).GetObjectReferenceForType(typeof(global::System.Collections.Generic.IDictionary<K, V>).TypeHandle));
return IDictionaryMethods<K, V>.TryGetValue(_obj, GetLookupCache((IWinRTObject)this), key, out value);
return IDictionaryMethods<K, V>.TryGetValue(_obj, null, key, out value);
}

void global::System.Collections.Generic.ICollection<global::System.Collections.Generic.KeyValuePair<K, V>>.Add(global::System.Collections.Generic.KeyValuePair<K, V> item)
Expand All @@ -1061,7 +1041,7 @@ public static ObjectReference<Vftbl> ObjRefFromAbi(IntPtr thisPtr)
bool global::System.Collections.Generic.ICollection<global::System.Collections.Generic.KeyValuePair<K, V>>.Contains(global::System.Collections.Generic.KeyValuePair<K, V> item)
{
var _obj = ((ObjectReference<Vftbl>)((IWinRTObject)this).GetObjectReferenceForType(typeof(global::System.Collections.Generic.IDictionary<K, V>).TypeHandle));
return IDictionaryMethods<K, V>.Contains(_obj, GetLookupCache((IWinRTObject)this), item);
return IDictionaryMethods<K, V>.Contains(_obj, null, item);
}

void global::System.Collections.Generic.ICollection<global::System.Collections.Generic.KeyValuePair<K, V>>.CopyTo(global::System.Collections.Generic.KeyValuePair<K, V>[] array, int arrayIndex)
Expand Down
48 changes: 5 additions & 43 deletions src/cswinrt/code_writers.h
Original file line number Diff line number Diff line change
Expand Up @@ -1862,7 +1862,7 @@ internal static % Instance => _instance;
else
{
w.write(R"(
internal sealed class _% : IWinRTObject
internal sealed class _%
{
private IObjectReference _obj;
public _%()
Expand All @@ -1872,23 +1872,6 @@ _obj = %(GuidGenerator.GetIID(typeof(%.%).GetHelperType()));
%
internal static % Instance => (%)_instance;
IObjectReference IWinRTObject.NativeObject => _obj;
bool IWinRTObject.HasUnwrappableNativeObject => false;
private volatile global::System.Collections.Concurrent.ConcurrentDictionary<RuntimeTypeHandle, IObjectReference> _queryInterfaceCache;
private global::System.Collections.Concurrent.ConcurrentDictionary<RuntimeTypeHandle, IObjectReference> MakeQueryInterfaceCache()
{
global::System.Threading.Interlocked.CompareExchange(ref _queryInterfaceCache, new global::System.Collections.Concurrent.ConcurrentDictionary<RuntimeTypeHandle, IObjectReference>(), null);
return _queryInterfaceCache;
}
global::System.Collections.Concurrent.ConcurrentDictionary<RuntimeTypeHandle, IObjectReference> IWinRTObject.QueryInterfaceCache => _queryInterfaceCache ?? MakeQueryInterfaceCache();
private volatile global::System.Collections.Concurrent.ConcurrentDictionary<RuntimeTypeHandle, object> _additionalTypeData;
private global::System.Collections.Concurrent.ConcurrentDictionary<RuntimeTypeHandle, object> MakeAdditionalTypeData()
{
global::System.Threading.Interlocked.CompareExchange(ref _additionalTypeData, new global::System.Collections.Concurrent.ConcurrentDictionary<RuntimeTypeHandle, object>(), null);
return _additionalTypeData;
}
global::System.Collections.Concurrent.ConcurrentDictionary<RuntimeTypeHandle, object> IWinRTObject.AdditionalTypeData => _additionalTypeData ?? MakeAdditionalTypeData();
}
)",
cache_type_name,
Expand Down Expand Up @@ -2494,28 +2477,25 @@ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
auto enumerableObjRefName = std::regex_replace(objref_name, std::regex("IDictionary"), "IEnumerable_global__System_Collections_Generic_KeyValuePair") + "_";

w.write(R"(
private Dictionary<%, (IntPtr, %)> _lookupCache = new Dictionary<%, (IntPtr, %)>();
%ICollection<%> %Keys => %.get_Keys(%);
%ICollection<%> %Values => %.get_Values(%);
%int %Count => %.get_Count(%);
%bool %IsReadOnly => %.get_IsReadOnly(%);
%% %this[% key]
{
get => %.Indexer_Get(%, _lookupCache, key);
get => %.Indexer_Get(%, null, key);
set => %.Indexer_Set(%, key, value);
}
%void %Add(% key, % value) => %.Add(%, key, value);
%bool %ContainsKey(% key) => %.ContainsKey(%, key);
%bool %Remove(% key) => %.Remove(%, key);
%bool %TryGetValue(% key, out % value) => %.TryGetValue(%, _lookupCache, key, out value);
%bool %TryGetValue(% key, out % value) => %.TryGetValue(%, null, key, out value);
%void %Add(KeyValuePair<%, %> item) => %.Add(%, item);
%void %Clear() => %.Clear(%);
%bool %Contains(KeyValuePair<%, %> item) => %.Contains(%, _lookupCache, item);
%bool %Contains(KeyValuePair<%, %> item) => %.Contains(%, null, item);
%void %CopyTo(KeyValuePair<%, %>[] array, int arrayIndex) => %.CopyTo(%, %, array, arrayIndex);
bool ICollection<KeyValuePair<%, %>>.Remove(KeyValuePair<%, %> item) => %.Remove(%, item);
)",
key, value, key, value,
visibility, key, self, abiClass, objref_name, //Keys
visibility, value, self, abiClass, objref_name, // Values
visibility, icollection, abiClass, objref_name, // Count
Expand Down Expand Up @@ -4095,7 +4075,7 @@ internal static _% Instance => _instance;
else
{
w.write(R"(
internal sealed class _% : IWinRTObject
internal sealed class _%
{
private IObjectReference _obj;
private IntPtr ThisPtr => _obj.ThisPtr;
Expand All @@ -4106,24 +4086,6 @@ _obj = ActivationFactory<%>.As(GuidGenerator.GetIID(typeof(%.%).GetHelperType())
private static _% _instance = new _%();
internal static _% Instance => _instance;
IObjectReference IWinRTObject.NativeObject => _obj;
bool IWinRTObject.HasUnwrappableNativeObject => false;
private volatile global::System.Collections.Concurrent.ConcurrentDictionary<RuntimeTypeHandle, IObjectReference> _queryInterfaceCache;
private global::System.Collections.Concurrent.ConcurrentDictionary<RuntimeTypeHandle, IObjectReference> MakeQueryInterfaceCache()
{
global::System.Threading.Interlocked.CompareExchange(ref _queryInterfaceCache, new global::System.Collections.Concurrent.ConcurrentDictionary<RuntimeTypeHandle, IObjectReference>(), null);
return _queryInterfaceCache;
}
global::System.Collections.Concurrent.ConcurrentDictionary<RuntimeTypeHandle, IObjectReference> IWinRTObject.QueryInterfaceCache => _queryInterfaceCache ?? MakeQueryInterfaceCache();
private volatile global::System.Collections.Concurrent.ConcurrentDictionary<RuntimeTypeHandle, object> _additionalTypeData;
private global::System.Collections.Concurrent.ConcurrentDictionary<RuntimeTypeHandle, object> MakeAdditionalTypeData()
{
global::System.Threading.Interlocked.CompareExchange(ref _additionalTypeData, new global::System.Collections.Concurrent.ConcurrentDictionary<RuntimeTypeHandle, object>(), null);
return _additionalTypeData;
}
global::System.Collections.Concurrent.ConcurrentDictionary<RuntimeTypeHandle, object> IWinRTObject.AdditionalTypeData => _additionalTypeData ?? MakeAdditionalTypeData();
%
}
)",
Expand Down
Loading

0 comments on commit 3171656

Please sign in to comment.