16.05.2013.diff

Innokenty Mikhailov, 05/17/2013 05:48 AM

Download (23.8 KB)

View differences:

enumerator.c
121 121
    VALUE stop_exc;
122 122
    VALUE size;
123 123
    VALUE (*size_fn)(ANYARGS);
124
    VALUE procs;
124 125
};
125 126

  
126 127
static VALUE rb_cGenerator, rb_cYielder;
127 128

  
128 129
struct generator {
129 130
    VALUE proc;
131
    VALUE obj;
132
    VALUE hybrid;
130 133
};
131 134

  
132 135
struct yielder {
133 136
    VALUE proc;
134 137
};
135 138

  
139
struct proc_entry {
140
    VALUE proc;
141
    VALUE memo;
142
    NODE * (*proc_fn)(ANYARGS);
143
    VALUE (*size_fn)(ANYARGS);
144
};
145

  
146

  
136 147
static VALUE generator_allocate(VALUE klass);
137 148
static VALUE generator_init(VALUE obj, VALUE proc);
138 149

  
......
151 162
    rb_gc_mark(ptr->feedvalue);
152 163
    rb_gc_mark(ptr->stop_exc);
153 164
    rb_gc_mark(ptr->size);
165
    rb_gc_mark(ptr->procs);
154 166
}
155 167

  
156 168
#define enumerator_free RUBY_TYPED_DEFAULT_FREE
......
182 194
    return ptr;
183 195
}
184 196

  
197
static void
198
proc_entry_mark(void *p)
199
{
200
    struct proc_entry *ptr = p;
201
    rb_gc_mark(ptr->proc);
202
    rb_gc_mark(ptr->memo);
203
}
204

  
205
#define proc_entry_free RUBY_TYPED_DEFAULT_FREE
206

  
207
static size_t
208
proc_entry_memsize(const void *p)
209
{
210
    return p ? sizeof(struct proc_entry) : 0;
211
}
212

  
213
static const rb_data_type_t proc_entry_data_type = {
214
    "proc_entry",
215
    {
216
	proc_entry_mark,
217
	proc_entry_free,
218
	proc_entry_memsize,
219
    },
220
};
221

  
222
static struct proc_entry *
223
proc_entry_ptr(VALUE proc_entry) {
224
    struct proc_entry *ptr;
225

  
226
    TypedData_Get_Struct(proc_entry, struct proc_entry, &proc_entry_data_type, ptr);
227

  
228
    return ptr;
229
}
230

  
185 231
/*
186 232
 * call-seq:
187 233
 *   obj.to_enum(method = :each, *args)                 -> enum
......
873 919
    return obj;
874 920
}
875 921

  
922
static struct generator * generator_ptr(VALUE obj);
923

  
924
static VALUE
925
append_method(VALUE obj, VALUE str, ID default_method)
926
{
927
    VALUE method;
928

  
929
    method = rb_attr_get(obj, id_method);
930
    if (NIL_P(method)) {
931
        rb_str_buf_cat2(str, ":");
932
        rb_str_buf_cat2(str, rb_id2name(default_method));
933
    }
934
    else if (method != Qfalse) {
935
        Check_Type(method, T_SYMBOL);
936
        rb_str_buf_cat2(str, ":");
937
        rb_str_buf_cat2(str, rb_id2name(SYM2ID(method)));
938
    }
939
    return str;
940
}
941

  
942
static VALUE
943
append_args(VALUE obj, VALUE str, VALUE default_args)
944
{
945
    VALUE eargs;
946
    int tainted, untrusted;
947

  
948
    eargs = rb_attr_get(obj, id_arguments);
949
    if (NIL_P(eargs)) {
950
        eargs = default_args;
951
    }
952
    if (eargs != Qfalse) {
953
        long   argc = RARRAY_LEN(eargs);
954
        VALUE *argv = RARRAY_PTR(eargs);
955

  
956
        if (argc > 0) {
957
            rb_str_buf_cat2(str, "(");
958

  
959
            while (argc--) {
960
                VALUE arg = *argv++;
961

  
962
                rb_str_concat(str, rb_inspect(arg));
963
                rb_str_buf_cat2(str, argc > 0 ? ", " : ")");
964

  
965
                if (OBJ_TAINTED(arg)) tainted = TRUE;
966
                if (OBJ_UNTRUSTED(arg)) untrusted = TRUE;
967
            }
968
        }
969
    }
970

  
971
    if (tainted) { OBJ_TAINT(str); }
972
    if (untrusted) { OBJ_UNTRUST(str); }
973
    return str;
974
}
975

  
876 976
static VALUE
877 977
inspect_enumerator(VALUE obj, VALUE dummy, int recur)
878 978
{
879 979
    struct enumerator *e;
980
    struct generator *g;
880 981
    const char *cname;
881
    VALUE eobj, eargs, str, method;
982
    VALUE eobj, str;
882 983
    int tainted, untrusted;
984
    int i;
883 985

  
884 986
    TypedData_Get_Struct(obj, struct enumerator, &enumerator_data_type, e);
885 987

  
......
895 997
	return str;
896 998
    }
897 999

  
898
    eobj = rb_attr_get(obj, id_receiver);
899
    if (NIL_P(eobj)) {
900
	eobj = e->obj;
1000
    if (e->procs) {
1001
        g = generator_ptr(e->obj);
1002
        eobj = g->obj;
1003
    } else {
1004
        eobj = rb_attr_get(obj, id_receiver);
1005
        if (NIL_P(eobj)) {
1006
            eobj = e->obj;
1007
        }
901 1008
    }
902 1009

  
903 1010
    tainted   = OBJ_TAINTED(eobj);
904 1011
    untrusted = OBJ_UNTRUSTED(eobj);
905 1012

  
906
    /* (1..100).each_cons(2) => "#<Enumerator: 1..100:each_cons(2)>" */
