Bug #6250 » lazy_enumerator.diff
| enumerator.c | ||
|---|---|---|
| 
         VALUE lookahead; 
   | 
||
| 
         VALUE feedvalue; 
   | 
||
| 
         VALUE stop_exc; 
   | 
||
| 
         VALUE lazy; 
   | 
||
| 
         VALUE procs; 
   | 
||
| 
     }; 
   | 
||
| 
     static VALUE rb_cGenerator, rb_cYielder; 
   | 
||
| ... | ... | |
| 
     static VALUE generator_allocate(VALUE klass); 
   | 
||
| 
     static VALUE generator_init(VALUE obj, VALUE proc); 
   | 
||
| 
     static VALUE process_element(struct enumerator *e, VALUE result); 
   | 
||
| 
     /* 
   | 
||
| 
      * Enumerator 
   | 
||
| 
      */ 
   | 
||
| ... | ... | |
| 
     } 
   | 
||
| 
     /* Lazy Enumerator methods */ 
   | 
||
| 
     struct proc_entry { 
   | 
||
| 
         VALUE proc; 
   | 
||
| 
         VALUE type; 
   | 
||
| 
     }; 
   | 
||
| 
     enum proc_entry_type { 
   | 
||
| 
         T_PROC_MAP = 0, 
   | 
||
| 
         T_PROC_SELECT = 1 
   | 
||
| 
     }; 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_init_iterator(VALUE val, VALUE m, int argc, VALUE *argv) 
   | 
