diff options
author | Jean Boussier <[email protected]> | 2021-10-28 14:07:11 +0200 |
---|---|---|
committer | Jean Boussier <[email protected]> | 2021-11-23 10:50:44 +0100 |
commit | c0c2b31a35e19a47b499b57807bc0a0f9325f6d3 (patch) | |
tree | ab7ee0710597903b43a8d086a3805059693de928 /class.c | |
parent | a88b19d3d08447eeb7045621f02a844173d64203 (diff) |
Add Class#subclasses
Implements [Feature #18273]
Returns an array containing the receiver's direct subclasses without
singleton classes.
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/5045
Diffstat (limited to 'class.c')
-rw-r--r-- | class.c | 73 |
1 files changed, 55 insertions, 18 deletions
@@ -1377,6 +1377,7 @@ struct subclass_traverse_data VALUE buffer; long count; long maxcount; + bool immediate_only; }; static void @@ -1390,8 +1391,38 @@ class_descendants_recursive(VALUE klass, VALUE v) rb_ary_push(data->buffer, klass); } data->count++; + if (!data->immediate_only) { + rb_class_foreach_subclass(klass, class_descendants_recursive, v); + } + } + else { + rb_class_foreach_subclass(klass, class_descendants_recursive, v); + } +} + +static VALUE +class_descendants(VALUE klass, bool immediate_only) +{ + struct subclass_traverse_data data = { Qfalse, 0, -1, immediate_only }; + + // estimate the count of subclasses + rb_class_foreach_subclass(klass, class_descendants_recursive, (VALUE) &data); + + // the following allocation may cause GC which may change the number of subclasses + data.buffer = rb_ary_new_capa(data.count); + data.maxcount = data.count; + data.count = 0; + + size_t gc_count = rb_gc_count(); + + // enumerate subclasses + rb_class_foreach_subclass(klass, class_descendants_recursive, (VALUE) &data); + + if (gc_count != rb_gc_count()) { + rb_bug("GC must not occur during the subclass iteration of Class#descendants"); } - rb_class_foreach_subclass(klass, class_descendants_recursive, v); + + return data.buffer; } /* @@ -1415,26 +1446,32 @@ class_descendants_recursive(VALUE klass, VALUE v) VALUE rb_class_descendants(VALUE klass) { - struct subclass_traverse_data data = { Qfalse, 0, -1 }; - - // estimate the count of subclasses - rb_class_foreach_subclass(klass, class_descendants_recursive, (VALUE) &data); - - // the following allocation may cause GC which may change the number of subclasses - data.buffer = rb_ary_new_capa(data.count); - data.maxcount = data.count; - data.count = 0; - - size_t gc_count = rb_gc_count(); + return class_descendants(klass, false); +} - // enumerate subclasses - rb_class_foreach_subclass(klass, class_descendants_recursive, (VALUE) &data); - if (gc_count != rb_gc_count()) { - rb_bug("GC must not occur during the subclass iteration of Class#descendants"); - } +/* + * call-seq: + * subclasses -> array + * + * Returns an array of classes where the receiver is the + * direct superclass of the class, excluding singleton classes. + * The order of the returned array is not defined. + * + * class A; end + * class B < A; end + * class C < B; end + * class D < A; end + * + * A.subclasses #=> [D, B] + * B.subclasses #=> [C] + * C.subclasses #=> [] + */ - return data.buffer; +VALUE +rb_class_subclasses(VALUE klass) +{ + return class_descendants(klass, true); } static void |