xref: /netbsd-src/external/gpl3/gcc.old/dist/libobjc/Protocol.m (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1/* This file contains the implementation of class Protocol.
2   Copyright (C) 1993, 2004, 2009 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 3, or (at your option)
9any later version.
10
11GCC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14GNU General Public License for more details.
15
16Under Section 7 of GPL version 3, you are granted additional
17permissions described in the GCC Runtime Library Exception, version
183.1, as published by the Free Software Foundation.
19
20You should have received a copy of the GNU General Public License and
21a copy of the GCC Runtime Library Exception along with this program;
22see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23<http://www.gnu.org/licenses/>.  */
24
25#include "objc/Protocol.h"
26#include "objc/objc-api.h"
27
28/* Method description list */
29struct objc_method_description_list {
30        int count;
31        struct objc_method_description list[1];
32};
33
34
35@implementation Protocol
36{
37@private
38        char *protocol_name;
39        struct objc_protocol_list *protocol_list;
40        struct objc_method_description_list *instance_methods, *class_methods;
41}
42
43/* Obtaining attributes intrinsic to the protocol */
44
45- (const char *)name
46{
47  return protocol_name;
48}
49
50/* Testing protocol conformance */
51
52- (BOOL) conformsTo: (Protocol *)aProtocolObject
53{
54  size_t i;
55  struct objc_protocol_list* proto_list;
56
57  if (aProtocolObject == nil)
58    return NO;
59
60  if (!strcmp(aProtocolObject->protocol_name, self->protocol_name))
61    return YES;
62
63  for (proto_list = protocol_list; proto_list; proto_list = proto_list->next)
64    {
65      for (i=0; i < proto_list->count; i++)
66	{
67	  if ([proto_list->list[i] conformsTo: aProtocolObject])
68	    return YES;
69	}
70    }
71
72  return NO;
73}
74
75/* Looking up information specific to a protocol */
76
77- (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel
78{
79  int i;
80  struct objc_protocol_list* proto_list;
81  const char* name = sel_get_name (aSel);
82  struct objc_method_description *result;
83
84  if (instance_methods)
85    for (i = 0; i < instance_methods->count; i++)
86      {
87	if (!strcmp ((char*)instance_methods->list[i].name, name))
88	  return &(instance_methods->list[i]);
89      }
90
91  for (proto_list = protocol_list; proto_list; proto_list = proto_list->next)
92    {
93      size_t j;
94      for (j=0; j < proto_list->count; j++)
95	{
96	  if ((result = [proto_list->list[j]
97			 descriptionForInstanceMethod: aSel]))
98	    return result;
99	}
100    }
101
102  return NULL;
103}
104
105- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel;
106{
107  int i;
108  struct objc_protocol_list* proto_list;
109  const char* name = sel_get_name (aSel);
110  struct objc_method_description *result;
111
112  if (class_methods)
113    for (i = 0; i < class_methods->count; i++)
114      {
115	if (!strcmp ((char*)class_methods->list[i].name, name))
116	  return &(class_methods->list[i]);
117      }
118
119  for (proto_list = protocol_list; proto_list; proto_list = proto_list->next)
120    {
121      size_t j;
122      for (j=0; j < proto_list->count; j++)
123	{
124	  if ((result = [proto_list->list[j]
125			 descriptionForClassMethod: aSel]))
126	    return result;
127	}
128    }
129
130  return NULL;
131}
132
133- (unsigned) hash
134{
135  /* Compute a hash of the protocol_name; use the same hash algorithm
136   * that we use for class names; protocol names and class names are
137   * somewhat similar types of string spaces.
138   */
139  int hash = 0, index;
140
141  for (index = 0; protocol_name[index] != '\0'; index++)
142    {
143      hash = (hash << 4) ^ (hash >> 28) ^ protocol_name[index];
144    }
145
146  hash = (hash ^ (hash >> 10) ^ (hash >> 20));
147
148  return hash;
149}
150
151/*
152 * Equality between formal protocols is only formal (nothing to do
153 * with actually checking the list of methods they have!).  Two formal
154 * Protocols are equal if and only if they have the same name.
155 *
156 * Please note (for comparisons with other implementations) that
157 * checking the names is equivalent to checking that Protocol A
158 * conforms to Protocol B and Protocol B conforms to Protocol A,
159 * because this happens iff they have the same name.  If they have
160 * different names, A conforms to B if and only if A includes B, but
161 * the situation where A includes B and B includes A is a circular
162 * dependency between Protocols which is forbidden by the compiler, so
163 * A conforms to B and B conforms to A with A and B having different
164 * names is an impossible case.
165 */
166- (BOOL) isEqual: (id)obj
167{
168  if (obj == self)
169    return YES;
170
171  if ([obj isKindOf: [Protocol class]])
172    {
173      if (strcmp (protocol_name, ((Protocol *)obj)->protocol_name) == 0)
174	return YES;
175    }
176
177  return NO;
178}
179@end
180
181