Coverage Report

Created: 2025-09-05 07:21

/src/mruby/mrbgems/mruby-set/src/set.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
** set.c - Set class
3
**
4
** See Copyright Notice in mruby.h
5
*/
6
7
#include <mruby.h>
8
#include <mruby/array.h>
9
#include <mruby/class.h>
10
#include <mruby/hash.h>
11
#include <mruby/string.h>
12
#include <mruby/variable.h>
13
#include <mruby/proc.h>
14
#include <mruby/data.h>
15
#include <mruby/internal.h>
16
#include <mruby/presym.h>
17
#include <mruby/khash.h>
18
19
/* Use khash.h for set implementation - set mode (no values, only keys) */
20
KHASH_DECLARE(set_val, mrb_value, char, FALSE)  /* FALSE = set mode */
21
22
/* Hash and equality functions for mrb_value keys */
23
static inline khint_t
24
kset_hash_value(mrb_state *mrb, mrb_value key)
25
17.7k
{
26
17.7k
  return (khint_t)mrb_obj_hash_code(mrb, key);
27
17.7k
}
28
29
static inline mrb_bool
30
kset_equal_value(mrb_state *mrb, mrb_value a, mrb_value b)
31
24.1k
{
32
24.1k
  return mrb_eql(mrb, a, b);
33
24.1k
}
34
35
KHASH_DEFINE(set_val, mrb_value, char, FALSE, kset_hash_value, kset_equal_value)
36
37
#define KSET_INITIAL_SIZE 4
38
0
#define GOLDEN_RATIO_PRIME 0x9e3779b97f4a7c15ULL
39
40
/* Compatibility layer and type definitions */
41
typedef kh_set_val_t kset_t;
42
typedef khint_t kset_iter_t;
43
44
/* API Aliases to khash.h */
45
0
#define kset_init(mrb) kh_init(set_val, mrb)
46
750
#define kset_init_data(mrb, s, sz) kh_init_data(set_val, mrb, s, sz)
47
750
#define kset_destroy_data(mrb, s) kh_destroy_data(set_val, mrb, s)
48
0
#define kset_clear(mrb, s) kh_clear(set_val, mrb, s)
49
0
#define kset_resize(mrb, s, sz) kh_resize(set_val, mrb, s, sz)
50
7.56k
#define kset_put(mrb, s, k) kh_put(set_val, mrb, s, k)
51
0
#define kset_put2(mrb, s, k, r) kh_put2(set_val, mrb, s, k, r)
52
4.54k
#define kset_get(mrb, s, k) kh_get(set_val, mrb, s, k)
53
916
#define kset_del(mrb, s, k) kh_del(set_val, mrb, s, k)
54
#define kset_exist(s, k) kh_exist(set_val, s, k)
55
5.21k
#define kset_key(s, k) kh_key(set_val, s, k)
56
256
#define kset_size(s) kh_size(s)
57
4.54k
#define kset_end(s) kh_end(s)
58
59
551
#define KSET_FOREACH(s, k) KHASH_FOREACH(set_val, s, k)
60
61
/* Helper macros for set state checking */
62
5.46k
#define kset_is_uninitialized(s) ((s)->data == NULL)
63
249
#define kset_is_empty(s) (kset_is_uninitialized(s) || kset_size(s) == 0)
64
65
/* Copy all elements from src to dst (merge operation) */
66
static void
67
kset_copy_merge(mrb_state *mrb, kset_t *dst, kset_t *src)
68
161
{
69
161
  if (!kset_is_empty(src)) {
70
161
    int ai = mrb_gc_arena_save(mrb);
71
4.21k
    KSET_FOREACH(src, k) {
72
2.38k
      kset_put(mrb, dst, kset_key(src, k));
73
2.38k
      mrb_gc_arena_restore(mrb, ai);
74
2.38k
    }
75
161
  }
76
161
}
77
78
79
/* Embedded set structure in RSet - exactly 3 pointers */
80
struct RSet {
81
  MRB_OBJECT_HEADER;
82
  kset_t set; /* Embedded directly, not a pointer */
83
};
84
85
mrb_static_assert_object_size(struct RSet);
86
87
5.96k
#define mrb_set_ptr(o) ((struct RSet*)mrb_obj_ptr(o))
88
89
/* Get pointer to embedded set */
90
static kset_t*
91
set_get_kset(mrb_state *mrb, mrb_value self)
92
5.96k
{
93
5.96k
  mrb_check_type(mrb, self, MRB_TT_SET);
94
5.96k
  return &mrb_set_ptr(self)->set;
95
5.96k
}
96
97
/* Helper function to ensure set is initialized */
98
static void
99
set_ensure_initialized(mrb_state *mrb, kset_t *set)
100
3.99k
{
101
3.99k
  if (kset_is_uninitialized(set)) {
102
0
    mrb_raise(mrb, E_RUNTIME_ERROR, "uninitialized Set");
103
0
  }
104
3.99k
}
105
106
/* Mark function for Set instances */
107
size_t
108
mrb_gc_mark_set(mrb_state *mrb, struct RBasic *obj)
109
29
{
110
29
  struct RSet *s = (struct RSet*)obj;
111
29
  kset_t *set = &s->set;
112
29
  if (kset_is_empty(set)) return 0;
113
114
1.84k
  KSET_FOREACH(set, k) {
115
997
    mrb_gc_mark_value(mrb, kset_key(set, k));
116
997
  }
117
29
  return set->size;
118
29
}
119
120
void
121
mrb_gc_free_set(mrb_state *mrb, struct RBasic *obj)
122
750
{
123
750
  struct RSet *s = (struct RSet*)obj;
124
750
  kset_destroy_data(mrb, &s->set);
125
750
}
126
127
size_t
128
mrb_set_memsize(mrb_value set)
129
0
{
130
0
  size_t size = sizeof(struct RSet);
131
0
  struct RSet *s = mrb_set_ptr(set);
132
0
  kset_t *kset = &s->set;
133
0
  if (kset->data) {
134
    /* New khash layout: keys + flags in single allocation */
135
0
    size += sizeof(mrb_value) * kset->n_buckets; /* keys */
136
0
    size += kset->n_buckets / 4; /* flags */
137
0
  }
138
0
  return size;
139
0
}
140
141
/* Helper function to check if a value is a Set and return a boolean result */
142
static mrb_bool
143
set_is_set(mrb_value obj)
144
941
{
145
941
  return mrb_type(obj) == MRB_TT_SET;
146
941
}
147
148
/* Helper function to check if a value is a Set and raise an error if not */
149
static void
150
set_check_type(mrb_state *mrb, mrb_value obj)
151
0
{
152
0
  if (!set_is_set(obj)) {
153
0
    mrb_raise(mrb, E_ARGUMENT_ERROR, "value must be a set");
154
0
  }
155
0
}
156
157
static mrb_value
158
set_init(mrb_state *mrb, mrb_value self)
159
360
{
160
360
  kset_t *set = set_get_kset(mrb, self);
161
360
  kset_init_data(mrb, set, KSET_INITIAL_SIZE);
162
360
  return self;
163
360
}
164
165
/*
166
 * call-seq:
167
 *   set.initialize_copy(orig)
168
  * Copy constructor.
169
 */
