lazy_enumerator.diff

Innokenty Mikhailov, 04/03/2012 05:52 PM

Download (28.6 KB)

View differences:

enumerator.c
119 119
    VALUE lookahead;
120 120
    VALUE feedvalue;
121 121
    VALUE stop_exc;
122
    VALUE lazy;
123
    VALUE procs;
122 124
};
123 125

  
124 126
static VALUE rb_cGenerator, rb_cYielder;
......
134 136
static VALUE generator_allocate(VALUE klass);
135 137
static VALUE generator_init(VALUE obj, VALUE proc);
136 138

  
139
static VALUE process_element(struct enumerator *e, VALUE result);
140

  
137 141
/*
138 142
 * Enumerator
139 143
 */
......
1175 1179
}
1176 1180

  
1177 1181
/* Lazy Enumerator methods */
1182

  
1183
struct proc_entry {
1184
    VALUE proc;
1185
    VALUE type;
1186
};
1187

  
1188
enum proc_entry_type {
1189
    T_PROC_MAP = 0,
1190
    T_PROC_SELECT = 1
1191
};
1192

  
1178 1193
static VALUE
1179
lazy_init_iterator(VALUE val, VALUE m, int argc, VALUE *argv)
1180
{
1181
    VALUE result;
1182
    if (argc == 1) {
1183
	VALUE args[2];
1184
	args[0] = m;
1185
	args[1] = val;
1186
	result = rb_yield_values2(2, args);
1194
process_element(struct enumerator *e, VALUE result)
1195
{
1196
    struct proc_entry *entry;
1197
    VALUE move_next = Qtrue;
1198
    VALUE *procs = RARRAY_PTR(e->procs);
1199
    long procs_number = RARRAY_LENINT(e->procs);
1200
    long i = 0;
1201

  
1202
    for (i = 0; i < procs_number; i++) {
1203
        Data_Get_Struct(procs[i], struct proc_entry, entry);
1204
        switch ((enum proc_entry_type) entry->type) {
1205
            case T_PROC_MAP:
1206
                result = rb_funcall(entry->proc, rb_intern("call"), 1, result);
1207
                break;
1208
            case T_PROC_SELECT:
1209
                if (RTEST(move_next)) {
1210
                    move_next = rb_funcall(entry->proc, rb_intern("call"), 1, result);
1211
                }
1212
                break;
1213
        }
1187 1214
    }
1188
    else {
1189
	VALUE args;
1190
	int len = rb_long2int((long)argc + 1);
1191 1215

  
1192
	args = rb_ary_tmp_new(len);
1193
	rb_ary_push(args, m);
1194
	if (argc > 0) {
1195
	    rb_ary_cat(args, argv, argc);
1196
	}
1197
	result = rb_yield_values2(len, RARRAY_PTR(args));
1198
	RB_GC_GUARD(args);
1216
    if (RTEST(move_next)) {
1217
        return result;
1218
    } else {
1219
        return Qundef;
1199 1220
    }
1200
    if (result == Qundef) rb_iter_break();
1201
    return Qnil;
1202 1221
}
1203 1222

  
1204 1223
static VALUE
1205
lazy_init_yielder(VALUE val, VALUE m, int argc, VALUE *argv)
1224
lazy_iterator_block(VALUE val, VALUE m, int argc, VALUE *argv)
1206 1225
{
1207 1226
    VALUE result;
1208
    result = rb_funcall2(m, id_yield, argc, argv);
1209
    if (result == Qundef) rb_iter_break();
1210
    return Qnil;
1211
}
1227
    VALUE yielder = RARRAY_PTR(m)[0];
1212 1228

  
1213
static VALUE
1214
lazy_init_block_i(VALUE val, VALUE m, int argc, VALUE *argv)
1215
{
1216
    rb_block_call(m, id_each, argc-1, argv+1, lazy_init_iterator, val);
1217
    return Qnil;
1229
    result = process_element(enumerator_ptr(RARRAY_PTR(m)[1]), val);
1230
    if (result != Qundef) {
1231
        return yielder_yield(yielder, rb_ary_new3(1, result));
1232
    } else {
1233
        return Qnil;
1234
    }
1218 1235
}
1219 1236

  
1220 1237
static VALUE
1221
lazy_init_block(VALUE val, VALUE m, int argc, VALUE *argv)
1238
lazy_generator_block(VALUE val, VALUE m, int argc, VALUE *argv)
1222 1239
{
1223
    rb_block_call(m, id_each, argc-1, argv+1, lazy_init_yielder, val);
1224
    return Qnil;
1240
    VALUE obj = RARRAY_PTR(m)[0];
1241
    VALUE enumerator = RARRAY_PTR(m)[1];
1242

  
1243
    return rb_block_call(obj, id_each, 0, Qnil,
1244
            lazy_iterator_block, rb_ary_new3(2, val, enumerator));
1225 1245
}
1226 1246

  
1227 1247
static VALUE
1228 1248
lazy_initialize(int argc, VALUE *argv, VALUE self)
1229 1249
{
1230
    VALUE obj, meth;
1231 1250
    VALUE generator;
1232
    int offset;
1251
    VALUE obj;
1252
    struct enumerator *ptr;
1233 1253

  
1234
    if (argc < 1) {
1235
	rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..)", argc);
1236
    }
1237
    else {
1238
	obj = argv[0];
1239
	if (argc == 1) {
1240
	    meth = sym_each;
1241
	    offset = 1;
1242
	}
1243
	else {
1244
	    meth = argv[1];
1245
	    offset = 2;
1246
	}
1247
    }
1254
    obj = argv[0];
1248 1255
    generator = generator_allocate(rb_cGenerator);
1249
    rb_block_call(generator, id_initialize, 0, 0,
1250
		  (rb_block_given_p() ? lazy_init_block_i : lazy_init_block),
1251
		  obj);
1252
    enumerator_init(self, generator, meth, argc - offset, argv + offset);
1253
    rb_ivar_set(self, id_receiver, obj);
1256
    rb_block_call(generator, rb_intern("initialize"), 0, Qnil,
1257
            lazy_generator_block, rb_ary_new3(2, obj, self));
1258
    enumerator_init(self, generator, sym_each, 0, Qnil);
1259
    ptr = enumerator_ptr(self);
1260
    ptr->lazy = Qtrue;
1261
    ptr->procs = rb_ary_new();
1254 1262

  
1255 1263
    return self;
1256 1264
}
1257 1265

  
1258 1266
static VALUE
1259
lazy_set_method(VALUE lazy, VALUE args)
1267
create_proc_entry(enum proc_entry_type proc_type)
1260 1268
{
1261
    ID id = rb_frame_this_func();
1262
    rb_ivar_set(lazy, id_method, ID2SYM(id));
1263
    if (NIL_P(args)) {
1264
	/* Qfalse indicates that the arguments are empty */
1265
	rb_ivar_set(lazy, id_arguments, Qfalse);
1266
    }
1267
    else {
1268
	rb_ivar_set(lazy, id_arguments, args);
1269
    }
1270
    return lazy;
1271
}
1269
    struct proc_entry *entry;
1270
    VALUE entry_obj;
1272 1271

  
1273
/*
1274
 * call-seq:
1275
 *   e.lazy -> lazy_enumerator
1276
 *
1277
 * Returns a lazy enumerator, whose methods map/collect,
1278
 * flat_map/collect_concat, select/find_all, reject, grep, zip, take,
1279
 * take_while, drop, drop_while, and cycle enumerate values only on an
1280
 * as-needed basis.  However, if a block is given to zip or cycle, values
1281
 * are enumerated immediately.
1282
 *
1283
 * === Example
1284
 *
1285
 * The following program finds pythagorean triples:
1286
 *
1287
 *   def pythagorean_triples
1288
 *     (1..Float::INFINITY).lazy.flat_map {|z|
1289
 *       (1..z).flat_map {|x|
1290
 *         (x..z).select {|y|
1291
 *           x**2 + y**2 == z**2
1292
 *         }.map {|y|
1293
 *           [x, y, z]
1294
 *         }
1295
 *       }
1296
 *     }
1297
 *   end
1298
 *   # show first ten pythagorean triples
1299
 *   p pythagorean_triples.take(10).force # take is lazy, so force is needed
1300
 *   p pythagorean_triples.first(10)      # first is eager
1301
 *   # show pythagorean triples less than 100
1302
 *   p pythagorean_triples.take_while { |*, z| z < 100 }.force
1303
 */
1304
static VALUE
1305
enumerable_lazy(VALUE obj)
1306
{
1307
    VALUE result;
1272
    entry_obj = Data_Make_Struct(rb_cObject, struct proc_entry, 0, RUBY_DEFAULT_FREE, entry);
1273
    Data_Get_Struct(entry_obj, struct proc_entry, entry);
1274
    entry->proc = rb_block_proc();
1275
    entry->type = proc_type;
1308 1276

  
1309
    result = rb_class_new_instance(1, &obj, rb_cLazy);
1310
    /* Qfalse indicates that the Enumerator::Lazy has no method name */
1311
    rb_ivar_set(result, id_method, Qfalse);
1312
    return result;
1313
}
1314

  
1315
static VALUE
1316
lazy_map_func(VALUE val, VALUE m, int argc, VALUE *argv)
1317
{
1318
    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
1319

  
1320
    rb_funcall(argv[0], id_yield, 1, result);
1321
    return Qnil;
1277
    return entry_obj;
1322 1278
}
1323 1279

  
1324 1280
static VALUE
1325 1281
lazy_map(VALUE obj)
1326 1282
{
1327
    if (!rb_block_given_p()) {
1328
	rb_raise(rb_eArgError, "tried to call lazy map without a block");
1329
    }
1330

  
1331
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1332
					 lazy_map_func, 0),
1333
			   Qnil);
1334
}
1335

  
1336
static VALUE
1337
lazy_flat_map_i(VALUE i, VALUE yielder, int argc, VALUE *argv)
1338
{
1339
    return rb_funcall2(yielder, id_yield, argc, argv);
1340
}
1341

  
1342
static VALUE
1343
lazy_flat_map_each(VALUE obj)
1344
{
1345
    NODE *memo = RNODE(obj);
1346
    rb_block_call(memo->u1.value, id_each, 0, 0, lazy_flat_map_i,
1347
		  memo->u2.value);
1348
    return Qnil;
1349
}
1350

  
1351
static VALUE
1352
lazy_flat_map_to_ary(VALUE obj)
1353
{
1354
    NODE *memo = RNODE(obj);
1355
    VALUE ary = rb_check_array_type(memo->u1.value);
1356
    if (NIL_P(ary)) {
1357
	rb_funcall(memo->u2.value, id_yield, 1, memo->u1.value);
1358
    }
1359
    else {
1360
	long i;
1361
	for (i = 0; i < RARRAY_LEN(ary); i++) {
1362
	    rb_funcall(memo->u2.value, id_yield, 1, RARRAY_PTR(ary)[i]);
1363
	}
1364
    }
1365
    return Qnil;
1366
}
1367

  
1368
static VALUE
1369
lazy_flat_map_func(VALUE val, VALUE m, int argc, VALUE *argv)
1370
{
1371
    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
1372
    if (TYPE(result) == T_ARRAY) {
1373
	long i;
1374
	for (i = 0; i < RARRAY_LEN(result); i++) {
1375
	    rb_funcall(argv[0], id_yield, 1, RARRAY_PTR(result)[i]);
1376
	}
1377
    }
1378
    else {
1379
	NODE *memo;
1380
	memo = NEW_MEMO(result, argv[0], 0);
1381
	rb_rescue2(lazy_flat_map_each, (VALUE) memo,
1382
		   lazy_flat_map_to_ary, (VALUE) memo,
1383
		   rb_eNoMethodError, (VALUE)0);
1384
    }
1385
    return Qnil;
1386
}
1387

  
1388
static VALUE
1389
lazy_flat_map(VALUE obj)
1390
{
1391
    if (!rb_block_given_p()) {
1392
	rb_raise(rb_eArgError, "tried to call lazy flat_map without a block");
1393
    }
1394

  
1395
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1396
					 lazy_flat_map_func, 0),
