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

ruby-changes:43774

From: mrkn <ko1@a...>
Date: Tue, 9 Aug 2016 17:54:20 +0900 (JST)
Subject: [ruby-changes:43774] mrkn:r55847 (trunk): hash.c: implement Hash#map_v and Hash#map_v!

mrkn	2016-08-09 17:54:15 +0900 (Tue, 09 Aug 2016)

  New Revision: 55847

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=55847

  Log:
    hash.c: implement Hash#map_v and Hash#map_v!
    
    * hash.c (rb_hash_map_v, rb_hash_map_v_bang): impelement Hash#map_v and
      Hash#map_v! [Feature #12512] [ruby-core:76095]
    
    * test/ruby/test_hash.rb: add tests for above change.

  Modified files:
    trunk/ChangeLog
    trunk/hash.c
    trunk/test/ruby/test_hash.rb
Index: hash.c
===================================================================
--- hash.c	(revision 55846)
+++ hash.c	(revision 55847)
@@ -1788,6 +1788,70 @@ rb_hash_each_pair(VALUE hash) https://github.com/ruby/ruby/blob/trunk/hash.c#L1788
 }
 
 static int
+map_v_i(VALUE key, VALUE value, VALUE result)
+{
+    VALUE new_value = rb_yield(value);
+    rb_hash_aset(result, key, new_value);
+    return ST_CONTINUE;
+}
+
+/*
+ *  call-seq:
+ *     hsh.map_v {|value| block } -> hsh
+ *     hsh.map_v                  -> an_enumerator
+ *
+ *  Return a new with the results of running block once for every value.
+ *  This method does not change the keys.
+ *
+ *     h = { a: 1, b: 2, c: 3 }
+ *     h.map_v {|v| v * v + 1 }  #=> { a: 2, b: 5, c: 10 }
+ *     h.map_v(&:to_s)           #=> { a: "1", b: "2", c: "3" }
+ *     h.map_v.with_index {|v, i| "#{v}.#{i}" }
+ *                               #=> { a: "1.0", b: "2.1", c: "3.2" }
+ *
+ *  If no block is given, an enumerator is returned instead.
+ */
+static VALUE
+rb_hash_map_v(VALUE hash)
+{
+    VALUE result;
+
+    RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
+    result = rb_hash_new();
+    if (!RHASH_EMPTY_P(hash)) {
+        rb_hash_foreach(hash, map_v_i, result);
+    }
+
+    return result;
+}
+
+/*
+ *  call-seq:
+ *     hsh.map_v! {|value| block } -> hsh
+ *     hsh.map_v!                  -> an_enumerator
+ *
+ *  Return a new with the results of running block once for every value.
+ *  This method does not change the keys.
+ *
+ *     h = { a: 1, b: 2, c: 3 }
+ *     h.map_v! {|v| v * v + 1 }  #=> { a: 2, b: 5, c: 10 }
+ *     h.map_v!(&:to_s)           #=> { a: "1", b: "2", c: "3" }
+ *     h.map_v!.with_index {|v, i| "#{v}.#{i}" }
+ *                                #=> { a: "1.0", b: "2.1", c: "3.2" }
+ *
+ *  If no block is given, an enumerator is returned instead.
+ */
+static VALUE
+rb_hash_map_v_bang(VALUE hash)
+{
+    RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
+    rb_hash_modify_check(hash);
+    if (RHASH(hash)->ntbl)
+        rb_hash_foreach(hash, map_v_i, hash);
+    return hash;
+}
+
+static int
 to_a_i(VALUE key, VALUE value, VALUE ary)
 {
     rb_ary_push(ary, rb_assoc_new(key, value));
@@ -4336,6 +4400,9 @@ Init_Hash(void) https://github.com/ruby/ruby/blob/trunk/hash.c#L4400
     rb_define_method(rb_cHash,"each_pair", rb_hash_each_pair, 0);
     rb_define_method(rb_cHash,"each", rb_hash_each_pair, 0);
 
+    rb_define_method(rb_cHash, "map_v", rb_hash_map_v, 0);
+    rb_define_method(rb_cHash, "map_v!", rb_hash_map_v_bang, 0);
+
     rb_define_method(rb_cHash,"keys", rb_hash_keys, 0);
     rb_define_method(rb_cHash,"values", rb_hash_values, 0);
     rb_define_method(rb_cHash,"values_at", rb_hash_values_at, -1);
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 55846)
+++ ChangeLog	(revision 55847)
@@ -1,3 +1,10 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Tue Aug  9 17:50:00 2016  Kenta Murata  <mrkn@m...>
+
+	* hash.c (rb_hash_map_v, rb_hash_map_v_bang): impelement Hash#map_v and
+	  Hash#map_v! [Feature #12512] [ruby-core:76095]
+
+	* test/ruby/test_hash.rb: add tests for above change.
+
 Tue Aug  9 16:09:03 2016  NARUSE, Yui  <naruse@r...>
 
 	* vm_insnhelper.c (vm_getivar): use always_inline because
Index: test/ruby/test_hash.rb
===================================================================
--- test/ruby/test_hash.rb	(revision 55846)
+++ test/ruby/test_hash.rb	(revision 55847)
@@ -1415,6 +1415,27 @@ class TestHash < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_hash.rb#L1415
     assert_equal([10, 20, 30], [1, 2, 3].map(&h))
   end
 
+  def test_map_v
+    x = @cls[a: 1, b: 2, c: 3]
+    y = x.map_v {|v| v ** 2 }
+    assert_equal([1, 4, 9], y.values_at(:a, :b, :c))
+    assert_not_same(x, y)
+
+    y = x.map_v.with_index {|v, i| "#{v}.#{i}" }
+    assert_equal(%w(1.0  2.1  3.2), y.values_at(:a, :b, :c))
+  end
+
+  def test_map_v_bang
+    x = @cls[a: 1, b: 2, c: 3]
+    y = x.map_v! {|v| v ** 2 }
+    assert_equal([1, 4, 9], y.values_at(:a, :b, :c))
+    assert_same(x, y)
+
+    x = @cls[a: 1, b: 2, c: 3]
+    y = x.map_v!.with_index {|v, i| "#{v}.#{i}" }
+    assert_equal(%w(1.0  2.1  3.2), y.values_at(:a, :b, :c))
+  end
+
   class TestSubHash < TestHash
     class SubHash < Hash
       def reject(*)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

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