@@ -571,6 +571,88 @@ static void set_elems(PARROT_INTERP, STable *st, void *data, INTVAL n) {
571
571
ensure_size (interp , body , repr_data , n );
572
572
}
573
573
574
+ static void splice (PARROT_INTERP , STable * st , void * data , PMC * from , INTVAL offset , INTVAL count ) {
575
+ VMArrayBody * body = (VMArrayBody * ) data ;
576
+ VMArrayREPRData * repr_data = (VMArrayREPRData * ) st -> REPR_data ;
577
+ INTVAL elems0 = body -> elems ;
578
+ INTVAL elems1 = VTABLE_elements (interp , from );
579
+ PMC * * slots = NULL ;
580
+ INTVAL start ;
581
+ INTVAL tail ;
582
+
583
+ /* XXX: This code assumes we store PMCs. Should fix that at some point. */
584
+ if (repr_data -> elem_size )
585
+ Parrot_ex_throw_from_c_args (interp , NULL , EXCEPTION_OUT_OF_BOUNDS ,
586
+ "VMArray: Can't splice natively typed array" );
587
+
588
+ if (offset < 0 )
589
+ offset += elems0 ;
590
+
591
+ if (offset < 0 )
592
+ Parrot_ex_throw_from_c_args (interp , NULL , EXCEPTION_OUT_OF_BOUNDS ,
593
+ "VMArray: illegal splice offset" );
594
+
595
+ /* When offset == 0, then we may be able to reduce the memmove calls and
596
+ * reallocs by adjusting start, elems0, and count to better match the
597
+ * incoming splice. In particular, we're seeking to adjust C<count> to as
598
+ * close to C<elems1> as we can. */
599
+ if (offset == 0 ) {
600
+ INTVAL n = elems1 - count ;
601
+ INTVAL start = body -> start ;
602
+ if (n > start ) n = start ;
603
+ if (n <= - elems0 ) {
604
+ elems0 = 0 ;
605
+ count = 0 ;
606
+ body -> start = 0 ;
607
+ body -> elems = elems0 ;
608
+ }
609
+ else if (n != 0 ) {
610
+ elems0 += n ;
611
+ count += n ;
612
+ body -> start = start - n ;
613
+ body -> elems = elems0 ;
614
+ }
615
+ }
616
+
617
+ /* If count == 0 and elems == 0, there's nothing left to copy of remove,
618
+ * so the splice is done! */
619
+ if (count == 0 && elems1 == 0 )
620
+ return ;
621
+
622
+ /* The number of elements to right og splice (the "tail"). */
623
+ tail = elems0 - offset - count ;
624
+ if (tail < 0 ) tail = 0 ;
625
+
626
+ if (tail > 0 && count > elems1 ) {
627
+ /* We're shrinking the array, so first move the tail left. */
628
+ slots = (PMC * * ) body -> slots ;
629
+ start = body -> start ;
630
+ memmove (slots + start + offset + elems1 ,
631
+ slots + start + offset + count ,
632
+ tail * sizeof (PMC * ));
633
+ }
634
+
635
+ /* Now, resize the array. */
636
+ ensure_size (interp , body , repr_data , offset + elems1 + tail );
637
+
638
+ slots = (PMC * * ) body -> slots ;
639
+ start = body -> start ;
640
+ if (tail > 0 && count < elems1 ) {
641
+ /* The array grew, so move the tail to the right. */
642
+ memmove (slots + start + offset + elems1 ,
643
+ slots + start + offset + count ,
644
+ tail * sizeof (PMC * ));
645
+ }
646
+
647
+ /* Now, copy from's elements into the array. */
648
+ if (elems1 > 0 ) {
649
+ PMC * iter = VTABLE_get_iter (interp , from );
650
+ INTVAL i ;
651
+ for (i = 0 ; i < elems1 ; i ++ )
652
+ set_pos_pmc (slots , start + offset + i , VTABLE_shift_pmc (interp , iter ));
653
+ }
654
+ }
655
+
574
656
/* Initializes the VMArray representation. */
575
657
REPROps * VMArray_initialize (PARROT_INTERP ) {
576
658
/* Allocate and populate the representation function table. */
@@ -600,5 +682,6 @@ REPROps * VMArray_initialize(PARROT_INTERP) {
600
682
this_repr -> pos_funcs -> unshift_boxed = unshift_boxed ;
601
683
this_repr -> pos_funcs -> shift_boxed = shift_boxed ;
602
684
this_repr -> pos_funcs -> set_elems = set_elems ;
685
+ this_repr -> pos_funcs -> splice = splice ;
603
686
return this_repr ;
604
687
}
0 commit comments