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