diff options
author | John Hawthorn <john@hawthorn.email> | 2022-03-05 13:03:33 -0800 |
---|---|---|
committer | John Hawthorn <john@hawthorn.email> | 2022-03-15 08:49:53 -0700 |
commit | d76ba1c219d9ab2cb74b4b1de2e467e085150c1b (patch) | |
tree | 2e76097ae39469ee198fe07f0c2349690c3d269a /object.c | |
parent | 7aabdbe837fc58bf95c4633ad9c164440ad93876 (diff) | |
download | ruby-d76ba1c219d9ab2cb74b4b1de2e467e085150c1b.tar.gz |
Fast rb_class_inherited_p
This uses the superclass table recently introduced to implement fast
inheritance checking between classes (ex. Foo < Bar).
This is almost identical to what we do in class_search_class_ancestor
(as called by rb_obj_is_kind_of) except that we are checking both
directions: ie. both whether Foo < Bar and whether Bar < Foo.
Diffstat (limited to 'object.c')
-rw-r--r-- | object.c | 41 |
1 files changed, 31 insertions, 10 deletions
@@ -1633,17 +1633,38 @@ VALUE rb_class_inherited_p(VALUE mod, VALUE arg) { if (mod == arg) return Qtrue; - if (!CLASS_OR_MODULE_P(arg) && !RB_TYPE_P(arg, T_ICLASS)) { - rb_raise(rb_eTypeError, "compared with non class/module"); - } - if (class_search_ancestor(mod, RCLASS_ORIGIN(arg))) { - return Qtrue; - } - /* not mod < arg; check if mod > arg */ - if (class_search_ancestor(arg, mod)) { - return Qfalse; + + if (RB_TYPE_P(arg, T_CLASS) && RB_TYPE_P(mod, T_CLASS)) { + // comparison between classes + size_t mod_depth = RCLASS_SUPERCLASS_DEPTH(mod); + size_t arg_depth = RCLASS_SUPERCLASS_DEPTH(arg); + if (arg_depth < mod_depth) { + // check if mod < arg + return RCLASS_SUPERCLASSES(mod)[arg_depth] == arg ? + Qtrue : + Qnil; + } else if (arg_depth > mod_depth) { + // check if mod > arg + return RCLASS_SUPERCLASSES(arg)[mod_depth] == mod ? + Qfalse : + Qnil; + } else { + // Depths match, and we know they aren't equal: no relation + return Qnil; + } + } else { + if (!CLASS_OR_MODULE_P(arg) && !RB_TYPE_P(arg, T_ICLASS)) { + rb_raise(rb_eTypeError, "compared with non class/module"); + } + if (class_search_ancestor(mod, RCLASS_ORIGIN(arg))) { + return Qtrue; + } + /* not mod < arg; check if mod > arg */ + if (class_search_ancestor(arg, mod)) { + return Qfalse; + } + return Qnil; } - return Qnil; } /* |