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