1397
			   Qnil);
1398
}
1283
    struct enumerator *e = enumerator_ptr(obj);
1399 1284

  
1400
static VALUE
1401
lazy_select_func(VALUE val, VALUE m, int argc, VALUE *argv)
1402
{
1403
    VALUE element = rb_enum_values_pack(argc - 1, argv + 1);
1285
    rb_ary_push(e->procs, create_proc_entry(T_PROC_MAP));
1404 1286

  
1405
    if (RTEST(rb_yield(element))) {
1406
	return rb_funcall(argv[0], id_yield, 1, element);
1407
    }
1408
    return Qnil;
1287
    return obj;
1409 1288
}
1410 1289

  
1411 1290
static VALUE
1412 1291
lazy_select(VALUE obj)
1413 1292
{
1414
    if (!rb_block_given_p()) {
1415
	rb_raise(rb_eArgError, "tried to call lazy select without a block");
1416
    }
1417

  
1418
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1419
					 lazy_select_func, 0),
1420
			   Qnil);
1421
}
1422

  
1423
static VALUE
1424
lazy_reject_func(VALUE val, VALUE m, int argc, VALUE *argv)
1425
{
1426
    VALUE element = rb_enum_values_pack(argc - 1, argv + 1);
1427

  
1428
    if (!RTEST(rb_yield(element))) {
1429
	return rb_funcall(argv[0], id_yield, 1, element);
1430
    }
1431
    return Qnil;
1432
}
1433

  
1434
static VALUE
1435
lazy_reject(VALUE obj)
1436
{
1437
    if (!rb_block_given_p()) {
1438
	rb_raise(rb_eArgError, "tried to call lazy reject without a block");
1439
    }
1440

  
1441
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1442
					 lazy_reject_func, 0),