170
static mrb_value
171
set_init_copy(mrb_state *mrb, mrb_value self)
172
390
{
173
390
  mrb_value orig = mrb_get_arg1(mrb);
174
175
390
  if (mrb_type(orig) != MRB_TT_SET) {
176
0
    mrb_raise(mrb, E_TYPE_ERROR, "initialize_copy should take a Set object");
177
0
  }
178
390
  if (mrb_obj_class(mrb, self) != mrb_obj_class(mrb, orig)) {
179
0
    mrb_raise(mrb, E_TYPE_ERROR, "initialize_copy should take same class object");
180
0
  }
181
182
390
  kset_t *orig_set = set_get_kset(mrb, orig);
183
390
  set_ensure_initialized(mrb, orig_set);
184
185
390
  kset_t *self_set = set_get_kset(mrb, self);
186
390
  kset_init_data(mrb, self_set, kset_size(orig_set));
187
390
  kh_replace(set_val, mrb, self_set, orig_set);
188
189
390
  return self;
190
390
}
191
192
/*
193
 * call-seq:
194
 *   set.size -> integer
195
 *   set.length -> integer
196
 *
197
 * Returns the number of elements.
198
 */
199
static mrb_value
200
set_size(mrb_state *mrb, mrb_value self)
201
0
{
202
0
  kset_t *set = set_get_kset(mrb, self);
203
0
  if (kset_is_empty(set)) return mrb_fixnum_value(0);
204
0
  return mrb_fixnum_value(kset_size(set));
205
0
}
206
207
/*
208
 * call-seq:
209
 *   set.empty? -> true or false
210
 *
211
 * Returns true if the set contains no elements.
212
 */
213
static mrb_value
214
set_empty_p(mrb_state *mrb, mrb_value self)
215
0
{
216
0
  kset_t *set = set_get_kset(mrb, self);
217
0
  return mrb_bool_value(kset_is_empty(set));
218
0
}
219
220
/*
221
 * call-seq:
222
 *   set.clear -> self
223
 *
224
 * Removes all elements and returns self.
225
 */
226
static mrb_value
227
set_clear(mrb_state *mrb, mrb_value self)
228
0
{
229
0
  kset_t *set = set_get_kset(mrb, self);
230
0
  if (!kset_is_empty(set)) {
231
0
    kset_clear(mrb, set);
232
0
  }
233
0
  return self;
234
0
}
235
236
/*
237
 * call-seq:
238
 *   set.to_a -> array
239
 *
240
 * Converts the set to an array.
241
 */
242
static mrb_value
243
set_to_a(mrb_state *mrb, mrb_value self)
244
0
{
245
0
  kset_t *set = set_get_kset(mrb, self);
246
247
0
  if (kset_is_empty(set)) return mrb_ary_new(mrb);
248
249
0
  mrb_value ary = mrb_ary_new_capa(mrb, kset_size(set));
250
251
0
  int ai = mrb_gc_arena_save(mrb);
252
0
  KSET_FOREACH(set, k) {
253
0
    mrb_ary_push(mrb, ary, kset_key(set, k));
254
0
    mrb_gc_arena_restore(mrb, ai);
255
0
  }
256
257
0
  return ary;
258
0
}
259
260
/*
261
 * call-seq:
262
 *   set.include?(object) -> true or false
263
 *   set.member?(object) -> true or false
264
 *   set === object -> true or false
265
 *
266
 * Returns true if the set contains the given object.
267
 */
268
static mrb_value
269
set_include_p(mrb_state *mrb, mrb_value self)
270
0
{
271
0
  mrb_value obj = mrb_get_arg1(mrb);
272
0
  kset_t *set = set_get_kset(mrb, self);
273
0
  if (kset_is_empty(set)) return mrb_false_value();
274
275
0
  return mrb_bool_value(kset_get(mrb, set, obj) != kset_end(set));
276
0
}
277
278
/*
279
 * call-seq:
280
 *   set.add(object) -> self
281
 *   set << object -> self
282
 *
283
 * Adds the given object to the set and returns self.
284
 */
285
static mrb_value
286
set_add(mrb_state *mrb, mrb_value self)
287
3.60k
{
288
3.60k
  mrb_value obj = mrb_get_arg1(mrb);
289
3.60k
  kset_t *set = set_get_kset(mrb, self);
290
3.60k
  set_ensure_initialized(mrb, set);
291
292
3.60k
  kset_put(mrb, set, obj);
293
3.60k
  return self;
294
3.60k
}
295
296
/*
297
 * call-seq:
298
 *   set.add?(object) -> self or nil
299
 *
300
 * Adds the given object to the set and returns self. If the object is already
301
 * in the set, returns nil.
302
 */
303
static mrb_value
304
set_add_p(mrb_state *mrb, mrb_value self)
305
0
{
306
0
  mrb_value obj = mrb_get_arg1(mrb);
307
0
  kset_t *set = set_get_kset(mrb, self);
308
0
  set_ensure_initialized(mrb, set);
309
310
0
  int ret;
311
0
  kset_put2(mrb, set, obj, &ret);
312
0
  return (ret == 0) ? mrb_nil_value() : self;
313
0
}
314
315
/*
316
 * call-seq:
317
 *   set.delete(object) -> self
318
 *
319
 * Deletes the given object from the set and returns self.
320
 */
321
static mrb_value
322
set_delete(mrb_state *mrb, mrb_value self)
323
20
{
324
20
  mrb_value obj = mrb_get_arg1(mrb);
325
20
  kset_t *set = set_get_kset(mrb, self);
326
20
  if (kset_is_empty(set)) return self;
327
328
20
  kset_iter_t k = kset_get(mrb, set, obj);
329
20
  if (k != kset_end(set)) {
330
0
    kset_del(mrb, set, k);
331
0
  }
332
20
  return self;
333
20
}
334
335
/*
336
 * call-seq:
337
 *   set.delete?(object) -> self or nil
338
 *
339
 * Deletes the given object from the set and returns self. If the object is not
340
 * in the set, returns nil.
341
 */
342
static mrb_value
343
set_delete_p(mrb_state *mrb, mrb_value self)
344
0
{
345
0
  mrb_value obj = mrb_get_arg1(mrb);
346
0
  kset_t *set = set_get_kset(mrb, self);
347
0
  if (kset_is_empty(set)) return mrb_nil_value();
348
349
0
  kset_iter_t k = kset_get(mrb, set, obj);
350
0
  if (k != kset_end(set)) {
351
0
    kset_del(mrb, set, k);
352
0
    return self;
353
0
  }
354
0
  else {
355
0
    return mrb_nil_value();
356
0
  }
357
0
}
358
359
/*
360
 * Core implementation of Set-to-Set merge (mutating version)
361
 * This is an internal method that will be called from Ruby
362
 */
363
static mrb_value
364
set_core_merge(mrb_state *mrb, mrb_value self)
365
211
{
366
211
  mrb_value other = mrb_get_arg1(mrb);
367
368
211
  if (!set_is_set(other)) {
369
211
    return mrb_false_value();
370
211
  }
371
372
0
  kset_t *self_set = set_get_kset(mrb, self);
373
0
  kset_t *other_set = set_get_kset(mrb, other);
374
375
0
  set_ensure_initialized(mrb, self_set);
376
0
  if (!kset_is_empty(other_set)) {
377
0
    kset_copy_merge(mrb, self_set, other_set);
378
0
  }
379
380
0
  return mrb_true_value();
381
211
}
382
383
/*
384
 * Core implementation of Set-to-Set subtraction (mutating version)
385
 * This is an internal method that will be called from Ruby
386
 */
387
static mrb_value
388
set_core_subtract(mrb_state *mrb, mrb_value self)
389
0
{
390
0
  mrb_value other = mrb_get_arg1(mrb);
391
392
0
  if (!set_is_set(other)) {
393
0
    return mrb_false_value();
394
0
  }
395
396
0
  kset_t *self_set = set_get_kset(mrb, self);
397
0
  if (kset_is_empty(self_set)) return mrb_true_value();
398
399
0
  kset_t *other_set = set_get_kset(mrb, other);
400
0
  if (kset_is_empty(other_set)) return mrb_true_value();
401
402
  /* Remove all elements that are in other set */
403
0
  KSET_FOREACH(other_set, k) {
404
0
    mrb_value key = kset_key(other_set, k);
405
0
    kset_iter_t self_k = kset_get(mrb, self_set, key);
406
0
    if (self_k != kset_end(self_set)) {
407
0
      kset_del(mrb, self_set, self_k);
408
0
    }
409
0
  }
410
411
0
  return mrb_true_value();
412
0
}
413
414
/*
415
 * Core implementation of Set-to-Set union
416
 * This is an internal method that will be called from Ruby
417
 */
