31
31
#include "sys-core.h"
32
32
#include "sys-int-funcs.h" //REB_I64_ADD_OF
33
33
34
+ enum loop_each_mode {
35
+ LM_FOR = 0 ,
36
+ LM_REMOVE ,
37
+ LM_REMOVE_COUNT ,
38
+ LM_MAP
39
+ };
34
40
35
41
/***********************************************************************
36
42
**
271
277
return R_RET ;
272
278
}
273
279
274
-
275
280
/***********************************************************************
276
281
**
277
282
*/ static int Loop_Each (REBVAL * ds , REBINT mode )
278
283
/*
279
284
** Supports these natives (modes):
280
285
** 0: foreach
281
286
** 1: remove-each
282
- ** 2: map
287
+ ** 2: remove-each/count
288
+ ** 3: map-each
283
289
**
284
290
***********************************************************************/
285
291
{
289
295
REBSER * frame ;
290
296
REBVAL * value ;
291
297
REBSER * series ;
292
- REBSER * out = NULL ; // output block (for MAP , mode = 2)
298
+ REBSER * out = NULL ; // output block (for LM_MAP , mode = 2)
293
299
294
300
REBINT index ; // !!!! should these be REBCNT?
295
301
REBINT tail ;
298
304
REBINT err ;
299
305
REBCNT i ;
300
306
REBCNT j ;
307
+ REBOOL return_count = FALSE;
301
308
302
- ASSERT2 (mode >= 0 && mode < 3 , RP_MISC );
309
+ ASSERT2 (mode >= 0 && mode < 4 , RP_MISC );
303
310
304
311
value = D_ARG (2 ); // series
305
312
if (IS_NONE (value )) return R_NONE ;
311
318
SET_NONE (D_RET );
312
319
SET_NONE (DS_NEXT );
313
320
314
- // If it's MAP , create result block:
315
- if (mode == 2 ) {
321
+ // If it's `map-each` , create result block:
322
+ if (mode == LM_MAP ) {
316
323
out = Make_Block (VAL_LEN (value ));
317
324
Set_Block (D_RET , out );
318
325
}
326
+ else if (mode == LM_REMOVE_COUNT ) {
327
+ mode = LM_REMOVE ;
328
+ return_count = TRUE;
329
+ }
319
330
320
331
// Get series info:
321
332
if (ANY_OBJECT (value )) {
333
344
series = VAL_SERIES (value );
334
345
index = VAL_INDEX (value );
335
346
if (index >= (REBINT )SERIES_TAIL (series )) {
336
- if (mode == 1 ) {
337
- SET_INTEGER (D_RET , 0 );
347
+ if (mode == LM_REMOVE ) {
348
+ if (return_count )
349
+ SET_INTEGER (D_RET , 0 );
350
+ else return R_ARG2 ;
338
351
}
339
352
return R_RET ;
340
353
}
341
354
}
342
355
343
- if (mode == 1 && IS_PROTECT_SERIES (series ))
356
+ if (mode == LM_REMOVE && IS_PROTECT_SERIES (series ))
344
357
Trap0 (RE_PROTECTED );
345
358
346
359
windex = index ;
448
461
break ;
449
462
}
450
463
// else CONTINUE:
451
- if (mode == 1 ) SET_FALSE (ds ); // keep the value (for mode == 1 )
464
+ if (mode == LM_REMOVE ) SET_FALSE (ds ); // keep the value (for mode == LM_REMOVE )
452
465
} else {
453
466
err = 0 ; // prevent later test against uninitialized value
454
467
}
455
468
456
- if (mode > 0 ) {
469
+ if (mode > LM_FOR ) {
457
470
//if (ANY_OBJECT(value)) Trap_Types(words, REB_BLOCK, VAL_TYPE(value)); //check not needed
458
471
459
472
// If FALSE return, copy values to the write location:
460
- if (mode == 1 ) { // remove-each
473
+ if (mode == LM_REMOVE ) { // remove-each
461
474
if (IS_FALSE (ds )) {
462
475
REBCNT wide = SERIES_WIDE (series );
463
476
// memory areas may overlap, so use memmove and not memcpy!
467
480
}
468
481
}
469
482
else
470
- if (!IS_UNSET (ds )) Append_Val (out , ds ); // (mode == 2 )
483
+ if (!IS_UNSET (ds )) Append_Val (out , ds ); // (mode == LM_MAP )
471
484
}
472
485
skip_hidden : ;
473
486
}
474
487
475
488
// Finish up:
476
- if (mode == 1 ) {
489
+ if (mode == LM_REMOVE ) {
477
490
// Remove hole (updates tail):
478
491
if (windex < index ) Remove_Series (series , windex , index - windex );
479
- SET_INTEGER (DS_RETURN , index - windex );
480
- if (IS_MAP (value )) return R_ARG2 ;
481
- return R_RET ;
492
+ if (return_count ) {
493
+ index -= windex ;
494
+ SET_INTEGER (DS_RETURN , IS_MAP (value ) ? index / 2 : index );
495
+ return R_RET ;
496
+ }
497
+ return R_ARG2 ;
482
498
}
483
499
484
- // If MAP and not BREAK/RETURN:
485
- if (mode == 2 && err != 2 ) return R_RET ;
500
+ // If map-each and not BREAK/RETURN:
501
+ if (mode == LM_MAP && err != 2 ) return R_RET ;
486
502
487
- return R_TOS1 ;
503
+ return R_TOS1 ; // foreach
488
504
}
489
505
490
506
@@ -586,7 +602,7 @@ skip_hidden: ;
586
602
**
587
603
***********************************************************************/
588
604
{
589
- return Loop_Each (ds , 0 );
605
+ return Loop_Each (ds , LM_FOR );
590
606
}
591
607
592
608
@@ -597,10 +613,11 @@ skip_hidden: ;
597
613
** 'word [get-word! word! block!] {Word or block of words}
598
614
** data [series!] {The series to traverse}
599
615
** body [block!] {Block to evaluate each time}
616
+ ** /count
600
617
**
601
618
***********************************************************************/
602
619
{
603
- return Loop_Each (ds , 1 );
620
+ return Loop_Each (ds , D_REF ( 4 ) ? LM_REMOVE_COUNT : LM_REMOVE );
604
621
}
605
622
606
623
@@ -614,7 +631,7 @@ skip_hidden: ;
614
631
**
615
632
***********************************************************************/
616
633
{
617
- return Loop_Each (ds , 2 );
634
+ return Loop_Each (ds , LM_MAP );
618
635
}
619
636
620
637
0 commit comments