Anasayfa
UO Sunucular
Forumlar
Profilim
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using Server;

namespace Server.Commands.Generic
{
public static class DistinctCompiler
{
public static IComparer Compile( AssemblyEmitter assembly, Type objectType, Property[] props )
{
TypeBuilder typeBuilder = assembly.DefineType(
"__distinct",
TypeAttributes.Public,
typeof( object )
);

#region Constructor
{
ConstructorBuilder ctor = typeBuilder.DefineConstructor(
MethodAttributes.Public,
CallingConventions.Standard,
Type.EmptyTypes
);

ILGenerator il = ctor.GetILGenerator();

// : base()
il.Emit( OpCodes.Ldarg_0 );
il.Emit( OpCodes.Call, typeof( object ).GetConstructor( Type.EmptyTypes ) );

// return;
il.Emit( OpCodes.Ret );
}
#endregion

#region IComparer
typeBuilder.AddInterfaceImplementation( typeof( IComparer ) );

MethodBuilder compareMethod;

#region Compare
{
MethodEmitter emitter = new MethodEmitter( typeBuilder );

emitter.Define(
/*  name  */ "Compare",
/*  attr  */ MethodAttributes.Public | MethodAttributes.Virtual,
/* return */ typeof( int ),
/* params */ new Type[] { typeof( object ), typeof( object ) } );

LocalBuilder a = emitter.CreateLocal( objectType );
LocalBuilder b = emitter.CreateLocal( objectType );

LocalBuilder v = emitter.CreateLocal( typeof( int ) );

emitter.LoadArgument( 1 );
emitter.CastAs( objectType );
emitter.StoreLocal( a );

emitter.LoadArgument( 2 );
emitter.CastAs( objectType );
emitter.StoreLocal( b );

emitter.Load( 0 );
emitter.StoreLocal( v );

Label end = emitter.CreateLabel();

for ( int i = 0; i < props.Length; ++i )
{
if ( i > 0 )
{
emitter.LoadLocal( v );
emitter.BranchIfTrue( end ); // if ( v != 0 ) return v;
}

Property prop = props[i];

emitter.LoadLocal( a );
emitter.Chain( prop );

bool couldCompare =
emitter.CompareTo( 1, delegate()
{
emitter.LoadLocal( b );
emitter.Chain( prop );
} );

if ( !couldCompare )
throw new InvalidOperationException( "Property is not comparable." );

emitter.StoreLocal( v );
}

emitter.MarkLabel( end );

emitter.LoadLocal( v );
emitter.Return();

typeBuilder.DefineMethodOverride(
emitter.Method,
typeof( IComparer ).GetMethod(
"Compare",
new Type[]
{
typeof( object ),
typeof( object )
}
)
);

compareMethod = emitter.Method;
}
#endregion
#endregion

#region IEqualityComparer
typeBuilder.AddInterfaceImplementation( typeof( IEqualityComparer<object> ) );

#region Equals
{
MethodEmitter emitter = new MethodEmitter( typeBuilder );

emitter.Define(
/*  name  */ "Equals",
/*  attr  */ MethodAttributes.Public | MethodAttributes.Virtual,
/* return */ typeof( bool ),
/* params */ new Type[] { typeof( object ), typeof( object ) } );

emitter.Generator.Emit( OpCodes.Ldarg_0 );
emitter.Generator.Emit( OpCodes.Ldarg_1 );
emitter.Generator.Emit( OpCodes.Ldarg_2 );

emitter.Generator.Emit( OpCodes.Call, compareMethod );

emitter.Generator.Emit( OpCodes.Ldc_I4_0 );

emitter.Generator.Emit( OpCodes.Ceq );

emitter.Generator.Emit( OpCodes.Ret );

typeBuilder.DefineMethodOverride(
emitter.Method,
typeof( IEqualityComparer<object> ).GetMethod(
"Equals",
new Type[]
{
typeof( object ),
typeof( object )
}
)
);
}
#endregion

#region GetHashCode
{
MethodEmitter emitter = new MethodEmitter( typeBuilder );

emitter.Define(
/*  name  */ "GetHashCode",
/*  attr  */ MethodAttributes.Public | MethodAttributes.Virtual,
/* return */ typeof( int ),
/* params */ new Type[] { typeof( object ) } );

LocalBuilder obj = emitter.CreateLocal( objectType );

emitter.LoadArgument( 1 );
emitter.CastAs( objectType );
emitter.StoreLocal( obj );

for ( int i = 0; i < props.Length; ++i )
{
Property prop = props[i];

emitter.LoadLocal( obj );
emitter.Chain( prop );

Type active = emitter.Active;

MethodInfo getHashCode = active.GetMethod( "GetHashCode", Type.EmptyTypes );

if ( getHashCode == null )
getHashCode = typeof( object ).GetMethod( "GetHashCode", Type.EmptyTypes );

if ( active != typeof( int ) )
{
if ( !active.IsValueType )
{
LocalBuilder value = emitter.AcquireTemp( active );

Label valueNotNull = emitter.CreateLabel();
Label done = emitter.CreateLabel();

emitter.StoreLocal( value );
emitter.LoadLocal( value );

emitter.BranchIfTrue( valueNotNull );

emitter.Load( 0 );
emitter.Pop( typeof( int ) );

emitter.Branch( done );

emitter.MarkLabel( valueNotNull );

emitter.LoadLocal( value );
emitter.Call( getHashCode );

emitter.ReleaseTemp( value );

emitter.MarkLabel( done );
}
else
{
emitter.Call( getHashCode );
}
}

if ( i > 0 )
emitter.Xor();
}

emitter.Return();

typeBuilder.DefineMethodOverride(
emitter.Method,
typeof( IEqualityComparer<object> ).GetMethod(
"GetHashCode",
new Type[]
{
typeof( object )
}
)
);
}
#endregion
#endregion

Type comparerType = typeBuilder.CreateType();

return (IComparer) Activator.CreateInstance( comparerType );
}
}
}

UO-Dev SPONSOR

UO-Dev SPONSOR

Henüz yorum yapılmamış. Yorum yazabilmek için giriş yapmanız gerekir.

Üyelerin oylama ortalaması (10 dışında) :

Henüz Oylanmamış

Oylar: 0