418
static mrb_value
419
set_core_union(mrb_state *mrb, mrb_value self)
420
209
{
421
209
  mrb_value other = mrb_get_arg1(mrb);
422
423
209
  if (!set_is_set(other)) {
424
48
    return mrb_nil_value();
425
48
  }
426
427
  /* Create a new set by duplicating self */
428
161
  mrb_value result = mrb_obj_dup(mrb, self);
429
161
  kset_t *result_set = set_get_kset(mrb, result);
430
161
  if (kset_is_uninitialized(result_set)) {
431
    /* If self is empty, initialize the set */
432
0
    kset_init_data(mrb, result_set, KSET_INITIAL_SIZE);
433
0
  }
434
435
  /* Add all elements from other set */
436
161
  kset_t *other_set = set_get_kset(mrb, other);
437
161
  if (!kset_is_uninitialized(other_set)) {
438
161
    kset_copy_merge(mrb, result_set, other_set);
439
161
  }
440
441
161
  return result;
442
209
}
443
444
/*
445
 * Core implementation of Set-to-Set difference
446
 * This is an internal method that will be called from Ruby
447
 */
448
static mrb_value
449
set_core_difference(mrb_state *mrb, mrb_value self)
450
181
{
451
181
  mrb_value other = mrb_get_arg1(mrb);
452
453
181
  if (!set_is_set(other)) {
454
20
    return mrb_nil_value();
455
20
  }
456
457
  /* Create a new set by duplicating self */
458
161
  mrb_value result = mrb_obj_dup(mrb, self);
459
161
  kset_t *result_set = set_get_kset(mrb, result);
460
161
  if (kset_is_uninitialized(result_set)) {
461
    /* If self is empty, return an empty set */
462
0
    return result;
463
0
  }
464
465
  /* Remove all elements that are in other set */
466
161
  kset_t *other_set = set_get_kset(mrb, other);
467
161
  if (!kset_is_uninitialized(other_set)) {
468
1.50k
    KSET_FOREACH(other_set, k) {
469
916
      mrb_value key = kset_key(other_set, k);
470
916
      kset_iter_t result_k = kset_get(mrb, result_set, key);
471
916
      if (result_k != kset_end(result_set)) {
472
916
        kset_del(mrb, result_set, result_k);
473
916
      }
474
916
    }
475
161
  }
476
477
161
  return result;
478
161
}
479
480
481
/*
482
 * Core implementation of Set-to-Set intersection
483
 * This is an internal method that will be called from Ruby
484
 */
485
static mrb_value
486
set_core_intersection(mrb_state *mrb, mrb_value self)
487
161
{
488
161
  mrb_value other = mrb_get_arg1(mrb);
489
490
161
  if (!set_is_set(other)) {
491
0
    return mrb_nil_value();
492
0
  }
493
494
  /* Create a new empty set of the same class as self */
495
161
  mrb_value result = mrb_obj_new(mrb, mrb_obj_class(mrb, self), 0, NULL);
496
161
  kset_t *result_set = set_get_kset(mrb, result);
497
498
161
  kset_t *self_set = set_get_kset(mrb, self);
499
161
  if (kset_is_uninitialized(self_set)) return result;
500
501
161
  kset_t *other_set = set_get_kset(mrb, other);
502
161
  if (kset_is_uninitialized(other_set)) return result;
503
504
4.21k
  KSET_FOREACH(other_set, k) {
505
2.38k
    mrb_value key = kset_key(other_set, k);
506
2.38k
    kset_iter_t self_k = kset_get(mrb, self_set, key);
507
508
    /* If key exists in self, add it to result */
509
2.38k
    if (self_k != kset_end(self_set)) {
510
916
      kset_put(mrb, result_set, key);
511
916
    }
512
2.38k
  }
513
514
161
  return result;
515
161
}
516
517
518
/*
519
 * Core implementation of Set-to-Set XOR (symmetric difference)
520
 * This is an internal method that will be called from Ruby
521
 */
522
static mrb_value
523
set_core_xor(mrb_state *mrb, mrb_value self)
524
179
{
525
179
  mrb_value other = mrb_get_arg1(mrb);
526
527
179
  if (!set_is_set(other)) {
528
163
    return mrb_nil_value();
529
163
  }
530
531
16
  mrb_value result = mrb_obj_new(mrb, mrb_obj_class(mrb, self), 0, NULL);
532
16
  kset_t *result_set = set_get_kset(mrb, result);
533
16
  kset_t *self_set, *other_set;
534
535
16
  self_set = set_get_kset(mrb, self);
536
16
  other_set = set_get_kset(mrb, other);
537
538
  /* Handle empty sets */
539
16
  if (kset_is_empty(self_set)) {
540
0
    if (!kset_is_empty(other_set)) {
541
0
      kset_copy_merge(mrb, result_set, other_set);
542
0
    }
543
0
    return result;
544
0
  }
545
16
  if (kset_is_empty(other_set)) {
546
0
    kh_replace(set_val, mrb, result_set, self_set);
547
0
    return result;
548
0
  }
549
550
  /* Add elements from self that are not in other */
551
16
  int ai = mrb_gc_arena_save(mrb);
552
1.16k
  KSET_FOREACH(self_set, k) {
553
601
    mrb_value key = kset_key(self_set, k);
554
601
    kset_iter_t other_k = kset_get(mrb, other_set, key);
555
556
    /* Add to result if not in other */
557
601
    if (other_k == kset_end(other_set)) {
558
310
      kset_put(mrb, result_set, key);
559
310
    }
560
601
    mrb_gc_arena_restore(mrb, ai);
561
601
  }
562
563
  /* Add elements from other that are not in self */
564
1.00k
  KSET_FOREACH(other_set, k) {
565
621
    mrb_value key = kset_key(other_set, k);
566
621
    kset_iter_t self_k = kset_get(mrb, self_set, key);
567
568
    /* Add to result if not in self */
569
621
    if (self_k == kset_end(self_set)) {
570
330
      kset_put(mrb, result_set, key);
571
330
    }
572
621
    mrb_gc_arena_restore(mrb, ai);
573
621
  }
574
575
16
  return result;
576
16
}
577
578
/*
579
 * call-seq:
580
 *   set == other -> true or false
581
 *
582
 * Returns true if two sets are equal.
583
 */
584
/*
585
 * call-seq:
586
 *   set.eql?(other) -> true or false
587
 *
588
 * Returns true if two sets are equal.
589
 */
590
static mrb_value
591
set_equal(mrb_state *mrb, mrb_value self)
592
0
{
593
0
  mrb_value other = mrb_get_arg1(mrb);
594
595
  /* Fast path: same object */
596
0
  if (mrb_obj_equal(mrb, self, other)) {
597
0
    return mrb_true_value();
598
0
  }
599
600
  /* Only compare with other Set objects */
601
0
  if (!set_is_set(other)) {
602
0
    return mrb_false_value();
603
0
  }
604
605
0
  kset_t *self_set = set_get_kset(mrb, self);
606
0
  kset_t *other_set = set_get_kset(mrb, other);
607
608
  /* Fast path: both empty */
609
0
  if (kset_is_empty(self_set) && kset_is_empty(other_set)) {
610
0
    return mrb_true_value();
611
0
  }
612
613
  /* Fast path: different sizes */
614
0
  if (kset_size(self_set) != kset_size(other_set)) {
615
0
    return mrb_false_value();
616
0
  }
617
618
  /* Compare elements: iterate through the smaller hash for efficiency */
619
0
  int ai = mrb_gc_arena_save(mrb);
620
0
  KSET_FOREACH(self_set, k) {
621
0
    kset_iter_t k2 = kset_get(mrb, other_set, kset_key(self_set, k));
622
0
    if (k2 == kset_end(other_set)) {
623
0
      return mrb_false_value(); /* Element in self not found in other */
624
0
    }
625
0
    mrb_gc_arena_restore(mrb, ai);
626
0
  }
627
628
0
  return mrb_true_value();
629
0
}
630
631
/*
632
 * call-seq:
633
 *   set.hash -> integer
634
 *
635
 * Compute a hash-code for this set.
636
 * Uses an improved hash algorithm for better distribution.
637
 */
638
static mrb_value
639
set_hash_m(mrb_state *mrb, mrb_value self)
640
0
{
641
0
  kset_t *set = set_get_kset(mrb, self);
642
643
  /* Use order-independent hash algorithm for sets */
644
0
  uint64_t hash = 0; /* Start with zero for XOR accumulation */
645
646
  /* Include the size of the set in the hash */
647
0
  size_t size = kset_size(set);
648
0
  hash ^= size * GOLDEN_RATIO_PRIME;
649
650
0
  if (!kset_is_uninitialized(set) && size > 0) {
651
    /* Process each element - order independent using XOR */
652
0
    int ai = mrb_gc_arena_save(mrb);
653
0
    KSET_FOREACH(set, k) {
654
      /* Get element's hash code */
655
0
      khint_t elem_hash = (khint_t)mrb_obj_hash_code(mrb, kset_key(set, k));
656
657
      /* XOR is commutative, so order doesn't matter */
658
0
      hash ^= elem_hash * GOLDEN_RATIO_PRIME;
659
660
0
      mrb_gc_arena_restore(mrb, ai);
661
0
    }
662
0
  }
663
664
  /* Final mixing to improve distribution */
665
0
  hash ^= hash >> 32;
666
667
0
  return mrb_fixnum_value((mrb_int)hash);
668
0
}
669
670
/*
671
 * call-seq:
672
 *   set.superset?(other) -> true or false
673
 *   set >= other -> true or false
674
 *
675
 * Returns true if the set is a superset of the given set.
676
 */
677
static mrb_value
678
set_superset_p(mrb_state *mrb, mrb_value self)
679
0
{
680
0
  mrb_value other = mrb_get_arg1(mrb);
681
682
  /* Check if other is a Set */
683
0
  set_check_type(mrb, other);
684
685
0
  kset_t *self_set = set_get_kset(mrb, self);
686
0
  kset_t *other_set = set_get_kset(mrb, other);
687
688
  /* Handle empty sets */
689
0
  if (kset_is_empty(other_set)) {
690
0
    return mrb_true_value(); /* Empty set is a subset of any set */
691
0
  }
692
693
0
  if (kset_is_uninitialized(self_set)) {
694
0
    return mrb_false_value(); /* Empty set is not a superset of a non-empty set */
695
0
  }
696
697
  /* Check size first - a superset must be at least as large as the subset */
698
0
  if (kset_size(self_set) < kset_size(other_set)) {
699
0
    return mrb_false_value();
700
0
  }
701
702
  /* Check if all elements in other are in self */
703
0
  int ai = mrb_gc_arena_save(mrb);
704
0
  KSET_FOREACH(other_set, k) {
705
0
    kset_iter_t self_k = kset_get(mrb, self_set, kset_key(other_set, k));
706
0
    if (self_k == kset_end(self_set)) {
707
0
      return mrb_false_value(); /* Element in other not found in self */
708
0
    }
709
0
    mrb_gc_arena_restore(mrb, ai);
710
0
  }
711
712
0
  return mrb_true_value();
713
0
}
714
715
/*
716
 * call-seq:
717
 *   set.proper_superset?(other) -> true or false
718
 *   set > other -> true or false
719
 *
720
 * Returns true if the set is a proper superset of the given set.
721
 */
722
static mrb_value
723
set_proper_superset_p(mrb_state *mrb, mrb_value self)
724
0
{
725
0
  mrb_value other = mrb_get_arg1(mrb);
726
727
  /* Check if other is a Set */
728
0
  set_check_type(mrb, other);
729
730
0
  kset_t *self_set = set_get_kset(mrb, self);
731
0
  kset_t *other_set = set_get_kset(mrb, other);
732
733
  /* Handle empty sets */
734
0
  if (kset_is_empty(other_set)) {
735
    /* Empty set is a proper subset of any non-empty set */
736
0
    return !kset_is_empty(self_set) ? mrb_true_value() : mrb_false_value();
737
0
  }
738
739
0
  if (kset_is_uninitialized(self_set)) {
740
0
    return mrb_false_value(); /* Empty set is not a proper superset of any set */
741
0
  }
742
743
  /* For a proper superset, self must be strictly larger than other */
744
0
  if (kset_size(self_set) <= kset_size(other_set)) {
745
0
    return mrb_false_value();
746
0
  }
747
748
  /* Check if all elements in other are in self */
749
0
  int ai = mrb_gc_arena_save(mrb);
750
0
  KSET_FOREACH(other_set, k) {
751
0
    kset_iter_t self_k = kset_get(mrb, self_set, kset_key(other_set, k));
752
0
    if (self_k == kset_end(self_set)) {
753
0
      return mrb_false_value(); /* Element in other not found in self */
754
0
    }
755
0
    mrb_gc_arena_restore(mrb, ai);
756
0
  }
757
758
0
  return mrb_true_value();
759
0
}
760
761
/*
762
 * call-seq:
763
 *   set.subset?(other) -> true or false
764
 *   set <= other -> true or false
765
 *
766
 * Returns true if the set is a subset of the given set.
767
 */
768
static mrb_value
769
set_subset_p(mrb_state *mrb, mrb_value self)
770
0
{
771
0
  mrb_value other = mrb_get_arg1(mrb);
772
773
  /* Check if other is a Set */
774
0
  set_check_type(mrb, other);
775
776
0
  kset_t *self_set = set_get_kset(mrb, self);
777
0
  kset_t *other_set = set_get_kset(mrb, other);
778
779
  /* Handle empty sets */
780
0
  if (kset_is_empty(self_set)) {
781
0
    return mrb_true_value(); /* Empty set is a subset of any set */
782
0
  }
783
784
0
  if (kset_is_uninitialized(other_set)) {
785
0
    return mrb_false_value(); /* Non-empty set is not a subset of an empty set */
786
0
  }
787
788
  /* Check size first - a subset cannot be larger than its superset */
789
0
  if (kset_size(other_set) < kset_size(self_set)) {
790
0
    return mrb_false_value();
791
0
  }
792
793
  /* Check if all elements in self are in other */
794
0
  int ai = mrb_gc_arena_save(mrb);
795
0
  KSET_FOREACH(self_set, k) {
796
0
    kset_iter_t other_k = kset_get(mrb, other_set, kset_key(self_set, k));
797
0
    if (other_k == kset_end(other_set)) {
798
0
      return mrb_false_value(); /* Element in self not found in other */
799
0
    }
800
0
    mrb_gc_arena_restore(mrb, ai);
801
0
  }
802
803
0
  return mrb_true_value();
804
0
}
805
806
/*
807
 * call-seq:
808
 *   set.proper_subset?(other) -> true or false
809
 *   set < other -> true or false
810
 *
811
 * Returns true if the set is a proper subset of the given set.
812
 */
813
static mrb_value
814
set_proper_subset_p(mrb_state *mrb, mrb_value self)
815
0
{
816
0
  mrb_value other = mrb_get_arg1(mrb);
817
818
  /* Check if other is a Set */
819
0
  set_check_type(mrb, other);
820
821
0
  kset_t *self_set = set_get_kset(mrb, self);
822
0
  kset_t *other_set = set_get_kset(mrb, other);
823
824
  /* Handle empty sets */
825
0
  if (kset_is_empty(self_set)) {
826
    /* Empty set is a proper subset of any non-empty set */
827
0
    return !kset_is_empty(other_set) ? mrb_true_value() : mrb_false_value();
828
0
  }
829
830
0
  if (kset_is_uninitialized(other_set)) {
831
0
    return mrb_false_value(); /* Non-empty set is not a proper subset of an empty set */
832
0
  }
833
834
  /* For a proper subset, self must be strictly smaller than other */
835
0
  if (kset_size(other_set) <= kset_size(self_set)) {
836
0
    return mrb_false_value();
837
0
  }
838
839
  /* Check if all elements in self are in other */
840
0
  int ai = mrb_gc_arena_save(mrb);
841
0
  KSET_FOREACH(self_set, k) {
842
0
    kset_iter_t other_k = kset_get(mrb, other_set, kset_key(self_set, k));
843
0
    if (other_k == kset_end(other_set)) {
844
0
      return mrb_false_value(); /* Element in self not found in other */
845
0
    }
846
0
    mrb_gc_arena_restore(mrb, ai);
847
0
  }
848
849
0
  return mrb_true_value();
850
0
}
851
852
/*
853
 * call-seq:
854
 *   set.intersect?(other) -> true or false
855
 *
856
 * Returns true if the set and the given set have at least one element in common.
857
 */
858
static mrb_value
859
set_intersect_p(mrb_state *mrb, mrb_value self)
860
0
{
861
0
  mrb_value other = mrb_get_arg1(mrb);
862
863
  /* Check if other is a Set */
864
0
  set_check_type(mrb, other);
865
866
0
  kset_t *self_set = set_get_kset(mrb, self);
867
0
  kset_t *other_set = set_get_kset(mrb, other);
868
869
  /* Handle empty sets */
870
0
  if (kset_is_empty(self_set) || kset_is_empty(other_set)) {
871
0
    return mrb_false_value(); /* Empty sets have no elements in common */
872
0
  }
873
874
  /* Iterate through the smaller set for efficiency */
875
0
  int ai = mrb_gc_arena_save(mrb);
876
0
  if (kset_size(self_set) < kset_size(other_set)) {
877
0
    KSET_FOREACH(self_set, k) {
878
0
      kset_iter_t other_k = kset_get(mrb, other_set, kset_key(self_set, k));
879
0
      if (other_k != kset_end(other_set)) {
880
0
        return mrb_true_value(); /* Found a common element */
881
0
      }
882
0
      mrb_gc_arena_restore(mrb, ai);
883
0
    }
884
0
  }
885
0
  else {
886
0
    KSET_FOREACH(other_set, k) {
887
0
      kset_iter_t self_k = kset_get(mrb, self_set, kset_key(other_set, k));
888
0
      if (self_k != kset_end(self_set)) {
889
0
        return mrb_true_value(); /* Found a common element */
890
0
      }
891
0
      mrb_gc_arena_restore(mrb, ai);
892
0
    }
893
0
  }
894
895
0
  return mrb_false_value(); /* No common elements found */
896
0
}
897
898
/*
899
 * call-seq:
900
 *   set.disjoint?(other) -> true or false
901
 *
902
 * Returns true if the set and the given set have no elements in common.
903
 */
904
static mrb_value
905
set_disjoint_p(mrb_state *mrb, mrb_value self)
906
0
{
907
0
  mrb_value result = set_intersect_p(mrb, self);
908
0
  return mrb_bool_value(!mrb_test(result));
909
0
}
910
911
/*
912
 * call-seq:
913
 *   set <=> other -> -1, 0, +1, or nil
914
 *
915
 * Compares this set with another set.
916
 * Returns -1 if this set is a proper subset of the other set,
917
 * +1 if this set is a proper superset of the other set,
918
 * 0 if the sets are equal,
919
 * or nil if the sets cannot be compared (they are neither subsets nor supersets).
920
 */
921
static mrb_value
922
set_cmp(mrb_state *mrb, mrb_value self)
923
0
{
924
0
  mrb_value other = mrb_get_arg1(mrb);
925
926
0
  if (!set_is_set(other)) {
927
0
    return mrb_nil_value();
928
0
  }
929
930
0
  kset_t *self_set = set_get_kset(mrb, self);
931
0
  kset_t *other_set = set_get_kset(mrb, other);
932
933
  /* Handle empty sets */
934
0
  if (kset_is_empty(self_set)) {
935
0
    if (kset_is_empty(other_set)) {
936
0
      return mrb_fixnum_value(0); /* Both empty, they're equal */
937
0
    }
938
0
    return mrb_fixnum_value(-1); /* Empty set is a proper subset of any non-empty set */
939
0
  }
940
941
0
  if (kset_is_empty(other_set)) {
942
0
    return mrb_fixnum_value(1); /* Any non-empty set is a proper superset of an empty set */
943
0
  }
944
945
  /* Compare sizes */
946
0
  mrb_int size_diff = kset_size(self_set) - kset_size(other_set);
947
948
0
  if (size_diff < 0) {
949
    /* self might be a proper subset of other */
950
0
    int ai = mrb_gc_arena_save(mrb);
951
0
    KSET_FOREACH(self_set, k) {
952
0
      kset_iter_t other_k = kset_get(mrb, other_set, kset_key(self_set, k));
953
0
      if (other_k == kset_end(other_set)) {
954
        /* Not a subset */
955
0
        return mrb_nil_value(); /* Not comparable */
956
0
      }
957
0
      mrb_gc_arena_restore(mrb, ai);
958
0
    }
959
960
    /* All elements of self are in other, and self is smaller than other */
961
0
    return mrb_fixnum_value(-1); /* self is a proper subset of other */
962
0
  }
963
0
  else if (size_diff > 0) {
964
    /* self might be a proper superset of other */
965
0
    int ai = mrb_gc_arena_save(mrb);
966
0
    KSET_FOREACH(other_set, k) {
967
0
      kset_iter_t self_k = kset_get(mrb, self_set, kset_key(other_set, k));
968
0
      if (self_k == kset_end(self_set)) {
969
        /* Not a superset */
970
0
        return mrb_nil_value(); /* Not comparable */
971
0
      }
972
0
      mrb_gc_arena_restore(mrb, ai);
973
0
    }
974
975
    /* All elements of other are in self, and self is larger than other */
976
0
    return mrb_fixnum_value(1); /* self is a proper superset of other */
977
0
  }
978
0
  else { /* size_diff == 0 */
979
    /* Same size, check if they're equal */
980
0
    mrb_bool is_equal = TRUE;
981
982
0
    int ai3 = mrb_gc_arena_save(mrb);
983
0
    KSET_FOREACH(self_set, k) {
984
0
      kset_iter_t other_k = kset_get(mrb, other_set, kset_key(self_set, k));
985
0
      if (other_k == kset_end(other_set)) {
986
0
        is_equal = FALSE;
987
0
        break;
988
0
      }
989
0
      mrb_gc_arena_restore(mrb, ai3);
990
0
    }
991
992
0
    if (is_equal) {
993
0
      return mrb_fixnum_value(0); /* Sets are equal */
994
0
    }
995
0
  }
996
997
  /* Sets are not comparable */
998
0
  return mrb_nil_value();
999
0
}
1000
1001
/*
1002
 * call-seq:
1003
 *   set.join(separator = nil) -> string
1004
 *
1005
 * Returns a string created by converting each element of the set to a string,
1006
 * separated by the given separator.
1007
 */
