static void reachable_object_from_root_i(const char *category, VALUE obj, void *ptr) { struct rofr_data *data = (struct rofr_data *)ptr; VALUE category_str; VALUE category_objects; if (category == data->last_category) { category_str = data->last_category_str; category_objects = data->last_category_objects; } else { data->last_category = category; category_str = data->last_category_str = rb_str_new2(category); category_objects = data->last_category_objects = rb_hash_new(); rb_funcall(category_objects, rb_intern("compare_by_identity"), 0); if (!NIL_P(rb_hash_lookup(data->categories, category_str))) { rb_bug("reachable_object_from_root_i: category should insert at once"); } rb_hash_aset(data->categories, category_str, category_objects); } if (rb_objspace_markable_object_p(obj) && obj != data->categories && obj != data->last_category_objects) { if (rb_objspace_internal_object_p(obj)) { obj = iow_newobj(obj); } rb_hash_aset(category_objects, obj, obj); } }
static void reachable_object_from_i(VALUE obj, void *data_ptr) { struct rof_data *data = (struct rof_data *)data_ptr; VALUE key = obj; VALUE val = obj; if (rb_objspace_markable_object_p(obj)) { if (rb_objspace_internal_object_p(obj)) { val = iow_newobj(obj); rb_ary_push(data->internals, val); } st_insert(data->refs, key, val); } }
static VALUE reachable_objects_from(VALUE self, VALUE obj) { if (rb_objspace_markable_object_p(obj)) { VALUE ret = rb_ary_new(); struct rof_data data; if (rb_typeddata_is_kind_of(obj, &iow_data_type)) { obj = (VALUE)DATA_PTR(obj); } data.refs = st_init_numtable(); data.internals = rb_ary_new(); rb_objspace_reachable_objects_from(obj, reachable_object_from_i, &data); st_foreach(data.refs, collect_values, (st_data_t)ret); return ret; } else { return Qnil; } }