[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]