home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / c / objam01.lha / objam / objc / class.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-10  |  8.8 KB  |  312 lines

  1. /*
  2. ** ObjectiveAmiga: Class related functions
  3. ** See GNU:lib/libobjam/ReadMe for details
  4. */
  5.  
  6.  
  7. #include "runtime.h"        /* the kitchen sink */
  8.  
  9. /* The table of classname->class.  Used for objc_lookup_class and friends */
  10. static cache_ptr __objc_class_hash = 0;
  11.  
  12. /* This is a hook which is called by objc_get_class and 
  13.    objc_lookup_class if the runtime is not able to find the class.
  14.    This may e.g. try to load in the class using dynamic loading */
  15. OCClass* (*_objc_lookup_class)(const char* name) = 0;
  16.  
  17.  
  18. /* True when class links has been resolved */     
  19. BOOL __objc_class_links_resolved = NO;
  20.  
  21.  
  22. /* Initial number of buckets size of class hash table. */
  23. #define CLASS_HASH_SIZE 32
  24.  
  25. void __objc_init_class_tables()
  26. {
  27.   /* Allocate the class hash table */
  28.  
  29.   if(__objc_class_hash)
  30.     return;
  31.  
  32.   __objc_class_hash
  33.     =  hash_new (CLASS_HASH_SIZE,
  34.          (hash_func_type) hash_string,
  35.          (compare_func_type) compare_strings);
  36. }  
  37.  
  38. /* This function adds a class to the class hash table, and assigns the 
  39.    class a number, unless it's already known */
  40. void
  41. __objc_add_class_to_hash(OCClass* class)
  42. {
  43.   OCClass* h_class;
  44.  
  45.   /* make sure the table is there */
  46.   assert(__objc_class_hash);
  47.  
  48.   /* make sure it's not a meta class */  
  49.   assert(CLS_ISCLASS(class));
  50.  
  51.   /* Check to see if the class is already in the hash table.  */
  52.   h_class = hash_value_for_key (__objc_class_hash, class->name);
  53.   if (!h_class)
  54.     {
  55.       /* The class isn't in the hash table.  Add the class and assign a class
  56.          number.  */
  57.       static unsigned int class_number = 1;
  58.  
  59.       CLS_SETNUMBER(class, class_number);
  60.       CLS_SETNUMBER(class->class_pointer, class_number);
  61.  
  62.       ++class_number;
  63.       hash_add (&__objc_class_hash, class->name, class);
  64.     }
  65. }
  66.  
  67. /* Get the class object for the class named NAME.  If NAME does not
  68.    identify a known class, the hook _objc_lookup_class is called.  If
  69.    this fails, nil is returned */
  70. OCClass* objc_lookup_class (const char* name)
  71. {
  72.   OCClass* class;
  73.  
  74.   /* Make sure the class hash table exists.  */
  75.   assert (__objc_class_hash);
  76.  
  77.   class = hash_value_for_key (__objc_class_hash, name);
  78.  
  79.   if (class)
  80.     return class;
  81.  
  82.   if (_objc_lookup_class)
  83.     return (*_objc_lookup_class)(name);
  84.   else
  85.     return 0;
  86. }
  87.  
  88. /* Get the class object for the class named NAME.  If NAME does not
  89.    identify a known class, the hook _objc_lookup_class is called.  If
  90.    this fails,  an error message is issued and the system aborts */
  91. OCClass*
  92. objc_get_class (const char *name)
  93. {
  94.   OCClass* class;
  95.  
  96.   /* Make sure the class hash table exists.  */
  97.   assert (__objc_class_hash);
  98.  
  99.   class = hash_value_for_key (__objc_class_hash, name);
  100.  
  101.   if (class)
  102.     return class;
  103.  
  104.   if (_objc_lookup_class)
  105.     class = (*_objc_lookup_class)(name);
  106.  
  107.   if(class)
  108.     return class;
  109.   
  110.   fprintf(stderr, "objc runtime: cannot find class %s\n", name);
  111.   abort();
  112. }
  113.  
  114.  
  115. /* Resolve super/subclass links for all classes.  The only thing we 
  116.    can be sure of is that the class_pointer for class objects point 
  117.    to the right meta class objects */
  118. void __objc_resolve_class_links()
  119. {
  120.   node_ptr node;
  121.   OCClass* object_class = objc_get_class ("Object");
  122.  
  123.   assert(object_class);
  124.  
  125.   /* Assign subclass links */
  126.   for (node = hash_next (__objc_class_hash, NULL); node;
  127.        node = hash_next (__objc_class_hash, node))
  128.     {
  129.       OCClass* class1 = node->value;
  130.  
  131.       /* Make sure we have what we think we have.  */
  132.       assert (CLS_ISCLASS(class1));
  133.       assert (CLS_ISMETA(class1->class_pointer));
  134.  
  135.       /* The class_pointer of all meta classes point to Object's meta class. */
  136.       class1->class_pointer->class_pointer = object_class->class_pointer;
  137.  
  138.       if (!(CLS_ISRESOLV(class1)))
  139.         {
  140.           CLS_SETRESOLV(class1);
  141.           CLS_SETRESOLV(class1->class_pointer);
  142.               
  143.           if(class1->super_class)
  144.             {   
  145.               OCClass* a_super_class 
  146.                 = objc_get_class ((char *) class1->super_class);
  147.               
  148.               assert (a_super_class);
  149.               
  150.               DEBUG_PRINTF ("making class connections for: %s\n",
  151.                             class1->name);
  152.               
  153.               /* assign subclass links for superclass */
  154.               class1->sibling_class = a_super_class->subclass_list;
  155.               a_super_class->subclass_list = class1;
  156.               
  157.               /* Assign subclass links for meta class of superclass */
  158.               if (a_super_class->class_pointer)
  159.                 {
  160.                   class1->class_pointer->sibling_class
  161.                     = a_super_class->class_pointer->subclass_list;
  162.                   a_super_class->class_pointer->subclass_list 
  163.                     = class1->class_pointer;
  164.                 }
  165.             }
  166.           else                  /* a root class, make its meta object */
  167.                                 /* be a subclass of Object */
  168.             {
  169.               class1->class_pointer->sibling_class 
  170.                 = object_class->subclass_list;
  171.               object_class->subclass_list = class1->class_pointer;
  172.             }
  173.         }
  174.     }
  175.  
  176.   /* Assign superclass links */
  177.   for (node = hash_next (__objc_class_hash, NULL); node;
  178.        node = hash_next (__objc_class_hash, node))
  179.     {
  180.       OCClass* class1 = node->value;
  181.       OCClass* sub_class;
  182.       for (sub_class = class1->subclass_list; sub_class;
  183.            sub_class = sub_class->sibling_class)
  184.         {
  185.           sub_class->super_class = class1;
  186.           if(CLS_ISCLASS(sub_class))
  187.             sub_class->class_pointer->super_class = class1->class_pointer;
  188.         }
  189.     }
  190. }
  191.  
  192.  
  193.  
  194. #define CLASSOF(c) ((c)->class_pointer)
  195.  
  196. OCClass*
  197. class_pose_as (OCClass* impostor, OCClass* super_class)
  198. {
  199.   if (!CLS_ISRESOLV (impostor))
  200.     __objc_resolve_class_links ();
  201.  
  202.   /* preconditions */
  203.   assert (impostor);
  204.   assert (super_class);
  205.   assert (impostor->super_class == super_class);
  206.   assert (CLS_ISCLASS (impostor));
  207.   assert (CLS_ISCLASS (super_class));
  208.   assert (impostor->instance_size == super_class->instance_size);
  209.  
  210.   {
  211.     OCClass **subclass = &(super_class->subclass_list);
  212.     BOOL super_is_base_class = NO;
  213.  
  214.     /* move subclasses of super_class to impostor */
  215.     while (*subclass)
  216.       {
  217.     OCClass *nextSub = (*subclass)->sibling_class;
  218.  
  219.     /* this happens when super_class is a base class */
  220.     if (*subclass == CLASSOF (super_class))
  221.       {
  222.         super_is_base_class = YES;
  223.       }
  224.     else if (*subclass != impostor)
  225.       {
  226.         OCClass *sub = *subclass;
  227.  
  228.         /* classes */
  229.         sub->sibling_class = impostor->subclass_list;
  230.         sub->super_class = impostor;
  231.         impostor->subclass_list = sub;
  232.         
  233.         /* meta classes */
  234.         CLASSOF (sub)->sibling_class = CLASSOF (impostor)->subclass_list;
  235.         CLASSOF (sub)->super_class = CLASSOF (impostor);
  236.         CLASSOF (impostor)->subclass_list = CLASSOF (sub);
  237.       }
  238.  
  239.     *subclass = nextSub;
  240.       }
  241.  
  242.     /* set subclasses of superclass to be impostor only */
  243.     super_class->subclass_list = impostor;
  244.     CLASSOF (super_class)->subclass_list = CLASSOF (impostor);
  245.     
  246.     /* set impostor to have no sibling classes */
  247.     impostor->sibling_class = 0;
  248.     CLASSOF (impostor)->sibling_class = 0;
  249.  
  250.     /* impostor has a sibling... */
  251.     if (super_is_base_class)
  252.       {
  253.     CLASSOF (super_class)->sibling_class = 0;
  254.     impostor->sibling_class = CLASSOF (super_class);
  255.       }
  256.   }
  257.   
  258.   /* check relationship of impostor and super_class */
  259.   assert (impostor->super_class == super_class);
  260.   assert (CLASSOF (impostor)->super_class == CLASSOF (super_class));
  261.  
  262.   /* by now, the re-organization of the class hierachy 
  263.      is done.  We only need to update various tables. */
  264.  
  265.   /* First, we change the names in the hash table.
  266.      This will change the behavior of objc_get_class () */
  267.   {
  268.     char* buffer = (char*) __objc_xmalloc(strlen (super_class->name) + 2);
  269.  
  270.     strcpy (buffer+1, super_class->name);
  271.     buffer[0] = '*';
  272.  
  273.     /* keep on prepending '*' until the name is unique */
  274.     while (hash_value_for_key (__objc_class_hash, buffer))
  275.       {
  276.     char *bbuffer = (char*) __objc_xmalloc (strlen (buffer)+2);
  277.  
  278.     strcpy (bbuffer+1, buffer);
  279.     bbuffer[0] = '*';
  280.     __objc_xfree (buffer);
  281.     buffer = bbuffer;
  282.       }
  283.  
  284.     hash_remove (__objc_class_hash, super_class->name);
  285.     hash_add (&__objc_class_hash, buffer, super_class);
  286.     hash_add (&__objc_class_hash, super_class->name, impostor);
  287.  
  288.     /* Note that -name and +name will still respond with
  289.        the same strings as before.  This way any
  290.        -isKindOfGivenName: will always work.         */
  291.   }
  292.  
  293.   /* next, we update the dispatch tables... */
  294.   {
  295.     OCClass *subclass;
  296.  
  297.     for (subclass = impostor->subclass_list;
  298.      subclass; subclass = subclass->sibling_class)
  299.       {
  300.     /* we use the opportunity to check what we did */
  301.     assert (subclass->super_class == impostor);
  302.     assert (CLASSOF (subclass)->super_class == CLASSOF (impostor));
  303.  
  304.     __objc_update_dispatch_table_for_class (CLASSOF (subclass));
  305.     __objc_update_dispatch_table_for_class (subclass);
  306.       }
  307.   }
  308.  
  309.   return impostor;
  310. }
  311.   
  312.