File Coverage

XS.xs
Criterion Covered Total %
statement 918 1001 91.7
branch 1331 2480 53.6
condition n/a
subroutine n/a
pod n/a
total 2249 3481 64.6


line stmt bran cond sub pod time code
1             /**
2             * List::MoreUtils::XS
3             * Copyright 2004 - 2010 by by Tassilo von Parseval
4             * Copyright 2013 - 2017 by Jens Rehsack
5             *
6             * All code added with 0.417 or later is licensed under the Apache License,
7             * Version 2.0 (the "License"); you may not use this file except in compliance
8             * with the License. You may obtain a copy of the License at
9             *
10             * http://www.apache.org/licenses/LICENSE-2.0
11             *
12             * Unless required by applicable law or agreed to in writing, software
13             * distributed under the License is distributed on an "AS IS" BASIS,
14             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15             * See the License for the specific language governing permissions and
16             * limitations under the License.
17             *
18             * All code until 0.416 is licensed under the same terms as Perl itself,
19             * either Perl version 5.8.4 or, at your option, any later version of
20             * Perl 5 you may have available.
21             */
22              
23             #include "LMUconfig.h"
24              
25             #ifdef HAVE_TIME_H
26             # include
27             #endif
28             #ifdef HAVE_SYS_TIME_H
29             # include
30             #endif
31              
32             #define PERL_NO_GET_CONTEXT
33             #include "EXTERN.h"
34             #include "perl.h"
35             #include "XSUB.h"
36             #include "multicall.h"
37              
38             #define NEED_gv_fetchpvn_flags
39             #include "ppport.h"
40              
41             #ifndef MAX
42             # define MAX(a,b) ((a)>(b)?(a):(b))
43             #endif
44             #ifndef MIN
45             # define MIN(a,b) (((a)<(b))?(a):(b))
46             #endif
47              
48             #ifndef aTHX
49             # define aTHX
50             # define pTHX
51             #endif
52              
53             #ifndef croak_xs_usage
54              
55             # ifndef PERL_ARGS_ASSERT_CROAK_XS_USAGE
56             # define PERL_ARGS_ASSERT_CROAK_XS_USAGE assert(cv); assert(params)
57             # endif
58              
59             static void
60             S_croak_xs_usage(pTHX_ const CV *const cv, const char *const params)
61             {
62             const GV *const gv = CvGV(cv);
63              
64             PERL_ARGS_ASSERT_CROAK_XS_USAGE;
65              
66             if (gv) {
67             const char *const gvname = GvNAME(gv);
68             const HV *const stash = GvSTASH(gv);
69             const char *const hvname = stash ? HvNAME(stash) : NULL;
70              
71             if (hvname)
72             Perl_croak_nocontext("Usage: %s::%s(%s)", hvname, gvname, params);
73             else
74             Perl_croak_nocontext("Usage: %s(%s)", gvname, params);
75             } else {
76             /* Pants. I don't think that it should be possible to get here. */
77             Perl_croak_nocontext("Usage: CODE(0x%"UVxf")(%s)", PTR2UV(cv), params);
78             }
79             }
80              
81             # define croak_xs_usage(a,b) S_croak_xs_usage(aTHX_ a,b)
82             #endif
83              
84             #ifdef SVf_IVisUV
85             # define slu_sv_value(sv) (SvIOK(sv)) ? (SvIOK_UV(sv)) ? (NV)(SvUVX(sv)) : (NV)(SvIVX(sv)) : (SvNV(sv))
86             #else
87             # define slu_sv_value(sv) (SvIOK(sv)) ? (NV)(SvIVX(sv)) : (SvNV(sv))
88             #endif
89              
90             #ifndef SvTEMP_off
91             # define SvTEMP_off(a) (a)
92             #endif
93              
94             /*
95             * Perl < 5.18 had some kind of different SvIV_please_nomg
96             */
97             #if PERL_VERSION_LE(5,18,0)
98             #undef SvIV_please_nomg
99             # define SvIV_please_nomg(sv) \
100             (!SvIOKp(sv) && (SvNOK(sv) || SvPOK(sv)) \
101             ? (SvIV_nomg(sv), SvIOK(sv)) \
102             : SvIOK(sv))
103             #endif
104              
105             #ifndef MUTABLE_GV
106             # define MUTABLE_GV(a) (GV *)(a)
107             #endif
108              
109             #if !defined(HAS_BUILTIN_EXPECT) && defined(HAVE_BUILTIN_EXPECT)
110             # ifdef LIKELY
111             # undef LIKELY
112             # endif
113             # ifdef UNLIKELY
114             # undef UNLIKELY
115             # endif
116             # define LIKELY(x) __builtin_expect(!!(x), 1)
117             # define UNLIKELY(x) __builtin_expect(!!(x), 0)
118             #endif
119              
120             #ifndef LIKELY
121             # define LIKELY(x) (x)
122             #endif
123             #ifndef UNLIKELY
124             # define UNLIKELY(x) (x)
125             #endif
126             #ifndef GV_NOTQUAL
127             # define GV_NOTQUAL 0
128             #endif
129              
130             #ifdef _MSC_VER
131             # define inline __inline
132             #endif
133              
134             #ifndef HAVE_SIZE_T
135             # if SIZEOF_PTR == SIZEOF_LONG_LONG
136             typedef unsigned long long size_t;
137             # elif SIZEOF_PTR == SIZEOF_LONG
138             typedef unsigned long size_t;
139             # elif SIZEOF_PTR == SIZEOF_INT
140             typedef unsigned int size_t;
141             # else
142             # error "Can't determine type for size_t"
143             # endif
144             #endif
145              
146             #ifndef HAVE_SSIZE_T
147             # if SIZEOF_PTR == SIZEOF_LONG_LONG
148             typedef signed long long ssize_t;
149             # elif SIZEOF_PTR == SIZEOF_LONG
150             typedef signed long ssize_t;
151             # elif SIZEOF_PTR == SIZEOF_INT
152             typedef signed int ssize_t;
153             # else
154             # error "Can't determine type for ssize_t"
155             # endif
156             #endif
157              
158              
159             /* compare left and right SVs. Returns:
160             * -1: <
161             * 0: ==
162             * 1: >
163             * 2: left or right was a NaN
164             */
165             static I32
166 30146           LMUncmp(pTHX_ SV* left, SV * right)
167             {
168             /* Fortunately it seems NaN isn't IOK */
169 30146 50         if(SvAMAGIC(left) || SvAMAGIC(right))
    0          
    0          
    50          
    0          
    0          
170 0           return SvIVX(amagic_call(left, right, ncmp_amg, 0));
171              
172 30146 100         if (SvIV_please_nomg(right) && SvIV_please_nomg(left))
    50          
    50          
    100          
    50          
    0          
    0          
    100          
173             {
174 30122 100         if (!SvUOK(left))
175             {
176 30096           const IV leftiv = SvIVX(left);
177 30096 100         if (!SvUOK(right))
178             {
179             /* ## IV <=> IV ## */
180 30084           const IV rightiv = SvIVX(right);
181 30084           return (leftiv > rightiv) - (leftiv < rightiv);
182             }
183             /* ## IV <=> UV ## */
184 12 50         if (leftiv < 0)
185             /* As (b) is a UV, it's >=0, so it must be < */
186 12           return -1;
187              
188 0           return ((UV)leftiv > SvUVX(right)) - ((UV)leftiv < SvUVX(right));
189             }
190              
191 26 50         if (SvUOK(right))
192             {
193             /* ## UV <=> UV ## */
194 26           const UV leftuv = SvUVX(left);
195 26           const UV rightuv = SvUVX(right);
196 26           return (leftuv > rightuv) - (leftuv < rightuv);
197             }
198              
199             /* ## UV <=> IV ## */
200 0 0         if (SvIVX(right) < 0)
201             /* As (a) is a UV, it's >=0, so it cannot be < */
202 0           return 1;
203              
204 0           return (SvUVX(left) > SvUVX(right)) - (SvUVX(left) < SvUVX(right));
205             }
206             else
207             {
208             #ifdef SvNV_nomg
209 24 50         NV const rnv = SvNV_nomg(right);
210 24 100         NV const lnv = SvNV_nomg(left);
211             #else
212             NV const rnv = slu_sv_value(right);
213             NV const lnv = slu_sv_value(left);
214             #endif
215              
216             #if defined(NAN_COMPARE_BROKEN) && defined(Perl_isnan)
217             if (Perl_isnan(lnv) || Perl_isnan(rnv))
218             return 2;
219             return (lnv > rnv) - (lnv < rnv);
220             #else
221 24 100         if (lnv < rnv)
222 9           return -1;
223 15 50         if (lnv > rnv)
224 15           return 1;
225 0 0         if (lnv == rnv)
226 0           return 0;
227 0           return 2;
228             #endif
229             }
230             }
231              
232             #define ncmp(left,right) LMUncmp(aTHX_ left,right)
233              
234             #define FUNC_NAME GvNAME(GvEGV(ST(items)))
235              
236             /* shameless stolen from PadWalker */
237             #ifndef PadARRAY
238             typedef AV PADNAMELIST;
239             typedef SV PADNAME;
240             # if PERL_VERSION_LE(5,8,0)
241             typedef AV PADLIST;
242             typedef AV PAD;
243             # endif
244             # define PadlistARRAY(pl) ((PAD **)AvARRAY(pl))
245             # define PadlistMAX(pl) av_len(pl)
246             # define PadlistNAMES(pl) (*PadlistARRAY(pl))
247             # define PadnamelistARRAY(pnl) ((PADNAME **)AvARRAY(pnl))
248             # define PadnamelistMAX(pnl) av_len(pnl)
249             # define PadARRAY AvARRAY
250             # define PadnameIsOUR(pn) !!(SvFLAGS(pn) & SVpad_OUR)
251             # define PadnameOURSTASH(pn) SvOURSTASH(pn)
252             # define PadnameOUTER(pn) !!SvFAKE(pn)
253             # define PadnamePV(pn) (SvPOKp(pn) ? SvPVX(pn) : NULL)
254             #endif
255              
256             static int
257 30           in_pad (pTHX_ SV *code)
258             {
259             GV *gv;
260             HV *stash;
261 30           CV *cv = sv_2cv(code, &stash, &gv, 0);
262 30           PADLIST *pad_list = (CvPADLIST(cv));
263 30           PADNAMELIST *pad_namelist = PadlistNAMES(pad_list);
264             int i;
265              
266 135 100         for (i=PadnamelistMAX(pad_namelist); i>=0; --i)
267             {
268 106           PADNAME* name_sv = PadnamelistARRAY(pad_namelist)[i];
269 106 50         if (name_sv)
270             {
271 106           char *name_str = PadnamePV(name_sv);
272 106 100         if (name_str) {
273              
274             /* perl < 5.6.0 does not yet have our */
275             # ifdef SVpad_OUR
276 11 50         if(PadnameIsOUR(name_sv))
277 0           continue;
278             # endif
279              
280             #if PERL_VERSION_LT(5,21,7)
281             if (!SvOK(name_sv))
282             continue;
283             #endif
284              
285 11 50         if (strEQ(name_str, "$a") || strEQ(name_str, "$b"))
    100          
286 1           return 1;
287             }
288             }
289             }
290 30           return 0;
291             }
292              
293             #define ASSERT_PL_defgv \
294             if(UNLIKELY(!GvSV(PL_defgv))) \
295             croak("panic: *_ disappeared");
296              
297             #define WARN_OFF \
298             SV *oldwarn = PL_curcop->cop_warnings; \
299             PL_curcop->cop_warnings = pWARN_NONE;
300              
301             #define WARN_ON \
302             PL_curcop->cop_warnings = oldwarn;
303              
304             #define EACH_ARRAY_BODY \
305             int i; \
306             arrayeach_args * args; \
307             HV *stash = gv_stashpv("List::MoreUtils::XS_ea", TRUE); \
308             CV *closure = newXS(NULL, XS_List__MoreUtils__XS__array_iterator, __FILE__); \
309             \
310             /* prototype */ \
311             sv_setpv((SV*)closure, ";$"); \
312             \
313             New(0, args, 1, arrayeach_args); \
314             New(0, args->avs, items, AV*); \
315             args->navs = items; \
316             args->curidx = 0; \
317             \
318             for (i = 0; i < items; i++) { \
319             if(UNLIKELY(!arraylike(ST(i)))) \
320             croak_xs_usage(cv, "\\@;\\@\\@..."); \
321             args->avs[i] = (AV*)SvRV(ST(i)); \
322             SvREFCNT_inc(args->avs[i]); \
323             } \
324             \
325             CvXSUBANY(closure).any_ptr = args; \
326             RETVAL = newRV_noinc((SV*)closure); \
327             \
328             /* in order to allow proper cleanup in DESTROY-handler */ \
329             sv_bless(RETVAL, stash)
330              
331             #define dMULTICALLSVCV \
332             HV *stash; \
333             GV *gv; \
334             I32 gimme = G_SCALAR; \
335             CV *mc_cv = sv_2cv(code, &stash, &gv, 0)
336              
337             #define FOR_EACH(on_item) \
338             if(!codelike(code)) \
339             croak_xs_usage(cv, "code, ..."); \
340             \
341             if (items > 1) { \
342             dMULTICALL; \
343             dMULTICALLSVCV; \
344             int i; \
345             SV **args = &PL_stack_base[ax]; \
346             PUSH_MULTICALL(mc_cv); \
347             SAVESPTR(GvSV(PL_defgv)); \
348             \
349             for(i = 1 ; i < items ; ++i) { \
350             SV *def_sv; \
351             ASSERT_PL_defgv \
352             def_sv = GvSV(PL_defgv) = args[i]; \
353             SvTEMP_off(def_sv); \
354             MULTICALL; \
355             on_item; \
356             } \
357             POP_MULTICALL; \
358             }
359              
360             #define TRUE_JUNCTION \
361             FOR_EACH(if (SvTRUE(*PL_stack_sp)) ON_TRUE) \
362             else ON_EMPTY;
363              
364             #define FALSE_JUNCTION \
365             FOR_EACH(if (!SvTRUE(*PL_stack_sp)) ON_FALSE) \
366             else ON_EMPTY;
367              
368             #define ROF_EACH(on_item) \
369             if(!codelike(code)) \
370             croak_xs_usage(cv, "code, ..."); \
371             \
372             if (items > 1) { \
373             dMULTICALL; \
374             dMULTICALLSVCV; \
375             int i; \
376             SV **args = &PL_stack_base[ax]; \
377             PUSH_MULTICALL(mc_cv); \
378             SAVESPTR(GvSV(PL_defgv)); \
379             \
380             for(i = items-1; i > 0; --i) { \
381             SV *def_sv; \
382             ASSERT_PL_defgv \
383             def_sv = GvSV(PL_defgv) = args[i]; \
384             SvTEMP_off(def_sv); \
385             MULTICALL; \
386             on_item; \
387             } \
388             POP_MULTICALL; \
389             }
390              
391             #define REDUCE_WITH(init) \
392             dMULTICALL; \
393             dMULTICALLSVCV; \
394             SV *rc, **args = &PL_stack_base[ax]; \
395             IV i; \
396             \
397             if(!codelike(code)) \
398             croak_xs_usage(cv, "code, list, list"); \
399             \
400             if (in_pad(aTHX_ code)) { \
401             croak("Can't use lexical $a or $b in pairwise code block"); \
402             } \
403             \
404             rc = (init); \
405             sv_2mortal(newRV_noinc(rc)); \
406             \
407             PUSH_MULTICALL(mc_cv); \
408             SAVESPTR(GvSV(PL_defgv)); \
409             \
410             /* Following code is stolen on request of */ \
411             /* Zefram from pp_sort.c of perl core 16ada23 */ \
412             /* I have no idea why it's necessary and there */\
413             /* is no reasonable documentation regarding */ \
414             /* deal with localized $a/$b/$_ */ \
415             SAVEGENERICSV(PL_firstgv); \
416             SAVEGENERICSV(PL_secondgv); \
417             PL_firstgv = MUTABLE_GV(SvREFCNT_inc( \
418             gv_fetchpvs("a", GV_ADD|GV_NOTQUAL, SVt_PV) \
419             )); \
420             PL_secondgv = MUTABLE_GV(SvREFCNT_inc( \
421             gv_fetchpvs("b", GV_ADD|GV_NOTQUAL, SVt_PV) \
422             )); \
423             save_gp(PL_firstgv, 0); save_gp(PL_secondgv, 0); \
424             GvINTRO_off(PL_firstgv); \
425             GvINTRO_off(PL_secondgv); \
426             SAVEGENERICSV(GvSV(PL_firstgv)); \
427             SvREFCNT_inc(GvSV(PL_firstgv)); \
428             SAVEGENERICSV(GvSV(PL_secondgv)); \
429             SvREFCNT_inc(GvSV(PL_secondgv)); \
430             \
431             for (i = 1; i < items; ++i) \
432             { \
433             SV *olda, *oldb; \
434             sv_setiv(GvSV(PL_defgv), i-1); \
435             \
436             olda = GvSV(PL_firstgv); \
437             oldb = GvSV(PL_secondgv); \
438             GvSV(PL_firstgv) = SvREFCNT_inc_simple_NN(rc); \
439             GvSV(PL_secondgv) = SvREFCNT_inc_simple_NN(args[i]); \
440             SvREFCNT_dec(olda); \
441             SvREFCNT_dec(oldb); \
442             MULTICALL; \
443             \
444             SvSetMagicSV(rc, *PL_stack_sp); \
445             } \
446             \
447             POP_MULTICALL; \
448             \
449             EXTEND(SP, 1); \
450             ST(0) = sv_2mortal(newSVsv(rc)); \
451             XSRETURN(1)
452              
453              
454             #define COUNT_ARGS \
455             for (i = 0; i < items; i++) { \
456             SvGETMAGIC(args[i]); \
457             if(SvOK(args[i])) { \
458             HE *he; \
459             SvSetSV_nosteal(tmp, args[i]); \
460             he = hv_fetch_ent(hv, tmp, 0, 0); \
461             if (NULL == he) { \
462             args[count++] = args[i]; \
463             hv_store_ent(hv, tmp, newSViv(1), 0); \
464             } \
465             else { \
466             SV *v = HeVAL(he); \
467             IV how_many = SvIVX(v); \
468             sv_setiv(v, ++how_many); \
469             } \
470             } \
471             else if(0 == seen_undef++) { \
472             args[count++] = args[i]; \
473             } \
474             }
475              
476             #define COUNT_ARGS_MAX \
477             do { \
478             for (i = 0; i < items; i++) { \
479             SvGETMAGIC(args[i]); \
480             if(SvOK(args[i])) { \
481             HE *he; \
482             SvSetSV_nosteal(tmp, args[i]); \
483             he = hv_fetch_ent(hv, tmp, 0, 0); \
484             if (NULL == he) { \
485             args[count++] = args[i]; \
486             hv_store_ent(hv, tmp, newSViv(1), 0); \
487             } \
488             else { \
489             SV *v = HeVAL(he); \
490             IV how_many = SvIVX(v); \
491             if(UNLIKELY(max < ++how_many)) \
492             max = how_many; \
493             sv_setiv(v, how_many); \
494             } \
495             } \
496             else if(0 == seen_undef++) { \
497             args[count++] = args[i]; \
498             } \
499             } \
500             if(UNLIKELY(max < seen_undef)) max = seen_undef; \
501             } while(0)
502              
503              
504             /* need this one for array_each() */
505             typedef struct
506             {
507             AV **avs; /* arrays over which to iterate in parallel */
508             int navs; /* number of arrays */
509             int curidx; /* the current index of the iterator */
510             } arrayeach_args;
511              
512             /* used for natatime and slideatatime_args */
513             typedef struct
514             {
515             SV **svs;
516             int nsvs;
517             int curidx;
518             int window;
519             int move;
520             } slideatatime_args;
521              
522             static void
523 1820           insert_after (pTHX_ int idx, SV *what, AV *av)
524             {
525             int i, len;
526 1820           av_extend(av, (len = av_len(av) + 1));
527              
528 107441 100         for (i = len; i > idx+1; i--)
529             {
530 105621           SV **sv = av_fetch(av, i-1, FALSE);
531 105621           SvREFCNT_inc(*sv);
532 105621           av_store(av, i, *sv);
533             }
534              
535 1820 50         if (!av_store(av, idx+1, what))
536 0           SvREFCNT_dec(what);
537 1820           }
538              
539             static int
540 196           is_like(pTHX_ SV *sv, const char *like)
541             {
542 196           int likely = 0;
543 196 100         if( sv_isobject( sv ) )
544             {
545 4           dSP;
546             int count;
547              
548 4           ENTER;
549 4           SAVETMPS;
550 4 50         PUSHMARK(SP);
551 4 50         XPUSHs( sv_2mortal( newSVsv( sv ) ) );
552 4 50         XPUSHs( sv_2mortal( newSVpv( like, strlen(like) ) ) );
553 4           PUTBACK;
554              
555 4 50         if( ( count = call_pv("overload::Method", G_SCALAR) ) )
556             {
557             I32 ax;
558 4           SPAGAIN;
559              
560 4           SP -= count;
561 4           ax = (SP - PL_stack_base) + 1;
562 4 50         if( SvTRUE(ST(0)) )
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
563 0           ++likely;
564             }
565              
566 4 50         FREETMPS;
567 4           LEAVE;
568             }
569              
570 196           return likely;
571             }
572              
573             static int
574 381           is_array(SV *sv)
575             {
576 381 100         return SvROK(sv) && ( SVt_PVAV == SvTYPE(SvRV(sv) ) );
    100          
577             }
578              
579             static int
580 6115           LMUcodelike(pTHX_ SV *code)
581             {
582 6115 50         SvGETMAGIC(code);
    0          
583 6115 100         return SvROK(code) && ( ( SVt_PVCV == SvTYPE(SvRV(code)) ) || ( is_like(aTHX_ code, "&{}" ) ) );
    50          
    0          
584             }
585              
586             #define codelike(code) LMUcodelike(aTHX_ code)
587              
588             static int
589 357           LMUarraylike(pTHX_ SV *array)
590             {
591 357 100         SvGETMAGIC(array);
    50          
592 357 100         return is_array(array) || is_like(aTHX_ array, "@{}" );
    50          
593             }
594              
595             #define arraylike(array) LMUarraylike(aTHX_ array)
596              
597             static void
598 61           LMUav2flat(pTHX_ AV *tgt, AV *args)
599             {
600 61           I32 k = 0, j = av_len(args) + 1;
601              
602 61           av_extend(tgt, AvFILLp(tgt) + j);
603              
604 297 100         while( --j >= 0 )
605             {
606 236           SV *sv = *av_fetch(args, k++, FALSE);
607 236 100         if(arraylike(sv))
608             {
609 46           AV *av = (AV *)SvRV(sv);
610 46           LMUav2flat(aTHX_ tgt, av);
611             }
612             else
613             {
614             // av_push(tgt, newSVsv(sv));
615 190           av_push(tgt, SvREFCNT_inc(sv));
616             }
617             }
618 61           }
619              
620             /*-
621             * Copyright (c) 1992, 1993
622             * The Regents of the University of California. All rights reserved.
623             *
624             * Redistribution and use in source and binary forms, with or without
625             * modification, are permitted provided that the following conditions
626             * are met:
627             * 1. Redistributions of source code must retain the above copyright
628             * notice, this list of conditions and the following disclaimer.
629             * 2. Redistributions in binary form must reproduce the above copyright
630             * notice, this list of conditions and the following disclaimer in the
631             * documentation and/or other materials provided with the distribution.
632             * 3. Neither the name of the University nor the names of its contributors
633             * may be used to endorse or promote products derived from this software
634             * without specific prior written permission.
635             *
636             * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
637             * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
638             * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
639             * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
640             * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
641             * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
642             * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
643             * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
644             * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
645             * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
646             * SUCH DAMAGE.
647             */
648              
649             /*
650             * FreeBSD's Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
651             * Modified for using Perl Sub (no XSUB) via MULTICALL and all values are SV **
652             */
653             static inline void
654 2           swapfunc(SV **a, SV **b, size_t n)
655             {
656 2           SV **pa = a;
657 2           SV **pb = b;
658 4 100         while(n-- > 0)
659             {
660 2           SV *t = *pa;
661 2           *pa++ = *pb;
662 2           *pb++ = t;
663             }
664 2           }
665              
666             #define swap(a, b) \
667             do { \
668             SV *t = *(a); \
669             *(a) = *(b); \
670             *(b) = t; \
671             } while(0)
672              
673             #define vecswap(a, b, n) \
674             if ((n) > 0) swapfunc(a, b, n)
675              
676             #if HAVE_FEATURE_STATEMENT_EXPRESSION
677             # define CMP(x, y) ({ \
678             SV *olda, *oldb; \
679             olda = GvSV(PL_firstgv); \
680             oldb = GvSV(PL_secondgv); \
681             GvSV(PL_firstgv) = SvREFCNT_inc_simple_NN(*(x)); \
682             GvSV(PL_secondgv) = SvREFCNT_inc_simple_NN(*(y)); \
683             SvREFCNT_dec(olda); \
684             SvREFCNT_dec(oldb); \
685             \
686             MULTICALL; \
687             SvIV(*PL_stack_sp); \
688             })
689             #else
690 60           static inline int _cmpsvs(pTHX_ SV *x, SV *y, OP *multicall_cop )
691             {
692             SV *olda, *oldb;
693              
694 60           olda = GvSV(PL_firstgv);
695 60           oldb = GvSV(PL_secondgv);
696 60           GvSV(PL_firstgv) = SvREFCNT_inc_simple_NN(x);
697 60           GvSV(PL_secondgv) = SvREFCNT_inc_simple_NN(y);
698 60           SvREFCNT_dec(olda);
699 60           SvREFCNT_dec(oldb);
700              
701 60           MULTICALL;
702 60 50         return SvIV(*PL_stack_sp);
703             }
704             # define CMP(x, y) _cmpsvs(aTHX_ *(x), *(y), multicall_cop)
705             #endif
706              
707             #define MED3(a, b, c) ( \
708             CMP(a, b) < 0 ? \
709             (CMP(b, c) < 0 ? b : (CMP(a, c) < 0 ? c : a )) \
710             :(CMP(b, c) > 0 ? b : (CMP(a, c) < 0 ? a : c )) \
711             )
712              
713             static void
714 4           bsd_qsort_r(pTHX_ SV **ary, size_t nelem, OP *multicall_cop)
715             {
716             SV **pa, **pb, **pc, **pd, **pl, **pm, **pn;
717             size_t d1, d2;
718 4           int cmp_result, swap_cnt = 0;
719              
720             loop:
721 6 100         if (nelem < 7)
722             {
723 22 100         for (pm = ary + 1; pm < ary + nelem; ++pm)
724 36 100         for (pl = pm;
725 32 100         pl > ary && CMP(pl - 1, pl) > 0;
726 18           pl -= 1)
727 18           swap(pl, pl - 1);
728              
729 4           return;
730             }
731              
732 2           pm = ary + (nelem / 2);
733 2 50         if (nelem > 7)
734             {
735 2           pl = ary;
736 2           pn = ary + (nelem - 1);
737 2 50         if (nelem > 40)
738             {
739 0           size_t d = (nelem / 8);
740              
741 0 0         pl = MED3(pl, pl + d, pl + 2 * d);
    0          
    0          
    0          
    0          
742 0 0         pm = MED3(pm - d, pm, pm + d);
    0          
    0          
    0          
    0          
743 0 0         pn = MED3(pn - 2 * d, pn - d, pn);
    0          
    0          
    0          
    0          
744             }
745 2 50         pm = MED3(pl, pm, pn);
    0          
    0          
    50          
    0          
746             }
747 2           swap(ary, pm);
748 2           pa = pb = ary + 1;
749              
750 2           pc = pd = ary + (nelem - 1);
751             for (;;)
752             {
753 12 50         while (pb <= pc && (cmp_result = CMP(pb, ary)) <= 0)
    50          
754             {
755 0 0         if (cmp_result == 0)
756             {
757 0           swap_cnt = 1;
758 0           swap(pa, pb);
759 0           pa += 1;
760             }
761              
762 0           pb += 1;
763             }
764              
765 14 100         while (pb <= pc && (cmp_result = CMP(pc, ary)) >= 0)
    100          
766             {
767 2 50         if (cmp_result == 0)
768             {
769 0           swap_cnt = 1;
770 0           swap(pc, pd);
771 0           pd -= 1;
772             }
773 2           pc -= 1;
774             }
775              
776 12 100         if (pb > pc)
777 2           break;
778              
779 10           swap(pb, pc);
780 10           swap_cnt = 1;
781 10           pb += 1;
782 10           pc -= 1;
783 10           }
784 2 50         if (swap_cnt == 0)
785             { /* Switch to insertion sort */
786 0 0         for (pm = ary + 1; pm < ary + nelem; pm += 1)
787 0 0         for (pl = pm;
788 0 0         pl > ary && CMP(pl - 1, pl) > 0;
789 0           pl -= 1)
790 0           swap(pl, pl - 1);
791 0           return;
792             }
793              
794 2           pn = ary + nelem;
795 2           d1 = MIN(pa - ary, pb - pa);
796 2 50         vecswap(ary, pb - d1, d1);
797 2           d1 = MIN(pd - pc, pn - pd - 1);
798 2 50         vecswap(pb, pn - d1, d1);
799              
800 2           d1 = pb - pa;
801 2           d2 = pd - pc;
802 2 50         if (d1 <= d2)
803             {
804             /* Recurse on left partition, then iterate on right partition */
805 2 50         if (d1 > 1)
806 2           bsd_qsort_r(aTHX_ ary, d1, multicall_cop);
807              
808 2 50         if (d2 > 1)
809             {
810             /* Iterate rather than recurse to save stack space */
811             /* qsort(pn - d2, d2, multicall_cop); */
812 2           ary = pn - d2;
813 2           nelem = d2;
814 2           goto loop;
815             }
816             }
817             else
818             {
819             /* Recurse on right partition, then iterate on left partition */
820 0 0         if (d2 > 1)
821 0           bsd_qsort_r(aTHX_ pn - d2, d2, multicall_cop);
822              
823 0 0         if (d1 > 1)
824             {
825             /* Iterate rather than recurse to save stack space */
826             /* qsort(ary, d1, multicall_cop); */
827 0           nelem = d1;
828 0           goto loop;
829             }
830             }
831             }
832              
833             /* lower_bound algorithm from STL - see http://en.cppreference.com/w/cpp/algorithm/lower_bound */
834             #define LOWER_BOUND(at) \
835             while (count > 0) { \
836             ssize_t step = count / 2; \
837             ssize_t it = first + step; \
838             \
839             ASSERT_PL_defgv \
840             GvSV(PL_defgv) = at; \
841             MULTICALL; \
842             cmprc = SvIV(*PL_stack_sp); \
843             if (cmprc < 0) { \
844             first = ++it; \
845             count -= step + 1; \
846             } \
847             else \
848             count = step; \
849             }
850              
851             #define LOWER_BOUND_QUICK(at) \
852             while (count > 0) { \
853             ssize_t step = count / 2; \
854             ssize_t it = first + step; \
855             \
856             ASSERT_PL_defgv \
857             GvSV(PL_defgv) = at; \
858             MULTICALL; \
859             cmprc = SvIV(*PL_stack_sp); \
860             if(UNLIKELY(0 == cmprc)) { \
861             first = it; \
862             break; \
863             } \
864             if (cmprc < 0) { \
865             first = ++it; \
866             count -= step + 1; \
867             } \
868             else \
869             count = step; \
870             }
871              
872             /* upper_bound algorithm from STL - see http://en.cppreference.com/w/cpp/algorithm/upper_bound */
873             #define UPPER_BOUND(at) \
874             while (count > 0) { \
875             ssize_t step = count / 2; \
876             ssize_t it = first + step; \
877             \
878             ASSERT_PL_defgv \
879             GvSV(PL_defgv) = at; \
880             MULTICALL; \
881             cmprc = SvIV(*PL_stack_sp); \
882             if (cmprc <= 0) { \
883             first = ++it; \
884             count -= step + 1; \
885             } \
886             else \
887             count = step; \
888             }
889              
890              
891             MODULE = List::MoreUtils::XS_ea PACKAGE = List::MoreUtils::XS_ea
892              
893             void
894             DESTROY(sv)
895             SV *sv;
896             CODE:
897             {
898             int i;
899 12           CV *code = (CV*)SvRV(sv);
900 12           arrayeach_args *args = (arrayeach_args *)(CvXSUBANY(code).any_ptr);
901 12 50         if (args)
902             {
903 32 100         for (i = 0; i < args->navs; ++i)
904 20           SvREFCNT_dec(args->avs[i]);
905              
906 12           Safefree(args->avs);
907 12           Safefree(args);
908 12           CvXSUBANY(code).any_ptr = NULL;
909             }
910             }
911              
912             MODULE = List::MoreUtils::XS_sa PACKAGE = List::MoreUtils::XS_sa
913              
914             void
915             DESTROY(sv)
916             SV *sv;
917             CODE:
918             {
919             int i;
920 12           CV *code = (CV*)SvRV(sv);
921 12           slideatatime_args *args = (slideatatime_args *)(CvXSUBANY(code).any_ptr);
922 12 50         if (args)
923             {
924 2058 100         for (i = 0; i < args->nsvs; ++i)
925 2046           SvREFCNT_dec(args->svs[i]);
926              
927 12           Safefree(args->svs);
928 12           Safefree(args);
929 12           CvXSUBANY(code).any_ptr = NULL;
930             }
931             }
932              
933             MODULE = List::MoreUtils::XS PACKAGE = List::MoreUtils::XS
934              
935             void
936             any (code,...)
937             SV *code;
938             PROTOTYPE: &@
939             CODE:
940             {
941             #define ON_TRUE { POP_MULTICALL; XSRETURN_YES; }
942             #define ON_EMPTY XSRETURN_NO
943 40007 100         TRUE_JUNCTION;
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    100          
    50          
    50          
    100          
    50          
    50          
944 1           XSRETURN_NO;
945             #undef ON_EMPTY
946             #undef ON_TRUE
947             }
948              
949             void
950             all (code, ...)
951             SV *code;
952             PROTOTYPE: &@
953             CODE:
954             {
955             #define ON_FALSE { POP_MULTICALL; XSRETURN_NO; }
956             #define ON_EMPTY XSRETURN_YES
957 25008 100         FALSE_JUNCTION;
    100          
    50          
    50          
    50          
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    100          
    50          
    50          
958 2           XSRETURN_YES;
959             #undef ON_EMPTY
960             #undef ON_FALSE
961             }
962              
963              
964             void
965             none (code, ...)
966             SV *code;
967             PROTOTYPE: &@
968             CODE:
969             {
970             #define ON_TRUE { POP_MULTICALL; XSRETURN_NO; }
971             #define ON_EMPTY XSRETURN_YES
972 40005 100         TRUE_JUNCTION;
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    100          
    50          
    50          
    100          
    50          
    50          
973 2           XSRETURN_YES;
974             #undef ON_EMPTY
975             #undef ON_TRUE
976             }
977              
978             void
979             notall (code, ...)
980             SV *code;
981             PROTOTYPE: &@
982             CODE:
983             {
984             #define ON_FALSE { POP_MULTICALL; XSRETURN_YES; }
985             #define ON_EMPTY XSRETURN_NO
986 20008 100         FALSE_JUNCTION;
    100          
    50          
    50          
    50          
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    100          
    50          
    50          
987 1           XSRETURN_NO;
988             #undef ON_EMPTY
989             #undef ON_FALSE
990             }
991              
992             void
993             one (code, ...)
994             SV *code;
995             PROTOTYPE: &@
996             CODE:
997             {
998 12           int found = 0;
999             #define ON_TRUE { if (found++) { POP_MULTICALL; XSRETURN_NO; }; }
1000             #define ON_EMPTY XSRETURN_NO
1001 2068 100         TRUE_JUNCTION;
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    50          
    50          
    100          
    50          
    50          
1002 4 100         if (found)
1003 3           XSRETURN_YES;
1004 1           XSRETURN_NO;
1005             #undef ON_EMPTY
1006             #undef ON_TRUE
1007             }
1008              
1009             void
1010             any_u (code,...)
1011             SV *code;
1012             PROTOTYPE: &@
1013             CODE:
1014             {
1015             #define ON_TRUE { POP_MULTICALL; XSRETURN_YES; }
1016             #define ON_EMPTY XSRETURN_UNDEF
1017 40007 100         TRUE_JUNCTION;
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    100          
    50          
    50          
    100          
    50          
    50          
1018 1           XSRETURN_NO;
1019             #undef ON_EMPTY
1020             #undef ON_TRUE
1021             }
1022              
1023             void
1024             all_u (code, ...)
1025             SV *code;
1026             PROTOTYPE: &@
1027             CODE:
1028             {
1029             #define ON_FALSE { POP_MULTICALL; XSRETURN_NO; }
1030             #define ON_EMPTY XSRETURN_UNDEF
1031 25008 100         FALSE_JUNCTION;
    100          
    50          
    50          
    50          
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    100          
    50          
    50          
1032 2           XSRETURN_YES;
1033             #undef ON_EMPTY
1034             #undef ON_FALSE
1035             }
1036              
1037              
1038             void
1039             none_u (code, ...)
1040             SV *code;
1041             PROTOTYPE: &@
1042             CODE:
1043             {
1044             #define ON_TRUE { POP_MULTICALL; XSRETURN_NO; }
1045             #define ON_EMPTY XSRETURN_UNDEF
1046 40005 100         TRUE_JUNCTION;
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    100          
    50          
    50          
    100          
    50          
    50          
1047 2           XSRETURN_YES;
1048             #undef ON_EMPTY
1049             #undef ON_TRUE
1050             }
1051              
1052             void
1053             notall_u (code, ...)
1054             SV *code;
1055             PROTOTYPE: &@
1056             CODE:
1057             {
1058             #define ON_FALSE { POP_MULTICALL; XSRETURN_YES; }
1059             #define ON_EMPTY XSRETURN_UNDEF
1060 20008 100         FALSE_JUNCTION;
    100          
    50          
    50          
    50          
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    100          
    50          
    50          
1061 1           XSRETURN_NO;
1062             #undef ON_EMPTY
1063             #undef ON_FALSE
1064             }
1065              
1066             void
1067             one_u (code, ...)
1068             SV *code;
1069             PROTOTYPE: &@
1070             CODE:
1071             {
1072 12           int found = 0;
1073             #define ON_TRUE { if (found++) { POP_MULTICALL; XSRETURN_NO; }; }
1074             #define ON_EMPTY XSRETURN_UNDEF
1075 2068 100         TRUE_JUNCTION;
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    50          
    50          
    100          
    50          
    50          
1076 4 100         if (found)
1077 3           XSRETURN_YES;
1078 1           XSRETURN_NO;
1079             #undef ON_EMPTY
1080             #undef ON_TRUE
1081             }
1082              
1083             void
1084             reduce_u(code, ...)
1085             SV *code;
1086             PROTOTYPE: &@
1087             CODE:
1088             {
1089 229 100         REDUCE_WITH(newSVsv(&PL_sv_undef));
    50          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
1090             }
1091              
1092             void
1093             reduce_0(code, ...)
1094             SV *code;
1095             PROTOTYPE: &@
1096             CODE:
1097             {
1098 237 100         REDUCE_WITH(newSViv(0));
    50          
    50          
    50          
    100          
    50          
    100          
    50          
    50          
    50          
1099             }
1100              
1101             void
1102             reduce_1(code, ...)
1103             SV *code;
1104             PROTOTYPE: &@
1105             CODE:
1106             {
1107 751 50         REDUCE_WITH(newSViv(1));
    50          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
1108             }
1109              
1110             void
1111             slide(code, ...)
1112             SV *code;
1113             PROTOTYPE: &@
1114             CODE:
1115             {
1116 2 50         if ((items <= 2) || (!codelike(code)))
    100          
1117 1           croak_xs_usage(cv, "code, item1, item2, ...");
1118             else {
1119             /* keep original stack a bit smaller ... */
1120             dMULTICALL;
1121 1           dMULTICALLSVCV;
1122             ssize_t i;
1123 1           SV **args = &PL_stack_base[ax];
1124 1           AV *rc = newAV();
1125              
1126 1           sv_2mortal(newRV_noinc((SV*)rc));
1127 1           av_extend(rc, items-2);
1128              
1129 1 50         PUSH_MULTICALL(mc_cv);
    50          
1130              
1131 1           SAVEGENERICSV(PL_firstgv);
1132 1           SAVEGENERICSV(PL_secondgv);
1133 1           PL_firstgv = MUTABLE_GV(SvREFCNT_inc(
1134             gv_fetchpvs("a", GV_ADD|GV_NOTQUAL, SVt_PV)
1135             ));
1136 1           PL_secondgv = MUTABLE_GV(SvREFCNT_inc(
1137             gv_fetchpvs("b", GV_ADD|GV_NOTQUAL, SVt_PV)
1138             ));
1139             /* make sure the GP isn't removed out from under us for
1140             * the SAVESPTR() */
1141 1           save_gp(PL_firstgv, 0);
1142 1           save_gp(PL_secondgv, 0);
1143             /* we don't want modifications localized */
1144 1           GvINTRO_off(PL_firstgv);
1145 1           GvINTRO_off(PL_secondgv);
1146 1           SAVEGENERICSV(GvSV(PL_firstgv));
1147 1           SvREFCNT_inc(GvSV(PL_firstgv));
1148 1           SAVEGENERICSV(GvSV(PL_secondgv));
1149 1           SvREFCNT_inc(GvSV(PL_secondgv));
1150              
1151 4 100         for(i = 1 ; i < items - 1; ++i) {
1152             SV *olda, *oldb;
1153              
1154 3           olda = GvSV(PL_firstgv);
1155 3           oldb = GvSV(PL_secondgv);
1156 3           GvSV(PL_firstgv) = SvREFCNT_inc_simple_NN(args[i]);
1157 3           GvSV(PL_secondgv) = SvREFCNT_inc_simple_NN(args[i+1]);
1158 3           SvREFCNT_dec(olda);
1159 3           SvREFCNT_dec(oldb);
1160 3           MULTICALL;
1161 3           av_push(rc, newSVsv(*PL_stack_sp));
1162             }
1163 1 50         POP_MULTICALL;
    50          
1164              
1165 4 100         for(i = av_len(rc); i >= 0; --i)
1166             {
1167 3           ST(i) = sv_2mortal(AvARRAY(rc)[i]);
1168 3           AvARRAY(rc)[i] = NULL;
1169             }
1170              
1171 1           AvFILLp(rc) = -1;
1172             }
1173              
1174 1           XSRETURN(items-2);
1175             }
1176              
1177             void
1178             _slideatatime_iterator ()
1179             PROTOTYPE:
1180             CODE:
1181             {
1182             int i;
1183              
1184             /* 'cv' is the hidden argument with which XS_List__MoreUtils__XS__slideatatime_iterator (this XSUB)
1185             * is called. The closure_arg struct is stored in this CV. */
1186              
1187 2043           slideatatime_args *args = (slideatatime_args*)CvXSUBANY(cv).any_ptr;
1188              
1189 2043 50         EXTEND(SP, args->window);
    50          
1190              
1191 4123 100         for (i = 0; i < args->window; i++)
1192 2101 100         if ((args->curidx + i) < args->nsvs)
1193 2080           ST(i) = sv_2mortal(newSVsv(args->svs[args->curidx + i]));
1194             else
1195 21           break;
1196              
1197 2043           args->curidx += args->move;
1198              
1199 2043           XSRETURN(i);
1200             }
1201              
1202             SV *
1203             slideatatime (move, window, ...)
1204             int move;
1205             int window;
1206             PROTOTYPE: $@
1207             CODE:
1208             {
1209             int i;
1210             slideatatime_args *args;
1211 8           HV *stash = gv_stashpv("List::MoreUtils::XS_sa", TRUE);
1212              
1213 8           CV *closure = newXS(NULL, XS_List__MoreUtils__XS__slideatatime_iterator, __FILE__);
1214              
1215             /* must NOT set prototype on iterator:
1216             * otherwise one cannot write: &$it */
1217             /* !! sv_setpv((SV*)closure, ""); !! */
1218              
1219 8           New(0, args, 1, slideatatime_args);
1220 8 50         New(0, args->svs, items-2, SV*);
1221 8           args->nsvs = items-2;
1222 8           args->curidx = 0;
1223 8           args->move = move;
1224 8           args->window = window;
1225              
1226 1045 100         for (i = 2; i < items; i++)
1227 1037           SvREFCNT_inc(args->svs[i-2] = ST(i));
1228              
1229 8           CvXSUBANY(closure).any_ptr = args;
1230 8           RETVAL = newRV_noinc((SV*)closure);
1231              
1232             /* in order to allow proper cleanup in DESTROY-handler */
1233 8           sv_bless(RETVAL, stash);
1234             }
1235             OUTPUT:
1236             RETVAL
1237              
1238              
1239              
1240             int
1241             true (code, ...)
1242             SV *code;
1243             PROTOTYPE: &@
1244             CODE:
1245             {
1246 10           I32 count = 0;
1247 70010 100         FOR_EACH(if (SvTRUE(*PL_stack_sp)) count++);
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    50          
    50          
1248 9           RETVAL = count;
1249             }
1250             OUTPUT:
1251             RETVAL
1252              
1253             int
1254             false (code, ...)
1255             SV *code;
1256             PROTOTYPE: &@
1257             CODE:
1258             {
1259 10           I32 count = 0;
1260 70010 100         FOR_EACH(if (!SvTRUE(*PL_stack_sp)) count++);
    100          
    50          
    50          
    50          
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    50          
    50          
1261 9           RETVAL = count;
1262             }
1263             OUTPUT:
1264             RETVAL
1265              
1266             int
1267             firstidx (code, ...)
1268             SV *code;
1269             PROTOTYPE: &@
1270             CODE:
1271             {
1272 13           RETVAL = -1;
1273 50007 100         FOR_EACH(if (SvTRUE(*PL_stack_sp)) { RETVAL = i-1; break; });
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    50          
    50          
1274             }
1275             OUTPUT:
1276             RETVAL
1277              
1278             SV *
1279             firstval (code, ...)
1280             SV *code;
1281             PROTOTYPE: &@
1282             CODE:
1283             {
1284 8           RETVAL = &PL_sv_undef;
1285 24 100         FOR_EACH(if (SvTRUE(*PL_stack_sp)) { SvREFCNT_inc(RETVAL = args[i]); break; });
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    50          
    50          
1286             }
1287             OUTPUT:
1288             RETVAL
1289              
1290             SV *
1291             firstres (code, ...)
1292             SV *code;
1293             PROTOTYPE: &@
1294             CODE:
1295             {
1296 7           RETVAL = &PL_sv_undef;
1297 23 100         FOR_EACH(if (SvTRUE(*PL_stack_sp)) { SvREFCNT_inc(RETVAL = *PL_stack_sp); break; });
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    100          
    50          
    50          
    100          
    50          
    50          
    50          
    100          
    50          
    0          
    100          
    100          
    50          
    50          
1298             }
1299             OUTPUT:
1300             RETVAL
1301              
1302             int
1303             onlyidx (code, ...)
1304             SV *code;
1305             PROTOTYPE: &@
1306             CODE:
1307             {
1308 17           int found = 0;
1309 17           RETVAL = -1;
1310 3529 100         FOR_EACH(if (SvTRUE(*PL_stack_sp)) { if (found++) {RETVAL = -1; break;} RETVAL = i-1; });
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    100          
    50          
    50          
1311             }
1312             OUTPUT:
1313             RETVAL
1314              
1315             SV *
1316             onlyval (code, ...)
1317             SV *code;
1318             PROTOTYPE: &@
1319             CODE:
1320             {
1321 17           int found = 0;
1322 17           RETVAL = &PL_sv_undef;
1323 3529 100         FOR_EACH(if (SvTRUE(*PL_stack_sp)) { if (found++) {SvREFCNT_dec(RETVAL); RETVAL = &PL_sv_undef; break;} SvREFCNT_inc(RETVAL = args[i]); });
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    100          
    50          
    50          
1324             }
1325             OUTPUT:
1326             RETVAL
1327              
1328             SV *
1329             onlyres (code, ...)
1330             SV *code;
1331             PROTOTYPE: &@
1332             CODE:
1333             {
1334 15           int found = 0;
1335 15           RETVAL = &PL_sv_undef;
1336 2927 100         FOR_EACH(if (SvTRUE(*PL_stack_sp)) { if (found++) {SvREFCNT_dec(RETVAL); RETVAL = &PL_sv_undef; break;}SvREFCNT_inc(RETVAL = *PL_stack_sp); });
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    100          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    100          
    50          
    50          
1337             }
1338             OUTPUT:
1339             RETVAL
1340              
1341             int
1342             lastidx (code, ...)
1343             SV *code;
1344             PROTOTYPE: &@
1345             CODE:
1346             {
1347 13           RETVAL = -1;
1348 20013 100         ROF_EACH(if (SvTRUE(*PL_stack_sp)){RETVAL = i-1;break;})
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    50          
    50          
1349             }
1350             OUTPUT:
1351             RETVAL
1352              
1353             SV *
1354             lastval (code, ...)
1355             SV *code;
1356             PROTOTYPE: &@
1357             CODE:
1358             {
1359 8           RETVAL = &PL_sv_undef;
1360 16 100         ROF_EACH(if (SvTRUE(*PL_stack_sp)) { /* see comment in indexes() */ SvREFCNT_inc(RETVAL = args[i]); break; });
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    50          
    50          
1361             }
1362             OUTPUT:
1363             RETVAL
1364              
1365             SV *
1366             lastres (code, ...)
1367             SV *code;
1368             PROTOTYPE: &@
1369             CODE:
1370             {
1371 7           RETVAL = &PL_sv_undef;
1372 15 100         ROF_EACH(if (SvTRUE(*PL_stack_sp)) { SvREFCNT_inc(RETVAL = *PL_stack_sp); break; });
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    100          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    0          
    0          
    100          
    100          
    50          
    50          
1373             }
1374             OUTPUT:
1375             RETVAL
1376              
1377             int
1378             insert_after (code, val, avref)
1379             SV *code;
1380             SV *val;
1381             SV *avref;
1382             PROTOTYPE: &$\@
1383             CODE:
1384             {
1385             dMULTICALL;
1386 11           dMULTICALLSVCV;
1387             int i;
1388             int len;
1389             AV *av;
1390              
1391 11 100         if(!codelike(code))
1392 2           croak_xs_usage(cv, "code, val, \\@area_of_operation");
1393 9 100         if(!arraylike(avref))
1394 1           croak_xs_usage(cv, "code, val, \\@area_of_operation");
1395              
1396 8           av = (AV*)SvRV(avref);
1397 8           len = av_len(av);
1398 8           RETVAL = 0;
1399              
1400 8 50         PUSH_MULTICALL(mc_cv);
    50          
1401 8           SAVESPTR(GvSV(PL_defgv));
1402              
1403 29 100         for (i = 0; i <= len ; ++i)
1404             {
1405 28 50         ASSERT_PL_defgv
1406 28           GvSV(PL_defgv) = *av_fetch(av, i, FALSE);
1407 28           MULTICALL;
1408 26 50         if (SvTRUE(*PL_stack_sp))
    50          
    50          
    0          
    0          
    100          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    0          
    100          
1409             {
1410 5           RETVAL = 1;
1411 5           break;
1412             }
1413             }
1414              
1415 6 50         POP_MULTICALL;
    50          
1416              
1417 6 100         if (RETVAL)
1418             {
1419 5           SvREFCNT_inc(val);
1420 5           insert_after(aTHX_ i, val, av);
1421             }
1422             }
1423             OUTPUT:
1424             RETVAL
1425              
1426             int
1427             insert_after_string (string, val, avref)
1428             SV *string;
1429             SV *val;
1430             SV *avref;
1431             PROTOTYPE: $$\@
1432             CODE:
1433             {
1434             int i, len;
1435             AV *av;
1436 8           RETVAL = 0;
1437              
1438 8 100         if(!arraylike(avref))
1439 1           croak_xs_usage(cv, "string, val, \\@area_of_operation");
1440              
1441 7           av = (AV*)SvRV(avref);
1442 7           len = av_len(av);
1443              
1444 24 50         for (i = 0; i <= len ; i++)
1445             {
1446 24           SV **sv = av_fetch(av, i, FALSE);
1447 24 100         if((SvFLAGS(*sv) & (SVf_OK & ~SVf_ROK)) && (0 == sv_cmp_locale(string, *sv)))
    100          
1448             {
1449 7           RETVAL = 1;
1450 7           break;
1451             }
1452             }
1453              
1454 7 50         if (RETVAL)
1455             {
1456 7           SvREFCNT_inc(val);
1457 7           insert_after(aTHX_ i, val, av);
1458             }
1459             }
1460             OUTPUT:
1461             RETVAL
1462              
1463             void
1464             apply (code, ...)
1465             SV *code;
1466             PROTOTYPE: &@
1467             CODE:
1468             {
1469 12 100         if(!codelike(code))
1470 2           croak_xs_usage(cv, "code, ...");
1471              
1472 10 100         if (items > 1) {
1473             dMULTICALL;
1474 8           dMULTICALLSVCV;
1475             int i;
1476 8           SV **args = &PL_stack_base[ax];
1477 8           AV *rc = newAV();
1478              
1479 8           sv_2mortal(newRV_noinc((SV*)rc));
1480 8           av_extend(rc, items-1);
1481              
1482 8 50         PUSH_MULTICALL(mc_cv);
    50          
1483 8           SAVESPTR(GvSV(PL_defgv));
1484              
1485 40 100         for(i = 1 ; i < items ; ++i) {
1486 34           av_push(rc, newSVsv(args[i]));
1487 34           GvSV(PL_defgv) = AvARRAY(rc)[AvFILLp(rc)];
1488 34           MULTICALL;
1489             }
1490 6 50         POP_MULTICALL;
    50          
1491              
1492 36 100         for(i = items - 1; i > 0; --i)
1493             {
1494 30           ST(i-1) = sv_2mortal(AvARRAY(rc)[i-1]);
1495 30           AvARRAY(rc)[i-1] = NULL;
1496             }
1497              
1498 6           AvFILLp(rc) = -1;
1499             }
1500              
1501 8           XSRETURN(items-1);
1502             }
1503              
1504             void
1505             after (code, ...)
1506             SV *code;
1507             PROTOTYPE: &@
1508             CODE:
1509             {
1510 7           int k = items, j;
1511 17 100         FOR_EACH(if (SvTRUE(*PL_stack_sp)) {k=i; break;});
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    50          
    50          
1512 14 100         for (j = k + 1; j < items; ++j)
1513 8           ST(j-k-1) = ST(j);
1514              
1515 6           j = items-k-1;
1516 6           XSRETURN(j > 0 ? j : 0);
1517             }
1518              
1519             void
1520             after_incl (code, ...)
1521             SV *code;
1522             PROTOTYPE: &@
1523             CODE:
1524             {
1525 6           int k = items, j;
1526 14 100         FOR_EACH(if (SvTRUE(*PL_stack_sp)) {k=i; break;});
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    50          
    50          
1527 17 100         for (j = k; j < items; j++)
1528 12           ST(j-k) = ST(j);
1529              
1530 5           XSRETURN(items-k);
1531             }
1532              
1533             void
1534             before (code, ...)
1535             SV *code;
1536             PROTOTYPE: &@
1537             CODE:
1538             {
1539 6           int k = items - 1;
1540 16 100         FOR_EACH(if (SvTRUE(*PL_stack_sp)) {k=i-1; break;}; args[i-1] = args[i];);
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    100          
    50          
    50          
    50          
1541              
1542 5           XSRETURN(k);
1543             }
1544              
1545             void
1546             before_incl (code, ...)
1547             SV *code;
1548             PROTOTYPE: &@
1549             CODE:
1550             {
1551 6           int k = items - 1;
1552 16 100         FOR_EACH(args[i-1] = args[i]; if (SvTRUE(*PL_stack_sp)) {k=i; break;});
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    100          
    100          
    50          
    50          
1553              
1554 5           XSRETURN(k);
1555             }
1556              
1557             void
1558             indexes (code, ...)
1559             SV *code;
1560             PROTOTYPE: &@
1561             CODE:
1562             {
1563 24 100         if(!codelike(code))
1564 1           croak_xs_usage(cv, "code, ...");
1565              
1566 23 50         if (items > 1) {
1567             dMULTICALL;
1568 23           dMULTICALLSVCV;
1569             int i;
1570 23           SV **args = &PL_stack_base[ax];
1571 23           AV *rc = newAV();
1572              
1573 23           sv_2mortal(newRV_noinc((SV*)rc));
1574 23           av_extend(rc, items-1);
1575              
1576 23 50         PUSH_MULTICALL(mc_cv);
    50          
1577 23           SAVESPTR(GvSV(PL_defgv));
1578              
1579 164 100         for(i = 1 ; i < items ; ++i)
1580             {
1581 143           GvSV(PL_defgv) = args[i];
1582 143           MULTICALL;
1583 141 50         if (SvTRUE(*PL_stack_sp))
    50          
    50          
    0          
    0          
    100          
    50          
    50          
    100          
    50          
    50          
    50          
    100          
    50          
    0          
    100          
1584 61           av_push(rc, newSViv(i-1));
1585             }
1586 21 50         POP_MULTICALL;
    50          
1587              
1588 72 100         for(i = av_len(rc); i >= 0; --i)
1589             {
1590 51           ST(i) = sv_2mortal(AvARRAY(rc)[i]);
1591 51           AvARRAY(rc)[i] = NULL;
1592             }
1593              
1594 21           i = AvFILLp(rc) + 1;
1595 21           AvFILLp(rc) = -1;
1596              
1597 21           XSRETURN(i);
1598             }
1599              
1600 0           XSRETURN_EMPTY;
1601             }
1602              
1603             void
1604             _array_iterator (method = "")
1605             const char *method;
1606             PROTOTYPE: ;$
1607             CODE:
1608             {
1609             int i;
1610 100           int exhausted = 1;
1611              
1612             /* 'cv' is the hidden argument with which XS_List__MoreUtils__array_iterator (this XSUB)
1613             * is called. The closure_arg struct is stored in this CV. */
1614              
1615 100           arrayeach_args *args = (arrayeach_args *)(CvXSUBANY(cv).any_ptr);
1616              
1617 100 100         if (strEQ(method, "index"))
1618             {
1619 10 50         EXTEND(SP, 1);
1620 10 50         ST(0) = args->curidx > 0 ? sv_2mortal(newSViv(args->curidx-1)) : &PL_sv_undef;
1621 10           XSRETURN(1);
1622             }
1623              
1624 90 50         EXTEND(SP, args->navs);
    50          
1625              
1626 262 100         for (i = 0; i < args->navs; i++)
1627             {
1628 172           AV *av = args->avs[i];
1629 172 100         if (args->curidx <= av_len(av))
1630             {
1631 150           ST(i) = sv_2mortal(newSVsv(*av_fetch(av, args->curidx, FALSE)));
1632 150           exhausted = 0;
1633 150           continue;
1634             }
1635 22           ST(i) = &PL_sv_undef;
1636             }
1637              
1638 90 100         if (exhausted)
1639 12           XSRETURN_EMPTY;
1640              
1641 78           args->curidx++;
1642 78           XSRETURN(args->navs);
1643             }
1644              
1645             SV *
1646             each_array (...)
1647             PROTOTYPE: \@;\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@
1648             CODE:
1649             {
1650 20 50         EACH_ARRAY_BODY;
    100          
    100          
1651             }
1652             OUTPUT:
1653             RETVAL
1654              
1655             SV *
1656             each_arrayref (...)
1657             CODE:
1658             {
1659 14 50         EACH_ARRAY_BODY;
    100          
    100          
1660             }
1661             OUTPUT:
1662             RETVAL
1663              
1664             void
1665             pairwise (code, list1, list2)
1666             SV *code;
1667             AV *list1;
1668             AV *list2;
1669             PROTOTYPE: &\@\@
1670             PPCODE:
1671             {
1672             dMULTICALL;
1673 13           dMULTICALLSVCV;
1674             int i, maxitems;
1675 13           AV *rc = newAV();
1676 13           sv_2mortal(newRV_noinc((SV*)rc));
1677              
1678 13 100         if(!codelike(code))
1679 1           croak_xs_usage(cv, "code, list, list");
1680              
1681 12 100         if (in_pad(aTHX_ code)) {
1682 1           croak("Can't use lexical $a or $b in pairwise code block");
1683             }
1684              
1685             /* deref AV's for convenience and
1686             * get maximum items */
1687 11 50         maxitems = MAX(av_len(list1),av_len(list2))+1;
1688 11           av_extend(rc, maxitems);
1689              
1690 11           gimme = G_ARRAY;
1691 11 50         PUSH_MULTICALL(mc_cv);
    50          
1692              
1693 11           SAVEGENERICSV(PL_firstgv);
1694 11           SAVEGENERICSV(PL_secondgv);
1695 11           PL_firstgv = MUTABLE_GV(SvREFCNT_inc(
1696             gv_fetchpvs("a", GV_ADD|GV_NOTQUAL, SVt_PV)
1697             ));
1698 11           PL_secondgv = MUTABLE_GV(SvREFCNT_inc(
1699             gv_fetchpvs("b", GV_ADD|GV_NOTQUAL, SVt_PV)
1700             ));
1701             /* make sure the GP isn't removed out from under us for
1702             * the SAVESPTR() */
1703 11           save_gp(PL_firstgv, 0);
1704 11           save_gp(PL_secondgv, 0);
1705             /* we don't want modifications localized */
1706 11           GvINTRO_off(PL_firstgv);
1707 11           GvINTRO_off(PL_secondgv);
1708 11           SAVEGENERICSV(GvSV(PL_firstgv));
1709 11           SvREFCNT_inc(GvSV(PL_firstgv));
1710 11           SAVEGENERICSV(GvSV(PL_secondgv));
1711 11           SvREFCNT_inc(GvSV(PL_secondgv));
1712              
1713 475 100         for (i = 0; i < maxitems; ++i)
1714             {
1715             SV **j;
1716 467           SV *olda = GvSV(PL_firstgv), *oldb = GvSV(PL_secondgv);
1717              
1718 467           SV **svp = av_fetch(list1, i, FALSE);
1719 467 100         GvSV(PL_firstgv) = SvREFCNT_inc_simple_NN(svp ? *svp : &PL_sv_undef);
    100          
1720 467           svp = av_fetch(list2, i, FALSE);
1721 467 50         GvSV(PL_secondgv) = SvREFCNT_inc_simple_NN(svp ? *svp : &PL_sv_undef);
    50          
1722 467           SvREFCNT_dec(olda);
1723 467           SvREFCNT_dec(oldb);
1724              
1725 467           MULTICALL;
1726              
1727 966 100         for (j = PL_stack_base+1; j <= PL_stack_sp; ++j)
1728 502           av_push(rc, newSVsv(*j));
1729             }
1730              
1731 8 50         POP_MULTICALL;
    50          
1732              
1733 8           SPAGAIN;
1734 8 50         EXTEND(SP, AvFILLp(rc) + 1);
    50          
1735              
1736 506 100         for(i = AvFILLp(rc); i >= 0; --i)
1737             {
1738 498           ST(i) = sv_2mortal(AvARRAY(rc)[i]);
1739 498           AvARRAY(rc)[i] = NULL;
1740             }
1741              
1742 8           i = AvFILLp(rc) + 1;
1743 8           AvFILLp(rc) = -1;
1744              
1745 8           XSRETURN(i);
1746             }
1747              
1748             SV *
1749             natatime (n, ...)
1750             int n;
1751             PROTOTYPE: $@
1752             CODE:
1753             {
1754             int i;
1755             slideatatime_args *args;
1756 4           HV *stash = gv_stashpv("List::MoreUtils::XS_sa", TRUE);
1757              
1758 4           CV *closure = newXS(NULL, XS_List__MoreUtils__XS__slideatatime_iterator, __FILE__);
1759              
1760             /* must NOT set prototype on iterator:
1761             * otherwise one cannot write: &$it */
1762             /* !! sv_setpv((SV*)closure, ""); !! */
1763              
1764 4           New(0, args, 1, slideatatime_args);
1765 4 50         New(0, args->svs, items-1, SV*);
1766 4           args->nsvs = items-1;
1767 4           args->curidx = 0;
1768 4           args->move = n;
1769 4           args->window = n;
1770              
1771 1013 100         for (i = 1; i < items; i++)
1772 1009           SvREFCNT_inc(args->svs[i-1] = ST(i));
1773              
1774 4           CvXSUBANY(closure).any_ptr = args;
1775 4           RETVAL = newRV_noinc((SV*)closure);
1776              
1777             /* in order to allow proper cleanup in DESTROY-handler */
1778 4           sv_bless(RETVAL, stash);
1779             }
1780             OUTPUT:
1781             RETVAL
1782              
1783             void
1784             arrayify(...)
1785             CODE:
1786             {
1787             I32 i;
1788 15           AV *rc = newAV();
1789 15           AV *args = av_make(items, &PL_stack_base[ax]);
1790 15           sv_2mortal(newRV_noinc((SV *)rc));
1791 15           sv_2mortal(newRV_noinc((SV *)args));
1792              
1793 15           LMUav2flat(aTHX_ rc, args);
1794              
1795 15           i = AvFILLp(rc);
1796 15 50         EXTEND(SP, i+1);
    50          
1797 205 100         for(; i >= 0; --i)
1798             {
1799 190           ST(i) = sv_2mortal(AvARRAY(rc)[i]);
1800 190           AvARRAY(rc)[i] = NULL;
1801             }
1802              
1803 15           i = AvFILLp(rc) + 1;
1804 15           AvFILLp(rc) = -1;
1805              
1806 15           XSRETURN(i);
1807             }
1808              
1809             void
1810             mesh (...)
1811             PROTOTYPE: \@\@;\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@
1812             CODE:
1813             {
1814 26           int i, j, maxidx = -1;
1815             AV **avs;
1816 26 50         New(0, avs, items, AV*);
1817              
1818 78 100         for (i = 0; i < items; i++)
1819             {
1820 53 100         if(!arraylike(ST(i)))
1821 1           croak_xs_usage(cv, "\\@\\@;\\@...");
1822              
1823 52           avs[i] = (AV*)SvRV(ST(i));
1824 52 100         if (av_len(avs[i]) > maxidx)
1825 29           maxidx = av_len(avs[i]);
1826             }
1827              
1828 25 50         EXTEND(SP, items * (maxidx + 1));
    50          
1829 1859 100         for (i = 0; i <= maxidx; i++)
1830 5508 100         for (j = 0; j < items; j++)
1831             {
1832 3674           SV **svp = av_fetch(avs[j], i, FALSE);
1833 3674 100         ST(i*items + j) = svp ? sv_2mortal(newSVsv(*svp)) : &PL_sv_undef;
1834             }
1835              
1836 25           Safefree(avs);
1837 25           XSRETURN(items * (maxidx + 1));
1838             }
1839              
1840             void
1841             zip6 (...)
1842             PROTOTYPE: \@\@;\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@
1843             CODE:
1844             {
1845 6           int i, j, maxidx = -1;
1846             AV **src;
1847 6 50         New(0, src, items, AV*);
1848              
1849 17 100         for (i = 0; i < items; i++)
1850             {
1851 12 100         if(!arraylike(ST(i)))
1852 1           croak_xs_usage(cv, "\\@\\@;\\@...");
1853              
1854 11           src[i] = (AV*)SvRV(ST(i));
1855 11 100         if (av_len(src[i]) > maxidx)
1856 7           maxidx = av_len(src[i]);
1857             }
1858              
1859 5 50         EXTEND(SP, maxidx + 1);
    50          
1860 32 100         for (i = 0; i <= maxidx; i++)
1861             {
1862             AV *av;
1863 27           ST(i) = sv_2mortal(newRV_noinc((SV *)(av = newAV())));
1864              
1865 84 100         for (j = 0; j < items; j++)
1866             {
1867 57           SV **svp = av_fetch(src[j], i, FALSE);
1868 57 100         av_push(av, newSVsv( svp ? *svp : &PL_sv_undef ));
1869             }
1870             }
1871              
1872 5           Safefree(src);
1873 5           XSRETURN(maxidx + 1);
1874             }
1875              
1876             void
1877             listcmp (...)
1878             PROTOTYPE: \@\@;\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@
1879             CODE:
1880             {
1881             I32 i;
1882 8           SV *tmp = sv_newmortal();
1883 8           HV *rc = newHV();
1884 8           SV *ret = sv_2mortal (newRV_noinc((SV *)rc));
1885 8           HV *distinct = newHV();
1886 8           sv_2mortal(newRV_noinc((SV*)distinct));
1887              
1888 21 100         for (i = 0; i < items; i++)
1889             {
1890             AV *av;
1891             I32 j;
1892              
1893 17 50         if(!arraylike(ST(i)))
1894 0           croak_xs_usage(cv, "\\@\\@;\\@...");
1895 17           av = (AV*)SvRV(ST(i));
1896              
1897 17           hv_clear(distinct);
1898              
1899 139 100         for(j = 0; j <= av_len(av); ++j)
1900             {
1901 126           SV **sv = av_fetch(av, j, FALSE);
1902             AV *store;
1903              
1904 126 50         if(NULL == sv)
1905 0           continue;
1906              
1907 126 50         SvGETMAGIC(*sv);
    0          
1908 126 100         if(SvOK(*sv))
    50          
    50          
1909             {
1910 105 50         SvSetSV_nosteal(tmp, *sv);
1911 105 100         if(hv_exists_ent(distinct, tmp, 0))
1912 1           continue;
1913              
1914 100           hv_store_ent(distinct, tmp, &PL_sv_yes, 0);
1915              
1916 100 100         if(hv_exists_ent(rc, *sv, 0))
1917             {
1918 34           HE *he = hv_fetch_ent(rc, *sv, 1, 0);
1919 34           store = (AV*)SvRV(HeVAL(he));
1920 34           av_push(store, newSViv(i));
1921             }
1922             else
1923             {
1924 66           store = newAV();
1925 66           av_push(store, newSViv(i));
1926 66           hv_store_ent(rc, tmp, newRV_noinc((SV *)store), 0);
1927             }
1928             }
1929             }
1930             }
1931              
1932 4 50         i = HvUSEDKEYS(rc);
1933 4 50         EXTEND(SP, i * 2);
    50          
1934              
1935 4           i = 0;
1936 4           hv_iterinit(rc);
1937             for(;;)
1938             {
1939 58           HE *he = hv_iternext(rc);
1940             SV *key, *val;
1941 58 100         if(NULL == he)
1942 4           break;
1943              
1944 54 50         if(UNLIKELY(( NULL == (key = HeSVKEY_force(he)) ) || ( NULL == (val = HeVAL(he)) )))
    50          
    50          
    50          
    50          
1945 0           continue;
1946              
1947 54           ST(i++) = key;
1948 54           ST(i++) = val;
1949 54           }
1950              
1951 4           XSRETURN(i);
1952             }
1953              
1954             void
1955             uniq (...)
1956             PROTOTYPE: @
1957             CODE:
1958             {
1959             I32 i;
1960 20           IV count = 0, seen_undef = 0;
1961 20           HV *hv = newHV();
1962 20           SV **args = &PL_stack_base[ax];
1963 20           SV *tmp = sv_newmortal();
1964 20           sv_2mortal(newRV_noinc((SV*)hv));
1965              
1966             /* don't build return list in scalar context */
1967 20 100         if (GIMME_V == G_SCALAR)
    100          
1968             {
1969 241 100         for (i = 0; i < items; i++)
1970             {
1971 236 100         SvGETMAGIC(args[i]);
    50          
1972 236 50         if(SvOK(args[i]))
    0          
    0          
1973             {
1974 236           sv_setsv_nomg(tmp, args[i]);
1975 354 100         if (!hv_exists_ent(hv, tmp, 0))
1976             {
1977 118           ++count;
1978 118           hv_store_ent(hv, tmp, &PL_sv_yes, 0);
1979             }
1980             }
1981 0 0         else if(0 == seen_undef++)
1982 0           ++count;
1983             }
1984 5           ST(0) = sv_2mortal(newSVuv(count));
1985 5           XSRETURN(1);
1986             }
1987              
1988             /* list context: populate SP with mortal copies */
1989 4490 100         for (i = 0; i < items; i++)
1990             {
1991 4477 100         SvGETMAGIC(args[i]);
    50          
1992 4477 100         if(SvOK(args[i]))
    50          
    50          
1993             {
1994 4476 50         SvSetSV_nosteal(tmp, args[i]);
1995 6830 100         if (!hv_exists_ent(hv, tmp, 0))
1996             {
1997             /*ST(count) = sv_2mortal(newSVsv(ST(i)));
1998             ++count;*/
1999 2354           args[count++] = args[i];
2000 2354           hv_store_ent(hv, tmp, &PL_sv_yes, 0);
2001             }
2002             }
2003 1 50         else if(0 == seen_undef++)
2004 1           args[count++] = args[i];
2005             }
2006              
2007 13           XSRETURN(count);
2008             }
2009              
2010             void
2011             singleton (...)
2012             PROTOTYPE: @
2013             CODE:
2014             {
2015             I32 i;
2016 19           IV cnt = 0, count = 0, seen_undef = 0;
2017 19           HV *hv = newHV();
2018 19           SV **args = &PL_stack_base[ax];
2019 19           SV *tmp = sv_newmortal();
2020              
2021 19           sv_2mortal(newRV_noinc((SV*)hv));
2022              
2023 42320 100         COUNT_ARGS
    50          
    100          
    50          
    50          
    50          
    100          
    100          
    100          
2024              
2025             /* don't build return list in scalar context */
2026 15 50         if (GIMME_V == G_SCALAR)
    100          
2027             {
2028 12772 100         for (i = 0; i < count; i++)
2029             {
2030 12765 100         if(SvOK(args[i]))
    50          
    50          
2031 12764           {
2032             HE *he;
2033 12764           sv_setsv_nomg(tmp, args[i]);
2034 12764           he = hv_fetch_ent(hv, tmp, 0, 0);
2035 12764 50         if (he)
2036 12764 100         if( 1 == SvIVX(HeVAL(he)) )
2037 4383           ++cnt;
2038             }
2039 1 50         else if(1 == seen_undef)
2040 0           ++cnt;
2041             }
2042 7           ST(0) = sv_2mortal(newSViv(cnt));
2043 7           XSRETURN(1);
2044             }
2045              
2046             /* list context: populate SP with mortal copies */
2047 12778 100         for (i = 0; i < count; i++)
2048             {
2049 12770 100         if(SvOK(args[i]))
    50          
    50          
2050 12768           {
2051             HE *he;
2052 12768 50         SvSetSV_nosteal(tmp, args[i]);
2053 12768           he = hv_fetch_ent(hv, tmp, 0, 0);
2054 12768 50         if (he)
2055 12768 100         if( 1 == SvIVX(HeVAL(he)) )
2056 4385           args[cnt++] = args[i];
2057             }
2058 2 100         else if(1 == seen_undef)
2059 1           args[cnt++] = args[i];
2060             }
2061              
2062 8           XSRETURN(cnt);
2063             }
2064              
2065             void
2066             duplicates (...)
2067             PROTOTYPE: @
2068             CODE:
2069             {
2070             I32 i;
2071 19           IV cnt = 0, count = 0, seen_undef = 0;
2072 19           HV *hv = newHV();
2073 19           SV **args = &PL_stack_base[ax];
2074 19           SV *tmp = sv_newmortal();
2075              
2076 19           sv_2mortal(newRV_noinc((SV*)hv));
2077              
2078 41461 100         COUNT_ARGS
    50          
    100          
    50          
    50          
    50          
    100          
    100          
    100          
2079              
2080             /* don't build return list in scalar context */
2081 15 50         if (GIMME_V == G_SCALAR)
    100          
2082             {
2083 11896 100         for (i = 0; i < count; i++)
2084             {
2085 11889 100         if(SvOK(args[i]))
    50          
    50          
2086 11888           {
2087             HE *he;
2088 11888           sv_setsv_nomg(tmp, args[i]);
2089 11888           he = hv_fetch_ent(hv, tmp, 0, 0);
2090 11888 50         if (he)
2091 11888 100         if( 1 < SvIVX(HeVAL(he)) )
2092 8382           ++cnt;
2093             }
2094 1 50         else if(1 < seen_undef)
2095 0           ++cnt;
2096             }
2097 7           ST(0) = sv_2mortal(newSViv(cnt));
2098 7           XSRETURN(1);
2099             }
2100              
2101             /* list context: populate SP with mortal copies */
2102 12778 100         for (i = 0; i < count; i++)
2103             {
2104 12770 100         if(SvOK(args[i]))
    50          
    50          
2105 12768           {
2106             HE *he;
2107 12768 50         SvSetSV_nosteal(tmp, args[i]);
2108 12768           he = hv_fetch_ent(hv, tmp, 0, 0);
2109 12768 50         if (he)
2110 12768 100         if( 1 < SvIVX(HeVAL(he)) )
2111 8384           args[cnt++] = args[i];
2112             }
2113 2 100         else if(1 < seen_undef) {
2114 1           args[cnt++] = args[i];
2115             }
2116             }
2117              
2118 8           XSRETURN(cnt);
2119             }
2120              
2121             void
2122             frequency (...)
2123             PROTOTYPE: @
2124             CODE:
2125             {
2126             I32 i;
2127 17           IV count = 0, seen_undef = 0;
2128 17           HV *hv = newHV();
2129 17           SV **args = &PL_stack_base[ax];
2130 17           SV *tmp = sv_newmortal();
2131              
2132 17           sv_2mortal(newRV_noinc((SV*)hv));
2133              
2134 42321 100         COUNT_ARGS
    50          
    100          
    50          
    50          
    50          
    100          
    100          
    100          
2135              
2136 13 50         i = HvUSEDKEYS(hv);
2137 13 100         if(seen_undef)
2138 1           ++i;
2139              
2140             /* don't build return list in scalar context */
2141 13 50         if (GIMME_V == G_SCALAR)
    100          
2142             {
2143 6           ST(0) = sv_2mortal(newSViv(i));
2144 6           XSRETURN(1);
2145             }
2146              
2147 7 50         EXTEND(SP, i * 2);
    100          
2148              
2149 7           i = 0;
2150 7           hv_iterinit(hv);
2151             for(;;)
2152             {
2153 12771           HE *he = hv_iternext(hv);
2154             SV *key, *val;
2155 12771 100         if(NULL == he)
2156 7           break;
2157              
2158 12764 50         if(UNLIKELY(( NULL == (key = HeSVKEY_force(he)) ) || ( NULL == (val = HeVAL(he)) )))
    50          
    50          
    50          
    50          
2159 0           continue;
2160              
2161 12764           ST(i++) = key;
2162 12764           ST(i++) = val;
2163 12764           }
2164              
2165 7 100         if(seen_undef)
2166             {
2167 1           ST(i++) = sv_2mortal(newRV(newSVsv(&PL_sv_undef)));
2168 1           ST(i++) = sv_2mortal(newSViv(seen_undef));;
2169             }
2170              
2171 7           XSRETURN(i);
2172             }
2173              
2174             void
2175             occurrences (...)
2176             PROTOTYPE: @
2177             CODE:
2178             {
2179             I32 i;
2180 12           IV count = 0, seen_undef = 0, max = items > 0 ? 1 : 0;
2181 12           HV *hv = newHV();
2182 12           SV **args = &PL_stack_base[ax];
2183 12           SV *tmp = sv_newmortal();
2184              
2185 12           sv_2mortal(newRV_noinc((SV*)hv));
2186              
2187 427 50         COUNT_ARGS_MAX;
    0          
    100          
    50          
    50          
    50          
    100          
    100          
    100          
    100          
    50          
2188              
2189             /* don't build return list in scalar context */
2190 8 50         if (GIMME_V == G_SCALAR)
    100          
2191             {
2192 2           ST(0) = sv_2mortal(newSViv(i));
2193 2           XSRETURN(1);
2194             }
2195              
2196 6 50         EXTEND(SP, max + 1);
    50          
2197 60 100         for(i = 0; i <= max; ++i)
2198 54           ST(i) = &PL_sv_undef;
2199              
2200 6           hv_iterinit(hv);
2201             for(;;)
2202             {
2203 112           HE *he = hv_iternext(hv);
2204             SV *key, *val;
2205             AV *store;
2206 112 100         if(NULL == he)
2207 6           break;
2208              
2209 106 50         if(UNLIKELY(( NULL == (key = HeSVKEY_force(he)) ) || ( NULL == (val = HeVAL(he)) )))
    50          
    50          
    50          
    50          
2210 0           continue;
2211              
2212 106           i = SvIVX(val);
2213 106 100         if(ST(i) == &PL_sv_undef)
2214             {
2215 28           store = newAV();
2216 28           ST(i) = sv_2mortal(newRV_noinc((SV *)store));
2217             }
2218             else
2219 78           store = (AV *)SvRV(ST(i));
2220 106           av_push(store, newSVsv(key));
2221 106           }
2222              
2223 6 100         if(seen_undef)
2224             {
2225             AV *store;
2226 1 50         if(ST(seen_undef) == &PL_sv_undef)
2227             {
2228 1           store = newAV();
2229 1           ST(seen_undef) = sv_2mortal(newRV_noinc((SV *)store));
2230             }
2231             else
2232             {
2233 0           store = (AV *)SvRV(ST(seen_undef));
2234             }
2235 1           av_push(store, &PL_sv_undef);
2236             }
2237              
2238 6           XSRETURN(max+1);
2239             }
2240              
2241             void
2242             mode (...)
2243             PROTOTYPE: @
2244             CODE:
2245             {
2246             I32 i;
2247 32           IV count = 0, seen_undef = 0, max = items > 0 ? 1 : 0;
2248 32           HV *hv = newHV();
2249 32           SV **args = &PL_stack_base[ax];
2250 32           SV *tmp = sv_newmortal();
2251              
2252 32           sv_2mortal(newRV_noinc((SV*)hv));
2253              
2254 1200 50         COUNT_ARGS_MAX;
    0          
    50          
    0          
    0          
    50          
    100          
    100          
    0          
    100          
    50          
2255              
2256 20 50         EXTEND(SP, count = 1);
2257 20           ST(0) = sv_2mortal(newSViv(max));
2258              
2259             /* don't build return list in scalar context */
2260 20 50         if (GIMME_V == G_SCALAR)
    100          
2261 10           XSRETURN(1);
2262              
2263              
2264 10           hv_iterinit(hv);
2265             for(;;)
2266             {
2267 178           HE *he = hv_iternext(hv);
2268             SV *key, *val;
2269 178 100         if(NULL == he)
2270 10           break;
2271              
2272 168 50         if(UNLIKELY(( NULL == (key = HeSVKEY_force(he)) ) || ( NULL == (val = HeVAL(he)) )))
    50          
    50          
    50          
    50          
2273 0           continue;
2274              
2275 168           i = SvIVX(val);
2276 168 100         if(max == i)
2277             {
2278 18           ++count;
2279 18 50         EXTEND(SP, count);
    50          
2280 18           ST(count-1) = sv_mortalcopy(key);
2281             }
2282 168           }
2283              
2284 10 50         if(seen_undef == max)
2285             {
2286 0           ++count;
2287 0 0         EXTEND(SP, count);
    0          
2288 0           ST(count-1) = &PL_sv_undef;
2289             }
2290              
2291 10           XSRETURN(count);
2292             }
2293              
2294             void
2295             samples (k, ...)
2296             I32 k;
2297             PROTOTYPE: $@
2298             CODE:
2299             {
2300             I32 i;
2301              
2302 5 100         if( k > (items - 1) )
2303 2           croak("Cannot get %" IVdf " samples from %" IVdf " elements", (IV)k, (IV)(items-1));
2304              
2305             /* Initialize Drand01 unless rand() or srand() has already been called */
2306 3 100         if(!PL_srand_called)
2307             {
2308             #ifdef HAVE_TIME
2309             /* using time(NULL) as seed seems to get better random numbers ... */
2310 1           (void)seedDrand01((Rand_seed_t)time(NULL));
2311             #else
2312             (void)seedDrand01((Rand_seed_t)Perl_seed(aTHX));
2313             #endif
2314 1           PL_srand_called = TRUE;
2315             }
2316              
2317             /* optimzed Knuth-Shuffle since we move our stack one item downwards
2318             with each exchange */
2319 33 100         for (i = items ; items - i < k ; )
2320             {
2321 30           I32 index = items - i + 1;
2322 30           I32 swap = index + (I32)(Drand01() * (double)(--i));
2323 30           ST(index-1) = ST(swap);
2324 30           ST(swap) = ST(index);
2325             }
2326              
2327 3           XSRETURN(k);
2328             }
2329              
2330             void
2331             minmax (...)
2332             PROTOTYPE: @
2333             CODE:
2334             {
2335             I32 i;
2336             SV *minsv, *maxsv;
2337              
2338 31 50         if (!items)
2339 0           XSRETURN_EMPTY;
2340              
2341 31 100         if (items == 1)
2342             {
2343 21 50         EXTEND(SP, 1);
2344 21           ST(1) = sv_2mortal(newSVsv(ST(0)));
2345 21           XSRETURN(2);
2346             }
2347              
2348 10           minsv = maxsv = ST(0);
2349              
2350 10057 100         for (i = 1; i < items; i += 2)
2351             {
2352 10047           SV *asv = ST(i-1);
2353 10047           SV *bsv = ST(i);
2354 10047           int cmp = ncmp(asv, bsv);
2355 10047 100         if (cmp < 0)
2356             {
2357 28           int min_cmp = ncmp(minsv, asv);
2358 28           int max_cmp = ncmp(maxsv, bsv);
2359 28 100         if (min_cmp > 0)
2360 1           minsv = asv;
2361 28 100         if (max_cmp < 0)
2362 28           maxsv = bsv;
2363             }
2364             else
2365             {
2366 10019           int min_cmp = ncmp(minsv, bsv);
2367 10019           int max_cmp = ncmp(maxsv, asv);
2368 10019 100         if (min_cmp > 0)
2369 10016           minsv = bsv;
2370 10019 100         if (max_cmp < 0)
2371 6           maxsv = asv;
2372             }
2373             }
2374              
2375 10 100         if (items & 1)
2376             {
2377 4           SV *rsv = ST(items-1);
2378 4 100         if (ncmp(minsv, rsv) > 0)
2379 3           minsv = rsv;
2380 1 50         else if (ncmp(maxsv, rsv) < 0)
2381 1           maxsv = rsv;
2382             }
2383              
2384 10           ST(0) = minsv;
2385 10           ST(1) = maxsv;
2386              
2387 10           XSRETURN(2);
2388             }
2389              
2390             void
2391             minmaxstr (...)
2392             PROTOTYPE: @
2393             CODE:
2394             {
2395             I32 i;
2396             SV *minsv, *maxsv;
2397              
2398 25 50         if (!items)
2399 0           XSRETURN_EMPTY;
2400              
2401 25 100         if (items == 1)
2402             {
2403 21 50         EXTEND(SP, 1);
2404 21           ST(1) = sv_2mortal(newSVsv(ST(0)));
2405 21           XSRETURN(2);
2406             }
2407              
2408 4           minsv = maxsv = ST(0);
2409              
2410 1356 100         for (i = 1; i < items; i += 2)
2411             {
2412 1352           SV *asv = ST(i-1);
2413 1352           SV *bsv = ST(i);
2414 1352           int cmp = sv_cmp_locale(asv, bsv);
2415 1352 50         if (cmp < 0)
2416             {
2417 0           int min_cmp = sv_cmp_locale(minsv, asv);
2418 0           int max_cmp = sv_cmp_locale(maxsv, bsv);
2419 0 0         if (min_cmp > 0)
2420 0           minsv = asv;
2421 0 0         if (max_cmp < 0)
2422 0           maxsv = bsv;
2423             }
2424             else
2425             {
2426 1352           int min_cmp = sv_cmp_locale(minsv, bsv);
2427 1352           int max_cmp = sv_cmp_locale(maxsv, asv);
2428 1352 50         if (min_cmp > 0)
2429 1352           minsv = bsv;
2430 1352 50         if (max_cmp < 0)
2431 0           maxsv = asv;
2432             }
2433             }
2434              
2435 4 100         if (items & 1)
2436             {
2437 3           SV *rsv = ST(items-1);
2438 3 100         if (sv_cmp_locale(minsv, rsv) > 0)
2439 2           minsv = rsv;
2440 1 50         else if (sv_cmp_locale(maxsv, rsv) < 0)
2441 1           maxsv = rsv;
2442             }
2443              
2444 4           ST(0) = minsv;
2445 4           ST(1) = maxsv;
2446              
2447 4           XSRETURN(2);
2448             }
2449              
2450             void
2451             part (code, ...)
2452             SV *code;
2453             PROTOTYPE: &@
2454             CODE:
2455             {
2456             dMULTICALL;
2457 12           dMULTICALLSVCV;
2458             int i;
2459 12           SV **args = &PL_stack_base[ax];
2460 12           AV *tmp = newAV();
2461 12           sv_2mortal(newRV_noinc((SV*)tmp));
2462              
2463 12 50         if(!codelike(code))
2464 0           croak_xs_usage(cv, "code, ...");
2465              
2466 12 100         if (items == 1)
2467 2           XSRETURN_EMPTY;
2468              
2469 10 50         PUSH_MULTICALL(mc_cv);
    50          
2470 10           SAVESPTR(GvSV(PL_defgv));
2471              
2472 96 100         for(i = 1 ; i < items ; ++i)
2473             {
2474             IV idx;
2475             SV **inner;
2476             AV *av;
2477              
2478 87 50         ASSERT_PL_defgv
2479 87           GvSV(PL_defgv) = args[i];
2480 87           MULTICALL;
2481 87 50         idx = SvIV(*PL_stack_sp);
2482              
2483 87 100         if (UNLIKELY(idx < 0 && (idx += (AvFILLp(tmp)+1)) < 0))
    100          
2484 1           croak("Modification of non-creatable array value attempted, subscript %" IVdf, idx);
2485              
2486 86 100         if(UNLIKELY(NULL == (inner = av_fetch(tmp, idx, FALSE))))
2487             {
2488 24           av = newAV();
2489 24           av_push(av, newSVsv(args[i]));
2490 24           av_store(tmp, idx, newRV_noinc((SV *)av));
2491             }
2492             else
2493             {
2494 62           av = (AV*)SvRV(*inner);
2495 62           av_push(av, newSVsv(args[i]));
2496             }
2497             }
2498 9 50         POP_MULTICALL;
    50          
2499              
2500 9 50         EXTEND(SP, AvFILLp(tmp)+1);
    100          
2501 12085 100         for(i = AvFILLp(tmp); i >= 0; --i)
2502             {
2503 12076           SV *v = AvARRAY(tmp)[i];
2504 12076 100         ST(i) = v && is_array(v) ? sv_2mortal(v) : &PL_sv_undef;
    50          
2505 12076           AvARRAY(tmp)[i] = NULL;
2506             }
2507              
2508 9           i = AvFILLp(tmp) + 1;
2509 9           AvFILLp(tmp) = -1;
2510              
2511 11           XSRETURN(i);
2512             }
2513              
2514             void
2515             bsearch (code, ...)
2516             SV *code;
2517             PROTOTYPE: &@
2518             CODE:
2519             {
2520 2029 100         I32 ret_gimme = GIMME_V;
2521 2029 100         if(!codelike(code))
2522 1           croak_xs_usage(cv, "code, ...");
2523              
2524 2028 50         if (items > 1)
2525             {
2526             dMULTICALL;
2527 2028           dMULTICALLSVCV;
2528 2028           ssize_t count = items - 1, first = 1;
2529 2028           int cmprc = -1;
2530 2028           SV **args = &PL_stack_base[ax];
2531              
2532 2028 50         PUSH_MULTICALL(mc_cv);
    50          
2533 2028           SAVESPTR(GvSV(PL_defgv));
2534              
2535 18255 50         LOWER_BOUND_QUICK(args[it])
    50          
    100          
    100          
    100          
2536              
2537 2026 100         if(cmprc < 0 && first < items)
    50          
2538             {
2539 0 0         ASSERT_PL_defgv
2540 0           GvSV(PL_defgv) = args[first];
2541 0           MULTICALL;
2542 0 0         cmprc = SvIV(*PL_stack_sp);
2543             }
2544              
2545 2026 50         POP_MULTICALL;
    50          
2546              
2547 2026 100         if(0 == cmprc)
2548             {
2549 2004 100         if (ret_gimme != G_ARRAY)
2550 2004           XSRETURN_YES;
2551 1000           ST(0) = args[first];
2552 1022           XSRETURN(1);
2553             }
2554             }
2555              
2556 22 50         if(ret_gimme == G_ARRAY)
2557 0           XSRETURN_EMPTY;
2558 22           XSRETURN_UNDEF;
2559             }
2560              
2561             int
2562             bsearchidx (code, ...)
2563             SV *code;
2564             PROTOTYPE: &@
2565             CODE:
2566             {
2567 1029 100         I32 ret_gimme = GIMME_V;
2568 1029 100         if(!codelike(code))
2569 1           croak_xs_usage(cv, "code, ...");
2570              
2571 1028           RETVAL = -1;
2572 1028 50         if (items > 1)
2573             {
2574             dMULTICALL;
2575 1028           dMULTICALLSVCV;
2576 1028           ssize_t count = items - 1, first = 1;
2577 1028           int cmprc = -1;
2578 1028           SV **args = &PL_stack_base[ax];
2579              
2580 1028 50         PUSH_MULTICALL(mc_cv);
    50          
2581 1028           SAVESPTR(GvSV(PL_defgv));
2582              
2583 9271 50         LOWER_BOUND_QUICK(args[it])
    50          
    100          
    100          
    100          
2584              
2585 1026 100         if(cmprc < 0 && first < items)
    50          
2586             {
2587 0 0         ASSERT_PL_defgv
2588 0           GvSV(PL_defgv) = args[first];
2589 0           MULTICALL;
2590 0 0         cmprc = SvIV(*PL_stack_sp);
2591             }
2592              
2593 1026 50         POP_MULTICALL;
    50          
2594              
2595 1026 100         if(0 == cmprc)
2596 1026           RETVAL = --first;
2597             }
2598             }
2599             OUTPUT:
2600             RETVAL
2601              
2602             int
2603             lower_bound (code, ...)
2604             SV *code;
2605             PROTOTYPE: &@
2606             CODE:
2607             {
2608 234 100         if(!codelike(code))
2609 1           croak_xs_usage(cv, "code, ...");
2610              
2611 233 50         if (items > 1)
2612             {
2613             dMULTICALL;
2614 233           dMULTICALLSVCV;
2615 233           ssize_t count = items - 1, first = 1;
2616 233           int cmprc = -1;
2617 233           SV **args = &PL_stack_base[ax];
2618              
2619 233 50         PUSH_MULTICALL(mc_cv);
    50          
2620 233           SAVESPTR(GvSV(PL_defgv));
2621              
2622 1788 50         LOWER_BOUND(args[it])
    50          
    100          
    100          
2623              
2624 233 50         POP_MULTICALL;
    50          
2625              
2626 233           RETVAL = --first;
2627             }
2628             else
2629 0           RETVAL = -1;
2630             }
2631             OUTPUT:
2632             RETVAL
2633              
2634             int
2635             upper_bound (code, ...)
2636             SV *code;
2637             PROTOTYPE: &@
2638             CODE:
2639             {
2640 234 100         if(!codelike(code))
2641 1           croak_xs_usage(cv, "code, ...");
2642              
2643 233 50         if (items > 1)
2644             {
2645             dMULTICALL;
2646 233           dMULTICALLSVCV;
2647 233           ssize_t count = items - 1, first = 1;
2648 233           int cmprc = -1;
2649 233           SV **args = &PL_stack_base[ax];
2650              
2651 233 50         PUSH_MULTICALL(mc_cv);
    50          
2652 233           SAVESPTR(GvSV(PL_defgv));
2653              
2654 1784 50         UPPER_BOUND(args[it])
    50          
    100          
    100          
2655              
2656 232 50         POP_MULTICALL;
    50          
2657              
2658 232           RETVAL = --first;
2659             }
2660             else
2661 0           RETVAL = -1;
2662             }
2663             OUTPUT:
2664             RETVAL
2665              
2666             void
2667             equal_range (code, ...)
2668             SV *code;
2669             PROTOTYPE: &@
2670             CODE:
2671             {
2672 12 100         if(!codelike(code))
2673 1           croak_xs_usage(cv, "code, ...");
2674              
2675 11 50         if (items > 1)
2676             {
2677             dMULTICALL;
2678 11           dMULTICALLSVCV;
2679 11           ssize_t count = items - 1, first = 1;
2680             ssize_t lb;
2681 11           int cmprc = -1;
2682 11           SV **args = &PL_stack_base[ax];
2683              
2684 11 50         PUSH_MULTICALL(mc_cv);
    50          
2685 11           SAVESPTR(GvSV(PL_defgv));
2686              
2687 75 50         LOWER_BOUND(args[it])
    50          
    100          
    100          
2688 9           lb = first - 1;
2689              
2690 9           count = items - first;
2691 56 50         UPPER_BOUND(args[it])
    50          
    100          
    100          
2692              
2693 9 50         POP_MULTICALL;
    50          
2694              
2695 9 50         EXTEND(SP, 2);
2696 9           ST(0) = sv_2mortal(newSViv(lb));
2697 9           ST(1) = sv_2mortal(newSViv(first - 1));
2698 9           XSRETURN(2);
2699             }
2700              
2701 0           XSRETURN_EMPTY;
2702             }
2703              
2704             int
2705             binsert(code, item, list)
2706             SV *code;
2707             SV *item;
2708             AV *list;
2709             PROTOTYPE: &$\@
2710             CODE:
2711             {
2712 1810 50         if(!codelike(code))
2713 0           croak_xs_usage(cv, "code, val, list");
2714              
2715 1810           RETVAL = -1;
2716              
2717 1810 100         if (AvFILLp(list) == -1)
2718             {
2719 1           av_push(list, newSVsv(item));
2720 1           RETVAL = 0;
2721             }
2722 1809 50         else if (AvFILLp(list) >= 0)
2723             {
2724             dMULTICALL;
2725 1809           dMULTICALLSVCV;
2726 1809           ssize_t count = AvFILLp(list) + 1, first = 0;
2727 1809           int cmprc = -1;
2728 1809           SV **btree = AvARRAY(list);
2729              
2730 1809 50         PUSH_MULTICALL(mc_cv);
    50          
2731 1809           SAVESPTR(GvSV(PL_defgv));
2732              
2733 14995 50         LOWER_BOUND(btree[it])
    50          
    100          
    100          
2734              
2735 1808 50         POP_MULTICALL;
    50          
2736              
2737 1808           SvREFCNT_inc(item);
2738 1808           insert_after(aTHX_ (RETVAL = first) - 1, item, list);
2739             }
2740             }
2741             OUTPUT:
2742             RETVAL
2743              
2744             void
2745             bremove(code, list)
2746             SV *code;
2747             AV *list;
2748             PROTOTYPE: &\@
2749             CODE:
2750             {
2751 419 100         I32 ret_gimme = GIMME_V;
2752 419 50         if(!codelike(code))
2753 0           croak_xs_usage(cv, "code, ...");
2754              
2755 419 50         if (AvFILLp(list) >= 0)
2756             {
2757             dMULTICALL;
2758 419           dMULTICALLSVCV;
2759 419           ssize_t count = AvFILLp(list) + 1, first = 0;
2760 419           int cmprc = -1;
2761 419           SV **btree = AvARRAY(list);
2762              
2763 419 50         PUSH_MULTICALL(mc_cv);
    50          
2764 419           SAVESPTR(GvSV(PL_defgv));
2765              
2766 2650 50         LOWER_BOUND_QUICK(btree[it])
    50          
    100          
    100          
    50          
2767              
2768 413 50         if(cmprc < 0 && first < items)
    0          
2769             {
2770 0 0         ASSERT_PL_defgv
2771 0           GvSV(PL_defgv) = btree[first];
2772 0           MULTICALL;
2773 0 0         cmprc = SvIV(*PL_stack_sp);
2774             }
2775              
2776 413 50         POP_MULTICALL;
    50          
2777              
2778 413 50         if(0 == cmprc)
2779             {
2780 413 100         if(AvFILLp(list) == first)
2781             {
2782 7           ST(0) = sv_2mortal(av_pop(list));
2783 413           XSRETURN(1);
2784             }
2785              
2786 406 100         if(0 == first)
2787             {
2788 6           ST(0) = sv_2mortal(av_shift(list));
2789 6           XSRETURN(1);
2790             }
2791              
2792 400           ST(0) = av_delete(list, first, 0);
2793 400           count = AvFILLp(list);
2794 30301 100         while(first < count)
2795             {
2796 29901           btree[first] = btree[first+1];
2797 29901           ++first;
2798             }
2799 400           SvREFCNT_inc(btree[count]);
2800 400           av_delete(list, count, G_DISCARD);
2801             #if PERL_VERSION_LE(5,8,5)
2802             sv_2mortal(ST(0));
2803             #endif
2804 400           XSRETURN(1);
2805             }
2806             }
2807              
2808 0 0         if (ret_gimme == G_ARRAY)
2809 0           XSRETURN_EMPTY;
2810             else
2811 0           XSRETURN_UNDEF;
2812             }
2813              
2814             void
2815             qsort(code, list)
2816             SV *code;
2817             AV *list;
2818             PROTOTYPE: &\@
2819             CODE:
2820             {
2821 2 50         I32 gimme = GIMME_V; /* perl-5.5.4 bus-errors out later when using GIMME
2822             therefore we save its value in a fresh variable */
2823             dMULTICALL;
2824              
2825 2 50         if(!codelike(code))
2826 0           croak_xs_usage(cv, "code, ...");
2827              
2828 2 50         if (in_pad(aTHX_ code))
2829 0           croak("Can't use lexical $a or $b in qsort's cmp code block");
2830            
2831 2 50         if (av_len(list) > 0)
2832             {
2833             HV *stash;
2834             GV *gv;
2835 2           CV *_cv = sv_2cv(code, &stash, &gv, 0);
2836              
2837 2 50         PUSH_MULTICALL(_cv);
    50          
2838              
2839 2           SAVEGENERICSV(PL_firstgv);
2840 2           SAVEGENERICSV(PL_secondgv);
2841 2           PL_firstgv = MUTABLE_GV(SvREFCNT_inc(
2842             gv_fetchpvs("a", GV_ADD|GV_NOTQUAL, SVt_PV)
2843             ));
2844 2           PL_secondgv = MUTABLE_GV(SvREFCNT_inc(
2845             gv_fetchpvs("b", GV_ADD|GV_NOTQUAL, SVt_PV)
2846             ));
2847             /* make sure the GP isn't removed out from under us for
2848             * the SAVESPTR() */
2849 2           save_gp(PL_firstgv, 0);
2850 2           save_gp(PL_secondgv, 0);
2851             /* we don't want modifications localized */
2852 2           GvINTRO_off(PL_firstgv);
2853 2           GvINTRO_off(PL_secondgv);
2854 2           SAVEGENERICSV(GvSV(PL_firstgv));
2855 2           SvREFCNT_inc(GvSV(PL_firstgv));
2856 2           SAVEGENERICSV(GvSV(PL_secondgv));
2857 2           SvREFCNT_inc(GvSV(PL_secondgv));
2858              
2859 2           bsd_qsort_r(aTHX_ AvARRAY(list), av_len(list) + 1, multicall_cop);
2860 2 50         POP_MULTICALL;
    50          
2861             }
2862             }
2863              
2864             void
2865             _XScompiled ()
2866             CODE:
2867 0           XSRETURN_YES;