diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb
index 588ac17a8..fe881367e 100644
--- a/mrbgems/mruby-array-ext/mrblib/array.rb
+++ b/mrbgems/mruby-array-ext/mrblib/array.rb
@@ -72,22 +72,6 @@ class Array
ary
end
- ##
- # call-seq:
- # ary | other_ary -> new_ary
- #
- # Set Union---Returns a new array by joining this array with
- # other_ary, removing duplicates.
- #
- # [ "a", "b", "c" ] | [ "c", "d", "a" ]
- # #=> [ "a", "b", "c", "d" ]
- #
- def |(elem)
- raise TypeError, "can't convert #{elem.class} into Array" unless elem.class == Array
-
- ary = self + elem
- ary.uniq! or ary
- end
##
# call-seq:
diff --git a/mrbgems/mruby-array-ext/src/array.c b/mrbgems/mruby-array-ext/src/array.c
index 808e4d6be..e03dd7ab4 100644
--- a/mrbgems/mruby-array-ext/src/array.c
+++ b/mrbgems/mruby-array-ext/src/array.c
@@ -411,6 +411,111 @@ ary_sub(mrb_state *mrb, mrb_value self)
return result_ary;
}
+/*
+ * call-seq:
+ * ary | other_ary -> new_ary
+ *
+ * Set Union---Returns a new array by joining this array with
+ * other_ary, removing duplicates.
+ *
+ * [ "a", "b", "c" ] | [ "c", "d", "a" ]
+ * #=> [ "a", "b", "c", "d" ]
+ */
+
+static mrb_value
+ary_union(mrb_state *mrb, mrb_value self)
+{
+ mrb_value other, result_ary;
+ struct RArray *self_ary, *other_ary;
+ mrb_value *p, *p_end, *other_p, *other_p_end;
+ mrb_int total_len;
+
+ mrb_get_args(mrb, "A", &other);
+
+ self_ary = mrb_ary_ptr(self);
+ other_ary = mrb_ary_ptr(other);
+ total_len = ARY_LEN(self_ary) + ARY_LEN(other_ary);
+
+ result_ary = mrb_ary_new(mrb);
+
+ if (total_len > SET_OP_HASH_THRESHOLD) {
+ /* Use hash for large arrays to achieve O(n) performance */
+ /* Follow the Ruby pattern: hash[key] = true, then check if hash[key] */
+ mrb_value hash = mrb_hash_new_capa(mrb, total_len);
+
+ /* Add elements from self */
+ p = ARY_PTR(self_ary);
+ p_end = p + ARY_LEN(self_ary);
+ while (p < p_end) {
+ mrb_value val = mrb_hash_get(mrb, hash, *p);
+ if (mrb_nil_p(val)) { /* key doesn't exist */
+ mrb_hash_set(mrb, hash, *p, mrb_true_value());
+ mrb_ary_push(mrb, result_ary, *p);
+ }
+ p++;
+ }
+
+ /* Add elements from other */
+ other_p = ARY_PTR(other_ary);
+ other_p_end = other_p + ARY_LEN(other_ary);
+ while (other_p < other_p_end) {
+ mrb_value val = mrb_hash_get(mrb, hash, *other_p);
+ if (mrb_nil_p(val)) { /* key doesn't exist */
+ mrb_hash_set(mrb, hash, *other_p, mrb_true_value());
+ mrb_ary_push(mrb, result_ary, *other_p);
+ }
+ other_p++;
+ }
+ }
+ else {
+ /* Use linear search for small arrays */
+
+ /* Add elements from self */
+ p = ARY_PTR(self_ary);
+ p_end = p + ARY_LEN(self_ary);
+ while (p < p_end) {
+ mrb_int result_len = RARRAY_LEN(result_ary);
+ mrb_value *result_ptr = ARY_PTR(RARRAY(result_ary));
+ mrb_bool found = FALSE;
+
+ for (mrb_int i = 0; i < result_len; i++) {
+ if (mrb_equal(mrb, *p, result_ptr[i])) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ mrb_ary_push(mrb, result_ary, *p);
+ }
+ p++;
+ }
+
+ /* Add elements from other */
+ other_p = ARY_PTR(other_ary);
+ other_p_end = other_p + ARY_LEN(other_ary);
+ while (other_p < other_p_end) {
+ mrb_int result_len = RARRAY_LEN(result_ary);
+ mrb_value *result_ptr = ARY_PTR(RARRAY(result_ary));
+ mrb_bool found = FALSE;
+
+ for (mrb_int i = 0; i < result_len; i++) {
+ if (mrb_equal(mrb, *other_p, result_ptr[i])) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ mrb_ary_push(mrb, result_ary, *other_p);
+ }
+ other_p++;
+ }
+ }
+
+ return result_ary;
+}
+
void
mrb_mruby_array_ext_gem_init(mrb_state* mrb)
{
@@ -426,6 +531,7 @@ mrb_mruby_array_ext_gem_init(mrb_state* mrb)
mrb_define_method_id(mrb, a, MRB_SYM(rotate), ary_rotate, MRB_ARGS_OPT(1));
mrb_define_method_id(mrb, a, MRB_SYM_B(rotate), ary_rotate_bang, MRB_ARGS_OPT(1));
mrb_define_method_id(mrb, a, MRB_OPSYM(sub), ary_sub, MRB_ARGS_REQ(1));
+ mrb_define_method_id(mrb, a, MRB_OPSYM(or), ary_union, MRB_ARGS_REQ(1));
}
void
diff --git a/mrbgems/mruby-array-ext/test/array.rb b/mrbgems/mruby-array-ext/test/array.rb
index f19b90278..706b55712 100644
--- a/mrbgems/mruby-array-ext/test/array.rb
+++ b/mrbgems/mruby-array-ext/test/array.rb
@@ -139,6 +139,34 @@ assert("Array#|") do
assert_equal [1, 2, 3, 1], a
end
+assert("Array#| with large arrays") do
+ # Test hash-based implementation (total length > 16)
+ a = (1..20).to_a
+ b = (18..50).to_a
+ result = a | b
+ expected = (1..50).to_a
+
+ assert_equal expected, result
+ assert_equal 50, result.size
+
+ # Test with overlapping ranges
+ a = (1..15).to_a
+ b = (10..25).to_a
+ result = a | b
+ expected = (1..25).to_a
+
+ assert_equal expected, result
+ assert_equal 25, result.size
+
+ # Ensure original arrays are unchanged
+ original_a = (1..20).to_a
+ original_b = (18..50).to_a
+ result = original_a | original_b
+ assert_equal (1..50).to_a, result
+ assert_equal (1..20).to_a, original_a
+ assert_equal (18..50).to_a, original_b
+end
+
assert("Array#union") do
a = [1, 2, 3, 1]
b = [1, 4]