Beispiel #1
0
/* :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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
    }
}
Beispiel #4
0
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;
    }
}
Beispiel #5
0
/**
 * 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;
}
Beispiel #6
0
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;
}
Beispiel #7
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);
    }
}
Beispiel #8
0
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;
}
Beispiel #9
0
void
rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE))
{
    Check_Type(klass, T_CLASS);
    RCLASS_EXT(klass)->allocator = func;
}