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