26_07_2013.diff

Innokenty Mikhailov, 06/26/2013 07:20 PM

Download (24.6 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
......
892 938
    return obj;
893 939
}
894 940

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

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

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

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

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

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

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

  
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);
981
                rb_str_concat(str, rb_inspect(arg));
982
                rb_str_buf_cat2(str, argc > 0 ? ", " : ")");
925 983

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

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

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

  
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));
1005
    TypedData_Get_Struct(obj, struct enumerator, &enumerator_data_type, e);
1006

  
1007
    cname = rb_obj_classname(obj);
1008

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

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

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

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

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

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

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

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

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

  
995 1089
static VALUE
996 1090
enumerator_size(VALUE obj)
997 1091
{
998 1092
    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);
1093
    long i = 0;
1094
    struct generator *g;
1095
    struct proc_entry *entry;
1096
    VALUE receiver;
1097

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

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

  
1127 1241
#define generator_free RUBY_TYPED_DEFAULT_FREE
......
1246 1360
}
1247 1361

  
1248 1362
/* Lazy Enumerator methods */
1363

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

  
......
1298 1414
    return Qnil;
1299 1415
}
1300 1416

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

  
1427
    result = NEW_MEMO(Qtrue, rb_enum_values_pack(argc, argv), Qfalse);
1428

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

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

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

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

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

  
1466
    if (RARRAY_LEN(procs) > 0) {
1467
        old_gen_ptr = generator_ptr(e->obj);
1468
        if (old_gen_ptr->hybrid) {
1469
            obj = enumerator;
1470
        } else {
1471
            obj = old_gen_ptr->obj;
1472
        }
1473
    } else {
1474
        obj = enumerator;
1475
    }
1476

  
1477
    generator = generator_allocate(rb_cGenerator);
1478

  
1479
    rb_block_call(generator, id_initialize, 0, 0,
1480
            lazy_init_block, rb_ary_new3(2, obj, procs));
1481

  
1482
    gen_ptr = generator_ptr(generator);
1483
    gen_ptr->obj = obj;
1484

  
1485
    return generator;
