Fixes for virtual dispatch for multiple inheritance.
+ Fix Itanium vtable layout: derived type's virtual methods come after primary base's but before the rest of the base classes' + Wrapper cleanup: move common init code to methods, cache all casted base wrappers right away in preparation for patching base-in-derived vtptrs + CppInstancePtr: read native_vtptr when constructed with native ptr-- will need hash lookup to detect managed instances + Clean/refactor LazyGeneratedList
This commit is contained in:
Родитель
0febce15f3
Коммит
6a8bec014e
|
@ -54,7 +54,7 @@ namespace Mono.VisualC.Interop.ABI {
|
|||
protected static readonly MethodInfo cppip_managedalloc = typeof (CppInstancePtr).GetProperty ("IsManagedAlloc").GetGetMethod ();
|
||||
protected static readonly MethodInfo cppip_getmanaged = typeof (CppInstancePtr).GetMethod ("GetManaged", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
protected static readonly ConstructorInfo cppip_fromnative = typeof (CppInstancePtr).GetConstructor (new Type [] { typeof (IntPtr) });
|
||||
protected static readonly ConstructorInfo cppip_fromsize = typeof (CppInstancePtr).GetConstructor (new Type [] { typeof (int) });
|
||||
protected static readonly ConstructorInfo cppip_fromsize = typeof (CppInstancePtr).GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null, new Type [] { typeof (int) }, null);
|
||||
protected static readonly ConstructorInfo cppip_fromsize_managed = typeof (CppInstancePtr).GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null,
|
||||
new Type[] { typeof (int), typeof (object) }, null);
|
||||
protected static readonly ConstructorInfo notimplementedexception = typeof (NotImplementedException).GetConstructor (new Type [] { typeof (string) });
|
||||
|
|
|
@ -38,25 +38,38 @@ namespace Mono.VisualC.Interop.ABI {
|
|||
{
|
||||
}
|
||||
|
||||
|
||||
// When adding a non-primary base class's complete vtable, we need to reserve space for
|
||||
// the stuff before the address point of the vtptr..
|
||||
// Includes vbase & vcall offsets (virtual inheritance), offset to top, and RTTI info
|
||||
public override void AddBase (CppTypeInfo baseType)
|
||||
protected override void AddBase (CppTypeInfo baseType, bool addVTable)
|
||||
{
|
||||
if (TypeComplete)
|
||||
return;
|
||||
|
||||
if (BaseClasses.Count > 0 && baseType.VirtualMethods.Any ()) { // already have a primary base
|
||||
// When adding a non-primary base class's complete vtable, we need to reserve space for
|
||||
// the stuff before the address point of the vtptr..
|
||||
// Includes vbase & vcall offsets (virtual inheritance), offset to top, and RTTI info
|
||||
if (addVTable) {
|
||||
|
||||
// FIXME: virtual inheritance
|
||||
virtual_methods.Insert (BaseVTableSlots, null);
|
||||
virtual_methods.Insert (BaseVTableSlots, null);
|
||||
BaseVTableSlots += 2;
|
||||
virtual_methods.Add (null);
|
||||
virtual_methods.Add (null);
|
||||
|
||||
vt_overrides.Add (2);
|
||||
vt_delegate_types.Add (2);
|
||||
}
|
||||
|
||||
base.AddBase (baseType);
|
||||
base.AddBase (baseType, addVTable);
|
||||
}
|
||||
|
||||
protected override bool OnVTableDuplicate (ref int iter, PInvokeSignature sig, PInvokeSignature dup)
|
||||
{
|
||||
var isOverride = base.OnVTableDuplicate (ref iter, sig, dup);
|
||||
if (isOverride && sig.Type == MethodType.NativeDtor) {
|
||||
|
||||
// also remove that pesky extra dtor
|
||||
virtual_methods.RemoveAt (iter + 1);
|
||||
vt_overrides.Remove (1);
|
||||
vt_delegate_types.Remove (1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace Mono.VisualC.Interop.ABI {
|
|||
|
||||
protected override CppTypeInfo MakeTypeInfo (IEnumerable<PInvokeSignature> methods)
|
||||
{
|
||||
return new MsvcTypeInfo (this, methods.Where (m => IsVirtual (m.OrigMethod)), layout_type, wrapper_type);
|
||||
return new CppTypeInfo (this, methods.Where (m => IsVirtual (m.OrigMethod)), layout_type, wrapper_type);
|
||||
}
|
||||
|
||||
public override CallingConvention? GetCallingConvention (MethodInfo methodInfo)
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
// Author:
|
||||
// Alexander Corrado (alexander.corrado@gmail.com)
|
||||
// Andreia Gaita (shana@spoiledcat.net)
|
||||
//
|
||||
// Copyright (C) 2010 Alexander Corrado
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Reflection;
|
||||
|
||||
using Mono.VisualC.Interop.Util;
|
||||
|
||||
namespace Mono.VisualC.Interop.ABI {
|
||||
public class MsvcTypeInfo : CppTypeInfo {
|
||||
public MsvcTypeInfo (MsvcAbi abi, IEnumerable<PInvokeSignature> virtualMethods, Type nativeLayout, Type wrapperType)
|
||||
: base (abi, virtualMethods, nativeLayout, wrapperType)
|
||||
{
|
||||
}
|
||||
|
||||
// AFIK, MSVC places only its first base's virtual methods in the derived class's
|
||||
// primary vtable. Subsequent base classes (each?) get another vtable pointer
|
||||
public override void AddBase (CppTypeInfo baseType)
|
||||
{
|
||||
if (TypeComplete)
|
||||
return;
|
||||
|
||||
if (BaseClasses.Count == 0)
|
||||
base.AddBase (baseType, false);
|
||||
else
|
||||
base.AddBase (baseType, true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -70,6 +70,7 @@ namespace Mono.VisualC.Interop {
|
|||
}
|
||||
|
||||
// Alloc a new C++ instance
|
||||
// NOTE: native_vtptr will be set later after native ctor is called
|
||||
internal CppInstancePtr (int nativeSize, object managedWrapper)
|
||||
{
|
||||
// Under the hood, we're secretly subclassing this C++ class to store a
|
||||
|
@ -89,7 +90,7 @@ namespace Mono.VisualC.Interop {
|
|||
}
|
||||
|
||||
// Alloc a new C++ instance when there is no managed wrapper.
|
||||
public CppInstancePtr (int nativeSize)
|
||||
internal CppInstancePtr (int nativeSize)
|
||||
{
|
||||
ptr = Marshal.AllocHGlobal (nativeSize);
|
||||
manage_memory = true;
|
||||
|
@ -101,6 +102,11 @@ namespace Mono.VisualC.Interop {
|
|||
if (native == IntPtr.Zero)
|
||||
throw new ArgumentOutOfRangeException ("native cannot be null pointer");
|
||||
|
||||
// Kludge! CppInstancePtr doesn't know whether this class is virtual or not, but we'll just assume that either
|
||||
// way it's at least sizeof(void*) and read what would be the vtptr anyway. Supposedly, if it's not virtual,
|
||||
// the wrappers won't use this field anyway...
|
||||
native_vtptr = Marshal.ReadIntPtr (native);
|
||||
|
||||
ptr = native;
|
||||
manage_memory = false;
|
||||
}
|
||||
|
|
|
@ -103,9 +103,9 @@ namespace Mono.VisualC.Interop {
|
|||
|
||||
public virtual void AddBase (CppTypeInfo baseType)
|
||||
{
|
||||
|
||||
// by default, do not add another vtable for this new base class
|
||||
AddBase (baseType, false);
|
||||
// by default, if we already have base class(es), this base's virtual methods are not included before the derived class's
|
||||
var addVTable = base_classes.Count >= 1;
|
||||
AddBase (baseType, addVTable);
|
||||
}
|
||||
|
||||
protected virtual void AddBase (CppTypeInfo baseType, bool addVTable)
|
||||
|
@ -114,34 +114,38 @@ namespace Mono.VisualC.Interop {
|
|||
return;
|
||||
|
||||
base_classes.Add (baseType);
|
||||
|
||||
bool addVTablePointer = addVTable || base_classes.Count > 1;
|
||||
int baseVMethodCount = baseType.virtual_methods.Count;
|
||||
|
||||
if (addVTable) {
|
||||
// If we are adding a new vtable, don't skew the offsets of the of this subclass's methods.
|
||||
// Instead append the new virtual methods to the end.
|
||||
|
||||
for (int i = 0; i < baseVMethodCount; i++)
|
||||
virtual_methods.Add (baseType.virtual_methods [i]);
|
||||
|
||||
vt_delegate_types.Add (baseVMethodCount);
|
||||
vt_overrides.Add (baseVMethodCount);
|
||||
|
||||
} else {
|
||||
|
||||
if (!addVTable) {
|
||||
// If we're not adding a new vtable, then all this base class's virtual methods go in primary vtable
|
||||
// Skew the offsets of this subclass's vmethods to account for the new base vmethods.
|
||||
|
||||
int baseVMethodCount = baseType.virtual_methods.Count;
|
||||
for (int i = 0; i < baseVMethodCount; i++)
|
||||
virtual_methods.Insert (BaseVTableSlots + i, baseType.virtual_methods [i]);
|
||||
|
||||
BaseVTableSlots += baseVMethodCount;
|
||||
vt_delegate_types.PrependLast (baseType.vt_delegate_types);
|
||||
//vt_overrides.PrependLast (baseType.vt_overrides);
|
||||
vt_delegate_types.Add (baseVMethodCount);
|
||||
vt_overrides.Add (baseVMethodCount);
|
||||
|
||||
} else {
|
||||
// FIXME: Implement this when we get around to msvc again ?
|
||||
}
|
||||
|
||||
field_offset_padding_without_vtptr += baseType.native_size +
|
||||
(addVTablePointer? baseType.FieldOffsetPadding : baseType.field_offset_padding_without_vtptr);
|
||||
}
|
||||
|
||||
public virtual TBase Cast<TBase> (ICppObject instance)
|
||||
where TBase : ICppObject
|
||||
public virtual CppInstancePtr Cast (ICppObject instance, Type targetType)
|
||||
{
|
||||
var targetType = typeof (TBase);
|
||||
var found = false;
|
||||
int offset = 0;
|
||||
|
||||
|
@ -162,11 +166,7 @@ namespace Mono.VisualC.Interop {
|
|||
// it is Disposed, even if wrappers created here still exist and are pointing to it. :/
|
||||
// The casted wrapper created here may be Disposed safely though.
|
||||
// FIXME: On NET_4_0 use IntPtr.Add
|
||||
var cppip = new CppInstancePtr (new IntPtr (instance.Native.Native.ToInt64 () + offset));
|
||||
|
||||
// Ugh, this requires boxing of cppip AND some slow reflection.. please cache the result of this!
|
||||
// FIXME: Perhaps Reflection.Emit all possible base casts and eliminate this beast?
|
||||
return (TBase)Activator.CreateInstance (targetType, cppip);
|
||||
return new CppInstancePtr (new IntPtr (instance.Native.Native.ToInt64 () + offset));
|
||||
}
|
||||
|
||||
public int CountBases (Func<CppTypeInfo, bool> predicate)
|
||||
|
@ -189,14 +189,10 @@ namespace Mono.VisualC.Interop {
|
|||
|
||||
TypeComplete = true;
|
||||
|
||||
// Tthis predicate ensures that duplicates are only removed
|
||||
// if declared in different classes (i.e. overridden methods).
|
||||
// We usually want to allow the same exact virtual methods to appear
|
||||
// multiple times, in the case of nonvirtual diamond inheritance, for example.
|
||||
RemoveVTableDuplicates ((pi1, pi2) => !pi1.OrigMethod.Equals (pi2.OrigMethod));
|
||||
RemoveVTableDuplicates ();
|
||||
}
|
||||
|
||||
protected virtual void RemoveVTableDuplicates (Func<PInvokeSignature,PInvokeSignature,bool> pred)
|
||||
protected virtual void RemoveVTableDuplicates ()
|
||||
{
|
||||
// check that any virtual methods overridden in a subclass are only included once
|
||||
var vsignatures = new Dictionary<MethodSignature,PInvokeSignature> (MethodSignature.EqualityComparer);
|
||||
|
@ -208,14 +204,29 @@ namespace Mono.VisualC.Interop {
|
|||
|
||||
PInvokeSignature existing;
|
||||
if (vsignatures.TryGetValue (sig, out existing)) {
|
||||
if (pred (sig, existing))
|
||||
virtual_methods.RemoveAt (i--);
|
||||
OnVTableDuplicate (ref i, sig, existing);
|
||||
} else {
|
||||
vsignatures.Add (sig, sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual bool OnVTableDuplicate (ref int iter, PInvokeSignature sig, PInvokeSignature dup)
|
||||
{
|
||||
// This predicate ensures that duplicates are only removed
|
||||
// if declared in different classes (i.e. overridden methods).
|
||||
// We usually want to allow the same exact virtual methods to appear
|
||||
// multiple times, in the case of nonvirtual diamond inheritance, for example.
|
||||
if (!sig.OrigMethod.Equals (dup.OrigMethod)) {
|
||||
virtual_methods.RemoveAt (iter--);
|
||||
vt_overrides.Remove (1);
|
||||
vt_delegate_types.Remove (1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual T GetAdjustedVirtualCall<T> (CppInstancePtr instance, int derivedVirtualMethodIndex)
|
||||
where T : class /* Delegate */
|
||||
{
|
||||
|
|
|
@ -48,7 +48,6 @@ FILES = \
|
|||
ABI/Impl/ItaniumAbi.cs \
|
||||
ABI/Impl/ItaniumTypeInfo.cs \
|
||||
ABI/Impl/MsvcAbi.cs \
|
||||
ABI/Impl/MsvcTypeInfo.cs \
|
||||
ABI/Impl/VirtualOnlyAbi.cs \
|
||||
ABI/MethodType.cs \
|
||||
ABI/VTable.cs \
|
||||
|
|
|
@ -76,7 +76,6 @@
|
|||
<Compile Include="Util\LazyGeneratedList.cs" />
|
||||
<Compile Include="Util\DelegateTypeCache.cs" />
|
||||
<Compile Include="Util\ReflectionHelper.cs" />
|
||||
<Compile Include="ABI\Impl\MsvcTypeInfo.cs" />
|
||||
<Compile Include="Util\MethodSignature.cs" />
|
||||
<Compile Include="CppModifiers.cs" />
|
||||
<Compile Include="ABI\Impl\ItaniumTypeInfo.cs" />
|
||||
|
|
|
@ -32,50 +32,19 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Mono.VisualC.Interop.Util {
|
||||
|
||||
public class LazyGeneratedList<TItem> : IList<TItem> where TItem : class {
|
||||
|
||||
private class Node<TItem> where TItem : class {
|
||||
|
||||
public LazyGeneratedList<TItem> List { get; set; }
|
||||
public Node<TItem> Next { get; set; }
|
||||
public Node (LazyGeneratedList<TItem> list, Node<TItem> next)
|
||||
{
|
||||
this.List = list;
|
||||
this.Next = next;
|
||||
}
|
||||
public void AppendNext (Node<TItem> node)
|
||||
{
|
||||
if (Next == null)
|
||||
Next = node;
|
||||
else
|
||||
Next.AppendNext (node);
|
||||
}
|
||||
public TItem this [int index] {
|
||||
get {
|
||||
if (index >= List.Count)
|
||||
return Next [index - List.Count];
|
||||
return List [index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LazyGeneratedList<TItem> : IList<TItem>
|
||||
where TItem : class
|
||||
{
|
||||
private TItem [] cache;
|
||||
private Func<int, TItem> generator;
|
||||
|
||||
private Node<TItem> previous;
|
||||
private Node<TItem> next;
|
||||
private int lead, content, follow;
|
||||
|
||||
private HashSet<int> removed;
|
||||
private int count;
|
||||
|
||||
public LazyGeneratedList (int count, Func<int, TItem> generator)
|
||||
{
|
||||
this.cache = new TItem [count];
|
||||
this.generator = generator;
|
||||
this.lead = 0;
|
||||
this.content = count;
|
||||
this.follow = 0;
|
||||
this.removed = new HashSet<int> ();
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public IEnumerator<TItem> GetEnumerator ()
|
||||
|
@ -89,86 +58,37 @@ namespace Mono.VisualC.Interop.Util {
|
|||
}
|
||||
|
||||
public int Count {
|
||||
get { return lead + content + follow; }
|
||||
get { return count; }
|
||||
}
|
||||
|
||||
public bool IsReadOnly {
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public TItem this [int index] {
|
||||
public TItem this [int i] {
|
||||
get {
|
||||
return ForIndex (index, i => previous [i], i => (cache [i] == null? (cache [i] = generator (i)) : cache [i]), i => next [i]);
|
||||
// access to cache [i] will throw the IndexOutOfRange exception for us
|
||||
return cache [i] == null? (cache [i] = generator (i)) : cache [i];
|
||||
}
|
||||
set {
|
||||
throw new NotSupportedException ("This IList is read only");
|
||||
}
|
||||
}
|
||||
|
||||
private TItem ForIndex (int index, Func<int,TItem> leadAction, Func<int,TItem> contentAction, Func<int,TItem> followAction)
|
||||
public void Add (int count)
|
||||
{
|
||||
if (removed.Contains (index))
|
||||
index++;
|
||||
|
||||
if (index < lead) {
|
||||
if (previous != null && index >= 0)
|
||||
return leadAction (index);
|
||||
throw new IndexOutOfRangeException (index.ToString ());
|
||||
}
|
||||
|
||||
int realIndex = index - lead;
|
||||
if (realIndex >= content) {
|
||||
int followIndex = realIndex - content;
|
||||
if (next != null && followIndex < follow)
|
||||
return followAction (followIndex);
|
||||
throw new IndexOutOfRangeException (index.ToString ());
|
||||
}
|
||||
|
||||
return contentAction (realIndex);
|
||||
this.count += count;
|
||||
// flush cache
|
||||
cache = new TItem [this.count];
|
||||
}
|
||||
public void Remove (int count)
|
||||
{
|
||||
this.count -= count;
|
||||
// flush cache
|
||||
cache = new TItem [this.count];
|
||||
}
|
||||
|
||||
/* Visual aid for the behavior of the following methods:
|
||||
|
||||
|<Prepended Range><Generated Range><Appended Range>|
|
||||
^ ^ ^ ^
|
||||
PrependFirst PrependLast AppendFirst AppendLast
|
||||
*/
|
||||
|
||||
public void AppendFirst (LazyGeneratedList<TItem> list)
|
||||
{
|
||||
follow += list.Count;
|
||||
next = new Node<TItem> (list, next);
|
||||
}
|
||||
|
||||
public void AppendLast (LazyGeneratedList<TItem> list)
|
||||
{
|
||||
var node = new Node<TItem> (list, null);
|
||||
if (next == null)
|
||||
next = node;
|
||||
else
|
||||
next.AppendNext (node);
|
||||
|
||||
follow += list.Count;
|
||||
}
|
||||
|
||||
public void PrependLast (LazyGeneratedList<TItem> list)
|
||||
{
|
||||
var node = new Node<TItem> (list, null);
|
||||
if (previous == null)
|
||||
previous = node;
|
||||
else
|
||||
previous.AppendNext (node);
|
||||
|
||||
lead += list.Count;
|
||||
}
|
||||
|
||||
public void PrependFirst (LazyGeneratedList<TItem> list)
|
||||
{
|
||||
lead += list.Count;
|
||||
previous = new Node<TItem> (list, previous);
|
||||
}
|
||||
|
||||
// FIXME: Should probably implement these 3 at some point
|
||||
// FIXME: Should probably implement these at some point
|
||||
public bool Contains (TItem item)
|
||||
{
|
||||
throw new NotImplementedException ();
|
||||
|
@ -181,24 +101,13 @@ namespace Mono.VisualC.Interop.Util {
|
|||
{
|
||||
throw new NotImplementedException ();
|
||||
}
|
||||
|
||||
|
||||
public void Insert (int index, TItem item)
|
||||
{
|
||||
throw new NotImplementedException ();
|
||||
}
|
||||
public void RemoveAt (int index)
|
||||
{
|
||||
while (removed.Contains (index))
|
||||
index++;
|
||||
|
||||
removed.Add (index);
|
||||
content--;
|
||||
}
|
||||
public void Add (int count)
|
||||
{
|
||||
content += count;
|
||||
Array.Resize (ref cache, content);
|
||||
throw new NotImplementedException ();
|
||||
}
|
||||
public void Add (TItem item)
|
||||
{
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -8,14 +8,8 @@
|
|||
var wrapper = Class.Name;
|
||||
var iface = "I" + Class.Name;
|
||||
var layout = "_" + Class.Name;
|
||||
|
||||
var initBases = "{";
|
||||
if (hasBase) {
|
||||
initBases = "\t: base (impl.TypeInfo) {";
|
||||
foreach (var nonPrimaryBase in Class.BaseClasses.Skip (1)) {
|
||||
initBases = string.Format ("{0}\n\t\t\tnew {1} (impl.TypeInfo);", initBases, nonPrimaryBase.Name);
|
||||
}
|
||||
}
|
||||
var layoutClass = (hasBase? "\t: base (impl.TypeInfo)\n\t\t{" : "{") + "\n\t\t\tLayoutClass ();";
|
||||
var initBases = (Class.BaseClasses.Count > 1 ? "\tInitBases ();\n\t\t}" : "}");
|
||||
#>
|
||||
// -------------------------------------------------------------------------
|
||||
// Managed wrapper for <#= Class.Name #>
|
||||
|
@ -94,26 +88,25 @@ namespace <#= Generator.Namespace #> {
|
|||
impl.<#= field.Name #> [Native] = value;
|
||||
}
|
||||
}
|
||||
<# }
|
||||
ClearIndent(); #>
|
||||
|
||||
<# /* Native constructor */ #>
|
||||
public <#= wrapper #> (CppInstancePtr native)
|
||||
<#= initBases #>
|
||||
Native = native;
|
||||
}
|
||||
<# } ClearIndent(); #>
|
||||
|
||||
<# /* Subclass constructor */ #>
|
||||
public <#= wrapper #> (CppTypeInfo subClass)
|
||||
<#= initBases #>
|
||||
<#= layoutClass #>
|
||||
subClass.AddBase (impl.TypeInfo);
|
||||
}
|
||||
<#= initBases #>
|
||||
|
||||
<# /* Native constructor */ #>
|
||||
public <#= wrapper #> (CppInstancePtr native)
|
||||
<#= layoutClass #>
|
||||
Native = native;
|
||||
<#= initBases #>
|
||||
|
||||
<# /* Wrapper methods */ #>
|
||||
<# PushIndent ("\t\t");
|
||||
foreach (var method in Class.Methods.Where (m => m.GenWrapperMethod)) {
|
||||
|
||||
WriteMethodHeader (method, initBases);
|
||||
WriteMethodHeader (method, layoutClass);
|
||||
|
||||
if (method.IsConstructor)
|
||||
Write ("Native = ");
|
||||
|
@ -129,8 +122,13 @@ namespace <#= Generator.Namespace #> {
|
|||
}
|
||||
|
||||
WriteParameters (method.Parameters, false, false);
|
||||
Write (");\n");
|
||||
PopIndent ();
|
||||
Write (");\n{0}}}\n\n", CurrentIndent);
|
||||
|
||||
if (method.IsConstructor)
|
||||
WriteLine (initBases);
|
||||
else
|
||||
WriteLine ("}");
|
||||
}
|
||||
ClearIndent (); #>
|
||||
|
||||
|
@ -179,23 +177,29 @@ namespace <#= Generator.Namespace #> {
|
|||
}
|
||||
ClearIndent (); #>
|
||||
|
||||
<# /* Make this wrapper castable to non-primary bases */
|
||||
foreach (var npBase in Class.BaseClasses.Skip (1)) {
|
||||
var prop = npBase.Name;
|
||||
var field = prop + "_lazy";
|
||||
#>
|
||||
// Non-primary base class implementation for <#= npBase.Name #>:
|
||||
private <#= npBase.Name #> <#= field #>;
|
||||
public <#= npBase.Name #> <#= prop #> {
|
||||
get {
|
||||
if (<#= field #> == null)
|
||||
<#= field #> = impl.TypeInfo.Cast<<#= npBase.Name #>> (this);
|
||||
return <#= field #>;
|
||||
}
|
||||
public <#= hasBase? "override" : "virtual" #> void Dispose ()
|
||||
{
|
||||
<# if (Class.Methods.Any (m => m.IsDestructor && !m.IsArtificial)) { #>
|
||||
impl.Destruct (Native);
|
||||
<# } #>
|
||||
Native.Dispose ();
|
||||
}
|
||||
|
||||
private void LayoutClass ()
|
||||
{
|
||||
<# foreach (var npBase in Class.BaseClasses.Skip (1)) { #>
|
||||
new <#= npBase.Name #> (impl.TypeInfo);
|
||||
<# } #>
|
||||
impl.TypeInfo.CompleteType ();
|
||||
}
|
||||
|
||||
<# /* Make this wrapper castable to non-primary bases */
|
||||
foreach (var npBase in Class.BaseClasses.Skip (1)) { #>
|
||||
// Non-primary base class implementation for <#= npBase.Name #>:
|
||||
public <#= npBase.Name #> <#= npBase.Name #> { get; protected set; }
|
||||
public static implicit operator <#= npBase.Name #>(<#= wrapper #> subClass)
|
||||
{
|
||||
return subClass.<#= prop #>;
|
||||
return subClass.<#= npBase.Name #>;
|
||||
}
|
||||
|
||||
<# PushIndent ("\t\t");
|
||||
|
@ -208,28 +212,27 @@ foreach (var npBase in Class.BaseClasses.Skip (1)) {
|
|||
|
||||
WriteMethodHeader (method, initBases);
|
||||
|
||||
Write ("{0}.{1} (", prop, method.FormattedName);
|
||||
Write ("{0}.{1} (", npBase.Name, method.FormattedName);
|
||||
|
||||
WriteParameters (method.Parameters, false, false);
|
||||
PopIndent ();
|
||||
Write (");\n{0}}}\n\n", CurrentIndent);
|
||||
}
|
||||
ClearIndent ();
|
||||
} #>
|
||||
|
||||
public <#= hasBase? "override" : "virtual" #> void Dispose ()
|
||||
}
|
||||
if (Class.BaseClasses.Count > 1) { #>
|
||||
private void InitBases ()
|
||||
{
|
||||
<# if (Class.Methods.Any (m => m.IsDestructor && !m.IsArtificial)) { #>
|
||||
impl.Destruct (Native);
|
||||
<# } #>
|
||||
Native.Dispose ();
|
||||
<# foreach (var npBase in Class.BaseClasses.Skip (1)) { #>
|
||||
<#= npBase.Name #> = new <#= npBase.Name #> (impl.TypeInfo.Cast (this, typeof (<#= npBase.Name #>)));
|
||||
<# } #>
|
||||
}
|
||||
|
||||
<# } #>
|
||||
}
|
||||
}
|
||||
|
||||
<#+
|
||||
private void WriteMethodHeader (Method method, string initBases)
|
||||
private void WriteMethodHeader (Method method, string layoutClass)
|
||||
{
|
||||
var returnType = GetCSharpType (method.ReturnType);
|
||||
|
||||
|
@ -253,7 +256,7 @@ private void WriteMethodHeader (Method method, string initBases)
|
|||
Write (")\n");
|
||||
|
||||
if (method.IsConstructor)
|
||||
WriteLine (initBases);
|
||||
WriteLine (layoutClass);
|
||||
else
|
||||
WriteLine ("{");
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче