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