Project

General

Profile

Feature #9970 ยป hash-map-keys-and-map-values.diff

seantheprogrammer (Sean Griffin), 06/21/2014 09:34 PM

View differences:

hash.c (working copy)
2450 2450
    return Qfalse;
2451 2451
}
2452 2452

  
2453
VALUE
2454
map_hash(VALUE hash, int (*func)(ANYARGS))
2455
{
2456
    VALUE result;
2457

  
2458
    RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
2459
    result = rb_hash_new();
2460
    if (!RHASH_EMPTY_P(hash)) {
2461
        rb_hash_foreach(hash, func, result);
2462
    }
2463
    return result;
2464
}
2465

  
2466
static int
2467
map_keys_i(VALUE key, VALUE value, VALUE result)
2468
{
2469
    rb_hash_aset(result, rb_yield(key), value);
2470
    return ST_CONTINUE;
2471
}
2472

  
2473
/*
2474
 *  call-seq:
2475
 *     hsh.map_keys {| key | block }  -> a_hash
2476
 *     hsh.map_keys                   -> an_enumerator
2477
 *
2478
 *  Returns a new hash, with the keys computed from running <code>block<code>
2479
 *  once for each key in the hash, and the values unchanged.
2480
 *
2481
 *  If no block is given, an enumerator is returned instead.
2482
 *
2483
 *     h = { "a" => 100, "b" => 200 }
2484
 *     h.map_keys { |key| key + '!' }   #=> { "a!" => 100, "b!" => 200 }
2485
 *
2486
 */
2487

  
2488
VALUE
2489
rb_hash_map_keys(VALUE hash)
2490
{
2491
    return map_hash(hash, map_keys_i);
2492
}
2493

  
2494
/*
2495
 *  call-seq:
2496
 *     hsh.map_keys! {| key | block }  -> hsh or nil
2497
 *     hsh.map_keys!                   -> an_enumerator
2498
 *
2499
 *  Replaces every key in the hash with the result of calling <code>block</code>
2500
 *  once for each key in the hash. Returns <code>nil</code> if no changes were made.
2501
 *
2502
 *  If no block is given, an enumerator is returned instead.
2503
 *
2504
 *     h = { "a" => 100, "b" => 200 }
2505
 *     h.map_keys! { |key| key + '!' }   #=> { "a!" => 100, "b!" => 200 }
2506
 *
2507
 */
2508

  
2509
VALUE
2510
rb_hash_map_keys_bang(VALUE hash)
2511
{
2512
    st_index_t n;
2513
    VALUE keys;
2514
    long i;
2515

  
2516
    RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
2517
    rb_hash_modify(hash);
2518
    n = RHASH_SIZE(hash);
2519
    if (!n) return Qnil;
2520

  
2521
    keys = rb_hash_keys(hash);
2522
    for (i = 0; i < RARRAY_LEN(keys); i++) {
2523
      VALUE key = RARRAY_AREF(keys, i);
2524
      rb_hash_aset(hash, rb_yield(key), rb_hash_delete(hash, key));
2525
    }
2526

  
2527
    return hash;
2528
}
2529

  
2530
static int
2531
map_values_i(VALUE key, VALUE value, VALUE result)
2532
{
2533
    rb_hash_aset(result, key, rb_yield(value));
2534
    return ST_CONTINUE;
2535
}
2536

  
2537
/*
2538
 *  call-seq:
2539
 *     hsh.map_values {| value | block }  -> a_hash
2540
 *     hsh.map_values                     -> an_enumerator
2541
 *
2542
 *  Returns a new hash, with the values computed from running <code>block<code>
2543
 *  once for each value in the hash, and the values unchanged.
2544
 *
2545
 *  If no block is given, an enumerator is returned instead.
2546
 *
2547
 *     h = { "a" => 100, "b" => 200 }
2548
 *     h.map_values { |value| value * 2 }   #=> { "a" => 200, "b" => 400 }
2549
 *
2550
 */