1443
			   Qnil);
1444
}
1445

  
1446
static VALUE
1447
lazy_grep_func(VALUE val, VALUE m, int argc, VALUE *argv)
1448
{
1449
    VALUE i = rb_enum_values_pack(argc - 1, argv + 1);
1450
    VALUE result = rb_funcall(m, id_eqq, 1, i);
1451

  
1452
    if (RTEST(result)) {
1453
	rb_funcall(argv[0], id_yield, 1, i);
1454
    }
1455
    return Qnil;
1456
}
1457

  
1458
static VALUE
1459
lazy_grep_iter(VALUE val, VALUE m, int argc, VALUE *argv)
1460
{
1461
    VALUE i = rb_enum_values_pack(argc - 1, argv + 1);
1462
    VALUE result = rb_funcall(m, id_eqq, 1, i);
1463

  
1464
    if (RTEST(result)) {
1465
	rb_funcall(argv[0], id_yield, 1, rb_yield(i));
1466
    }
1467
    return Qnil;
1468
}
1469

  
1470
static VALUE
1471
lazy_grep(VALUE obj, VALUE pattern)
1472
{
1473
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1474
					 rb_block_given_p() ?
1475
					 lazy_grep_iter : lazy_grep_func,
1476
					 pattern),
1477
			   rb_ary_new3(1, pattern));
