/* :nodoc: */ VALUE rb_mod_init_copy(VALUE clone, VALUE orig) { if (RB_TYPE_P(clone, T_CLASS)) { class_init_copy_check(clone, orig); } if (!OBJ_INIT_COPY(clone, orig)) return clone; if (!FL_TEST(CLASS_OF(clone), FL_SINGLETON)) { RBASIC_SET_CLASS(clone, rb_singleton_class_clone(orig)); rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone); } RCLASS_SET_SUPER(clone, RCLASS_SUPER(orig)); RCLASS_EXT(clone)->allocator = RCLASS_EXT(orig)->allocator; if (RCLASS_IV_TBL(orig)) { st_data_t id; if (RCLASS_IV_TBL(clone)) { st_free_table(RCLASS_IV_TBL(clone)); } RCLASS_IV_TBL(clone) = rb_st_copy(clone, RCLASS_IV_TBL(orig)); CONST_ID(id, "__tmp_classpath__"); st_delete(RCLASS_IV_TBL(clone), &id, 0); CONST_ID(id, "__classpath__"); st_delete(RCLASS_IV_TBL(clone), &id, 0); CONST_ID(id, "__classid__"); st_delete(RCLASS_IV_TBL(clone), &id, 0); } if (RCLASS_CONST_TBL(orig)) { struct clone_const_arg arg; if (RCLASS_CONST_TBL(clone)) { rb_free_const_table(RCLASS_CONST_TBL(clone)); } RCLASS_CONST_TBL(clone) = st_init_numtable(); arg.klass = clone; arg.tbl = RCLASS_CONST_TBL(clone); st_foreach(RCLASS_CONST_TBL(orig), clone_const_i, (st_data_t)&arg); } if (RCLASS_M_TBL(orig)) { if (RCLASS_M_TBL_WRAPPER(clone)) { rb_free_m_tbl_wrapper(RCLASS_M_TBL_WRAPPER(clone)); } RCLASS_M_TBL_INIT(clone); st_foreach(RCLASS_M_TBL(orig), clone_method_i, (st_data_t)clone); } return clone; }
static void rb_module_add_to_subclasses_list(VALUE module, VALUE iclass) { rb_subclass_entry_t *entry, *head; entry = malloc(sizeof(*entry)); entry->klass = iclass; entry->next = NULL; head = RCLASS_EXT(module)->subclasses; if (head) { entry->next = head; RCLASS_EXT(head->klass)->module_subclasses = &entry->next; } RCLASS_EXT(module)->subclasses = entry; RCLASS_EXT(iclass)->module_subclasses = &RCLASS_EXT(module)->subclasses; }
void rb_class_subclass_add(VALUE super, VALUE klass) { rb_subclass_entry_t *entry, *head; if (super && super != Qundef) { entry = malloc(sizeof(*entry)); entry->klass = klass; entry->next = NULL; head = RCLASS_EXT(super)->subclasses; if (head) { entry->next = head; RCLASS_EXT(head->klass)->parent_subclasses = &entry->next; } RCLASS_EXT(super)->subclasses = entry; RCLASS_EXT(klass)->parent_subclasses = &RCLASS_EXT(super)->subclasses; } }
VALUE rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach) { VALUE klass = RBASIC(obj)->klass; if (!FL_TEST(klass, FL_SINGLETON)) return klass; else { /* copy singleton(unnamed) class */ VALUE clone = class_alloc(RBASIC(klass)->flags, 0); if (BUILTIN_TYPE(obj) == T_CLASS) { RBASIC_SET_CLASS(clone, clone); } else { RBASIC_SET_CLASS(clone, rb_singleton_class_clone(klass)); } RCLASS_SET_SUPER(clone, RCLASS_SUPER(klass)); RCLASS_EXT(clone)->allocator = RCLASS_EXT(klass)->allocator; if (RCLASS_IV_TBL(klass)) { RCLASS_IV_TBL(clone) = rb_st_copy(clone, RCLASS_IV_TBL(klass)); } if (RCLASS_CONST_TBL(klass)) { struct clone_const_arg arg; RCLASS_CONST_TBL(clone) = st_init_numtable(); arg.klass = clone; arg.tbl = RCLASS_CONST_TBL(clone); st_foreach(RCLASS_CONST_TBL(klass), clone_const_i, (st_data_t)&arg); } if (attach != Qundef) { rb_singleton_class_attached(clone, attach); } RCLASS_M_TBL_INIT(clone); st_foreach(RCLASS_M_TBL(klass), clone_method_i, (st_data_t)clone); rb_singleton_class_attached(RBASIC(clone)->klass, clone); FL_SET(clone, FL_SINGLETON); return clone; } }
/** * Allocates a struct RClass for a new class. * * \param flags initial value for basic.flags of the returned class. * \param klass the class of the returned class. * \return an uninitialized Class object. * \pre \p klass must refer \c Class class or an ancestor of Class. * \pre \code (flags | T_CLASS) != 0 \endcode * \post the returned class can safely be \c #initialize 'd. * * \note this function is not Class#allocate. */ static VALUE class_alloc(VALUE flags, VALUE klass) { NEWOBJ_OF(obj, struct RClass, klass, (flags & T_MASK) | (RGENGC_WB_PROTECTED_CLASS ? FL_WB_PROTECTED : 0)); obj->ptr = ALLOC(rb_classext_t); RCLASS_IV_TBL(obj) = 0; RCLASS_CONST_TBL(obj) = 0; RCLASS_M_TBL_WRAPPER(obj) = 0; RCLASS_SET_SUPER((VALUE)obj, 0); RCLASS_ORIGIN(obj) = (VALUE)obj; RCLASS_IV_INDEX_TBL(obj) = 0; RCLASS_EXT(obj)->subclasses = NULL; RCLASS_EXT(obj)->parent_subclasses = NULL; RCLASS_EXT(obj)->module_subclasses = NULL; RCLASS_SERIAL(obj) = rb_next_class_serial(); RCLASS_REFINED_CLASS(obj) = Qnil; RCLASS_EXT(obj)->allocator = 0; return (VALUE)obj; }
rb_alloc_func_t rb_get_alloc_func(VALUE klass) { Check_Type(klass, T_CLASS); for (; klass; klass = RCLASS_SUPER(klass)) { rb_alloc_func_t allocator = RCLASS_EXT(klass)->allocator; if (allocator == UNDEF_ALLOC_FUNC) break; if (allocator) return allocator; } return 0; }
void rb_class_foreach_subclass(VALUE klass, void(*f)(VALUE)) { rb_subclass_entry_t *cur = RCLASS_EXT(klass)->subclasses; /* do not be tempted to simplify this loop into a for loop, the order of operations is important here if `f` modifies the linked list */ while (cur) { VALUE curklass = cur->klass; cur = cur->next; f(curklass); } }
void rb_class_remove_from_super_subclasses(VALUE klass) { rb_subclass_entry_t *entry; if (RCLASS_EXT(klass)->parent_subclasses) { entry = *RCLASS_EXT(klass)->parent_subclasses; *RCLASS_EXT(klass)->parent_subclasses = entry->next; if (entry->next) { RCLASS_EXT(entry->next->klass)->parent_subclasses = RCLASS_EXT(klass)->parent_subclasses; } free(entry); } RCLASS_EXT(klass)->parent_subclasses = NULL; }
void rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE)) { Check_Type(klass, T_CLASS); RCLASS_EXT(klass)->allocator = func; }