1008
static mrb_value
1009
set_join(mrb_state *mrb, mrb_value self)
1010
0
{
1011
0
  mrb_value separator = mrb_nil_value();
1012
0
  mrb_get_args(mrb, "|S", &separator);
1013
1014
0
  kset_t *set = set_get_kset(mrb, self);
1015
0
  if (kset_is_empty(set)) {
1016
0
    return mrb_str_new_lit(mrb, "");
1017
0
  }
1018
1019
  /* Get separator string */
1020
0
  const char *sep_ptr = "";
1021
0
  mrb_int sep_len = 0;
1022
0
  if (!mrb_nil_p(separator)) {
1023
0
    sep_ptr = RSTRING_PTR(separator);
1024
0
    sep_len = RSTRING_LEN(separator);
1025
0
  }
1026
1027
  /* Create result string */
1028
0
  mrb_value result = mrb_str_new_capa(mrb, 64);  /* Initial capacity */
1029
0
  mrb_bool first = TRUE;
1030
1031
  /* Iterate through all elements */
1032
0
  int ai = mrb_gc_arena_save(mrb);
1033
0
  KSET_FOREACH(set, k) {
1034
0
    if (!first) {
1035
0
      mrb_str_cat(mrb, result, sep_ptr, sep_len);
1036
0
    }
1037
0
    else {
1038
0
      first = FALSE;
1039
0
    }
1040
1041
0
    mrb_value elem = kset_key(set, k);
1042
0
    mrb_value str = mrb_obj_as_string(mrb, elem);
1043
0
    mrb_str_cat_str(mrb, result, str);
1044
1045
0
    mrb_gc_arena_restore(mrb, ai);
1046
0
  }
1047
1048
0
  return result;
1049
0
}
1050
1051
/*
1052
 * call-seq:
1053
 *   set.inspect -> string
1054
 *   set.to_s -> string
1055
 *
1056
 * Returns a string representation of the set.
1057
 * Format: Set[elem1, elem2, ...]
1058
 */
1059
static mrb_value
1060
set_inspect(mrb_state *mrb, mrb_value self)
1061
7
{
1062
7
  struct RClass* c = mrb_obj_class(mrb, self);
1063
7
  const char* classname = mrb_class_name(mrb, c);
1064
7
  kset_t *set = set_get_kset(mrb, self);
1065
1066
  /* Handle empty set */
1067
7
  if (kset_is_empty(set)) {
1068
0
    return mrb_format(mrb, "%s[]", classname);
1069
0
  }
1070
1071
  /* Handle recursive inspection */
1072
7
  if (MRB_RECURSIVE_UNARY_P(mrb, MRB_SYM(inspect), self)) {
1073
0
    return mrb_format(mrb, "%s[...]", classname);
1074
0
  }
1075
1076
  /* Estimate buffer size based on set size */
1077
7
  size_t size = kset_size(set);
1078
7
  size_t buffer_size = 16 + strlen(classname) + (size * 8); /* Rough estimate */
1079
1080
  /* Create the beginning of the string with pre-allocated capacity */
1081
7
  mrb_value result_str = mrb_str_new_capa(mrb, buffer_size);
1082
7
  mrb_str_cat_cstr(mrb, result_str, classname);
1083
7
  mrb_str_cat_lit(mrb, result_str, "[");
1084
1085
  /* Iterate through all elements */
1086
7
  mrb_bool first = TRUE;
1087
7
  int ai = mrb_gc_arena_save(mrb);
1088
1.79k
  KSET_FOREACH(set, k) {
1089
693
    if (!first) {
1090
686
      mrb_str_cat_lit(mrb, result_str, ", ");
1091
686
    }
1092
7
    else {
1093
7
      first = FALSE;
1094
7
    }
1095
1096
693
    mrb_value elem = kset_key(set, k);
1097
693
    mrb_value entry_str = mrb_inspect(mrb, elem);
1098
693
    mrb_str_cat_str(mrb, result_str, entry_str);
1099
1100
693
    mrb_gc_arena_restore(mrb, ai);
1101
693
  }
1102
1103
  /* Add the closing part */
1104
7
  mrb_str_cat_lit(mrb, result_str, "]");
1105
1106
7
  return result_str;
1107
7
}
1108
1109
/*
1110
 * call-seq:
1111
 *   set.reset -> self
1112
 *
1113
 * Resets the internal state after modification to existing elements.
1114
 * This is necessary when the hash value of objects in the set has changed.
1115
 * It rebuilds the hash table to ensure all elements can be found.
1116
 */
1117
static mrb_value
1118
set_reset(mrb_state *mrb, mrb_value self)
1119
0
{
1120
0
  mrb_check_frozen_value(mrb, self);
1121
1122
0
  kset_t *set = set_get_kset(mrb, self);
1123
0
  if (!kset_is_empty(set)) {
1124
0
    kset_resize(mrb, set, kset_size(set));
1125
0
  }
1126
1127
0
  return self;
1128
0
}
1129
1130
/*
1131
 * call-seq:
1132
 *   set.add_all(*objects) -> self
1133
 *
1134
 * Adds multiple objects to the set and returns self.
1135
 */
1136
static mrb_value
1137
set_add_all(mrb_state *mrb, mrb_value self)
1138
0
{
1139
0
  const mrb_value *argv;
1140
0
  mrb_int argc;
1141
1142
0
  mrb_get_args(mrb, "*", &argv, &argc);
1143
0
  kset_t *set = set_get_kset(mrb, self);
1144
0
  set_ensure_initialized(mrb, set);
1145
1146
0
  int ai = mrb_gc_arena_save(mrb);
1147
0
  for (mrb_int i = 0; i < argc; i++) {
1148
0
    kset_put(mrb, set, argv[i]);
1149
0
    mrb_gc_arena_restore(mrb, ai);
1150
0
  }
1151
1152
0
  return self;
1153
0
}
1154
1155
/*
1156
 * Optimized implementation for flattening sets
1157
 * Uses a more efficient algorithm with minimal memory usage
1158
 */
1159
1160
/* Small array for tracking seen object IDs to detect cycles */
1161
0
#define MAX_NESTED_DEPTH 16
1162
1163
/*
1164
 * Recursively flattens a set by merging nested sets into the target set.
1165
 * This is an internal helper function that does not call back to the VM.
1166
 *
1167
 * @param mrb The mruby state
1168
 * @param target The target set table to add elements to
1169
 * @param source The source set table to flatten
1170
 * @param seen_count Pointer to the current count of seen sets (recursion depth)
1171
 * @return 0 on success, -1 if recursion depth exceeds maximum
1172
 */
1173
static int
1174
set_flatten_recursive(mrb_state *mrb, kset_t *target, kset_t *source, int *seen_count)
1175
0
{
1176
0
  if (!source || !target) return 0;
1177
0
  if (*seen_count >= MAX_NESTED_DEPTH) return -1;
1178
1179
0
  int ai = mrb_gc_arena_save(mrb);
1180
  /* Process each element in the source set */
1181
0
  KSET_FOREACH(source, k) {
1182
0
    mrb_value elem = kset_key(source, k);
1183
1184
    /* Check if element is a Set */
1185
0
    if (set_is_set(elem)) {
1186
      /* Increment recursion depth */
1187
0
      (*seen_count)++;
1188
1189
      /* Recursively flatten the nested set */
1190
0
      kset_t *nested_set = set_get_kset(mrb, elem);
1191
0
      if (nested_set) {
1192
0
        int nested_result = set_flatten_recursive(mrb, target, nested_set, seen_count);
1193
0
        if (nested_result < 0) {
1194
0
          return nested_result; /* Propagate error code */
1195
0
        }
1196
0
      }
1197
1198
      /* Decrement recursion depth */
1199
0
      (*seen_count)--;
1200
0
    }
1201
0
    else {
1202
      /* Add non-Set element directly */
1203
0
      kset_put(mrb, target, elem);
1204
0
    }
1205
0
    mrb_gc_arena_restore(mrb, ai);
1206
0
  }
1207
0
  return 0;
1208
0
}
1209
1210
/*
1211
 * Helper function: Check if a set has any nested sets
1212
 * Returns TRUE if nested sets found, FALSE otherwise
1213
 */
