mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* class.c: refactored singleton class related matters.
Handles eigenclasses and plain classes transparently. (make_metaclass): renamed from make_metametaclass. (METACLASS_OF): new utility macro (META_CLASS_OF_CLASS_CLASS): ditto. (ENSURE_EIGENCLASS): ditto. (make_singleton_class): extracted from rb_singleton_class. (boot_defclass): moved from object.c (Init_class_hierarchy): extracted from Init_Object. (rb_make_metaclass): refactored. (singleton_class_of): extracted from rb_singleton_class. (rb_singleton_class): refactored. (rb_define_singleton_method): it needs a metaclass only but not its metametaclass. * object.c: booting class hierarchy was moved to class.c for keeping dependency between compilation units least. (Init_Object): extracting the booting into Init_class_hierarchy. (boot_defclass): moved to class.c. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@24720 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
7fed54570f
commit
e056ac59a7
3 changed files with 187 additions and 111 deletions
24
ChangeLog
24
ChangeLog
|
@ -1,3 +1,27 @@
|
||||||
|
Mon Aug 31 14:17:09 2009 Yuki Sonoda (Yugui) <yugui@yugui.jp>
|
||||||
|
|
||||||
|
* class.c: refactored singleton class related matters.
|
||||||
|
Handles eigenclasses and plain classes transparently.
|
||||||
|
|
||||||
|
(make_metaclass): renamed from make_metametaclass.
|
||||||
|
(METACLASS_OF): new utility macro
|
||||||
|
(META_CLASS_OF_CLASS_CLASS): ditto.
|
||||||
|
(ENSURE_EIGENCLASS): ditto.
|
||||||
|
(make_singleton_class): extracted from rb_singleton_class.
|
||||||
|
(boot_defclass): moved from object.c
|
||||||
|
(Init_class_hierarchy): extracted from Init_Object.
|
||||||
|
(rb_make_metaclass): refactored.
|
||||||
|
(singleton_class_of): extracted from rb_singleton_class.
|
||||||
|
(rb_singleton_class): refactored.
|
||||||
|
(rb_define_singleton_method): it needs a metaclass only
|
||||||
|
but not its metametaclass.
|
||||||
|
|
||||||
|
* object.c: booting class hierarchy was moved to class.c
|
||||||
|
for keeping dependency between compilation units least.
|
||||||
|
(Init_Object): extracting the booting into
|
||||||
|
Init_class_hierarchy.
|
||||||
|
(boot_defclass): moved to class.c.
|
||||||
|
|
||||||
Sun Aug 30 23:44:09 2009 Tanaka Akira <akr@fsij.org>
|
Sun Aug 30 23:44:09 2009 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
* time.c (find_time_t): use mktime for the first guess.
|
* time.c (find_time_t): use mktime for the first guess.
|
||||||
|
|
237
class.c
237
class.c
|
@ -30,6 +30,7 @@
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
extern st_table *rb_class_tbl;
|
extern st_table *rb_class_tbl;
|
||||||
|
static ID id_attached;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocates a struct RClass for a new class.
|
* Allocates a struct RClass for a new class.
|
||||||
|
@ -190,7 +191,7 @@ rb_singleton_class_clone(VALUE obj)
|
||||||
else {
|
else {
|
||||||
struct clone_method_data data;
|
struct clone_method_data data;
|
||||||
/* copy singleton(unnamed) class */
|
/* copy singleton(unnamed) class */
|
||||||
VALUE clone = class_alloc(RBASIC(klass)->flags, 0);
|
VALUE clone = class_alloc(RBASIC(klass)->flags, 0);
|
||||||
|
|
||||||
if (BUILTIN_TYPE(obj) == T_CLASS) {
|
if (BUILTIN_TYPE(obj) == T_CLASS) {
|
||||||
RBASIC(clone)->klass = (VALUE)clone;
|
RBASIC(clone)->klass = (VALUE)clone;
|
||||||
|
@ -214,92 +215,155 @@ rb_singleton_class_clone(VALUE obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Attach a object to a singleton class.
|
||||||
|
* @pre \a klass is the singleton class of \a obj.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
rb_singleton_class_attached(VALUE klass, VALUE obj)
|
rb_singleton_class_attached(VALUE klass, VALUE obj)
|
||||||
{
|
{
|
||||||
if (FL_TEST(klass, FL_SINGLETON)) {
|
if (FL_TEST(klass, FL_SINGLETON)) {
|
||||||
ID attached;
|
|
||||||
if (!RCLASS_IV_TBL(klass)) {
|
if (!RCLASS_IV_TBL(klass)) {
|
||||||
RCLASS_IV_TBL(klass) = st_init_numtable();
|
RCLASS_IV_TBL(klass) = st_init_numtable();
|
||||||
}
|
}
|
||||||
CONST_ID(attached, "__attached__");
|
st_insert(RCLASS_IV_TBL(klass), id_attached, obj);
|
||||||
st_insert(RCLASS_IV_TBL(klass), attached, obj);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Creates a meta^(n+1)-class for a meta^(n)-class.
|
|
||||||
* \param metaclass a class of a class
|
|
||||||
* \return the created meta^(n+1)-class.
|
|
||||||
* \pre \a metaclass is a metaclass
|
|
||||||
* \post the class of \a metaclass is the returned class.
|
|
||||||
*/
|
|
||||||
static VALUE
|
|
||||||
make_metametaclass(VALUE metaclass)
|
|
||||||
{
|
|
||||||
VALUE metametaclass, super_of_metaclass;
|
|
||||||
|
|
||||||
if (RBASIC(metaclass)->klass == metaclass) { /* for meta^(n)-class of Class */
|
#define METACLASS_OF(k) RBASIC(k)->klass
|
||||||
metametaclass = rb_class_boot(Qnil);
|
|
||||||
RBASIC(metametaclass)->klass = metametaclass;
|
/*!
|
||||||
|
* whether k is a meta^(n)-class of Class class
|
||||||
|
* @retval 1 if \a k is a meta^(n)-class of Class class (n >= 0)
|
||||||
|
* @retval 0 otherwise
|
||||||
|
*/
|
||||||
|
#define META_CLASS_OF_CLASS_CLASS_P(k) (METACLASS_OF(k) == k)
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* ensures \a klass belongs to its own eigenclass.
|
||||||
|
* @return the eigenclass of \a klass
|
||||||
|
* @post \a klass belongs to the returned eigenclass.
|
||||||
|
* i.e. the attached object of the eigenclass is \a klass.
|
||||||
|
* @note this macro creates a new eigenclass if necessary.
|
||||||
|
*/
|
||||||
|
#define ENSURE_EIGENCLASS(klass) \
|
||||||
|
(rb_ivar_get(METACLASS_OF(klass), id_attached) == klass ? METACLASS_OF(klass) : make_metaclass(klass))
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Creates a metaclass of \a klass
|
||||||
|
* \param klass a class
|
||||||
|
* \return created metaclass for the class
|
||||||
|
* \pre \a klass is a Class object
|
||||||
|
* \pre \a klass has no singleton class.
|
||||||
|
* \post the class of \a klass is the returned class.
|
||||||
|
* \post the returned class is meta^(n+1)-class when \a klass is a meta^(n)-klass for n >= 0
|
||||||
|
*/
|
||||||
|
static inline VALUE
|
||||||
|
make_metaclass(VALUE klass)
|
||||||
|
{
|
||||||
|
VALUE super;
|
||||||
|
VALUE metaclass = rb_class_boot(Qundef);
|
||||||
|
|
||||||
|
FL_SET(metaclass, FL_SINGLETON);
|
||||||
|
rb_singleton_class_attached(metaclass, klass);
|
||||||
|
|
||||||
|
if (META_CLASS_OF_CLASS_CLASS_P(klass)) {
|
||||||
|
METACLASS_OF(klass) = METACLASS_OF(metaclass) = metaclass;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
metametaclass = rb_class_boot(Qnil);
|
VALUE tmp = METACLASS_OF(klass); /* for a meta^(n)-class klass, tmp is meta^(n)-class of Class class */
|
||||||
RBASIC(metametaclass)->klass =
|
METACLASS_OF(klass) = metaclass;
|
||||||
(RBASIC(RBASIC(metaclass)->klass)->klass == RBASIC(metaclass)->klass)
|
METACLASS_OF(metaclass) = ENSURE_EIGENCLASS(tmp);
|
||||||
? make_metametaclass(RBASIC(metaclass)->klass)
|
|
||||||
: RBASIC(RBASIC(metaclass)->klass)->klass;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FL_SET(metametaclass, FL_SINGLETON);
|
super = RCLASS_SUPER(klass);
|
||||||
rb_singleton_class_attached(metametaclass, metaclass);
|
while (FL_TEST(super, T_ICLASS)) super = RCLASS_SUPER(super);
|
||||||
RBASIC(metaclass)->klass = metametaclass;
|
RCLASS_SUPER(metaclass) = super ? ENSURE_EIGENCLASS(super) : rb_cClass;
|
||||||
|
|
||||||
super_of_metaclass = RCLASS_SUPER(metaclass);
|
OBJ_INFECT(metaclass, RCLASS_SUPER(metaclass));
|
||||||
while (FL_TEST(super_of_metaclass, T_ICLASS)) {
|
|
||||||
super_of_metaclass = RCLASS_SUPER(super_of_metaclass);
|
return metaclass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Creates a singleton class for \a obj.
|
||||||
|
* \pre \a obj must not a immediate nor a special const.
|
||||||
|
* \pre \a obj must not a Class object.
|
||||||
|
* \pre \a obj has no singleton class.
|
||||||
|
*/
|
||||||
|
static inline VALUE
|
||||||
|
make_singleton_class(VALUE obj)
|
||||||
|
{
|
||||||
|
VALUE metasuper;
|
||||||
|
VALUE super = RBASIC(obj)->klass;
|
||||||
|
VALUE klass = rb_class_boot(super);
|
||||||
|
|
||||||
|
FL_SET(klass, FL_SINGLETON);
|
||||||
|
RBASIC(obj)->klass = klass;
|
||||||
|
rb_singleton_class_attached(klass, obj);
|
||||||
|
|
||||||
|
metasuper = RBASIC(rb_class_real(super))->klass;
|
||||||
|
/* metaclass of a superclass may be NULL at boot time */
|
||||||
|
if (metasuper) {
|
||||||
|
RBASIC(klass)->klass = metasuper;
|
||||||
}
|
}
|
||||||
RCLASS_SUPER(metametaclass) =
|
return klass;
|
||||||
rb_iv_get(RBASIC(super_of_metaclass)->klass, "__attached__") == super_of_metaclass
|
}
|
||||||
? RBASIC(super_of_metaclass)->klass
|
|
||||||
: make_metametaclass(super_of_metaclass);
|
|
||||||
OBJ_INFECT(metametaclass, RCLASS_SUPER(metametaclass));
|
|
||||||
|
|
||||||
return metametaclass;
|
|
||||||
|
static VALUE
|
||||||
|
boot_defclass(const char *name, VALUE super)
|
||||||
|
{
|
||||||
|
extern st_table *rb_class_tbl;
|
||||||
|
VALUE obj = rb_class_boot(super);
|
||||||
|
ID id = rb_intern(name);
|
||||||
|
|
||||||
|
rb_name_class(obj, id);
|
||||||
|
st_add_direct(rb_class_tbl, id, obj);
|
||||||
|
rb_const_set((rb_cObject ? rb_cObject : obj), id, obj);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Init_class_hierarchy(void)
|
||||||
|
{
|
||||||
|
id_attached = rb_intern("__attached__");
|
||||||
|
|
||||||
|
rb_cBasicObject = boot_defclass("BasicObject", 0);
|
||||||
|
rb_cObject = boot_defclass("Object", rb_cBasicObject);
|
||||||
|
rb_cModule = boot_defclass("Module", rb_cObject);
|
||||||
|
rb_cClass = boot_defclass("Class", rb_cModule);
|
||||||
|
|
||||||
|
RBASIC(rb_cClass)->klass
|
||||||
|
= RBASIC(rb_cModule)->klass
|
||||||
|
= RBASIC(rb_cObject)->klass
|
||||||
|
= RBASIC(rb_cBasicObject)->klass
|
||||||
|
= rb_cClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \internal
|
* \internal
|
||||||
* Creates a singleton class for an object.
|
* Creates a new *singleton class* for an object.
|
||||||
*
|
*
|
||||||
* \note DO NOT USE the function in an extension libraries. Use rb_singleton_class.
|
* \pre \a obj has no singleton class.
|
||||||
* \param obj An object.
|
* \note DO NOT USE the function in an extension libraries. Use \ref rb_singleton_class.
|
||||||
* \param super A class from which the singleton class derives.
|
* \param obj An object.
|
||||||
* \note \a super is ignored if \a obj is a metaclass.
|
* \param unused ignored.
|
||||||
* \return The singleton class of the object.
|
* \return The singleton class of the object.
|
||||||
*/
|
*/
|
||||||
VALUE
|
VALUE
|
||||||
rb_make_metaclass(VALUE obj, VALUE super)
|
rb_make_metaclass(VALUE obj, VALUE unused)
|
||||||
{
|
{
|
||||||
if (BUILTIN_TYPE(obj) == T_CLASS && FL_TEST(obj, FL_SINGLETON)) { /* obj is a metaclass */
|
if (BUILTIN_TYPE(obj) == T_CLASS) {
|
||||||
return make_metametaclass(obj);
|
return make_metaclass(obj);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
VALUE metasuper;
|
return make_singleton_class(obj);
|
||||||
VALUE klass = rb_class_boot(super);
|
|
||||||
|
|
||||||
FL_SET(klass, FL_SINGLETON);
|
|
||||||
RBASIC(obj)->klass = klass;
|
|
||||||
rb_singleton_class_attached(klass, obj);
|
|
||||||
|
|
||||||
metasuper = RBASIC(rb_class_real(super))->klass;
|
|
||||||
/* metaclass of a superclass may be NULL at boot time */
|
|
||||||
if (metasuper) {
|
|
||||||
RBASIC(klass)->klass = metasuper;
|
|
||||||
}
|
|
||||||
return klass;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1044,23 +1108,18 @@ rb_undef_method(VALUE klass, const char *name)
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Returns the singleton class of \a obj.
|
* \internal
|
||||||
|
* Returns the singleton class of \a obj. Creates it if necessary.
|
||||||
*
|
*
|
||||||
* \param obj an arbitrary object.
|
* \note DO NOT expose the returned singleton class to
|
||||||
* \throw TypeError if \a obj is a Fixnum or a Symbol.
|
* outside of class.c.
|
||||||
* \return the singleton class.
|
* Use \ref rb_singleton_class instead for
|
||||||
*
|
* consistency of the metaclass hierarchy.
|
||||||
* \post \a obj has the singleton class.
|
|
||||||
* \note a new singleton class will be created
|
|
||||||
* if \a obj does not have it.
|
|
||||||
* \note the singleton classes for nil, true and false are:
|
|
||||||
* NilClass, TrueClass and FalseClass.
|
|
||||||
*/
|
*/
|
||||||
VALUE
|
static VALUE
|
||||||
rb_singleton_class(VALUE obj)
|
singleton_class_of(VALUE obj)
|
||||||
{
|
{
|
||||||
VALUE klass;
|
VALUE klass;
|
||||||
ID attached;
|
|
||||||
|
|
||||||
if (FIXNUM_P(obj) || SYMBOL_P(obj)) {
|
if (FIXNUM_P(obj) || SYMBOL_P(obj)) {
|
||||||
rb_raise(rb_eTypeError, "can't define singleton");
|
rb_raise(rb_eTypeError, "can't define singleton");
|
||||||
|
@ -1072,19 +1131,14 @@ rb_singleton_class(VALUE obj)
|
||||||
rb_bug("unknown immediate %ld", obj);
|
rb_bug("unknown immediate %ld", obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
CONST_ID(attached, "__attached__");
|
|
||||||
if (FL_TEST(RBASIC(obj)->klass, FL_SINGLETON) &&
|
if (FL_TEST(RBASIC(obj)->klass, FL_SINGLETON) &&
|
||||||
rb_ivar_get(RBASIC(obj)->klass, attached) == obj) {
|
rb_ivar_get(RBASIC(obj)->klass, id_attached) == obj) {
|
||||||
klass = RBASIC(obj)->klass;
|
klass = RBASIC(obj)->klass;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
klass = rb_make_metaclass(obj, RBASIC(obj)->klass);
|
klass = rb_make_metaclass(obj, RBASIC(obj)->klass);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BUILTIN_TYPE(obj) == T_CLASS) {
|
|
||||||
if (rb_iv_get(RBASIC(klass)->klass, "__attached__") != klass)
|
|
||||||
make_metametaclass(klass);
|
|
||||||
}
|
|
||||||
if (OBJ_TAINTED(obj)) {
|
if (OBJ_TAINTED(obj)) {
|
||||||
OBJ_TAINT(klass);
|
OBJ_TAINT(klass);
|
||||||
}
|
}
|
||||||
|
@ -1102,6 +1156,35 @@ rb_singleton_class(VALUE obj)
|
||||||
return klass;
|
return klass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the singleton class of \a obj. Creates it if necessary.
|
||||||
|
*
|
||||||
|
* \param obj an arbitrary object.
|
||||||
|
* \throw TypeError if \a obj is a Fixnum or a Symbol.
|
||||||
|
* \return the singleton class.
|
||||||
|
*
|
||||||
|
* \post \a obj has its own singleton class.
|
||||||
|
* \post if \a obj is a class,
|
||||||
|
* the returned singleton class also has its own
|
||||||
|
* singleton class in order to keep consistency of the
|
||||||
|
* inheritance structure of metaclasses.
|
||||||
|
* \note a new singleton class will be created
|
||||||
|
* if \a obj does not have it.
|
||||||
|
* \note the singleton classes for nil, true and false are:
|
||||||
|
* NilClass, TrueClass and FalseClass.
|
||||||
|
*/
|
||||||
|
VALUE
|
||||||
|
rb_singleton_class(VALUE obj)
|
||||||
|
{
|
||||||
|
VALUE klass = singleton_class_of(obj);
|
||||||
|
|
||||||
|
/* ensures an exposed class belongs to its own eigenclass */
|
||||||
|
if (TYPE(obj) == T_CLASS) ENSURE_EIGENCLASS(klass);
|
||||||
|
|
||||||
|
return klass;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \}
|
* \}
|
||||||
*/
|
*/
|
||||||
|
@ -1121,7 +1204,7 @@ rb_singleton_class(VALUE obj)
|
||||||
void
|
void
|
||||||
rb_define_singleton_method(VALUE obj, const char *name, VALUE (*func)(ANYARGS), int argc)
|
rb_define_singleton_method(VALUE obj, const char *name, VALUE (*func)(ANYARGS), int argc)
|
||||||
{
|
{
|
||||||
rb_define_method(rb_singleton_class(obj), name, func, argc);
|
rb_define_method(singleton_class_of(obj), name, func, argc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
37
object.c
37
object.c
|
@ -2386,25 +2386,6 @@ rb_f_array(VALUE obj, VALUE arg)
|
||||||
return rb_Array(arg);
|
return rb_Array(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
|
||||||
boot_defclass(const char *name, VALUE super)
|
|
||||||
{
|
|
||||||
extern st_table *rb_class_tbl;
|
|
||||||
VALUE obj = rb_class_boot(super);
|
|
||||||
ID id = rb_intern(name);
|
|
||||||
|
|
||||||
rb_name_class(obj, id);
|
|
||||||
st_add_direct(rb_class_tbl, id, obj);
|
|
||||||
rb_const_set((rb_cObject ? rb_cObject : obj), id, obj);
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
boot_defmetametaclass(VALUE klass, VALUE metametaclass)
|
|
||||||
{
|
|
||||||
RBASIC(RBASIC(klass)->klass)->klass = metametaclass;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Document-class: Class
|
* Document-class: Class
|
||||||
*
|
*
|
||||||
|
@ -2504,26 +2485,14 @@ boot_defmetametaclass(VALUE klass, VALUE metametaclass)
|
||||||
void
|
void
|
||||||
Init_Object(void)
|
Init_Object(void)
|
||||||
{
|
{
|
||||||
|
extern void Init_class_hierarchy(void);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
Init_class_hierarchy();
|
||||||
|
|
||||||
#undef rb_intern
|
#undef rb_intern
|
||||||
#define rb_intern(str) rb_intern_const(str)
|
#define rb_intern(str) rb_intern_const(str)
|
||||||
|
|
||||||
VALUE metaclass;
|
|
||||||
|
|
||||||
rb_cBasicObject = boot_defclass("BasicObject", 0);
|
|
||||||
rb_cObject = boot_defclass("Object", rb_cBasicObject);
|
|
||||||
rb_cModule = boot_defclass("Module", rb_cObject);
|
|
||||||
rb_cClass = boot_defclass("Class", rb_cModule);
|
|
||||||
|
|
||||||
metaclass = rb_make_metaclass(rb_cBasicObject, rb_cClass);
|
|
||||||
metaclass = rb_make_metaclass(rb_cObject, metaclass);
|
|
||||||
metaclass = rb_make_metaclass(rb_cModule, metaclass);
|
|
||||||
metaclass = rb_make_metaclass(rb_cClass, metaclass);
|
|
||||||
boot_defmetametaclass(rb_cModule, metaclass);
|
|
||||||
boot_defmetametaclass(rb_cObject, metaclass);
|
|
||||||
boot_defmetametaclass(rb_cBasicObject, metaclass);
|
|
||||||
|
|
||||||
rb_define_private_method(rb_cBasicObject, "initialize", rb_obj_dummy, 0);
|
rb_define_private_method(rb_cBasicObject, "initialize", rb_obj_dummy, 0);
|
||||||
rb_define_alloc_func(rb_cBasicObject, rb_class_allocate_instance);
|
rb_define_alloc_func(rb_cBasicObject, rb_class_allocate_instance);
|
||||||
rb_define_method(rb_cBasicObject, "==", rb_obj_equal, 1);
|
rb_define_method(rb_cBasicObject, "==", rb_obj_equal, 1);
|
||||||
|
|
Loading…
Reference in a new issue