aboutsummaryrefslogtreecommitdiffstats
path: root/object.c
diff options
context:
space:
mode:
authorJohn Hawthorn <john@hawthorn.email>2022-03-05 13:03:33 -0800
committerJohn Hawthorn <john@hawthorn.email>2022-03-15 08:49:53 -0700
commitd76ba1c219d9ab2cb74b4b1de2e467e085150c1b (patch)
tree2e76097ae39469ee198fe07f0c2349690c3d269a /object.c
parent7aabdbe837fc58bf95c4633ad9c164440ad93876 (diff)
downloadruby-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.c41
1 files changed, 31 insertions, 10 deletions
diff --git a/object.c b/object.c
index a1093463c4..f6736fbe8b 100644
--- a/object.c
+++ b/object.c
@@ -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;
}
/*