1478
}
1479

  
1480
static VALUE
1481
call_next(VALUE obj)
1482
{
1483
    return rb_funcall(obj, id_next, 0);
1484
}
1485

  
1486
static VALUE
1487
next_stopped(VALUE obj)
1488
{
1489
    return Qnil;
1490
}
1491

  
1492
static VALUE
1493
lazy_zip_func(VALUE val, VALUE arg, int argc, VALUE *argv)
1494
{
1495
    VALUE yielder, ary, v;
1496
    long i;
1497

  
1498
    yielder = argv[0];
1499
    ary = rb_ary_new2(RARRAY_LEN(arg) + 1);
1500
    rb_ary_push(ary, argv[1]);
1501
    for (i = 0; i < RARRAY_LEN(arg); i++) {
1502
	v = rb_rescue2(call_next, RARRAY_PTR(arg)[i], next_stopped, 0,
1503
		       rb_eStopIteration, (VALUE)0);
1504
	rb_ary_push(ary, v);
1505
    }
1506
    rb_funcall(yielder, id_yield, 1, ary);
1507
    return Qnil;
1508
}
1509

  
1510
static VALUE
1511
lazy_zip(int argc, VALUE *argv, VALUE obj)
1512
{
1513
    VALUE ary;
1514
    int i;
1515

  
1516
    if (rb_block_given_p()) {
1517
	return rb_call_super(argc, argv);
1518
    }
1519
    ary = rb_ary_new2(argc);
1520
    for (i = 0; i < argc; i++) {
1521
	rb_ary_push(ary, rb_funcall(argv[i], id_lazy, 0));
1522
    }
1523

  
1524
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1525
					 lazy_zip_func, ary),
1526
			   rb_ary_new4(argc, argv));
1527
}
1528

  
1529
static VALUE
1530
lazy_take_func(VALUE val, VALUE args, int argc, VALUE *argv)
1531
{
1532
    NODE *memo = RNODE(args);
1533

  
1534
    rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
1535
    if (--memo->u3.cnt == 0) {
1536
	return Qundef;
1537
    }
1538
    else {
1539
	return Qnil;
1540
    }
1541
}
1542

  
1543
static VALUE
1544
lazy_take(VALUE obj, VALUE n)
1545
{
1546
    NODE *memo;
1547
    long len = NUM2LONG(n);
1548
    int argc = 1;
1549
    VALUE argv[3];
1550

  
1551
    if (len < 0) {
1552
	rb_raise(rb_eArgError, "attempt to take negative size");
1553
    }
1554
    argv[0] = obj;
1555
    if (len == 0) {
1556
	argv[1] = sym_cycle;
1557
	argv[2] = INT2NUM(0);
1558
	argc = 3;
1559
    }
1560
    memo = NEW_MEMO(0, 0, len);
1561
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, argc, argv,
1562
					 lazy_take_func, (VALUE) memo),
1563
			   rb_ary_new3(1, n));
1564
}
1565

  
1566
static VALUE
1567
lazy_take_while_func(VALUE val, VALUE args, int argc, VALUE *argv)
1568
{
1569
    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
1570
    if (!RTEST(result)) return Qundef;
1571
    rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
1572
    return Qnil;
1573
}
1574

  
1575
static VALUE
1576
lazy_take_while(VALUE obj)
1577
{
1578
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1579
					 lazy_take_while_func, 0),
1580
			   Qnil);
1581
}
1582

  
1583
static VALUE
1584
lazy_drop_func(VALUE val, VALUE args, int argc, VALUE *argv)
1585
{
1586
    NODE *memo = RNODE(args);
1587

  
1588
    if (memo->u3.cnt == 0) {
1589
	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
1590
    }
1591
    else {
1592
	memo->u3.cnt--;
1593
    }
1594
    return Qnil;
1595
}
1596

  
1597
static VALUE
1598
lazy_drop(VALUE obj, VALUE n)
1599
{
1600
    NODE *memo;
1601
    long len = NUM2LONG(n);
1602

  
1603
    if (len < 0) {
1604
	rb_raise(rb_eArgError, "attempt to drop negative size");
1605
    }
1606
    memo = NEW_MEMO(0, 0, len);
1607
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1608
					 lazy_drop_func, (VALUE) memo),
1609
			   rb_ary_new3(1, n));
1610
}
1611

  
1612
static VALUE
1613
lazy_drop_while_func(VALUE val, VALUE args, int argc, VALUE *argv)
1614
{
1615
    NODE *memo = RNODE(args);
1616

  
1617
    if (!memo->u3.state && !RTEST(rb_yield_values2(argc - 1, &argv[1]))) {
1618
	memo->u3.state = TRUE;
1619
    }
1620
    if (memo->u3.state) {
1621
	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
1622
    }
1623
    return Qnil;
1624
}
1625

  
1626
static VALUE
1627
lazy_drop_while(VALUE obj)
1628
{
1629
    NODE *memo;
1293
    struct enumerator *e = enumerator_ptr(obj);
1630 1294

  
1631
    memo = NEW_MEMO(0, 0, FALSE);
1632
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1633
					 lazy_drop_while_func, (VALUE) memo),
1634
			   Qnil);
1635
}
1295
    rb_ary_push(e->procs, create_proc_entry(T_PROC_SELECT));
1636 1296

  
1637
static VALUE
1638
lazy_cycle_func(VALUE val, VALUE m, int argc, VALUE *argv)
1639
{
1640
    return rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
1297
    return obj;
1641 1298
}
1642 1299

  
1643 1300
static VALUE
1644
lazy_cycle(int argc, VALUE *argv, VALUE obj)
1301
enumerable_lazy(VALUE self)
1645 1302
{
1646
    VALUE args;
1647
    int len = rb_long2int((long)argc + 2);
1648

  
1649
    if (rb_block_given_p()) {
1650
	return rb_call_super(argc, argv);
1651
    }
1652
    args = rb_ary_tmp_new(len);
1653
    rb_ary_push(args, obj);
1654
    rb_ary_push(args, sym_cycle);
1655
    if (argc > 0) {
1656
	rb_ary_cat(args, argv, argc);
1657
    }
1658
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, len,
1659
					 RARRAY_PTR(args), lazy_cycle_func,
1660
					 args /* prevent from GC */),