1214
static mrb_bool
1215
set_has_nested_sets(mrb_state *mrb, kset_t *set)
1216
0
{
1217
0
  if (kset_is_empty(set)) return FALSE;
1218
1219
0
  int ai = mrb_gc_arena_save(mrb);
1220
0
  KSET_FOREACH(set, k) {
1221
0
    if (set_is_set(kset_key(set, k))) {
1222
0
      return TRUE;
1223
0
    }
1224
0
    mrb_gc_arena_restore(mrb, ai);
1225
0
  }
1226
0
  return FALSE;
1227
0
}
1228
1229
/*
1230
 * Helper function: Perform the actual flattening operation
1231
 * Returns the flattened set (creates a new kset_t*)
1232
 */
1233
static kset_t*
1234
set_do_flatten(mrb_state *mrb, kset_t *source_set)
1235
0
{
1236
0
  kset_t *result_set = kset_init(mrb);
1237
0
  int seen_count = 0;
1238
1239
0
  if (set_flatten_recursive(mrb, result_set, source_set, &seen_count) < 0) {
1240
0
    kh_destroy(set_val, mrb, result_set);
1241
0
    mrb_raise(mrb, E_ARGUMENT_ERROR, "flatten recursion depth too deep");
1242
0
  }
1243
1244
0
  return result_set;
1245
0
}
1246
1247
/*
1248
 * call-seq:
1249
 *   set.flatten -> new_set
1250
 *
1251
 * Returns a new set that is a flattened version of this set.
1252
 * Recursively flattens nested sets.
1253
 */
1254
static mrb_value
1255
set_flatten(mrb_state *mrb, mrb_value self)
1256
0
{
1257
0
  kset_t *self_set = set_get_kset(mrb, self);
1258
1259
  /* Fast path for empty sets */
1260
0
  if (kset_is_empty(self_set)) {
1261
0
    return mrb_obj_new(mrb, mrb_obj_class(mrb, self), 0, NULL);
1262
0
  }
1263
1264
  /* Fast path: check if there are any nested sets */
1265
0
  if (!set_has_nested_sets(mrb, self_set)) {
1266
0
    return mrb_obj_dup(mrb, self);
1267
0
  }
1268
1269
  /* Create a new set and flatten into it */
1270
0
  mrb_value result = mrb_obj_new(mrb, mrb_obj_class(mrb, self), 0, NULL);
1271
0
  kset_t *result_set = set_get_kset(mrb, result);
1272
1273
0
  kset_t *flattened = set_do_flatten(mrb, self_set);
1274
1275
  /* Replace result_set's data with flattened data */
1276
0
  kset_destroy_data(mrb, result_set);
1277
0
  *result_set = *flattened;
1278
0
  mrb_free(mrb, flattened);
1279
1280
0
  return result;
1281
0
}
1282
1283
/*
1284
 * call-seq:
1285
 *   set.flatten! -> self or nil
1286
 *
1287
 * Replaces the contents of this set with a flattened version of itself.
1288
 * Returns self if flattened, nil if no changes were made.
1289
 */
1290
static mrb_value
1291
set_flatten_bang(mrb_state *mrb, mrb_value self)
1292
0
{
1293
0
  mrb_check_frozen_value(mrb, self);
1294
1295
0
  kset_t *self_set = set_get_kset(mrb, self);
1296
0
  if (kset_is_empty(self_set)) {
1297
0
    return mrb_nil_value(); /* No changes needed for empty set */
1298
0
  }
1299
1300
  /* Check if there are any nested sets */
1301
0
  if (!set_has_nested_sets(mrb, self_set)) {
1302
0
    return mrb_nil_value(); /* No nested sets, no changes needed */
1303
0
  }
1304
1305
  /* Flatten into a new set and replace self */
1306
0
  kset_t *flattened = set_do_flatten(mrb, self_set);
1307
1308
0
  kset_destroy_data(mrb, self_set);
1309
0
  *self_set = *flattened;
1310
0
  mrb_free(mrb, flattened);
1311
1312
0
  return self;
1313
0
}
1314
1315
/*
1316
 * call-seq:
1317
 *   set.delete_all(*objects) -> self
1318
 *
1319
 * Deletes multiple objects from the set and returns self.
1320
 */
1321
static mrb_value
1322
set_delete_all(mrb_state *mrb, mrb_value self)
1323
0
{
1324
0
  const mrb_value *argv;
1325
0
  mrb_int argc;
1326
1327
0
  mrb_get_args(mrb, "*", &argv, &argc);
1328
0
  kset_t *ks = set_get_kset(mrb, self);
1329
0
  if (kset_is_uninitialized(ks)) return self;
1330
1331
0
  int ai = mrb_gc_arena_save(mrb);
1332
0
  for (mrb_int i = 0; i < argc; i++) {
1333
0
    kset_iter_t k = kset_get(mrb, ks, argv[i]);
1334
0
    if (k != kset_end(ks)) {
1335
0
      kset_del(mrb, ks, k);
1336
0
    }
1337
0
    mrb_gc_arena_restore(mrb, ai);
1338
0
  }
1339
1340
0
  return self;
1341
0
}
1342
1343
/*
1344
 * call-seq:
1345
 *   set.include_all?(*objects) -> true or false
1346
 *
1347
 * Returns true if the set contains all of the given objects.
1348
 */
1349
static mrb_value
1350
set_include_all_p(mrb_state *mrb, mrb_value self)
1351
0
{
1352
0
  const mrb_value *argv;
1353
0
  mrb_int argc;
1354
1355
0
  mrb_get_args(mrb, "*", &argv, &argc);
1356
0
  kset_t *ks = set_get_kset(mrb, self);
1357
0
  if (kset_is_uninitialized(ks)) return mrb_false_value();
1358
1359
0
  for (mrb_int i = 0; i < argc; i++) {
1360
0
    kset_iter_t k = kset_get(mrb, ks, argv[i]);
1361
0
    if (k == kset_end(ks)) {
1362
0
      return mrb_false_value();
1363
0
    }
1364
0
  }
1365
1366
0
  return mrb_true_value();
1367
0
}
1368
1369
/*
1370
 * call-seq:
1371
 *   set.include_any?(*objects) -> true or false
1372
 *
1373
 * Returns true if the set contains any of the given objects.
1374
 */
1375
static mrb_value
1376
set_include_any_p(mrb_state *mrb, mrb_value self)
1377
0
{
1378
0
  const mrb_value *argv;
1379
0
  mrb_int argc;
1380
1381
0
  mrb_get_args(mrb, "*", &argv, &argc);
1382
0
  kset_t *ks = set_get_kset(mrb, self);
1383
0
  if (kset_is_empty(ks)) return mrb_false_value();
1384
1385
0
  for (mrb_int i = 0; i < argc; i++) {
1386
0
    kset_iter_t k = kset_get(mrb, ks, argv[i]);
1387
0
    if (k != kset_end(ks)) {
1388
0
      return mrb_true_value();
1389
0
    }
1390
0
  }
1391
1392
0
  return mrb_false_value();
1393
0
}
1394
1395
/*
1396
 * call-seq:
1397
 *   Set[*ary] -> new_set
1398
 *
1399
 * Creates a new set containing the given objects.
1400
 */
