protected override bool DoDefineMembers () { if (!base.DoDefineMembers ()) return false; Location loc = Location; Method equals = new Method (this, null, new TypeExpression (TypeManager.bool_type, loc), Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN, new MemberName ("Equals", loc), Mono.CSharp.ParametersCompiled.CreateFullyResolved (new Parameter (null, "obj", 0, null, loc), TypeManager.object_type), null); Method tostring = new Method (this, null, new TypeExpression (TypeManager.string_type, loc), Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN, new MemberName ("ToString", loc), Mono.CSharp.ParametersCompiled.EmptyReadOnlyParameters, null); ToplevelBlock equals_block = new ToplevelBlock (Compiler, equals.ParameterInfo, loc); TypeExpr current_type; if (type_params != null) { var targs = new TypeArguments (); foreach (var type_param in type_params) targs.Add (new TypeParameterExpr (type_param, type_param.Location)); current_type = new GenericTypeExpr (Definition, targs, loc); } else { current_type = new TypeExpression (Definition, loc); } equals_block.AddVariable (current_type, "other", loc); LocalVariableReference other_variable = new LocalVariableReference (equals_block, "other", loc); MemberAccess system_collections_generic = new MemberAccess (new MemberAccess ( new QualifiedAliasMember ("global", "System", loc), "Collections", loc), "Generic", loc); Expression rs_equals = null; Expression string_concat = new StringConstant ("{", loc); Expression rs_hashcode = new IntConstant (-2128831035, loc); for (int i = 0; i < parameters.Count; ++i) { var p = parameters [i]; var f = Fields [i]; MemberAccess equality_comparer = new MemberAccess (new MemberAccess ( system_collections_generic, "EqualityComparer", new TypeArguments (new SimpleName (CurrentTypeParameters [i].Name, loc)), loc), "Default", loc); Arguments arguments_equal = new Arguments (2); arguments_equal.Add (new Argument (new MemberAccess (new This (f.Location), f.Name))); arguments_equal.Add (new Argument (new MemberAccess (other_variable, f.Name))); Expression field_equal = new Invocation (new MemberAccess (equality_comparer, "Equals", loc), arguments_equal); Arguments arguments_hashcode = new Arguments (1); arguments_hashcode.Add (new Argument (new MemberAccess (new This (f.Location), f.Name))); Expression field_hashcode = new Invocation (new MemberAccess (equality_comparer, "GetHashCode", loc), arguments_hashcode); IntConstant FNV_prime = new IntConstant (16777619, loc); rs_hashcode = new Binary (Binary.Operator.Multiply, new Binary (Binary.Operator.ExclusiveOr, rs_hashcode, field_hashcode, loc), FNV_prime, loc); Expression field_to_string = new Conditional (new BooleanExpression (new Binary (Binary.Operator.Inequality, new MemberAccess (new This (f.Location), f.Name), new NullLiteral (loc), loc)), new Invocation (new MemberAccess ( new MemberAccess (new This (f.Location), f.Name), "ToString"), null), new StringConstant (string.Empty, loc), loc); if (rs_equals == null) { rs_equals = field_equal; string_concat = new Binary (Binary.Operator.Addition, string_concat, new Binary (Binary.Operator.Addition, new StringConstant (" " + p.Name + " = ", loc), field_to_string, loc), loc); continue; } // // Implementation of ToString () body using string concatenation // string_concat = new Binary (Binary.Operator.Addition, new Binary (Binary.Operator.Addition, string_concat, new StringConstant (", " + p.Name + " = ", loc), loc), field_to_string, loc); rs_equals = new Binary (Binary.Operator.LogicalAnd, rs_equals, field_equal, loc); } string_concat = new Binary (Binary.Operator.Addition, string_concat, new StringConstant (" }", loc), loc); // // Equals (object obj) override // LocalVariableReference other_variable_assign = new LocalVariableReference (equals_block, "other", loc); equals_block.AddStatement (new StatementExpression ( new SimpleAssign (other_variable_assign, new As (equals_block.GetParameterReference ("obj", loc), current_type, loc), loc))); Expression equals_test = new Binary (Binary.Operator.Inequality, other_variable, new NullLiteral (loc), loc); if (rs_equals != null) equals_test = new Binary (Binary.Operator.LogicalAnd, equals_test, rs_equals, loc); equals_block.AddStatement (new Return (equals_test, loc)); equals.Block = equals_block; equals.Define (); AddMethod (equals); // // GetHashCode () override // Method hashcode = new Method (this, null, new TypeExpression (TypeManager.int32_type, loc), Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN, new MemberName ("GetHashCode", loc), Mono.CSharp.ParametersCompiled.EmptyReadOnlyParameters, null); // // Modified FNV with good avalanche behavior and uniform // distribution with larger hash sizes. // // const int FNV_prime = 16777619; // int hash = (int) 2166136261; // foreach (int d in data) // hash = (hash ^ d) * FNV_prime; // hash += hash << 13; // hash ^= hash >> 7; // hash += hash << 3; // hash ^= hash >> 17; // hash += hash << 5; ToplevelBlock hashcode_top = new ToplevelBlock (Compiler, loc); Block hashcode_block = new Block (hashcode_top); hashcode_top.AddStatement (new Unchecked (hashcode_block, loc)); hashcode_block.AddVariable (new TypeExpression (TypeManager.int32_type, loc), "hash", loc); LocalVariableReference hash_variable = new LocalVariableReference (hashcode_block, "hash", loc); LocalVariableReference hash_variable_assign = new LocalVariableReference (hashcode_block, "hash", loc); hashcode_block.AddStatement (new StatementExpression ( new SimpleAssign (hash_variable_assign, rs_hashcode))); hashcode_block.AddStatement (new StatementExpression ( new CompoundAssign (Binary.Operator.Addition, hash_variable, new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (13, loc), loc), loc))); hashcode_block.AddStatement (new StatementExpression ( new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable, new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (7, loc), loc), loc))); hashcode_block.AddStatement (new StatementExpression ( new CompoundAssign (Binary.Operator.Addition, hash_variable, new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (3, loc), loc), loc))); hashcode_block.AddStatement (new StatementExpression ( new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable, new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (17, loc), loc), loc))); hashcode_block.AddStatement (new StatementExpression ( new CompoundAssign (Binary.Operator.Addition, hash_variable, new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (5, loc), loc), loc))); hashcode_block.AddStatement (new Return (hash_variable, loc)); hashcode.Block = hashcode_top; hashcode.Define (); AddMethod (hashcode); // // ToString () override // ToplevelBlock tostring_block = new ToplevelBlock (Compiler, loc); tostring_block.AddStatement (new Return (string_concat, loc)); tostring.Block = tostring_block; tostring.Define (); AddMethod (tostring); return true; }