907
    str = rb_sprintf("#<%s: ", cname);
908
    rb_str_concat(str, rb_inspect(eobj));
909
    method = rb_attr_get(obj, id_method);
910
    if (NIL_P(method)) {
911
	rb_str_buf_cat2(str, ":");
912
	rb_str_buf_cat2(str, rb_id2name(e->meth));
913
    }
914
    else if (method != Qfalse) {
915
	Check_Type(method, T_SYMBOL);
916
	rb_str_buf_cat2(str, ":");
917
	rb_str_buf_cat2(str, rb_id2name(SYM2ID(method)));
918
    }
919

  
920
    eargs = rb_attr_get(obj, id_arguments);
921
    if (NIL_P(eargs)) {
922
	eargs = e->args;
923
    }
924
    if (eargs != Qfalse) {
925
	long   argc = RARRAY_LEN(eargs);
926
	VALUE *argv = RARRAY_PTR(eargs);
927

  
928
	if (argc > 0) {
929
	    rb_str_buf_cat2(str, "(");
930

  
931
	    while (argc--) {
932
		VALUE arg = *argv++;
933

  
934
		rb_str_concat(str, rb_inspect(arg));
935
		rb_str_buf_cat2(str, argc > 0 ? ", " : ")");
1013
    /* (1..100).each_cons(2) => "#<Enumerator: 1..100:each_cons(2)>"
1014
     * In case procs chained enumerator traversing all proc entries manually
1015
     */
1016
    if (e->procs) {
1017
        if (strcmp(rb_obj_classname(eobj), cname) == 0) {
1018
            str = rb_inspect(eobj);
1019
        } else {
1020
            str = rb_sprintf("#<%s: ", cname);
1021
            rb_str_concat(str, rb_inspect(eobj));
1022
            rb_str_buf_cat2(str, ">");
1023
        }
1024
        for (i = 0; i < RARRAY_LEN(e->procs); i++) {
1025
            str = rb_str_concat(rb_sprintf("#<%s: ", cname), str);
1026
            append_method(RARRAY_AREF(e->procs, i), str, e->meth);
1027
            append_args(RARRAY_AREF(e->procs, i), str, e->args);
1028
            rb_str_buf_cat2(str, ">");
1029
        }
1030
    } else {
1031
        str = rb_sprintf("#<%s: ", cname);
1032
        rb_str_concat(str, rb_inspect(eobj));
1033
        append_method(obj, str, e->meth);
1034
        append_args(obj, str, e->args);
936 1035

  
937
		if (OBJ_TAINTED(arg)) tainted = TRUE;
938
		if (OBJ_UNTRUSTED(arg)) untrusted = TRUE;
939
	    }
940
	}
1036
        rb_str_buf_cat2(str, ">");
941 1037
    }
942 1038

  
943
    rb_str_buf_cat2(str, ">");
944

  
945 1039
    if (tainted) OBJ_TAINT(str);
946 1040
    if (untrusted) OBJ_UNTRUST(str);
947 1041
    return str;
......
971 1065
 *   (1..100).drop_while.size # => nil
972 1066
 */
973 1067

  
1068
static struct generator * generator_ptr(VALUE obj);
1069

  
974 1070
static VALUE
975 1071
enumerator_size(VALUE obj)
976 1072
{
977 1073
    struct enumerator *e = enumerator_ptr(obj);
978

  
979
    if (e->size_fn) {
980
	return (*e->size_fn)(e->obj, e->args, obj);
981
    }
982
    if (rb_obj_is_proc(e->size)) {
983
        if (e->args)
984
	    return rb_proc_call(e->size, e->args);
985
        else
986
            return rb_proc_call_with_block(e->size, 0, 0, Qnil);
1074
    long i = 0;
1075
    struct generator *g;
1076
    struct proc_entry *entry;
1077
    VALUE receiver;
1078

  
1079
    if (e->procs) {
1080
        g = generator_ptr(e->obj);
1081
        receiver = rb_check_funcall(g->obj, id_size, 0, 0);
1082
        for(i = 0; i < RARRAY_LEN(e->procs); i++) {
1083
            entry = proc_entry_ptr(RARRAY_AREF(e->procs, i));
1084
            if (entry->size_fn) {
1085
                receiver = (*entry->size_fn)(RARRAY_AREF(e->procs, i), receiver);
1086
            } else {
1087
                return Qnil;
1088
            }
1089
        }
1090
        return receiver;
1091
    } else {
1092
        if (e->size_fn) {
1093
            return (*e->size_fn)(e->obj, e->args, obj);
1094
        }
1095
        if (rb_obj_is_proc(e->size)) {
1096
            if (e->args)
1097
                return rb_proc_call(e->size, e->args);
1098
            else
1099
                return rb_proc_call_with_block(e->size, 0, 0, Qnil);
1100
        }
1101
        return e->size;
987 1102
    }
988
    return e->size;
989 1103
}
990 1104

  
991 1105
/*
......
1101 1215
{
1102 1216
    struct generator *ptr = p;
1103 1217
    rb_gc_mark(ptr->proc);
1218
    rb_gc_mark(ptr->obj);
1219
    rb_gc_mark(ptr->hybrid);
1104 1220
}
1105 1221

  
1106 1222
#define generator_free RUBY_TYPED_DEFAULT_FREE
......
1225 1341
}
1226 1342

  
1227 1343
/* Lazy Enumerator methods */
1344

  
1228 1345
static VALUE
1229 1346
enum_size(VALUE self)
1230 1347
{
1231
    VALUE r = rb_check_funcall(self, id_size, 0, 0);
1348
    VALUE r;
1349
    r = rb_check_funcall(self, id_size, 0, 0);
1232 1350
    return (r == Qundef) ? Qnil : r;
1233 1351
}
1234 1352

  
......
1277 1395
    return Qnil;
1278 1396
}
1279 1397

  
1398
static VALUE
1399
lazy_init_yielder(VALUE val, VALUE m, int argc, VALUE *argv)
1400
{
1401
    VALUE yielder = RARRAY_AREF(m, 0);
1402
    VALUE procs_array = RARRAY_AREF(m, 1);
1403
    struct proc_entry *entry;
1404
    VALUE memos = rb_attr_get(yielder, id_memo);
1405
    long i = 0;
1406
    NODE *result;
1407

  
1408
    result = NEW_MEMO(Qtrue, rb_enum_values_pack(argc, argv), Qfalse);
1409

  
1410
    for (i = 0; i < RARRAY_LEN(procs_array); i++) {
1411
        entry = proc_entry_ptr(RARRAY_AREF(procs_array, i));
1412
        if (RTEST(result->u1.value)) {
1413
            (*entry->proc_fn)(RARRAY_AREF(procs_array, i), result, memos, i);
1414
        }
1415
    }
1416

  
1417
    if (RTEST(result->u1.value)) {
1418
        rb_funcall2(yielder, id_yield, 1, &(result->u2.value));
1419
    }
1420
    if (RTEST(result->u3.value)) {
1421
        rb_iter_break();
1422
    }
1423
    return result->u2.value;
1424
    return Qnil;
1425
}
1426

  
1427
static VALUE
1428
lazy_init_block(VALUE val, VALUE m, int argc, VALUE *argv)
1429
{
1430
    VALUE procs = RARRAY_AREF(m, 1);
1431

  
1432
    rb_ivar_set(val, id_memo, rb_ary_new2(RARRAY_LEN(procs)));
1433
    rb_block_call(RARRAY_AREF(m, 0), id_each, 0, 0,
1434
            lazy_init_yielder, rb_ary_new3(2, val, procs));
1435
    return Qnil;
1436
}
1437

  
1438
static VALUE
1439
lazy_generator_init(VALUE enumerator, VALUE procs)
1440
{
1441
    VALUE generator;
1442
    VALUE obj;
1443
    struct generator *gen_ptr;
1444
    struct generator *old_gen_ptr;
1445
    struct enumerator *e = enumerator_ptr(enumerator);
1446

  
1447
    if (RARRAY_LEN(procs) > 0) {
1448
        old_gen_ptr = generator_ptr(e->obj);
1449
        if (old_gen_ptr->hybrid) {
1450
            obj = enumerator;
1451
        } else {
1452
            obj = old_gen_ptr->obj;
1453
        }
1454
    } else {
1455
        obj = enumerator;
1456
    }
1457

  
1458
    generator = generator_allocate(rb_cGenerator);
1459

  
1460
    rb_block_call(generator, id_initialize, 0, 0,
1461
            lazy_init_block, rb_ary_new3(2, obj, procs));
1462

  
1463
    gen_ptr = generator_ptr(generator);
1464
    gen_ptr->obj = obj;
1465

  
1466
    return generator;
1467
}
1468

  
1469
static VALUE
1470
create_proc_entry(VALUE memo, NODE * (*proc_fn)(ANYARGS))
1471
{
1472
    struct proc_entry *entry;
1473
    VALUE entry_obj;
1474

  
1475
    entry_obj = TypedData_Make_Struct(rb_cObject, struct proc_entry,
1476
            &proc_entry_data_type, entry);
1477
    if (rb_block_given_p()) {
1478
        entry->proc = rb_block_proc();
1479
    }
1480
    entry->proc_fn = proc_fn;
1481
    entry->memo = memo;
1482

  
1483
    return entry_obj;
1484
}
1485

  
1486
static VALUE
1487
lazy_add_proc(VALUE enum_obj, VALUE memo, NODE * (*proc_fn)(ANYARGS))
1488
{
1489
    struct enumerator *ptr;
1490
    VALUE entry;
1491

  
1492
    entry = create_proc_entry(memo, proc_fn);
1493
    ptr = enumerator_ptr(enum_obj);
1494
    rb_ary_push(ptr->procs, entry);
1495

  
1496
    return entry;
1497
}
1280 1498
/*
1281 1499
 * call-seq:
1282 1500
 *   Lazy.new(obj, size=nil) { |yielder, *values| ... }
......
1328 1546
}
1329 1547

  
1330 1548
static VALUE
1549
lazy_proc_entry_set_method(VALUE proc_entry, VALUE args, VALUE (*size_fn)(ANYARGS)) {
1550
    ID id = rb_frame_this_func();
1551
    struct proc_entry *e = proc_entry_ptr(proc_entry);
1552
    rb_ivar_set(proc_entry, id_method, ID2SYM(id));
1553
    if (NIL_P(args)) {
1554
	/* Qfalse indicates that the arguments are empty */
1555
	rb_ivar_set(proc_entry, id_arguments, Qfalse);
1556
    }
