Project

General

Profile

Feature #16350 ยป 0001-Start-implementing-ArithmeticSequence-member.patch

patch (unfinished implementation, tests currently fail) - parker (Parker Finch), 11/16/2019 05:10 PM

View differences:

enumerator.c
3624 3624
    return str;
3625 3625
}
3626

  
3627
/*
3628
 *  call-seq:
3629
 *     arith_sequence.include?(obj)     -> true or false
3630
 *     arith_sequence.member?(obj)      -> true or false
3631
 *
3632
 *  Returns <code>true</code> if any member of <i>arith_sequence</i>
3633
 *  equals <i>obj</i>. If <i>obj</i> is an integer and the beginning
3634
 *  and step are integers, then this computes whether or not the
3635
 *  sequence includes <i>obj</i> using arithmetic. If <i>obj</i> is a
3636
 *  float, then TBD. (It might just fall back to the existing behavior
3637
 *  of enumerating the sequence until the sequence ends or the number
3638
 *  is found.)
3639
 *
3640
 *     (1..10).include? 5  #=> true
3641
 *     (1..10).include? 15 #=> false
3642
 *     (1..10).member? 5   #=> true
3643
 *     (1..10).member? 15  #=> false
3644
 *
3645
 */
3646

  
3647
static VALUE
3648
arith_seq_member_p(VALUE self, VALUE element)
3649
{
3650
    VALUE b, s, offset, remainder;
3651

  
3652
    b = arith_seq_begin(self);
3653

  
3654
    if (!(CLASS_OF(b) == CLASS_OF(element))) {
3655
        return Qfalse;
3656
    }
3657

  
3658
    s = arith_seq_step(self);
3659

  
3660
    if ( (RB_FLOAT_TYPE_P(s) && FLOAT_ZERO_P(s)) ||
3661
         (RB_INTEGER_TYPE_P(s) && FIXNUM_ZERO_P(s))) {
3662
        if (element == b) return Qtrue;
3663
        return Qfalse;
3664
    }
3665

  
3666
    /* TODO: Handle floats */
3667

  
3668
    offset = rb_int_minus(element, b);
3669

  
3670
    /* Determine if the sequence will be going away from the element,
3671
     * e.g. if the sequence is 1.step then no non-positive numbers
3672
     * will be in the sequence. TODO: Also check the end of the range,
3673
     * if it exists.
3674
     */
3675

  
3676
    if (FIXNUM_POSITIVE_P(offset)) {
3677
        if (!FIXNUM_POSITIVE_P(s)) {
3678
            return Qfalse;
3679
        }
3680
    } else {
3681
        if (FIXNUM_POSITIVE_P(s)) {
3682
            return Qfalse;
3683
        }
3684
    }
3685

  
3686
    /* Test to see if the difference between the element between
3687
     * checked and the beginning of the sequence is divisible by the
3688
     * step of the sequence. If it is, then the element is included in
3689
     * the sequence. Otherwise, it's not.
3690
     */
3691

  
3692
    remainder = rb_int_modulo(offset, s);
3693

  
3694
    if (FIXNUM_ZERO_P(remainder)) {
3695
        return Qtrue;
3696
    }
3697
    else {
3698
        return Qfalse;
3699
    }
3700
}
3701

  
3702

  
3626 3703
/*
3627 3704
 * call-seq:
3628 3705
 *   aseq == obj  -> true or false
......
4100 4177
    rb_define_method(rb_cArithSeq, "hash", arith_seq_hash, 0);
4101 4178
    rb_define_method(rb_cArithSeq, "each", arith_seq_each, 0);
4102 4179
    rb_define_method(rb_cArithSeq, "size", arith_seq_size, 0);
4180
    rb_define_method(rb_cArithSeq, "member?", arith_seq_member_p, 1);
4181
    rb_define_method(rb_cArithSeq, "include?", arith_seq_member_p, 1);
4103 4182
    rb_provide("enumerator.so");	/* for backward compatibility */
4104 4183
}
test/ruby/test_arithmetic_sequence.rb
486 486
    assert_equal([1.0, 2.5, 4.0, 5.5, 7.0, 8.5, 10.0].sum, (1.0..10.0).step(1.5).sum)
487 487
    assert_equal([1/2r, 1r, 3/2r, 2, 5/2r, 3, 7/2r, 4].sum, ((1/2r)...(9/2r)).step(1/2r).sum)
488 488
  end
489

  
490
  def test_member_p
491
    assert_send([1.step, :member?, 10])
492
    assert_not_send([1.step(by: 2), :member?, 10])
493
    assert_send([1.step(by: 0), :member?, 1])
494
    assert_not_send([1.step(by: 0), :member?, 2])
495
    assert_send([1.step(by: -1), :member?, -5])
496
    assert_not_send([1.step(by: -1), :member?, 5])
497

  
498
    assert_send([(1..10).step, :member?, 6])
499
    assert_not_send([(1..10).step(2), :member?, 6])
500
    assert_not_send([(1..10).step, :member?, 11])
501
    assert_not_send([(-5..5).step, :member? -10])
502

  
503
    assert_send([1.5.step, :member?, 2.5])
504
    assert_not_send([1.5.step, :member?, 3])
505
  end
489 506
end
490
-