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