26_06_2013_2.diff

Innokenty Mikhailov, 06/27/2013 05:24 AM

Download (24.4 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;
130 132
};
131 133

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

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

  
145

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

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

  
156 167
#define enumerator_free RUBY_TYPED_DEFAULT_FREE
......
182 193
    return ptr;
183 194
}
184 195

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

  
204
#define proc_entry_free RUBY_TYPED_DEFAULT_FREE
205

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

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

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

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

  
227
    return ptr;
228
}
229

  
185 230
/*
186 231
 * call-seq:
187 232
 *   obj.to_enum(method = :each, *args)                 -> enum
......
892 937
    return obj;
893 938
}
894 939

  
895
static VALUE append_method(VALUE obj, VALUE str, ID default_method, VALUE default_args);
940
static struct generator * generator_ptr(VALUE obj);
896 941

  
897 942
static VALUE
898
inspect_enumerator(VALUE obj, VALUE dummy, int recur)
943
append_method(VALUE obj, VALUE str, ID default_method)
899 944
{
900
    struct enumerator *e;
901
    VALUE eobj, str, cname;
945
    VALUE method;
902 946

  
903
    TypedData_Get_Struct(obj, struct enumerator, &enumerator_data_type, e);
947
    method = rb_attr_get(obj, id_method);
948
    if (NIL_P(method)) {
949
        rb_str_buf_cat2(str, ":");
950
        rb_str_buf_cat2(str, rb_id2name(default_method));
951
    }
952
    else if (method != Qfalse) {
953
        Check_Type(method, T_SYMBOL);
954
        rb_str_buf_cat2(str, ":");
955
        rb_str_buf_cat2(str, rb_id2name(SYM2ID(method)));
956
    }
957
    return str;
958
}
904 959

  
905
    cname = rb_obj_class(obj);
960
static VALUE
961
append_args(VALUE obj, VALUE str, VALUE default_args)
962
{
963
    VALUE eargs;
964
    int tainted, untrusted;
906 965

  
907
    if (!e || e->obj == Qundef) {
908
	return rb_sprintf("#<%"PRIsVALUE": uninitialized>", rb_class_path(cname));
966
    eargs = rb_attr_get(obj, id_arguments);
967
    if (NIL_P(eargs)) {
968
        eargs = default_args;
909 969
    }
970
    if (eargs != Qfalse) {
971
        long   argc = RARRAY_LEN(eargs);
972
        VALUE *argv = RARRAY_PTR(eargs);
910 973

  
911
    if (recur) {
912
	str = rb_sprintf("#<%"PRIsVALUE": ...>", rb_class_path(cname));
913
	OBJ_TAINT(str);
914
	return str;
915
    }
974
        if (argc > 0) {
975
            rb_str_buf_cat2(str, "(");
916 976

  
917
    eobj = rb_attr_get(obj, id_receiver);
918
    if (NIL_P(eobj)) {
919
	eobj = e->obj;
920
    }
977
            while (argc--) {
978
                VALUE arg = *argv++;
921 979

  
922
    /* (1..100).each_cons(2) => "#<Enumerator: 1..100:each_cons(2)>" */
923
    str = rb_sprintf("#<%"PRIsVALUE": %+"PRIsVALUE, rb_class_path(cname), eobj);
924
    append_method(obj, str, e->meth, e->args);
980
                rb_str_concat(str, rb_inspect(arg));
981
                rb_str_buf_cat2(str, argc > 0 ? ", " : ")");
925 982

  
926
    rb_str_buf_cat2(str, ">");
983
                if (OBJ_TAINTED(arg)) tainted = TRUE;
984
                if (OBJ_UNTRUSTED(arg)) untrusted = TRUE;
985
            }
986
        }
987
    }
927 988

  
989
    if (tainted) { OBJ_TAINT(str); }
990
    if (untrusted) { OBJ_UNTRUST(str); }
928 991
    return str;
