Feature #12080 » 0001-Enumerable-Array-Range-first-Array-Range-last-with-b.patch
array.c | ||
---|---|---|
/*
|
||
* call-seq:
|
||
* ary.first -> obj or nil
|
||
* ary.first(n) -> new_ary
|
||
* ary.first -> obj or nil
|
||
* ary.first { |obj| block } -> obj or nil
|
||
* ary.first(n) -> new_ary
|
||
* ary.first(n) { |obj| block } -> new_ary
|
||
*
|
||
* Returns the first element, or the first +n+ elements, of the array.
|
||
* If the array is empty, the first form returns +nil+, and the
|
||
* second form returns an empty array. See also Array#last for
|
||
* the opposite effect.
|
||
* second form returns an empty array.
|
||
* If a block is given, only elements which the given block returns a true
|
||
* value are counted.
|
||
*
|
||
* a = [ "q", "r", "s", "t" ]
|
||
* a.first #=> "q"
|
||
* a.first(2) #=> ["q", "r"]
|
||
* See also Array#last for the opposite effect.
|
||
*
|
||
* a = [ "q", "r", "s", "t", "aa" ]
|
||
* a.first #=> "q"
|
||
* a.first(2) #=> ["q", "r"]
|
||
* a.first { |i| i.size > 1 } #=> "aa"
|
||
*/
|
||
static VALUE
|
||
rb_ary_first(int argc, VALUE *argv, VALUE ary)
|
||
{
|
||
if (argc == 0) {
|
||
if (RARRAY_LEN(ary) == 0) return Qnil;
|
||
return RARRAY_AREF(ary, 0);
|
||
if (!rb_block_given_p()) {
|
||
if (argc == 0) {
|
||
if (RARRAY_LEN(ary) == 0) return Qnil;
|
||
return RARRAY_AREF(ary, 0);
|
||
}
|
||
else {
|
||
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST);
|
||
}
|
||
}
|
||
else {
|
||
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST);
|
||
long i;
|
||
if (argc == 0) {
|
||
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
||
if (RTEST(rb_yield(RARRAY_AREF(ary, i))))
|
||
return RARRAY_AREF(ary, i);
|
||
}
|
||
return Qnil;
|
||
}
|
||
else {
|
||
long take = NUM2LONG(argv[0]);
|
||
VALUE result = rb_ary_new();;
|
||
if (take < 0) rb_raise(rb_eArgError, "attempt to take negative size");
|
||
if (take == 0) return rb_ary_new2(0);
|
||
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
||
if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) {
|
||
rb_ary_push(result, RARRAY_AREF(ary, i));
|
||
if (!--take) break;
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
}
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* ary.last -> obj or nil
|
||
* ary.last(n) -> new_ary
|
||
* ary.last -> obj or nil
|
||
* ary.last { |obj| block } -> obj or nil
|
||
* ary.last(n) -> new_ary
|
||
* ary.last(n) { |obj| block } -> new_ary
|
||
*
|
||
* Returns the last element(s) of +self+. If the array is empty,
|
||
* the first form returns +nil+.
|
||
*
|
||
* See also Array#first for the opposite effect.
|
||
*
|
||
* a = [ "w", "x", "y", "z" ]
|
||
* a.last #=> "z"
|
||
* a.last(2) #=> ["y", "z"]
|
||
* a = [ "w", "x", "y", "z", "aa" ]
|
||
* a.last #=> "aa"
|
||
* a.last(2) #=> ["z", "aa"]
|
||
* a.last { |i| i.size == 1 } #=> "x"
|
||
*/
|
||
VALUE
|
||
rb_ary_last(int argc, const VALUE *argv, VALUE ary)
|
||
{
|
||
if (argc == 0) {
|
||
long len = RARRAY_LEN(ary);
|
||
if (len == 0) return Qnil;
|
||
return RARRAY_AREF(ary, len-1);
|
||
if (!rb_block_given_p()) {
|
||
if (argc == 0) {
|
||
long len = RARRAY_LEN(ary);
|
||
if (len == 0) return Qnil;
|
||
return RARRAY_AREF(ary, len-1);
|
||
}
|
||
else {
|
||
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST);
|
||
}
|
||
}
|
||
else {
|
||
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST);
|
||
long i;
|
||
if (argc == 0) {
|
||
for (i = RARRAY_LEN(ary); --i >= 0; ) {
|
||
if (RTEST(rb_yield(RARRAY_AREF(ary, i))))
|
||
return RARRAY_AREF(ary, i);
|
||
}
|
||
return Qnil;
|
||
}
|
||
else {
|
||
long take = NUM2LONG(argv[0]);
|
||
VALUE result = rb_ary_new();;
|
||
if (take < 0) rb_raise(rb_eArgError, "attempt to take negative size");
|
||
if (take == 0) return rb_ary_new2(0);
|
||
for (i = RARRAY_LEN(ary); --i >= 0; ) {
|
||
if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) {
|
||
rb_ary_push(result, RARRAY_AREF(ary, i));
|
||
if (!--take) break;
|
||
}
|
||
}
|
||
return rb_ary_reverse(result);
|
||
}
|
||
}
|
||
}
|
||
enum.c | ||
---|---|---|
UNREACHABLE;
|
||
}
|
||
static VALUE
|
||
take_find_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, params))
|
||
{
|
||
struct MEMO *memo = MEMO_CAST(params);
|
||
ENUM_WANT_SVALUE();
|
||
if (RTEST(rb_yield(i))) {
|
||
rb_ary_push(memo->v1, i);
|
||
if (!--memo->u3.cnt) rb_iter_break();
|
||
}
|
||
return Qnil;
|
||
}
|
||
static VALUE enum_take(VALUE obj, VALUE n);
|
||
/*
|
||
* call-seq:
|
||
* enum.first -> obj or nil
|
||
* enum.first(n) -> an_array
|
||
* enum.first -> obj or nil
|
||
* enum.first { |obj| block } -> obj or nil
|
||
* enum.first(n) -> an_array
|
||
* enum.first(n) { |obj| block } -> an_array
|
||
*
|
||
* Returns the first element, or the first +n+ elements, of the enumerable.
|
||
* If the enumerable is empty, the first form returns <code>nil</code>, and the
|
||
* second form returns an empty array.
|
||
* If a block is given, only elements which the given block returns a true
|
||
* value are counted.
|
||
*
|
||
* %w[foo bar baz].first #=> "foo"
|
||
* %w[foo bar baz].first(2) #=> ["foo", "bar"]
|
||
* %w[foo bar baz].first(10) #=> ["foo", "bar", "baz"]
|
||
* [].first #=> nil
|
||
* [].first(10) #=> []
|
||
* %w[foo bar baz].first #=> "foo"
|
||
* %w[foo bar baz].first(2) #=> ["foo", "bar"]
|
||
* %w[foo bar baz].first(10) #=> ["foo", "bar", "baz"]
|
||
* [].first #=> nil
|
||
* [].first(10) #=> []
|
||
* [1,2,3,4].first { |i| i.even? } #=> 2
|
||
* [1,2,2,2].first(2) { |i| i > 1 } #=> [2, 2]
|
||
*
|
||
*/
|
||
... | ... | |
enum_first(int argc, VALUE *argv, VALUE obj)
|
||
{
|
||
struct MEMO *memo;
|
||
long len;
|
||
rb_check_arity(argc, 0, 1);
|
||
if (argc > 0) {
|
||
return enum_take(obj, argv[0]);
|
||
if (!rb_block_given_p()) return enum_take(obj, argv[0]);
|
||
len = NUM2LONG(argv[0]);
|
||
if (len < 0) rb_raise(rb_eArgError, "attempt to take negative size");
|
||
if (len == 0) return rb_ary_new2(0);
|
||
memo = MEMO_NEW(rb_ary_new(), 0, len);
|
||
rb_block_call(obj, id_each, 0, 0, take_find_i, (VALUE)memo);
|
||
return memo->v1;
|
||
}
|
||
else {
|
||
memo = MEMO_NEW(Qnil, 0, 0);
|
||
rb_block_call(obj, id_each, 0, 0, first_i, (VALUE)memo);
|
||
rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? find_i : first_i, (VALUE)memo);
|
||
return memo->v1;
|
||
}
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* enum.sort -> array
|
gc.c | ||
---|---|---|
rb_gc_register_mark_object(VALUE obj)
|
||
{
|
||
VALUE ary_ary = GET_THREAD()->vm->mark_object_ary;
|
||
VALUE ary = rb_ary_last(0, 0, ary_ary);
|
||
VALUE ary = Qnil;
|
||
if (RARRAY_LEN(ary_ary))
|
||
ary = RARRAY_AREF(ary_ary, RARRAY_LEN(ary_ary) - 1);
|
||
if (ary == Qnil || RARRAY_LEN(ary) >= MARK_OBJECT_ARY_BUCKET_SIZE) {
|
||
ary = rb_ary_tmp_new(MARK_OBJECT_ARY_BUCKET_SIZE);
|
range.c | ||
---|---|---|
{
|
||
VALUE n, ary[2];
|
||
if (rb_block_given_p()) return rb_call_super(argc, argv);
|
||
if (argc == 0) return RANGE_BEG(range);
|
||
rb_scan_args(argc, argv, "1", &n);
|
||
... | ... | |
static VALUE
|
||
range_last(int argc, VALUE *argv, VALUE range)
|
||
{
|
||
if (argc == 0) return RANGE_END(range);
|
||
return rb_ary_last(argc, argv, rb_Array(range));
|
||
if (argc > 0 || rb_block_given_p()) {
|
||
return rb_ary_last(argc, argv, rb_Array(range));
|
||
}
|
||
else {
|
||
return RANGE_END(range);
|
||
}
|
||
}
|
||
test/ruby/test_array.rb | ||
---|---|---|
def test_first
|
||
assert_equal(3, @cls[3, 4, 5].first)
|
||
assert_equal(nil, @cls[].first)
|
||
assert_equal(2, @cls[1, 2, 3, 4].first { |i| i.even? })
|
||
assert_equal(nil, @cls[1, 2, 3, 4].first { |i| i > 100 })
|
||
end
|
||
def test_flatten
|
||
... | ... | |
assert_equal(nil, @cls[].last)
|
||
assert_equal(1, @cls[1].last)
|
||
assert_equal(99, @cls[*(3..99).to_a].last)
|
||
assert_equal(3, @cls[1, 2, 3, 4].last { |i| i.odd? })
|
||
assert_equal(nil, @cls[1, 2, 3, 4].last { |i| i > 100 })
|
||
end
|
||
def test_length
|
||
... | ... | |
def test_first2
|
||
assert_equal([0], [0].first(2))
|
||
assert_raise(ArgumentError) { [0].first(-1) }
|
||
assert_equal([2, 4], @cls[1, 2, 4, 6].first(2) { |i| i.even? })
|
||
assert_equal([2, 4, 6], @cls[2, 4, 5, 6].first(10) { |i| i.even? })
|
||
assert_raise(ArgumentError) { @cls[1, 2].first(-1) { |i| i.even? } }
|
||
end
|
||
def test_last2
|
||
assert_equal([0], [0].last(2))
|
||
assert_raise(ArgumentError) { [0].last(-1) }
|
||
assert_equal([4, 6], @cls[2, 4, 5, 6].last(2) { |i| i.even? })
|
||
assert_equal([2, 4, 6], @cls[2, 4, 5, 6].last(10) { |i| i.even? })
|
||
assert_raise(ArgumentError) { @cls[1, 2].last(-1) { |i| i.even? } }
|
||
end
|
||
def test_shift2
|
test/ruby/test_enum.rb | ||
---|---|---|
assert_equal([1, 2, 3], @obj.first(3))
|
||
assert_nil(@empty.first)
|
||
assert_equal([], @empty.first(10))
|
||
assert_equal(2, @obj.first { |i| i.even? })
|
||
assert_equal([3], @obj.first(2) { |i| i > 2 })
|
||
bug5801 = '[ruby-dev:45041]'
|
||
assert_in_out_err([], <<-'end;', [], /unexpected break/)
|
test/ruby/test_range.rb | ||
---|---|---|
assert_equal("a", ("a".."c").first)
|
||
assert_equal("c", ("a".."c").last)
|
||
assert_equal(0, (2..0).last)
|
||
assert_equal(1, (0..11).first { |i| i.odd? })
|
||
assert_equal(11, (0..11).last { |i| i.odd? })
|
||
assert_equal([1, 3], (0..11).first(2) { |i| i.odd? })
|
||
assert_equal([9, 11], (0..11).last(2) { |i| i.odd? })
|
||
assert_equal([0, 1, 2], (0...10).first(3))
|
||
assert_equal([7, 8, 9], (0...10).last(3))
|
||
... | ... | |
assert_equal("a", ("a"..."c").first)
|
||
assert_equal("c", ("a"..."c").last)
|
||
assert_equal(0, (2...0).last)
|
||
assert_equal(1, (0...11).first { |i| i.odd? })
|
||
assert_equal(9, (0...11).last { |i| i.odd? })
|
||
assert_equal([1, 3], (0...11).first(2) { |i| i.odd? })
|
||
assert_equal([7, 9], (0...11).last(2) { |i| i.odd? })
|
||
end
|
||
def test_to_s
|