2551

  
2552
VALUE
2553
rb_hash_map_values(VALUE hash)
2554
{
2555
    return map_hash(hash, map_values_i);
2556
}
2557

  
2558
/*
2559
 *  call-seq:
2560
 *     hsh.map_values! {| value | block }  -> hsh or nil
2561
 *     hsh.map_values!                     -> an_enumerator
2562
 *
2563
 *  Replaces every value in the hash with the result of calling <code>block</code>
2564
 *  once for each value in the hash, and the keys unchanged.
2565
 *
2566
 *  If no block is given, an enumerator is returned instead.
2567
 *
2568
 *     h = { "a" => 100, "b" => 200 }
2569
 *     h.map_values! { |value| value * 2 }   #=> { "a" => 200, "b" => 400 }
2570
 *
2571
 */
2572

  
2573
VALUE
2574
rb_hash_map_values_bang(VALUE hash)
2575
{
2576
    st_index_t n;
2577

  
2578
    RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
2579
    n = RHASH_SIZE(hash);
2580
    if (!n) return Qnil;
2581
    rb_hash_foreach(hash, map_values_i, hash);
2582

  
2583
    return hash;
2584
}
2585

  
2453 2586
static int path_tainted = -1;
2454 2587

  
2455 2588
static char **origenviron;
......
3810 3943
    rb_define_method(rb_cHash, "assoc", rb_hash_assoc, 1);
3811 3944
    rb_define_method(rb_cHash, "rassoc", rb_hash_rassoc, 1);
3812 3945
    rb_define_method(rb_cHash, "flatten", rb_hash_flatten, -1);
3946
    rb_define_method(rb_cHash, "map_keys", rb_hash_map_keys, 0);
3947
    rb_define_method(rb_cHash, "map_keys!", rb_hash_map_keys_bang, 0);
3948
    rb_define_method(rb_cHash, "map_values", rb_hash_map_values, 0);
3949
    rb_define_method(rb_cHash, "map_values!", rb_hash_map_values_bang, 0);
3813 3950

  
3814 3951
    rb_define_method(rb_cHash,"include?", rb_hash_has_key, 1);
3815 3952
    rb_define_method(rb_cHash,"member?", rb_hash_has_key, 1);
test/ruby/test_hash.rb (working copy)
1269 1269
    assert_equal(bug9381, hash[wrapper.new(5)])
1270 1270
  end
1271 1271

  
1272
  def test_map_keys
1273
    original = { 'a' => 'a', 'b' => 'b' }
1274
    mapped = original.map_keys { |key| key + '!' }
1275

  
1276
    assert_equal({ 'a' => 'a', 'b' => 'b' }, original)
1277
    assert_equal({ 'a!' => 'a', 'b!' => 'b' }, mapped)
1278
  end
1279

  
1280
  def test_map_keys_bang
1281
    original = { 'a' => 'a', 'b' => 'b' }
1282
    mapped = original.map_keys! { |key| key + '!' }
1283

  
1284
    assert_equal({ 'a!' => 'a', 'b!' => 'b' }, original)
1285
    assert_equal({ 'a!' => 'a', 'b!' => 'b' }, mapped)
1286
  end
1287

  
1288
  def test_map_keys_bang_on_empty_hash
1289
    original = {}
1290
    mapped = original.map_keys! { |key| key + '!' }
1291

  
1292
    assert_equal({}, original)
1293
    assert_nil mapped
1294
  end
1295

  
1296
  def test_map_values
1297
    original = { 'a' => 'a', 'b' => 'b' }
1298
    mapped = original.map_values { |value| value + '!' }
1299

  
1300
    assert_equal({ 'a' => 'a', 'b' => 'b' }, original)
1301
    assert_equal({ 'a' => 'a!', 'b' => 'b!' }, mapped)
1302
  end
1303

  
1304
  def test_map_values_bang
1305
    original = { 'a' => 'a', 'b' => 'b' }
1306
    mapped = original.map_values! { |value| value + '!' }
1307

  
1308
    assert_equal({ 'a' => 'a!', 'b' => 'b!' }, original)
1309
    assert_equal({ 'a' => 'a!', 'b' => 'b!' }, mapped)
1310
  end
1311

  
1312
  def test_map_values_bang_on_empty_hash
1313
    original = {}
1314
    mapped = original.map_values! { |value| value + '!' }
1315

  
1316
    assert_equal({}, original)
1317
    assert_nil mapped
1318
  end
1319

  
1320

  
1272 1321
  class TestSubHash < TestHash
1273 1322
    class SubHash < Hash
1274 1323
      def reject(*)