102
102
*
103
103
*/
104
104
VALUE rb_cEnumerator ;
105
- static ID id_rewind , id_each ;
105
+ VALUE rb_cLazy ;
106
+ static ID id_rewind , id_each , id_new , id_initialize , id_yield , id_call ;
106
107
static VALUE sym_each ;
107
108
108
109
VALUE rb_eStopIteration ;
@@ -1200,6 +1201,159 @@ generator_each(int argc, VALUE *argv, VALUE obj)
1200
1201
* end
1201
1202
*
1202
1203
*/
1204
+
1205
+ /* Lazy Enumerator methods */
1206
+ static VALUE
1207
+ lazy_init_iterator (VALUE val , VALUE m , int argc , VALUE * argv )
1208
+ {
1209
+ VALUE args [2 ];
1210
+ args [0 ] = m ;
1211
+ args [1 ] = val ;
1212
+ return rb_yield_values2 (2 , args );
1213
+ }
1214
+
1215
+ static VALUE
1216
+ lazy_init_yielder (VALUE val , VALUE m , int argc , VALUE * argv )
1217
+ {
1218
+ return rb_funcall2 (m , id_yield , 1 , & val );
1219
+ }
1220
+
1221
+ static VALUE
1222
+ lazy_init_block_i (VALUE val , VALUE m , int argc , VALUE * argv )
1223
+ {
1224
+ return rb_block_call (m , id_each , argc - 1 , argv + 1 , lazy_init_iterator , val );
1225
+ }
1226
+
1227
+ static VALUE
1228
+ lazy_init_block (VALUE val , VALUE m , int argc , VALUE * argv )
1229
+ {
1230
+ return rb_block_call (m , id_each , argc - 1 , argv + 1 , lazy_init_yielder , val );
1231
+ }
1232
+
1233
+ static VALUE
1234
+ lazy_initialize (int argc , VALUE * argv , VALUE obj )
1235
+ {
1236
+ VALUE generator , arg ;
1237
+
1238
+ if (argc < 1 ) rb_raise (rb_eArgError , "wrong number of arguments(%d for 1+)" , argc );
1239
+ -- argc ;
1240
+ arg = * argv ++ ;
1241
+ generator = generator_allocate (rb_cGenerator );
1242
+ rb_block_call (generator , id_initialize , 0 , 0 ,
1243
+ (rb_block_given_p () ? lazy_init_block_i : lazy_init_block ),
1244
+ arg );
1245
+ enumerator_init (obj , generator , sym_each , argc , argv );
1246
+
1247
+ return obj ;
1248
+ }
1249
+
1250
+ /*
1251
+ * call-seq:
1252
+ * e.lazy -> lazy_enumerator
1253
+ */
1254
+ static VALUE
1255
+ enumerable_lazy (int argc , VALUE * argv , VALUE obj )
1256
+ {
1257
+ if (argc > 0 ) {
1258
+ VALUE ret , buff , * args = ALLOCV_N (VALUE , buff , argc + 1 );
1259
+ args [0 ] = obj ;
1260
+ MEMCPY (args + 1 , argv , VALUE , argc );
1261
+ ret = rb_class_new_instance (argc + 1 , args , rb_cLazy );
1262
+ ALLOCV_END (buff );
1263
+ return ret ;
1264
+ }
1265
+ else {
1266
+ return rb_class_new_instance (1 , & obj , rb_cLazy );
1267
+ }
1268
+ }
1269
+
1270
+ static VALUE
1271
+ lazy_map_func (VALUE val , VALUE m , int argc , VALUE * argv )
1272
+ {
1273
+ VALUE result = rb_yield_values2 (argc - 1 , & argv [1 ]);
1274
+
1275
+ return rb_funcall (argv [0 ], id_yield , 1 , result );
1276
+ }
1277
+
1278
+ static VALUE
1279
+ lazy_map (VALUE obj )
1280
+ {
1281
+ if (!rb_block_given_p ()) {
1282
+ rb_raise (rb_eArgError , "tried to call lazy map without a block" );
1283
+ }
1284
+
1285
+ return rb_block_call (rb_cLazy , id_new , 1 , & obj , lazy_map_func , 0 );
1286
+ }
1287
+
1288
+
1289
+ static VALUE
1290
+ lazy_select_func (VALUE val , VALUE m , int argc , VALUE * argv )
1291
+ {
1292
+ VALUE element = argv [1 ];
1293
+ VALUE result = rb_yield_values2 (argc - 1 , & argv [1 ]);
1294
+
1295
+ if (RTEST (result )) {
1296
+ return rb_funcall (argv [0 ], id_yield , 1 , element );
1297
+ }
1298
+ else {
1299
+ return result ;
1300
+ }
1301
+ }
1302
+
1303
+ static VALUE
1304
+ lazy_select (VALUE obj )
1305
+ {
1306
+ if (!rb_block_given_p ()) {
1307
+ rb_raise (rb_eArgError , "tried to call lazy select without a block" );
1308
+ }
1309
+
1310
+ return rb_block_call (rb_cLazy , id_new , 1 , & obj , lazy_select_func , 0 );
1311
+ }
1312
+
1313
+ static VALUE
1314
+ lazy_reject_func (VALUE val , VALUE m , int argc , VALUE * argv )
1315
+ {
1316
+ VALUE element = argv [1 ];
1317
+ VALUE result = rb_yield_values2 (argc - 1 , & argv [1 ]);
1318
+
1319
+ if (!RTEST (result )) {
1320
+ return rb_funcall (argv [0 ], id_yield , 1 , element );
1321
+ }
1322
+ else {
1323
+ return result ;
1324
+ }
1325
+ }
1326
+
1327
+ static VALUE
1328
+ lazy_reject (VALUE obj )
1329
+ {
1330
+ if (!rb_block_given_p ()) {
1331
+ rb_raise (rb_eArgError , "tried to call lazy reject without a block" );
1332
+ }
1333
+
1334
+ return rb_block_call (rb_cLazy , id_new , 1 , & obj , lazy_reject_func , 0 );
1335
+ }
1336
+
1337
+ static VALUE
1338
+ lazy_grep_func (VALUE val , VALUE m , int argc , VALUE * argv )
1339
+ {
1340
+ VALUE element = argv [1 ];
1341
+ VALUE result = rb_funcall (m , rb_intern ("=~" ), 1 , element );
1342
+
1343
+ if (RTEST (result )) {
1344
+ return rb_funcall (argv [0 ], id_yield , 1 , element );
1345
+ }
1346
+ else {
1347
+ return result ;
1348
+ }
1349
+ }
1350
+
1351
+ static VALUE
1352
+ lazy_grep (VALUE obj , VALUE pattern )
1353
+ {
1354
+ return rb_block_call (rb_cLazy , id_new , 1 , & obj , lazy_grep_func , pattern );
1355
+ }
1356
+
1203
1357
static VALUE
1204
1358
stop_result (VALUE self )
1205
1359
{
@@ -1231,6 +1385,18 @@ Init_Enumerator(void)
1231
1385
rb_define_method (rb_cEnumerator , "rewind" , enumerator_rewind , 0 );
1232
1386
rb_define_method (rb_cEnumerator , "inspect" , enumerator_inspect , 0 );
1233
1387
1388
+ /* Enumerable::Lazy */
1389
+ rb_cLazy = rb_define_class_under (rb_mEnumerable , "Lazy" , rb_cEnumerator );
1390
+ rb_define_method (rb_mEnumerable , "lazy" , enumerable_lazy , -1 );
1391
+ rb_define_method (rb_cLazy , "initialize" , lazy_initialize , -1 );
1392
+ rb_define_method (rb_cLazy , "map" , lazy_map , 0 );
1393
+ rb_define_method (rb_cLazy , "select" , lazy_select , 0 );
1394
+ rb_define_method (rb_cLazy , "reject" , lazy_reject , 0 );
1395
+ rb_define_method (rb_cLazy , "grep" , lazy_grep , 1 );
1396
+
1397
+ rb_define_alias (rb_cLazy , "collect" , "map" );
1398
+ rb_define_alias (rb_cLazy , "find_all" , "select" );
1399
+
1234
1400
rb_eStopIteration = rb_define_class ("StopIteration" , rb_eIndexError );
1235
1401
rb_define_method (rb_eStopIteration , "result" , stop_result , 0 );
1236
1402
@@ -1251,6 +1417,10 @@ Init_Enumerator(void)
1251
1417
1252
1418
id_rewind = rb_intern ("rewind" );
1253
1419
id_each = rb_intern ("each" );
1420
+ id_call = rb_intern ("call" );
1421
+ id_yield = rb_intern ("yield" );
1422
+ id_new = rb_intern ("new" );
1423
+ id_initialize = rb_intern ("initialize" );
1254
1424
sym_each = ID2SYM (id_each );
1255
1425
1256
1426
rb_provide ("enumerator.so" ); /* for backward compatibility */
0 commit comments