summaryrefslogtreecommitdiff
path: root/set.c
diff options
context:
space:
mode:
Diffstat (limited to 'set.c')
-rw-r--r--set.c316
1 files changed, 179 insertions, 137 deletions
diff --git a/set.c b/set.c
index 60c099bf49..8d6f33329b 100644
--- a/set.c
+++ b/set.c
@@ -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");
}