1401
static mrb_value
1402
set_s_create(mrb_state *mrb, mrb_value klass)
1403
20
{
1404
20
  const mrb_value *argv;
1405
20
  mrb_int argc;
1406
1407
20
  mrb_get_args(mrb, "*", &argv, &argc);
1408
1409
  /* Optimized direct creation */
1410
20
  mrb_value set = mrb_obj_new(mrb, mrb_class_ptr(klass), 0, NULL);
1411
20
  kset_t *ks = set_get_kset(mrb, set);
1412
1413
40
  for (mrb_int i = 0; i < argc; i++) {
1414
20
    kset_put(mrb, ks, argv[i]);
1415
20
  }
1416
1417
20
  return set;
1418
20
}
1419
1420
void
1421
mrb_mruby_set_gem_init(mrb_state *mrb)
1422
784
{
1423
784
  struct RClass *set;
1424
1425
784
  set = mrb_define_class(mrb, "Set", mrb->object_class);
1426
784
  MRB_SET_INSTANCE_TT(set, MRB_TT_SET);
1427
1428
784
  mrb_include_module(mrb, set, mrb_module_get(mrb, "Enumerable"));
1429
1430
784
  mrb_define_class_method(mrb, set, "[]", set_s_create, MRB_ARGS_ANY());
1431
1432
784
  mrb_define_private_method(mrb, set, "initialize_copy", set_init_copy, MRB_ARGS_REQ(1));
1433
1434
784
  mrb_define_method_id(mrb, set, MRB_SYM(size), set_size, MRB_ARGS_NONE());
1435
784
  mrb_define_method_id(mrb, set, MRB_SYM(length), set_size, MRB_ARGS_NONE());
1436
784
  mrb_define_method_id(mrb, set, MRB_SYM_Q(empty), set_empty_p, MRB_ARGS_NONE());
1437
784
  mrb_define_method_id(mrb, set, MRB_SYM(clear), set_clear, MRB_ARGS_NONE());
1438
784
  mrb_define_method_id(mrb, set, MRB_SYM(to_a), set_to_a, MRB_ARGS_NONE());
1439
1440
784
  mrb_define_method_id(mrb, set, MRB_SYM_Q(include), set_include_p, MRB_ARGS_REQ(1));
1441
784
  mrb_define_method_id(mrb, set, MRB_SYM_Q(member), set_include_p, MRB_ARGS_REQ(1));
1442
784
  mrb_define_method_id(mrb, set, MRB_OPSYM(eqq), set_include_p, MRB_ARGS_REQ(1));
1443
1444
784
  mrb_define_method_id(mrb, set, MRB_SYM(add), set_add, MRB_ARGS_REQ(1));
1445
784
  mrb_define_method_id(mrb, set, MRB_OPSYM(lshift), set_add, MRB_ARGS_REQ(1));
1446
784
  mrb_define_method_id(mrb, set, MRB_SYM_Q(add), set_add_p, MRB_ARGS_REQ(1));
1447
1448
784
  mrb_define_method_id(mrb, set, MRB_SYM(delete), set_delete, MRB_ARGS_REQ(1));
1449
784
  mrb_define_method_id(mrb, set, MRB_SYM_Q(delete), set_delete_p, MRB_ARGS_REQ(1));
1450
1451
784
  mrb_define_method_id(mrb, set, MRB_SYM(__init), set_init, MRB_ARGS_NONE());
1452
784
  mrb_define_method_id(mrb, set, MRB_SYM(__merge), set_core_merge, MRB_ARGS_REQ(1));
1453
784
  mrb_define_method_id(mrb, set, MRB_SYM(__subtract), set_core_subtract, MRB_ARGS_REQ(1));
1454
1455
784
  mrb_define_method_id(mrb, set, MRB_SYM(__union), set_core_union, MRB_ARGS_REQ(1));
1456
1457
784
  mrb_define_method_id(mrb, set, MRB_SYM(__difference), set_core_difference, MRB_ARGS_REQ(1));
1458
1459
784
  mrb_define_method_id(mrb, set, MRB_SYM(__intersection), set_core_intersection, MRB_ARGS_REQ(1));
1460
784
  mrb_define_method_id(mrb, set, MRB_SYM(__xor), set_core_xor, MRB_ARGS_REQ(1));
1461
1462
784
  mrb_define_method_id(mrb, set, MRB_OPSYM(eq), set_equal, MRB_ARGS_REQ(1));
1463
784
  mrb_define_method_id(mrb, set, MRB_SYM(hash), set_hash_m, MRB_ARGS_NONE());
1464
784
  mrb_define_alias(mrb, set, "eql?", "==");
1465
1466
784
  mrb_define_method_id(mrb, set, MRB_SYM(join), set_join, MRB_ARGS_OPT(1));
1467
784
  mrb_define_method_id(mrb, set, MRB_SYM(inspect), set_inspect, MRB_ARGS_NONE());
1468
784
  mrb_define_method_id(mrb, set, MRB_SYM(to_s), set_inspect, MRB_ARGS_NONE());
1469
1470
784
  mrb_define_method_id(mrb, set, MRB_SYM(reset), set_reset, MRB_ARGS_NONE());
1471
1472
  /* Bulk operation methods */
1473
784
  mrb_define_method_id(mrb, set, MRB_SYM(add_all), set_add_all, MRB_ARGS_ANY());
1474
784
  mrb_define_method_id(mrb, set, MRB_SYM(delete_all), set_delete_all, MRB_ARGS_ANY());
1475
784
  mrb_define_method_id(mrb, set, MRB_SYM_Q(include_all), set_include_all_p, MRB_ARGS_ANY());
1476
784
  mrb_define_method_id(mrb, set, MRB_SYM_Q(include_any), set_include_any_p, MRB_ARGS_ANY());
1477
1478
  /* Register our new C implementations */
1479
784
  mrb_define_method_id(mrb, set, MRB_SYM_Q(superset), set_superset_p, MRB_ARGS_REQ(1));
1480
784
  mrb_define_method_id(mrb, set, MRB_OPSYM(ge), set_superset_p, MRB_ARGS_REQ(1));
1481
784
  mrb_define_method_id(mrb, set, MRB_SYM_Q(proper_superset), set_proper_superset_p, MRB_ARGS_REQ(1));
1482
784
  mrb_define_method_id(mrb, set, MRB_OPSYM(gt), set_proper_superset_p, MRB_ARGS_REQ(1));
1483
1484
784
  mrb_define_method_id(mrb, set, MRB_SYM_Q(subset), set_subset_p, MRB_ARGS_REQ(1));
1485
784
  mrb_define_method_id(mrb, set, MRB_OPSYM(le), set_subset_p, MRB_ARGS_REQ(1));
1486
784
  mrb_define_method_id(mrb, set, MRB_SYM_Q(proper_subset), set_proper_subset_p, MRB_ARGS_REQ(1));
1487
784
  mrb_define_method_id(mrb, set, MRB_OPSYM(lt), set_proper_subset_p, MRB_ARGS_REQ(1));
1488
1489
784
  mrb_define_method_id(mrb, set, MRB_SYM_Q(intersect), set_intersect_p, MRB_ARGS_REQ(1));
1490
784
  mrb_define_method_id(mrb, set, MRB_SYM_Q(disjoint), set_disjoint_p, MRB_ARGS_REQ(1));
1491
1492
784
  mrb_define_method_id(mrb, set, MRB_OPSYM(cmp), set_cmp, MRB_ARGS_REQ(1));
1493
1494
784
  mrb_define_method_id(mrb, set, MRB_SYM(flatten), set_flatten, MRB_ARGS_NONE());
1495
784
  mrb_define_method_id(mrb, set, MRB_SYM_B(flatten), set_flatten_bang, MRB_ARGS_NONE());
1496
784
}
1497
1498
void
1499
mrb_mruby_set_gem_final(mrb_state *mrb)
1500
784
{
1501
784
}