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