Initial revision

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@206 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Andrew McCallum 1995-03-24 21:50:00 +00:00
parent ccdd9fa46c
commit c10655a5bc
4 changed files with 788 additions and 0 deletions

View file

@ -0,0 +1,43 @@
/* Interface for behaviors for Obj-C, "for Protocols with implementations".
Copyright (C) 1995 Free Software Foundation, Inc.
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
Date: March 1995
This file is part of the GNU Objective C Class Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __behavior_h_OBJECTS_INCLUDE
#define __behavior_h_OBJECTS_INCLUDE
/* Call this method from CLASS's +initialize method to add a behavior
to CLASS. A "behavior" is like a protocol with an implementation.
This functions adds to CLASS all the instance and factory methods
of BEHAVIOR as well as the instance and factory methods of
BEHAVIOR's superclasses (We stop adding super classes as soon as we
encounter a common ancestor.) CLASS and BEHAVIOR should share the
same instance variable layout.
xxx We do not yet deal with Protocols, but we should. */
void class_add_behavior (Class class, Class behavior);
/* Set to non-zero if you want debugging messages on stderr. */
void set_behavior_debug(int i);
#endif /* __behavior_h_OBJECTS_INCLUDE */

351
Source/behavior.c Normal file
View file

@ -0,0 +1,351 @@
/* Behaviors for Objective-C, "for Protocols with implementations".
Copyright (C) 1995 Free Software Foundation, Inc.
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
Date: March 1995
This file is part of the GNU Objective C Class Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* A Behavior can be seen as a "Protocol with an implementation" or a
"Class without any instance variables". A key feature of behaviors
is that they give a degree of multiple inheritance.
xxx not necessarily on the "no instance vars". The behavior just has
to have the same layout as the class.
The following function is a sneaky hack way that provides Behaviors
without adding any new syntax to the Objective C language. Simply
define a class with the methods you want in the behavior, then call
this function with that class as the BEHAVIOR argument.
This function should be called in CLASS's +initialize method.
If you add several behaviors to a class, be aware that the order of
the additions is significant.
*/
#include <objc/objc.h>
#include <objc/objc-api.h>
#include <objc/sarray.h>
#include <objects/objc-malloc.h>
#include <assert.h>
static int debug_behavior = 0;
static Method_t search_for_method_in_list (MethodList_t list, SEL op);
static void __objc_send_initialize(Class class);
#if 0
static void __objc_init_protocols (struct objc_protocol_list* protos);
static void __objc_class_add_protocols (Class class,
struct objc_protocol_list* protos);
#endif
static BOOL class_is_kind_of(Class self, Class class);
void class_add_methods_if_not_there(Class class, MethodList_t mlist);
/* xxx consider using sendmsg.c:__objc_update_dispatch_table_for_class,
but, I think it will be slower than the current method. */
void
set_behavior_debug(int i)
{
behavior_debug = i;
}
void
class_add_behavior (Class class, Class behavior)
{
Class behavior_super_class = class_get_super_class(behavior);
assert(CLS_ISCLASS(class));
assert(CLS_ISCLASS(behavior));
__objc_send_initialize(class);
__objc_send_initialize(behavior);
#if 0
/* xxx Do protocols */
if (behavior->protocols)
{
/* xxx Make sure they are not already there before adding. */
__objc_init_protocols (behavior->protocols);
__objc_class_add_protocols (class, behavior->protocols);
}
#endif
/* Add instance methods */
class_add_methods_if_not_there(class,
behavior->methods);
/* Add class methods */
class_add_methods_if_not_there(class->class_pointer,
behavior->class_pointer->methods);
/* Add behavior's superclass, if not already there. */
{
if (!class_is_kind_of(class, behavior_super_class))
class_add_behavior(class, behavior_super_class);
}
return;
}
void
class_add_methods_if_not_there(Class class, MethodList_t mlist)
{
static SEL initialize_sel = 0;
if (!initialize_sel)
initialize_sel = sel_register_name ("initialize");
/* Add methods to class->dtable and class->methods */
for ( ; mlist; mlist = mlist->method_next)
{
int counter;
MethodList_t new_list;
counter = mlist->method_count - 1;
/* xxx This is a little wasteful of memory, since not necessarily
all methods will go in here. */
new_list = (MethodList_t)
(*objc_malloc)
(sizeof(MethodList) + sizeof(struct objc_method[counter]));
new_list->method_count = 0;
while (counter >= 0)
{
Method_t method = &(mlist->method_list[counter]);
if (debug_behavior)
fprintf(stderr, "processing method %s\n",
sel_get_name(method->method_name));
if (!search_for_method_in_list(class->methods, method->method_name)
&& method->method_name->sel_id != initialize_sel->sel_id)
{
/* As long as the method isn't defined in the CLASS,
put the BEHAVIOR method in there. Thus, behavior
methods override the superclasses' methods. */
sarray_at_put_safe (class->dtable,
(sidx) method->method_name->sel_id,
method->method_imp);
new_list->method_list[new_list->method_count] = *method;
(new_list->method_count)++;
if (debug_behavior)
fprintf(stderr, "added method %s\n",
sel_get_name(method->method_name));
}
counter -= 1;
}
new_list->method_next = class->methods;
class->methods = new_list;
}
}
#if 0
/* This is like class_add_method_list(), except is doesn't balk at
duplicates; it simply ignores them. Thus, a method implemented
in CLASS overrides a method implemented in BEHAVIOR. */
void
class_add_behavior_method_list (Class class, MethodList_t list)
{
int i;
static SEL initialize_sel = 0;
if (!initialize_sel)
initialize_sel = sel_register_name ("initialize");
/* Passing of a linked list is not allowed. Do multiple calls. */
assert (!list->method_next);
/* Check for duplicates. */
for (i = 0; i < list->method_count; ++i)
{
Method_t method = &list->method_list[i];
if (method->method_name) /* Sometimes these are NULL */
{
if (search_for_method_in_list (class->methods, method->method_name)
&& method->method_name->sel_id != initialize_sel->sel_id)
{
/* Duplication. Print a error message an change the method name
to NULL. */
fprintf (stderr, "attempt to add a existing method: %s\n",
sel_get_name(method->method_name));
method->method_name = 0;
}
else
{
/* Behavior method not implemented in class. Add it. */
sarray_at_put_safe (class->dtable,
(sidx) method->method_name->sel_id,
method->method_imp);
}
}
}
/* Add the methods to the class's method list. */
list->method_next = class->methods;
class->methods = list;
}
#endif
/* Given a linked list of method and a method's name. Search for the named
method's method structure. Return a pointer to the method's method
structure if found. NULL otherwise. */
static Method_t
search_for_method_in_list (MethodList_t list, SEL op)
{
MethodList_t method_list = list;
if (! sel_is_mapped (op))
return NULL;
/* If not found then we'll search the list. */
while (method_list)
{
int i;
/* Search the method list. */
for (i = 0; i < method_list->method_count; ++i)
{
Method_t method = &method_list->method_list[i];
if (method->method_name)
if (method->method_name->sel_id == op->sel_id)
return method;
}
/* The method wasn't found. Follow the link to the next list of
methods. */
method_list = method_list->method_next;
}
return NULL;
}
/* Send +initialize to class if not already done */
static void __objc_send_initialize(Class class)
{
/* This *must* be a class object */
assert(CLS_ISCLASS(class));
assert(!CLS_ISMETA(class));
if (!CLS_ISINITIALIZED(class))
{
CLS_SETINITIALIZED(class);
CLS_SETINITIALIZED(class->class_pointer);
if(class->super_class)
__objc_send_initialize(class->super_class);
{
MethodList_t method_list = class->class_pointer->methods;
SEL op = sel_register_name ("initialize");
/* If not found then we'll search the list. */
while (method_list)
{
int i;
/* Search the method list. */
for (i = 0; i < method_list->method_count; ++i)
{
Method_t method = &method_list->method_list[i];
if (method->method_name->sel_id == op->sel_id)
(*method->method_imp)((id) class, op);
}
/* The method wasn't found. Follow the link to the next list of
methods. */
method_list = method_list->method_next;
}
}
}
}
#if 0
static void
__objc_init_protocols (struct objc_protocol_list* protos)
{
int i;
static Class proto_class = 0;
if (! protos)
return;
if (!proto_class)
proto_class = objc_lookup_class("Protocol");
if (!proto_class)
{
unclaimed_proto_list = list_cons (protos, unclaimed_proto_list);
return;
}
#if 0
assert (protos->next == 0); /* only single ones allowed */
#endif
for(i = 0; i < protos->count; i++)
{
struct objc_protocol* aProto = protos->list[i];
if (((size_t)aProto->class_pointer) == PROTOCOL_VERSION)
{
/* assign class pointer */
aProto->class_pointer = proto_class;
/* init super protocols */
__objc_init_protocols (aProto->protocol_list);
}
else if (protos->list[i]->class_pointer != proto_class)
{
fprintf (stderr,
"Version %d doesn't match runtime protocol version %d\n",
(int)((char*)protos->list[i]->class_pointer-(char*)0),
PROTOCOL_VERSION);
abort ();
}
}
}
static void __objc_class_add_protocols (Class class,
struct objc_protocol_list* protos)
{
/* Well... */
if (! protos)
return;
/* Add it... */
protos->next = class->protocols;
class->protocols = protos;
}
#endif /* 0 */
static BOOL class_is_kind_of(Class self, Class aClassObject)
{
Class class;
for (class = self; class!=Nil; class = class_get_super_class(class))
if (class==aClassObject)
return YES;
return NO;
}