1557
    else {
1558
	rb_ivar_set(proc_entry, id_arguments, args);
1559
    }
1560
    e->size_fn = size_fn;
1561
    return proc_entry;
1562
}
1563

  
1564
static VALUE
1331 1565
lazy_set_method(VALUE lazy, VALUE args, VALUE (*size_fn)(ANYARGS))
1332 1566
{
1333 1567
    ID id = rb_frame_this_func();
......
1344 1578
    return lazy;
1345 1579
}
1346 1580

  
1581
static VALUE
1582
lazy_copy(int argc, VALUE *argv, VALUE obj)
1583
{
1584
    struct enumerator *new_e;
1585
    struct generator *g;
1586
    VALUE new_obj;
1587
    VALUE new_generator;
1588
    VALUE new_procs;
1589
    struct enumerator *e = enumerator_ptr(obj);
1590

  
1591
    if (RTEST(e->procs)) {
1592
        new_procs = rb_ary_new4(RARRAY_LEN(e->procs), RARRAY_PTR(e->procs));
1593
    } else {
1594
        new_procs = rb_ary_new();
1595
    }
1596

  
1597
    new_generator = lazy_generator_init(obj, new_procs);
1598
    g = generator_ptr(new_generator);
1599
    g->hybrid = Qfalse;
1600

  
1601
    new_obj = enumerator_init_copy(enumerator_allocate(rb_cLazy), obj);
1602
    new_e = enumerator_ptr(new_obj);
1603
    new_e->obj = new_generator;
1604
    new_e->procs = new_procs;
1605
    new_e->meth = rb_to_id(sym_each);
1606

  
1607
    if (argc > 0) {
1608
        new_e->meth = rb_to_id(*argv++);
1609
        new_e->args = rb_ary_new4(argc - 1, argv);
1610
    } else {
1611
        new_e->meth = id_each;
1612
        new_e->args = rb_ary_new4(argc, argv);
1613
    }
1614
    return new_obj;
1615
}
1616

  
1347 1617
/*
1348 1618
 * call-seq:
1349 1619
 *   e.lazy -> lazy_enumerator
......
1431 1701
}
1432 1702

  
1433 1703
static VALUE
1434
lazy_map_func(VALUE val, VALUE m, int argc, VALUE *argv)
1704
lazy_map_size(VALUE entry, VALUE receiver)
1435 1705
{
1436
    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
1706
    return receiver;
1707
}
1437 1708

  
1438
    rb_funcall(argv[0], id_yield, 1, result);
1439
    return Qnil;
1709
static NODE *
1710
lazy_map_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index)
1711
{
1712
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
1713
    result->u2.value = rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil);
1714
    return result;
1440 1715
}
1441 1716

  
1442 1717
static VALUE
1443 1718
lazy_map(VALUE obj)
1444 1719
{
1720
    VALUE new_enum;
1721
    VALUE entry;
1722

  
1445 1723
    if (!rb_block_given_p()) {
1446 1724
	rb_raise(rb_eArgError, "tried to call lazy map without a block");
1447 1725
    }
1448 1726

  
1449
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1450
					 lazy_map_func, 0),
1451
			   Qnil, lazy_receiver_size);
1727
    new_enum = lazy_copy(0, 0, obj);
1728
    entry = lazy_add_proc(new_enum, Qnil, lazy_map_func);
1729
    lazy_proc_entry_set_method(entry, Qnil, lazy_map_size);
1730

  
1731
    return new_enum;
1452 1732
}
1453 1733

  
1454 1734
static VALUE
......
1536 1816
			   Qnil, 0);
1537 1817
}
1538 1818

  
1539
static VALUE
1540
lazy_select_func(VALUE val, VALUE m, int argc, VALUE *argv)
1819
static NODE *
1820
lazy_select_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index)
1541 1821
{
1542
    VALUE element = rb_enum_values_pack(argc - 1, argv + 1);
1543

  
1544
    if (RTEST(rb_yield(element))) {
1545
	return rb_funcall(argv[0], id_yield, 1, element);
1546
    }
1547
    return Qnil;
1822
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
1823
    result->u1.value = rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil);
1824
    return result;
1548 1825
}
1549 1826

  
1550 1827
static VALUE
1551 1828
lazy_select(VALUE obj)
1552 1829
{
1830
    VALUE new_enum;
1831
    VALUE entry;
1832

  
1553 1833
    if (!rb_block_given_p()) {
1554 1834
	rb_raise(rb_eArgError, "tried to call lazy select without a block");
1555 1835
    }
1556 1836

  
1557
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1558
					 lazy_select_func, 0),
1559
			   Qnil, 0);
1837
    new_enum = lazy_copy(0, 0, obj);
1838
    entry = lazy_add_proc(new_enum, Qnil, lazy_select_func);
1839
    lazy_proc_entry_set_method(entry, Qnil, 0);
1840
    return new_enum;
1560 1841
}
1561 1842

  
1562
static VALUE
1563
lazy_reject_func(VALUE val, VALUE m, int argc, VALUE *argv)
1564
{
1565
    VALUE element = rb_enum_values_pack(argc - 1, argv + 1);
1566

  
1567
    if (!RTEST(rb_yield(element))) {
1568
	return rb_funcall(argv[0], id_yield, 1, element);
1569
    }
1570
    return Qnil;
1843
static NODE *
1844
lazy_reject_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index) {
1845
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
1846
    result->u1.value = !RTEST(rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil));
1847
    return result;
1571 1848
}
1572 1849

  
1573 1850
static VALUE
1574 1851
lazy_reject(VALUE obj)
1575 1852
{
1853
    VALUE new_enum, entry;
1854

  
1576 1855
    if (!rb_block_given_p()) {
1577 1856
	rb_raise(rb_eArgError, "tried to call lazy reject without a block");
1578 1857
    }
1579 1858

  
1580
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1581
					 lazy_reject_func, 0),
1582
			   Qnil, 0);
1859
    new_enum = lazy_copy(0, 0, obj);
1860
    entry = lazy_add_proc(new_enum, Qnil, lazy_reject_func);
1861
    lazy_proc_entry_set_method(entry, Qnil, 0);
1862
    return new_enum;
1583 1863
}
1584 1864

  
1585
static VALUE
1586
lazy_grep_func(VALUE val, VALUE m, int argc, VALUE *argv)
1587
{
1588
    VALUE i = rb_enum_values_pack(argc - 1, argv + 1);
1589
    VALUE result = rb_funcall(m, id_eqq, 1, i);
1590

  
1591
    if (RTEST(result)) {
1592
	rb_funcall(argv[0], id_yield, 1, i);
1593
    }
1594
    return Qnil;
1865
static NODE *
1866
lazy_grep_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index) {
1867
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
1868
    result->u1.value = rb_funcall(entry->memo, id_eqq, 1, result->u2.value);
1869
    return result;
1595 1870
}
1596 1871

  
1597
static VALUE
1598
lazy_grep_iter(VALUE val, VALUE m, int argc, VALUE *argv)
1599
{
1600
    VALUE i = rb_enum_values_pack(argc - 1, argv + 1);
1601
    VALUE result = rb_funcall(m, id_eqq, 1, i);
1872
static NODE *
1873
lazy_grep_iter(VALUE proc_entry, NODE *result, VALUE memos, int memo_index) {
1874
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
1875
    result->u1.value = rb_funcall(entry->memo, id_eqq, 1, result->u2.value);
1602 1876

  
1603
    if (RTEST(result)) {
1604
	rb_funcall(argv[0], id_yield, 1, rb_yield(i));
1877
    if (RTEST(result->u1.value)) {
1878
        result->u2.value = rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil);
1605 1879
    }
1606
    return Qnil;
1880

  
1881
    return result;
1607 1882
}
1608 1883

  
1609 1884
static VALUE
1610 1885
lazy_grep(VALUE obj, VALUE pattern)
1611 1886
{
1612
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1613
					 rb_block_given_p() ?
1614
					 lazy_grep_iter : lazy_grep_func,
1615
					 pattern),
1616
			   rb_ary_new3(1, pattern), 0);
1887
    VALUE new_enum, entry;
1888

  
1889
    new_enum = lazy_copy(0, 0, obj);
1890
    entry = lazy_add_proc(new_enum, pattern, rb_block_given_p() ?
1891
					 lazy_grep_iter : lazy_grep_func);
1892
    lazy_proc_entry_set_method(entry, rb_ary_new3(1, pattern), 0);
1893

  
1894
    return new_enum;
1617 1895
}
1618 1896

  
1619 1897
static VALUE
......
1709 1987
}
1710 1988

  
1711 1989
static VALUE
1712
lazy_take_func(VALUE val, VALUE args, int argc, VALUE *argv)
1990
lazy_take_size(VALUE entry, VALUE receiver)
1991
{
1992
    long len = NUM2LONG(RARRAY_AREF(rb_ivar_get(entry, id_arguments), 0));
1993
    if (NIL_P(receiver) || (FIXNUM_P(receiver) && FIX2LONG(receiver) < len))
1994
	return receiver;
1995
    return LONG2NUM(len);
1996
}
1997

  
1998
static NODE *
1999
lazy_take_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index)
1713 2000
{
1714 2001
    long remain;
1715
    VALUE memo = rb_attr_get(argv[0], id_memo);
2002
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
2003
    VALUE memo = rb_ary_entry(memos, memo_index);
2004

  
1716 2005
    if (NIL_P(memo)) {
1717
	memo = args;
2006
	memo = entry->memo;
1718 2007
    }
1719 2008

  
1720
    rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
1721
    if ((remain = NUM2LONG(memo)-1) == 0) {
1722
	return Qundef;
1723
    }
1724
    else {
1725
	rb_ivar_set(argv[0], id_memo, LONG2NUM(remain));
1726
	return Qnil;
2009
    remain = NUM2LONG(memo);
2010
    if (remain == 0) {
2011
        result->u1.value = Qfalse;
2012
        result->u3.value = Qtrue;
2013
    } else if(--remain == 0) {
2014
        result->u3.value = Qtrue;
1727 2015
    }
1728
}
1729

  
1730
static VALUE
1731
lazy_take_size(VALUE generator, VALUE args, VALUE lazy)
1732
{
1733
    VALUE receiver = lazy_size(lazy);
1734
    long len = NUM2LONG(RARRAY_AREF(rb_ivar_get(lazy, id_arguments), 0));
1735
    if (NIL_P(receiver) || (FIXNUM_P(receiver) && FIX2LONG(receiver) < len))
1736
	return receiver;
1737
    return LONG2NUM(len);
2016
    rb_ary_store(memos, memo_index, LONG2NUM(remain));
2017
    return result;
1738 2018
}
1739 2019

  
1740 2020
static VALUE
1741 2021
lazy_take(VALUE obj, VALUE n)
1742 2022
{
1743 2023
    long len = NUM2LONG(n);
1744
    VALUE lazy;
2024
    VALUE new_enum;
2025
    int argc = 0;
2026
    VALUE argv[2];
2027
    VALUE entry;
1745 2028

  
1746 2029
    if (len < 0) {
1747 2030
	rb_raise(rb_eArgError, "attempt to take negative size");
1748 2031
    }
2032

  
1749 2033
    if (len == 0) {
1750
	VALUE len = INT2FIX(0);
1751
	lazy = lazy_to_enum_i(obj, sym_cycle, 1, &len, 0);
1752
    }
1753
    else {
1754
	lazy = rb_block_call(rb_cLazy, id_new, 1, &obj,
1755
					 lazy_take_func, n);
2034
       argv[0] = sym_cycle;
2035
       argv[1] = INT2NUM(0);
2036
       argc = 2;
1756 2037
    }
1757
    return lazy_set_method(lazy, rb_ary_new3(1, n), lazy_take_size);
2038

  
2039
    new_enum = lazy_copy(argc, argv, obj);
2040
    entry = lazy_add_proc(new_enum, n, lazy_take_func);
2041
    lazy_proc_entry_set_method(entry, rb_ary_new3(1, n), lazy_take_size);
2042

  
2043
    return new_enum;
1758 2044
}
1759 2045

  
1760
static VALUE
1761
lazy_take_while_func(VALUE val, VALUE args, int argc, VALUE *argv)
1762
{
1763
    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
1764
    if (!RTEST(result)) return Qundef;
1765
    rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
1766
    return Qnil;
2046
static NODE *
2047
lazy_take_while_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index) {
2048
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
2049
    result->u1.value = rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil);
2050
    if (!RTEST(result->u1.value)) {
2051
        result->u1.value = Qfalse;
2052
        result->u2.value = Qundef;
2053
        result->u3.value = Qtrue;
2054
    }
2055
    return result;
1767 2056
}
1768 2057

  
1769 2058
static VALUE
1770 2059
lazy_take_while(VALUE obj)
1771 2060
{
2061
    VALUE new_enum, entry;
2062

  
1772 2063
    if (!rb_block_given_p()) {
1773 2064
	rb_raise(rb_eArgError, "tried to call lazy take_while without a block");
1774 2065
    }
1775
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1776
					 lazy_take_while_func, 0),
1777
			   Qnil, 0);
2066

  
2067
    new_enum = lazy_copy(0, 0, obj);
2068
    entry = lazy_add_proc(new_enum, Qnil, lazy_take_while_func);
2069
    lazy_proc_entry_set_method(entry, Qnil, 0);
2070

  
2071
    return new_enum;
1778 2072
}
1779 2073

  
1780 2074
static VALUE
1781
lazy_drop_size(VALUE generator, VALUE args, VALUE lazy)
2075
lazy_drop_size(VALUE proc_entry, VALUE receiver)
1782 2076
{
1783
    long len = NUM2LONG(RARRAY_AREF(rb_ivar_get(lazy, id_arguments), 0));
1784
    VALUE receiver = lazy_size(lazy);
2077
    long len = NUM2LONG(RARRAY_AREF(rb_ivar_get(proc_entry, id_arguments), 0));
1785 2078
    if (NIL_P(receiver))
1786 2079
	return receiver;
1787 2080
    if (FIXNUM_P(receiver)) {
......
1791 2084
    return rb_funcall(receiver, '-', 1, LONG2NUM(len));
1792 2085
}
1793 2086

  
1794
static VALUE
1795
lazy_drop_func(VALUE val, VALUE args, int argc, VALUE *argv)
2087
static NODE *
2088
lazy_drop_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index)
1796 2089
{
1797 2090
    long remain;
1798
    VALUE memo = rb_attr_get(argv[0], id_memo);
2091
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
2092
    VALUE memo = rb_ary_entry(memos, memo_index);
2093

  
1799 2094
    if (NIL_P(memo)) {
1800
	memo = args;
1801
    }
1802
    if ((remain = NUM2LONG(memo)) == 0) {
1803
	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
2095
	memo = entry->memo;
1804 2096
    }
1805
    else {
1806
	rb_ivar_set(argv[0], id_memo, LONG2NUM(--remain));
2097
    remain = NUM2LONG(memo);
2098
    if (remain-- > 0) {
2099
        result->u1.value = Qfalse;
2100
	rb_ary_store(memos, memo_index, LONG2NUM(remain));
1807 2101
    }
1808
    return Qnil;
2102

  
2103
    return result;
1809 2104
}
1810 2105

  
1811 2106
static VALUE
1812 2107
lazy_drop(VALUE obj, VALUE n)
1813 2108
{
1814 2109
    long len = NUM2LONG(n);
2110
    VALUE new_enum, entry;
2111
    VALUE argv[2];
2112
    argv[0] = sym_each;
2113
    argv[1] = n;
1815 2114

  
1816 2115
    if (len < 0) {
1817 2116
	rb_raise(rb_eArgError, "attempt to drop negative size");
1818 2117
    }
1819
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1820
					 lazy_drop_func, n),
1821
			   rb_ary_new3(1, n), lazy_drop_size);
2118

  
2119
    new_enum = lazy_copy(2, argv, obj);
2120
    entry = lazy_add_proc(new_enum, n, lazy_drop_func);
2121
    lazy_proc_entry_set_method(entry, rb_ary_new3(1, n), lazy_drop_size);
2122

  
2123
    return new_enum;
1822 2124
}
1823 2125

  
1824
static VALUE
1825
lazy_drop_while_func(VALUE val, VALUE args, int argc, VALUE *argv)
1826
{
1827
    VALUE memo = rb_attr_get(argv[0], id_memo);
1828
    if (NIL_P(memo) && !RTEST(rb_yield_values2(argc - 1, &argv[1]))) {
1829
	rb_ivar_set(argv[0], id_memo, memo = Qtrue);
2126
static NODE *
2127
lazy_drop_while_func(VALUE proc_entry, NODE* result, VALUE memos, int memo_index) {
2128
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
2129
    VALUE memo = rb_ary_entry(memos, memo_index);
2130

  
2131
    if(NIL_P(memo)) {
2132
        memo = entry->memo;
1830 2133
    }
1831
    if (memo == Qtrue) {
1832
	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
2134

  
2135
    if (!RTEST(memo)) {
2136
        result->u1.value = !RTEST(rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil));
2137
        if (result->u1.value) {
2138
            rb_ary_store(memos, memo_index, Qtrue);
2139
        }
1833 2140
    }
1834
    return Qnil;
2141
    return result;
1835 2142
}
1836 2143

  
1837 2144
static VALUE
1838 2145
lazy_drop_while(VALUE obj)
1839 2146
{
2147
    VALUE new_enum, entry;
2148

  
1840 2149
    if (!rb_block_given_p()) {
1841 2150
	rb_raise(rb_eArgError, "tried to call lazy drop_while without a block");
1842 2151
    }
1843
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1844
					 lazy_drop_while_func, 0),
1845
			   Qnil, 0);
2152

  
2153
    new_enum = lazy_copy(0, 0, obj);
2154
    entry = lazy_add_proc(new_enum, Qfalse, lazy_drop_while_func);
2155
    lazy_proc_entry_set_method(entry, Qnil, 0);
2156

  
2157
    return new_enum;
1846 2158
}
1847 2159

  
1848 2160
static VALUE