~ubuntu-branches/ubuntu/intrepid/ruby1.9/intrepid-updates

« back to all changes in this revision

Viewing changes to enum.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2007-09-04 16:01:17 UTC
  • mfrom: (1.1.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20070904160117-i15zckg2nhxe9fyw
Tags: 1.9.0+20070830-2ubuntu1
* Sync from Debian; remaining changes:
  - Add -g to CFLAGS.
* Fixes build failure on ia64.
* Fixes build failure with gcc-4.2 on lpia.
* Robustify check for target_os, fixing build failure on lpia.
* Set Ubuntu maintainer address.

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
  enum.c -
4
4
 
5
5
  $Author: matz $
6
 
  $Date: 2007-06-01 01:59:12 +0900 (金, 01  6月 2007) $
 
6
  $Date: 2007-08-25 12:29:39 +0900 (土, 25  8月 2007) $
7
7
  created at: Fri Oct  1 15:15:19 JST 1993
8
8
 
9
 
  Copyright (C) 1993-2003 Yukihiro Matsumoto
 
9
  Copyright (C) 1993-2007 Yukihiro Matsumoto
10
10
 
11
11
**********************************************************************/
12
12
 
13
 
#include "ruby.h"
14
 
#include "node.h"
15
 
#include "util.h"
 
13
#include "ruby/ruby.h"
 
14
#include "ruby/node.h"
 
15
#include "ruby/util.h"
16
16
 
17
17
VALUE rb_mEnumerable;
18
 
static ID id_each, id_eqq, id_cmp;
 
18
static ID id_each, id_eqq, id_cmp, id_next;
19
19
 
20
20
static VALUE
21
21
grep_i(VALUE i, VALUE *arg)
627
627
{
628
628
    VALUE a = (*(NODE *const *)ap)->u1.value;
629
629
    VALUE b = (*(NODE *const *)bp)->u1.value;
 
630
    VALUE ary = (VALUE)data;
630
631
 
 
632
    if (RBASIC(ary)->klass) {
 
633
        rb_raise(rb_eRuntimeError, "sort_by reentered");
 
634
    }
631
635
    return rb_cmpint(rb_funcall(a, id_cmp, 1, b), a, b);
632
636
}
633
637
 
717
721
    RBASIC(ary)->klass = 0;
718
722
    rb_block_call(obj, id_each, 0, 0, sort_by_i, ary);
719
723
    if (RARRAY_LEN(ary) > 1) {
720
 
        ruby_qsort(RARRAY_PTR(ary), RARRAY_LEN(ary), sizeof(VALUE), sort_by_cmp, 0);
 
724
        ruby_qsort(RARRAY_PTR(ary), RARRAY_LEN(ary), sizeof(VALUE),
 
725
                   sort_by_cmp, (void *)ary);
721
726
    }
722
727
    if (RBASIC(ary)->klass) {
723
728
        rb_raise(rb_eRuntimeError, "sort_by reentered");
1048
1053
}
1049
1054
 
1050
1055
static VALUE
 
1056
minmax_i(VALUE i, VALUE *memo)
 
1057
{
 
1058
    int n;
 
1059
 
 
1060
    if (memo[0] == Qundef) {
 
1061
        memo[0] = i;
 
1062
        memo[1] = i;
 
1063
    }
 
1064
    else {
 
1065
        n = rb_cmpint(rb_funcall(i, id_cmp, 1, memo[0]), i, memo[0]);
 
1066
        if (n < 0) {
 
1067
            memo[0] = i;
 
1068
        }
 
1069
        n = rb_cmpint(rb_funcall(i, id_cmp, 1, memo[1]), i, memo[1]);
 
1070
        if (n > 0) {
 
1071
            memo[1] = i;
 
1072
        }
 
1073
    }
 
1074
    return Qnil;
 
1075
}
 
1076
 
 
1077
static VALUE
 
1078
minmax_ii(VALUE i, VALUE *memo)
 
1079
{
 
1080
    int n;
 
1081
 
 
1082
    if (memo[0] == Qundef) {
 
1083
        memo[0] = i;
 
1084
        memo[1] = i;
 
1085
    }
 
1086
    else {
 
1087
        VALUE ary = memo[2];
 
1088
 
 
1089
        RARRAY_PTR(ary)[0] = i;
 
1090
        RARRAY_PTR(ary)[1] = memo[0];
 
1091
        n = rb_cmpint(rb_yield(ary), i, memo[0]);
 
1092
        if (n < 0) {
 
1093
            memo[0] = i;
 
1094
        }
 
1095
        RARRAY_PTR(ary)[0] = i;
 
1096
        RARRAY_PTR(ary)[1] = memo[1];
 
1097
        n = rb_cmpint(rb_yield(ary), i, memo[1]);
 
1098
        if (n > 0) {
 
1099
            memo[1] = i;
 
1100
        }
 
1101
    }
 
1102
    return Qnil;
 
1103
}
 
1104
 
 
1105
/*
 
1106
 *  call-seq:
 
1107
 *     enum.minmax                   => [min,max]
 
1108
 *     enum.minmax {|a,b| block }    => [min,max]
 
1109
 *  
 
1110
 *  Returns two elements array which contains the mininum and the
 
1111
 *  maxinum value in the enumerable.  The first form assumes all
 
1112
 *  objects implement <code>Comparable</code>; the second uses the
 
1113
 *  block to return <em>a <=> b</em>.
 
1114
 *     
 
1115
 *     a = %w(albatross dog horse)
 
1116
 *     a.minmax                                  #=> ["albatross", "horse"]
 
1117
 *     a.minmax {|a,b| a.length <=> b.length }   #=> ["dog", "albatross"]
 
1118
 */  
 
1119
 
 
1120
static VALUE
 
1121
enum_minmax(VALUE obj)
 
1122
{
 
1123
    VALUE result[3];
 
1124
    VALUE ary = rb_ary_new3(2, Qnil, Qnil);
 
1125
 
 
1126
    result[0] = Qundef;
 
1127
    if (rb_block_given_p()) {
 
1128
        result[2] = ary;
 
1129
        rb_block_call(obj, id_each, 0, 0, minmax_ii, (VALUE)result);
 
1130
    }
 
1131
    else {
 
1132
        rb_block_call(obj, id_each, 0, 0, minmax_i, (VALUE)result);
 
1133
    }
 
1134
    if (result[0] != Qundef) {
 
1135
        RARRAY_PTR(ary)[0] = result[0];
 
1136
        RARRAY_PTR(ary)[1] = result[1];
 
1137
    }
 
1138
    return ary;
 
1139
}
 
1140
 
 
1141
static VALUE
1051
1142
min_by_i(VALUE i, VALUE *memo)
1052
1143
{
1053
1144
    VALUE v;
1130
1221
}
1131
1222
 
1132
1223
static VALUE
 
1224
minmax_by_i(VALUE i, VALUE *memo)
 
1225
{
 
1226
    VALUE v;
 
1227
 
 
1228
    v = rb_yield(i);
 
1229
    if (memo[0] == Qundef) {
 
1230
        memo[0] = v;
 
1231
        memo[1] = v;
 
1232
        memo[2] = i;
 
1233
        memo[3] = i;
 
1234
    }
 
1235
    else {
 
1236
        if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo[0]), v, memo[0]) < 0) {
 
1237
            memo[0] = v;
 
1238
            memo[2] = i;
 
1239
        }
 