351
Source/behavior.m Normal file
View file

@ -0,0 +1,351 @@
/* Behaviors for Objective-C, "for Protocols with implementations".
Copyright (C) 1995 Free Software Foundation, Inc.
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
Date: March 1995
This file is part of the GNU Objective C Class Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* A Behavior can be seen as a "Protocol with an implementation" or a
"Class without any instance variables". A key feature of behaviors
is that they give a degree of multiple inheritance.
xxx not necessarily on the "no instance vars". The behavior just has
to have the same layout as the class.
The following function is a sneaky hack way that provides Behaviors
without adding any new syntax to the Objective C language. Simply
define a class with the methods you want in the behavior, then call
this function with that class as the BEHAVIOR argument.
This function should be called in CLASS's +initialize method.
If you add several behaviors to a class, be aware that the order of
the additions is significant.
*/
#include <objc/objc.h>
#include <objc/objc-api.h>
#include <objc/sarray.h>
#include <objects/objc-malloc.h>
#include <assert.h>
static int debug_behavior = 0;
static Method_t search_for_method_in_list (MethodList_t list, SEL op);
static void __objc_send_initialize(Class class);
#if 0
static void __objc_init_protocols (struct objc_protocol_list* protos);
static void __objc_class_add_protocols (Class class,
struct objc_protocol_list* protos);
#endif
static BOOL class_is_kind_of(Class self, Class class);
void class_add_methods_if_not_there(Class class, MethodList_t mlist);
/* xxx consider using sendmsg.c:__objc_update_dispatch_table_for_class,
but, I think it will be slower than the current method. */
void
set_behavior_debug(int i)
{
behavior_debug = i;
}
void
class_add_behavior (Class class, Class behavior)
{
Class behavior_super_class = class_get_super_class(behavior);
assert(CLS_ISCLASS(class));
assert(CLS_ISCLASS(behavior));
__objc_send_initialize(class);
__objc_send_initialize(behavior);
#if 0
/* xxx Do protocols */
if (behavior->protocols)
{
/* xxx Make sure they are not already there before adding. */
__objc_init_protocols (behavior->protocols);
__objc_class_add_protocols (class, behavior->protocols);
}
#endif
/* Add instance methods */
class_add_methods_if_not_there(class,
behavior->methods);
/* Add class methods */
class_add_methods_if_not_there(class->class_pointer,
behavior->class_pointer->methods);
/* Add behavior's superclass, if not already there. */
{
if (!class_is_kind_of(class, behavior_super_class))
class_add_behavior(class, behavior_super_class);
}
return;
}
void
class_add_methods_if_not_there(Class class, MethodList_t mlist)
{
static SEL initialize_sel = 0;
if (!initialize_sel)
initialize_sel = sel_register_name ("initialize");
/* Add methods to class->dtable and class->methods */
for ( ; mlist; mlist = mlist->method_next)
{
int counter;
MethodList_t new_list;
counter = mlist->method_count - 1;
/* xxx This is a little wasteful of memory, since not necessarily
all methods will go in here. */
new_list = (MethodList_t)
(*objc_malloc)
(sizeof(MethodList) + sizeof(struct objc_method[counter]));
new_list->method_count = 0;
while (counter >= 0)
{
Method_t method = &(mlist->method_list[counter]);
if (debug_behavior)
fprintf(stderr, "processing method %s\n",
sel_get_name(method->method_name));
if (!search_for_method_in_list(class->methods, method->method_name)
&& method->method_name->sel_id != initialize_sel->sel_id)
{
/* As long as the method isn't defined in the CLASS,
put the BEHAVIOR method in there. Thus, behavior
methods override the superclasses' methods. */
sarray_at_put_safe (class->dtable,
(sidx) method->method_name->sel_id,
method->method_imp);
new_list->method_list[new_list->method_count] = *method;
(new_list->method_count)++;
if (debug_behavior)
fprintf(stderr, "added method %s\n",
sel_get_name(method->method_name));
}
counter -= 1;
}
new_list->method_next = class->methods;
class->methods = new_list;
}
}
#if 0
/* This is like class_add_method_list(), except is doesn't balk at
duplicates; it simply ignores them. Thus, a method implemented
in CLASS overrides a method implemented in BEHAVIOR. */
void
class_add_behavior_method_list (Class class, MethodList_t list)
{
int i;
static SEL initialize_sel = 0;
if (!initialize_sel)
initialize_sel = sel_register_name ("initialize");
/* Passing of a linked list is not allowed. Do multiple calls. */
assert (!list->method_next);
/* Check for duplicates. */
for (i = 0; i < list->method_count; ++i)
{
Method_t method = &list->method_list[i];
if (method->method_name) /* Sometimes these are NULL */
{
if (search_for_method_in_list (class->methods, method->method_name)
&& method->method_name->sel_id != initialize_sel->sel_id)
{
/* Duplication. Print a error message an change the method name
to NULL. */
fprintf (stderr, "attempt to add a existing method: %s\n",
sel_get_name(method->method_name));
method->method_name = 0;
}
else
{
/* Behavior method not implemented in class. Add it. */
sarray_at_put_safe (class->dtable,
(sidx) method->method_name->sel_id,
method->method_imp);
}
}
}
/* Add the methods to the class's method list. */
list->method_next = class->methods;
class->methods = list;
}
#endif
/* Given a linked list of method and a method's name. Search for the named
method's method structure. Return a pointer to the method's method
structure if found. NULL otherwise. */
static Method_t
search_for_method_in_list (MethodList_t list, SEL op)
{
MethodList_t method_list = list;
if (! sel_is_mapped (op))
return NULL;
/* If not found then we'll search the list. */
while (method_list)
{
int i;
/* Search the method list. */
for (i = 0; i < method_list->method_count; ++i)
{
Method_t method = &method_list->method_list[i];
if (method->method_name)
if (method->method_name->sel_id == op->sel_id)
return method;
}
/* The method wasn't found. Follow the link to the next list of
methods. */
method_list = method_list->method_next;
}
return NULL;
}
/* Send +initialize to class if not already done */
static void __objc_send_initialize(Class class)
{
/* This *must* be a class object */
assert(CLS_ISCLASS(class));
assert(!CLS_ISMETA(class));
if (!CLS_ISINITIALIZED(class))
{
CLS_SETINITIALIZED(class);
CLS_SETINITIALIZED(class->class_pointer);
if(class->super_class)
__objc_send_initialize(class->super_class);
{
MethodList_t method_list = class->class_pointer->methods;
SEL op = sel_register_name ("initialize");
/* If not found then we'll search the list. */
while (method_list)
{
int i;
/* Search the method list. */
for (i = 0; i < method_list->method_count; ++i)
{
Method_t method = &method_list->method_list[i];
if (method->method_name->sel_id == op->sel_id)
(*method->method_imp)((id) class, op);
}
/* The method wasn't found. Follow the link to the next list of
methods. */
method_list = method_list->method_next;
}
}
}
}
#if 0
static void
__objc_init_protocols (struct objc_protocol_list* protos)
{
int i;
static Class proto_class = 0;
if (! protos)
return;
if (!proto_class)
proto_class = objc_lookup_class("Protocol");
if (!proto_class)
{
unclaimed_proto_list = list_cons (protos, unclaimed_proto_list);
return;
}
#if 0
assert (protos->next == 0); /* only single ones allowed */
#endif
for(i = 0; i < protos->count; i++)
{
struct objc_protocol* aProto = protos->list[i];
if (((size_t)aProto->class_pointer) == PROTOCOL_VERSION)
{
/* assign class pointer */
aProto->class_pointer = proto_class;
/* init super protocols */
__objc_init_protocols (aProto->protocol_list);
}
else if (protos->list[i]->class_pointer != proto_class)
{
fprintf (stderr,
"Version %d doesn't match runtime protocol version %d\n",
(int)((char*)protos->list[i]->class_pointer-(char*)0),
PROTOCOL_VERSION);
abort ();
}
}
}
static void __objc_class_add_protocols (Class class,
struct objc_protocol_list* protos)
{
/* Well... */
if (! protos)
return;
/* Add it... */
protos->next = class->protocols;
class->protocols = protos;
}
#endif /* 0 */
static BOOL class_is_kind_of(Class self, Class aClassObject)
{
Class class;
for (class = self; class!=Nil; class = class_get_super_class(class))
if (class==aClassObject)
return YES;
return NO;
}

43
Source/objects/behavior.h Normal file
View file

@ -0,0 +1,43 @@
/* Interface for behaviors for Obj-C, "for Protocols with implementations".
Copyright (C) 1995 Free Software Foundation, Inc.
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
Date: March 1995
This file is part of the GNU Objective C Class Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __behavior_h_OBJECTS_INCLUDE
#define __behavior_h_OBJECTS_INCLUDE
/* Call this method from CLASS's +initialize method to add a behavior
to CLASS. A "behavior" is like a protocol with an implementation.
This functions adds to CLASS all the instance and factory methods
of BEHAVIOR as well as the instance and factory methods of
BEHAVIOR's superclasses (We stop adding super classes as soon as we
encounter a common ancestor.) CLASS and BEHAVIOR should share the
same instance variable layout.
xxx We do not yet deal with Protocols, but we should. */
void class_add_behavior (Class class, Class behavior);
/* Set to non-zero if you want debugging messages on stderr. */
void set_behavior_debug(int i);
#endif /* __behavior_h_OBJECTS_INCLUDE */