ruby-changes:42076
From: mame <ko1@a...>
Date: Thu, 17 Mar 2016 21:14:27 +0900 (JST)
Subject: [ruby-changes:42076] mame:r54150 (trunk): * array.c (rb_ary_max, rb_ary_min): Array#max and Array#min added.
mame 2016-03-17 21:14:21 +0900 (Thu, 17 Mar 2016) New Revision: 54150 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=54150 Log: * array.c (rb_ary_max, rb_ary_min): Array#max and Array#min added. [Feature #12172] * internal.h (OPTIMIZED_CMP): moved from enum.c so that array.c can use it. * test/ruby/test_array.rb (test_max, test_min): tests for Array#max and Array#min. * test/ruby/test_enum.rb (test_max, test_min): revised a bit to test Enumerable#max and #min explicitly. Modified files: trunk/ChangeLog trunk/array.c trunk/enum.c trunk/internal.h trunk/test/ruby/test_array.rb trunk/test/ruby/test_enum.rb Index: enum.c =================================================================== --- enum.c (revision 54149) +++ enum.c (revision 54150) @@ -1486,13 +1486,6 @@ enum_none(VALUE obj) https://github.com/ruby/ruby/blob/trunk/enum.c#L1486 return memo->v1; } -#define OPTIMIZED_CMP(a, b, data) \ - ((FIXNUM_P(a) && FIXNUM_P(b) && CMP_OPTIMIZABLE(data, Fixnum)) ? \ - (((long)a > (long)b) ? 1 : ((long)a < (long)b) ? -1 : 0) : \ - (STRING_P(a) && STRING_P(b) && CMP_OPTIMIZABLE(data, String)) ? \ - rb_str_cmp(a, b) : \ - rb_cmpint(rb_funcallv(a, id_cmp, 1, &b), a, b)) - struct min_t { VALUE min; struct cmp_opt_data cmp_opt; Index: test/ruby/test_array.rb =================================================================== --- test/ruby/test_array.rb (revision 54149) +++ test/ruby/test_array.rb (revision 54150) @@ -1552,6 +1552,37 @@ class TestArray < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_array.rb#L1552 assert_equal "wrong array length at 2 (expected 2, was 1)", e.message end + def test_min + assert_equal(1, [1, 2, 3, 1, 2].min) + assert_equal(3, [1, 2, 3, 1, 2].min {|a,b| b <=> a }) + cond = ->((a, ia), (b, ib)) { (b <=> a).nonzero? or ia <=> ib } + assert_equal([3, 2], [1, 2, 3, 1, 2].each_with_index.min(&cond)) + ary = %w(albatross dog horse) + assert_equal("albatross", ary.min) + assert_equal("dog", ary.min {|a,b| a.length <=> b.length }) + assert_equal(1, [3,2,1].min) + assert_equal(%w[albatross dog], ary.min(2)) + assert_equal(%w[dog horse], + ary.min(2) {|a,b| a.length <=> b.length }) + assert_equal([13, 14], [20, 32, 32, 21, 30, 25, 29, 13, 14].min(2)) + assert_equal([2, 4, 6, 7], [2, 4, 8, 6, 7].min(4)) + end + + def test_max + assert_equal(3, [1, 2, 3, 1, 2].max) + assert_equal(1, [1, 2, 3, 1, 2].max {|a,b| b <=> a }) + cond = ->((a, ia), (b, ib)) { (b <=> a).nonzero? or ia <=> ib } + assert_equal([1, 3], [1, 2, 3, 1, 2].each_with_index.max(&cond)) + ary = %w(albatross dog horse) + assert_equal("horse", ary.max) + assert_equal("albatross", ary.max {|a,b| a.length <=> b.length }) + assert_equal(1, [3,2,1].max{|a,b| b <=> a }) + assert_equal(%w[horse dog], ary.max(2)) + assert_equal(%w[albatross horse], + ary.max(2) {|a,b| a.length <=> b.length }) + assert_equal([3, 2], [0, 0, 0, 0, 0, 0, 1, 3, 2].max(2)) + end + def test_uniq a = [] b = a.uniq Index: test/ruby/test_enum.rb =================================================================== --- test/ruby/test_enum.rb (revision 54149) +++ test/ruby/test_enum.rb (revision 54150) @@ -331,15 +331,15 @@ class TestEnumerable < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/test/ruby/test_enum.rb#L331 assert_equal(3, @obj.min {|a,b| b <=> a }) cond = ->((a, ia), (b, ib)) { (b <=> a).nonzero? or ia <=> ib } assert_equal([3, 2], @obj.each_with_index.min(&cond)) - ary = %w(albatross dog horse) - assert_equal("albatross", ary.min) - assert_equal("dog", ary.min {|a,b| a.length <=> b.length }) - assert_equal(1, [3,2,1].min) - assert_equal(%w[albatross dog], ary.min(2)) + enum = %w(albatross dog horse).to_enum + assert_equal("albatross", enum.min) + assert_equal("dog", enum.min {|a,b| a.length <=> b.length }) + assert_equal(1, [3,2,1].to_enum.min) + assert_equal(%w[albatross dog], enum.min(2)) assert_equal(%w[dog horse], - ary.min(2) {|a,b| a.length <=> b.length }) - assert_equal([13, 14], [20, 32, 32, 21, 30, 25, 29, 13, 14].min(2)) - assert_equal([2, 4, 6, 7], [2, 4, 8, 6, 7].min(4)) + enum.min(2) {|a,b| a.length <=> b.length }) + assert_equal([13, 14], [20, 32, 32, 21, 30, 25, 29, 13, 14].to_enum.min(2)) + assert_equal([2, 4, 6, 7], [2, 4, 8, 6, 7].to_enum.min(4)) end def test_max @@ -347,14 +347,14 @@ class TestEnumerable < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/test/ruby/test_enum.rb#L347 assert_equal(1, @obj.max {|a,b| b <=> a }) cond = ->((a, ia), (b, ib)) { (b <=> a).nonzero? or ia <=> ib } assert_equal([1, 3], @obj.each_with_index.max(&cond)) - ary = %w(albatross dog horse) - assert_equal("horse", ary.max) - assert_equal("albatross", ary.max {|a,b| a.length <=> b.length }) - assert_equal(1, [3,2,1].max{|a,b| b <=> a }) - assert_equal(%w[horse dog], ary.max(2)) + enum = %w(albatross dog horse).to_enum + assert_equal("horse", enum.max) + assert_equal("albatross", enum.max {|a,b| a.length <=> b.length }) + assert_equal(1, [3,2,1].to_enum.max{|a,b| b <=> a }) + assert_equal(%w[horse dog], enum.max(2)) assert_equal(%w[albatross horse], - ary.max(2) {|a,b| a.length <=> b.length }) - assert_equal([3, 2], [0, 0, 0, 0, 0, 0, 1, 3, 2].max(2)) + enum.max(2) {|a,b| a.length <=> b.length }) + assert_equal([3, 2], [0, 0, 0, 0, 0, 0, 1, 3, 2].to_enum.max(2)) end def test_minmax Index: ChangeLog =================================================================== --- ChangeLog (revision 54149) +++ ChangeLog (revision 54150) @@ -1,4 +1,18 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 -Thu Mar 17 21:02:42 2016 Yusuke Endoh <mame@t...> +Thu Mar 17 21:09:34 2016 Yusuke Endoh <mame@r...> + + * array.c (rb_ary_max, rb_ary_min): Array#max and Array#min added. + [Feature #12172] + + * internal.h (OPTIMIZED_CMP): moved from enum.c so that array.c can + use it. + + * test/ruby/test_array.rb (test_max, test_min): tests for Array#max + and Array#min. + + * test/ruby/test_enum.rb (test_max, test_min): revised a bit to test + Enumerable#max and #min explicitly. + +Thu Mar 17 21:02:42 2016 Yusuke Endoh <mame@r...> * internal.c: struct cmp_opt_data added for refactoring out a data structure for CMP_OPTIMIZABLE Index: internal.h =================================================================== --- internal.h (revision 54149) +++ internal.h (revision 54150) @@ -698,6 +698,13 @@ struct cmp_opt_data { https://github.com/ruby/ruby/blob/trunk/internal.h#L698 rb_method_basic_definition_p(TOKEN_PASTE(rb_c,type), id_cmp) && \ ((data).opt_methods |= CMP_OPTIMIZABLE_BIT(type)))) +#define OPTIMIZED_CMP(a, b, data) \ + ((FIXNUM_P(a) && FIXNUM_P(b) && CMP_OPTIMIZABLE(data, Fixnum)) ? \ + (((long)a > (long)b) ? 1 : ((long)a < (long)b) ? -1 : 0) : \ + (STRING_P(a) && STRING_P(b) && CMP_OPTIMIZABLE(data, String)) ? \ + rb_str_cmp(a, b) : \ + rb_cmpint(rb_funcallv(a, id_cmp, 1, &b), a, b)) + /* ment is in method.h */ /* global variable */ Index: array.c =================================================================== --- array.c (revision 54149) +++ array.c (revision 54150) @@ -4178,6 +4178,96 @@ rb_ary_or(VALUE ary1, VALUE ary2) https://github.com/ruby/ruby/blob/trunk/array.c#L4178 return ary3; } +/* + * call-seq: + * ary.max -> obj + * ary.max { |a, b| block } -> obj + * ary.max(n) -> array + * ary.max(n) {|a,b| block } -> array + * + * Returns the object in _ary_ with the maximum value. The + * first form assumes all objects implement <code>Comparable</code>; + * the second uses the block to return <em>a <=> b</em>. + * + * a = %w(albatross dog horse) + * a.max #=> "horse" + * a.max { |a, b| a.length <=> b.length } #=> "albatross" + * + * If the +n+ argument is given, maximum +n+ elements are returned + * as an array. + * + * a = %w[albatross dog horse] + * a.max(2) #=> ["horse", "dog"] + * a.max(2) {|a, b| a.length <=> b.length } #=> ["albatross", "horse"] + */ +static VALUE +rb_ary_max(int argc, VALUE *argv, VALUE ary) +{ + struct cmp_opt_data cmp_opt = { 0, 0 }; + VALUE result = Qundef, v; + VALUE num; + long i; + + rb_scan_args(argc, argv, "01", &num); + + if (!NIL_P(num) || rb_block_given_p()) + return rb_call_super(argc, argv); /* XXX: should redefine? */ + + for (i = 0; i < RARRAY_LEN(ary); i++) { + v = RARRAY_AREF(ary, i); + if (result == Qundef || OPTIMIZED_CMP(v, result, cmp_opt) > 0) { + result = v; + } + } + if (result == Qundef) return Qnil; + return result; +} + +/* + * call-seq: + * ary.min -> obj + * ary.min {| a,b | block } -> obj + * ary.min(n) -> array + * ary.min(n) {| a,b | block } -> array + * + * Returns the object in _ary_ with the minimum value. The + * first form assumes all objects implement <code>Comparable</code>; + * the second uses the block to return <em>a <=> b</em>. + * + * a = %w(albatross dog horse) + * a.min #=> "albatross" + * a.min { |a, b| a.length <=> b.length } #=> "dog" + * + * If the +n+ argument is given, minimum +n+ elements are returned + * as an array. + * + * a = %w[albatross dog horse] + * a.min(2) #=> ["albatross", "dog"] + * a.min(2) {|a, b| a.length <=> b.length } #=> ["dog", "horse"] + */ +static VALUE +rb_ary_min(int argc, VALUE *argv, VALUE ary) +{ + struct cmp_opt_data cmp_opt = { 0, 0 }; + VALUE result = Qundef, v; + VALUE num; + long i; + + rb_scan_args(argc, argv, "01", &num); + + if (!NIL_P(num) || rb_block_given_p()) + return rb_call_super(argc, argv); /* XXX: should redefine? */ + + for (i = 0; i < RARRAY_LEN(ary); i++) { + v = RARRAY_AREF(ary, i); + if (result == Qundef || OPTIMIZED_CMP(v, result, cmp_opt) < 0) { + result = v; + } + } + if (result == Qundef) return Qnil; + return result; +} + static int push_value(st_data_t key, st_data_t val, st_data_t ary) { @@ -5867,6 +5957,9 @@ Init_Array(void) https://github.com/ruby/ruby/blob/trunk/array.c#L5957 rb_define_method(rb_cArray, "&", rb_ary_and, 1); rb_define_method(rb_cArray, "|", rb_ary_or, 1); + rb_define_method(rb_cArray, "max", rb_ary_max, -1); + rb_define_method(rb_cArray, "min", rb_ary_min, -1); + rb_define_method(rb_cArray, "uniq", rb_ary_uniq, 0); rb_define_method(rb_cArray, "uniq!", rb_ary_uniq_bang, 0); rb_define_method(rb_cArray, "compact", rb_ary_compact, 0); -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/