Ruby 4.0.7p0 (2026-09-15 revision 229531a6cfbf07e3caef30dbac24a2a3f3fed482)
set.c
1/* This implements sets using the same hash table implementation as in
2 st.c, but without a value for each hash entry. This results in the
3 same basic performance characteristics as when using an st table,
4 but uses 1/3 less memory.
5 */
6
7#include "id.h"
8#include "internal.h"
9#include "internal/bits.h"
10#include "internal/error.h"
11#include "internal/hash.h"
12#include "internal/proc.h"
13#include "internal/sanitizers.h"
14#include "internal/set_table.h"
15#include "internal/symbol.h"
16#include "internal/variable.h"
17#include "ruby_assert.h"
18
19#include <stdio.h>
20#ifdef HAVE_STDLIB_H
21#include <stdlib.h>
22#endif
23#include <string.h>
24
25#ifndef SET_DEBUG
26#define SET_DEBUG 0
27#endif
28
29#if SET_DEBUG
30#include "internal/gc.h"
31#endif
32
33static st_index_t
34dbl_to_index(double d)
35{
36 union {double d; st_index_t i;} u;
37 u.d = d;
38 return u.i;
39}
40
41static const uint64_t prime1 = ((uint64_t)0x2e0bb864 << 32) | 0xe9ea7df5;
42static const uint32_t prime2 = 0x830fcab9;
43
44static inline uint64_t
45mult_and_mix(uint64_t m1, uint64_t m2)
46{
47#if defined HAVE_UINT128_T
48 uint128_t r = (uint128_t) m1 * (uint128_t) m2;
49 return (uint64_t) (r >> 64) ^ (uint64_t) r;
50#else
51 uint64_t hm1 = m1 >> 32, hm2 = m2 >> 32;
52 uint64_t lm1 = m1, lm2 = m2;
53 uint64_t v64_128 = hm1 * hm2;
54 uint64_t v32_96 = hm1 * lm2 + lm1 * hm2;
55 uint64_t v1_32 = lm1 * lm2;
56
57 return (v64_128 + (v32_96 >> 32)) ^ ((v32_96 << 32) + v1_32);
58#endif
59}
60
61static inline uint64_t
62key64_hash(uint64_t key, uint32_t seed)
63{
64 return mult_and_mix(key + seed, prime1);
65}
66
67/* Should cast down the result for each purpose */
68#define set_index_hash(index) key64_hash(rb_hash_start(index), prime2)
69
70static st_index_t
71set_ident_hash(st_data_t n)
72{
73#ifdef USE_FLONUM /* RUBY */
74 /*
75 * - flonum (on 64-bit) is pathologically bad, mix the actual
76 * float value in, but do not use the float value as-is since
77 * many integers get interpreted as 2.0 or -2.0 [Bug #10761]
78 */
79 if (FLONUM_P(n)) {
80 n ^= dbl_to_index(rb_float_value(n));
81 }
82#endif
83
84 return (st_index_t)set_index_hash((st_index_t)n);
85}
86
87static const struct st_hash_type identhash = {
88 rb_st_numcmp,
89 set_ident_hash,
90};
91
92static const struct st_hash_type objhash = {
93 rb_any_cmp,
94 rb_any_hash,
95};
96
98
99#define id_each idEach
100static ID id_each_entry;
101static ID id_any_p;
102static ID id_new;
103static ID id_i_hash;
104static ID id_set_iter_lev;
105static ID id_subclass_compatible;
106static ID id_class_methods;
107
108#define RSET_INITIALIZED FL_USER1
109#define RSET_LEV_MASK (FL_USER13 | FL_USER14 | FL_USER15 | /* FL 13..19 */ \
110 FL_USER16 | FL_USER17 | FL_USER18 | FL_USER19)
111#define RSET_LEV_SHIFT (FL_USHIFT + 13)
112#define RSET_LEV_MAX 127 /* 7 bits */
113
114#define SET_ASSERT(expr) RUBY_ASSERT_MESG_WHEN(SET_DEBUG, expr, #expr)
115
116#define RSET_SIZE(set) set_table_size(RSET_TABLE(set))
117#define RSET_EMPTY(set) (RSET_SIZE(set) == 0)
118#define RSET_SIZE_NUM(set) SIZET2NUM(RSET_SIZE(set))
119#define RSET_IS_MEMBER(sobj, item) set_table_lookup(RSET_TABLE(set), (st_data_t)(item))
120#define RSET_COMPARE_BY_IDENTITY(set) (RSET_TABLE(set)->type == &identhash)
121
123 set_table table;
124};
125
126static int
127mark_and_pin_key(st_data_t key, st_data_t data)
128{
129 rb_gc_mark((VALUE)key);
130
131 return ST_CONTINUE;
132}
133
134static int
135mark_key(st_data_t key, st_data_t data)
136{
137 rb_gc_mark_movable((VALUE)key);
138
139 return ST_CONTINUE;
140}
141
142static void
143set_mark(void *ptr)
144{
145 struct set_object *sobj = ptr;
146 if (sobj->table.entries) {
147 if (sobj->table.type == &identhash) {
148 set_table_foreach(&sobj->table, mark_and_pin_key, 0);
149 }
150 else {
151 set_table_foreach(&sobj->table, mark_key, 0);
152 }
153 }
154}
155
156static void
157set_free_embedded(struct set_object *sobj)
158{
159 free((&sobj->table)->entries);
160}
161
162static void
163set_free(void *ptr)
164{
165 struct set_object *sobj = ptr;
166 set_free_embedded(sobj);
167 memset(&sobj->table, 0, sizeof(sobj->table));
168}
169
170static size_t
171set_size(const void *ptr)
172{
173 const struct set_object *sobj = ptr;
174 /* Do not count the table size twice, as it is embedded */
175 return (unsigned long)set_memsize(&sobj->table) - sizeof(sobj->table);
176}
177
178static int
179set_foreach_replace(st_data_t key, st_data_t argp, int error)
180{
181 if (rb_gc_location((VALUE)key) != (VALUE)key) {
182 return ST_REPLACE;
183 }
184
185 return ST_CONTINUE;
186}
187
188static int
189set_replace_ref(st_data_t *key, st_data_t argp, int existing)
190{
191 rb_gc_mark_and_move((VALUE *)key);
192
193 return ST_CONTINUE;
194}
195
196static void
197set_update_references(void *ptr)
198{
199 struct set_object *sobj = ptr;
200 set_foreach_with_replace(&sobj->table, set_foreach_replace, set_replace_ref, 0);
201}
202
203static const rb_data_type_t set_data_type = {
204 .wrap_struct_name = "set",
205 .function = {
206 .dmark = set_mark,
207 .dfree = set_free,
208 .dsize = set_size,
209 .dcompact = set_update_references,
210 },
211 .flags = RUBY_TYPED_EMBEDDABLE | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE
212};
213
214static inline set_table *
215RSET_TABLE(VALUE set)
216{
217 struct set_object *sobj;
218 TypedData_Get_Struct(set, struct set_object, &set_data_type, sobj);
219 return &sobj->table;
220}
221
222static unsigned long
223iter_lev_in_ivar(VALUE set)
224{
225 VALUE levval = rb_ivar_get(set, id_set_iter_lev);
226 SET_ASSERT(FIXNUM_P(levval));
227 long lev = FIX2LONG(levval);
228 SET_ASSERT(lev >= 0);
229 return (unsigned long)lev;
230}
231
232void rb_ivar_set_internal(VALUE obj, ID id, VALUE val);
233
234static void
235iter_lev_in_ivar_set(VALUE set, unsigned long lev)
236{
237 SET_ASSERT(lev >= RSET_LEV_MAX);
238 SET_ASSERT(POSFIXABLE(lev)); /* POSFIXABLE means fitting to long */
239 rb_ivar_set_internal(set, id_set_iter_lev, LONG2FIX((long)lev));
240}
241
242static inline unsigned long
243iter_lev_in_flags(VALUE set)
244{
245 return (unsigned long)((RBASIC(set)->flags >> RSET_LEV_SHIFT) & RSET_LEV_MAX);
246}
247
248static inline void
249iter_lev_in_flags_set(VALUE set, unsigned long lev)
250{
251 SET_ASSERT(lev <= RSET_LEV_MAX);
252 RBASIC(set)->flags = ((RBASIC(set)->flags & ~RSET_LEV_MASK) | ((VALUE)lev << RSET_LEV_SHIFT));
253}
254
255static inline bool
256set_iterating_p(VALUE set)
257{
258 return iter_lev_in_flags(set) > 0;
259}
260
261static void
262set_iter_lev_inc(VALUE set)
263{
264 unsigned long lev = iter_lev_in_flags(set);
265 if (lev == RSET_LEV_MAX) {
266 lev = iter_lev_in_ivar(set) + 1;
267 if (!POSFIXABLE(lev)) { /* paranoiac check */
268 rb_raise(rb_eRuntimeError, "too much nested iterations");
269 }
270 }
271 else {
272 lev += 1;
273 iter_lev_in_flags_set(set, lev);
274 if (lev < RSET_LEV_MAX) return;
275 }
276 iter_lev_in_ivar_set(set, lev);
277}
278
279static void
280set_iter_lev_dec(VALUE set)
281{
282 unsigned long lev = iter_lev_in_flags(set);
283 if (lev == RSET_LEV_MAX) {
284 lev = iter_lev_in_ivar(set);
285 if (lev > RSET_LEV_MAX) {
286 iter_lev_in_ivar_set(set, lev-1);
287 return;
288 }
289 rb_attr_delete(set, id_set_iter_lev);
290 }
291 else if (lev == 0) {
292 rb_raise(rb_eRuntimeError, "iteration level underflow");
293 }
294 iter_lev_in_flags_set(set, lev - 1);
295}
296
297static VALUE
298set_foreach_ensure(VALUE set)
299{
300 set_iter_lev_dec(set);
301 return 0;
302}
303
304typedef int set_foreach_func(VALUE, VALUE);
305
307 VALUE set;
308 set_foreach_func *func;
309 VALUE arg;
310};
311
312static int
313set_iter_status_check(int status)
314{
315 if (status == ST_CONTINUE) {
316 return ST_CHECK;
317 }
318
319 return status;
320}
321
322static int
323set_foreach_iter(st_data_t key, st_data_t argp, int error)
324{
325 struct set_foreach_arg *arg = (struct set_foreach_arg *)argp;
326
327 if (error) return ST_STOP;
328
329 set_table *tbl = RSET_TABLE(arg->set);
330 int status = (*arg->func)((VALUE)key, arg->arg);
331
332 if (RSET_TABLE(arg->set) != tbl) {
333 rb_raise(rb_eRuntimeError, "reset occurred during iteration");
334 }
335
336 return set_iter_status_check(status);
337}
338
339static VALUE
340set_foreach_call(VALUE arg)
341{
342 VALUE set = ((struct set_foreach_arg *)arg)->set;
343 int ret = 0;
344 ret = set_foreach_check(RSET_TABLE(set), set_foreach_iter,
345 (st_data_t)arg, (st_data_t)Qundef);
346 if (ret) {
347 rb_raise(rb_eRuntimeError, "ret: %d, set modified during iteration", ret);
348 }
349 return Qnil;
350}
351
352static void
353set_iter(VALUE set, set_foreach_func *func, VALUE farg)
354{
355 struct set_foreach_arg arg;
356
357 if (RSET_EMPTY(set))
358 return;
359 arg.set = set;
360 arg.func = func;
361 arg.arg = farg;
362 if (RB_OBJ_FROZEN(set)) {
363 set_foreach_call((VALUE)&arg);
364 }
365 else {
366 set_iter_lev_inc(set);
367 rb_ensure(set_foreach_call, (VALUE)&arg, set_foreach_ensure, set);
368 }
369}
370
371NORETURN(static void no_new_item(void));
372static void
373no_new_item(void)
374{
375 rb_raise(rb_eRuntimeError, "can't add a new item into set during iteration");
376}
377
378static void
379set_compact_after_delete(VALUE set)
380{
381 if (!set_iterating_p(set)) {
382 set_compact_table(RSET_TABLE(set));
383 }
384}
385
386static int
387set_table_insert_wb(set_table *tab, VALUE set, VALUE key, VALUE *key_addr)
388{
389 if (tab->type != &identhash && rb_obj_class(key) == rb_cString && !RB_OBJ_FROZEN(key)) {
390 key = rb_hash_key_str(key);
391 if (key_addr) *key_addr = key;
392 }
393 int ret = set_insert(tab, (st_data_t)key);
394 if (ret == 0) RB_OBJ_WRITTEN(set, Qundef, key);
395 return ret;
396}
397
398static int
399set_insert_wb(VALUE set, VALUE key, VALUE *key_addr)
400{
401 return set_table_insert_wb(RSET_TABLE(set), set, key, key_addr);
402}
403
404static VALUE
405set_alloc_with_size(VALUE klass, st_index_t size)
406{
407 VALUE set;
408 struct set_object *sobj;
409
410 set = TypedData_Make_Struct(klass, struct set_object, &set_data_type, sobj);
411 set_init_table_with_size(&sobj->table, &objhash, size);
412
413 return set;
414}
415
416
417static VALUE
418set_s_alloc(VALUE klass)
419{
420 return set_alloc_with_size(klass, 0);
421}
422
423/*
424 * call-seq:
425 * Set[*objects] -> new_set
426 *
427 * Returns a new Set object populated with the given objects,
428 * See Set::new.
429 */
430static VALUE
431set_s_create(int argc, VALUE *argv, VALUE klass)
432{
433 VALUE set = set_alloc_with_size(klass, argc);
434 set_table *table = RSET_TABLE(set);
435 int i;
436
437 for (i=0; i < argc; i++) {
438 set_table_insert_wb(table, set, argv[i], NULL);
439 }
440
441 return set;
442}
443
444static VALUE
445set_s_inherited(VALUE klass, VALUE subclass)
446{
447 if (klass == rb_cSet) {
448 // When subclassing directly from Set, include the compatibility layer
449 rb_require("set/subclass_compatible.rb");
450 VALUE subclass_compatible = rb_const_get(klass, id_subclass_compatible);
451 rb_include_module(subclass, subclass_compatible);
452 rb_extend_object(subclass, rb_const_get(subclass_compatible, id_class_methods));
453 }
454 return Qnil;
455}
456
457static void
458check_set(VALUE arg)
459{
460 if (!rb_obj_is_kind_of(arg, rb_cSet)) {
461 rb_raise(rb_eArgError, "value must be a set");
462 }
463}
464
465static ID
466enum_method_id(VALUE other)
467{
468 if (rb_respond_to(other, id_each_entry)) {
469 return id_each_entry;
470 }
471 else if (rb_respond_to(other, id_each)) {
472 return id_each;
473 }
474 else {
475 rb_raise(rb_eArgError, "value must be enumerable");
476 }
477}
478
479static VALUE
480set_enum_size(VALUE set, VALUE args, VALUE eobj)
481{
482 return RSET_SIZE_NUM(set);
483}
484
485static VALUE
486set_initialize_without_block(RB_BLOCK_CALL_FUNC_ARGLIST(i, set))
487{
488 VALUE element = i;
489 set_insert_wb(set, element, &element);
490 return element;
491}
492
493static VALUE
494set_initialize_with_block(RB_BLOCK_CALL_FUNC_ARGLIST(i, set))
495{
496 VALUE element = rb_yield(i);
497 set_insert_wb(set, element, &element);
498 return element;
499}
500
501/*
502 * call-seq:
503 * Set.new -> new_set
504 * Set.new(enum) -> new_set
505 * Set.new(enum) { |elem| ... } -> new_set
506 *
507 * Creates a new set containing the elements of the given enumerable
508 * object.
509 *
510 * If a block is given, the elements of enum are preprocessed by the
511 * given block.
512 *
513 * Set.new([1, 2]) #=> Set[1, 2]
514 * Set.new([1, 2, 1]) #=> Set[1, 2]
515 * Set.new([1, 'c', :s]) #=> Set[1, "c", :s]
516 * Set.new(1..5) #=> Set[1, 2, 3, 4, 5]
517 * Set.new([1, 2, 3]) { |x| x * x } #=> Set[1, 4, 9]
518 */
519static VALUE
520set_i_initialize(int argc, VALUE *argv, VALUE set)
521{
522 if (RBASIC(set)->flags & RSET_INITIALIZED) {
523 rb_raise(rb_eRuntimeError, "cannot reinitialize set");
524 }
525 RBASIC(set)->flags |= RSET_INITIALIZED;
526
527 VALUE other;
528 rb_check_arity(argc, 0, 1);
529
530 if (argc > 0 && (other = argv[0]) != Qnil) {
531 if (RB_TYPE_P(other, T_ARRAY)) {
532 long i;
533 int block_given = rb_block_given_p();
534 set_table *into = RSET_TABLE(set);
535 for (i=0; i<RARRAY_LEN(other); i++) {
536 VALUE key = RARRAY_AREF(other, i);
537 if (block_given) key = rb_yield(key);
538 set_table_insert_wb(into, set, key, NULL);
539 }
540 }
541 else {
542 rb_block_call(other, enum_method_id(other), 0, 0,
543 rb_block_given_p() ? set_initialize_with_block : set_initialize_without_block,
544 set);
545 }
546 }
547
548 return set;
549}
550
551/* :nodoc: */
552static VALUE
553set_i_initialize_copy(VALUE set, VALUE other)
554{
555 if (set == other) return set;
556
557 if (set_iterating_p(set)) {
558 rb_raise(rb_eRuntimeError, "cannot replace set during iteration");
559 }
560
561 struct set_object *sobj;
562 TypedData_Get_Struct(set, struct set_object, &set_data_type, sobj);
563
564 set_free_embedded(sobj);
565 set_copy(&sobj->table, RSET_TABLE(other));
566 rb_gc_writebarrier_remember(set);
567
568 return set;
569}
570
571static int
572set_inspect_i(st_data_t key, st_data_t arg)
573{
574 VALUE *args = (VALUE*)arg;
575 VALUE str = args[0];
576 if (args[1] == Qtrue) {
577 rb_str_buf_cat_ascii(str, ", ");
578 }
579 else {
580 args[1] = Qtrue;
581 }
583
584 return ST_CONTINUE;
585}
586
587static VALUE
588set_inspect(VALUE set, VALUE dummy, int recur)
589{
590 VALUE str;
591 VALUE klass_name = rb_class_path(CLASS_OF(set));
592
593 if (recur) {
594 str = rb_sprintf("%"PRIsVALUE"[...]", klass_name);
595 return rb_str_export_to_enc(str, rb_usascii_encoding());
596 }
597
598 str = rb_sprintf("%"PRIsVALUE"[", klass_name);
599 VALUE args[2] = {str, Qfalse};
600 set_iter(set, set_inspect_i, (st_data_t)args);
601 rb_str_buf_cat2(str, "]");
602
603 return str;
604}
605
606/*
607 * call-seq:
608 * inspect -> new_string
609 *
610 * Returns a new string containing the set entries:
611 *
612 * s = Set.new
613 * s.inspect # => "Set[]"
614 * s.add(1)
615 * s.inspect # => "Set[1]"
616 * s.add(2)
617 * s.inspect # => "Set[1, 2]"
618 *
619 * Related: see {Methods for Converting}[rdoc-ref:Set@Methods+for+Converting].
620 */
621static VALUE
622set_i_inspect(VALUE set)
623{
624 return rb_exec_recursive(set_inspect, set, 0);
625}
626
627static int
628set_to_a_i(st_data_t key, st_data_t arg)
629{
630 rb_ary_push((VALUE)arg, (VALUE)key);
631 return ST_CONTINUE;
632}
633
634/*
635 * call-seq:
636 * to_a -> array
637 *
638 * Returns an array containing all elements in the set.
639 *
640 * Set[1, 2].to_a #=> [1, 2]
641 * Set[1, 'c', :s].to_a #=> [1, "c", :s]
642 */
643static VALUE
644set_i_to_a(VALUE set)
645{
646 st_index_t size = RSET_SIZE(set);
647 VALUE ary = rb_ary_new_capa(size);
648
649 if (size == 0) return ary;
650
651 if (ST_DATA_COMPATIBLE_P(VALUE)) {
652 RARRAY_PTR_USE(ary, ptr, {
653 size = set_keys(RSET_TABLE(set), ptr, size);
654 });
655 rb_gc_writebarrier_remember(ary);
656 rb_ary_set_len(ary, size);
657 }
658 else {
659 set_iter(set, set_to_a_i, (st_data_t)ary);
660 }
661 return ary;
662}
663
664/*
665 * call-seq:
666 * to_set(klass = Set, *args, &block) -> self or new_set
667 *
668 * Without arguments, returns +self+ (for duck-typing in methods that
669 * accept "set, or set-convertible" arguments).
670 *
671 * A form with arguments is _deprecated_. It converts the set to another
672 * with <tt>klass.new(self, *args, &block)</tt>.
673 */
674static VALUE
675set_i_to_set(int argc, VALUE *argv, VALUE set)
676{
677 VALUE klass;
678
679 if (argc == 0) {
680 klass = rb_cSet;
681 argv = &set;
682 argc = 1;
683 }
684 else {
685 rb_warn_deprecated("passing arguments to Set#to_set", NULL);
686 klass = argv[0];
687 argv[0] = set;
688 }
689
690 if (klass == rb_cSet && rb_obj_is_instance_of(set, rb_cSet) &&
691 argc == 1 && !rb_block_given_p()) {
692 return set;
693 }
694
695 return rb_funcall_passing_block(klass, id_new, argc, argv);
696}
697
698/*
699 * call-seq:
700 * join(separator=nil)-> new_string
701 *
702 * Returns a string created by converting each element of the set to a string.
703 */
704static VALUE
705set_i_join(int argc, VALUE *argv, VALUE set)
706{
707 rb_check_arity(argc, 0, 1);
708 return rb_ary_join(set_i_to_a(set), argc == 0 ? Qnil : argv[0]);
709}
710
711/*
712 * call-seq:
713 * add(obj) -> self
714 *
715 * Adds the given object to the set and returns self. Use Set#merge to
716 * add many elements at once.
717 *
718 * Set[1, 2].add(3) #=> Set[1, 2, 3]
719 * Set[1, 2].add([3, 4]) #=> Set[1, 2, [3, 4]]
720 * Set[1, 2].add(2) #=> Set[1, 2]
721 */
722static VALUE
723set_i_add(VALUE set, VALUE item)
724{
725 rb_check_frozen(set);
726 if (set_iterating_p(set)) {
727 if (!set_table_lookup(RSET_TABLE(set), (st_data_t)item)) {
728 no_new_item();
729 }
730 }
731 else {
732 set_insert_wb(set, item, NULL);
733 }
734 return set;
735}
736
737/*
738 * call-seq:
739 * add?(obj) -> self or nil
740 *
741 * Adds the given object to the set and returns self. If the object is
742 * already in the set, returns nil.
743 *
744 * Set[1, 2].add?(3) #=> Set[1, 2, 3]
745 * Set[1, 2].add?([3, 4]) #=> Set[1, 2, [3, 4]]
746 * Set[1, 2].add?(2) #=> nil
747 */
748static VALUE
749set_i_add_p(VALUE set, VALUE item)
750{
751 rb_check_frozen(set);
752 if (set_iterating_p(set)) {
753 if (!set_table_lookup(RSET_TABLE(set), (st_data_t)item)) {
754 no_new_item();
755 }
756 return Qnil;
757 }
758 else {
759 return set_insert_wb(set, item, NULL) ? Qnil : set;
760 }
761}
762
763/*
764 * call-seq:
765 * delete(obj) -> self
766 *
767 * Deletes the given object from the set and returns self. Use subtract
768 * to delete many items at once.
769 */
770static VALUE
771set_i_delete(VALUE set, VALUE item)
772{
773 rb_check_frozen(set);
774 if (set_table_delete(RSET_TABLE(set), (st_data_t *)&item)) {
775 set_compact_after_delete(set);
776 }
777 return set;
778}
779
780/*
781 * call-seq:
782 * delete?(obj) -> self or nil
783 *
784 * Deletes the given object from the set and returns self. If the
785 * object is not in the set, returns nil.
786 */
787static VALUE
788set_i_delete_p(VALUE set, VALUE item)
789{
790 rb_check_frozen(set);
791 if (set_table_delete(RSET_TABLE(set), (st_data_t *)&item)) {
792 set_compact_after_delete(set);
793 return set;
794 }
795 return Qnil;
796}
797
798static int
799set_delete_if_i(st_data_t key, st_data_t dummy)
800{
801 return RTEST(rb_yield((VALUE)key)) ? ST_DELETE : ST_CONTINUE;
802}
803
804/*
805 * call-seq:
806 * delete_if { |o| ... } -> self
807 * delete_if -> enumerator
808 *
809 * Deletes every element of the set for which block evaluates to
810 * true, and returns self. Returns an enumerator if no block is given.
811 */
812static VALUE
813set_i_delete_if(VALUE set)
814{
815 RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
816 rb_check_frozen(set);
817 set_iter(set, set_delete_if_i, 0);
818 set_compact_after_delete(set);
819 return set;
820}
821
822/*
823 * call-seq:
824 * reject! { |o| ... } -> self
825 * reject! -> enumerator
826 *
827 * Equivalent to Set#delete_if, but returns nil if no changes were made.
828 * Returns an enumerator if no block is given.
829 */
830static VALUE
831set_i_reject(VALUE set)
832{
833 RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
834 rb_check_frozen(set);
835
836 set_table *table = RSET_TABLE(set);
837 size_t n = set_table_size(table);
838 set_iter(set, set_delete_if_i, 0);
839
840 if (n == set_table_size(table)) return Qnil;
841
842 set_compact_after_delete(set);
843 return set;
844}
845
846static int
847set_classify_i(st_data_t key, st_data_t tmp)
848{
849 VALUE* args = (VALUE*)tmp;
850 VALUE hash = args[0];
851 VALUE hash_key = rb_yield(key);
852 VALUE set = rb_hash_lookup2(hash, hash_key, Qundef);
853 if (set == Qundef) {
854 set = set_s_alloc(args[1]);
855 rb_hash_aset(hash, hash_key, set);
856 }
857 set_i_add(set, key);
858
859 return ST_CONTINUE;
860}
861
862/*
863 * call-seq:
864 * classify { |o| ... } -> hash
865 * classify -> enumerator
866 *
867 * Classifies the set by the return value of the given block and
868 * returns a hash of {value => set of elements} pairs. The block is
869 * called once for each element of the set, passing the element as
870 * parameter.
871 *
872 * files = Set.new(Dir.glob("*.rb"))
873 * hash = files.classify { |f| File.mtime(f).year }
874 * hash #=> {2000 => Set["a.rb", "b.rb"],
875 * # 2001 => Set["c.rb", "d.rb", "e.rb"],
876 * # 2002 => Set["f.rb"]}
877 *
878 * Returns an enumerator if no block is given.
879 */
880static VALUE
881set_i_classify(VALUE set)
882{
883 RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
884 VALUE args[2];
885 args[0] = rb_hash_new();
886 args[1] = rb_obj_class(set);
887 set_iter(set, set_classify_i, (st_data_t)args);
888 return args[0];
889}
890
891// Union-find with path compression
892static long
893set_divide_union_find_root(long *uf_parents, long index, long *tmp_array)
894{
895 long root = uf_parents[index];
896 long update_size = 0;
897 while (root != index) {
898 tmp_array[update_size++] = index;
899 index = root;
900 root = uf_parents[index];
901 }
902 for (long j = 0; j < update_size; j++) {
903 long idx = tmp_array[j];
904 uf_parents[idx] = root;
905 }
906 return root;
907}
908
909static void
910set_divide_union_find_merge(long *uf_parents, long i, long j, long *tmp_array)
911{
912 long root_i = set_divide_union_find_root(uf_parents, i, tmp_array);
913 long root_j = set_divide_union_find_root(uf_parents, j, tmp_array);
914 if (root_i != root_j) uf_parents[root_j] = root_i;
915}
916
917static VALUE
918set_divide_arity2(VALUE set)
919{
920 VALUE tmp, uf;
921 long size, *uf_parents, *tmp_array;
922 VALUE set_class = rb_obj_class(set);
923 VALUE items = set_i_to_a(set);
924 rb_ary_freeze(items);
925 size = RARRAY_LEN(items);
926 tmp_array = ALLOCV_N(long, tmp, size);
927 uf_parents = ALLOCV_N(long, uf, size);
928 for (long i = 0; i < size; i++) {
929 uf_parents[i] = i;
930 }
931 for (long i = 0; i < size - 1; i++) {
932 VALUE item1 = RARRAY_AREF(items, i);
933 for (long j = i + 1; j < size; j++) {
934 VALUE item2 = RARRAY_AREF(items, j);
935 if (RTEST(rb_yield_values(2, item1, item2)) &&
936 RTEST(rb_yield_values(2, item2, item1))) {
937 set_divide_union_find_merge(uf_parents, i, j, tmp_array);
938 }
939 }
940 }
941 VALUE final_set = set_s_create(0, 0, rb_cSet);
942 VALUE hash = rb_hash_new();
943 for (long i = 0; i < size; i++) {
944 VALUE v = RARRAY_AREF(items, i);
945 long root = set_divide_union_find_root(uf_parents, i, tmp_array);
946 VALUE set = rb_hash_aref(hash, LONG2FIX(root));
947 if (set == Qnil) {
948 set = set_s_create(0, 0, set_class);
949 rb_hash_aset(hash, LONG2FIX(root), set);
950 set_i_add(final_set, set);
951 }
952 set_i_add(set, v);
953 }
954 ALLOCV_END(tmp);
955 ALLOCV_END(uf);
956 return final_set;
957}
958
959static void set_merge_enum_into(VALUE set, VALUE arg);
960
961/*
962 * call-seq:
963 * divide { |o1, o2| ... } -> set
964 * divide { |o| ... } -> set
965 * divide -> enumerator
966 *
967 * Divides the set into a set of subsets according to the commonality
968 * defined by the given block.
969 *
970 * If the arity of the block is 2, elements o1 and o2 are in common
971 * if both block.call(o1, o2) and block.call(o2, o1) are true.
972 * Otherwise, elements o1 and o2 are in common if
973 * block.call(o1) == block.call(o2).
974 *
975 * numbers = Set[1, 3, 4, 6, 9, 10, 11]
976 * set = numbers.divide { |i,j| (i - j).abs == 1 }
977 * set #=> Set[Set[1],
978 * # Set[3, 4],
979 * # Set[6],
980 * # Set[9, 10, 11]]
981 *
982 * Returns an enumerator if no block is given.
983 */
984static VALUE
985set_i_divide(VALUE set)
986{
987 RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
988
989 if (rb_block_arity() == 2) {
990 return set_divide_arity2(set);
991 }
992
993 VALUE values = rb_hash_values(set_i_classify(set));
994 set = set_alloc_with_size(rb_cSet, RARRAY_LEN(values));
995 set_merge_enum_into(set, values);
996 return set;
997}
998
999static int
1000set_clear_i(st_data_t key, st_data_t dummy)
1001{
1002 return ST_DELETE;
1003}
1004
1005/*
1006 * call-seq:
1007 * clear -> self
1008 *
1009 * Removes all elements and returns self.
1010 *
1011 * set = Set[1, 'c', :s] #=> Set[1, "c", :s]
1012 * set.clear #=> Set[]
1013 * set #=> Set[]
1014 */
1015static VALUE
1016set_i_clear(VALUE set)
1017{
1018 rb_check_frozen(set);
1019 if (RSET_SIZE(set) == 0) return set;
1020 if (set_iterating_p(set)) {
1021 set_iter(set, set_clear_i, 0);
1022 }
1023 else {
1024 set_table_clear(RSET_TABLE(set));
1025 set_compact_after_delete(set);
1026 }
1027 return set;
1028}
1029
1031 VALUE set;
1032 set_table *into;
1033 set_table *other;
1034};
1035
1036static int
1037set_intersection_i(st_data_t key, st_data_t tmp)
1038{
1039 struct set_intersection_data *data = (struct set_intersection_data *)tmp;
1040 if (set_table_lookup(data->other, key)) {
1041 set_table_insert_wb(data->into, data->set, key, NULL);
1042 }
1043
1044 return ST_CONTINUE;
1045}
1046
1047static VALUE
1048set_intersection_block(RB_BLOCK_CALL_FUNC_ARGLIST(i, data))
1049{
1050 set_intersection_i((st_data_t)i, (st_data_t)data);
1051 return i;
1052}
1053
1054/*
1055 * call-seq:
1056 * set & enum -> new_set
1057 *
1058 * Returns a new set containing elements common to the set and the given
1059 * enumerable object.
1060 *
1061 * Set[1, 3, 5] & Set[3, 2, 1] #=> Set[3, 1]
1062 * Set['a', 'b', 'z'] & ['a', 'b', 'c'] #=> Set["a", "b"]
1063 */
1064static VALUE
1065set_i_intersection(VALUE set, VALUE other)
1066{
1067 VALUE new_set = set_s_alloc(rb_obj_class(set));
1068 set_table *stable = RSET_TABLE(set);
1069 set_table *ntable = RSET_TABLE(new_set);
1070
1071 if (rb_obj_is_kind_of(other, rb_cSet)) {
1072 set_table *otable = RSET_TABLE(other);
1073 if (set_table_size(stable) >= set_table_size(otable)) {
1074 /* Swap so we iterate over the smaller set */
1075 otable = stable;
1076 set = other;
1077 }
1078
1079 struct set_intersection_data data = {
1080 .set = new_set,
1081 .into = ntable,
1082 .other = otable
1083 };
1084 set_iter(set, set_intersection_i, (st_data_t)&data);
1085 }
1086 else {
1087 struct set_intersection_data data = {
1088 .set = new_set,
1089 .into = ntable,
1090 .other = stable
1091 };
1092 rb_block_call(other, enum_method_id(other), 0, 0, set_intersection_block, (VALUE)&data);
1093 }
1094
1095 return new_set;
1096}
1097
1098/*
1099 * call-seq:
1100 * include?(item) -> true or false
1101 *
1102 * Returns true if the set contains the given object:
1103 *
1104 * Set[1, 2, 3].include? 2 #=> true
1105 * Set[1, 2, 3].include? 4 #=> false
1106 *
1107 * Note that <code>include?</code> and <code>member?</code> do not test member
1108 * equality using <code>==</code> as do other Enumerables.
1109 *
1110 * This is aliased to #===, so it is usable in +case+ expressions:
1111 *
1112 * case :apple
1113 * when Set[:potato, :carrot]
1114 * "vegetable"
1115 * when Set[:apple, :banana]
1116 * "fruit"
1117 * end
1118 * # => "fruit"
1119 *
1120 * See also Enumerable#include?
1121 */
1122static VALUE
1123set_i_include(VALUE set, VALUE item)
1124{
1125 return RBOOL(RSET_IS_MEMBER(set, item));
1126}
1127
1129 VALUE set;
1130 set_table *into;
1131};
1132
1133static int
1134set_merge_i(st_data_t key, st_data_t data)
1135{
1136 struct set_merge_args *args = (struct set_merge_args *)data;
1137 set_table_insert_wb(args->into, args->set, key, NULL);
1138 return ST_CONTINUE;
1139}
1140
1141static VALUE
1142set_merge_block(RB_BLOCK_CALL_FUNC_ARGLIST(key, set))
1143{
1144 VALUE element = key;
1145 set_insert_wb(set, element, &element);
1146 return element;
1147}
1148
1149static void
1150set_merge_enum_into(VALUE set, VALUE arg)
1151{
1152 if (rb_obj_is_kind_of(arg, rb_cSet)) {
1153 struct set_merge_args args = {
1154 .set = set,
1155 .into = RSET_TABLE(set)
1156 };
1157 set_iter(arg, set_merge_i, (st_data_t)&args);
1158 }
1159 else if (RB_TYPE_P(arg, T_ARRAY)) {
1160 long i;
1161 set_table *into = RSET_TABLE(set);
1162 for (i=0; i<RARRAY_LEN(arg); i++) {
1163 set_table_insert_wb(into, set, RARRAY_AREF(arg, i), NULL);
1164 }
1165 }
1166 else {
1167 rb_block_call(arg, enum_method_id(arg), 0, 0, set_merge_block, (VALUE)set);
1168 }
1169}
1170
1171/*
1172 * call-seq:
1173 * merge(*enums, **nil) -> self
1174 *
1175 * Merges the elements of the given enumerable objects to the set and
1176 * returns self.
1177 */
1178static VALUE
1179set_i_merge(int argc, VALUE *argv, VALUE set)
1180{
1181 if (rb_keyword_given_p()) {
1182 rb_raise(rb_eArgError, "no keywords accepted");
1183 }
1184
1185 if (set_iterating_p(set)) {
1186 rb_raise(rb_eRuntimeError, "cannot add to set during iteration");
1187 }
1188
1189 rb_check_frozen(set);
1190
1191 int i;
1192
1193 for (i=0; i < argc; i++) {
1194 set_merge_enum_into(set, argv[i]);
1195 }
1196
1197 return set;
1198}
1199
1200static VALUE
1201set_reset_table_with_type(VALUE set, const struct st_hash_type *type)
1202{
1203 rb_check_frozen(set);
1204
1205 struct set_object *sobj;
1206 TypedData_Get_Struct(set, struct set_object, &set_data_type, sobj);
1207 set_table *old = &sobj->table;
1208
1209 size_t size = set_table_size(old);
1210 if (size > 0) {
1211 set_table *new = set_init_table_with_size(NULL, type, size);
1212 struct set_merge_args args = {
1213 .set = set,
1214 .into = new
1215 };
1216 set_iter(set, set_merge_i, (st_data_t)&args);
1217 set_free_embedded(sobj);
1218 memcpy(&sobj->table, new, sizeof(*new));
1219 free(new);
1220 }
1221 else {
1222 sobj->table.type = type;
1223 }
1224
1225 return set;
1226}
1227
1228/*
1229 * call-seq:
1230 * compare_by_identity -> self
1231 *
1232 * Makes the set compare its elements by their identity and returns self.
1233 */
1234static VALUE
1235set_i_compare_by_identity(VALUE set)
1236{
1237 if (RSET_COMPARE_BY_IDENTITY(set)) return set;
1238
1239 if (set_iterating_p(set)) {
1240 rb_raise(rb_eRuntimeError, "compare_by_identity during iteration");
1241 }
1242
1243 return set_reset_table_with_type(set, &identhash);
1244}
1245
1246/*
1247 * call-seq:
1248 * compare_by_identity? -> true or false
1249 *
1250 * Returns true if the set will compare its elements by their
1251 * identity. Also see Set#compare_by_identity.
1252 */
1253static VALUE
1254set_i_compare_by_identity_p(VALUE set)
1255{
1256 return RBOOL(RSET_COMPARE_BY_IDENTITY(set));
1257}
1258
1259/*
1260 * call-seq:
1261 * size -> integer
1262 *
1263 * Returns the number of elements.
1264 */
1265static VALUE
1266set_i_size(VALUE set)
1267{
1268 return RSET_SIZE_NUM(set);
1269}
1270
1271/*
1272 * call-seq:
1273 * empty? -> true or false
1274 *
1275 * Returns true if the set contains no elements.
1276 */
1277static VALUE
1278set_i_empty(VALUE set)
1279{
1280 return RBOOL(RSET_EMPTY(set));
1281}
1282
1283static int
1284set_xor_i(st_data_t key, st_data_t data)
1285{
1286 VALUE element = (VALUE)key;
1287 VALUE set = (VALUE)data;
1288 set_table *table = RSET_TABLE(set);
1289 if (set_table_insert_wb(table, set, element, &element)) {
1290 set_table_delete(table, &element);
1291 }
1292 return ST_CONTINUE;
1293}
1294
1295/*
1296 * call-seq:
1297 * set ^ enum -> new_set
1298 *
1299 * Returns a new set containing elements exclusive between the set and the
1300 * given enumerable object. <tt>(set ^ enum)</tt> is equivalent to
1301 * <tt>((set | enum) - (set & enum))</tt>.
1302 *
1303 * Set[1, 2] ^ Set[2, 3] #=> Set[3, 1]
1304 * Set[1, 'b', 'c'] ^ ['b', 'd'] #=> Set["d", 1, "c"]
1305 */
1306static VALUE
1307set_i_xor(VALUE set, VALUE other)
1308{
1309 VALUE new_set = rb_obj_dup(set);
1310
1311 if (rb_obj_is_kind_of(other, rb_cSet)) {
1312 set_iter(other, set_xor_i, (st_data_t)new_set);
1313 }
1314 else {
1315 VALUE tmp = set_s_alloc(rb_cSet);
1316 set_merge_enum_into(tmp, other);
1317 set_iter(tmp, set_xor_i, (st_data_t)new_set);
1318 }
1319 set_compact_after_delete(set);
1320
1321 return new_set;
1322}
1323
1324/*
1325 * call-seq:
1326 * set | enum -> new_set
1327 *
1328 * Returns a new set built by merging the set and the elements of the
1329 * given enumerable object.
1330 *
1331 * Set[1, 2, 3] | Set[2, 4, 5] #=> Set[1, 2, 3, 4, 5]
1332 * Set[1, 5, 'z'] | (1..6) #=> Set[1, 5, "z", 2, 3, 4, 6]
1333 */
1334static VALUE
1335set_i_union(VALUE set, VALUE other)
1336{
1337 set = rb_obj_dup(set);
1338 set_merge_enum_into(set, other);
1339 return set;
1340}
1341
1342static int
1343set_remove_i(st_data_t key, st_data_t from)
1344{
1345 set_table_delete((struct set_table *)from, (st_data_t *)&key);
1346 return ST_CONTINUE;
1347}
1348
1349static VALUE
1350set_remove_block(RB_BLOCK_CALL_FUNC_ARGLIST(key, set))
1351{
1352 rb_check_frozen(set);
1353 set_table_delete(RSET_TABLE(set), (st_data_t *)&key);
1354 return key;
1355}
1356
1357static void
1358set_remove_enum_from(VALUE set, VALUE arg)
1359{
1360 if (rb_obj_is_kind_of(arg, rb_cSet)) {
1361 set_iter(arg, set_remove_i, (st_data_t)RSET_TABLE(set));
1362 }
1363 else {
1364 rb_block_call(arg, enum_method_id(arg), 0, 0, set_remove_block, (VALUE)set);
1365 }
1366 set_compact_after_delete(set);
1367}
1368
1369/*
1370 * call-seq:
1371 * subtract(enum) -> self
1372 *
1373 * Deletes every element that appears in the given enumerable object
1374 * and returns self.
1375 */
1376static VALUE
1377set_i_subtract(VALUE set, VALUE other)
1378{
1379 rb_check_frozen(set);
1380 set_remove_enum_from(set, other);
1381 return set;
1382}
1383
1384/*
1385 * call-seq:
1386 * set - enum -> new_set
1387 *
1388 * Returns a new set built by duplicating the set, removing every
1389 * element that appears in the given enumerable object.
1390 *
1391 * Set[1, 3, 5] - Set[1, 5] #=> Set[3]
1392 * Set['a', 'b', 'z'] - ['a', 'c'] #=> Set["b", "z"]
1393 */
1394static VALUE
1395set_i_difference(VALUE set, VALUE other)
1396{
1397 return set_i_subtract(rb_obj_dup(set), other);
1398}
1399
1400static int
1401set_each_i(st_data_t key, st_data_t dummy)
1402{
1403 rb_yield(key);
1404 return ST_CONTINUE;
1405}
1406
1407/*
1408 * call-seq:
1409 * each { |o| ... } -> self
1410 * each -> enumerator
1411 *
1412 * Calls the given block once for each element in the set, passing
1413 * the element as parameter. Returns an enumerator if no block is
1414 * given.
1415 */
1416static VALUE
1417set_i_each(VALUE set)
1418{
1419 RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
1420 set_iter(set, set_each_i, 0);
1421 return set;
1422}
1423
1424static int
1425set_collect_i(st_data_t key, st_data_t data)
1426{
1427 set_insert_wb((VALUE)data, rb_yield((VALUE)key), NULL);
1428 return ST_CONTINUE;
1429}
1430
1431/*
1432 * call-seq:
1433 * collect! { |o| ... } -> self
1434 * collect! -> enumerator
1435 *
1436 * Replaces the elements with ones returned by +collect+.
1437 * Returns an enumerator if no block is given.
1438 */
1439static VALUE
1440set_i_collect(VALUE set)
1441{
1442 RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
1443 rb_check_frozen(set);
1444
1445 VALUE new_set = set_s_alloc(rb_obj_class(set));
1446 set_iter(set, set_collect_i, (st_data_t)new_set);
1447 set_i_initialize_copy(set, new_set);
1448
1449 return set;
1450}
1451
1452static int
1453set_keep_if_i(st_data_t key, st_data_t into)
1454{
1455 if (!RTEST(rb_yield((VALUE)key))) {
1456 set_table_delete((set_table *)into, &key);
1457 }
1458 return ST_CONTINUE;
1459}
1460
1461/*
1462 * call-seq:
1463 * keep_if { |o| ... } -> self
1464 * keep_if -> enumerator
1465 *
1466 * Deletes every element of the set for which block evaluates to false, and
1467 * returns self. Returns an enumerator if no block is given.
1468 */
1469static VALUE
1470set_i_keep_if(VALUE set)
1471{
1472 RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
1473 rb_check_frozen(set);
1474
1475 set_iter(set, set_keep_if_i, (st_data_t)RSET_TABLE(set));
1476 set_compact_after_delete(set);
1477
1478 return set;
1479}
1480
1481/*
1482 * call-seq:
1483 * select! { |o| ... } -> self
1484 * select! -> enumerator
1485 *
1486 * Equivalent to Set#keep_if, but returns nil if no changes were made.
1487 * Returns an enumerator if no block is given.
1488 */
1489static VALUE
1490set_i_select(VALUE set)
1491{
1492 RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
1493 rb_check_frozen(set);
1494
1495 set_table *table = RSET_TABLE(set);
1496 size_t n = set_table_size(table);
1497 set_iter(set, set_keep_if_i, (st_data_t)table);
1498 set_compact_after_delete(set);
1499
1500 return (n == set_table_size(table)) ? Qnil : set;
1501}
1502
1503/*
1504 * call-seq:
1505 * replace(enum) -> self
1506 *
1507 * Replaces the contents of the set with the contents of the given
1508 * enumerable object and returns self.
1509 *
1510 * set = Set[1, 'c', :s] #=> Set[1, "c", :s]
1511 * set.replace([1, 2]) #=> Set[1, 2]
1512 * set #=> Set[1, 2]
1513 */
1514static VALUE
1515set_i_replace(VALUE set, VALUE other)
1516{
1517 rb_check_frozen(set);
1518
1519 if (rb_obj_is_kind_of(other, rb_cSet)) {
1520 set_i_initialize_copy(set, other);
1521 }
1522 else {
1523 if (set_iterating_p(set)) {
1524 rb_raise(rb_eRuntimeError, "cannot replace set during iteration");
1525 }
1526
1527 // make sure enum is enumerable before calling clear
1528 enum_method_id(other);
1529
1530 set_table_clear(RSET_TABLE(set));
1531 set_merge_enum_into(set, other);
1532 }
1533 set_compact_after_delete(set);
1534
1535 return set;
1536}
1537
1538/*
1539 * call-seq:
1540 * reset -> self
1541 *
1542 * Resets the internal state after modification to existing elements
1543 * and returns self. Elements will be reindexed and deduplicated.
1544 */
1545static VALUE
1546set_i_reset(VALUE set)
1547{
1548 if (set_iterating_p(set)) {
1549 rb_raise(rb_eRuntimeError, "reset during iteration");
1550 }
1551
1552 return set_reset_table_with_type(set, RSET_TABLE(set)->type);
1553}
1554
1555static void set_flatten_merge(VALUE set, VALUE from, VALUE seen);
1556
1557static int
1558set_flatten_merge_i(st_data_t item, st_data_t arg)
1559{
1560 VALUE *args = (VALUE *)arg;
1561 VALUE set = args[0];
1562 if (rb_obj_is_kind_of(item, rb_cSet)) {
1563 VALUE e_id = rb_obj_id(item);
1564 VALUE hash = args[2];
1565 switch(rb_hash_aref(hash, e_id)) {
1566 case Qfalse:
1567 return ST_CONTINUE;
1568 case Qtrue:
1569 rb_raise(rb_eArgError, "tried to flatten recursive Set");
1570 default:
1571 break;
1572 }
1573
1574 rb_hash_aset(hash, e_id, Qtrue);
1575 set_flatten_merge(set, item, hash);
1576 rb_hash_aset(hash, e_id, Qfalse);
1577 }
1578 else {
1579 set_i_add(set, item);
1580 }
1581 return ST_CONTINUE;
1582}
1583
1584static void
1585set_flatten_merge(VALUE set, VALUE from, VALUE hash)
1586{
1587 VALUE args[3] = {set, from, hash};
1588 set_iter(from, set_flatten_merge_i, (st_data_t)args);
1589}
1590
1591/*
1592 * call-seq:
1593 * flatten -> set
1594 *
1595 * Returns a new set that is a copy of the set, flattening each
1596 * containing set recursively.
1597 */
1598static VALUE
1599set_i_flatten(VALUE set)
1600{
1601 VALUE new_set = set_s_alloc(rb_obj_class(set));
1602 set_flatten_merge(new_set, set, rb_hash_new());
1603 return new_set;
1604}
1605
1606static int
1607set_contains_set_i(st_data_t item, st_data_t arg)
1608{
1609 if (rb_obj_is_kind_of(item, rb_cSet)) {
1610 *(bool *)arg = true;
1611 return ST_STOP;
1612 }
1613 return ST_CONTINUE;
1614}
1615
1616/*
1617 * call-seq:
1618 * flatten! -> self
1619 *
1620 * Equivalent to Set#flatten, but replaces the receiver with the
1621 * result in place. Returns nil if no modifications were made.
1622 */
1623static VALUE
1624set_i_flatten_bang(VALUE set)
1625{
1626 bool contains_set = false;
1627 set_iter(set, set_contains_set_i, (st_data_t)&contains_set);
1628 if (!contains_set) return Qnil;
1629 rb_check_frozen(set);
1630 return set_i_replace(set, set_i_flatten(set));
1631}
1632
1634 set_table *table;
1635 VALUE result;
1636};
1637
1638static int
1639set_le_i(st_data_t key, st_data_t arg)
1640{
1641 struct set_subset_data *data = (struct set_subset_data *)arg;
1642 if (set_table_lookup(data->table, key)) return ST_CONTINUE;
1643 data->result = Qfalse;
1644 return ST_STOP;
1645}
1646
1647static VALUE
1648set_le(VALUE set, VALUE other)
1649{
1650 struct set_subset_data data = {
1651 .table = RSET_TABLE(other),
1652 .result = Qtrue
1653 };
1654 set_iter(set, set_le_i, (st_data_t)&data);
1655 return data.result;
1656}
1657
1658/*
1659 * call-seq:
1660 * proper_subset?(set) -> true or false
1661 *
1662 * Returns true if the set is a proper subset of the given set.
1663 */
1664static VALUE
1665set_i_proper_subset(VALUE set, VALUE other)
1666{
1667 check_set(other);
1668 if (RSET_SIZE(set) >= RSET_SIZE(other)) return Qfalse;
1669 return set_le(set, other);
1670}
1671
1672/*
1673 * call-seq:
1674 * subset?(set) -> true or false
1675 *
1676 * Returns true if the set is a subset of the given set.
1677 */
1678static VALUE
1679set_i_subset(VALUE set, VALUE other)
1680{
1681 check_set(other);
1682 if (RSET_SIZE(set) > RSET_SIZE(other)) return Qfalse;
1683 return set_le(set, other);
1684}
1685
1686/*
1687 * call-seq:
1688 * proper_superset?(set) -> true or false
1689 *
1690 * Returns true if the set is a proper superset of the given set.
1691 */
1692static VALUE
1693set_i_proper_superset(VALUE set, VALUE other)
1694{
1695 check_set(other);
1696 if (RSET_SIZE(set) <= RSET_SIZE(other)) return Qfalse;
1697 return set_le(other, set);
1698}
1699
1700/*
1701 * call-seq:
1702 * superset?(set) -> true or false
1703 *
1704 * Returns true if the set is a superset of the given set.
1705 */
1706static VALUE
1707set_i_superset(VALUE set, VALUE other)
1708{
1709 check_set(other);
1710 if (RSET_SIZE(set) < RSET_SIZE(other)) return Qfalse;
1711 return set_le(other, set);
1712}
1713
1714static int
1715set_intersect_i(st_data_t key, st_data_t arg)
1716{
1717 VALUE *args = (VALUE *)arg;
1718 if (set_table_lookup((set_table *)args[0], key)) {
1719 args[1] = Qtrue;
1720 return ST_STOP;
1721 }
1722 return ST_CONTINUE;
1723}
1724
1725/*
1726 * call-seq:
1727 * intersect?(set) -> true or false
1728 *
1729 * Returns true if the set and the given enumerable have at least one
1730 * element in common.
1731 *
1732 * Set[1, 2, 3].intersect? Set[4, 5] #=> false
1733 * Set[1, 2, 3].intersect? Set[3, 4] #=> true
1734 * Set[1, 2, 3].intersect? 4..5 #=> false
1735 * Set[1, 2, 3].intersect? [3, 4] #=> true
1736 */
1737static VALUE
1738set_i_intersect(VALUE set, VALUE other)
1739{
1740 if (rb_obj_is_kind_of(other, rb_cSet)) {
1741 size_t set_size = RSET_SIZE(set);
1742 size_t other_size = RSET_SIZE(other);
1743 VALUE args[2];
1744 args[1] = Qfalse;
1745 VALUE iter_arg;
1746
1747 if (set_size < other_size) {
1748 iter_arg = set;
1749 args[0] = (VALUE)RSET_TABLE(other);
1750 }
1751 else {
1752 iter_arg = other;
1753 args[0] = (VALUE)RSET_TABLE(set);
1754 }
1755 set_iter(iter_arg, set_intersect_i, (st_data_t)args);
1756 return args[1];
1757 }
1758 else if (rb_obj_is_kind_of(other, rb_mEnumerable)) {
1759 return rb_funcall(other, id_any_p, 1, set);
1760 }
1761 else {
1762 rb_raise(rb_eArgError, "value must be enumerable");
1763 }
1764}
1765
1766/*
1767 * call-seq:
1768 * disjoint?(set) -> true or false
1769 *
1770 * Returns true if the set and the given enumerable have no
1771 * element in common. This method is the opposite of +intersect?+.
1772 *
1773 * Set[1, 2, 3].disjoint? Set[3, 4] #=> false
1774 * Set[1, 2, 3].disjoint? Set[4, 5] #=> true
1775 * Set[1, 2, 3].disjoint? [3, 4] #=> false
1776 * Set[1, 2, 3].disjoint? 4..5 #=> true
1777 */
1778static VALUE
1779set_i_disjoint(VALUE set, VALUE other)
1780{
1781 return RBOOL(!RTEST(set_i_intersect(set, other)));
1782}
1783
1784/*
1785 * call-seq:
1786 * set <=> other -> -1, 0, 1, or nil
1787 *
1788 * Returns 0 if the set are equal, -1 / 1 if the set is a
1789 * proper subset / superset of the given set, or nil if
1790 * they both have unique elements.
1791 */
1792static VALUE
1793set_i_compare(VALUE set, VALUE other)
1794{
1795 if (rb_obj_is_kind_of(other, rb_cSet)) {
1796 size_t set_size = RSET_SIZE(set);
1797 size_t other_size = RSET_SIZE(other);
1798
1799 if (set_size < other_size) {
1800 if (set_le(set, other) == Qtrue) {
1801 return INT2NUM(-1);
1802 }
1803 }
1804 else if (set_size > other_size) {
1805 if (set_le(other, set) == Qtrue) {
1806 return INT2NUM(1);
1807 }
1808 }
1809 else if (set_le(set, other) == Qtrue) {
1810 return INT2NUM(0);
1811 }
1812 }
1813
1814 return Qnil;
1815}
1816
1818 VALUE result;
1819 VALUE set;
1820};
1821
1822static int
1823set_eql_i(st_data_t item, st_data_t arg)
1824{
1825 struct set_equal_data *data = (struct set_equal_data *)arg;
1826
1827 if (!set_table_lookup(RSET_TABLE(data->set), item)) {
1828 data->result = Qfalse;
1829 return ST_STOP;
1830 }
1831 return ST_CONTINUE;
1832}
1833
1834static VALUE
1835set_recursive_eql(VALUE set, VALUE dt, int recur)
1836{
1837 if (recur) return Qtrue;
1838 struct set_equal_data *data = (struct set_equal_data*)dt;
1839 data->result = Qtrue;
1840 set_iter(set, set_eql_i, dt);
1841 return data->result;
1842}
1843
1844/*
1845 * call-seq:
1846 * set == other -> true or false
1847 *
1848 * Returns true if two sets are equal.
1849 */
1850static VALUE
1851set_i_eq(VALUE set, VALUE other)
1852{
1853 if (!rb_obj_is_kind_of(other, rb_cSet)) return Qfalse;
1854 if (set == other) return Qtrue;
1855
1856 set_table *stable = RSET_TABLE(set);
1857 set_table *otable = RSET_TABLE(other);
1858 size_t ssize = set_table_size(stable);
1859 size_t osize = set_table_size(otable);
1860
1861 if (ssize != osize) return Qfalse;
1862 if (ssize == 0 && osize == 0) return Qtrue;
1863 if (stable->type != otable->type) return Qfalse;
1864
1865 struct set_equal_data data;
1866 data.set = other;
1867 return rb_exec_recursive_paired(set_recursive_eql, set, other, (VALUE)&data);
1868}
1869
1870static int
1871set_hash_i(st_data_t item, st_data_t(arg))
1872{
1873 st_index_t *hval = (st_index_t *)arg;
1874 st_index_t ival = rb_hash(item);
1875 *hval ^= rb_st_hash(&ival, sizeof(st_index_t), 0);
1876 return ST_CONTINUE;
1877}
1878
1879/*
1880 * call-seq:
1881 * hash -> integer
1882 *
1883 * Returns hash code for set.
1884 */
1885static VALUE
1886set_i_hash(VALUE set)
1887{
1888 st_index_t size = RSET_SIZE(set);
1889 st_index_t hval = rb_st_hash_start(size);
1890 hval = rb_hash_uint(hval, (st_index_t)set_i_hash);
1891 if (size) {
1892 set_iter(set, set_hash_i, (VALUE)&hval);
1893 }
1894 hval = rb_st_hash_end(hval);
1895 return ST2FIX(hval);
1896}
1897
1898/* :nodoc: */
1899static int
1900set_to_hash_i(st_data_t key, st_data_t arg)
1901{
1902 rb_hash_aset((VALUE)arg, (VALUE)key, Qtrue);
1903 return ST_CONTINUE;
1904}
1905
1906static VALUE
1907set_i_to_h(VALUE set)
1908{
1909 st_index_t size = RSET_SIZE(set);
1910 VALUE hash;
1911 if (RSET_COMPARE_BY_IDENTITY(set)) {
1912 hash = rb_ident_hash_new_with_size(size);
1913 }
1914 else {
1915 hash = rb_hash_new_with_size(size);
1916 }
1917 rb_hash_set_default(hash, Qfalse);
1918
1919 if (size == 0) return hash;
1920
1921 set_iter(set, set_to_hash_i, (st_data_t)hash);
1922 return hash;
1923}
1924
1925static VALUE
1926compat_dumper(VALUE set)
1927{
1928 VALUE dumper = rb_class_new_instance(0, 0, rb_cObject);
1929 rb_ivar_set(dumper, id_i_hash, set_i_to_h(set));
1930 return dumper;
1931}
1932
1933static int
1934set_i_from_hash_i(st_data_t key, st_data_t val, st_data_t set)
1935{
1936 if ((VALUE)val != Qtrue) {
1937 rb_raise(rb_eRuntimeError, "expect true as Set value: %"PRIsVALUE, rb_obj_class((VALUE)val));
1938 }
1939 set_i_add((VALUE)set, (VALUE)key);
1940 return ST_CONTINUE;
1941}
1942
1943static VALUE
1944set_i_from_hash(VALUE set, VALUE hash)
1945{
1946 Check_Type(hash, T_HASH);
1947 if (rb_hash_compare_by_id_p(hash)) set_i_compare_by_identity(set);
1948 rb_hash_stlike_foreach(hash, set_i_from_hash_i, (st_data_t)set);
1949 return set;
1950}
1951
1952static VALUE
1953compat_loader(VALUE self, VALUE a)
1954{
1955 return set_i_from_hash(self, rb_ivar_get(a, id_i_hash));
1956}
1957
1958/* C-API functions */
1959
1960void
1961rb_set_foreach(VALUE set, int (*func)(VALUE element, VALUE arg), VALUE arg)
1962{
1963 set_iter(set, func, arg);
1964}
1965
1966VALUE
1968{
1969 return set_alloc_with_size(rb_cSet, 0);
1970}
1971
1972VALUE
1974{
1975 return set_alloc_with_size(rb_cSet, (st_index_t)capa);
1976}
1977
1978bool
1980{
1981 return RSET_IS_MEMBER(set, element);
1982}
1983
1984bool
1986{
1987 return set_i_add_p(set, element) != Qnil;
1988}
1989
1990VALUE
1992{
1993 return set_i_clear(set);
1994}
1995
1996bool
1998{
1999 return set_i_delete_p(set, element) != Qnil;
2000}
2001
2002size_t
2004{
2005 return RSET_SIZE(set);
2006}
2007
2008/*
2009 * Document-class: Set
2010 *
2011 * The Set class implements a collection of unordered values with no
2012 * duplicates. It is a hybrid of Array's intuitive inter-operation
2013 * facilities and Hash's fast lookup.
2014 *
2015 * Set is easy to use with Enumerable objects (implementing #each).
2016 * Most of the initializer methods and binary operators accept generic
2017 * Enumerable objects besides sets and arrays. An Enumerable object
2018 * can be converted to Set using the +to_set+ method.
2019 *
2020 * Set uses a data structure similar to Hash for storage, except that
2021 * it only has keys and no values.
2022 *
2023 * * Equality of elements is determined according to Object#eql? and
2024 * Object#hash. Use Set#compare_by_identity to make a set compare
2025 * its elements by their identity.
2026 * * Set assumes that the identity of each element does not change
2027 * while it is stored. Modifying an element of a set will render the
2028 * set to an unreliable state.
2029 * * When a string is to be stored, a frozen copy of the string is
2030 * stored instead unless the original string is already frozen.
2031 *
2032 * == Comparison
2033 *
2034 * The comparison operators <tt><</tt>, <tt>></tt>, <tt><=</tt>, and
2035 * <tt>>=</tt> are implemented as shorthand for the
2036 * {proper_,}{subset?,superset?} methods. The <tt><=></tt>
2037 * operator reflects this order, or returns +nil+ for sets that both
2038 * have distinct elements (<tt>{x, y}</tt> vs. <tt>{x, z}</tt> for example).
2039 *
2040 * == Example
2041 *
2042 * s1 = Set[1, 2] #=> Set[1, 2]
2043 * s2 = [1, 2].to_set #=> Set[1, 2]
2044 * s1 == s2 #=> true
2045 * s1.add("foo") #=> Set[1, 2, "foo"]
2046 * s1.merge([2, 6]) #=> Set[1, 2, "foo", 6]
2047 * s1.subset?(s2) #=> false
2048 * s2.subset?(s1) #=> true
2049 *
2050 * == Contact
2051 *
2052 * - Akinori MUSHA <knu@iDaemons.org> (current maintainer)
2053 *
2054 * == Inheriting from \Set
2055 *
2056 * Before Ruby 4.0 (released December 2025), \Set had a different, less
2057 * efficient implementation. It was reimplemented in C, and the behavior
2058 * of some of the core methods were adjusted.
2059 *
2060 * To keep backward compatibility, when a class is inherited from \Set,
2061 * additional module +Set::SubclassCompatible+ is included, which makes
2062 * the inherited class behavior, as well as internal method names,
2063 * closer to what it was before Ruby 4.0.
2064 *
2065 * It can be easily seen, for example, in the #inspect method behavior:
2066 *
2067 * p Set[1, 2, 3]
2068 * # prints "Set[1, 2, 3]"
2069 *
2070 * class MySet < Set
2071 * end
2072 * p MySet[1, 2, 3]
2073 * # prints "#<MySet: {1, 2, 3}>", like it was in Ruby 3.4
2074 *
2075 * For new code, if backward compatibility is not necessary,
2076 * it is recommended to instead inherit from +Set::CoreSet+, which
2077 * avoids including the "compatibility" layer:
2078 *
2079 * class MyCoreSet < Set::CoreSet
2080 * end
2081 * p MyCoreSet[1, 2, 3]
2082 * # prints "MyCoreSet[1, 2, 3]"
2083 *
2084 * == Set's methods
2085 *
2086 * First, what's elsewhere. \Class \Set:
2087 *
2088 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
2089 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
2090 * which provides dozens of additional methods.
2091 *
2092 * In particular, class \Set does not have many methods of its own
2093 * for fetching or for iterating.
2094 * Instead, it relies on those in \Enumerable.
2095 *
2096 * Here, class \Set provides methods that are useful for:
2097 *
2098 * - {Creating a Set}[rdoc-ref:Set@Methods+for+Creating+a+Set]
2099 * - {Set Operations}[rdoc-ref:Set@Methods+for+Set+Operations]
2100 * - {Comparing}[rdoc-ref:Set@Methods+for+Comparing]
2101 * - {Querying}[rdoc-ref:Set@Methods+for+Querying]
2102 * - {Assigning}[rdoc-ref:Set@Methods+for+Assigning]
2103 * - {Deleting}[rdoc-ref:Set@Methods+for+Deleting]
2104 * - {Converting}[rdoc-ref:Set@Methods+for+Converting]
2105 * - {Iterating}[rdoc-ref:Set@Methods+for+Iterating]
2106 * - {And more....}[rdoc-ref:Set@Other+Methods]
2107 *
2108 * === Methods for Creating a \Set
2109 *
2110 * - ::[]:
2111 * Returns a new set containing the given objects.
2112 * - ::new:
2113 * Returns a new set containing either the given objects
2114 * (if no block given) or the return values from the called block
2115 * (if a block given).
2116 *
2117 * === Methods for \Set Operations
2118 *
2119 * - #| (aliased as #union and #+):
2120 * Returns a new set containing all elements from +self+
2121 * and all elements from a given enumerable (no duplicates).
2122 * - #& (aliased as #intersection):
2123 * Returns a new set containing all elements common to +self+
2124 * and a given enumerable.
2125 * - #- (aliased as #difference):
2126 * Returns a copy of +self+ with all elements
2127 * in a given enumerable removed.
2128 * - #^: Returns a new set containing all elements from +self+
2129 * and a given enumerable except those common to both.
2130 *
2131 * === Methods for Comparing
2132 *
2133 * - #<=>: Returns -1, 0, or 1 as +self+ is less than, equal to,
2134 * or greater than a given object.
2135 * - #==: Returns whether +self+ and a given enumerable are equal,
2136 * as determined by Object#eql?.
2137 * - #compare_by_identity?:
2138 * Returns whether the set considers only identity
2139 * when comparing elements.
2140 *
2141 * === Methods for Querying
2142 *
2143 * - #length (aliased as #size):
2144 * Returns the count of elements.
2145 * - #empty?:
2146 * Returns whether the set has no elements.
2147 * - #include? (aliased as #member? and #===):
2148 * Returns whether a given object is an element in the set.
2149 * - #subset? (aliased as #<=):
2150 * Returns whether a given object is a subset of the set.
2151 * - #proper_subset? (aliased as #<):
2152 * Returns whether a given enumerable is a proper subset of the set.
2153 * - #superset? (aliased as #>=):
2154 * Returns whether a given enumerable is a superset of the set.
2155 * - #proper_superset? (aliased as #>):
2156 * Returns whether a given enumerable is a proper superset of the set.
2157 * - #disjoint?:
2158 * Returns +true+ if the set and a given enumerable
2159 * have no common elements, +false+ otherwise.
2160 * - #intersect?:
2161 * Returns +true+ if the set and a given enumerable:
2162 * have any common elements, +false+ otherwise.
2163 * - #compare_by_identity?:
2164 * Returns whether the set considers only identity
2165 * when comparing elements.
2166 *
2167 * === Methods for Assigning
2168 *
2169 * - #add (aliased as #<<):
2170 * Adds a given object to the set; returns +self+.
2171 * - #add?:
2172 * If the given object is not an element in the set,
2173 * adds it and returns +self+; otherwise, returns +nil+.
2174 * - #merge:
2175 * Merges the elements of each given enumerable object to the set; returns +self+.
2176 * - #replace:
2177 * Replaces the contents of the set with the contents
2178 * of a given enumerable.
2179 *
2180 * === Methods for Deleting
2181 *
2182 * - #clear:
2183 * Removes all elements in the set; returns +self+.
2184 * - #delete:
2185 * Removes a given object from the set; returns +self+.
2186 * - #delete?:
2187 * If the given object is an element in the set,
2188 * removes it and returns +self+; otherwise, returns +nil+.
2189 * - #subtract:
2190 * Removes each given object from the set; returns +self+.
2191 * - #delete_if - Removes elements specified by a given block.
2192 * - #select! (aliased as #filter!):
2193 * Removes elements not specified by a given block.
2194 * - #keep_if:
2195 * Removes elements not specified by a given block.
2196 * - #reject!
2197 * Removes elements specified by a given block.
2198 *
2199 * === Methods for Converting
2200 *
2201 * - #classify:
2202 * Returns a hash that classifies the elements,
2203 * as determined by the given block.
2204 * - #collect! (aliased as #map!):
2205 * Replaces each element with a block return-value.
2206 * - #divide:
2207 * Returns a hash that classifies the elements,
2208 * as determined by the given block;
2209 * differs from #classify in that the block may accept
2210 * either one or two arguments.
2211 * - #flatten:
2212 * Returns a new set that is a recursive flattening of +self+.
2213 * - #flatten!:
2214 * Replaces each nested set in +self+ with the elements from that set.
2215 * - #inspect (aliased as #to_s):
2216 * Returns a string displaying the elements.
2217 * - #join:
2218 * Returns a string containing all elements, converted to strings
2219 * as needed, and joined by the given record separator.
2220 * - #to_a:
2221 * Returns an array containing all set elements.
2222 * - #to_set:
2223 * Returns +self+ if given no arguments and no block;
2224 * with a block given, returns a new set consisting of block
2225 * return values.
2226 *
2227 * === Methods for Iterating
2228 *
2229 * - #each:
2230 * Calls the block with each successive element; returns +self+.
2231 *
2232 * === Other Methods
2233 *
2234 * - #reset:
2235 * Resets the internal state; useful if an object
2236 * has been modified while an element in the set.
2237 *
2238 */
2239void
2240Init_Set(void)
2241{
2242 rb_cSet = rb_define_class("Set", rb_cObject);
2244
2245 id_each_entry = rb_intern_const("each_entry");
2246 id_any_p = rb_intern_const("any?");
2247 id_new = rb_intern_const("new");
2248 id_i_hash = rb_intern_const("@hash");
2249 id_subclass_compatible = rb_intern_const("SubclassCompatible");
2250 id_class_methods = rb_intern_const("ClassMethods");
2251 id_set_iter_lev = rb_make_internal_id();
2252
2253 rb_define_alloc_func(rb_cSet, set_s_alloc);
2254 rb_define_singleton_method(rb_cSet, "[]", set_s_create, -1);
2255
2256 rb_define_method(rb_cSet, "initialize", set_i_initialize, -1);
2257 rb_define_method(rb_cSet, "initialize_copy", set_i_initialize_copy, 1);
2258
2259 rb_define_method(rb_cSet, "&", set_i_intersection, 1);
2260 rb_define_alias(rb_cSet, "intersection", "&");
2261 rb_define_method(rb_cSet, "-", set_i_difference, 1);
2262 rb_define_alias(rb_cSet, "difference", "-");
2263 rb_define_method(rb_cSet, "^", set_i_xor, 1);
2264 rb_define_method(rb_cSet, "|", set_i_union, 1);
2265 rb_define_alias(rb_cSet, "+", "|");
2266 rb_define_alias(rb_cSet, "union", "|");
2267 rb_define_method(rb_cSet, "<=>", set_i_compare, 1);
2268 rb_define_method(rb_cSet, "==", set_i_eq, 1);
2269 rb_define_alias(rb_cSet, "eql?", "==");
2270 rb_define_method(rb_cSet, "add", set_i_add, 1);
2271 rb_define_alias(rb_cSet, "<<", "add");
2272 rb_define_method(rb_cSet, "add?", set_i_add_p, 1);
2273 rb_define_method(rb_cSet, "classify", set_i_classify, 0);
2274 rb_define_method(rb_cSet, "clear", set_i_clear, 0);
2275 rb_define_method(rb_cSet, "collect!", set_i_collect, 0);
2276 rb_define_alias(rb_cSet, "map!", "collect!");
2277 rb_define_method(rb_cSet, "compare_by_identity", set_i_compare_by_identity, 0);
2278 rb_define_method(rb_cSet, "compare_by_identity?", set_i_compare_by_identity_p, 0);
2279 rb_define_method(rb_cSet, "delete", set_i_delete, 1);
2280 rb_define_method(rb_cSet, "delete?", set_i_delete_p, 1);
2281 rb_define_method(rb_cSet, "delete_if", set_i_delete_if, 0);
2282 rb_define_method(rb_cSet, "disjoint?", set_i_disjoint, 1);
2283 rb_define_method(rb_cSet, "divide", set_i_divide, 0);
2284 rb_define_method(rb_cSet, "each", set_i_each, 0);
2285 rb_define_method(rb_cSet, "empty?", set_i_empty, 0);
2286 rb_define_method(rb_cSet, "flatten", set_i_flatten, 0);
2287 rb_define_method(rb_cSet, "flatten!", set_i_flatten_bang, 0);
2288 rb_define_method(rb_cSet, "hash", set_i_hash, 0);
2289 rb_define_method(rb_cSet, "include?", set_i_include, 1);
2290 rb_define_alias(rb_cSet, "member?", "include?");
2291 rb_define_alias(rb_cSet, "===", "include?");
2292 rb_define_method(rb_cSet, "inspect", set_i_inspect, 0);
2293 rb_define_alias(rb_cSet, "to_s", "inspect");
2294 rb_define_method(rb_cSet, "intersect?", set_i_intersect, 1);
2295 rb_define_method(rb_cSet, "join", set_i_join, -1);
2296 rb_define_method(rb_cSet, "keep_if", set_i_keep_if, 0);
2297 rb_define_method(rb_cSet, "merge", set_i_merge, -1);
2298 rb_define_method(rb_cSet, "proper_subset?", set_i_proper_subset, 1);
2299 rb_define_alias(rb_cSet, "<", "proper_subset?");
2300 rb_define_method(rb_cSet, "proper_superset?", set_i_proper_superset, 1);
2301 rb_define_alias(rb_cSet, ">", "proper_superset?");
2302 rb_define_method(rb_cSet, "reject!", set_i_reject, 0);
2303 rb_define_method(rb_cSet, "replace", set_i_replace, 1);
2304 rb_define_method(rb_cSet, "reset", set_i_reset, 0);
2305 rb_define_method(rb_cSet, "size", set_i_size, 0);
2306 rb_define_alias(rb_cSet, "length", "size");
2307 rb_define_method(rb_cSet, "select!", set_i_select, 0);
2308 rb_define_alias(rb_cSet, "filter!", "select!");
2309 rb_define_method(rb_cSet, "subset?", set_i_subset, 1);
2310 rb_define_alias(rb_cSet, "<=", "subset?");
2311 rb_define_method(rb_cSet, "subtract", set_i_subtract, 1);
2312 rb_define_method(rb_cSet, "superset?", set_i_superset, 1);
2313 rb_define_alias(rb_cSet, ">=", "superset?");
2314 rb_define_method(rb_cSet, "to_a", set_i_to_a, 0);
2315 rb_define_method(rb_cSet, "to_set", set_i_to_set, -1);
2316
2317 /* :nodoc: */
2318 VALUE compat = rb_define_class_under(rb_cSet, "compatible", rb_cObject);
2319 rb_marshal_define_compat(rb_cSet, compat, compat_dumper, compat_loader);
2320
2321 // Create Set::CoreSet before defining inherited, so it does not include
2322 // the backwards compatibility layer.
2324 rb_define_private_method(rb_singleton_class(rb_cSet), "inherited", set_s_inherited, 1);
2325
2326 rb_provide("set.rb");
2327}
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_private_method(klass, mid, func, arity)
Defines klass#mid and makes it private.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1691
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:1484
void rb_extend_object(VALUE obj, VALUE module)
Extend the object with the module.
Definition eval.c:1871
VALUE rb_singleton_class(VALUE obj)
Finds or creates the singleton class of the passed object.
Definition class.c:2817
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1515
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2860
int rb_keyword_given_p(void)
Determines if the current method is given a keyword argument.
Definition eval.c:1034
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1021
#define rb_str_buf_cat2
Old name of rb_usascii_str_new_cstr.
Definition string.h:1683
#define Qundef
Old name of RUBY_Qundef.
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define FLONUM_P
Old name of RB_FLONUM_P.
#define Qtrue
Old name of RUBY_Qtrue.
#define ST2FIX
Old name of RB_ST2FIX.
Definition st_data_t.h:33
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
#define POSFIXABLE
Old name of RB_POSFIXABLE.
Definition fixnum.h:29
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1429
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
Definition eval.c:1172
VALUE rb_cSet
Set class.
Definition set.c:97
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2249
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:264
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:582
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:686
VALUE rb_obj_is_instance_of(VALUE obj, VALUE klass)
Queries if the given object is a direct instance of the given class.
Definition object.c:867
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:923
VALUE rb_cString
String class.
Definition string.c:84
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:615
VALUE rb_str_export_to_enc(VALUE obj, rb_encoding *enc)
Identical to rb_str_export(), except it additionally takes an encoding.
Definition string.c:1447
VALUE rb_funcall_passing_block(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv_public(), except you can pass the passed block.
Definition vm_eval.c:1180
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1117
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
#define RETURN_SIZED_ENUMERATOR(obj, argc, argv, size_fn)
This roughly resembles return enum_for(__callee__) unless block_given?.
Definition enumerator.h:208
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
Definition load.c:695
#define rb_hash_uint(h, i)
Just another name of st_hash_uint.
Definition string.h:943
VALUE rb_str_buf_append(VALUE dst, VALUE src)
Identical to rb_str_cat_cstr(), except it takes Ruby's string instead of C's.
Definition string.c:3765
VALUE rb_str_buf_cat_ascii(VALUE dst, const char *src)
Identical to rb_str_cat_cstr(), except it additionally assumes the source string be a NUL terminated ...
Definition string.c:3741
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
Definition thread.c:5607
VALUE rb_exec_recursive_paired(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE p, VALUE h)
Identical to rb_exec_recursive(), except it checks for the recursion on the ordered pair of { g,...
Definition thread.c:5618
VALUE rb_const_get(VALUE space, ID name)
Identical to rb_const_defined(), except it returns the actual defined value.
Definition variable.c:3505
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:2030
VALUE rb_ivar_get(VALUE obj, ID name)
Identical to rb_iv_get(), except it accepts the name as an ID instead of a C string.
Definition variable.c:1505
VALUE rb_class_path(VALUE mod)
Identical to rb_mod_name(), except it returns #<Class: ...> style inspection for anonymous modules.
Definition variable.c:380
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3471
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
int capa
Designed capacity of the buffer.
Definition io.h:11
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:2
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition iterator.h:58
VALUE rb_yield_values(int n,...)
Identical to rb_yield(), except it takes variadic number of parameters and pass them to the block.
Definition vm_eval.c:1395
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1372
void rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE(*dumper)(VALUE), VALUE(*loader)(VALUE, VALUE))
Marshal format compatibility layer.
Definition marshal.c:137
VALUE rb_block_call(VALUE q, ID w, int e, const VALUE *r, type *t, VALUE y)
Call a method with a block.
VALUE type(ANYARGS)
ANYARGS-ed function type.
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
#define RARRAY_PTR_USE(ary, ptr_name, expr)
Declares a section of code where raw pointers are used.
Definition rarray.h:348
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RBASIC(obj)
Convenient casting macro.
Definition rbasic.h:40
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:649
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:205
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:508
VALUE rb_require(const char *feature)
Identical to rb_require_string(), except it takes C's string instead of Ruby's.
Definition load.c:1454
size_t rb_set_size(VALUE set)
Returns the number of elements in the set.
Definition set.c:2003
VALUE rb_set_clear(VALUE set)
Removes all entries from set.
Definition set.c:1991
bool rb_set_delete(VALUE set, VALUE element)
Removes the element from from set.
Definition set.c:1997
bool rb_set_add(VALUE set, VALUE element)
Adds element to set.
Definition set.c:1985
void rb_set_foreach(VALUE set, int(*func)(VALUE element, VALUE arg), VALUE arg)
Iterates over a set.
Definition set.c:1961
bool rb_set_lookup(VALUE set, VALUE element)
Whether the set contains the given element.
Definition set.c:1979
VALUE rb_set_new(void)
Creates a new, empty set object.
Definition set.c:1967
VALUE rb_set_new_capa(size_t capa)
Identical to rb_set_new(), except it additionally specifies how many elements it is expected to conta...
Definition set.c:1973
#define RTEST
This is an old name of RB_TEST.
set_table_entry * entries
Array of size 2^entry_power.
Definition set_table.h:28
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40