929 992
}
930 993

  
931 994
static VALUE
932
append_method(VALUE obj, VALUE str, ID default_method, VALUE default_args)
995
inspect_enumerator(VALUE obj, VALUE dummy, int recur)
933 996
{
934
    VALUE method, eargs;
997
    struct enumerator *e;
998
    struct generator *g;
999
    const char *cname;
1000
    VALUE eobj, str;
1001
    int tainted, untrusted;
1002
    int i;
935 1003

  
936
    method = rb_attr_get(obj, id_method);
937
    if (method != Qfalse) {
938
	ID mid = default_method;
939
	if (!NIL_P(method)) {
940
	    Check_Type(method, T_SYMBOL);
941
	    mid = SYM2ID(method);
942
	}
943
	rb_str_buf_cat2(str, ":");
944
	rb_str_buf_append(str, rb_id2str(mid));
1004
    TypedData_Get_Struct(obj, struct enumerator, &enumerator_data_type, e);
1005

  
1006
    cname = rb_obj_classname(obj);
1007

  
1008
    if (!e || e->obj == Qundef) {
1009
	return rb_sprintf("#<%"PRIsVALUE": uninitialized>", rb_class_path(cname));
945 1010
    }
946 1011

  
947
    eargs = rb_attr_get(obj, id_arguments);
948
    if (NIL_P(eargs)) {
949
	eargs = default_args;
1012
    if (recur) {
1013
	str = rb_sprintf("#<%"PRIsVALUE": ...>", rb_class_path(cname));
1014
	OBJ_TAINT(str);
1015
	return str;
950 1016
    }
951
    if (eargs != Qfalse) {
952
	long   argc = RARRAY_LEN(eargs);
953
	VALUE *argv = RARRAY_PTR(eargs);
954 1017

  
955
	if (argc > 0) {
956
	    rb_str_buf_cat2(str, "(");
1018
    if (e->procs) {
1019
        g = generator_ptr(e->obj);
1020
        eobj = g->obj;
1021
    } else {
1022
        eobj = rb_attr_get(obj, id_receiver);
1023
        if (NIL_P(eobj)) {
1024
            eobj = e->obj;
1025
        }
1026
    }
957 1027

  
958
	    while (argc--) {
959
		VALUE arg = *argv++;
1028
    tainted   = OBJ_TAINTED(eobj);
1029
    untrusted = OBJ_UNTRUSTED(eobj);
960 1030

  
961
		rb_str_append(str, rb_inspect(arg));
962
		rb_str_buf_cat2(str, argc > 0 ? ", " : ")");
963
		OBJ_INFECT(str, arg);
964
	    }
965
	}
1031
    /* (1..100).each_cons(2) => "#<Enumerator: 1..100:each_cons(2)>"
1032
     * In case procs chained enumerator traversing all proc entries manually
1033
     */
1034
    if (e->procs) {
1035
        if (strcmp(rb_obj_classname(eobj), cname) == 0) {
1036
            str = rb_inspect(eobj);
1037
        } else {
1038
            str = rb_sprintf("#<%s: ", cname);
1039
            rb_str_concat(str, rb_inspect(eobj));
1040
            rb_str_buf_cat2(str, ">");
1041
        }
1042
        for (i = 0; i < RARRAY_LEN(e->procs); i++) {
1043
            str = rb_str_concat(rb_sprintf("#<%s: ", cname), str);
1044
            append_method(RARRAY_AREF(e->procs, i), str, e->meth);
1045
            append_args(RARRAY_AREF(e->procs, i), str, e->args);
1046
            rb_str_buf_cat2(str, ">");
1047
        }
1048
    } else {
1049
        str = rb_sprintf("#<%s: ", cname);
1050
        rb_str_concat(str, rb_inspect(eobj));
1051
        append_method(obj, str, e->meth);
1052
        append_args(obj, str, e->args);
1053

  
1054
        rb_str_buf_cat2(str, ">");
966 1055
    }
967 1056

  
1057
    if (tainted) OBJ_TAINT(str);
1058
    if (untrusted) OBJ_UNTRUST(str);
968 1059
    return str;
969 1060
}
970 1061

  
......
992 1083
 *   (1..100).drop_while.size # => nil
993 1084
 */
994 1085

  
1086
static struct generator * generator_ptr(VALUE obj);
1087

  
995 1088
static VALUE
996 1089
enumerator_size(VALUE obj)
997 1090
{
998 1091
    struct enumerator *e = enumerator_ptr(obj);
999

  
1000
    if (e->size_fn) {
1001
	return (*e->size_fn)(e->obj, e->args, obj);
1002
    }
1003
    if (rb_obj_is_proc(e->size)) {
1004
        if (e->args)
1005
	    return rb_proc_call(e->size, e->args);
1006
        else
1007
            return rb_proc_call_with_block(e->size, 0, 0, Qnil);
1092
    long i = 0;
1093
    struct generator *g;
1094
    struct proc_entry *entry;
1095
    VALUE receiver;
1096

  
1097
    if (e->procs) {
1098
        g = generator_ptr(e->obj);
1099
        receiver = rb_check_funcall(g->obj, id_size, 0, 0);
1100
        for(i = 0; i < RARRAY_LEN(e->procs); i++) {
1101
            entry = proc_entry_ptr(RARRAY_AREF(e->procs, i));
1102
            if (entry->size_fn) {
1103
                receiver = (*entry->size_fn)(RARRAY_AREF(e->procs, i), receiver);
1104
            } else {
1105
                return Qnil;
1106
            }
1107
        }
1108
        return receiver;
1109
    } else {
1110
        if (e->size_fn) {
1111
            return (*e->size_fn)(e->obj, e->args, obj);
1112
        }
1113
        if (rb_obj_is_proc(e->size)) {
1114
            if (e->args)
1115
                return rb_proc_call(e->size, e->args);
1116
            else
1117
                return rb_proc_call_with_block(e->size, 0, 0, Qnil);
1118
        }
1119
        return e->size;
1008 1120
    }
1009
    return e->size;
1010 1121
}
1011 1122

  
1012 1123
/*
......
1122 1233
{
1123 1234
    struct generator *ptr = p;
1124 1235
    rb_gc_mark(ptr->proc);
1236
    rb_gc_mark(ptr->obj);
1125 1237
}
1126 1238

  
1127 1239
#define generator_free RUBY_TYPED_DEFAULT_FREE
......
1246 1358
}
1247 1359

  
1248 1360
/* Lazy Enumerator methods */
1361

  
1249 1362
static VALUE
1250 1363
enum_size(VALUE self)
1251 1364
{
1252
    VALUE r = rb_check_funcall(self, id_size, 0, 0);
1365
    VALUE r;
1366
    r = rb_check_funcall(self, id_size, 0, 0);
1253 1367
    return (r == Qundef) ? Qnil : r;
1254 1368
}
1255 1369

  
......
1298 1412
    return Qnil;
1299 1413
}
1300 1414

  
1415
static VALUE
1416
lazy_init_yielder(VALUE val, VALUE m, int argc, VALUE *argv)
1417
{
1418
    VALUE yielder = RARRAY_AREF(m, 0);
1419
    VALUE procs_array = RARRAY_AREF(m, 1);
1420
    struct proc_entry *entry;
1421
    VALUE memos = rb_attr_get(yielder, id_memo);
1422
    long i = 0;
1423
    NODE *result;
1424

  
1425
    result = NEW_MEMO(Qtrue, rb_enum_values_pack(argc, argv), Qfalse);
1426

  
1427
    for (i = 0; i < RARRAY_LEN(procs_array); i++) {
1428
        entry = proc_entry_ptr(RARRAY_AREF(procs_array, i));
1429
        if (RTEST(result->u1.value)) {
1430
            (*entry->proc_fn)(RARRAY_AREF(procs_array, i), result, memos, i);
1431
        }
1432
    }
1433

  
1434
    if (RTEST(result->u1.value)) {
1435
        rb_funcall2(yielder, id_yield, 1, &(result->u2.value));
1436
    }
1437
    if (RTEST(result->u3.value)) {
1438
        rb_iter_break();
1439
    }
1440
    return result->u2.value;
1441
    return Qnil;
1442
}
1443

  
1444
static VALUE
1445
lazy_init_block(VALUE val, VALUE m, int argc, VALUE *argv)
1446
{
1447
    VALUE procs = RARRAY_AREF(m, 1);
1448

  
1449
    rb_ivar_set(val, id_memo, rb_ary_new2(RARRAY_LEN(procs)));
1450
    rb_block_call(RARRAY_AREF(m, 0), id_each, 0, 0,
1451
            lazy_init_yielder, rb_ary_new3(2, val, procs));
1452
    return Qnil;
1453
}
1454

  
1455
static VALUE
1456
lazy_generator_init(VALUE enumerator, VALUE procs)
1457
{
1458
    VALUE generator;
1459
    VALUE obj;
1460
    struct generator *gen_ptr;
1461
    struct generator *old_gen_ptr;
1462
    struct enumerator *e = enumerator_ptr(enumerator);
1463

  
1464
    if (RARRAY_LEN(procs) > 0) {
1465
        old_gen_ptr = generator_ptr(e->obj);
1466
        obj = old_gen_ptr->obj;
1467
    } else {
1468
        obj = enumerator;
1469
    }
1470

  
1471
    generator = generator_allocate(rb_cGenerator);
1472

  
1473
    rb_block_call(generator, id_initialize, 0, 0,
1474
            lazy_init_block, rb_ary_new3(2, obj, procs));
1475

  
1476
    gen_ptr = generator_ptr(generator);
1477
    gen_ptr->obj = obj;
1478

  
1479
    return generator;
1480
}
1481

  
1482
static VALUE
1483
create_proc_entry(VALUE memo, NODE * (*proc_fn)(ANYARGS))
1484
{
1485
    struct proc_entry *entry;
1486
    VALUE entry_obj;
1487

  
1488
    entry_obj = TypedData_Make_Struct(rb_cObject, struct proc_entry,
1489
            &proc_entry_data_type, entry);
1490
    if (rb_block_given_p()) {
1491
        entry->proc = rb_block_proc();
1492
    }
1493
    entry->proc_fn = proc_fn;
1494
    entry->memo = memo;
1495

  
1496
    return entry_obj;
1497
}
1498

  
1499
static VALUE
1500
lazy_add_proc(VALUE enum_obj, VALUE memo, NODE * (*proc_fn)(ANYARGS))
1501
{
1502
    struct enumerator *ptr;
1503
    VALUE entry;
1504

  
1505
    entry = create_proc_entry(memo, proc_fn);
1506
    ptr = enumerator_ptr(enum_obj);
1507
    rb_ary_push(ptr->procs, entry);
1508

  
1509
    return entry;
1510
}
1301 1511
/*
1302 1512
 * call-seq:
1303 1513
 *   Lazy.new(obj, size=nil) { |yielder, *values| ... }
......
1349 1559
}
1350 1560

  
1351 1561
static VALUE
1562
lazy_proc_entry_set_method(VALUE proc_entry, VALUE args, VALUE (*size_fn)(ANYARGS)) {
1563
    ID id = rb_frame_this_func();
1564
    struct proc_entry *e = proc_entry_ptr(proc_entry);
1565
    rb_ivar_set(proc_entry, id_method, ID2SYM(id));
1566
    if (NIL_P(args)) {
1567
	/* Qfalse indicates that the arguments are empty */
1568
	rb_ivar_set(proc_entry, id_arguments, Qfalse);
1569
    }
1570
    else {
1571
	rb_ivar_set(proc_entry, id_arguments, args);
1572
    }
1573
    e->size_fn = size_fn;
1574
    return proc_entry;
1575
}
1576

  
1577
static VALUE
1352 1578
lazy_set_method(VALUE lazy, VALUE args, VALUE (*size_fn)(ANYARGS))
1353 1579
{
1354 1580
    ID id = rb_frame_this_func();
......
1365 1591
    return lazy;
1366 1592
}
1367 1593

  
1594
static VALUE
1595
lazy_copy(int argc, VALUE *argv, VALUE obj)
1596
{
1597
    struct enumerator *new_e;
1598
    struct generator *g;
1599
    VALUE new_obj;
1600
    VALUE new_generator;
1601
    VALUE new_procs;
1602
    struct enumerator *e = enumerator_ptr(obj);
1603

  
1604
    if (RTEST(e->procs)) {
1605
        new_procs = rb_ary_new4(RARRAY_LEN(e->procs), RARRAY_PTR(e->procs));
1606
    } else {
1607
        new_procs = rb_ary_new();
1608
    }
1609

  
1610
    new_generator = lazy_generator_init(obj, new_procs);
1611
    g = generator_ptr(new_generator);
1612

  
1613
    new_obj = enumerator_init_copy(enumerator_allocate(rb_cLazy), obj);
1614
    new_e = enumerator_ptr(new_obj);
1615
    new_e->obj = new_generator;
1616
    new_e->procs = new_procs;
1617
    new_e->meth = rb_to_id(sym_each);
1618

  
1619
    if (argc > 0) {
1620
        new_e->meth = rb_to_id(*argv++);
1621
        new_e->args = rb_ary_new4(argc - 1, argv);
1622
    } else {
1623
        new_e->meth = id_each;
1624
        new_e->args = rb_ary_new4(argc, argv);
1625
    }
1626
    return new_obj;
1627
}
1628

  
1368 1629
/*
1369 1630
 * call-seq:
1370 1631
 *   e.lazy -> lazy_enumerator
......
1452 1713
}
1453 1714

  
1454 1715
static VALUE
1455
lazy_map_func(VALUE val, VALUE m, int argc, VALUE *argv)
1716
lazy_map_size(VALUE entry, VALUE receiver)
1456 1717
{
1457
    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
1718
    return receiver;
1719
}
1458 1720

  
1459
    rb_funcall(argv[0], id_yield, 1, result);
1460
    return Qnil;
1721
static NODE *
1722
lazy_map_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index)
1723
{
1724
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
1725
    result->u2.value = rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil);
1726
    return result;
1461 1727
}
1462 1728

  
1463 1729
static VALUE
1464 1730
lazy_map(VALUE obj)
1465 1731
{
1732
    VALUE new_enum;
1733
    VALUE entry;
1734

  
1466 1735
    if (!rb_block_given_p()) {
1467 1736
	rb_raise(rb_eArgError, "tried to call lazy map without a block");
1468 1737
    }
1469 1738

  
1470
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1471
					 lazy_map_func, 0),
1472
			   Qnil, lazy_receiver_size);
1739
    new_enum = lazy_copy(0, 0, obj);
1740
    entry = lazy_add_proc(new_enum, Qnil, lazy_map_func);
1741
    lazy_proc_entry_set_method(entry, Qnil, lazy_map_size);
1742

  
1743
    return new_enum;
1473 1744
}
1474 1745

  
1475 1746
static VALUE
......
1557 1828
			   Qnil, 0);
1558 1829
}
1559 1830

  
1560
static VALUE
1561
lazy_select_func(VALUE val, VALUE m, int argc, VALUE *argv)
1831
static NODE *
1832
lazy_select_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index)
1562 1833
{
1563
    VALUE element = rb_enum_values_pack(argc - 1, argv + 1);
1564

  
1565
    if (RTEST(rb_yield(element))) {
1566
	return rb_funcall(argv[0], id_yield, 1, element);
1567
    }
1568
    return Qnil;
1834
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
1835
    result->u1.value = rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil);
1836
    return result;
1569 1837
}
1570 1838

  
1571 1839
static VALUE
1572 1840
lazy_select(VALUE obj)
1573 1841
{
1842
    VALUE new_enum;
1843
    VALUE entry;
1844

  
1574 1845
    if (!rb_block_given_p()) {
1575 1846
	rb_raise(rb_eArgError, "tried to call lazy select without a block");
1576 1847
    }
1577 1848

  
1578
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1579
					 lazy_select_func, 0),
1580
			   Qnil, 0);
1849
    new_enum = lazy_copy(0, 0, obj);
1850
    entry = lazy_add_proc(new_enum, Qnil, lazy_select_func);
1851
    lazy_proc_entry_set_method(entry, Qnil, 0);
1852
    return new_enum;
1581 1853
}
1582 1854

  
1583
static VALUE
1584
lazy_reject_func(VALUE val, VALUE m, int argc, VALUE *argv)
1585
{
1586
    VALUE element = rb_enum_values_pack(argc - 1, argv + 1);
1587

  
1588
    if (!RTEST(rb_yield(element))) {
1589
	return rb_funcall(argv[0], id_yield, 1, element);
1590
    }
1591
    return Qnil;
1855
static NODE *
1856
lazy_reject_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index) {
1857
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
1858
    result->u1.value = !RTEST(rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil));
1859
    return result;
1592 1860
}
1593 1861

  
1594 1862
static VALUE
1595 1863
lazy_reject(VALUE obj)
1596 1864
{
1865
    VALUE new_enum, entry;
1866

  
1597 1867
    if (!rb_block_given_p()) {
1598 1868
	rb_raise(rb_eArgError, "tried to call lazy reject without a block");
1599 1869
    }
1600 1870

  
1601
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1602
					 lazy_reject_func, 0),
1603
			   Qnil, 0);
1871
    new_enum = lazy_copy(0, 0, obj);
1872
    entry = lazy_add_proc(new_enum, Qnil, lazy_reject_func);
1873
    lazy_proc_entry_set_method(entry, Qnil, 0);
1874
    return new_enum;
1604 1875
}
1605 1876

  
1606
static VALUE
1607
lazy_grep_func(VALUE val, VALUE m, int argc, VALUE *argv)
1608
{
1609
    VALUE i = rb_enum_values_pack(argc - 1, argv + 1);
1610
    VALUE result = rb_funcall(m, id_eqq, 1, i);
1611

  
1612
    if (RTEST(result)) {
1613
	rb_funcall(argv[0], id_yield, 1, i);
1614
    }
1615
    return Qnil;
1877
static NODE *
1878
lazy_grep_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index) {
1879
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
1880
    result->u1.value = rb_funcall(entry->memo, id_eqq, 1, result->u2.value);
1881
    return result;
1616 1882
}
1617 1883

  
1618
static VALUE
1619
lazy_grep_iter(VALUE val, VALUE m, int argc, VALUE *argv)
1620
{
1621
    VALUE i = rb_enum_values_pack(argc - 1, argv + 1);
1622
    VALUE result = rb_funcall(m, id_eqq, 1, i);
1884
static NODE *
1885
lazy_grep_iter(VALUE proc_entry, NODE *result, VALUE memos, int memo_index) {
1886
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
1887
    result->u1.value = rb_funcall(entry->memo, id_eqq, 1, result->u2.value);
1623 1888

  
1624
    if (RTEST(result)) {
1625
	rb_funcall(argv[0], id_yield, 1, rb_yield(i));
1889
    if (RTEST(result->u1.value)) {
1890
        result->u2.value = rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil);
1626 1891
    }
1627
    return Qnil;
1892

  
1893
    return result;
1628 1894
}
1629 1895

  
1630 1896
static VALUE
1631 1897
lazy_grep(VALUE obj, VALUE pattern)
1632 1898
{
1633
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1634
					 rb_block_given_p() ?
1635
					 lazy_grep_iter : lazy_grep_func,
1636
					 pattern),
1637
			   rb_ary_new3(1, pattern), 0);
1899
    VALUE new_enum, entry;
1900

  
1901
    new_enum = lazy_copy(0, 0, obj);
1902
    entry = lazy_add_proc(new_enum, pattern, rb_block_given_p() ?
1903
					 lazy_grep_iter : lazy_grep_func);
1904
    lazy_proc_entry_set_method(entry, rb_ary_new3(1, pattern), 0);
1905

  
1906
    return new_enum;
1638 1907
}
1639 1908

  
1640 1909
static VALUE
......
1730 1999
}
1731 2000

  
1732 2001
static VALUE
1733
lazy_take_func(VALUE val, VALUE args, int argc, VALUE *argv)
2002
lazy_take_size(VALUE entry, VALUE receiver)
2003
{
2004
    long len = NUM2LONG(RARRAY_AREF(rb_ivar_get(entry, id_arguments), 0));
2005
    if (NIL_P(receiver) || (FIXNUM_P(receiver) && FIX2LONG(receiver) < len))
2006
	return receiver;
2007
    return LONG2NUM(len);
2008
}
2009

  
2010
static NODE *
2011
lazy_take_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index)
1734 2012
{
1735 2013
    long remain;
1736
    VALUE memo = rb_attr_get(argv[0], id_memo);
2014
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
2015
    VALUE memo = rb_ary_entry(memos, memo_index);
2016

  
1737 2017
    if (NIL_P(memo)) {
1738
	memo = args;
2018
	memo = entry->memo;
1739 2019
    }
1740 2020

  
1741
    rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
1742
    if ((remain = NUM2LONG(memo)-1) == 0) {
1743
	return Qundef;
2021
    remain = NUM2LONG(memo);
2022
    if (remain == 0) {
2023
        result->u1.value = Qfalse;
2024
        result->u3.value = Qtrue;
2025
    } else if(--remain == 0) {
2026
        result->u3.value = Qtrue;
1744 2027
    }
1745
    else {
1746
	rb_ivar_set(argv[0], id_memo, LONG2NUM(remain));
1747
	return Qnil;
1748
    }
1749
}
1750

  
1751
static VALUE
1752
lazy_take_size(VALUE generator, VALUE args, VALUE lazy)
1753
{
1754
    VALUE receiver = lazy_size(lazy);
1755
    long len = NUM2LONG(RARRAY_AREF(rb_ivar_get(lazy, id_arguments), 0));
1756
    if (NIL_P(receiver) || (FIXNUM_P(receiver) && FIX2LONG(receiver) < len))
1757
	return receiver;
1758
    return LONG2NUM(len);
2028
    rb_ary_store(memos, memo_index, LONG2NUM(remain));
2029
    return result;
1759 2030
}
1760 2031

  
1761 2032
static VALUE
1762 2033
lazy_take(VALUE obj, VALUE n)
1763 2034
{
1764 2035
    long len = NUM2LONG(n);
1765
    VALUE lazy;
2036
    VALUE new_enum;
2037
    int argc = 0;
2038
    VALUE argv[2];
2039
    VALUE entry;
1766 2040

  
1767 2041
    if (len < 0) {
1768 2042
	rb_raise(rb_eArgError, "attempt to take negative size");
1769 2043
    }
2044

  
1770 2045
    if (len == 0) {
1771
	VALUE len = INT2FIX(0);
1772
	lazy = lazy_to_enum_i(obj, sym_cycle, 1, &len, 0);
2046
       argv[0] = sym_cycle;
2047
       argv[1] = INT2NUM(0);
2048
       argc = 2;
1773 2049
    }
1774
    else {
1775
	lazy = rb_block_call(rb_cLazy, id_new, 1, &obj,
1776
					 lazy_take_func, n);
1777
    }
1778
    return lazy_set_method(lazy, rb_ary_new3(1, n), lazy_take_size);
2050

  
2051
    new_enum = lazy_copy(argc, argv, obj);
2052
    entry = lazy_add_proc(new_enum, n, lazy_take_func);
2053
    lazy_proc_entry_set_method(entry, rb_ary_new3(1, n), lazy_take_size);
2054

  
2055
    return new_enum;
1779 2056
}
1780 2057

  
1781
static VALUE
1782
lazy_take_while_func(VALUE val, VALUE args, int argc, VALUE *argv)
1783
{
1784
    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
1785
    if (!RTEST(result)) return Qundef;
1786
    rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
1787
    return Qnil;
2058
static NODE *
2059
lazy_take_while_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index) {
2060
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
2061
    result->u1.value = rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil);
2062
    if (!RTEST(result->u1.value)) {
2063
        result->u1.value = Qfalse;
2064
        result->u2.value = Qundef;
2065
        result->u3.value = Qtrue;
2066
    }
2067
    return result;
1788 2068
}
1789 2069

  
1790 2070
static VALUE
1791 2071
lazy_take_while(VALUE obj)
1792 2072
{
2073
    VALUE new_enum, entry;
2074

  
1793 2075
    if (!rb_block_given_p()) {
1794 2076
	rb_raise(rb_eArgError, "tried to call lazy take_while without a block");
1795 2077
    }
1796
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1797
					 lazy_take_while_func, 0),
1798
			   Qnil, 0);
2078

  
2079
    new_enum = lazy_copy(0, 0, obj);
2080
    entry = lazy_add_proc(new_enum, Qnil, lazy_take_while_func);
2081
    lazy_proc_entry_set_method(entry, Qnil, 0);
2082

  
2083
    return new_enum;
1799 2084
}
1800 2085

  
1801 2086
static VALUE
1802
lazy_drop_size(VALUE generator, VALUE args, VALUE lazy)
2087
lazy_drop_size(VALUE proc_entry, VALUE receiver)
1803 2088
{
1804
    long len = NUM2LONG(RARRAY_AREF(rb_ivar_get(lazy, id_arguments), 0));
1805
    VALUE receiver = lazy_size(lazy);
2089
    long len = NUM2LONG(RARRAY_AREF(rb_ivar_get(proc_entry, id_arguments), 0));
1806 2090
    if (NIL_P(receiver))
1807 2091
	return receiver;
1808 2092
    if (FIXNUM_P(receiver)) {
......
1812 2096
    return rb_funcall(receiver, '-', 1, LONG2NUM(len));
1813 2097
}
1814 2098

  
1815
static VALUE
1816
lazy_drop_func(VALUE val, VALUE args, int argc, VALUE *argv)
2099
static NODE *
2100
lazy_drop_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index)
1817 2101
{
1818 2102
    long remain;
1819
    VALUE memo = rb_attr_get(argv[0], id_memo);
2103
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
2104
    VALUE memo = rb_ary_entry(memos, memo_index);
2105

  
1820 2106
    if (NIL_P(memo)) {
1821
	memo = args;
2107
	memo = entry->memo;
1822 2108
    }
1823
    if ((remain = NUM2LONG(memo)) == 0) {
1824
	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
1825
    }
1826
    else {
1827
	rb_ivar_set(argv[0], id_memo, LONG2NUM(--remain));
2109
    remain = NUM2LONG(memo);
2110
    if (remain-- > 0) {
2111
        result->u1.value = Qfalse;
2112
	rb_ary_store(memos, memo_index, LONG2NUM(remain));
1828 2113
    }
1829
    return Qnil;
2114

  
2115
    return result;
1830 2116
}
1831 2117

  
1832 2118
static VALUE
1833 2119
lazy_drop(VALUE obj, VALUE n)
1834 2120
{
1835 2121
    long len = NUM2LONG(n);
2122
    VALUE new_enum, entry;
2123
    VALUE argv[2];
2124
    argv[0] = sym_each;
2125
    argv[1] = n;
1836 2126

  
1837 2127
    if (len < 0) {
1838 2128
	rb_raise(rb_eArgError, "attempt to drop negative size");
1839 2129
    }
1840
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1841
					 lazy_drop_func, n),
1842
			   rb_ary_new3(1, n), lazy_drop_size);
2130

  
2131
    new_enum = lazy_copy(2, argv, obj);
2132
    entry = lazy_add_proc(new_enum, n, lazy_drop_func);
2133
    lazy_proc_entry_set_method(entry, rb_ary_new3(1, n), lazy_drop_size);
2134

  
2135
    return new_enum;
1843 2136
}
1844 2137

  
1845
static VALUE
1846
lazy_drop_while_func(VALUE val, VALUE args, int argc, VALUE *argv)
1847
{
1848
    VALUE memo = rb_attr_get(argv[0], id_memo);
1849
    if (NIL_P(memo) && !RTEST(rb_yield_values2(argc - 1, &argv[1]))) {
1850
	rb_ivar_set(argv[0], id_memo, memo = Qtrue);
2138
static NODE *
2139
lazy_drop_while_func(VALUE proc_entry, NODE* result, VALUE memos, int memo_index) {
2140
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
2141
    VALUE memo = rb_ary_entry(memos, memo_index);
2142

  
2143
    if(NIL_P(memo)) {
2144
        memo = entry->memo;
1851 2145
    }
1852
    if (memo == Qtrue) {
1853
	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
2146

  
2147
    if (!RTEST(memo)) {
2148
        result->u1.value = !RTEST(rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil));
2149
        if (result->u1.value) {
2150
            rb_ary_store(memos, memo_index, Qtrue);
2151
        }
1854 2152
    }
1855
    return Qnil;
2153
    return result;
1856 2154
}
1857 2155

  
1858 2156
static VALUE
1859 2157
lazy_drop_while(VALUE obj)
1860 2158
{
2159
    VALUE new_enum, entry;
2160

  
1861 2161
    if (!rb_block_given_p()) {
1862 2162
	rb_raise(rb_eArgError, "tried to call lazy drop_while without a block");
1863 2163
    }
1864
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1865
					 lazy_drop_while_func, 0),
1866
			   Qnil, 0);
2164

  
2165
    new_enum = lazy_copy(0, 0, obj);
2166
    entry = lazy_add_proc(new_enum, Qfalse, lazy_drop_while_func);
2167
    lazy_proc_entry_set_method(entry, Qnil, 0);
2168

  
2169
    return new_enum;
1867 2170
}
1868 2171

  
1869 2172
static VALUE