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

ruby-changes:51990

From: mrkn <ko1@a...>
Date: Mon, 6 Aug 2018 18:08:34 +0900 (JST)
Subject: [ruby-changes:51990] mrkn:r64205 (trunk): enumerator.c: Introduce Enumerator::ArithmeticSequence

mrkn	2018-08-06 18:08:28 +0900 (Mon, 06 Aug 2018)

  New Revision: 64205

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

  Log:
    enumerator.c: Introduce Enumerator::ArithmeticSequence
    
    This commit introduces new core class Enumerator::ArithmeticSequence.
    Enumerator::ArithmeticSequence is a subclass of Enumerator, and
    represents a number generator of an arithmetic sequence.
    
    After this commit, Numeric#step and Range#step without blocks
    returned an ArithmeticSequence object instead of an Enumerator.
    
    This class introduces the following incompatibilities:
    
    - You can create a zero-step ArithmeticSequence,
      and its size is not ArgumentError, but Infinity.
    - You can create a negative-step ArithmeticSequence from a range.
    
    [ruby-core:82816] [Feature #13904]

  Added files:
    trunk/test/ruby/test_arithmetic_sequence.rb
  Modified files:
    trunk/enumerator.c
    trunk/internal.h
    trunk/numeric.c
    trunk/range.c
    trunk/spec/ruby/core/numeric/shared/step.rb
    trunk/spec/ruby/core/numeric/step_spec.rb
    trunk/spec/ruby/core/range/step_spec.rb
    trunk/test/ruby/test_enumerator.rb
    trunk/test/ruby/test_numeric.rb
    trunk/test/ruby/test_range.rb
Index: test/ruby/test_arithmetic_sequence.rb
===================================================================
--- test/ruby/test_arithmetic_sequence.rb	(nonexistent)
+++ test/ruby/test_arithmetic_sequence.rb	(revision 64205)
@@ -0,0 +1,367 @@ https://github.com/ruby/ruby/blob/trunk/test/ruby/test_arithmetic_sequence.rb#L1
+# frozen_string_literal: false
+require 'test/unit'
+
+class TestArithmeticSequence < Test::Unit::TestCase
+  def test_begin
+    assert_equal(1, 1.step.begin)
+    assert_equal(1, 1.step(10).begin)
+    assert_equal(1, 1.step(to: 10).begin)
+    assert_equal(1, 1.step(nil).begin)
+    assert_equal(1, 1.step(to: nil).begin)
+    assert_equal(1, 1.step(by: 2).begin)
+    assert_equal(1, 1.step(by: -1).begin)
+    assert_equal(1, 1.step(by: nil).begin)
+    assert_equal(1, 1.step(10, 2).begin)
+    assert_equal(1, 1.step(10, by: 2).begin)
+    assert_equal(1, 1.step(to: 10, by: 2).begin)
+    assert_equal(10, 10.step(to: 1, by: -1).begin)
+    assert_equal(10, 10.step(to: 1, by: -2).begin)
+    assert_equal(10, 10.step(to: -1, by: -2).begin)
+    assert_equal(10.0, 10.0.step(to: -1.0, by: -2.0).begin)
+  end
+
+  def test_end
+    assert_equal(nil, 1.step.end)
+    assert_equal(10, 1.step(10).end)
+    assert_equal(10, 1.step(to: 10).end)
+    assert_equal(nil, 1.step(nil).end)
+    assert_equal(nil, 1.step(to: nil).end)
+    assert_equal(nil, 1.step(by: 2).end)
+    assert_equal(nil, 1.step(by: -1).end)
+    assert_equal(nil, 1.step(by: nil).end)
+    assert_equal(10, 1.step(10, 2).end)
+    assert_equal(10, 1.step(10, by: 2).end)
+    assert_equal(10, 1.step(to: 10, by: 2).end)
+    assert_equal(1, 10.step(to: 1, by: -1).end)
+    assert_equal(1, 10.step(to: 1, by: -2).end)
+    assert_equal(-1, 10.step(to: -1, by: -2).end)
+    assert_equal(-1.0, 10.0.step(to: -1.0, by: -2.0).end)
+  end
+
+  def test_exclude_end_p
+    assert_equal(false, 1.step.exclude_end?)
+    assert_equal(false, 1.step(10).exclude_end?)
+    assert_equal(false, 1.step(to: 10).exclude_end?)
+    assert_equal(false, 1.step(nil).exclude_end?)
+    assert_equal(false, 1.step(to: nil).exclude_end?)
+    assert_equal(false, 1.step(by: 2).exclude_end?)
+    assert_equal(false, 1.step(by: -1).exclude_end?)
+    assert_equal(false, 1.step(by: nil).exclude_end?)
+    assert_equal(false, 1.step(10, 2).exclude_end?)
+    assert_equal(false, 1.step(10, by: 2).exclude_end?)
+    assert_equal(false, 1.step(to: 10, by: 2).exclude_end?)
+    assert_equal(false, 10.step(to: 1, by: -1).exclude_end?)
+    assert_equal(false, 10.step(to: 1, by: -2).exclude_end?)
+    assert_equal(false, 10.step(to: -1, by: -2).exclude_end?)
+  end
+
+  def test_step
+    assert_equal(1, 1.step.step)
+    assert_equal(1, 1.step(10).step)
+    assert_equal(1, 1.step(to: 10).step)
+    assert_equal(1, 1.step(nil).step)
+    assert_equal(1, 1.step(to: nil).step)
+    assert_equal(2, 1.step(by: 2).step)
+    assert_equal(-1, 1.step(by: -1).step)
+    assert_equal(1, 1.step(by: nil).step)
+    assert_equal(2, 1.step(10, 2).step)
+    assert_equal(2, 1.step(10, by: 2).step)
+    assert_equal(2, 1.step(to: 10, by: 2).step)
+    assert_equal(-1, 10.step(to: 1, by: -1).step)
+    assert_equal(-2, 10.step(to: 1, by: -2).step)
+    assert_equal(-2, 10.step(to: -1, by: -2).step)
+    assert_equal(-2.0, 10.0.step(to: -1.0, by: -2.0).step)
+  end
+
+  def test_eq
+    seq = 1.step
+    assert_equal(seq, seq)
+    assert_equal(seq, 1.step)
+    assert_equal(seq, 1.step(nil))
+  end
+
+  def test_eqq
+    seq = 1.step
+    assert_operator(seq, :===, seq)
+    assert_operator(seq, :===, 1.step)
+    assert_operator(seq, :===, 1.step(nil))
+  end
+
+  def test_eql_p
+    seq = 1.step
+    assert_operator(seq, :eql?, seq)
+    assert_operator(seq, :eql?, 1.step)
+    assert_operator(seq, :eql?, 1.step(nil))
+  end
+
+  def test_hash
+    seq = 1.step
+    assert_equal(seq.hash, seq.hash)
+    assert_equal(seq.hash, 1.step.hash)
+    assert_equal(seq.hash, 1.step(nil).hash)
+  end
+
+  def test_first
+    seq = 1.step
+    assert_equal(1, seq.first)
+    assert_equal([1], seq.first(1))
+    assert_equal([1, 2, 3], seq.first(3))
+
+    seq = 1.step(by: 2)
+    assert_equal(1, seq.first)
+    assert_equal([1], seq.first(1))
+    assert_equal([1, 3, 5], seq.first(3))
+
+    seq = 10.step(by: -2)
+    assert_equal(10, seq.first)
+    assert_equal([10], seq.first(1))
+    assert_equal([10, 8, 6], seq.first(3))
+
+    seq = 1.step(by: 4)
+    assert_equal([1, 5, 9], seq.first(3))
+
+    seq = 1.step(10, by: 4)
+    assert_equal([1, 5, 9], seq.first(5))
+
+    seq = 1.step(0)
+    assert_equal(nil, seq.first)
+    assert_equal([], seq.first(1))
+    assert_equal([], seq.first(3))
+
+    seq = 1.step(10, by: -1)
+    assert_equal(nil, seq.first)
+    assert_equal([], seq.first(1))
+    assert_equal([], seq.first(3))
+
+    seq = 10.0.step(-1.0, by: -2.0)
+    assert_equal(10.0, seq.first)
+    assert_equal([10.0], seq.first(1))
+    assert_equal([10.0, 8.0, 6.0], seq.first(3))
+  end
+
+  def test_last
+    seq = 1.step(10)
+    assert_equal(10, seq.last)
+    assert_equal([10], seq.last(1))
+    assert_equal([8, 9, 10], seq.last(3))
+
+    seq = 1.step(10, 2)
+    assert_equal(9, seq.last)
+    assert_equal([9], seq.last(1))
+    assert_equal([5, 7, 9], seq.last(3))
+
+    seq = 10.step(1, -2)
+    assert_equal(2, seq.last)
+    assert_equal([2], seq.last(1))
+    assert_equal([6, 4, 2], seq.last(3))
+
+    seq = 10.step(-1, -2)
+    assert_equal(0, seq.last)
+
+    seq = 1.step(10, 4)
+    assert_equal([1, 5, 9], seq.last(5))
+
+    seq = 10.step(1)
+    assert_equal(nil, seq.last)
+    assert_equal([], seq.last(1))
+    assert_equal([], seq.last(5))
+
+    seq = 1.step(10, -1)
+    assert_equal(nil, seq.last)
+    assert_equal([], seq.last(1))
+    assert_equal([], seq.last(5))
+
+    seq = (1..10).step
+    assert_equal(10, seq.last)
+    assert_equal([10], seq.last(1))
+    assert_equal([8, 9, 10], seq.last(3))
+
+    seq = (1...10).step
+    assert_equal(9, seq.last)
+    assert_equal([9], seq.last(1))
+    assert_equal([7, 8, 9], seq.last(3))
+
+    seq = 10.0.step(-3.0, by: -2.0)
+    assert_equal(-2.0, seq.last)
+    assert_equal([-2.0], seq.last(1))
+    assert_equal([2.0, 0.0, -2.0], seq.last(3))
+  end
+
+  def test_to_a
+    assert_equal([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 1.step(10).to_a)
+    assert_equal([1, 3, 5, 7, 9], 1.step(10, 2).to_a)
+    assert_equal([1, 3, 5, 7, 9], (1..10).step(2).to_a)
+    assert_equal([10, 8, 6, 4, 2], 10.step(1, by: -2).to_a)
+    assert_equal([10, 8, 6, 4, 2], (10..1).step(-2).to_a)
+    assert_equal([10.0, 8.0, 6.0, 4.0, 2.0], (10.0..1.0).step(-2.0).to_a)
+  end
+
+  def test_slice
+    seq = 1.step(10, 2)
+    assert_equal([[1, 3, 5], [7, 9]], seq.each_slice(3).to_a)
+
+    seq = 10.step(1, -2)
+    assert_equal([[10, 8, 6], [4, 2]], seq.each_slice(3).to_a)
+  end
+
+  def test_cons
+    seq = 1.step(10, 2)
+    assert_equal([[1, 3, 5], [3, 5, 7], [5, 7, 9]], seq.each_cons(3).to_a)
+
+    seq = 10.step(1, -2)
+    assert_equal([[10, 8, 6], [8, 6, 4], [6, 4, 2]], seq.each_cons(3).to_a)
+  end
+
+  def test_with_index
+    seq = 1.step(6, 2)
+    assert_equal([[1, 0], [3, 1], [5, 2]], seq.with_index.to_a)
+    assert_equal([[1, 10], [3, 11], [5, 12]], seq.with_index(10).to_a)
+
+    seq = 10.step(5, -2)
+    assert_equal([[10, 0], [8, 1], [6, 2]], seq.with_index.to_a)
+    assert_equal([[10, 10], [8, 11], [6, 12]], seq.with_index(10).to_a)
+  end
+
+  def test_with_object
+    obj = [0, 1]
+    seq = 1.step(10, 2)
+    ret = seq.each_with_object(obj) do |i, memo|
+      memo[0] += i
+      memo[1] *= i
+    end
+    assert_same(obj, ret)
+    assert_equal([25, 945], ret)
+
+    obj = [0, 1]
+    seq = 10.step(1, -2)
+    ret = seq.each_with_object(obj) do |i, memo|
+      memo[0] += i
+      memo[1] *= i
+    end
+    assert_same(obj, ret)
+    assert_equal([30, 3840], ret)
+  end
+
+  def test_next
+    seq = 1.step(10, 2)
+    [1, 3, 5, 7, 9].each do |i|
+      assert_equal(i, seq.next)
+    end
+
+    seq = 10.step(1, -2)
+    [10, 8, 6, 4, 2].each do |i|
+      assert_equal(i, seq.next)
+    end
+  end
+
+  def test_next_rewind
+    seq = 1.step(6, 2)
+    assert_equal(1, seq.next)
+    assert_equal(3, seq.next)
+    seq.rewind
+    assert_equal(1, seq.next)
+    assert_equal(3, seq.next)
+    assert_equal(5, seq.next)
+    assert_raise(StopIteration) { seq.next }
+
+    seq = 10.step(5, -2)
+    assert_equal(10, seq.next)
+    assert_equal(8, seq.next)
+    seq.rewind
+    assert_equal(10, seq.next)
+    assert_equal(8, seq.next)
+    assert_equal(6, seq.next)
+    assert_raise(StopIteration) { seq.next }
+  end
+
+  def test_next_after_stopiteration
+    seq = 1.step(2, 2)
+    assert_equal(1, seq.next)
+    assert_raise(StopIteration) { seq.next }
+    assert_raise(StopIteration) { seq.next }
+    seq.rewind
+    assert_equal(1, seq.next)
+    assert_raise(StopIteration) { seq.next }
+    assert_raise(StopIteration) { seq.next }
+  end
+
+  def test_stop_result
+    seq = 1.step(2, 2)
+    res = seq.each {}
+    assert_equal(1, seq.next)
+    exc = assert_raise(StopIteration) { seq.next }
+    assert_equal(res, exc.result)
+  end
+
+  def test_peek
+    seq = 1.step(2, 2)
+    assert_equal(1, seq.peek)
+    assert_equal(1, seq.peek)
+    assert_equal(1, seq.next)
+    assert_raise(StopIteration) { seq.peek }
+    assert_raise(StopIteration) { seq.peek }
+
+    seq = 10.step(9, -2)
+    assert_equal(10, seq.peek)
+    assert_equal(10, seq.peek)
+    assert_equal(10, seq.next)
+    assert_raise(StopIteration) { seq.peek }
+    assert_raise(StopIteration) { seq.peek }
+  end
+
+  def test_next_values
+    seq = 1.step(2, 2)
+    assert_equal([1], seq.next_values)
+  end
+
+  def test_peek_values
+    seq = 1.step(2, 2)
+    assert_equal([1], seq.peek_values)
+  end
+
+  def test_num_step_inspect
+    assert_equal('(1.step)', 1.step.inspect)
+    assert_equal('(1.step(10))', 1.step(10).inspect)
+    assert_equal('(1.step(10, 2))', 1.step(10, 2).inspect)
+    assert_equal('(1.step(10, by: 2))', 1.step(10, by: 2).inspect)
+    assert_equal('(1.step(by: 2))', 1.step(by: 2).inspect)
+  end
+
+  def test_range_step_inspect
+    assert_equal('((1..).step)', (1..).step.inspect)
+    assert_equal('((1..10).step)', (1..10).step.inspect)
+    assert_equal('((1..10).step(2))', (1..10).step(2).inspect)
+  end
+
+  def test_num_step_size
+    assert_equal(10, 1.step(10).size)
+    assert_equal(5, 1.step(10, 2).size)
+    assert_equal(4, 1.step(10, 3).size)
+    assert_equal(1, 1.step(10, 10).size)
+    assert_equal(0, 1.step(0).size)
+    assert_equal(Float::INFINITY, 1.step.size)
+
+    assert_equal(10, 10.step(1, -1).size)
+    assert_equal(5, 10.step(1, -2).size)
+    assert_equal(4, 10.step(1, -3).size)
+    assert_equal(1, 10.step(1, -10).size)
+    assert_equal(0, 1.step(2, -1).size)
+    assert_equal(Float::INFINITY, 1.step(by: -1).size)
+  end
+
+  def test_range_step_size
+    assert_equal(10, (1..10).step.size)
+    assert_equal(9, (1...10).step.size)
+    assert_equal(5, (1..10).step(2).size)
+    assert_equal(5, (1...10).step(2).size)
+    assert_equal(4, (1...9).step(2).size)
+    assert_equal(Float::INFINITY, (1..).step.size)
+
+    assert_equal(10, (10..1).step(-1).size)
+    assert_equal(9, (10...1).step(-1).size)
+    assert_equal(5, (10..1).step(-2).size)
+    assert_equal(5, (10...1).step(-2).size)
+    assert_equal(4, (10...2).step(-2).size)
+    assert_equal(Float::INFINITY, (1..).step(-1).size)
+  end
+end
Index: test/ruby/test_enumerator.rb
===================================================================
--- test/ruby/test_enumerator.rb	(revision 64204)
+++ test/ruby/test_enumerator.rb	(revision 64205)
@@ -632,7 +632,7 @@ class TestEnumerator < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/test/ruby/test_enumerator.rb#L632
     assert_equal 4, (1..10).step(3).size
     assert_equal 3, (1...10).step(3).size
     assert_equal Float::INFINITY, (42..Float::INFINITY).step(2).size
-    assert_raise(ArgumentError){ (1..10).step(-2).size }
+    assert_equal 0, (1..10).step(-2).size
   end
 
   def test_size_for_downup_to
Index: test/ruby/test_range.rb
===================================================================
--- test/ruby/test_range.rb	(revision 64204)
+++ test/ruby/test_range.rb	(revision 64205)
@@ -222,7 +222,11 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L222
     (0..).step(2) {|x| a << x; break if a.size == 10 }
     assert_equal([0, 2, 4, 6, 8, 10, 12, 14, 16, 18], a)
 
-    assert_raise(ArgumentError) { (0..10).step(-1) { } }
+    assert_kind_of(Enumerator::ArithmeticSequence, (0..10).step)
+    assert_kind_of(Enumerator::ArithmeticSequence, (0..10).step(2))
+    assert_kind_of(Enumerator::ArithmeticSequence, (0..10).step(0.5))
+    assert_kind_of(Enumerator::ArithmeticSequence, (10..0).step(-1))
+
     assert_raise(ArgumentError) { (0..10).step(0) { } }
     assert_raise(ArgumentError) { (0..).step(-1) { } }
     assert_raise(ArgumentError) { (0..).step(0) { } }
Index: test/ruby/test_numeric.rb
===================================================================
--- test/ruby/test_numeric.rb	(revision 64204)
+++ test/ruby/test_numeric.rb	(revision 64205)
@@ -260,11 +260,11 @@ class TestNumeric < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_numeric.rb#L260
     assert_raise(ArgumentError) { 1.step(10, 1, 0) { } }
     assert_raise(ArgumentError) { 1.step(10, 1, 0).size }
     assert_raise(ArgumentError) { 1.step(10, 0) { } }
-    assert_raise(ArgumentError) { 1.step(10, 0).size }
     assert_raise(ArgumentError) { 1.step(10, "1") { } }
     assert_raise(ArgumentError) { 1.step(10, "1").size }
     assert_raise(TypeError) { 1.step(10, nil) { } }
-    assert_raise(TypeError) { 1.step(10, nil).size }
+    assert_nothing_raised { 1.step(10, 0).size }
+    assert_nothing_raised { 1.step(10, nil).size }
     assert_nothing_raised { 1.step(by: 0, to: nil) }
     assert_nothing_raised { 1.step(by: 0, to: nil).size }
     assert_nothing_raised { 1.step(by: 0) }
@@ -272,6 +272,14 @@ class TestNumeric < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_numeric.rb#L272
     assert_nothing_raised { 1.step(by: nil) }
     assert_nothing_raised { 1.step(by: nil).size }
 
+    assert_kind_of(Enumerator::ArithmeticSequence, 1.step(10))
+    assert_kind_of(Enumerator::ArithmeticSequence, 1.step(10, 2))
+    assert_kind_of(Enumerator::ArithmeticSequence, 1.step(10, by: 2))
+    assert_kind_of(Enumerator::ArithmeticSequence, 1.step(by: 2))
+    assert_kind_of(Enumerator::ArithmeticSequence, 1.step(by: 2, to: nil))
+    assert_kind_of(Enumerator::ArithmeticSequence, 1.step(by: 2, to: 10))
+    assert_kind_of(Enumerator::ArithmeticSequence, 1.step(by: -1))
+
     bug9811 = '[ruby-dev:48177] [Bug #9811]'
     assert_raise(ArgumentError, bug9811) { 1.step(10, foo: nil) {} }
     assert_raise(ArgumentError, bug9811) { 1.step(10, foo: nil).size }
Index: enumerator.c
===================================================================
--- enumerator.c	(revision 64204)
+++ enumerator.c	(revision 64205)
@@ -15,6 +15,10 @@ https://github.com/ruby/ruby/blob/trunk/enumerator.c#L15
 #include "internal.h"
 #include "id.h"
 
+#ifdef HAVE_FLOAT_H
+#include <float.h>
+#endif
+
 /*
  * Document-class: Enumerator
  *
@@ -105,6 +109,7 @@ VALUE rb_cEnumerator; https://github.com/ruby/ruby/blob/trunk/enumerator.c#L109
 static VALUE rb_cLazy;
 static ID id_rewind, id_new, id_yield, id_to_enum;
 static ID id_next, id_result, id_lazy, id_receiver, id_arguments, id_memo, id_method, id_force;
+static ID id_begin, id_end, id_step, id_exclude_end;
 static VALUE sym_each, sym_cycle;
 
 #define id_call idCall
@@ -156,6 +161,8 @@ struct proc_entry { https://github.com/ruby/ruby/blob/trunk/enumerator.c#L161
 static VALUE generator_allocate(VALUE klass);
 static VALUE generator_init(VALUE obj, VALUE proc);
 
+static VALUE rb_cArithSeq;
+
 /*
  * Enumerator
  */
@@ -2375,6 +2382,391 @@ stop_result(VALUE self) https://github.com/ruby/ruby/blob/trunk/enumerator.c#L2382
     return rb_attr_get(self, id_result);
 }
 
+VALUE
+rb_arith_seq_new(VALUE obj, VALUE meth, int argc, VALUE const *argv,
+                 rb_enumerator_size_func *size_fn,
+                 VALUE beg, VALUE end, VALUE step, int excl)
+{
+    VALUE aseq = enumerator_init(enumerator_allocate(rb_cArithSeq),
+                                 obj, meth, argc, argv, size_fn, Qnil);
+    rb_ivar_set(aseq, id_begin, beg);
+    rb_ivar_set(aseq, id_end, end);
+    rb_ivar_set(aseq, id_step, step);
+    rb_ivar_set(aseq, id_exclude_end, excl ? Qtrue : Qfalse);
+    return aseq;
+}
+
+static inline VALUE
+arith_seq_begin(VALUE self)
+{
+    return rb_ivar_get(self, id_begin);
+}
+
+static inline VALUE
+arith_seq_end(VALUE self)
+{
+    return rb_ivar_get(self, id_end);
+}
+
+static inline VALUE
+arith_seq_step(VALUE self)
+{
+    return rb_ivar_get(self, id_step);
+}
+
+static inline VALUE
+arith_seq_exclude_end(VALUE self)
+{
+    return rb_ivar_get(self, id_exclude_end);
+}
+
+static inline int
+arith_seq_exclude_end_p(VALUE self)
+{
+    return RTEST(arith_seq_exclude_end(self));
+}
+
+static VALUE
+arith_seq_first(int argc, VALUE *argv, VALUE self)
+{
+    VALUE b, e, s, len_1;
+
+    b = arith_seq_begin(self);
+    e = arith_seq_end(self);
+    s = arith_seq_step(self);
+
+    if (!NIL_P(e)) {
+        len_1 = rb_int_idiv(rb_int_minus(e, b), s);
+        if (rb_num_negative_int_p(len_1)) {
+            if (argc == 0) {
+                return Qnil;
+            }
+            return rb_ary_new_capa(0);
+        }
+    }
+
+    if (argc == 0) {
+        return b;
+    }
+
+    /* TODO: optimization */
+
+    return rb_call_super(argc, argv);
+}
+
+static VALUE
+arith_seq_last(int argc, VALUE *argv, VALUE self)
+{
+    VALUE b, e, s, len_1, len, last, nv, ary;
+    int last_is_adjusted;
+    long n;
+
+    e = arith_seq_end(self);
+    if (NIL_P(e)) {
+        rb_raise(rb_eRangeError,
+                 "cannot get the last element of endless arithmetic sequence");
+    }
+
+    b = arith_seq_begin(self);
+    s = arith_seq_step(self);
+
+    len_1 = rb_int_idiv(rb_int_minus(e, b), s);
+    if (rb_num_negative_int_p(len_1)) {
+        if (argc == 0) {
+            return Qnil;
+        }
+        return rb_ary_new_capa(0);
+    }
+
+    last = rb_int_plus(b, rb_int_mul(s, len_1));
+    if ((last_is_adjusted = arith_seq_exclude_end_p(self) && rb_equal(last, e))) {
+        last = rb_int_minus(last, s);
+    }
+
+    if (argc == 0) {
+        return last;
+    }
+
+    if (last_is_adjusted) {
+        len = len_1;
+    }
+    else {
+        len = rb_int_plus(len_1, INT2FIX(1));
+    }
+
+    rb_scan_args(argc, argv, "1", &nv);
+    if (RTEST(rb_int_gt(nv, len))) {
+        nv = len;
+    }
+    n = NUM2LONG(nv);
+    if (n < 0) {
+        rb_raise(rb_eArgError, "negative array size");
+    }
+
+    ary = rb_ary_new_capa(n);
+    b = rb_int_minus(last, rb_int_mul(s, nv));
+    while (n) {
+        b = rb_int_plus(b, s);
+        rb_ary_push(ary, b);
+        --n;
+    }
+
+    return ary;
+}
+
+static VALUE
+arith_seq_inspect(VALUE self)
+{
+    struct enumerator *e;
+    VALUE eobj, str, eargs;
+    int range_p;
+
+    TypedData_Get_Struct(self, struct enumerator, &enumerator_data_type, e);
+
+    eobj = rb_attr_get(self, id_receiver);
+    if (NIL_P(eobj)) {
+        eobj = e->obj;
+    }
+
+    range_p = RTEST(rb_obj_is_kind_of(eobj, rb_cRange));
+    str = rb_sprintf("(%s%"PRIsVALUE"%s.", range_p ? "(" : "", eobj, range_p ? ")" : "");
+
+    rb_str_buf_append(str, rb_id2str(e->meth));
+
+    eargs = rb_attr_get(eobj, id_arguments);
+    if (NIL_P(eargs)) {
+        eargs = e->args;
+    }
+    if (eargs != Qfalse) {
+        long argc = RARRAY_LEN(eargs);
+        const VALUE *argv = RARRAY_CONST_PTR(eargs); /* WB: no new reference */
+
+        if (argc > 0) {
+            VALUE kw (... truncated)

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

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