1240
        if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo[1]), v, memo[1]) > 0) {
 
1241
            memo[1] = v;
 
1242
            memo[3] = i;
 
1243
        }
 
1244
    }
 
1245
    return Qnil;
 
1246
}
 
1247
 
 
1248
/*
 
1249
 *  call-seq:
 
1250
 *     enum.minmax_by {| obj| block }   => [min, max]
 
1251
 *  
 
1252
 *  Returns two elements array array containing the objects in
 
1253
 *  <i>enum</i> that gives the minmum and maximum values respectively
 
1254
 *  from the given block.
 
1255
 *     
 
1256
 *     a = %w(albatross dog horse)
 
1257
 *     a.minmax_by {|x| x.length }   #=> ["dog", "albatross"]
 
1258
 */
 
1259
 
 
1260
static VALUE
 
1261
enum_minmax_by(VALUE obj)
 
1262
{
 
1263
    VALUE memo[4];
 
1264
 
 
1265
    RETURN_ENUMERATOR(obj, 0, 0);
 
1266
 
 
1267
    memo[0] = Qundef;
 
1268
    memo[1] = Qundef;
 
1269
    memo[2] = Qnil;
 
1270
    memo[3] = Qnil;
 
1271
    rb_block_call(obj, id_each, 0, 0, minmax_by_i, (VALUE)memo);
 
1272
    return rb_assoc_new(memo[2], memo[3]);
 
1273
}
 
