Skip to content

Commit

Permalink
Refactor RealmObject to reduce the number of methods (#2013)
Browse files Browse the repository at this point in the history
* Refactor RealmObject to reduce the number of methods

* more fixes

* some comments

* Use PrimitiveValue for queries too

* some after-rebase fixes
  • Loading branch information
nirinchev committed Sep 9, 2020
1 parent 701a1f2 commit 48cec07
Show file tree
Hide file tree
Showing 13 changed files with 389 additions and 765 deletions.
42 changes: 42 additions & 0 deletions Realm/Realm.Fody/ImportedReferences.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ internal abstract class ImportedReferences

public MethodReference RealmObject_GetBacklinks { get; private set; }

public MethodReference RealmObject_GetPrimitiveValue { get; private set; }

public MethodReference RealmObject_SetPrimitiveValue { get; private set; }

public MethodReference RealmObject_SetPrimitiveValueUnique { get; private set; }

public TypeReference IRealmObjectHelper { get; private set; }

public TypeReference PreserveAttribute { get; private set; }
Expand Down Expand Up @@ -129,6 +135,8 @@ internal abstract class ImportedReferences

public MethodReference RealmSchema_AddDefaultTypes { get; private set; }

public TypeReference RealmSchema_PropertyType { get; private set; }

protected ModuleDefinition Module { get; }

protected Fody.TypeSystem Types { get; }
Expand Down Expand Up @@ -239,6 +247,7 @@ private void InitializeRealm(IMetadataScope realmAssembly)
{
Realm = new TypeReference("Realms", "Realm", Module, realmAssembly);
RealmObject = new TypeReference("Realms", "RealmObject", Module, realmAssembly);
RealmSchema_PropertyType = new TypeReference("Realms.Schema", "PropertyType", Module, realmAssembly, valueType: true);

{
RealmIntegerOfT = new TypeReference("Realms", "RealmInteger`1", Module, realmAssembly)
Expand Down Expand Up @@ -311,6 +320,34 @@ private void InitializeRealm(IMetadataScope realmAssembly)
RealmObject_GetBacklinks.Parameters.Add(new ParameterDefinition(Types.StringReference));
}

{
RealmObject_GetPrimitiveValue = new MethodReference("GetPrimitiveValue", Types.VoidReference, RealmObject) { HasThis = true };
var T = new GenericParameter(RealmObject_GetPrimitiveValue);
RealmObject_GetPrimitiveValue.ReturnType = T;
RealmObject_GetPrimitiveValue.GenericParameters.Add(T);
RealmObject_GetPrimitiveValue.Parameters.Add(new ParameterDefinition(Types.StringReference));
RealmObject_GetPrimitiveValue.Parameters.Add(new ParameterDefinition(RealmSchema_PropertyType));
}

{
RealmObject_SetPrimitiveValue = new MethodReference("SetPrimitiveValue", Types.VoidReference, RealmObject) { HasThis = true };
var T = new GenericParameter(RealmObject_SetPrimitiveValue);
RealmObject_SetPrimitiveValue.GenericParameters.Add(T);
RealmObject_SetPrimitiveValue.Parameters.Add(new ParameterDefinition(Types.StringReference));
RealmObject_SetPrimitiveValue.Parameters.Add(new ParameterDefinition(T));
RealmObject_SetPrimitiveValue.Parameters.Add(new ParameterDefinition(RealmSchema_PropertyType));
}

{
RealmObject_SetPrimitiveValueUnique = new MethodReference("SetPrimitiveValueUnique", Types.VoidReference, RealmObject) { HasThis = true };
var T = new GenericParameter(RealmObject_SetPrimitiveValueUnique);
RealmObject_SetPrimitiveValueUnique.GenericParameters.Add(T);
RealmObject_SetPrimitiveValueUnique.Parameters.Add(new ParameterDefinition(Types.StringReference));
RealmObject_SetPrimitiveValueUnique.Parameters.Add(new ParameterDefinition(T));
RealmObject_SetPrimitiveValueUnique.Parameters.Add(new ParameterDefinition(RealmSchema_PropertyType));
}


IRealmObjectHelper = new TypeReference("Realms.Weaving", "IRealmObjectHelper", Module, realmAssembly);

PreserveAttribute = new TypeReference("Realms", "PreserveAttribute", Module, realmAssembly);
Expand Down Expand Up @@ -373,6 +410,11 @@ protected AssemblyNameReference GetOrAddFrameworkReference(string assemblyName)
return assembly;
}

public FieldReference GetPropertyTypeField(string name)
{
return new FieldReference(name, RealmSchema_PropertyType, RealmSchema_PropertyType);
}

public GenericParameter GetRealmIntegerGenericParameter(IGenericParameterProvider owner)
{
var T = new GenericParameter(owner)
Expand Down
66 changes: 53 additions & 13 deletions Realm/Realm.Fody/ModuleWeaver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,21 @@ public partial class ModuleWeaver : Fody.BaseModuleWeaver
private static readonly Dictionary<string, string> _typeTable = new Dictionary<string, string>
{
{ StringTypeName, "String" },
{ CharTypeName, "Char" },
{ SingleTypeName, "Single" },
{ DoubleTypeName, "Double" },
{ BooleanTypeName, "Boolean" },
{ DateTimeOffsetTypeName, "DateTimeOffset" },
{ ByteArrayTypeName, "ByteArray" },
{ NullableCharTypeName, "NullableChar" },
{ NullableSingleTypeName, "NullableSingle" },
};

private static readonly Dictionary<string, string> _primitiveValueTypes = new Dictionary<string, string>
{
{ CharTypeName, "Int" },
{ SingleTypeName, "Float" },
{ DoubleTypeName, "Double" },
{ BooleanTypeName, "Bool" },
{ DateTimeOffsetTypeName, "Date" },
{ NullableCharTypeName, "NullableInt" },
{ NullableSingleTypeName, "NullableFloat" },
{ NullableDoubleTypeName, "NullableDouble" },
{ NullableBooleanTypeName, "NullableBoolean" },
{ NullableDateTimeOffsetTypeName, "NullableDateTimeOffset" }
{ NullableBooleanTypeName, "NullableBool" },
{ NullableDateTimeOffsetTypeName, "NullableDate" },
};

private static readonly IEnumerable<string> _realmIntegerBackedTypes = new[]
Expand Down Expand Up @@ -347,6 +351,30 @@ private WeaveResult WeaveProperty(PropertyDefinition prop, TypeDefinition type,
ReplaceGetter(prop, columnName, realmAccessors.Getter);
ReplaceSetter(prop, backingField, columnName, realmAccessors.Setter);
}
else if (_primitiveValueTypes.TryGetValue(prop.PropertyType.FullName, out var propertyType))
{
if (prop.SetMethod == null)
{
return WeaveResult.Skipped();
}

var suffix = isPrimaryKey ? "Unique" : string.Empty;
var typeId = $"{prop.PropertyType.FullName}{suffix}";

if (!methodTable.TryGetValue(typeId, out var accessors))
{
var getter = new GenericInstanceMethod(_references.RealmObject_GetPrimitiveValue) { GenericArguments = { prop.PropertyType } };
var setter = new GenericInstanceMethod(isPrimaryKey ? _references.RealmObject_SetPrimitiveValueUnique : _references.RealmObject_SetPrimitiveValue)
{
GenericArguments = { prop.PropertyType }
};
methodTable[typeId] = accessors = new Accessors { Getter = getter, Setter = setter };
}

var propertyTypeRef = _references.GetPropertyTypeField(propertyType);
ReplaceGetter(prop, columnName, accessors.Getter, propertyTypeRef);
ReplaceSetter(prop, backingField, columnName, accessors.Setter, propertyTypeRef);
}
else if (_realmIntegerBackedTypes.Contains(prop.PropertyType.FullName))
{
// If the property is automatic but doesn't have a setter, we should still ignore it.
Expand Down Expand Up @@ -425,7 +453,8 @@ private WeaveResult WeaveProperty(PropertyDefinition prop, TypeDefinition type,
var elementType = ((GenericInstanceType)prop.PropertyType).GenericArguments.Single();
if (!elementType.Resolve().BaseType.IsSameAs(_references.RealmObject) &&
!_realmIntegerBackedTypes.Contains(elementType.FullName) &&
!_typeTable.ContainsKey(elementType.FullName))
!_typeTable.ContainsKey(elementType.FullName) &&
!_primitiveValueTypes.ContainsKey(elementType.FullName))
{
return WeaveResult.Error($"{type.Name}.{prop.Name} is an IList but its generic type is {elementType.Name} which is not supported by Realm.");
}
Expand Down Expand Up @@ -529,8 +558,9 @@ private Accessors GetAccessors(TypeReference backingType, bool isPrimaryKey, IDi
var getter = new MethodReference($"Get{typeName}Value", backingType, _references.RealmObject)
{
HasThis = true,
Parameters = { new ParameterDefinition(ModuleDefinition.TypeSystem.String) }
Parameters = { new ParameterDefinition(ModuleDefinition.TypeSystem.String) },
};

var setter = new MethodReference($"Set{typeName}Value" + (isPrimaryKey ? "Unique" : string.Empty), ModuleDefinition.TypeSystem.Void, _references.RealmObject)
{
HasThis = true,
Expand All @@ -547,7 +577,7 @@ private Accessors GetAccessors(TypeReference backingType, bool isPrimaryKey, IDi
return realmAccessors;
}

private void ReplaceGetter(PropertyDefinition prop, string columnName, MethodReference getValueReference)
private void ReplaceGetter(PropertyDefinition prop, string columnName, MethodReference getValueReference, FieldReference propertyTypeRef = null)
{
//// A synthesized property getter looks like this:
//// 0: ldarg.0
Expand Down Expand Up @@ -576,6 +606,11 @@ private void ReplaceGetter(PropertyDefinition prop, string columnName, MethodRef
il.InsertBefore(start, il.Create(OpCodes.Brfalse_S, start));
il.InsertBefore(start, il.Create(OpCodes.Ldarg_0)); // this for call
il.InsertBefore(start, il.Create(OpCodes.Ldstr, columnName)); // [stack = this | name ]
if (propertyTypeRef != null)
{
il.InsertBefore(start, il.Create(OpCodes.Ldc_I4, (int)(byte)propertyTypeRef.Resolve().Constant));
}

il.InsertBefore(start, il.Create(OpCodes.Call, getValueReference));
il.InsertBefore(start, il.Create(OpCodes.Ret));

Expand Down Expand Up @@ -767,7 +802,7 @@ private void ReplaceBacklinksGetter(PropertyDefinition prop, FieldReference back
Debug.Write("[get list] ");
}

private void ReplaceSetter(PropertyDefinition prop, FieldReference backingField, string columnName, MethodReference setValueReference)
private void ReplaceSetter(PropertyDefinition prop, FieldReference backingField, string columnName, MethodReference setValueReference, FieldReference propertyTypeRef = null)
{
//// A synthesized property setter looks like this:
//// 0: ldarg.0
Expand Down Expand Up @@ -829,6 +864,11 @@ private void ReplaceSetter(PropertyDefinition prop, FieldReference backingField,
il.Append(managedSetStart);
il.Append(il.Create(OpCodes.Ldstr, columnName));
il.Append(il.Create(OpCodes.Ldarg_1));
if (propertyTypeRef != null)
{
il.Append(il.Create(OpCodes.Ldc_I4, (int)(byte)propertyTypeRef.Resolve().Constant));
}

il.Append(il.Create(OpCodes.Call, setValueReference));
il.Append(il.Create(OpCodes.Ret));

Expand Down
18 changes: 11 additions & 7 deletions Realm/Realm/Dynamic/MetaRealmObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ internal class MetaRealmObject : DynamicMetaObject
.MakeGenericMethod(typeof(DynamicRealmObject));

private static readonly MethodInfo PrimitiveValueGetMethod = typeof(PrimitiveValue).GetMethod(nameof(PrimitiveValue.Get), BindingFlags.Public | BindingFlags.Instance);
private static readonly MethodInfo CreatePrimitiveMethod = typeof(PrimitiveValue).GetMethod(nameof(PrimitiveValue.Generic), BindingFlags.Public | BindingFlags.Static);
private static readonly MethodInfo CreatePrimitiveMethod = typeof(PrimitiveValue).GetMethod(nameof(PrimitiveValue.Create), BindingFlags.Public | BindingFlags.Static);

private static readonly ObjectHandle DummyHandle = new ObjectHandle(null, IntPtr.Zero);

Expand Down Expand Up @@ -144,7 +144,7 @@ public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
case PropertyType.Int:
case PropertyType.Bool:
case Schema.PropertyType.Float:
case PropertyType.Float:
case PropertyType.Double:
case PropertyType.Date:
arguments.Add(Expression.Constant(property.Type));
Expand Down Expand Up @@ -277,20 +277,24 @@ private Expression GetLimitedSelf()
return convertedExpression;
}

// GetString(colKey)
// GetByteArray(colKey)
private static MethodInfo GetGetMethod<TResult>(Func<ColumnKey, TResult> @delegate) => @delegate.GetMethodInfo();

// GetPrimitive(colKey, propertyType)
private static MethodInfo GetGetMethod<TResult>(Func<ColumnKey, PropertyType, TResult> @delegate) => @delegate.GetMethodInfo();

// GetBacklinks(propertyIndex)
private static MethodInfo GetGetMethod<TResult>(Func<IntPtr, TResult> @delegate) => @delegate.GetMethodInfo();

private static MethodInfo GetSetMethod<TValue>(Action<ColumnKey, TValue> @delegate) => @delegate.GetMethodInfo();

// SetXXXUnique(colKey, isNullable, value)
private static MethodInfo GetSetMethod<TValue>(Action<ColumnKey, bool, TValue> @delegate) => @delegate.GetMethodInfo();

// GetList(realm, colKey, objectType)
// GetObject(realm, colKey, objectType)
private static MethodInfo GetGetMethod<TResult>(Func<Realm, ColumnKey, string, TResult> @delegate) => @delegate.GetMethodInfo();

// SetXXX(colKey)
private static MethodInfo GetSetMethod<TValue>(Action<ColumnKey, TValue> @delegate) => @delegate.GetMethodInfo();

// SetObject(realm, colKey)
private static MethodInfo GetSetMethod<TValue>(Action<Realm, ColumnKey, TValue> @delegate) => @delegate.GetMethodInfo();
}
}
Loading

0 comments on commit 48cec07

Please sign in to comment.