Feature #12080 ยป v2-0001-Enumerable-Array-Range-first-Array-Range-last-wit.patch
array.c | ||
---|---|---|
1310 | 1310 | |
1311 | 1311 |
/* |
1312 | 1312 |
* call-seq: |
1313 |
* ary.first -> obj or nil |
|
1314 |
* ary.first(n) -> new_ary |
|
1313 |
* ary.first -> obj or nil |
|
1314 |
* ary.first { |obj| block } -> obj or nil |
|
1315 |
* ary.first(n) -> new_ary |
|
1316 |
* ary.first(n) { |obj| block } -> new_ary |
|
1315 | 1317 |
* |
1316 | 1318 |
* Returns the first element, or the first +n+ elements, of the array. |
1317 |
* If the array is empty, the first form returns +nil+, and the |
|
1318 |
* second form returns an empty array. See also Array#last for |
|
1319 |
* the opposite effect. |
|
1319 |
* If the array is empty, the first form returns +nil+, and the second form |
|
1320 |
* returns an empty array. |
|
1321 |
* If a block is given, only elements for which the given block returns a true |
|
1322 |
* value are counted. |
|
1323 |
* |
|
1324 |
* See also Array#last for the opposite effect. |
|
1320 | 1325 |
* |
1321 |
* a = [ "q", "r", "s", "t" ] |
|
1322 |
* a.first #=> "q" |
|
1323 |
* a.first(2) #=> ["q", "r"] |
|
1326 |
* a = [ "q", "r", "s", "t", "aa" ] |
|
1327 |
* a.first #=> "q" |
|
1328 |
* a.first(2) #=> ["q", "r"] |
|
1329 |
* a.first { |i| i.size > 1 } #=> "aa" |
|
1324 | 1330 |
*/ |
1325 | 1331 | |
1326 | 1332 |
static VALUE |
1327 | 1333 |
rb_ary_first(int argc, VALUE *argv, VALUE ary) |
1328 | 1334 |
{ |
1329 |
if (argc == 0) { |
|
1330 |
if (RARRAY_LEN(ary) == 0) return Qnil; |
|
1331 |
return RARRAY_AREF(ary, 0); |
|
1335 |
if (!rb_block_given_p()) { |
|
1336 |
if (argc == 0) { |
|
1337 |
if (RARRAY_LEN(ary) == 0) return Qnil; |
|
1338 |
return RARRAY_AREF(ary, 0); |
|
1339 |
} |
|
1340 |
else { |
|
1341 |
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST); |
|
1342 |
} |
|
1332 | 1343 |
} |
1333 | 1344 |
else { |
1334 |
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST); |
|
1345 |
long i; |
|
1346 |
if (argc == 0) { |
|
1347 |
for (i = 0; i < RARRAY_LEN(ary); i++) { |
|
1348 |
if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) |
|
1349 |
return RARRAY_AREF(ary, i); |
|
1350 |
} |
|
1351 |
return Qnil; |
|
1352 |
} |
|
1353 |
else { |
|
1354 |
long take = NUM2LONG(argv[0]); |
|
1355 |
VALUE result = rb_ary_new();; |
|
1356 |
if (take < 0) rb_raise(rb_eArgError, "attempt to take negative size"); |
|
1357 |
if (take == 0) return rb_ary_new2(0); |
|
1358 |
for (i = 0; i < RARRAY_LEN(ary); i++) { |
|
1359 |
if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) { |
|
1360 |
rb_ary_push(result, RARRAY_AREF(ary, i)); |
|
1361 |
if (!--take) break; |
|
1362 |
} |
|
1363 |
} |
|
1364 |
return result; |
|
1365 |
} |
|
1335 | 1366 |
} |
1336 | 1367 |
} |
1337 | 1368 | |
1338 | 1369 |
/* |
1339 | 1370 |
* call-seq: |
1340 |
* ary.last -> obj or nil |
|
1341 |
* ary.last(n) -> new_ary |
|
1371 |
* ary.last -> obj or nil |
|
1372 |
* ary.last { |obj| block } -> obj or nil |
|
1373 |
* ary.last(n) -> new_ary |
|
1374 |
* ary.last(n) { |obj| block } -> new_ary |
|
1342 | 1375 |
* |
1343 |
* Returns the last element(s) of +self+. If the array is empty, |
|
1344 |
* the first form returns +nil+. |
|
1376 |
* Returns the last element(s) of +self+. If the array is empty, the first |
|
1377 |
* form returns +nil+. |
|
1378 |
* If a block is given, only elements for which the given block returns a true |
|
1379 |
* value are counted. |
|
1345 | 1380 |
* |
1346 | 1381 |
* See also Array#first for the opposite effect. |
1347 | 1382 |
* |
1348 |
* a = [ "w", "x", "y", "z" ] |
|
1349 |
* a.last #=> "z" |
|
1350 |
* a.last(2) #=> ["y", "z"] |
|
1383 |
* a = [ "w", "x", "y", "z", "aa" ] |
|
1384 |
* a.last #=> "aa" |
|
1385 |
* a.last(2) #=> ["z", "aa"] |
|
1386 |
* a.last { |i| i.size == 1 } #=> "x" |
|
1351 | 1387 |
*/ |
1352 | 1388 | |
1353 | 1389 |
VALUE |
1354 | 1390 |
rb_ary_last(int argc, const VALUE *argv, VALUE ary) |
1355 | 1391 |
{ |
1356 |
if (argc == 0) { |
|
1357 |
long len = RARRAY_LEN(ary); |
|
1358 |
if (len == 0) return Qnil; |
|
1359 |
return RARRAY_AREF(ary, len-1); |
|
1392 |
if (!rb_block_given_p()) { |
|
1393 |
if (argc == 0) { |
|
1394 |
long len = RARRAY_LEN(ary); |
|
1395 |
if (len == 0) return Qnil; |
|
1396 |
return RARRAY_AREF(ary, len-1); |
|
1397 |
} |
|
1398 |
else { |
|
1399 |
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST); |
|
1400 |
} |
|
1360 | 1401 |
} |
1361 | 1402 |
else { |
1362 |
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST); |
|
1403 |
long i; |
|
1404 |
if (argc == 0) { |
|
1405 |
for (i = RARRAY_LEN(ary); --i >= 0; ) { |
|
1406 |
if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) |
|
1407 |
return RARRAY_AREF(ary, i); |
|
1408 |
} |
|
1409 |
return Qnil; |
|
1410 |
} |
|
1411 |
else { |
|
1412 |
long take = NUM2LONG(argv[0]); |
|
1413 |
VALUE result = rb_ary_new();; |
|
1414 |
if (take < 0) rb_raise(rb_eArgError, "attempt to take negative size"); |
|
1415 |
if (take == 0) return rb_ary_new2(0); |
|
1416 |
for (i = RARRAY_LEN(ary); --i >= 0; ) { |
|
1417 |
if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) { |
|
1418 |
rb_ary_push(result, RARRAY_AREF(ary, i)); |
|
1419 |
if (!--take) break; |
|
1420 |
} |
|
1421 |
} |
|
1422 |
return rb_ary_reverse(result); |
|
1423 |
} |
|
1363 | 1424 |
} |
1364 | 1425 |
} |
1365 | 1426 |
enum.c | ||
---|---|---|
909 | 909 |
UNREACHABLE; |
910 | 910 |
} |
911 | 911 | |
912 |
static VALUE |
|
913 |
take_find_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, params)) |
|
914 |
{ |
|
915 |
struct MEMO *memo = MEMO_CAST(params); |
|
916 |
ENUM_WANT_SVALUE(); |
|
917 |
if (RTEST(rb_yield(i))) { |
|
918 |
rb_ary_push(memo->v1, i); |
|
919 |
if (!--memo->u3.cnt) rb_iter_break(); |
|
920 |
} |
|
921 |
return Qnil; |
|
922 |
} |
|
923 | ||
912 | 924 |
static VALUE enum_take(VALUE obj, VALUE n); |
913 | 925 | |
914 | 926 |
/* |
915 | 927 |
* call-seq: |
916 |
* enum.first -> obj or nil |
|
917 |
* enum.first(n) -> an_array |
|
928 |
* enum.first -> obj or nil |
|
929 |
* enum.first { |obj| block } -> obj or nil |
|
930 |
* enum.first(n) -> an_array |
|
931 |
* enum.first(n) { |obj| block } -> an_array |
|
918 | 932 |
* |
919 | 933 |
* Returns the first element, or the first +n+ elements, of the enumerable. |
920 | 934 |
* If the enumerable is empty, the first form returns <code>nil</code>, and the |
921 | 935 |
* second form returns an empty array. |
936 |
* If a block is given, only elements for which the given block returns a true |
|
937 |
* value are counted. |
|
922 | 938 |
* |
923 |
* %w[foo bar baz].first #=> "foo" |
|
924 |
* %w[foo bar baz].first(2) #=> ["foo", "bar"] |
|
925 |
* %w[foo bar baz].first(10) #=> ["foo", "bar", "baz"] |
|
926 |
* [].first #=> nil |
|
927 |
* [].first(10) #=> [] |
|
939 |
* %w[foo bar baz].first #=> "foo" |
|
940 |
* %w[foo bar baz].first(2) #=> ["foo", "bar"] |
|
941 |
* %w[foo bar baz].first(10) #=> ["foo", "bar", "baz"] |
|
942 |
* [].first #=> nil |
|
943 |
* [].first(10) #=> [] |
|
944 |
* [1,2,3,4].first { |i| i.even? } #=> 2 |
|
945 |
* [1,2,2,2].first(2) { |i| i > 1 } #=> [2, 2] |
|
928 | 946 |
* |
929 | 947 |
*/ |
930 | 948 | |
... | ... | |
932 | 950 |
enum_first(int argc, VALUE *argv, VALUE obj) |
933 | 951 |
{ |
934 | 952 |
struct MEMO *memo; |
953 |
long len; |
|
935 | 954 |
rb_check_arity(argc, 0, 1); |
955 | ||
936 | 956 |
if (argc > 0) { |
937 |
return enum_take(obj, argv[0]); |
|
957 |
if (!rb_block_given_p()) return enum_take(obj, argv[0]); |
|
958 | ||
959 |
len = NUM2LONG(argv[0]); |
|
960 |
if (len < 0) rb_raise(rb_eArgError, "attempt to take negative size"); |
|
961 |
if (len == 0) return rb_ary_new2(0); |
|
962 | ||
963 |
memo = MEMO_NEW(rb_ary_new(), 0, len); |
|
964 |
rb_block_call(obj, id_each, 0, 0, take_find_i, (VALUE)memo); |
|
965 |
return memo->v1; |
|
938 | 966 |
} |
939 | 967 |
else { |
940 | 968 |
memo = MEMO_NEW(Qnil, 0, 0); |
941 |
rb_block_call(obj, id_each, 0, 0, first_i, (VALUE)memo); |
|
969 |
rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? find_i : first_i, (VALUE)memo);
|
|
942 | 970 |
return memo->v1; |
943 | 971 |
} |
944 | 972 |
} |
945 | 973 | |
946 | ||
947 | 974 |
/* |
948 | 975 |
* call-seq: |
949 | 976 |
* enum.sort -> array |
gc.c | ||
---|---|---|
6094 | 6094 |
rb_gc_register_mark_object(VALUE obj) |
6095 | 6095 |
{ |
6096 | 6096 |
VALUE ary_ary = GET_THREAD()->vm->mark_object_ary; |
6097 |
VALUE ary = rb_ary_last(0, 0, ary_ary); |
|
6097 |
VALUE ary = Qnil; |
|
6098 |
if (RARRAY_LEN(ary_ary)) |
|
6099 |
ary = RARRAY_AREF(ary_ary, RARRAY_LEN(ary_ary) - 1); |
|
6098 | 6100 | |
6099 | 6101 |
if (ary == Qnil || RARRAY_LEN(ary) >= MARK_OBJECT_ARY_BUCKET_SIZE) { |
6100 | 6102 |
ary = rb_ary_tmp_new(MARK_OBJECT_ARY_BUCKET_SIZE); |
range.c | ||
---|---|---|
851 | 851 | |
852 | 852 |
/* |
853 | 853 |
* call-seq: |
854 |
* rng.first -> obj |
|
855 |
* rng.first(n) -> an_array |
|
854 |
* rng.first -> obj |
|
855 |
* rng.first { |obj| block } -> obj |
|
856 |
* rng.first(n) -> an_array |
|
857 |
* rng.first(n) { |obj| block } -> an_array |
|
856 | 858 |
* |
857 | 859 |
* Returns the first object in the range, or an array of the first +n+ |
858 | 860 |
* elements. |
861 |
* If a block is given, only elements for which the given block returns a true |
|
862 |
* value are counted. |
|
859 | 863 |
* |
860 |
* (10..20).first #=> 10 |
|
861 |
* (10..20).first(3) #=> [10, 11, 12] |
|
864 |
* (10..20).first #=> 10 |
|
865 |
* (10..20).first { |i| i.odd? } #=> 11 |
|
866 |
* (10..20).first(3) #=> [10, 11, 12] |
|
867 |
* (10..20).first(3) { |i| i.odd? } #=> [11, 13, 15] |
|
862 | 868 |
*/ |
863 | 869 | |
864 | 870 |
static VALUE |
... | ... | |
866 | 872 |
{ |
867 | 873 |
VALUE n, ary[2]; |
868 | 874 | |
875 |
if (rb_block_given_p()) return rb_call_super(argc, argv); |
|
869 | 876 |
if (argc == 0) return RANGE_BEG(range); |
870 | 877 | |
871 | 878 |
rb_scan_args(argc, argv, "1", &n); |
... | ... | |
879 | 886 | |
880 | 887 |
/* |
881 | 888 |
* call-seq: |
882 |
* rng.last -> obj |
|
883 |
* rng.last(n) -> an_array |
|
889 |
* rng.last -> obj |
|
890 |
* rng.last { |obj| block } -> obj |
|
891 |
* rng.last(n) -> an_array |
|
892 |
* rng.last(n) { |obj| block } -> an_array |
|
884 | 893 |
* |
885 | 894 |
* Returns the last object in the range, |
886 | 895 |
* or an array of the last +n+ elements. |
887 |
* |
|
888 |
* Note that with no arguments +last+ will return the object that defines |
|
889 |
* the end of the range even if #exclude_end? is +true+. |
|
890 |
* |
|
891 |
* (10..20).last #=> 20 |
|
892 |
* (10...20).last #=> 20 |
|
893 |
* (10..20).last(3) #=> [18, 19, 20] |
|
894 |
* (10...20).last(3) #=> [17, 18, 19] |
|
896 |
* If a block is given, only elements for which the given block returns a true |
|
897 |
* value are counted. |
|
898 |
* |
|
899 |
* Note that with no arguments nor a block +last+ will return the object that |
|
900 |
* defines the end of the range even if #exclude_end? is +true+. |
|
901 |
* |
|
902 |
* (10..20).last #=> 20 |
|
903 |
* (10...20).last #=> 20 |
|
904 |
* (10...20).last { true } #=> 19 |
|
905 |
* (10..20).last(3) #=> [18, 19, 20] |
|
906 |
* (10...20).last(3) #=> [17, 18, 19] |
|
907 |
* (10...20).last(3) { |i| i.odd? } #=> [15, 17, 19] |
|
895 | 908 |
*/ |
896 | 909 | |
897 | 910 |
static VALUE |
898 | 911 |
range_last(int argc, VALUE *argv, VALUE range) |
899 | 912 |
{ |
900 |
if (argc == 0) return RANGE_END(range); |
|
901 |
return rb_ary_last(argc, argv, rb_Array(range)); |
|
913 |
if (argc > 0 || rb_block_given_p()) { |
|
914 |
return rb_ary_last(argc, argv, rb_Array(range)); |
|
915 |
} |
|
916 |
else { |
|
917 |
return RANGE_END(range); |
|
918 |
} |
|
902 | 919 |
} |
903 | 920 | |
904 | 921 |
test/ruby/test_array.rb | ||
---|---|---|
756 | 756 |
def test_first |
757 | 757 |
assert_equal(3, @cls[3, 4, 5].first) |
758 | 758 |
assert_equal(nil, @cls[].first) |
759 |
assert_equal(2, @cls[1, 2, 3, 4].first { |i| i.even? }) |
|
760 |
assert_equal(nil, @cls[1, 2, 3, 4].first { |i| i > 100 }) |
|
759 | 761 |
end |
760 | 762 | |
761 | 763 |
def test_flatten |
... | ... | |
1059 | 1061 |
assert_equal(nil, @cls[].last) |
1060 | 1062 |
assert_equal(1, @cls[1].last) |
1061 | 1063 |
assert_equal(99, @cls[*(3..99).to_a].last) |
1064 |
assert_equal(3, @cls[1, 2, 3, 4].last { |i| i.odd? }) |
|
1065 |
assert_equal(nil, @cls[1, 2, 3, 4].last { |i| i > 100 }) |
|
1062 | 1066 |
end |
1063 | 1067 | |
1064 | 1068 |
def test_length |
... | ... | |
1999 | 2003 |
def test_first2 |
2000 | 2004 |
assert_equal([0], [0].first(2)) |
2001 | 2005 |
assert_raise(ArgumentError) { [0].first(-1) } |
2006 |
assert_equal([2, 4], @cls[1, 2, 4, 6].first(2) { |i| i.even? }) |
|
2007 |
assert_equal([2, 4, 6], @cls[2, 4, 5, 6].first(10) { |i| i.even? }) |
|
2008 |
assert_raise(ArgumentError) { @cls[1, 2].first(-1) { |i| i.even? } } |
|
2002 | 2009 |
end |
2003 | 2010 | |
2004 | 2011 |
def test_last2 |
2005 | 2012 |
assert_equal([0], [0].last(2)) |
2006 | 2013 |
assert_raise(ArgumentError) { [0].last(-1) } |
2014 |
assert_equal([4, 6], @cls[2, 4, 5, 6].last(2) { |i| i.even? }) |
|
2015 |
assert_equal([2, 4, 6], @cls[2, 4, 5, 6].last(10) { |i| i.even? }) |
|
2016 |
assert_raise(ArgumentError) { @cls[1, 2].last(-1) { |i| i.even? } } |
|
2007 | 2017 |
end |
2008 | 2018 | |
2009 | 2019 |
def test_shift2 |
test/ruby/test_enum.rb | ||
---|---|---|
267 | 267 |
assert_equal([1, 2, 3], @obj.first(3)) |
268 | 268 |
assert_nil(@empty.first) |
269 | 269 |
assert_equal([], @empty.first(10)) |
270 |
assert_equal(2, @obj.first { |i| i.even? }) |
|
271 |
assert_equal([3], @obj.first(2) { |i| i > 2 }) |
|
270 | 272 | |
271 | 273 |
bug5801 = '[ruby-dev:45041]' |
272 | 274 |
assert_in_out_err([], <<-'end;', [], /unexpected break/, bug5801) |
test/ruby/test_range.rb | ||
---|---|---|
271 | 271 |
assert_equal("a", ("a".."c").first) |
272 | 272 |
assert_equal("c", ("a".."c").last) |
273 | 273 |
assert_equal(0, (2..0).last) |
274 |
assert_equal(1, (0..11).first { |i| i.odd? }) |
|
275 |
assert_equal(11, (0..11).last { |i| i.odd? }) |
|
276 |
assert_equal([1, 3], (0..11).first(2) { |i| i.odd? }) |
|
277 |
assert_equal([9, 11], (0..11).last(2) { |i| i.odd? }) |
|
274 | 278 | |
275 | 279 |
assert_equal([0, 1, 2], (0...10).first(3)) |
276 | 280 |
assert_equal([7, 8, 9], (0...10).last(3)) |
... | ... | |
279 | 283 |
assert_equal("a", ("a"..."c").first) |
280 | 284 |
assert_equal("c", ("a"..."c").last) |
281 | 285 |
assert_equal(0, (2...0).last) |
286 |
assert_equal(1, (0...11).first { |i| i.odd? }) |
|
287 |
assert_equal(9, (0...11).last { |i| i.odd? }) |
|
288 |
assert_equal([1, 3], (0...11).first(2) { |i| i.odd? }) |
|
289 |
assert_equal([7, 9], (0...11).last(2) { |i| i.odd? }) |
|
282 | 290 |
end |
283 | 291 | |
284 | 292 |
def test_to_s |
285 |
- |