||
| 
     { 
   | 
||
| 
         VALUE result; 
   | 
||
| 
         if (argc == 1) { 
   | 
||
| 
     	VALUE args[2]; 
   | 
||
| 
     	args[0] = m; 
   | 
||
| 
     	args[1] = val; 
   | 
||
| 
     	result = rb_yield_values2(2, args); 
   | 
||
| 
     process_element(struct enumerator *e, VALUE result) 
   | 
||
| 
     { 
   | 
||
| 
         struct proc_entry *entry; 
   | 
||
| 
         VALUE move_next = Qtrue; 
   | 
||
| 
         VALUE *procs = RARRAY_PTR(e->procs); 
   | 
||
| 
         long procs_number = RARRAY_LENINT(e->procs); 
   | 
||
| 
         long i = 0; 
   | 
||
| 
         for (i = 0; i < procs_number; i++) { 
   | 
||
| 
             Data_Get_Struct(procs[i], struct proc_entry, entry); 
   | 
||
| 
             switch ((enum proc_entry_type) entry->type) { 
   | 
||
| 
                 case T_PROC_MAP: 
   | 
||
| 
                     result = rb_funcall(entry->proc, rb_intern("call"), 1, result); 
   | 
||
| 
                     break; 
   | 
||
| 
                 case T_PROC_SELECT: 
   | 
||
| 
                     if (RTEST(move_next)) { 
   | 
||
| 
                         move_next = rb_funcall(entry->proc, rb_intern("call"), 1, result); 
   | 
||
| 
                     } 
   | 
||
| 
                     break; 
   | 
||
| 
             } 
   | 
||
| 
         } 
   | 
||
| 
         else { 
   | 
||
| 
     	VALUE args; 
   | 
||
| 
     	int len = rb_long2int((long)argc + 1); 
   | 
||
| 
     	args = rb_ary_tmp_new(len); 
   | 
||
| 
     	rb_ary_push(args, m); 
   | 
||
| 
     	if (argc > 0) { 
   | 
||
| 
     	    rb_ary_cat(args, argv, argc); 
   | 
||
| 
     	} 
   | 
||
| 
     	result = rb_yield_values2(len, RARRAY_PTR(args)); 
   | 
||
| 
     	RB_GC_GUARD(args); 
   | 
||
| 
         if (RTEST(move_next)) { 
   | 
||
| 
             return result; 
   | 
||
| 
         } else { 
   | 
||
| 
             return Qundef; 
   | 
||
| 
         } 
   | 
||
| 
         if (result == Qundef) rb_iter_break(); 
   | 
||
| 
         return Qnil; 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_init_yielder(VALUE val, VALUE m, int argc, VALUE *argv) 
   | 
||
| 
     lazy_iterator_block(VALUE val, VALUE m, int argc, VALUE *argv) 
   | 
||
| 
     { 
   | 
||
| 
         VALUE result; 
   | 
||
| 
         result = rb_funcall2(m, id_yield, argc, argv); 
   | 
||
| 
         if (result == Qundef) rb_iter_break(); 
   | 
||
| 
         return Qnil; 
   | 
||
| 
     } 
   | 
||
| 
         VALUE yielder = RARRAY_PTR(m)[0]; 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_init_block_i(VALUE val, VALUE m, int argc, VALUE *argv) 
   | 
||
| 
     { 
   | 
||
| 
         rb_block_call(m, id_each, argc-1, argv+1, lazy_init_iterator, val); 
   | 
||
| 
         return Qnil; 
   | 
||
| 
         result = process_element(enumerator_ptr(RARRAY_PTR(m)[1]), val); 
   | 
||
| 
         if (result != Qundef) { 
   | 
||
| 
             return yielder_yield(yielder, rb_ary_new3(1, result)); 
   | 
||
| 
         } else { 
   | 
||
| 
             return Qnil; 
   | 
||
| 
         } 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_init_block(VALUE val, VALUE m, int argc, VALUE *argv) 
   | 
||
| 
     lazy_generator_block(VALUE val, VALUE m, int argc, VALUE *argv) 
   | 
||
| 
     { 
   | 
||
| 
         rb_block_call(m, id_each, argc-1, argv+1, lazy_init_yielder, val); 
   | 
||
| 
         return Qnil; 
   | 
||
| 
         VALUE obj = RARRAY_PTR(m)[0]; 
   | 
||
| 
         VALUE enumerator = RARRAY_PTR(m)[1]; 
   | 
||
| 
         return rb_block_call(obj, id_each, 0, Qnil, 
   | 
||
| 
                 lazy_iterator_block, rb_ary_new3(2, val, enumerator)); 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_initialize(int argc, VALUE *argv, VALUE self) 
   | 
||
| 
     { 
   | 
||
| 
         VALUE obj, meth; 
   | 
||
| 
         VALUE generator; 
   | 
||
| 
         int offset; 
   | 
||
| 
         VALUE obj; 
   | 
||
| 
         struct enumerator *ptr; 
   | 
||
| 
         if (argc < 1) { 
   | 
||
| 
     	rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..)", argc); 
   | 
||
| 
         } 
   | 
||
| 
         else { 
   | 
||
| 
     	obj = argv[0]; 
   | 
||
| 
     	if (argc == 1) { 
   | 
||
| 
     	    meth = sym_each; 
   | 
||
| 
     	    offset = 1; 
   | 
||
| 
     	} 
   | 
||
| 
     	else { 
   | 
||
| 
     	    meth = argv[1]; 
   | 
||
| 
     	    offset = 2; 
   | 
||
| 
     	} 
   | 
||
| 
         } 
   | 
||
| 
         obj = argv[0]; 
   | 
||
| 
         generator = generator_allocate(rb_cGenerator); 
   | 
||
| 
         rb_block_call(generator, id_initialize, 0, 0, 
   | 
||
| 
     		  (rb_block_given_p() ? lazy_init_block_i : lazy_init_block), 
   | 
||
| 
     		  obj); 
   | 
||
| 
         enumerator_init(self, generator, meth, argc - offset, argv + offset); 
   | 
||
| 
         rb_ivar_set(self, id_receiver, obj); 
   | 
||
| 
         rb_block_call(generator, rb_intern("initialize"), 0, Qnil, 
   | 
||
| 
                 lazy_generator_block, rb_ary_new3(2, obj, self)); 
   | 
||
| 
         enumerator_init(self, generator, sym_each, 0, Qnil); 
   | 
||
| 
         ptr = enumerator_ptr(self); 
   | 
||
| 
         ptr->lazy = Qtrue; 
   | 
||
| 
         ptr->procs = rb_ary_new(); 
   | 
||
| 
         return self; 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_set_method(VALUE lazy, VALUE args) 
   | 
||
| 
     create_proc_entry(enum proc_entry_type proc_type) 
   | 
||
| 
     { 
   | 
||
| 
         ID id = rb_frame_this_func(); 
   | 
||
| 
         rb_ivar_set(lazy, id_method, ID2SYM(id)); 
   | 
||
| 
         if (NIL_P(args)) { 
   | 
||
| 
     	/* Qfalse indicates that the arguments are empty */ 
   | 
||
| 
     	rb_ivar_set(lazy, id_arguments, Qfalse); 
   | 
||
| 
         } 
   | 
||
| 
         else { 
   | 
||
| 
     	rb_ivar_set(lazy, id_arguments, args); 
   | 
||
| 
         } 
   | 
||
| 
         return lazy; 
   | 
||
| 
     } 
   | 
||
| 
         struct proc_entry *entry; 
   | 
||
| 
         VALUE entry_obj; 
   | 
||
| 
     /* 
   | 
||
| 
      * call-seq: 
   | 
||
| 
      *   e.lazy -> lazy_enumerator 
   | 
||
| 
      * 
   | 
||
| 
      * Returns a lazy enumerator, whose methods map/collect, 
   | 
||
| 
      * flat_map/collect_concat, select/find_all, reject, grep, zip, take, 
   | 
||
| 
      * take_while, drop, drop_while, and cycle enumerate values only on an 
   | 
||
| 
      * as-needed basis.  However, if a block is given to zip or cycle, values 
   | 
||
| 
      * are enumerated immediately. 
   | 
||
| 
      * 
   | 
||
| 
      * === Example 
   | 
||
| 
      * 
   | 
||
| 
      * The following program finds pythagorean triples: 
   | 
||
| 
      * 
   | 
||
| 
      *   def pythagorean_triples 
   | 
||
| 
      *     (1..Float::INFINITY).lazy.flat_map {|z| 
   | 
||
| 
      *       (1..z).flat_map {|x| 
   | 
||
| 
      *         (x..z).select {|y| 
   | 
||
| 
      *           x**2 + y**2 == z**2 
   | 
||
| 
      *         }.map {|y| 
   | 
||
| 
      *           [x, y, z] 
   | 
||
| 
      *         } 
   | 
||
| 
      *       } 
   | 
||
| 
      *     } 
   | 
||
| 
      *   end 
   | 
||
| 
      *   # show first ten pythagorean triples 
   | 
||
| 
      *   p pythagorean_triples.take(10).force # take is lazy, so force is needed 
   | 
||
| 
      *   p pythagorean_triples.first(10)      # first is eager 
   | 
||
| 
      *   # show pythagorean triples less than 100 
   | 
||
| 
      *   p pythagorean_triples.take_while { |*, z| z < 100 }.force 
   | 
||
| 
      */ 
   | 
||
| 
     static VALUE 
   | 
||
| 
     enumerable_lazy(VALUE obj) 
   | 
||
| 
     { 
   | 
||
| 
         VALUE result; 
   | 
||
| 
         entry_obj = Data_Make_Struct(rb_cObject, struct proc_entry, 0, RUBY_DEFAULT_FREE, entry); 
   | 
||
| 
         Data_Get_Struct(entry_obj, struct proc_entry, entry); 
   | 
||
| 
         entry->proc = rb_block_proc(); 
   | 
||
| 
         entry->type = proc_type; 
   | 
||
| 
         result = rb_class_new_instance(1, &obj, rb_cLazy); 
   | 
||
| 
         /* Qfalse indicates that the Enumerator::Lazy has no method name */ 
   | 
||
| 
         rb_ivar_set(result, id_method, Qfalse); 
   | 
||
| 
         return result; 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_map_func(VALUE val, VALUE m, int argc, VALUE *argv) 
   | 
||
| 
     { 
   | 
||
| 
         VALUE result = rb_yield_values2(argc - 1, &argv[1]); 
   | 
||
| 
         rb_funcall(argv[0], id_yield, 1, result); 
   | 
||
| 
         return Qnil; 
   | 
||
| 
         return entry_obj; 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_map(VALUE obj) 
   | 
||
| 
     { 
   | 
||
| 
         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); 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_flat_map_i(VALUE i, VALUE yielder, int argc, VALUE *argv) 
   | 
||
| 
     { 
   | 
||
| 
         return rb_funcall2(yielder, id_yield, argc, argv); 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_flat_map_each(VALUE obj) 
   | 
||
| 
     { 
   | 
||
| 
         NODE *memo = RNODE(obj); 
   | 
||
| 
         rb_block_call(memo->u1.value, id_each, 0, 0, lazy_flat_map_i, 
   | 
||
| 
     		  memo->u2.value); 
   | 
||
| 
         return Qnil; 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_flat_map_to_ary(VALUE obj) 
   | 
||
| 
     { 
   | 
||
| 
         NODE *memo = RNODE(obj); 
   | 
||
| 
         VALUE ary = rb_check_array_type(memo->u1.value); 
   | 
||
| 
         if (NIL_P(ary)) { 
   | 
||
| 
     	rb_funcall(memo->u2.value, id_yield, 1, memo->u1.value); 
   | 
||
| 
         } 
   | 
||
| 
         else { 
   | 
||
| 
     	long i; 
   | 
||
| 
     	for (i = 0; i < RARRAY_LEN(ary); i++) { 
   | 
||
| 
     	    rb_funcall(memo->u2.value, id_yield, 1, RARRAY_PTR(ary)[i]); 
   | 
||
| 
     	} 
   | 
||
| 
         } 
   | 
||
| 
         return Qnil; 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_flat_map_func(VALUE val, VALUE m, int argc, VALUE *argv) 
   | 
||
| 
     { 
   | 
||
| 
         VALUE result = rb_yield_values2(argc - 1, &argv[1]); 
   | 
||
| 
         if (TYPE(result) == T_ARRAY) { 
   | 
||
| 
     	long i; 
   | 
||
| 
     	for (i = 0; i < RARRAY_LEN(result); i++) { 
   | 
||
| 
     	    rb_funcall(argv[0], id_yield, 1, RARRAY_PTR(result)[i]); 
   | 
||
| 
     	} 
   | 
||
| 
         } 
   | 
||
| 
         else { 
   | 
||
| 
     	NODE *memo; 
   | 
||
| 
     	memo = NEW_MEMO(result, argv[0], 0); 
   | 
||
| 
     	rb_rescue2(lazy_flat_map_each, (VALUE) memo, 
   | 
||
| 
     		   lazy_flat_map_to_ary, (VALUE) memo, 
   | 
||
| 
     		   rb_eNoMethodError, (VALUE)0); 
   | 
||
| 
         } 
   | 
||
| 
         return Qnil; 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_flat_map(VALUE obj) 
   | 
||
| 
     { 
   | 
||
| 
         if (!rb_block_given_p()) { 
   | 
||
| 
     	rb_raise(rb_eArgError, "tried to call lazy flat_map without a block"); 
   | 
||
| 
         } 
   | 
||
| 
         return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj, 
   | 
||
| 
     					 lazy_flat_map_func, 0), 
   | 
||
| 
     			   Qnil); 
   | 
||
| 
     } 
   | 
||
| 
         struct enumerator *e = enumerator_ptr(obj); 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_select_func(VALUE val, VALUE m, int argc, VALUE *argv) 
   | 
||
| 
     { 
   | 
||
| 
         VALUE element = rb_enum_values_pack(argc - 1, argv + 1); 
   | 
||
| 
         rb_ary_push(e->procs, create_proc_entry(T_PROC_MAP)); 
   | 
||
| 
         if (RTEST(rb_yield(element))) { 
   | 
||
| 
     	return rb_funcall(argv[0], id_yield, 1, element); 
   | 
||
| 
         } 
   | 
||
| 
         return Qnil; 
   | 
||
| 
         return obj; 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_select(VALUE obj) 
   | 
||
| 
     { 
   | 
||
| 
         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); 
   | 
||
| 
     } 
   | 
||
| 
     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 VALUE 
   | 
||
| 
     lazy_reject(VALUE obj) 
   | 
||
| 
     { 
   | 
||
| 
         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); 
   | 
||
| 
     } 
   | 
||
| 
     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 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); 
   | 
||
| 
         if (RTEST(result)) { 
   | 
||
| 
     	rb_funcall(argv[0], id_yield, 1, rb_yield(i)); 
   | 
||
| 
         } 
   | 
||
| 
         return Qnil; 
   | 
||
| 
     } 
   | 
||
| 
     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)); 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     call_next(VALUE obj) 
   | 
||
| 
     { 
   | 
||
| 
         return rb_funcall(obj, id_next, 0); 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     next_stopped(VALUE obj) 
   | 
||
| 
     { 
   | 
||
| 
         return Qnil; 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_zip_func(VALUE val, VALUE arg, int argc, VALUE *argv) 
   | 
||
| 
     { 
   | 
||
| 
         VALUE yielder, ary, v; 
   | 
||
| 
         long i; 
   | 
||
| 
         yielder = argv[0]; 
   | 
||
| 
         ary = rb_ary_new2(RARRAY_LEN(arg) + 1); 
   | 
||
| 
         rb_ary_push(ary, argv[1]); 
   | 
||
| 
         for (i = 0; i < RARRAY_LEN(arg); i++) { 
   | 
||
| 
     	v = rb_rescue2(call_next, RARRAY_PTR(arg)[i], next_stopped, 0, 
   | 
||
| 
     		       rb_eStopIteration, (VALUE)0); 
   | 
||
| 
     	rb_ary_push(ary, v); 
   | 
||
| 
         } 
   | 
||
| 
         rb_funcall(yielder, id_yield, 1, ary); 
   | 
||
| 
         return Qnil; 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_zip(int argc, VALUE *argv, VALUE obj) 
   | 
||
| 
     { 
   | 
||
| 
         VALUE ary; 
   | 
||
| 
         int i; 
   | 
||
| 
         if (rb_block_given_p()) { 
   | 
||
| 
     	return rb_call_super(argc, argv); 
   | 
||
| 
         } 
   | 
||
| 
         ary = rb_ary_new2(argc); 
   | 
||
| 
         for (i = 0; i < argc; i++) { 
   | 
||
| 
     	rb_ary_push(ary, rb_funcall(argv[i], id_lazy, 0)); 
   | 
||
| 
         } 
   | 
||
| 
         return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj, 
   | 
||
| 
     					 lazy_zip_func, ary), 
   | 
||
| 
     			   rb_ary_new4(argc, argv)); 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_take_func(VALUE val, VALUE args, int argc, VALUE *argv) 
   | 
||
| 
     { 
   | 
||
| 
         NODE *memo = RNODE(args); 
   | 
||
| 
         rb_funcall2(argv[0], id_yield, argc - 1, argv + 1); 
   | 
||
| 
         if (--memo->u3.cnt == 0) { 
   | 
||
| 
     	return Qundef; 
   | 
||
| 
         } 
   | 
||
| 
         else { 
   | 
||
| 
     	return Qnil; 
   | 
||
| 
         } 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_take(VALUE obj, VALUE n) 
   | 
||
| 
     { 
   | 
||
| 
         NODE *memo; 
   | 
||
| 
         long len = NUM2LONG(n); 
   | 
||
| 
         int argc = 1; 
   | 
||
| 
         VALUE argv[3]; 
   | 
||
| 
         if (len < 0) { 
   | 
||
| 
     	rb_raise(rb_eArgError, "attempt to take negative size"); 
   | 
||
| 
         } 
   | 
||
| 
         argv[0] = obj; 
   | 
||
| 
         if (len == 0) { 
   | 
||
| 
     	argv[1] = sym_cycle; 
   | 
||
| 
     	argv[2] = INT2NUM(0); 
   | 
||
| 
     	argc = 3; 
   | 
||
| 
         } 
   | 
||
| 
         memo = NEW_MEMO(0, 0, len); 
   | 
||
| 
         return lazy_set_method(rb_block_call(rb_cLazy, id_new, argc, argv, 
   | 
||
| 
     					 lazy_take_func, (VALUE) memo), 
   | 
||
| 
     			   rb_ary_new3(1, n)); 
   | 
||
| 
     } 
   | 
||
| 
     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 VALUE 
   | 
||
| 
     lazy_take_while(VALUE obj) 
   | 
||
| 
     { 
   | 
||
| 
         return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj, 
   | 
||
| 
     					 lazy_take_while_func, 0), 
   | 
||
| 
     			   Qnil); 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_drop_func(VALUE val, VALUE args, int argc, VALUE *argv) 
   | 
||
| 
     { 
   | 
||
| 
         NODE *memo = RNODE(args); 
   | 
||
| 
         if (memo->u3.cnt == 0) { 
   | 
||
| 
     	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1); 
   | 
||
| 
         } 
   | 
||
| 
         else { 
   | 
||
| 
     	memo->u3.cnt--; 
   | 
||
| 
         } 
   | 
||
| 
         return Qnil; 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_drop(VALUE obj, VALUE n) 
   | 
||
| 
     { 
   | 
||
| 
         NODE *memo; 
   | 
||
| 
         long len = NUM2LONG(n); 
   | 
||
| 
         if (len < 0) { 
   | 
||
| 
     	rb_raise(rb_eArgError, "attempt to drop negative size"); 
   | 
||
| 
         } 
   | 
||
| 
         memo = NEW_MEMO(0, 0, len); 
   | 
||
| 
         return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj, 
   | 
||
| 
     					 lazy_drop_func, (VALUE) memo), 
   | 
||
| 
     			   rb_ary_new3(1, n)); 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_drop_while_func(VALUE val, VALUE args, int argc, VALUE *argv) 
   | 
||
| 
     { 
   | 
||
| 
         NODE *memo = RNODE(args); 
   | 
||
| 
         if (!memo->u3.state && !RTEST(rb_yield_values2(argc - 1, &argv[1]))) { 
   | 
||
| 
     	memo->u3.state = TRUE; 
   | 
||
| 
         } 
   | 
||
| 
         if (memo->u3.state) { 
   | 
||
| 
     	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1); 
   | 
||
| 
         } 
   | 
||
| 
         return Qnil; 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_drop_while(VALUE obj) 
   | 
||
| 
     { 
   | 
||
| 
         NODE *memo; 
   | 
||
| 
         struct enumerator *e = enumerator_ptr(obj); 
   | 
||
| 
         memo = NEW_MEMO(0, 0, FALSE); 
   | 
||
| 
         return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj, 
   | 
||
| 
     					 lazy_drop_while_func, (VALUE) memo), 
   | 
||
| 
     			   Qnil); 
   | 
||
| 
     } 
   | 
||
| 
         rb_ary_push(e->procs, create_proc_entry(T_PROC_SELECT)); 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_cycle_func(VALUE val, VALUE m, int argc, VALUE *argv) 
   | 
||
| 
     { 
   | 
||
| 
         return rb_funcall2(argv[0], id_yield, argc - 1, argv + 1); 
   | 
||
| 
         return obj; 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_cycle(int argc, VALUE *argv, VALUE obj) 
   | 
||
| 
     enumerable_lazy(VALUE self) 
   | 
||
| 
     { 
   | 
||
| 
         VALUE args; 
   | 
||
| 
         int len = rb_long2int((long)argc + 2); 
   | 
||
| 
         if (rb_block_given_p()) { 
   | 
||
| 
     	return rb_call_super(argc, argv); 
   | 
||
| 
         } 
   | 
||
| 
         args = rb_ary_tmp_new(len); 
   | 
||
| 
         rb_ary_push(args, obj); 
   | 
||
| 
         rb_ary_push(args, sym_cycle); 
   | 
||
| 
         if (argc > 0) { 
   | 
||
| 
     	rb_ary_cat(args, argv, argc); 
   | 
||
| 
         } 
   | 
||
| 
         return lazy_set_method(rb_block_call(rb_cLazy, id_new, len, 
   | 
||
| 
     					 RARRAY_PTR(args), lazy_cycle_func, 
   | 
||
| 
     					 args /* prevent from GC */), 
   | 
||
| 
     			   rb_ary_new4(argc, argv)); 
   | 
||
| 
         return rb_class_new_instance(1, &self, rb_cLazy); 
   | 
||
| 
     } 
   | 
||
| 
     static VALUE 
   | 
||
| 
     lazy_lazy(VALUE obj) 
   | 
||
| 
     { 
   | 
||
| 
         return obj; 
   | 
||
| 
     } 
   | 
||
| 
     /* Lazy Enumerator methods */ 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_init_iterator(VALUE val, VALUE m, int argc, VALUE *argv) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    VALUE result; 
   | 
||
| 
     //    if (argc == 1) { 
   | 
||
| 
     //	VALUE args[2]; 
   | 
||
| 
     //	args[0] = m; 
   | 
||
| 
     //	args[1] = val; 
   | 
||
| 
     //	result = rb_yield_values2(2, args); 
   | 
||
| 
     //    } 
   | 
||
| 
     //    else { 
   | 
||
| 
     //	VALUE args; 
   | 
||
| 
     //	int len = rb_long2int((long)argc + 1); 
   | 
||
| 
     // 
   | 
||
| 
     //	args = rb_ary_tmp_new(len); 
   | 
||
| 
     //	rb_ary_push(args, m); 
   | 
||
| 
     //	if (argc > 0) { 
   | 
||
| 
     //	    rb_ary_cat(args, argv, argc); 
   | 
||
| 
     //	} 
   | 
||
| 
     //	result = rb_yield_values2(len, RARRAY_PTR(args)); 
   | 
||
| 
     //	RB_GC_GUARD(args); 
   | 
||
| 
     //    } 
   | 
||
| 
     //    if (result == Qundef) rb_iter_break(); 
   | 
||
| 
     //    return Qnil; 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_init_yielder(VALUE val, VALUE m, int argc, VALUE *argv) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    VALUE result; 
   | 
||
| 
     //    result = rb_funcall2(m, id_yield, argc, argv); 
   | 
||
| 
     //    if (result == Qundef) rb_iter_break(); 
   | 
||
| 
     //    return Qnil; 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_init_block_i(VALUE val, VALUE m, int argc, VALUE *argv) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    rb_block_call(m, id_each, argc-1, argv+1, lazy_init_iterator, val); 
   | 
||
| 
     //    return Qnil; 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_init_block(VALUE val, VALUE m, int argc, VALUE *argv) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    rb_block_call(m, id_each, argc-1, argv+1, lazy_init_yielder, val); 
   | 
||
| 
     //    return Qnil; 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_initialize(int argc, VALUE *argv, VALUE self) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    VALUE obj, meth; 
   | 
||
| 
     //    VALUE generator; 
   | 
||
| 
     //    int offset; 
   | 
||
| 
     // 
   | 
||
| 
     //    if (argc < 1) { 
   | 
||
| 
     //	rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..)", argc); 
   | 
||
| 
     //    } 
   | 
||
| 
     //    else { 
   | 
||
| 
     //	obj = argv[0]; 
   | 
||
| 
     //	if (argc == 1) { 
   | 
||
| 
     //	    meth = sym_each; 
   | 
||
| 
     //	    offset = 1; 
   | 
||
| 
     //	} 
   | 
||
| 
     //	else { 
   | 
||
| 
     //	    meth = argv[1]; 
   | 
||
| 
     //	    offset = 2; 
   | 
||
| 
     //	} 
   | 
||
| 
     //    } 
   | 
||
| 
     //    generator = generator_allocate(rb_cGenerator); 
   | 
||
| 
     //    rb_block_call(generator, id_initialize, 0, 0, 
   | 
||
| 
     //		  (rb_block_given_p() ? lazy_init_block_i : lazy_init_block), 
   | 
||
| 
     //		  obj); 
   | 
||
| 
     //    enumerator_init(self, generator, meth, argc - offset, argv + offset); 
   | 
||
| 
     //    rb_ivar_set(self, id_receiver, obj); 
   | 
||
| 
     // 
   | 
||
| 
     //    return self; 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_set_method(VALUE lazy, VALUE args) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    ID id = rb_frame_this_func(); 
   | 
||
| 
     //    rb_ivar_set(lazy, id_method, ID2SYM(id)); 
   | 
||
| 
     //    if (NIL_P(args)) { 
   | 
||
| 
     //	/* Qfalse indicates that the arguments are empty */ 
   | 
||
| 
     //	rb_ivar_set(lazy, id_arguments, Qfalse); 
   | 
||
| 
     //    } 
   | 
||
| 
     //    else { 
   | 
||
| 
     //	rb_ivar_set(lazy, id_arguments, args); 
   | 
||
| 
     //    } 
   | 
||
| 
     //    return lazy; 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     ///* 
   | 
||
| 
     // * call-seq: 
   | 
||
| 
     // *   e.lazy -> lazy_enumerator 
   | 
||
| 
     // * 
   | 
||
| 
     // * Returns a lazy enumerator, whose methods map/collect, 
   | 
||
| 
     // * flat_map/collect_concat, select/find_all, reject, grep, zip, take, 
   | 
||
| 
     // * take_while, drop, drop_while, and cycle enumerate values only on an 
   | 
||
| 
     // * as-needed basis.  However, if a block is given to zip or cycle, values 
   | 
||
| 
     // * are enumerated immediately. 
   | 
||
| 
     // * 
   | 
||
| 
     // * === Example 
   | 
||
| 
     // * 
   | 
||
| 
     // * The following program finds pythagorean triples: 
   | 
||
| 
     // * 
   | 
||
| 
     // *   def pythagorean_triples 
   | 
||
| 
     // *     (1..Float::INFINITY).lazy.flat_map {|z| 
   | 
||
| 
     // *       (1..z).flat_map {|x| 
   | 
||
| 
     // *         (x..z).select {|y| 
   | 
||
| 
     // *           x**2 + y**2 == z**2 
   | 
||
| 
     // *         }.map {|y| 
   | 
||
| 
     // *           [x, y, z] 
   | 
||
| 
     // *         } 
   | 
||
| 
     // *       } 
   | 
||
| 
     // *     } 
   | 
||
| 
     // *   end 
   | 
||
| 
     // *   # show first ten pythagorean triples 
   | 
||
| 
     // *   p pythagorean_triples.take(10).force # take is lazy, so force is needed 
   | 
||
| 
     // *   p pythagorean_triples.first(10)      # first is eager 
   | 
||
| 
     // *   # show pythagorean triples less than 100 
   | 
||
| 
     // *   p pythagorean_triples.take_while { |*, z| z < 100 }.force 
   | 
||
| 
     // */ 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //enumerable_lazy(VALUE obj) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    VALUE result; 
   | 
||
| 
     // 
   | 
||
| 
     //    result = rb_class_new_instance(1, &obj, rb_cLazy); 
   | 
||
| 
     //    /* Qfalse indicates that the Enumerator::Lazy has no method name */ 
   | 
||
| 
     //    rb_ivar_set(result, id_method, Qfalse); 
   | 
||
| 
     //    return result; 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_map_func(VALUE val, VALUE m, int argc, VALUE *argv) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    VALUE result = rb_yield_values2(argc - 1, &argv[1]); 
   | 
||
| 
     // 
   | 
||
| 
     //    rb_funcall(argv[0], id_yield, 1, result); 
   | 
||
| 
     //    return Qnil; 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_map(VALUE obj) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    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); 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_flat_map_i(VALUE i, VALUE yielder, int argc, VALUE *argv) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    return rb_funcall2(yielder, id_yield, argc, argv); 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_flat_map_each(VALUE obj) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    NODE *memo = RNODE(obj); 
   | 
||
| 
     //    rb_block_call(memo->u1.value, id_each, 0, 0, lazy_flat_map_i, 
   | 
||
| 
     //		  memo->u2.value); 
   | 
||
| 
     //    return Qnil; 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_flat_map_to_ary(VALUE obj) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    NODE *memo = RNODE(obj); 
   | 
||
| 
     //    VALUE ary = rb_check_array_type(memo->u1.value); 
   | 
||
| 
     //    if (NIL_P(ary)) { 
   | 
||
| 
     //	rb_funcall(memo->u2.value, id_yield, 1, memo->u1.value); 
   | 
||
| 
     //    } 
   | 
||
| 
     //    else { 
   | 
||
| 
     //	long i; 
   | 
||
| 
     //	for (i = 0; i < RARRAY_LEN(ary); i++) { 
   | 
||
| 
     //	    rb_funcall(memo->u2.value, id_yield, 1, RARRAY_PTR(ary)[i]); 
   | 
||
| 
     //	} 
   | 
||
| 
     //    } 
   | 
||
| 
     //    return Qnil; 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_flat_map_func(VALUE val, VALUE m, int argc, VALUE *argv) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    VALUE result = rb_yield_values2(argc - 1, &argv[1]); 
   | 
||
| 
     //    if (TYPE(result) == T_ARRAY) { 
   | 
||
| 
     //	long i; 
   | 
||
| 
     //	for (i = 0; i < RARRAY_LEN(result); i++) { 
   | 
||
| 
     //	    rb_funcall(argv[0], id_yield, 1, RARRAY_PTR(result)[i]); 
   | 
||
| 
     //	} 
   | 
||
| 
     //    } 
   | 
||
| 
     //    else { 
   | 
||
| 
     //	NODE *memo; 
   | 
||
| 
     //	memo = NEW_MEMO(result, argv[0], 0); 
   | 
||
| 
     //	rb_rescue2(lazy_flat_map_each, (VALUE) memo, 
   | 
||
| 
     //		   lazy_flat_map_to_ary, (VALUE) memo, 
   | 
||
| 
     //		   rb_eNoMethodError, (VALUE)0); 
   | 
||
| 
     //    } 
   | 
||
| 
     //    return Qnil; 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_flat_map(VALUE obj) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    if (!rb_block_given_p()) { 
   | 
||
| 
     //	rb_raise(rb_eArgError, "tried to call lazy flat_map without a block"); 
   | 
||
| 
     //    } 
   | 
||
| 
     // 
   | 
||
| 
     //    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj, 
   | 
||
| 
     //					 lazy_flat_map_func, 0), 
   | 
||
| 
     //			   Qnil); 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_select_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 VALUE 
   | 
||
| 
     //lazy_select(VALUE obj) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    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); 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //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 VALUE 
   | 
||
| 
     //lazy_reject(VALUE obj) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    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); 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //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 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); 
   | 
||
| 
     // 
   | 
||
| 
     //    if (RTEST(result)) { 
   | 
||
| 
     //	rb_funcall(argv[0], id_yield, 1, rb_yield(i)); 
   | 
||
| 
     //    } 
   | 
||
| 
     //    return Qnil; 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //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)); 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //call_next(VALUE obj) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    return rb_funcall(obj, id_next, 0); 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //next_stopped(VALUE obj) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    return Qnil; 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_zip_func(VALUE val, VALUE arg, int argc, VALUE *argv) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    VALUE yielder, ary, v; 
   | 
||
| 
     //    long i; 
   | 
||
| 
     // 
   | 
||
| 
     //    yielder = argv[0]; 
   | 
||
| 
     //    ary = rb_ary_new2(RARRAY_LEN(arg) + 1); 
   | 
||
| 
     //    rb_ary_push(ary, argv[1]); 
   | 
||
| 
     //    for (i = 0; i < RARRAY_LEN(arg); i++) { 
   | 
||
| 
     //	v = rb_rescue2(call_next, RARRAY_PTR(arg)[i], next_stopped, 0, 
   | 
||
| 
     //		       rb_eStopIteration, (VALUE)0); 
   | 
||
| 
     //	rb_ary_push(ary, v); 
   | 
||
| 
     //    } 
   | 
||
| 
     //    rb_funcall(yielder, id_yield, 1, ary); 
   | 
||
| 
     //    return Qnil; 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_zip(int argc, VALUE *argv, VALUE obj) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    VALUE ary; 
   | 
||
| 
     //    int i; 
   | 
||
| 
     // 
   | 
||
| 
     //    if (rb_block_given_p()) { 
   | 
||
| 
     //	return rb_call_super(argc, argv); 
   | 
||
| 
     //    } 
   | 
||
| 
     //    ary = rb_ary_new2(argc); 
   | 
||
| 
     //    for (i = 0; i < argc; i++) { 
   | 
||
| 
     //	rb_ary_push(ary, rb_funcall(argv[i], id_lazy, 0)); 
   | 
||
| 
     //    } 
   | 
||
| 
     // 
   | 
||
| 
     //    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj, 
   | 
||
| 
     //					 lazy_zip_func, ary), 
   | 
||
| 
     //			   rb_ary_new4(argc, argv)); 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_take_func(VALUE val, VALUE args, int argc, VALUE *argv) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    NODE *memo = RNODE(args); 
   | 
||
| 
     // 
   | 
||
| 
     //    rb_funcall2(argv[0], id_yield, argc - 1, argv + 1); 
   | 
||
| 
     //    if (--memo->u3.cnt == 0) { 
   | 
||
| 
     //	return Qundef; 
   | 
||
| 
     //    } 
   | 
||
| 
     //    else { 
   | 
||
| 
     //	return Qnil; 
   | 
||
| 
     //    } 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_take(VALUE obj, VALUE n) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    NODE *memo; 
   | 
||
| 
     //    long len = NUM2LONG(n); 
   | 
||
| 
     //    int argc = 1; 
   | 
||
| 
     //    VALUE argv[3]; 
   | 
||
| 
     // 
   | 
||
| 
     //    if (len < 0) { 
   | 
||
| 
     //	rb_raise(rb_eArgError, "attempt to take negative size"); 
   | 
||
| 
     //    } 
   | 
||
| 
     //    argv[0] = obj; 
   | 
||
| 
     //    if (len == 0) { 
   | 
||
| 
     //	argv[1] = sym_cycle; 
   | 
||
| 
     //	argv[2] = INT2NUM(0); 
   | 
||
| 
     //	argc = 3; 
   | 
||
| 
     //    } 
   | 
||
| 
     //    memo = NEW_MEMO(0, 0, len); 
   | 
||
| 
     //    return lazy_set_method(rb_block_call(rb_cLazy, id_new, argc, argv, 
   | 
||
| 
     //					 lazy_take_func, (VALUE) memo), 
   | 
||
| 
     //			   rb_ary_new3(1, n)); 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //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 VALUE 
   | 
||
| 
     //lazy_take_while(VALUE obj) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj, 
   | 
||
| 
     //					 lazy_take_while_func, 0), 
   | 
||
| 
     //			   Qnil); 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_drop_func(VALUE val, VALUE args, int argc, VALUE *argv) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    NODE *memo = RNODE(args); 
   | 
||
| 
     // 
   | 
||
| 
     //    if (memo->u3.cnt == 0) { 
   | 
||
| 
     //	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1); 
   | 
||
| 
     //    } 
   | 
||
| 
     //    else { 
   | 
||
| 
     //	memo->u3.cnt--; 
   | 
||
| 
     //    } 
   | 
||
| 
     //    return Qnil; 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_drop(VALUE obj, VALUE n) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    NODE *memo; 
   | 
||
| 
     //    long len = NUM2LONG(n); 
   | 
||
| 
     // 
   | 
||
| 
     //    if (len < 0) { 
   | 
||
| 
     //	rb_raise(rb_eArgError, "attempt to drop negative size"); 
   | 
||
| 
     //    } 
   | 
||
| 
     //    memo = NEW_MEMO(0, 0, len); 
   | 
||
| 
     //    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj, 
   | 
||
| 
     //					 lazy_drop_func, (VALUE) memo), 
   | 
||
| 
     //			   rb_ary_new3(1, n)); 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_drop_while_func(VALUE val, VALUE args, int argc, VALUE *argv) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    NODE *memo = RNODE(args); 
   | 
||
| 
     // 
   | 
||
| 
     //    if (!memo->u3.state && !RTEST(rb_yield_values2(argc - 1, &argv[1]))) { 
   | 
||
| 
     //	memo->u3.state = TRUE; 
   | 
||
| 
     //    } 
   | 
||
| 
     //    if (memo->u3.state) { 
   | 
||
| 
     //	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1); 
   | 
||
| 
     //    } 
   | 
||
| 
     //    return Qnil; 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_drop_while(VALUE obj) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    NODE *memo; 
   | 
||
| 
     // 
   | 
||
| 
     //    memo = NEW_MEMO(0, 0, FALSE); 
   | 
||
| 
     //    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj, 
   | 
||
| 
     //					 lazy_drop_while_func, (VALUE) memo), 
   | 
||
| 
     //			   Qnil); 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_cycle_func(VALUE val, VALUE m, int argc, VALUE *argv) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    return rb_funcall2(argv[0], id_yield, argc - 1, argv + 1); 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_cycle(int argc, VALUE *argv, VALUE obj) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    VALUE args; 
   | 
||
| 
     //    int len = rb_long2int((long)argc + 2); 
   | 
||
| 
     // 
   | 
||
| 
     //    if (rb_block_given_p()) { 
   | 
||
| 
     //	return rb_call_super(argc, argv); 
   | 
||
| 
     //    } 
   | 
||
| 
     //    args = rb_ary_tmp_new(len); 
   | 
||
| 
     //    rb_ary_push(args, obj); 
   | 
||
| 
     //    rb_ary_push(args, sym_cycle); 
   | 
||
| 
     //    if (argc > 0) { 
   | 
||
| 
     //	rb_ary_cat(args, argv, argc); 
   | 
||
| 
     //    } 
   | 
||
| 
     //    return lazy_set_method(rb_block_call(rb_cLazy, id_new, len, 
   | 
||
| 
     //					 RARRAY_PTR(args), lazy_cycle_func, 
   | 
||
| 
     //					 args /* prevent from GC */), 
   | 
||
| 
     //			   rb_ary_new4(argc, argv)); 
   | 
||
| 
     //} 
   | 
||
| 
     // 
   | 
||
| 
     //static VALUE 
   | 
||
| 
     //lazy_lazy(VALUE obj) 
   | 
||
| 
     //{ 
   | 
||
| 
     //    return obj; 
   | 
||
| 
     //} 
   | 
||
| 
     /* 
   | 
||
| 
      * Document-class: StopIteration 
   | 
||
| ... | ... | |
| 
         rb_define_method(rb_mEnumerable, "lazy", enumerable_lazy, 0); 
   | 
||
| 
         rb_define_method(rb_cLazy, "initialize", lazy_initialize, -1); 
   | 
||
| 
         rb_define_method(rb_cLazy, "map", lazy_map, 0); 
   | 
||
| 
         rb_define_method(rb_cLazy, "collect", lazy_map, 0); 
   | 
||
| 
         rb_define_method(rb_cLazy, "flat_map", lazy_flat_map, 0); 
   | 
||
| 
         rb_define_method(rb_cLazy, "collect_concat", lazy_flat_map, 0); 
   | 
||
| 
         //rb_define_method(rb_cLazy, "collect", lazy_map, 0); 
   | 
||
| 
         //rb_define_method(rb_cLazy, "flat_map", lazy_flat_map, 0); 
   | 
||
| 
         //rb_define_method(rb_cLazy, "collect_concat", lazy_flat_map, 0); 
   | 
||
| 
         rb_define_method(rb_cLazy, "select", lazy_select, 0); 
   | 
||
| 
         rb_define_method(rb_cLazy, "find_all", lazy_select, 0); 
   | 
||
| 
         rb_define_method(rb_cLazy, "reject", lazy_reject, 0); 
   | 
||
| 
         rb_define_method(rb_cLazy, "grep", lazy_grep, 1); 
   | 
||
| 
         rb_define_method(rb_cLazy, "zip", lazy_zip, -1); 
   | 
||
| 
         rb_define_method(rb_cLazy, "take", lazy_take, 1); 
   | 
||
| 
         rb_define_method(rb_cLazy, "take_while", lazy_take_while, 0); 
   | 
||
| 
         rb_define_method(rb_cLazy, "drop", lazy_drop, 1); 
   | 
||
| 
         rb_define_method(rb_cLazy, "drop_while", lazy_drop_while, 0); 
   | 
||
| 
         rb_define_method(rb_cLazy, "cycle", lazy_cycle, -1); 
   | 
||
| 
         rb_define_method(rb_cLazy, "lazy", lazy_lazy, 0); 
   | 
||
| 
         rb_define_alias(rb_cLazy, "force", "to_a"); 
   | 
||
| 
         //rb_define_method(rb_cLazy, "reject", lazy_reject, 0); 
   | 
||
| 
         //rb_define_method(rb_cLazy, "grep", lazy_grep, 1); 
   | 
||
| 
         //rb_define_method(rb_cLazy, "zip", lazy_zip, -1); 
   | 
||
| 
         //rb_define_method(rb_cLazy, "take", lazy_take, 1); 
   | 
||
| 
         //rb_define_method(rb_cLazy, "take_while", lazy_take_while, 0); 
   | 
||
| 
         //rb_define_method(rb_cLazy, "drop", lazy_drop, 1); 
   | 
||
| 
         //rb_define_method(rb_cLazy, "drop_while", lazy_drop_while, 0); 
   | 
||
| 
         //rb_define_method(rb_cLazy, "cycle", lazy_cycle, -1); 
   | 
||
| 
         //rb_define_method(rb_cLazy, "lazy", lazy_lazy, 0); 
   | 
||
| 
         //rb_define_alias(rb_cLazy, "force", "to_a"); 
   | 
||
| 
         rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError); 
   | 
||
| 
         rb_define_method(rb_eStopIteration, "result", stop_result, 0); 
   | 
||