diff options
Diffstat (limited to 'set.c')
| -rw-r--r-- | set.c | 316 |
1 files changed, 179 insertions, 137 deletions
@@ -102,6 +102,8 @@ static ID id_any_p; static ID id_new; static ID id_i_hash; static ID id_set_iter_lev; +static ID id_subclass_compatible; +static ID id_class_methods; #define RSET_INITIALIZED FL_USER1 #define RSET_LEV_MASK (FL_USER13 | FL_USER14 | FL_USER15 | /* FL 13..19 */ \ @@ -114,7 +116,7 @@ static ID id_set_iter_lev; #define RSET_SIZE(set) set_table_size(RSET_TABLE(set)) #define RSET_EMPTY(set) (RSET_SIZE(set) == 0) #define RSET_SIZE_NUM(set) SIZET2NUM(RSET_SIZE(set)) -#define RSET_IS_MEMBER(sobj, item) set_table_lookup(RSET_TABLE(set), (st_data_t)(item)) +#define RSET_IS_MEMBER(set, item) set_table_lookup(RSET_TABLE(set), (st_data_t)(item)) #define RSET_COMPARE_BY_IDENTITY(set) (RSET_TABLE(set)->type == &identhash) struct set_object { @@ -122,6 +124,14 @@ struct set_object { }; static int +mark_and_pin_key(st_data_t key, st_data_t data) +{ + rb_gc_mark((VALUE)key); + + return ST_CONTINUE; +} + +static int mark_key(st_data_t key, st_data_t data) { rb_gc_mark_movable((VALUE)key); @@ -133,21 +143,21 @@ static void set_mark(void *ptr) { struct set_object *sobj = ptr; - if (sobj->table.entries) set_table_foreach(&sobj->table, mark_key, 0); -} - -static void -set_free_embedded(struct set_object *sobj) -{ - free((&sobj->table)->entries); + if (sobj->table.entries) { + if (sobj->table.type == &identhash) { + set_table_foreach(&sobj->table, mark_and_pin_key, 0); + } + else { + set_table_foreach(&sobj->table, mark_key, 0); + } + } } static void set_free(void *ptr) { struct set_object *sobj = ptr; - set_free_embedded(sobj); - memset(&sobj->table, 0, sizeof(sobj->table)); + set_free_embedded_table(&sobj->table); } static size_t @@ -367,11 +377,10 @@ set_compact_after_delete(VALUE set) } static int -set_table_insert_wb(set_table *tab, VALUE set, VALUE key, VALUE *key_addr) +set_table_insert_wb(set_table *tab, VALUE set, VALUE key) { if (tab->type != &identhash && rb_obj_class(key) == rb_cString && !RB_OBJ_FROZEN(key)) { key = rb_hash_key_str(key); - if (key_addr) *key_addr = key; } int ret = set_insert(tab, (st_data_t)key); if (ret == 0) RB_OBJ_WRITTEN(set, Qundef, key); @@ -379,9 +388,9 @@ set_table_insert_wb(set_table *tab, VALUE set, VALUE key, VALUE *key_addr) } static int -set_insert_wb(VALUE set, VALUE key, VALUE *key_addr) +set_insert_wb(VALUE set, VALUE key) { - return set_table_insert_wb(RSET_TABLE(set), set, key, key_addr); + return set_table_insert_wb(RSET_TABLE(set), set, key); } static VALUE @@ -418,12 +427,25 @@ set_s_create(int argc, VALUE *argv, VALUE klass) int i; for (i=0; i < argc; i++) { - set_table_insert_wb(table, set, argv[i], NULL); + set_table_insert_wb(table, set, argv[i]); } return set; } +static VALUE +set_s_inherited(VALUE klass, VALUE subclass) +{ + if (klass == rb_cSet) { + // When subclassing directly from Set, include the compatibility layer + rb_require("set/subclass_compatible.rb"); + VALUE subclass_compatible = rb_const_get(klass, id_subclass_compatible); + rb_include_module(subclass, subclass_compatible); + rb_extend_object(subclass, rb_const_get(subclass_compatible, id_class_methods)); + } + return Qnil; +} + static void check_set(VALUE arg) { @@ -456,7 +478,7 @@ static VALUE set_initialize_without_block(RB_BLOCK_CALL_FUNC_ARGLIST(i, set)) { VALUE element = i; - set_insert_wb(set, element, &element); + set_insert_wb(set, element); return element; } @@ -464,27 +486,41 @@ static VALUE set_initialize_with_block(RB_BLOCK_CALL_FUNC_ARGLIST(i, set)) { VALUE element = rb_yield(i); - set_insert_wb(set, element, &element); + set_insert_wb(set, element); return element; } /* - * call-seq: - * Set.new -> new_set - * Set.new(enum) -> new_set - * Set.new(enum) { |elem| ... } -> new_set + * call-seq: + * Set.new(object = nil) -> new_set + * Set.new(object = nil) {|element| ... } -> new_set + * + * Returns a new \Set object based on the given +object+, + * which must be an Enumerable or +nil+. + * + * With argument +object+ given as +nil+, + * returns a new empty \Set object: + * + * Set.new # => Set[] + * Set.new { fail 'Cannot happen' } # => Set[] # Block not called. + * + * With no block given and +object+ given as an Enumerable, + * populates the new set with the elements of +object+: * - * Creates a new set containing the elements of the given enumerable - * object. + * Set.new(%w[ a b c ]) # => Set["a", "b", "c"] + * Set.new({foo: 0, bar: 1}) # => Set[[:foo, 0], [:bar, 1]] + * Set.new(4..10) # => Set[4, 5, 6, 7, 8, 9, 10] + * Set.new(Dir.new('lib')).take(5) + * # => [".", "..", "bundled_gems.rb", "bundler", "bundler.rb"] + * Set.new(File.new('doc/NEWS/NEWS-4.0.0.md')).take(3) + * # => ["# NEWS for Ruby 4.0.0\n", "\n", "This document is a list of user-visible feature changes\n"] * - * If a block is given, the elements of enum are preprocessed by the - * given block. + * With a block given and +object+ given as an Enumerable, + * calls the block with each element of +object+; + * adds the block's return value to the new set: + * + * Set.new(4..10) {|i| i * 2 } # => Set[8, 10, 12, 14, 16, 18, 20] * - * Set.new([1, 2]) #=> #<Set: {1, 2}> - * Set.new([1, 2, 1]) #=> #<Set: {1, 2}> - * Set.new([1, 'c', :s]) #=> #<Set: {1, "c", :s}> - * Set.new(1..5) #=> #<Set: {1, 2, 3, 4, 5}> - * Set.new([1, 2, 3]) { |x| x * x } #=> #<Set: {1, 4, 9}> */ static VALUE set_i_initialize(int argc, VALUE *argv, VALUE set) @@ -505,18 +541,10 @@ set_i_initialize(int argc, VALUE *argv, VALUE set) for (i=0; i<RARRAY_LEN(other); i++) { VALUE key = RARRAY_AREF(other, i); if (block_given) key = rb_yield(key); - set_table_insert_wb(into, set, key, NULL); + set_table_insert_wb(into, set, key); } } else { - ID id_size = rb_intern("size"); - if (rb_obj_is_kind_of(other, rb_mEnumerable) && rb_respond_to(other, id_size)) { - VALUE size = rb_funcall(other, id_size, 0); - if (RB_TYPE_P(size, T_FLOAT) && RFLOAT_VALUE(size) == INFINITY) { - rb_raise(rb_eArgError, "cannot initialize Set from an object with infinite size"); - } - } - rb_block_call(other, enum_method_id(other), 0, 0, rb_block_given_p() ? set_initialize_with_block : set_initialize_without_block, set); @@ -539,7 +567,7 @@ set_i_initialize_copy(VALUE set, VALUE other) struct set_object *sobj; TypedData_Get_Struct(set, struct set_object, &set_data_type, sobj); - set_free_embedded(sobj); + set_free_embedded_table(&sobj->table); set_copy(&sobj->table, RSET_TABLE(other)); rb_gc_writebarrier_remember(set); @@ -588,11 +616,11 @@ set_inspect(VALUE set, VALUE dummy, int recur) * Returns a new string containing the set entries: * * s = Set.new - * s.inspect # => "#<Set: {}>" + * s.inspect # => "Set[]" * s.add(1) - * s.inspect # => "#<Set: {1}>" + * s.inspect # => "Set[1]" * s.add(2) - * s.inspect # => "#<Set: {1, 2}>" + * s.inspect # => "Set[1, 2]" * * Related: see {Methods for Converting}[rdoc-ref:Set@Methods+for+Converting]. */ @@ -641,36 +669,19 @@ set_i_to_a(VALUE set) /* * call-seq: - * to_set(klass = Set, *args, &block) -> self or new_set - * - * Returns self if receiver is an instance of +Set+ and no arguments or - * block are given. Otherwise, converts the set to another with - * <tt>klass.new(self, *args, &block)</tt>. + * to_set(&block) -> self or new_set * - * In subclasses, returns `klass.new(self, *args, &block)` unless overridden. + * Without a block, if +self+ is an instance of +Set+, returns +self+. + * Otherwise, calls <tt>Set.new(self, &block)</tt>. */ static VALUE -set_i_to_set(int argc, VALUE *argv, VALUE set) +set_i_to_set(VALUE set) { - VALUE klass; - - if (argc == 0) { - klass = rb_cSet; - argv = &set; - argc = 1; - } - else { - rb_warn_deprecated("passing arguments to Set#to_set", NULL); - klass = argv[0]; - argv[0] = set; - } - - if (klass == rb_cSet && rb_obj_is_instance_of(set, rb_cSet) && - argc == 1 && !rb_block_given_p()) { + if (rb_obj_is_instance_of(set, rb_cSet) && !rb_block_given_p()) { return set; } - return rb_funcall_passing_block(klass, id_new, argc, argv); + return rb_funcall_passing_block(rb_cSet, id_new, 1, &set); } /* @@ -690,12 +701,12 @@ set_i_join(int argc, VALUE *argv, VALUE set) * call-seq: * add(obj) -> self * - * Adds the given object to the set and returns self. Use `merge` to + * Adds the given object to the set and returns self. Use Set#merge to * add many elements at once. * - * Set[1, 2].add(3) #=> #<Set: {1, 2, 3}> - * Set[1, 2].add([3, 4]) #=> #<Set: {1, 2, [3, 4]}> - * Set[1, 2].add(2) #=> #<Set: {1, 2}> + * Set[1, 2].add(3) #=> Set[1, 2, 3] + * Set[1, 2].add([3, 4]) #=> Set[1, 2, [3, 4]] + * Set[1, 2].add(2) #=> Set[1, 2] */ static VALUE set_i_add(VALUE set, VALUE item) @@ -707,7 +718,7 @@ set_i_add(VALUE set, VALUE item) } } else { - set_insert_wb(set, item, NULL); + set_insert_wb(set, item); } return set; } @@ -719,8 +730,8 @@ set_i_add(VALUE set, VALUE item) * Adds the given object to the set and returns self. If the object is * already in the set, returns nil. * - * Set[1, 2].add?(3) #=> #<Set: {1, 2, 3}> - * Set[1, 2].add?([3, 4]) #=> #<Set: {1, 2, [3, 4]}> + * Set[1, 2].add?(3) #=> Set[1, 2, 3] + * Set[1, 2].add?([3, 4]) #=> Set[1, 2, [3, 4]] * Set[1, 2].add?(2) #=> nil */ static VALUE @@ -734,7 +745,7 @@ set_i_add_p(VALUE set, VALUE item) return Qnil; } else { - return set_insert_wb(set, item, NULL) ? Qnil : set; + return set_insert_wb(set, item) ? Qnil : set; } } @@ -849,9 +860,9 @@ set_classify_i(st_data_t key, st_data_t tmp) * * files = Set.new(Dir.glob("*.rb")) * hash = files.classify { |f| File.mtime(f).year } - * hash #=> {2000 => #<Set: {"a.rb", "b.rb"}>, - * # 2001 => #<Set: {"c.rb", "d.rb", "e.rb"}>, - * # 2002 => #<Set: {"f.rb"}>} + * hash #=> {2000 => Set["a.rb", "b.rb"], + * # 2001 => Set["c.rb", "d.rb", "e.rb"], + * # 2002 => Set["f.rb"]} * * Returns an enumerator if no block is given. */ @@ -952,10 +963,10 @@ static void set_merge_enum_into(VALUE set, VALUE arg); * * numbers = Set[1, 3, 4, 6, 9, 10, 11] * set = numbers.divide { |i,j| (i - j).abs == 1 } - * set #=> #<Set: {#<Set: {1}>, - * # #<Set: {3, 4}>, - * # #<Set: {6}>}> - * # #<Set: {9, 10, 11}>, + * set #=> Set[Set[1], + * # Set[3, 4], + * # Set[6], + * # Set[9, 10, 11]] * * Returns an enumerator if no block is given. */ @@ -986,9 +997,9 @@ set_clear_i(st_data_t key, st_data_t dummy) * * Removes all elements and returns self. * - * set = Set[1, 'c', :s] #=> #<Set: {1, "c", :s}> - * set.clear #=> #<Set: {}> - * set #=> #<Set: {}> + * set = Set[1, 'c', :s] #=> Set[1, "c", :s] + * set.clear #=> Set[] + * set #=> Set[] */ static VALUE set_i_clear(VALUE set) @@ -1016,7 +1027,7 @@ set_intersection_i(st_data_t key, st_data_t tmp) { struct set_intersection_data *data = (struct set_intersection_data *)tmp; if (set_table_lookup(data->other, key)) { - set_table_insert_wb(data->into, data->set, key, NULL); + set_table_insert_wb(data->into, data->set, key); } return ST_CONTINUE; @@ -1036,8 +1047,8 @@ set_intersection_block(RB_BLOCK_CALL_FUNC_ARGLIST(i, data)) * Returns a new set containing elements common to the set and the given * enumerable object. * - * Set[1, 3, 5] & Set[3, 2, 1] #=> #<Set: {3, 1}> - * Set['a', 'b', 'z'] & ['a', 'b', 'c'] #=> #<Set: {"a", "b"}> + * Set[1, 3, 5] & Set[3, 2, 1] #=> Set[3, 1] + * Set['a', 'b', 'z'] & ['a', 'b', 'c'] #=> Set["a", "b"] */ static VALUE set_i_intersection(VALUE set, VALUE other) @@ -1112,7 +1123,7 @@ static int set_merge_i(st_data_t key, st_data_t data) { struct set_merge_args *args = (struct set_merge_args *)data; - set_table_insert_wb(args->into, args->set, key, NULL); + set_table_insert_wb(args->into, args->set, key); return ST_CONTINUE; } @@ -1120,7 +1131,7 @@ static VALUE set_merge_block(RB_BLOCK_CALL_FUNC_ARGLIST(key, set)) { VALUE element = key; - set_insert_wb(set, element, &element); + set_insert_wb(set, element); return element; } @@ -1138,7 +1149,7 @@ set_merge_enum_into(VALUE set, VALUE arg) long i; set_table *into = RSET_TABLE(set); for (i=0; i<RARRAY_LEN(arg); i++) { - set_table_insert_wb(into, set, RARRAY_AREF(arg, i), NULL); + set_table_insert_wb(into, set, RARRAY_AREF(arg, i)); } } else { @@ -1192,9 +1203,9 @@ set_reset_table_with_type(VALUE set, const struct st_hash_type *type) .into = new }; set_iter(set, set_merge_i, (st_data_t)&args); - set_free_embedded(sobj); + set_free_embedded_table(&sobj->table); memcpy(&sobj->table, new, sizeof(*new)); - free(new); + SIZED_FREE(new); } else { sobj->table.type = type; @@ -1264,7 +1275,7 @@ set_xor_i(st_data_t key, st_data_t data) VALUE element = (VALUE)key; VALUE set = (VALUE)data; set_table *table = RSET_TABLE(set); - if (set_table_insert_wb(table, set, element, &element)) { + if (set_table_insert_wb(table, set, element)) { set_table_delete(table, &element); } return ST_CONTINUE; @@ -1278,21 +1289,23 @@ set_xor_i(st_data_t key, st_data_t data) * given enumerable object. <tt>(set ^ enum)</tt> is equivalent to * <tt>((set | enum) - (set & enum))</tt>. * - * Set[1, 2] ^ Set[2, 3] #=> #<Set: {3, 1}> - * Set[1, 'b', 'c'] ^ ['b', 'd'] #=> #<Set: {"d", 1, "c"}> + * Set[1, 2] ^ Set[2, 3] #=> Set[3, 1] + * Set[1, 'b', 'c'] ^ ['b', 'd'] #=> Set["d", 1, "c"] */ static VALUE set_i_xor(VALUE set, VALUE other) { - VALUE new_set; + VALUE new_set = rb_obj_dup(set); + if (rb_obj_is_kind_of(other, rb_cSet)) { - new_set = other; + set_iter(other, set_xor_i, (st_data_t)new_set); } else { - new_set = set_s_alloc(rb_obj_class(set)); - set_merge_enum_into(new_set, other); + VALUE tmp = set_s_alloc(rb_cSet); + set_merge_enum_into(tmp, other); + set_iter(tmp, set_xor_i, (st_data_t)new_set); } - set_iter(set, set_xor_i, (st_data_t)new_set); + return new_set; } @@ -1303,8 +1316,8 @@ set_i_xor(VALUE set, VALUE other) * Returns a new set built by merging the set and the elements of the * given enumerable object. * - * Set[1, 2, 3] | Set[2, 4, 5] #=> #<Set: {1, 2, 3, 4, 5}> - * Set[1, 5, 'z'] | (1..6) #=> #<Set: {1, 5, "z", 2, 3, 4, 6}> + * Set[1, 2, 3] | Set[2, 4, 5] #=> Set[1, 2, 3, 4, 5] + * Set[1, 5, 'z'] | (1..6) #=> Set[1, 5, "z", 2, 3, 4, 6] */ static VALUE set_i_union(VALUE set, VALUE other) @@ -1362,8 +1375,8 @@ set_i_subtract(VALUE set, VALUE other) * Returns a new set built by duplicating the set, removing every * element that appears in the given enumerable object. * - * Set[1, 3, 5] - Set[1, 5] #=> #<Set: {3}> - * Set['a', 'b', 'z'] - ['a', 'c'] #=> #<Set: {"b", "z"}> + * Set[1, 3, 5] - Set[1, 5] #=> Set[3] + * Set['a', 'b', 'z'] - ['a', 'c'] #=> Set["b", "z"] */ static VALUE set_i_difference(VALUE set, VALUE other) @@ -1398,7 +1411,7 @@ set_i_each(VALUE set) static int set_collect_i(st_data_t key, st_data_t data) { - set_insert_wb((VALUE)data, rb_yield((VALUE)key), NULL); + set_insert_wb((VALUE)data, rb_yield((VALUE)key)); return ST_CONTINUE; } @@ -1479,9 +1492,9 @@ set_i_select(VALUE set) * Replaces the contents of the set with the contents of the given * enumerable object and returns self. * - * set = Set[1, 'c', :s] #=> #<Set: {1, "c", :s}> - * set.replace([1, 2]) #=> #<Set: {1, 2}> - * set #=> #<Set: {1, 2}> + * set = Set[1, 'c', :s] #=> Set[1, "c", :s] + * set.replace([1, 2]) #=> Set[1, 2] + * set #=> Set[1, 2] */ static VALUE set_i_replace(VALUE set, VALUE other) @@ -1757,7 +1770,7 @@ set_i_disjoint(VALUE set, VALUE other) * set <=> other -> -1, 0, 1, or nil * * Returns 0 if the set are equal, -1 / 1 if the set is a - * proper subset / superset of the given set, or or nil if + * proper subset / superset of the given set, or nil if * they both have unique elements. */ static VALUE @@ -1979,21 +1992,14 @@ rb_set_size(VALUE set) /* * Document-class: Set * - * Copyright (c) 2002-2024 Akinori MUSHA <knu@iDaemons.org> - * - * Documentation by Akinori MUSHA and Gavin Sinclair. - * - * All rights reserved. You can redistribute and/or modify it under the same - * terms as Ruby. - * * The Set class implements a collection of unordered values with no * duplicates. It is a hybrid of Array's intuitive inter-operation * facilities and Hash's fast lookup. * - * Set is easy to use with Enumerable objects (implementing `each`). + * Set is easy to use with Enumerable objects (implementing #each). * Most of the initializer methods and binary operators accept generic * Enumerable objects besides sets and arrays. An Enumerable object - * can be converted to Set using the `to_set` method. + * can be converted to Set using the +to_set+ method. * * Set uses a data structure similar to Hash for storage, except that * it only has keys and no values. @@ -2017,11 +2023,11 @@ rb_set_size(VALUE set) * * == Example * - * s1 = Set[1, 2] #=> #<Set: {1, 2}> - * s2 = [1, 2].to_set #=> #<Set: {1, 2}> + * s1 = Set[1, 2] #=> Set[1, 2] + * s2 = [1, 2].to_set #=> Set[1, 2] * s1 == s2 #=> true - * s1.add("foo") #=> #<Set: {1, 2, "foo"}> - * s1.merge([2, 6]) #=> #<Set: {1, 2, "foo", 6}> + * s1.add("foo") #=> Set[1, 2, "foo"] + * s1.merge([2, 6]) #=> Set[1, 2, "foo", 6] * s1.subset?(s2) #=> false * s2.subset?(s1) #=> true * @@ -2029,12 +2035,42 @@ rb_set_size(VALUE set) * * - Akinori MUSHA <knu@iDaemons.org> (current maintainer) * - * == What's Here + * == Inheriting from \Set + * + * Before Ruby 4.0 (released December 2025), \Set had a different, less + * efficient implementation. It was reimplemented in C, and the behavior + * of some of the core methods were adjusted. + * + * To keep backward compatibility, when a class is inherited from \Set, + * additional module +Set::SubclassCompatible+ is included, which makes + * the inherited class behavior, as well as internal method names, + * closer to what it was before Ruby 4.0. + * + * It can be easily seen, for example, in the #inspect method behavior: + * + * p Set[1, 2, 3] + * # prints "Set[1, 2, 3]" + * + * class MySet < Set + * end + * p MySet[1, 2, 3] + * # prints "#<MySet: {1, 2, 3}>", like it was in Ruby 3.4 + * + * For new code, if backward compatibility is not necessary, + * it is recommended to instead inherit from +Set::CoreSet+, which + * avoids including the "compatibility" layer: + * + * class MyCoreSet < Set::CoreSet + * end + * p MyCoreSet[1, 2, 3] + * # prints "MyCoreSet[1, 2, 3]" + * + * == Set's methods * - * First, what's elsewhere. \Class \Set: + * First, what's elsewhere. \Class \Set: * - * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here]. - * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here], + * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here]. + * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here], * which provides dozens of additional methods. * * In particular, class \Set does not have many methods of its own @@ -2043,16 +2079,15 @@ rb_set_size(VALUE set) * * Here, class \Set provides methods that are useful for: * - * - {Creating an Array}[rdoc-ref:Array@Methods+for+Creating+an+Array] - * - {Creating a Set}[rdoc-ref:Array@Methods+for+Creating+a+Set] - * - {Set Operations}[rdoc-ref:Array@Methods+for+Set+Operations] - * - {Comparing}[rdoc-ref:Array@Methods+for+Comparing] - * - {Querying}[rdoc-ref:Array@Methods+for+Querying] - * - {Assigning}[rdoc-ref:Array@Methods+for+Assigning] - * - {Deleting}[rdoc-ref:Array@Methods+for+Deleting] - * - {Converting}[rdoc-ref:Array@Methods+for+Converting] - * - {Iterating}[rdoc-ref:Array@Methods+for+Iterating] - * - {And more....}[rdoc-ref:Array@Other+Methods] + * - {Creating a Set}[rdoc-ref:Set@Methods+for+Creating+a+Set] + * - {Set Operations}[rdoc-ref:Set@Methods+for+Set+Operations] + * - {Comparing}[rdoc-ref:Set@Methods+for+Comparing] + * - {Querying}[rdoc-ref:Set@Methods+for+Querying] + * - {Assigning}[rdoc-ref:Set@Methods+for+Assigning] + * - {Deleting}[rdoc-ref:Set@Methods+for+Deleting] + * - {Converting}[rdoc-ref:Set@Methods+for+Converting] + * - {Iterating}[rdoc-ref:Set@Methods+for+Iterating] + * - {And more....}[rdoc-ref:Set@Other+Methods] * * === Methods for Creating a \Set * @@ -2195,6 +2230,8 @@ Init_Set(void) id_any_p = rb_intern_const("any?"); id_new = rb_intern_const("new"); id_i_hash = rb_intern_const("@hash"); + id_subclass_compatible = rb_intern_const("SubclassCompatible"); + id_class_methods = rb_intern_const("ClassMethods"); id_set_iter_lev = rb_make_internal_id(); rb_define_alloc_func(rb_cSet, set_s_alloc); @@ -2259,11 +2296,16 @@ Init_Set(void) rb_define_method(rb_cSet, "superset?", set_i_superset, 1); rb_define_alias(rb_cSet, ">=", "superset?"); rb_define_method(rb_cSet, "to_a", set_i_to_a, 0); - rb_define_method(rb_cSet, "to_set", set_i_to_set, -1); + rb_define_method(rb_cSet, "to_set", set_i_to_set, 0); /* :nodoc: */ VALUE compat = rb_define_class_under(rb_cSet, "compatible", rb_cObject); rb_marshal_define_compat(rb_cSet, compat, compat_dumper, compat_loader); + // Create Set::CoreSet before defining inherited, so it does not include + // the backwards compatibility layer. + rb_define_class_under(rb_cSet, "CoreSet", rb_cSet); + rb_define_private_method(rb_singleton_class(rb_cSet), "inherited", set_s_inherited, 1); + rb_provide("set.rb"); } |
