/* This file contains the implementation of class Protocol. Copyright (C) 1993, 2004, 2009 Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. Under Section 7 of GPL version 3, you are granted additional permissions described in the GCC Runtime Library Exception, version 3.1, as published by the Free Software Foundation. You should have received a copy of the GNU General Public License and a copy of the GCC Runtime Library Exception along with this program; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ #include "objc-private/common.h" #include "objc/Protocol.h" #include "objc/objc-api.h" /* Method description list */ struct objc_method_description_list { int count; struct objc_method_description list[1]; }; @implementation Protocol { @private char *protocol_name; struct objc_protocol_list *protocol_list; struct objc_method_description_list *instance_methods, *class_methods; } /* Obtaining attributes intrinsic to the protocol */ - (const char *)name { return protocol_name; } /* Testing protocol conformance */ - (BOOL) conformsTo: (Protocol *)aProtocolObject { size_t i; struct objc_protocol_list* proto_list; if (aProtocolObject == nil) return NO; if (!strcmp(aProtocolObject->protocol_name, self->protocol_name)) return YES; for (proto_list = protocol_list; proto_list; proto_list = proto_list->next) { for (i=0; i < proto_list->count; i++) { if ([proto_list->list[i] conformsTo: aProtocolObject]) return YES; } } return NO; } /* Looking up information specific to a protocol */ - (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel { int i; struct objc_protocol_list* proto_list; const char* name = sel_get_name (aSel); struct objc_method_description *result; if (instance_methods) for (i = 0; i < instance_methods->count; i++) { if (!strcmp ((char*)instance_methods->list[i].name, name)) return &(instance_methods->list[i]); } for (proto_list = protocol_list; proto_list; proto_list = proto_list->next) { size_t j; for (j=0; j < proto_list->count; j++) { if ((result = [proto_list->list[j] descriptionForInstanceMethod: aSel])) return result; } } return NULL; } - (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel; { int i; struct objc_protocol_list* proto_list; const char* name = sel_get_name (aSel); struct objc_method_description *result; if (class_methods) for (i = 0; i < class_methods->count; i++) { if (!strcmp ((char*)class_methods->list[i].name, name)) return &(class_methods->list[i]); } for (proto_list = protocol_list; proto_list; proto_list = proto_list->next) { size_t j; for (j=0; j < proto_list->count; j++) { if ((result = [proto_list->list[j] descriptionForClassMethod: aSel])) return result; } } return NULL; } - (unsigned) hash { /* Compute a hash of the protocol_name; use the same hash algorithm * that we use for class names; protocol names and class names are * somewhat similar types of string spaces. */ int hash = 0, index; for (index = 0; protocol_name[index] != '\0'; index++) { hash = (hash << 4) ^ (hash >> 28) ^ protocol_name[index]; } hash = (hash ^ (hash >> 10) ^ (hash >> 20)); return hash; } /* * Equality between formal protocols is only formal (nothing to do * with actually checking the list of methods they have!). Two formal * Protocols are equal if and only if they have the same name. * * Please note (for comparisons with other implementations) that * checking the names is equivalent to checking that Protocol A * conforms to Protocol B and Protocol B conforms to Protocol A, * because this happens iff they have the same name. If they have * different names, A conforms to B if and only if A includes B, but * the situation where A includes B and B includes A is a circular * dependency between Protocols which is forbidden by the compiler, so * A conforms to B and B conforms to A with A and B having different * names is an impossible case. */ - (BOOL) isEqual: (id)obj { if (obj == self) return YES; if ([obj isKindOf: [Protocol class]]) { if (strcmp (protocol_name, ((Protocol *)obj)->protocol_name) == 0) return YES; } return NO; } @end