1486
}
1487

  
1488
static VALUE
1489
create_proc_entry(VALUE memo, NODE * (*proc_fn)(ANYARGS))
1490
{
1491
    struct proc_entry *entry;
1492
    VALUE entry_obj;
1493

  
1494
    entry_obj = TypedData_Make_Struct(rb_cObject, struct proc_entry,
1495
            &proc_entry_data_type, entry);
1496
    if (rb_block_given_p()) {
1497
        entry->proc = rb_block_proc();
1498
    }
1499
    entry->proc_fn = proc_fn;
1500
    entry->memo = memo;
1501

  
1502
    return entry_obj;
1503
}
1504

  
1505
static VALUE
1506
lazy_add_proc(VALUE enum_obj, VALUE memo, NODE * (*proc_fn)(ANYARGS))
1507
{
1508
    struct enumerator *ptr;
1509
    VALUE entry;
1510

  
1511
    entry = create_proc_entry(memo, proc_fn);
1512
    ptr = enumerator_ptr(enum_obj);
1513
    rb_ary_push(ptr->procs, entry);
1514

  
1515
    return entry;
1516
}
1301 1517
/*
1302 1518
 * call-seq:
1303 1519
 *   Lazy.new(obj, size=nil) { |yielder, *values| ... }
......
1349 1565
}
1350 1566

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

  
1583
static VALUE
1352 1584
lazy_set_method(VALUE lazy, VALUE args, VALUE (*size_fn)(ANYARGS))
1353 1585
{
1354 1586
    ID id = rb_frame_this_func();
......
1365 1597
    return lazy;
1366 1598
}
1367 1599

  
1600
static VALUE
1601
lazy_copy(int argc, VALUE *argv, VALUE obj)
1602
{
1603
    struct enumerator *new_e;
1604
    struct generator *g;
1605
    VALUE new_obj;
1606
    VALUE new_generator;
1607
    VALUE new_procs;
1608
    struct enumerator *e = enumerator_ptr(obj);
1609

  
1610
    if (RTEST(e->procs)) {
1611
        new_procs = rb_ary_new4(RARRAY_LEN(e->procs), RARRAY_PTR(e->procs));
1612
    } else {
1613
        new_procs = rb_ary_new();
1614
    }
1615

  
1616
    new_generator = lazy_generator_init(obj, new_procs);
1617
    g = generator_ptr(new_generator);
1618
    g->hybrid = Qfalse;
1619

  
1620
    new_obj = enumerator_init_copy(enumerator_allocate(rb_cLazy), obj);
1621
    new_e = enumerator_ptr(new_obj);
1622
    new_e->obj = new_generator;
1623
    new_e->procs = new_procs;
1624
    new_e->meth = rb_to_id(sym_each);
1625

  
1626
    if (argc > 0) {
1627
        new_e->meth = rb_to_id(*argv++);
1628
        new_e->args = rb_ary_new4(argc - 1, argv);
1629
    } else {
1630
        new_e->meth = id_each;
1631
        new_e->args = rb_ary_new4(argc, argv);
1632
    }
1633
    return new_obj;
1634
}
1635

  
1368 1636
/*
1369 1637
 * call-seq:
1370 1638
 *   e.lazy -> lazy_enumerator
......
1452 1720
}
1453 1721

  
1454 1722
static VALUE
1455
lazy_map_func(VALUE val, VALUE m, int argc, VALUE *argv)
1723
lazy_map_size(VALUE entry, VALUE receiver)
1456 1724
{
1457
    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
1725
    return receiver;
1726
}
1458 1727

  
1459
    rb_funcall(argv[0], id_yield, 1, result);
1460
    return Qnil;
1728
static NODE *
1729
lazy_map_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index)
1730
{
1731
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
1732
    result->u2.value = rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil);
1733
    return result;
1461 1734
}
1462 1735

  
1463 1736
static VALUE
1464 1737
lazy_map(VALUE obj)
1465 1738
{
1739
    VALUE new_enum;
1740
    VALUE entry;
1741

  
1466 1742
    if (!rb_block_given_p()) {
1467 1743
	rb_raise(rb_eArgError, "tried to call lazy map without a block");
1468 1744
    }
1469 1745

  
1470
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1471
					 lazy_map_func, 0),
1472
			   Qnil, lazy_receiver_size);
1746
    new_enum = lazy_copy(0, 0, obj);
1747
    entry = lazy_add_proc(new_enum, Qnil, lazy_map_func);
1748
    lazy_proc_entry_set_method(entry, Qnil, lazy_map_size);
1749

  
1750
    return new_enum;
1473 1751
}
1474 1752

  
1475 1753
static VALUE
......
1557 1835
			   Qnil, 0);
1558 1836
}
1559 1837

  
1560
static VALUE
1561
lazy_select_func(VALUE val, VALUE m, int argc, VALUE *argv)
1838
static NODE *
1839
lazy_select_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index)
1562 1840
{
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;
1841
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
1842
    result->u1.value = rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil);
1843
    return result;
1569 1844
}
1570 1845

  
1571 1846
static VALUE
1572 1847
lazy_select(VALUE obj)
1573 1848
{
1849
    VALUE new_enum;
1850
    VALUE entry;
1851

  
1574 1852
    if (!rb_block_given_p()) {
1575 1853
	rb_raise(rb_eArgError, "tried to call lazy select without a block");
1576 1854
    }
1577 1855

  
1578
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1579
					 lazy_select_func, 0),
1580
			   Qnil, 0);
1856
    new_enum = lazy_copy(0, 0, obj);
1857
    entry = lazy_add_proc(new_enum, Qnil, lazy_select_func);
1858
    lazy_proc_entry_set_method(entry, Qnil, 0);
1859
    return new_enum;
1581 1860
}
1582 1861

  
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;
1862
static NODE *
1863
lazy_reject_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index) {
1864
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
1865
    result->u1.value = !RTEST(rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil));
1866
    return result;
1592 1867
}
1593 1868

  
1594 1869
static VALUE
1595 1870
lazy_reject(VALUE obj)
1596 1871
{
1872
    VALUE new_enum, entry;
1873

  
1597 1874
    if (!rb_block_given_p()) {
1598 1875
	rb_raise(rb_eArgError, "tried to call lazy reject without a block");
1599 1876
    }
1600 1877

  
1601
    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
1602
					 lazy_reject_func, 0),
1603
			   Qnil, 0);
1878
    new_enum = lazy_copy(0, 0, obj);
1879
    entry = lazy_add_proc(new_enum, Qnil, lazy_reject_func);
1880
    lazy_proc_entry_set_method(entry, Qnil, 0);
1881
    return new_enum;
1604 1882
}
1605 1883

  
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;
1884
static NODE *
1885
lazy_grep_func(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);
1888
    return result;
1616 1889
}
1617 1890

  
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);
1891
static NODE *
1892
lazy_grep_iter(VALUE proc_entry, NODE *result, VALUE memos, int memo_index) {
1893
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
1894
    result->u1.value = rb_funcall(entry->memo, id_eqq, 1, result->u2.value);
1623 1895

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

  
1900
    return result;
1628 1901
}
1629 1902

  
1630 1903
static VALUE
1631 1904
lazy_grep(VALUE obj, VALUE pattern)
1632 1905
{
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);
1906
    VALUE new_enum, entry;
1907

  
1908
    new_enum = lazy_copy(0, 0, obj);
1909
    entry = lazy_add_proc(new_enum, pattern, rb_block_given_p() ?
1910
					 lazy_grep_iter : lazy_grep_func);
1911
    lazy_proc_entry_set_method(entry, rb_ary_new3(1, pattern), 0);
1912

  
1913
    return new_enum;
1638 1914
}
1639 1915

  
1640 1916
static VALUE
......
1730 2006
}
1731 2007

  
1732 2008
static VALUE
1733
lazy_take_func(VALUE val, VALUE args, int argc, VALUE *argv)
2009
lazy_take_size(VALUE entry, VALUE receiver)
2010
{
2011
    long len = NUM2LONG(RARRAY_AREF(rb_ivar_get(entry, id_arguments), 0));
2012
    if (NIL_P(receiver) || (FIXNUM_P(receiver) && FIX2LONG(receiver) < len))
2013
	return receiver;
2014
    return LONG2NUM(len);
2015
}
2016

  
2017
static NODE *
2018
lazy_take_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index)
1734 2019
{
1735 2020
    long remain;
1736
    VALUE memo = rb_attr_get(argv[0], id_memo);
2021
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
2022
    VALUE memo = rb_ary_entry(memos, memo_index);
2023

  
1737 2024
    if (NIL_P(memo)) {
1738
	memo = args;
2025
	memo = entry->memo;
1739 2026
    }
1740 2027

  
1741
    rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
1742
    if ((remain = NUM2LONG(memo)-1) == 0) {
1743
	return Qundef;
2028
    remain = NUM2LONG(memo);
2029
    if (remain == 0) {
2030
        result->u1.value = Qfalse;
2031
        result->u3.value = Qtrue;
2032
    } else if(--remain == 0) {
2033
        result->u3.value = Qtrue;
1744 2034
    }
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);
2035
    rb_ary_store(memos, memo_index, LONG2NUM(remain));
2036
    return result;
1759 2037
}
1760 2038

  
1761 2039
static VALUE
1762 2040
lazy_take(VALUE obj, VALUE n)
1763 2041
{
1764 2042
    long len = NUM2LONG(n);
1765
    VALUE lazy;
2043
    VALUE new_enum;
2044
    int argc = 0;
2045
    VALUE argv[2];
2046
    VALUE entry;
1766 2047

  
1767 2048
    if (len < 0) {
1768 2049
	rb_raise(rb_eArgError, "attempt to take negative size");
1769 2050
    }
2051

  
1770 2052
    if (len == 0) {
1771
	VALUE len = INT2FIX(0);
1772
	lazy = lazy_to_enum_i(obj, sym_cycle, 1, &len, 0);
2053
       argv[0] = sym_cycle;
2054
       argv[1] = INT2NUM(0);
2055
       argc = 2;
1773 2056
    }
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);
2057

  
2058
    new_enum = lazy_copy(argc, argv, obj);
2059
    entry = lazy_add_proc(new_enum, n, lazy_take_func);
2060
    lazy_proc_entry_set_method(entry, rb_ary_new3(1, n), lazy_take_size);
2061

  
2062
    return new_enum;
1779 2063
}
1780 2064

  
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;
2065
static NODE *
2066
lazy_take_while_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index) {
2067
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
2068
    result->u1.value = rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil);
2069
    if (!RTEST(result->u1.value)) {
2070
        result->u1.value = Qfalse;
2071
        result->u2.value = Qundef;
2072
        result->u3.value = Qtrue;
2073
    }
2074
    return result;
1788 2075
}
1789 2076

  
1790 2077
static VALUE
1791 2078
lazy_take_while(VALUE obj)
1792 2079
{
2080
    VALUE new_enum, entry;
2081

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

  
2086
    new_enum = lazy_copy(0, 0, obj);
2087
    entry = lazy_add_proc(new_enum, Qnil, lazy_take_while_func);
2088
    lazy_proc_entry_set_method(entry, Qnil, 0);
2089

  
2090
    return new_enum;
1799 2091
}
1800 2092

  
1801 2093
static VALUE
1802
lazy_drop_size(VALUE generator, VALUE args, VALUE lazy)
2094
lazy_drop_size(VALUE proc_entry, VALUE receiver)
1803 2095
{
1804
    long len = NUM2LONG(RARRAY_AREF(rb_ivar_get(lazy, id_arguments), 0));
1805
    VALUE receiver = lazy_size(lazy);
2096
    long len = NUM2LONG(RARRAY_AREF(rb_ivar_get(proc_entry, id_arguments), 0));
1806 2097
    if (NIL_P(receiver))
1807 2098
	return receiver;
1808 2099
    if (FIXNUM_P(receiver)) {
......
1812 2103
    return rb_funcall(receiver, '-', 1, LONG2NUM(len));
1813 2104
}
1814 2105

  
1815
static VALUE
1816
lazy_drop_func(VALUE val, VALUE args, int argc, VALUE *argv)
2106
static NODE *
2107
lazy_drop_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index)
1817 2108
{
1818 2109
    long remain;
1819
    VALUE memo = rb_attr_get(argv[0], id_memo);
2110
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
2111
    VALUE memo = rb_ary_entry(memos, memo_index);
2112

  
1820 2113
    if (NIL_P(memo)) {
1821
	memo = args;
2114
	memo = entry->memo;
1822 2115
    }
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));
2116
    remain = NUM2LONG(memo);
2117
    if (remain-- > 0) {
2118
        result->u1.value = Qfalse;
2119
	rb_ary_store(memos, memo_index, LONG2NUM(remain));
1828 2120
    }
1829
    return Qnil;
2121

  
2122
    return result;
1830 2123
}
1831 2124

  
1832 2125
static VALUE
1833 2126
lazy_drop(VALUE obj, VALUE n)
1834 2127
{
1835 2128
    long len = NUM2LONG(n);
2129
    VALUE new_enum, entry;
2130
    VALUE argv[2];
2131
    argv[0] = sym_each;
2132
    argv[1] = n;
1836 2133

  
1837 2134
    if (len < 0) {
1838 2135
	rb_raise(rb_eArgError, "attempt to drop negative size");
1839 2136
    }
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);
2137

  
2138
    new_enum = lazy_copy(2, argv, obj);
2139
    entry = lazy_add_proc(new_enum, n, lazy_drop_func);
2140
    lazy_proc_entry_set_method(entry, rb_ary_new3(1, n), lazy_drop_size);
2141

  
2142
    return new_enum;
1843 2143
}
1844 2144

  
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);
2145
static NODE *
2146
lazy_drop_while_func(VALUE proc_entry, NODE* result, VALUE memos, int memo_index) {
2147
    struct proc_entry *entry = proc_entry_ptr(proc_entry);
2148
    VALUE memo = rb_ary_entry(memos, memo_index);
2149

  
2150
    if(NIL_P(memo)) {
2151
        memo = entry->memo;
1851 2152
    }
1852
    if (memo == Qtrue) {
1853
	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
2153

  
2154
    if (!RTEST(memo)) {
2155
        result->u1.value = !RTEST(rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil));
2156
        if (result->u1.value) {
2157
            rb_ary_store(memos, memo_index, Qtrue);
2158
        }
1854 2159
    }
1855
    return Qnil;
2160
    return result;
1856 2161
}
1857 2162

  
1858 2163
static VALUE
1859 2164
lazy_drop_while(VALUE obj)
1860 2165
{
2166
    VALUE new_enum, entry;
2167

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

  
2172
    new_enum = lazy_copy(0, 0, obj);
2173
    entry = lazy_add_proc(new_enum, Qfalse, lazy_drop_while_func);
2174
    lazy_proc_entry_set_method(entry, Qnil, 0);
2175

  
2176
    return new_enum;
1867 2177
}
1868 2178

  
1869 2179
static VALUE