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