Feature #6183 » 16.05.2013.diff
| 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 struct generator * generator_ptr(VALUE obj); 
   | 
||
| 
     static VALUE 
   | 
||
| 
     append_method(VALUE obj, VALUE str, ID default_method) 
   | 
||
| 
     { 
   | 
||
| 
         VALUE method; 
   | 
||
| 
         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; 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     append_args(VALUE obj, VALUE str, VALUE default_args) 
   | 
||
| 
     { 
   | 
||
| 
         VALUE eargs; 
   | 
||
| 
         int tainted, untrusted; 
   | 
||
| 
         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 (argc > 0) { 
   | 
||
| 
                 rb_str_buf_cat2(str, "("); 
   | 
||
| 
                 while (argc--) { 
   | 
||
| 
                     VALUE arg = *argv++; 
   | 
||
| 
                     rb_str_concat(str, rb_inspect(arg)); 
   | 
||
| 
                     rb_str_buf_cat2(str, argc > 0 ? ", " : ")"); 
   | 
||
| 
                     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 
   | 
||
| 
     inspect_enumerator(VALUE obj, VALUE dummy, int recur) 
   | 
||
| 
     { 
   | 
||
| 
         struct enumerator *e; 
   | 
||
| 
         struct generator *g; 
   | 
||
| 
         const char *cname; 
   | 
||
| 
         VALUE eobj, eargs, str, method; 
   | 
||
| 
         VALUE eobj, str; 
   | 
||
| 
         int tainted, untrusted; 
   | 
||
| 
         int i; 
   | 
||
| 
         TypedData_Get_Struct(obj, struct enumerator, &enumerator_data_type, e); 
   | 
||
| ... | ... | |
| 
     	return str; 
   | 
||
| 
         } 
   | 
||
| 
         eobj = rb_attr_get(obj, id_receiver); 
   | 
||
| 
         if (NIL_P(eobj)) { 
   | 
||
| 
     	eobj = e->obj; 
   | 
||
| 
         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; 
   | 
||
| 
             } 
   | 
||
| 
         } 
   | 
||
| 
         tainted   = OBJ_TAINTED(eobj); 
   | 
||
| 
         untrusted = OBJ_UNTRUSTED(eobj); 
   | 
||
| 
         /* (1..100).each_cons(2) => "#<Enumerator: 1..100:each_cons(2)>" */ 
   | 
||
| 
         str = rb_sprintf("#<%s: ", cname); 
   | 
||
| 
         rb_str_concat(str, rb_inspect(eobj)); 
   | 
||
| 
         method = rb_attr_get(obj, id_method); 
   | 
||
| 
         if (NIL_P(method)) { 
   | 
||
| 
     	rb_str_buf_cat2(str, ":"); 
   | 
||
| 
     	rb_str_buf_cat2(str, rb_id2name(e->meth)); 
   | 
||
| 
         } 
   | 
||
| 
         else if (method != Qfalse) { 
   | 
||
| 
     	Check_Type(method, T_SYMBOL); 
   | 
||
| 
     	rb_str_buf_cat2(str, ":"); 
   | 
||
| 
     	rb_str_buf_cat2(str, rb_id2name(SYM2ID(method))); 
   | 
||
| 
         } 
   | 
||
| 
         eargs = rb_attr_get(obj, id_arguments); 
   | 
||
| 
         if (NIL_P(eargs)) { 
   | 
||
| 
     	eargs = e->args; 
   | 
||
| 
         } 
   | 
||
| 
         if (eargs != Qfalse) { 
   | 
||
| 
     	long   argc = RARRAY_LEN(eargs); 
   | 
||
| 
     	VALUE *argv = RARRAY_PTR(eargs); 
   | 
||
| 
     	if (argc > 0) { 
   | 
||
| 
     	    rb_str_buf_cat2(str, "("); 
   | 
||
| 
     	    while (argc--) { 
   | 
||
| 
     		VALUE arg = *argv++; 
   | 
||
| 
     		rb_str_concat(str, rb_inspect(arg)); 
   | 
||
| 
     		rb_str_buf_cat2(str, argc > 0 ? ", " : ")"); 
   | 
||
| 
         /* (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); 
   | 
||
| 
     		if (OBJ_TAINTED(arg)) tainted = TRUE; 
   | 
||
| 
     		if (OBJ_UNTRUSTED(arg)) untrusted = TRUE; 
   | 
||
| 
     	    } 
   | 
||
| 
     	} 
   | 
||
| 
             rb_str_buf_cat2(str, ">"); 
   | 
||
| 
         } 
   | 
||
| 
         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; 
   | 
||
| 
         } 
   | 
||
| 
         else { 
   | 
||
| 
     	rb_ivar_set(argv[0], id_memo, LONG2NUM(remain)); 
   | 
||
| 
     	return Qnil; 
   | 
||
| 
         remain = NUM2LONG(memo); 
   | 
||
| 
         if (remain == 0) { 
   | 
||
| 
             result->u1.value = Qfalse; 
   | 
||
| 
             result->u3.value = Qtrue; 
   | 
||
| 
         } else if(--remain == 0) { 
   | 
||
| 
             result->u3.value = Qtrue; 
   | 
||
| 
         } 
   | 
||
| 
     } 
   | 
||
| 
     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); 
   | 
||
| 
         } 
   | 
||
| 
         else { 
   | 
||
| 
     	lazy = rb_block_call(rb_cLazy, id_new, 1, &obj, 
   | 
||
| 
     					 lazy_take_func, n); 
   | 
||
| 
            argv[0] = sym_cycle; 
   | 
||
| 
            argv[1] = INT2NUM(0); 
   | 
||
| 
            argc = 2; 
   | 
||
| 
         } 
   | 
||
| 
         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; 
   | 
||
| 
         } 
   | 
||
| 
         if ((remain = NUM2LONG(memo)) == 0) { 
   | 
||
| 
     	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1); 
   | 
||
| 
     	memo = entry->memo; 
   | 
||
| 
         } 
   | 
||
| 
         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 
   | 
||