ruby-changes:64713
From: zverok <ko1@a...>
Date: Sat, 2 Jan 2021 17:27:44 +0900 (JST)
Subject: [ruby-changes:64713] b8d33df1d9 (master): Add Enumerable#compact and Enumerator::Lazy#compact
https://git.ruby-lang.org/ruby.git/commit/?id=b8d33df1d9 From b8d33df1d9799cd04b92c1c28e42cc3028cc7524 Mon Sep 17 00:00:00 2001 From: zverok <zverok.offline@g...> Date: Sat, 5 Dec 2020 13:39:20 +0200 Subject: Add Enumerable#compact and Enumerator::Lazy#compact diff --git a/enum.c b/enum.c index da9f434..e9cac3e 100644 --- a/enum.c +++ b/enum.c @@ -4178,6 +4178,48 @@ enum_uniq(VALUE obj) https://github.com/ruby/ruby/blob/trunk/enum.c#L4178 return ret; } +static VALUE +compact_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary)) +{ + ENUM_WANT_SVALUE(); + + if (!NIL_P(i)) { + rb_ary_push(ary, i); + } + return Qnil; +} + +/* + * call-seq: + * enum.compact -> array + * + * Returns an array of all non-+nil+ elements from enumeration. + * + * def with_nils + * yield 1 + * yield 2 + * yield nil + * yield 3 + * end + * + * to_enum(:with_nils).compact + * # => [1, 2, 3] + * + * See also Array#compact. + */ + +static VALUE +enum_compact(VALUE obj) +{ + VALUE ary; + + ary = rb_ary_new(); + rb_block_call(obj, id_each, 0, 0, compact_i, ary); + + return ary; +} + + /* * The Enumerable mixin provides collection classes with several * traversal and searching methods, and with the ability to sort. The @@ -4251,6 +4293,7 @@ Init_Enumerable(void) https://github.com/ruby/ruby/blob/trunk/enum.c#L4293 rb_define_method(rb_mEnumerable, "chunk_while", enum_chunk_while, 0); rb_define_method(rb_mEnumerable, "sum", enum_sum, -1); rb_define_method(rb_mEnumerable, "uniq", enum_uniq, 0); + rb_define_method(rb_mEnumerable, "compact", enum_compact, 0); id_next = rb_intern_const("next"); } diff --git a/enumerator.c b/enumerator.c index b4a7cb5..6d6a588 100644 --- a/enumerator.c +++ b/enumerator.c @@ -2654,6 +2654,30 @@ lazy_uniq(VALUE obj) https://github.com/ruby/ruby/blob/trunk/enumerator.c#L2654 } static struct MEMO * +lazy_compact_proc(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_index) +{ + if (NIL_P(result->memo_value)) return 0; + return result; +} + +static const lazyenum_funcs lazy_compact_funcs = { + lazy_compact_proc, 0, +}; + +/* + * call-seq: + * lazy.compact -> lazy_enumerator + * + * Like Enumerable#compact, but chains operation to be lazy-evaluated. + */ + +static VALUE +lazy_compact(VALUE obj) +{ + return lazy_add_method(obj, 0, 0, Qnil, Qnil, &lazy_compact_funcs); +} + +static struct MEMO * lazy_with_index_proc(VALUE proc_entry, struct MEMO* result, VALUE memos, long memo_index) { struct proc_entry *entry = proc_entry_ptr(proc_entry); @@ -4098,6 +4122,7 @@ InitVM_Enumerator(void) https://github.com/ruby/ruby/blob/trunk/enumerator.c#L4122 rb_define_method(rb_cLazy, "slice_when", lazy_super, -1); rb_define_method(rb_cLazy, "chunk_while", lazy_super, -1); rb_define_method(rb_cLazy, "uniq", lazy_uniq, 0); + rb_define_method(rb_cLazy, "compact", lazy_compact, 0); rb_define_method(rb_cLazy, "with_index", lazy_with_index, -1); lazy_use_super_method = rb_hash_new_with_size(18); diff --git a/test/ruby/test_enum.rb b/test/ruby/test_enum.rb index 126b100..fc02203 100644 --- a/test/ruby/test_enum.rb +++ b/test/ruby/test_enum.rb @@ -1229,6 +1229,21 @@ class TestEnumerable < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_enum.rb#L1229 assert_equal([1, [1, 2]], Foo.new.to_enum.uniq) end + def test_compact + class << (enum = Object.new) + include Enumerable + def each + yield 3 + yield nil + yield 7 + yield 9 + yield nil + end + end + + assert_equal([3, 7, 9], enum.compact) + end + def test_transient_heap_sort_by klass = Class.new do include Comparable diff --git a/test/ruby/test_enumerator.rb b/test/ruby/test_enumerator.rb index eb15d4b..718bcb7 100644 --- a/test/ruby/test_enumerator.rb +++ b/test/ruby/test_enumerator.rb @@ -696,6 +696,11 @@ class TestEnumerator < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_enumerator.rb#L696 assert_equal([0, 1], u.force) end + def test_compact + u = [0, 1, nil, 2, 3, nil].to_enum.lazy.compact + assert_equal([0, 1, 2, 3], u.force) + end + def test_enum_chain_and_plus r = 1..5 -- cgit v0.10.2 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/