// internal bool asCModule::AreInterfacesEqual(asCObjectType *a, asCObjectType *b, asCArray<sObjectTypePair> &equals) { // An interface is considered equal to another if the following criterias apply: // // - The interface names are equal // - The number of methods is equal // - All the methods are equal // - The order of the methods is equal // - If a method returns or takes an interface by handle or reference, both interfaces must be equal // ------------ // TODO: Study the possiblity of allowing interfaces where methods are declared in different orders to // be considered equal. The compiler and VM can handle this, but it complicates the comparison of interfaces // where multiple methods take different interfaces as parameters (or return values). Example: // // interface A // { // void f(B, C); // void f(B); // void f(C); // } // // If 'void f(B)' in module A is compared against 'void f(C)' in module B, then the code will assume // interface B in module A equals interface C in module B. Thus 'void f(B, C)' in module A won't match // 'void f(C, B)' in module B. // ------------ // Are both interfaces? if( !a->IsInterface() || !b->IsInterface() ) return false; // Are the names equal? if( a->name != b->name ) return false; // Are the number of methods equal? if( a->methods.GetLength() != b->methods.GetLength() ) return false; // Keep the number of equals in the list so we can restore it later if necessary int prevEquals = (int)equals.GetLength(); // Are the methods equal to each other? bool match = true; for( unsigned int n = 0; n < a->methods.GetLength(); n++ ) { match = false; asCScriptFunction *funcA = (asCScriptFunction*)engine->GetFunctionDescriptorById(a->methods[n]); asCScriptFunction *funcB = (asCScriptFunction*)engine->GetFunctionDescriptorById(b->methods[n]); // funcB can be null if the module that created the interface has been // discarded but the type has not yet been released by the engine. if( funcB == 0 ) break; // The methods must have the same name and the same number of parameters if( funcA->name != funcB->name || funcA->parameterTypes.GetLength() != funcB->parameterTypes.GetLength() ) break; // The return types must be equal. If the return type is an interface the interfaces must match. if( !AreTypesEqual(funcA->returnType, funcB->returnType, equals) ) break; match = true; for( unsigned int p = 0; p < funcA->parameterTypes.GetLength(); p++ ) { if( !AreTypesEqual(funcA->parameterTypes[p], funcB->parameterTypes[p], equals) || funcA->inOutFlags[p] != funcB->inOutFlags[p] ) { match = false; break; } } if( !match ) break; } // For each of the new interfaces that we're assuming to be equal, we need to validate this if( match ) { for( unsigned int n = prevEquals; n < equals.GetLength(); n++ ) { if( !AreInterfacesEqual(equals[n].a, equals[n].b, equals) ) { match = false; break; } } } if( !match ) { // The interfaces doesn't match. // Restore the list of previous equals before we go on, so // the caller can continue comparing with another interface equals.SetLength(prevEquals); } return match; }