Project

General

Profile

Feature #6183 » 26_07_2013.diff

gregolsen (Innokenty Mikhailov), 06/26/2013 07:20 PM

View differences:

enumerator.c
VALUE stop_exc;
VALUE size;
VALUE (*size_fn)(ANYARGS);
VALUE procs;
};
static VALUE rb_cGenerator, rb_cYielder;
struct generator {
VALUE proc;
VALUE obj;
VALUE hybrid;
};
struct yielder {
VALUE proc;
};
struct proc_entry {
VALUE proc;
VALUE memo;
NODE * (*proc_fn)(ANYARGS);
VALUE (*size_fn)(ANYARGS);
};
static VALUE generator_allocate(VALUE klass);
static VALUE generator_init(VALUE obj, VALUE proc);
......
rb_gc_mark(ptr->feedvalue);
rb_gc_mark(ptr->stop_exc);
rb_gc_mark(ptr->size);
rb_gc_mark(ptr->procs);
}
#define enumerator_free RUBY_TYPED_DEFAULT_FREE
......
return ptr;
}
static void
proc_entry_mark(void *p)
{
struct proc_entry *ptr = p;
rb_gc_mark(ptr->proc);
rb_gc_mark(ptr->memo);
}
#define proc_entry_free RUBY_TYPED_DEFAULT_FREE
static size_t
proc_entry_memsize(const void *p)
{
return p ? sizeof(struct proc_entry) : 0;
}
static const rb_data_type_t proc_entry_data_type = {
"proc_entry",
{
proc_entry_mark,
proc_entry_free,
proc_entry_memsize,
},
};
static struct proc_entry *
proc_entry_ptr(VALUE proc_entry) {
struct proc_entry *ptr;
TypedData_Get_Struct(proc_entry, struct proc_entry, &proc_entry_data_type, ptr);
return ptr;
}
/*
* call-seq:
* obj.to_enum(method = :each, *args) -> enum
......
return obj;
}
static VALUE append_method(VALUE obj, VALUE str, ID default_method, VALUE default_args);
static struct generator * generator_ptr(VALUE obj);
static VALUE
inspect_enumerator(VALUE obj, VALUE dummy, int recur)
append_method(VALUE obj, VALUE str, ID default_method)
{
struct enumerator *e;
VALUE eobj, str, cname;
VALUE method;
TypedData_Get_Struct(obj, struct enumerator, &enumerator_data_type, e);
method = rb_attr_get(obj, id_method);
if (NIL_P(method)) {
rb_str_buf_cat2(str, ":");
rb_str_buf_cat2(str, rb_id2name(default_method));
}
else if (method != Qfalse) {
Check_Type(method, T_SYMBOL);
rb_str_buf_cat2(str, ":");
rb_str_buf_cat2(str, rb_id2name(SYM2ID(method)));
}
return str;
}
cname = rb_obj_class(obj);
static VALUE
append_args(VALUE obj, VALUE str, VALUE default_args)
{
VALUE eargs;
int tainted, untrusted;
if (!e || e->obj == Qundef) {
return rb_sprintf("#<%"PRIsVALUE": uninitialized>", rb_class_path(cname));
eargs = rb_attr_get(obj, id_arguments);
if (NIL_P(eargs)) {
eargs = default_args;
}
if (eargs != Qfalse) {
long argc = RARRAY_LEN(eargs);
VALUE *argv = RARRAY_PTR(eargs);
if (recur) {
str = rb_sprintf("#<%"PRIsVALUE": ...>", rb_class_path(cname));
OBJ_TAINT(str);
return str;
}
if (argc > 0) {
rb_str_buf_cat2(str, "(");
eobj = rb_attr_get(obj, id_receiver);
if (NIL_P(eobj)) {
eobj = e->obj;
}
while (argc--) {
VALUE arg = *argv++;
/* (1..100).each_cons(2) => "#<Enumerator: 1..100:each_cons(2)>" */
str = rb_sprintf("#<%"PRIsVALUE": %+"PRIsVALUE, rb_class_path(cname), eobj);
append_method(obj, str, e->meth, e->args);
rb_str_concat(str, rb_inspect(arg));
rb_str_buf_cat2(str, argc > 0 ? ", " : ")");
rb_str_buf_cat2(str, ">");
if (OBJ_TAINTED(arg)) tainted = TRUE;
if (OBJ_UNTRUSTED(arg)) untrusted = TRUE;
}
}
}
if (tainted) { OBJ_TAINT(str); }
if (untrusted) { OBJ_UNTRUST(str); }
return str;
}
static VALUE
append_method(VALUE obj, VALUE str, ID default_method, VALUE default_args)
inspect_enumerator(VALUE obj, VALUE dummy, int recur)
{
VALUE method, eargs;
struct enumerator *e;
struct generator *g;
const char *cname;
VALUE eobj, str;
int tainted, untrusted;
int i;
method = rb_attr_get(obj, id_method);
if (method != Qfalse) {
ID mid = default_method;
if (!NIL_P(method)) {
Check_Type(method, T_SYMBOL);
mid = SYM2ID(method);
}
rb_str_buf_cat2(str, ":");
rb_str_buf_append(str, rb_id2str(mid));
TypedData_Get_Struct(obj, struct enumerator, &enumerator_data_type, e);
cname = rb_obj_classname(obj);
if (!e || e->obj == Qundef) {
return rb_sprintf("#<%"PRIsVALUE": uninitialized>", rb_class_path(cname));
}
eargs = rb_attr_get(obj, id_arguments);
if (NIL_P(eargs)) {
eargs = default_args;
if (recur) {
str = rb_sprintf("#<%"PRIsVALUE": ...>", rb_class_path(cname));
OBJ_TAINT(str);
return str;
}
if (eargs != Qfalse) {
long argc = RARRAY_LEN(eargs);
VALUE *argv = RARRAY_PTR(eargs);
if (argc > 0) {
rb_str_buf_cat2(str, "(");
if (e->procs) {
g = generator_ptr(e->obj);
eobj = g->obj;
} else {
eobj = rb_attr_get(obj, id_receiver);
if (NIL_P(eobj)) {
eobj = e->obj;
}
}
while (argc--) {
VALUE arg = *argv++;
tainted = OBJ_TAINTED(eobj);
untrusted = OBJ_UNTRUSTED(eobj);
rb_str_append(str, rb_inspect(arg));
rb_str_buf_cat2(str, argc > 0 ? ", " : ")");
OBJ_INFECT(str, arg);
}
}
/* (1..100).each_cons(2) => "#<Enumerator: 1..100:each_cons(2)>"
* In case procs chained enumerator traversing all proc entries manually
*/
if (e->procs) {
if (strcmp(rb_obj_classname(eobj), cname) == 0) {
str = rb_inspect(eobj);
} else {
str = rb_sprintf("#<%s: ", cname);
rb_str_concat(str, rb_inspect(eobj));
rb_str_buf_cat2(str, ">");
}
for (i = 0; i < RARRAY_LEN(e->procs); i++) {
str = rb_str_concat(rb_sprintf("#<%s: ", cname), str);
append_method(RARRAY_AREF(e->procs, i), str, e->meth);
append_args(RARRAY_AREF(e->procs, i), str, e->args);
rb_str_buf_cat2(str, ">");
}
} else {
str = rb_sprintf("#<%s: ", cname);
rb_str_concat(str, rb_inspect(eobj));
append_method(obj, str, e->meth);
append_args(obj, str, e->args);
rb_str_buf_cat2(str, ">");
}
if (tainted) OBJ_TAINT(str);
if (untrusted) OBJ_UNTRUST(str);
return str;
}
......
* (1..100).drop_while.size # => nil
*/
static struct generator * generator_ptr(VALUE obj);
static VALUE
enumerator_size(VALUE obj)
{
struct enumerator *e = enumerator_ptr(obj);
if (e->size_fn) {
return (*e->size_fn)(e->obj, e->args, obj);
}
if (rb_obj_is_proc(e->size)) {
if (e->args)
return rb_proc_call(e->size, e->args);
else
return rb_proc_call_with_block(e->size, 0, 0, Qnil);
long i = 0;
struct generator *g;
struct proc_entry *entry;
VALUE receiver;
if (e->procs) {
g = generator_ptr(e->obj);
receiver = rb_check_funcall(g->obj, id_size, 0, 0);
for(i = 0; i < RARRAY_LEN(e->procs); i++) {
entry = proc_entry_ptr(RARRAY_AREF(e->procs, i));
if (entry->size_fn) {
receiver = (*entry->size_fn)(RARRAY_AREF(e->procs, i), receiver);
} else {
return Qnil;
}
}
return receiver;
} else {
if (e->size_fn) {
return (*e->size_fn)(e->obj, e->args, obj);
}
if (rb_obj_is_proc(e->size)) {
if (e->args)
return rb_proc_call(e->size, e->args);
else
return rb_proc_call_with_block(e->size, 0, 0, Qnil);
}
return e->size;
}
return e->size;
}
/*
......
{
struct generator *ptr = p;
rb_gc_mark(ptr->proc);
rb_gc_mark(ptr->obj);
rb_gc_mark(ptr->hybrid);
}
#define generator_free RUBY_TYPED_DEFAULT_FREE
......
}
/* Lazy Enumerator methods */
static VALUE
enum_size(VALUE self)
{
VALUE r = rb_check_funcall(self, id_size, 0, 0);
VALUE r;
r = rb_check_funcall(self, id_size, 0, 0);
return (r == Qundef) ? Qnil : r;
}
......
return Qnil;
}
static VALUE
lazy_init_yielder(VALUE val, VALUE m, int argc, VALUE *argv)
{
VALUE yielder = RARRAY_AREF(m, 0);
VALUE procs_array = RARRAY_AREF(m, 1);
struct proc_entry *entry;
VALUE memos = rb_attr_get(yielder, id_memo);
long i = 0;
NODE *result;
result = NEW_MEMO(Qtrue, rb_enum_values_pack(argc, argv), Qfalse);
for (i = 0; i < RARRAY_LEN(procs_array); i++) {
entry = proc_entry_ptr(RARRAY_AREF(procs_array, i));
if (RTEST(result->u1.value)) {
(*entry->proc_fn)(RARRAY_AREF(procs_array, i), result, memos, i);
}
}
if (RTEST(result->u1.value)) {
rb_funcall2(yielder, id_yield, 1, &(result->u2.value));
}
if (RTEST(result->u3.value)) {
rb_iter_break();
}
return result->u2.value;
return Qnil;
}
static VALUE
lazy_init_block(VALUE val, VALUE m, int argc, VALUE *argv)
{
VALUE procs = RARRAY_AREF(m, 1);
rb_ivar_set(val, id_memo, rb_ary_new2(RARRAY_LEN(procs)));
rb_block_call(RARRAY_AREF(m, 0), id_each, 0, 0,
lazy_init_yielder, rb_ary_new3(2, val, procs));
return Qnil;
}
static VALUE
lazy_generator_init(VALUE enumerator, VALUE procs)
{
VALUE generator;
VALUE obj;
struct generator *gen_ptr;
struct generator *old_gen_ptr;
struct enumerator *e = enumerator_ptr(enumerator);
if (RARRAY_LEN(procs) > 0) {
old_gen_ptr = generator_ptr(e->obj);
if (old_gen_ptr->hybrid) {
obj = enumerator;
} else {
obj = old_gen_ptr->obj;
}
} else {
obj = enumerator;
}
generator = generator_allocate(rb_cGenerator);
rb_block_call(generator, id_initialize, 0, 0,
lazy_init_block, rb_ary_new3(2, obj, procs));
gen_ptr = generator_ptr(generator);
gen_ptr->obj = obj;
return generator;
}
static VALUE
create_proc_entry(VALUE memo, NODE * (*proc_fn)(ANYARGS))
{
struct proc_entry *entry;
VALUE entry_obj;
entry_obj = TypedData_Make_Struct(rb_cObject, struct proc_entry,
&proc_entry_data_type, entry);
if (rb_block_given_p()) {
entry->proc = rb_block_proc();
}
entry->proc_fn = proc_fn;
entry->memo = memo;
return entry_obj;
}
static VALUE
lazy_add_proc(VALUE enum_obj, VALUE memo, NODE * (*proc_fn)(ANYARGS))
{
struct enumerator *ptr;
VALUE entry;
entry = create_proc_entry(memo, proc_fn);
ptr = enumerator_ptr(enum_obj);
rb_ary_push(ptr->procs, entry);
return entry;
}
/*
* call-seq:
* Lazy.new(obj, size=nil) { |yielder, *values| ... }
......
}
static VALUE
lazy_proc_entry_set_method(VALUE proc_entry, VALUE args, VALUE (*size_fn)(ANYARGS)) {
ID id = rb_frame_this_func();
struct proc_entry *e = proc_entry_ptr(proc_entry);
rb_ivar_set(proc_entry, id_method, ID2SYM(id));
if (NIL_P(args)) {
/* Qfalse indicates that the arguments are empty */
rb_ivar_set(proc_entry, id_arguments, Qfalse);
}
else {
rb_ivar_set(proc_entry, id_arguments, args);
}
e->size_fn = size_fn;
return proc_entry;
}
static VALUE
lazy_set_method(VALUE lazy, VALUE args, VALUE (*size_fn)(ANYARGS))
{
ID id = rb_frame_this_func();
......
return lazy;
}
static VALUE
lazy_copy(int argc, VALUE *argv, VALUE obj)
{
struct enumerator *new_e;
struct generator *g;
VALUE new_obj;
VALUE new_generator;
VALUE new_procs;
struct enumerator *e = enumerator_ptr(obj);
if (RTEST(e->procs)) {
new_procs = rb_ary_new4(RARRAY_LEN(e->procs), RARRAY_PTR(e->procs));
} else {
new_procs = rb_ary_new();
}
new_generator = lazy_generator_init(obj, new_procs);
g = generator_ptr(new_generator);
g->hybrid = Qfalse;
new_obj = enumerator_init_copy(enumerator_allocate(rb_cLazy), obj);
new_e = enumerator_ptr(new_obj);
new_e->obj = new_generator;
new_e->procs = new_procs;
new_e->meth = rb_to_id(sym_each);
if (argc > 0) {
new_e->meth = rb_to_id(*argv++);
new_e->args = rb_ary_new4(argc - 1, argv);
} else {
new_e->meth = id_each;
new_e->args = rb_ary_new4(argc, argv);
}
return new_obj;
}
/*
* call-seq:
* e.lazy -> lazy_enumerator
......
}
static VALUE
lazy_map_func(VALUE val, VALUE m, int argc, VALUE *argv)
lazy_map_size(VALUE entry, VALUE receiver)
{
VALUE result = rb_yield_values2(argc - 1, &argv[1]);
return receiver;
}
rb_funcall(argv[0], id_yield, 1, result);
return Qnil;
static NODE *
lazy_map_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index)
{
struct proc_entry *entry = proc_entry_ptr(proc_entry);
result->u2.value = rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil);
return result;
}
static VALUE
lazy_map(VALUE obj)
{
VALUE new_enum;
VALUE entry;
if (!rb_block_given_p()) {
rb_raise(rb_eArgError, "tried to call lazy map without a block");
}
return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
lazy_map_func, 0),
Qnil, lazy_receiver_size);
new_enum = lazy_copy(0, 0, obj);
entry = lazy_add_proc(new_enum, Qnil, lazy_map_func);
lazy_proc_entry_set_method(entry, Qnil, lazy_map_size);
return new_enum;
}
static VALUE
......
Qnil, 0);
}
static VALUE
lazy_select_func(VALUE val, VALUE m, int argc, VALUE *argv)
static NODE *
lazy_select_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index)
{
VALUE element = rb_enum_values_pack(argc - 1, argv + 1);
if (RTEST(rb_yield(element))) {
return rb_funcall(argv[0], id_yield, 1, element);
}
return Qnil;
struct proc_entry *entry = proc_entry_ptr(proc_entry);
result->u1.value = rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil);
return result;
}
static VALUE
lazy_select(VALUE obj)
{
VALUE new_enum;
VALUE entry;
if (!rb_block_given_p()) {
rb_raise(rb_eArgError, "tried to call lazy select without a block");
}
return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
lazy_select_func, 0),
Qnil, 0);
new_enum = lazy_copy(0, 0, obj);
entry = lazy_add_proc(new_enum, Qnil, lazy_select_func);
lazy_proc_entry_set_method(entry, Qnil, 0);
return new_enum;
}
static VALUE
lazy_reject_func(VALUE val, VALUE m, int argc, VALUE *argv)
{
VALUE element = rb_enum_values_pack(argc - 1, argv + 1);
if (!RTEST(rb_yield(element))) {
return rb_funcall(argv[0], id_yield, 1, element);
}
return Qnil;
static NODE *
lazy_reject_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index) {
struct proc_entry *entry = proc_entry_ptr(proc_entry);
result->u1.value = !RTEST(rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil));
return result;
}
static VALUE
lazy_reject(VALUE obj)
{
VALUE new_enum, entry;
if (!rb_block_given_p()) {
rb_raise(rb_eArgError, "tried to call lazy reject without a block");
}
return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
lazy_reject_func, 0),
Qnil, 0);
new_enum = lazy_copy(0, 0, obj);
entry = lazy_add_proc(new_enum, Qnil, lazy_reject_func);
lazy_proc_entry_set_method(entry, Qnil, 0);
return new_enum;
}
static VALUE
lazy_grep_func(VALUE val, VALUE m, int argc, VALUE *argv)
{
VALUE i = rb_enum_values_pack(argc - 1, argv + 1);
VALUE result = rb_funcall(m, id_eqq, 1, i);
if (RTEST(result)) {
rb_funcall(argv[0], id_yield, 1, i);
}
return Qnil;
static NODE *
lazy_grep_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index) {
struct proc_entry *entry = proc_entry_ptr(proc_entry);
result->u1.value = rb_funcall(entry->memo, id_eqq, 1, result->u2.value);
return result;
}
static VALUE
lazy_grep_iter(VALUE val, VALUE m, int argc, VALUE *argv)
{
VALUE i = rb_enum_values_pack(argc - 1, argv + 1);
VALUE result = rb_funcall(m, id_eqq, 1, i);
static NODE *
lazy_grep_iter(VALUE proc_entry, NODE *result, VALUE memos, int memo_index) {
struct proc_entry *entry = proc_entry_ptr(proc_entry);
result->u1.value = rb_funcall(entry->memo, id_eqq, 1, result->u2.value);
if (RTEST(result)) {
rb_funcall(argv[0], id_yield, 1, rb_yield(i));
if (RTEST(result->u1.value)) {
result->u2.value = rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil);
}
return Qnil;
return result;
}
static VALUE
lazy_grep(VALUE obj, VALUE pattern)
{
return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
rb_block_given_p() ?
lazy_grep_iter : lazy_grep_func,
pattern),
rb_ary_new3(1, pattern), 0);
VALUE new_enum, entry;
new_enum = lazy_copy(0, 0, obj);
entry = lazy_add_proc(new_enum, pattern, rb_block_given_p() ?
lazy_grep_iter : lazy_grep_func);
lazy_proc_entry_set_method(entry, rb_ary_new3(1, pattern), 0);
return new_enum;
}
static VALUE
......
}
static VALUE
lazy_take_func(VALUE val, VALUE args, int argc, VALUE *argv)
lazy_take_size(VALUE entry, VALUE receiver)
{
long len = NUM2LONG(RARRAY_AREF(rb_ivar_get(entry, id_arguments), 0));
if (NIL_P(receiver) || (FIXNUM_P(receiver) && FIX2LONG(receiver) < len))
return receiver;
return LONG2NUM(len);
}
static NODE *
lazy_take_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index)
{
long remain;
VALUE memo = rb_attr_get(argv[0], id_memo);
struct proc_entry *entry = proc_entry_ptr(proc_entry);
VALUE memo = rb_ary_entry(memos, memo_index);
if (NIL_P(memo)) {
memo = args;
memo = entry->memo;
}
rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
if ((remain = NUM2LONG(memo)-1) == 0) {
return Qundef;
remain = NUM2LONG(memo);
if (remain == 0) {
result->u1.value = Qfalse;
result->u3.value = Qtrue;
} else if(--remain == 0) {
result->u3.value = Qtrue;
}
else {
rb_ivar_set(argv[0], id_memo, LONG2NUM(remain));
return Qnil;
}
}
static VALUE
lazy_take_size(VALUE generator, VALUE args, VALUE lazy)
{
VALUE receiver = lazy_size(lazy);
long len = NUM2LONG(RARRAY_AREF(rb_ivar_get(lazy, id_arguments), 0));
if (NIL_P(receiver) || (FIXNUM_P(receiver) && FIX2LONG(receiver) < len))
return receiver;
return LONG2NUM(len);
rb_ary_store(memos, memo_index, LONG2NUM(remain));
return result;
}
static VALUE
lazy_take(VALUE obj, VALUE n)
{
long len = NUM2LONG(n);
VALUE lazy;
VALUE new_enum;
int argc = 0;
VALUE argv[2];
VALUE entry;
if (len < 0) {
rb_raise(rb_eArgError, "attempt to take negative size");
}
if (len == 0) {
VALUE len = INT2FIX(0);
lazy = lazy_to_enum_i(obj, sym_cycle, 1, &len, 0);
argv[0] = sym_cycle;
argv[1] = INT2NUM(0);
argc = 2;
}
else {
lazy = rb_block_call(rb_cLazy, id_new, 1, &obj,
lazy_take_func, n);
}
return lazy_set_method(lazy, rb_ary_new3(1, n), lazy_take_size);
new_enum = lazy_copy(argc, argv, obj);
entry = lazy_add_proc(new_enum, n, lazy_take_func);
lazy_proc_entry_set_method(entry, rb_ary_new3(1, n), lazy_take_size);
return new_enum;
}
static VALUE
lazy_take_while_func(VALUE val, VALUE args, int argc, VALUE *argv)
{
VALUE result = rb_yield_values2(argc - 1, &argv[1]);
if (!RTEST(result)) return Qundef;
rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
return Qnil;
static NODE *
lazy_take_while_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index) {
struct proc_entry *entry = proc_entry_ptr(proc_entry);
result->u1.value = rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil);
if (!RTEST(result->u1.value)) {
result->u1.value = Qfalse;
result->u2.value = Qundef;
result->u3.value = Qtrue;
}
return result;
}
static VALUE
lazy_take_while(VALUE obj)
{
VALUE new_enum, entry;
if (!rb_block_given_p()) {
rb_raise(rb_eArgError, "tried to call lazy take_while without a block");
}
return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
lazy_take_while_func, 0),
Qnil, 0);
new_enum = lazy_copy(0, 0, obj);
entry = lazy_add_proc(new_enum, Qnil, lazy_take_while_func);
lazy_proc_entry_set_method(entry, Qnil, 0);
return new_enum;
}
static VALUE
lazy_drop_size(VALUE generator, VALUE args, VALUE lazy)
lazy_drop_size(VALUE proc_entry, VALUE receiver)
{
long len = NUM2LONG(RARRAY_AREF(rb_ivar_get(lazy, id_arguments), 0));
VALUE receiver = lazy_size(lazy);
long len = NUM2LONG(RARRAY_AREF(rb_ivar_get(proc_entry, id_arguments), 0));
if (NIL_P(receiver))
return receiver;
if (FIXNUM_P(receiver)) {
......
return rb_funcall(receiver, '-', 1, LONG2NUM(len));
}
static VALUE
lazy_drop_func(VALUE val, VALUE args, int argc, VALUE *argv)
static NODE *
lazy_drop_func(VALUE proc_entry, NODE *result, VALUE memos, int memo_index)
{
long remain;
VALUE memo = rb_attr_get(argv[0], id_memo);
struct proc_entry *entry = proc_entry_ptr(proc_entry);
VALUE memo = rb_ary_entry(memos, memo_index);
if (NIL_P(memo)) {
memo = args;
memo = entry->memo;
}
if ((remain = NUM2LONG(memo)) == 0) {
rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
}
else {
rb_ivar_set(argv[0], id_memo, LONG2NUM(--remain));
remain = NUM2LONG(memo);
if (remain-- > 0) {
result->u1.value = Qfalse;
rb_ary_store(memos, memo_index, LONG2NUM(remain));
}
return Qnil;
return result;
}
static VALUE
lazy_drop(VALUE obj, VALUE n)
{
long len = NUM2LONG(n);
VALUE new_enum, entry;
VALUE argv[2];
argv[0] = sym_each;
argv[1] = n;
if (len < 0) {
rb_raise(rb_eArgError, "attempt to drop negative size");
}
return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
lazy_drop_func, n),
rb_ary_new3(1, n), lazy_drop_size);
new_enum = lazy_copy(2, argv, obj);
entry = lazy_add_proc(new_enum, n, lazy_drop_func);
lazy_proc_entry_set_method(entry, rb_ary_new3(1, n), lazy_drop_size);
return new_enum;
}
static VALUE
lazy_drop_while_func(VALUE val, VALUE args, int argc, VALUE *argv)
{
VALUE memo = rb_attr_get(argv[0], id_memo);
if (NIL_P(memo) && !RTEST(rb_yield_values2(argc - 1, &argv[1]))) {
rb_ivar_set(argv[0], id_memo, memo = Qtrue);
static NODE *
lazy_drop_while_func(VALUE proc_entry, NODE* result, VALUE memos, int memo_index) {
struct proc_entry *entry = proc_entry_ptr(proc_entry);
VALUE memo = rb_ary_entry(memos, memo_index);
if(NIL_P(memo)) {
memo = entry->memo;
}
if (memo == Qtrue) {
rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
if (!RTEST(memo)) {
result->u1.value = !RTEST(rb_proc_call_with_block(entry->proc, 1, &(result->u2.value), Qnil));
if (result->u1.value) {
rb_ary_store(memos, memo_index, Qtrue);
}
}
return Qnil;
return result;
}
static VALUE
lazy_drop_while(VALUE obj)
{
VALUE new_enum, entry;
if (!rb_block_given_p()) {
rb_raise(rb_eArgError, "tried to call lazy drop_while without a block");
}
return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
lazy_drop_while_func, 0),
Qnil, 0);
new_enum = lazy_copy(0, 0, obj);
entry = lazy_add_proc(new_enum, Qfalse, lazy_drop_while_func);
lazy_proc_entry_set_method(entry, Qnil, 0);
return new_enum;
}
static VALUE
(5-5/6)