1661
			   rb_ary_new4(argc, argv));
1303
    return rb_class_new_instance(1, &self, rb_cLazy);
1662 1304
}
1663 1305

  
1664
static VALUE
1665
lazy_lazy(VALUE obj)
1666
{
1667
    return obj;
1668
}
1306
/* Lazy Enumerator methods */
1307
//static VALUE
1308
//lazy_init_iterator(VALUE val, VALUE m, int argc, VALUE *argv)
1309
//{
1310
//    VALUE result;
1311
//    if (argc == 1) {
1312
//	VALUE args[2];
1313
//	args[0] = m;
1314
//	args[1] = val;
1315
//	result = rb_yield_values2(2, args);
1316
//    }
1317
//    else {
1318
//	VALUE args;
1319
//	int len = rb_long2int((long)argc + 1);
1320
//
1321
//	args = rb_ary_tmp_new(len);
1322
//	rb_ary_push(args, m);
1323
//	if (argc > 0) {
1324
//	    rb_ary_cat(args, argv, argc);
1325
//	}
1326
//	result = rb_yield_values2(len, RARRAY_PTR(args));
1327
//	RB_GC_GUARD(args);
1328
//    }
1329
//    if (result == Qundef) rb_iter_break();
1330
//    return Qnil;
1331
//}
1332
//
1333
//static VALUE
1334
//lazy_init_yielder(VALUE val, VALUE m, int argc, VALUE *argv)
1335
//{
1336
//    VALUE result;
1337
//    result = rb_funcall2(m, id_yield, argc, argv);
1338
//    if (result == Qundef) rb_iter_break();
1339
//    return Qnil;
1340
//}
1341
//
1342
//static VALUE
1343
//lazy_init_block_i(VALUE val, VALUE m, int argc, VALUE *argv)
1344
//{
1345
//    rb_block_call(m, id_each, argc-1, argv+1, lazy_init_iterator, val);
1346
//    return Qnil;
1347
//}
1348
//
1349
//static VALUE
1350
//lazy_init_block(VALUE val, VALUE m, int argc, VALUE *argv)
1351
//{
1352
//    rb_block_call(m, id_each, argc-1, argv+1, lazy_init_yielder, val);
1353
//    return Qnil;
1354
//}
1355
//
1356
//static VALUE
1357
//lazy_initialize(int argc, VALUE *argv, VALUE self)
1358
//{
1359
//    VALUE obj, meth;
1360
//    VALUE generator;
1361
//    int offset;
1362
//
1363
//    if (argc < 1) {
1364
//	rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..)", argc);
1365
//    }
1366
//    else {
1367
//	obj = argv[0];
1368
//	if (argc == 1) {
1369
//	    meth = sym_each;
1370
//	    offset = 1;
1371
//	}
1372
//	else {
1373
//	    meth = argv[1];
1374
//	    offset = 2;
1375
//	}
1376
//    }
1377
//    generator = generator_allocate(rb_cGenerator);
1378
//    rb_block_call(generator, id_initialize, 0, 0,
1379
//		  (rb_block_given_p() ? lazy_init_block_i : lazy_init_block),
1380
//		  obj);
1381
//    enumerator_init(self, generator, meth, argc - offset, argv + offset);
1382
//    rb_ivar_set(self, id_receiver, obj);
1383
//
1384
//    return self;
1385
//}
1386
//
1387
//static VALUE
1388
//lazy_set_method(VALUE lazy, VALUE args)
1389
//{
1390
//    ID id = rb_frame_this_func();
1391
//    rb_ivar_set(lazy, id_method, ID2SYM(id));
1392
//    if (NIL_P(args)) {
1393
//	/* Qfalse indicates that the arguments are empty */
1394
//	rb_ivar_set(lazy, id_arguments, Qfalse);
1395
//    }
1396
//    else {
1397
//	rb_ivar_set(lazy, id_arguments, args);
1398
//    }
1399
//    return lazy;
1400
//}
1401
//
1402
///*
1403
// * call-seq:
1404
// *   e.lazy -> lazy_enumerator
1405
// *
1406
// * Returns a lazy enumerator, whose methods map/collect,
1407
// * flat_map/collect_concat, select/find_all, reject, grep, zip, take,
1408
// * take_while, drop, drop_while, and cycle enumerate values only on an
1409
// * as-needed basis.  However, if a block is given to zip or cycle, values
1410
// * are enumerated immediately.
1411
// *
1412
// * === Example
1413
// *
1414
// * The following program finds pythagorean triples:
1415
// *
1416
// *   def pythagorean_triples
1417
// *     (1..Float::INFINITY).lazy.flat_map {|z|
1418
// *       (1..z).flat_map {|x|
1419
// *         (x..z).select {|y|
1420
// *           x**2 + y**2 == z**2
1421
// *         }.map {|y|
1422
// *           [x, y, z]
1423
// *         }
1424
// *       }
1425
// *     }
1426
// *   end
1427
// *   # show first ten pythagorean triples
1428
// *   p pythagorean_triples.take(10).force # take is lazy, so force is needed
1429
// *   p pythagorean_triples.first(10)      # first is eager
1430
// *   # show pythagorean triples less than 100
1431
// *   p pythagorean_triples.take_while { |*, z| z < 100 }.force
1432
// */
1433
//static VALUE
1434
//enumerable_lazy(VALUE obj)
1435
//{
1436
//    VALUE result;
1437
//
1438
//    result = rb_class_new_instance(1, &obj, rb_cLazy);
1439
//    /* Qfalse indicates that the Enumerator::Lazy has no method name */
1440
//    rb_ivar_set(result, id_method, Qfalse);
1441
//    return result;
1442
//}
1443
//
1444
//static VALUE
1445
//lazy_map_func(VALUE val, VALUE m, int argc, VALUE *argv)
1446
//{
1447
//    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
1448
//
1449
//    rb_funcall(argv[0], id_yield, 1, result);
1450
//    return Qnil;
1451
//}
1452
//
1453
//static VALUE
1454
//lazy_map(VALUE obj)
1455
//{
1456
//    if (!rb_block_given_p()) {
1457
//	rb_raise(rb_eArgError, "tried to call lazy map without a block");
1458
//    }
1459
//
1460
//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1461
//					 lazy_map_func, 0),
1462
//			   Qnil);
1463
//}
1464
//
1465
//static VALUE
1466
//lazy_flat_map_i(VALUE i, VALUE yielder, int argc, VALUE *argv)
1467
//{
1468
//    return rb_funcall2(yielder, id_yield, argc, argv);
1469
//}
1470
//
1471
//static VALUE
1472
//lazy_flat_map_each(VALUE obj)
1473
//{
1474
//    NODE *memo = RNODE(obj);
1475
//    rb_block_call(memo->u1.value, id_each, 0, 0, lazy_flat_map_i,
1476
//		  memo->u2.value);
1477
//    return Qnil;
1478
//}
1479
//
1480
//static VALUE
1481
//lazy_flat_map_to_ary(VALUE obj)
1482
//{
1483
//    NODE *memo = RNODE(obj);
1484
//    VALUE ary = rb_check_array_type(memo->u1.value);
1485
//    if (NIL_P(ary)) {
1486
//	rb_funcall(memo->u2.value, id_yield, 1, memo->u1.value);
1487
//    }
1488
//    else {
1489
//	long i;
1490
//	for (i = 0; i < RARRAY_LEN(ary); i++) {
1491
//	    rb_funcall(memo->u2.value, id_yield, 1, RARRAY_PTR(ary)[i]);
1492
//	}
1493
//    }
1494
//    return Qnil;
1495
//}
1496
//
1497
//static VALUE
1498
//lazy_flat_map_func(VALUE val, VALUE m, int argc, VALUE *argv)
1499
//{
1500
//    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
1501
//    if (TYPE(result) == T_ARRAY) {
1502
//	long i;
1503
//	for (i = 0; i < RARRAY_LEN(result); i++) {
1504
//	    rb_funcall(argv[0], id_yield, 1, RARRAY_PTR(result)[i]);
1505
//	}
1506
//    }
1507
//    else {
1508
//	NODE *memo;
1509
//	memo = NEW_MEMO(result, argv[0], 0);
1510
//	rb_rescue2(lazy_flat_map_each, (VALUE) memo,
1511
//		   lazy_flat_map_to_ary, (VALUE) memo,
1512
//		   rb_eNoMethodError, (VALUE)0);
1513
//    }
1514
//    return Qnil;
1515
//}
1516
//
1517
//static VALUE
1518
//lazy_flat_map(VALUE obj)
1519
//{
1520
//    if (!rb_block_given_p()) {
1521
//	rb_raise(rb_eArgError, "tried to call lazy flat_map without a block");
1522
//    }
1523
//
1524
//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1525
//					 lazy_flat_map_func, 0),
1526
//			   Qnil);
1527
//}
1528
//
1529
//static VALUE
1530
//lazy_select_func(VALUE val, VALUE m, int argc, VALUE *argv)
1531
//{
1532
//    VALUE element = rb_enum_values_pack(argc - 1, argv + 1);
1533
//
1534
//    if (RTEST(rb_yield(element))) {
1535
//	return rb_funcall(argv[0], id_yield, 1, element);
1536
//    }
1537
//    return Qnil;
1538
//}
1539
//
1540
//static VALUE
1541
//lazy_select(VALUE obj)
1542
//{
1543
//    if (!rb_block_given_p()) {
1544
//	rb_raise(rb_eArgError, "tried to call lazy select without a block");
1545
//    }
1546
//
1547
//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1548
//					 lazy_select_func, 0),
1549
//			   Qnil);
1550
//}
1551
//
1552
//static VALUE
1553
//lazy_reject_func(VALUE val, VALUE m, int argc, VALUE *argv)
1554
//{
1555
//    VALUE element = rb_enum_values_pack(argc - 1, argv + 1);
1556
//
1557
//    if (!RTEST(rb_yield(element))) {
1558
//	return rb_funcall(argv[0], id_yield, 1, element);
1559
//    }
1560
//    return Qnil;
1561
//}
1562
//
1563
//static VALUE
1564
//lazy_reject(VALUE obj)
1565
//{
1566
//    if (!rb_block_given_p()) {
1567
//	rb_raise(rb_eArgError, "tried to call lazy reject without a block");
1568
//    }
1569
//
1570
//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1571
//					 lazy_reject_func, 0),
1572
//			   Qnil);
1573
//}
1574
//
1575
//static VALUE
1576
//lazy_grep_func(VALUE val, VALUE m, int argc, VALUE *argv)
1577
//{
1578
//    VALUE i = rb_enum_values_pack(argc - 1, argv + 1);
1579
//    VALUE result = rb_funcall(m, id_eqq, 1, i);
1580
//
1581
//    if (RTEST(result)) {
1582
//	rb_funcall(argv[0], id_yield, 1, i);
1583
//    }
1584
//    return Qnil;
1585
//}
1586
//
1587
//static VALUE
1588
//lazy_grep_iter(VALUE val, VALUE m, int argc, VALUE *argv)
1589
//{
1590
//    VALUE i = rb_enum_values_pack(argc - 1, argv + 1);
1591
//    VALUE result = rb_funcall(m, id_eqq, 1, i);
1592
//
1593
//    if (RTEST(result)) {
1594
//	rb_funcall(argv[0], id_yield, 1, rb_yield(i));
1595
//    }
1596
//    return Qnil;
1597
//}
1598
//
1599
//static VALUE
1600
//lazy_grep(VALUE obj, VALUE pattern)
1601
//{
1602
//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1603
//					 rb_block_given_p() ?
1604
//					 lazy_grep_iter : lazy_grep_func,
1605
//					 pattern),
1606
//			   rb_ary_new3(1, pattern));
1607
//}
1608
//
1609
//static VALUE
1610
//call_next(VALUE obj)
1611
//{
1612
//    return rb_funcall(obj, id_next, 0);
1613
//}
1614
//
1615
//static VALUE
1616
//next_stopped(VALUE obj)
1617
//{
1618
//    return Qnil;
1619
//}
1620
//
1621
//static VALUE
1622
//lazy_zip_func(VALUE val, VALUE arg, int argc, VALUE *argv)
1623
//{
1624
//    VALUE yielder, ary, v;
1625
//    long i;
1626
//
1627
//    yielder = argv[0];
1628
//    ary = rb_ary_new2(RARRAY_LEN(arg) + 1);
1629
//    rb_ary_push(ary, argv[1]);
1630
//    for (i = 0; i < RARRAY_LEN(arg); i++) {
1631
//	v = rb_rescue2(call_next, RARRAY_PTR(arg)[i], next_stopped, 0,
1632
//		       rb_eStopIteration, (VALUE)0);
1633
//	rb_ary_push(ary, v);
1634
//    }
1635
//    rb_funcall(yielder, id_yield, 1, ary);
1636
//    return Qnil;
1637
//}
1638
//
1639
//static VALUE
1640
//lazy_zip(int argc, VALUE *argv, VALUE obj)
1641
//{
1642
//    VALUE ary;
1643
//    int i;
1644
//
1645
//    if (rb_block_given_p()) {
1646
//	return rb_call_super(argc, argv);
1647
//    }
1648
//    ary = rb_ary_new2(argc);
1649
//    for (i = 0; i < argc; i++) {
1650
//	rb_ary_push(ary, rb_funcall(argv[i], id_lazy, 0));
1651
//    }
1652
//
1653
//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1654
//					 lazy_zip_func, ary),
1655
//			   rb_ary_new4(argc, argv));
1656
//}
1657
//
1658
//static VALUE
1659
//lazy_take_func(VALUE val, VALUE args, int argc, VALUE *argv)
1660
//{
1661
//    NODE *memo = RNODE(args);
1662
//
1663
//    rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
1664
//    if (--memo->u3.cnt == 0) {
1665
//	return Qundef;
1666
//    }
1667
//    else {
1668
//	return Qnil;
1669
//    }
1670
//}
1671
//
1672
//static VALUE
1673
//lazy_take(VALUE obj, VALUE n)
1674
//{
1675
//    NODE *memo;
1676
//    long len = NUM2LONG(n);
1677
//    int argc = 1;
1678
//    VALUE argv[3];
1679
//
1680
//    if (len < 0) {
1681
//	rb_raise(rb_eArgError, "attempt to take negative size");
1682
//    }
1683
//    argv[0] = obj;
1684
//    if (len == 0) {
1685
//	argv[1] = sym_cycle;
1686
//	argv[2] = INT2NUM(0);
1687
//	argc = 3;
1688
//    }
1689
//    memo = NEW_MEMO(0, 0, len);
1690
//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, argc, argv,
1691
//					 lazy_take_func, (VALUE) memo),
1692
//			   rb_ary_new3(1, n));
1693
//}
1694
//
1695
//static VALUE
1696
//lazy_take_while_func(VALUE val, VALUE args, int argc, VALUE *argv)
1697
//{
1698
//    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
1699
//    if (!RTEST(result)) return Qundef;
1700
//    rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
1701
//    return Qnil;
1702
//}
1703
//
1704
//static VALUE
1705
//lazy_take_while(VALUE obj)
1706
//{
1707
//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1708
//					 lazy_take_while_func, 0),
1709
//			   Qnil);
1710
//}
1711
//
1712
//static VALUE
1713
//lazy_drop_func(VALUE val, VALUE args, int argc, VALUE *argv)
1714
//{
1715
//    NODE *memo = RNODE(args);
1716
//
1717
//    if (memo->u3.cnt == 0) {
1718
//	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
1719
//    }
1720
//    else {
1721
//	memo->u3.cnt--;
1722
//    }
1723
//    return Qnil;
1724
//}
1725
//
1726
//static VALUE
1727
//lazy_drop(VALUE obj, VALUE n)
1728
//{
1729
//    NODE *memo;
1730
//    long len = NUM2LONG(n);
1731
//
1732
//    if (len < 0) {
1733
//	rb_raise(rb_eArgError, "attempt to drop negative size");
1734
//    }
1735
//    memo = NEW_MEMO(0, 0, len);
1736
//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1737
//					 lazy_drop_func, (VALUE) memo),
1738
//			   rb_ary_new3(1, n));
1739
//}
1740
//
1741
//static VALUE
1742
//lazy_drop_while_func(VALUE val, VALUE args, int argc, VALUE *argv)
1743
//{
1744
//    NODE *memo = RNODE(args);
1745
//
1746
//    if (!memo->u3.state && !RTEST(rb_yield_values2(argc - 1, &argv[1]))) {
1747
//	memo->u3.state = TRUE;
1748
//    }
1749
//    if (memo->u3.state) {
1750
//	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
1751
//    }
1752
//    return Qnil;
1753
//}
1754
//
1755
//static VALUE
1756
//lazy_drop_while(VALUE obj)
1757
//{
1758
//    NODE *memo;
1759
//
1760
//    memo = NEW_MEMO(0, 0, FALSE);
1761
//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1762
//					 lazy_drop_while_func, (VALUE) memo),
1763
//			   Qnil);
1764
//}
1765
//
1766
//static VALUE
1767
//lazy_cycle_func(VALUE val, VALUE m, int argc, VALUE *argv)
1768
//{
1769
//    return rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
1770
//}
1771
//
1772
//static VALUE
1773
//lazy_cycle(int argc, VALUE *argv, VALUE obj)
1774
//{
1775
//    VALUE args;
1776
//    int len = rb_long2int((long)argc + 2);
1777
//
1778
//    if (rb_block_given_p()) {
1779
//	return rb_call_super(argc, argv);
1780
//    }
1781
//    args = rb_ary_tmp_new(len);
1782
//    rb_ary_push(args, obj);
1783
//    rb_ary_push(args, sym_cycle);
1784
//    if (argc > 0) {
1785
//	rb_ary_cat(args, argv, argc);
1786
//    }
1787
//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, len,
1788
//					 RARRAY_PTR(args), lazy_cycle_func,
1789
//					 args /* prevent from GC */),
1790
//			   rb_ary_new4(argc, argv));
1791
//}
1792
//
1793
//static VALUE
1794
//lazy_lazy(VALUE obj)
1795
//{
1796
//    return obj;
1797
//}
1669 1798

  
1670 1799
/*
1671 1800
 * Document-class: StopIteration
......
1750 1879
    rb_define_method(rb_mEnumerable, "lazy", enumerable_lazy, 0);
1751 1880
    rb_define_method(rb_cLazy, "initialize", lazy_initialize, -1);
1752 1881
    rb_define_method(rb_cLazy, "map", lazy_map, 0);
1753
    rb_define_method(rb_cLazy, "collect", lazy_map, 0);
1754
    rb_define_method(rb_cLazy, "flat_map", lazy_flat_map, 0);
1755
    rb_define_method(rb_cLazy, "collect_concat", lazy_flat_map, 0);
1882
    //rb_define_method(rb_cLazy, "collect", lazy_map, 0);
1883
    //rb_define_method(rb_cLazy, "flat_map", lazy_flat_map, 0);
1884
    //rb_define_method(rb_cLazy, "collect_concat", lazy_flat_map, 0);
1756 1885
    rb_define_method(rb_cLazy, "select", lazy_select, 0);
1757 1886
    rb_define_method(rb_cLazy, "find_all", lazy_select, 0);
1758
    rb_define_method(rb_cLazy, "reject", lazy_reject, 0);
1759
    rb_define_method(rb_cLazy, "grep", lazy_grep, 1);
1760
    rb_define_method(rb_cLazy, "zip", lazy_zip, -1);
1761
    rb_define_method(rb_cLazy, "take", lazy_take, 1);
1762
    rb_define_method(rb_cLazy, "take_while", lazy_take_while, 0);
1763
    rb_define_method(rb_cLazy, "drop", lazy_drop, 1);
1764
    rb_define_method(rb_cLazy, "drop_while", lazy_drop_while, 0);
1765
    rb_define_method(rb_cLazy, "cycle", lazy_cycle, -1);
1766
    rb_define_method(rb_cLazy, "lazy", lazy_lazy, 0);
1767

  
1768
    rb_define_alias(rb_cLazy, "force", "to_a");
1887
    //rb_define_method(rb_cLazy, "reject", lazy_reject, 0);
1888
    //rb_define_method(rb_cLazy, "grep", lazy_grep, 1);
1889
    //rb_define_method(rb_cLazy, "zip", lazy_zip, -1);
1890
    //rb_define_method(rb_cLazy, "take", lazy_take, 1);
1891
    //rb_define_method(rb_cLazy, "take_while", lazy_take_while, 0);
1892
    //rb_define_method(rb_cLazy, "drop", lazy_drop, 1);
1893
    //rb_define_method(rb_cLazy, "drop_while", lazy_drop_while, 0);
1894
    //rb_define_method(rb_cLazy, "cycle", lazy_cycle, -1);
1895
    //rb_define_method(rb_cLazy, "lazy", lazy_lazy, 0);
1896

  
1897
    //rb_define_alias(rb_cLazy, "force", "to_a");
1769 1898

  
1770 1899
    rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
1771 1900
    rb_define_method(rb_eStopIteration, "result", stop_result, 0);