1274
 
 
1275
static VALUE
1133
1276
member_i(VALUE item, VALUE *memo)
1134
1277
{
1135
1278
    if (rb_equal(item, memo[0])) {
1205
1348
}
1206
1349
 
1207
1350
static VALUE
1208
 
zip_i(VALUE val, VALUE *memo)
 
1351
zip_i(VALUE val, NODE *memo)
1209
1352
{
1210
 
    VALUE result = memo[0];
1211
 
    VALUE args = memo[1];
1212
 
    int idx = memo[2]++;
1213
 
    VALUE tmp;
 
1353
    volatile VALUE result = memo->u1.value;
 
1354
    volatile VALUE args = memo->u2.value;
 
1355
    volatile VALUE tmp;
1214
1356
    int i;
1215
1357
 
1216
1358
    tmp = rb_ary_new2(RARRAY_LEN(args) + 1);
1217
1359
    rb_ary_store(tmp, 0, val);
1218
1360
    for (i=0; i<RARRAY_LEN(args); i++) {
1219
 
        rb_ary_push(tmp, rb_ary_entry(RARRAY_PTR(args)[i], idx));
 
1361
        VALUE v = rb_funcall(RARRAY_PTR(args)[i], id_next, 0, 0);
 
1362
        rb_ary_push(tmp, v);
1220
1363
    }
1221
 
    if (rb_block_given_p()) {
 
1364
    if (NIL_P(result)) {
1222
1365
        rb_yield(tmp);
1223
1366
    }
1224
1367
    else {
1227
1370
    return Qnil;
1228
1371
}
1229
1372
 
 
1373
static VALUE
 
1374
zip_b(NODE *memo)
 
1375
{
 
1376
    return rb_block_call(memo->u3.value, id_each, 0, 0, zip_i, (VALUE)memo);
 
1377
}
 
1378
 
1230
1379
/*
1231
1380
 *  call-seq:
1232
 
 *     enum.zip(arg, ...)                   => array
 
1381
 *     enum.zip(arg, ...)                   => enumerator
1233
1382
 *     enum.zip(arg, ...) {|arr| block }    => nil
1234
1383
 *  
1235
 
 *  Converts any arguments to arrays, then merges elements of
1236
 
 *  <i>enum</i> with corresponding elements from each argument. This
1237
 
 *  generates a sequence of <code>enum#size</code> <em>n</em>-element
1238
 
 *  arrays, where <em>n</em> is one more that the count of arguments. If
1239
 
 *  the size of any argument is less than <code>enum#size</code>,
1240
 
 *  <code>nil</code> values are supplied. If a block given, it is
1241
 
 *  invoked for each output array, otherwise an array of arrays is
1242
 
 *  returned.
 
1384
 *  Takes one element from <i>enum</i> and merges corresponding
 
1385
 *  elements from each <i>args</i>.  This generates a sequence of
 
1386
 *  <em>n</em>-element arrays, where <em>n</em> is one more that the
 
1387
 *  count of arguments.  The length of the sequence is truncated to
 
1388
 *  the size of the shortest argument (or <i>enum</i>).  If a block
 
1389
 *  given, it is invoked for each output array, otherwise an array of
 
1390
 *  arrays is returned.
1243
1391
 *     
1244
1392
 *     a = [ 4, 5, 6 ]
1245
1393
 *     b = [ 7, 8, 9 ]
1246
1394
 *     
1247
 
 *     (1..3).zip(a, b)      #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
1248
 
 *     "cat\ndog".zip([1])   #=> [["cat\n", 1], ["dog", nil]]
1249
 
 *     (1..3).zip            #=> [[1], [2], [3]]
 
1395
 *     [1,2,3].zip(a, b)      #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
 
1396
 *     [1,2].zip(a,b)         #=> [[1, 4, 7], [2, 5, 8]]
 
1397
 *     a.zip([1,2],[8])       #=> [[4,1,8]]
1250
1398
 *     
1251
1399
 */
1252
1400
 
1255
1403
{
1256
1404
    int i;
1257
1405
    VALUE result;
1258
 
    VALUE memo[3];
 
1406
    NODE *memo;
1259
1407
 
1260
1408
    for (i=0; i<argc; i++) {
1261
 
        argv[i] = rb_convert_type(argv[i], T_ARRAY, "Array", "to_a");
 
1409
        argv[i] = rb_funcall(argv[i], rb_intern("to_enum"), 1, ID2SYM(id_each));
1262
1410
    }
1263
1411
    RETURN_ENUMERATOR(obj, argc, argv);
1264
1412
    result = rb_block_given_p() ? Qnil : rb_ary_new();
1265
 
    memo[0] = result;
1266
 
    memo[1] = rb_ary_new4(argc, argv);
1267
 
    memo[2] = 0;
1268
 
    rb_block_call(obj, id_each, 0, 0, zip_i, (VALUE)memo);
 
1413
    memo = rb_node_newnode(NODE_MEMO, result, rb_ary_new4(argc, argv), obj);
 
1414
    rb_rescue2(zip_b, (VALUE)memo, 0, 0, rb_eStopIteration, (VALUE)0);
1269
1415
 
1270
1416
    return result;
1271
1417
}
1383
1529
    return args[0];
1384
1530
}
1385
1531
 
 
1532
 
 
1533
static VALUE
 
1534
cycle_i(VALUE i, VALUE ary)
 
1535
{
 
1536
    rb_ary_push(ary, i);
 
1537
    rb_yield(i);
 
1538
    return Qnil;
 
1539
}
 
1540
 
 
1541
/*
 
1542
 *  call-seq:
 
1543
 *     enum.cycle {|obj| block }
 
1544
 *  
 
1545
 *  Calls <i>block</i> for each element of enumerable repeatedly
 
1546
 *  forever.  Enumerable#cycle saves elements in an internal array.
 
1547
 *     
 
1548
 *     a = ["a", "b", "c"]
 
1549
 *     a.cycle {|x| puts x }  # print, a, b, c, a, b, c,.. forever.
 
1550
 *     
 
1551
 */
 
1552
 
 
1553
static VALUE
 
1554
enum_cycle(VALUE obj)
 
1555
{
 
1556
    VALUE ary;
 
1557
    long i;
 
1558
 
 
1559
    RETURN_ENUMERATOR(obj, 0, 0);
 
1560
    ary = rb_ary_new();
 
1561
    rb_block_call(obj, id_each, 0, 0, cycle_i, ary);
 
1562
    for (;;) {
 
1563
        for (i=0; i<RARRAY_LEN(ary); i++) {
 
1564
            rb_yield(RARRAY_PTR(ary)[i]);
 
1565
        }
 
1566
    }
 
1567
    return Qnil;
 
1568
}
 
1569
 
1386
1570
/*
1387
1571
 *  The <code>Enumerable</code> mixin provides collection classes with
1388
1572
 *  several traversal and searching methods, and with the ability to
1425
1609
    rb_define_method(rb_mEnumerable,"none?", enum_none, 0);
1426
1610
    rb_define_method(rb_mEnumerable,"min", enum_min, 0);
1427
1611
    rb_define_method(rb_mEnumerable,"max", enum_max, 0);
1428
 
    rb_define_method(rb_mEnumerable,"min_by", enum_min_by, 0);
1429
 
    rb_define_method(rb_mEnumerable,"max_by", enum_max_by, 0);
 
1612
    rb_define_method(rb_mEnumerable,"minmax", enum_minmax, 0);
 
1613
    rb_define_method(rb_mEnumerable,"min_by", enum_min_by, 0);  
 
1614
    rb_define_method(rb_mEnumerable,"max_by", enum_max_by, 0);  
 
1615
    rb_define_method(rb_mEnumerable,"minmax_by", enum_minmax_by, 0);
1430
1616
    rb_define_method(rb_mEnumerable,"member?", enum_member, 1);
1431
1617
    rb_define_method(rb_mEnumerable,"include?", enum_member, 1);
1432
1618
    rb_define_method(rb_mEnumerable,"each_with_index", enum_each_with_index, -1);
1433
1619
    rb_define_method(rb_mEnumerable, "zip", enum_zip, -1);
1434
1620
    rb_define_method(rb_mEnumerable, "take", enum_take, -1);
1435
1621
    rb_define_method(rb_mEnumerable, "drop", enum_drop, -1);
 
1622
    rb_define_method(rb_mEnumerable, "cycle", enum_cycle, 0);
1436
1623
 
1437
1624
    id_eqq  = rb_intern("===");
1438
1625
    id_each = rb_intern("each");
1439
1626
    id_cmp  = rb_intern("<=>");
 
1627
    id_next = rb_intern("next");
1440
1628
}
1441
1629