File Coverage

XS.xs
Criterion Covered Total %
statement 919 1004 91.5
branch 1333 2484 53.6
condition n/a
subroutine n/a
pod n/a
total 2252 3488 64.5


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 1821           insert_after (pTHX_ int idx, SV *what, AV *av)
524             {
525             int i, len;
526 1821           av_extend(av, (len = av_len(av) + 1));
527              
528 107541 100         for (i = len; i > idx+1; i--)
529             {
530 105720           SV **sv = av_fetch(av, i-1, FALSE);
531 105720           SvREFCNT_inc(*sv);
532 105720           av_store(av, i, *sv);
533             }
534              
535 1821 50         if (!av_store(av, idx+1, what))
536 0           SvREFCNT_dec(what);
537 1821           }
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 364 100         for (i = 0; i < maxitems; ++i)
1714             {
1715             SV **j;
1716 356           SV *olda = GvSV(PL_firstgv), *oldb = GvSV(PL_secondgv);
1717              
1718 356           SV **svp = av_fetch(list1, i, FALSE);
1719 356 100         GvSV(PL_firstgv) = SvREFCNT_inc_simple_NN(svp ? *svp : &PL_sv_undef);
    100          
1720 356           svp = av_fetch(list2, i, FALSE);
1721 356 50         GvSV(PL_secondgv) = SvREFCNT_inc_simple_NN(svp ? *svp : &PL_sv_undef);
    50          
1722 356           SvREFCNT_dec(olda);
1723 356           SvREFCNT_dec(oldb);
1724              
1725 356           MULTICALL;
1726              
1727 744 100         for (j = PL_stack_base+1; j <= PL_stack_sp; ++j)
1728 391           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 395 100         for(i = AvFILLp(rc); i >= 0; --i)
1737             {
1738 387           ST(i) = sv_2mortal(AvARRAY(rc)[i]);
1739 387           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         if (GIMME_V == G_SCALAR)
    50          
1934             {
1935 0           ST(0) = sv_2mortal(newSVuv(i));
1936 0           XSRETURN(1);
1937             }
1938             else
1939             {
1940 4 50         EXTEND(SP, i * 2);
    50          
1941              
1942 4           i = 0;
1943 4           hv_iterinit(rc);
1944             for(;;)
1945             {
1946 58           HE *he = hv_iternext(rc);
1947             SV *key, *val;
1948 58 100         if(NULL == he)
1949 4           break;
1950              
1951 54 50         if(UNLIKELY(( NULL == (key = HeSVKEY_force(he)) ) || ( NULL == (val = HeVAL(he)) )))
    50          
    50          
    50          
    50          
1952 0           continue;
1953              
1954 54           ST(i++) = key;
1955 54           ST(i++) = val;
1956 54           }
1957              
1958 4           XSRETURN(i);
1959             }
1960             }
1961              
1962             void
1963             uniq (...)
1964             PROTOTYPE: @
1965             CODE:
1966             {
1967             I32 i;
1968 20           IV count = 0, seen_undef = 0;
1969 20           HV *hv = newHV();
1970 20           SV **args = &PL_stack_base[ax];
1971 20           SV *tmp = sv_newmortal();
1972 20           sv_2mortal(newRV_noinc((SV*)hv));
1973              
1974             /* don't build return list in scalar context */
1975 20 100         if (GIMME_V == G_SCALAR)
    100          
1976             {
1977 241 100         for (i = 0; i < items; i++)
1978             {
1979 236 100         SvGETMAGIC(args[i]);
    50          
1980 236 50         if(SvOK(args[i]))
    0          
    0          
1981             {
1982 236           sv_setsv_nomg(tmp, args[i]);
1983 354 100         if (!hv_exists_ent(hv, tmp, 0))
1984             {
1985 118           ++count;
1986 118           hv_store_ent(hv, tmp, &PL_sv_yes, 0);
1987             }
1988             }
1989 0 0         else if(0 == seen_undef++)
1990 0           ++count;
1991             }
1992 5           ST(0) = sv_2mortal(newSVuv(count));
1993 5           XSRETURN(1);
1994             }
1995              
1996             /* list context: populate SP with mortal copies */
1997 4490 100         for (i = 0; i < items; i++)
1998             {
1999 4477 100         SvGETMAGIC(args[i]);
    50          
2000 4477 100         if(SvOK(args[i]))
    50          
    50          
2001             {
2002 4476 50         SvSetSV_nosteal(tmp, args[i]);
2003 6830 100         if (!hv_exists_ent(hv, tmp, 0))
2004             {
2005             /*ST(count) = sv_2mortal(newSVsv(ST(i)));
2006             ++count;*/
2007 2354           args[count++] = args[i];
2008 2354           hv_store_ent(hv, tmp, &PL_sv_yes, 0);
2009             }
2010             }
2011 1 50         else if(0 == seen_undef++)
2012 1           args[count++] = args[i];
2013             }
2014              
2015 13           XSRETURN(count);
2016             }
2017              
2018             void
2019             singleton (...)
2020             PROTOTYPE: @
2021             CODE:
2022             {
2023             I32 i;
2024 19           IV cnt = 0, count = 0, seen_undef = 0;
2025 19           HV *hv = newHV();
2026 19           SV **args = &PL_stack_base[ax];
2027 19           SV *tmp = sv_newmortal();
2028              
2029 19           sv_2mortal(newRV_noinc((SV*)hv));
2030              
2031 42320 100         COUNT_ARGS
    50          
    100          
    50          
    50          
    50          
    100          
    100          
    100          
2032              
2033             /* don't build return list in scalar context */
2034 15 50         if (GIMME_V == G_SCALAR)
    100          
2035             {
2036 12772 100         for (i = 0; i < count; i++)
2037             {
2038 12765 100         if(SvOK(args[i]))
    50          
    50          
2039 12764           {
2040             HE *he;
2041 12764           sv_setsv_nomg(tmp, args[i]);
2042 12764           he = hv_fetch_ent(hv, tmp, 0, 0);
2043 12764 50         if (he)
2044 12764 100         if( 1 == SvIVX(HeVAL(he)) )
2045 4383           ++cnt;
2046             }
2047 1 50         else if(1 == seen_undef)
2048 0           ++cnt;
2049             }
2050 7           ST(0) = sv_2mortal(newSViv(cnt));
2051 7           XSRETURN(1);
2052             }
2053              
2054             /* list context: populate SP with mortal copies */
2055 12778 100         for (i = 0; i < count; i++)
2056             {
2057 12770 100         if(SvOK(args[i]))
    50          
    50          
2058 12768           {
2059             HE *he;
2060 12768 50         SvSetSV_nosteal(tmp, args[i]);
2061 12768           he = hv_fetch_ent(hv, tmp, 0, 0);
2062 12768 50         if (he)
2063 12768 100         if( 1 == SvIVX(HeVAL(he)) )
2064 4385           args[cnt++] = args[i];
2065             }
2066 2 100         else if(1 == seen_undef)
2067 1           args[cnt++] = args[i];
2068             }
2069              
2070 8           XSRETURN(cnt);
2071             }
2072              
2073             void
2074             duplicates (...)
2075             PROTOTYPE: @
2076             CODE:
2077             {
2078             I32 i;
2079 19           IV cnt = 0, count = 0, seen_undef = 0;
2080 19           HV *hv = newHV();
2081 19           SV **args = &PL_stack_base[ax];
2082 19           SV *tmp = sv_newmortal();
2083              
2084 19           sv_2mortal(newRV_noinc((SV*)hv));
2085              
2086 41461 100         COUNT_ARGS
    50          
    100          
    50          
    50          
    50          
    100          
    100          
    100          
2087              
2088             /* don't build return list in scalar context */
2089 15 50         if (GIMME_V == G_SCALAR)
    100          
2090             {
2091 11896 100         for (i = 0; i < count; i++)
2092             {
2093 11889 100         if(SvOK(args[i]))
    50          
    50          
2094 11888           {
2095             HE *he;
2096 11888           sv_setsv_nomg(tmp, args[i]);
2097 11888           he = hv_fetch_ent(hv, tmp, 0, 0);
2098 11888 50         if (he)
2099 11888 100         if( 1 < SvIVX(HeVAL(he)) )
2100 8382           ++cnt;
2101             }
2102 1 50         else if(1 < seen_undef)
2103 0           ++cnt;
2104             }
2105 7           ST(0) = sv_2mortal(newSViv(cnt));
2106 7           XSRETURN(1);
2107             }
2108              
2109             /* list context: populate SP with mortal copies */
2110 12778 100         for (i = 0; i < count; i++)
2111             {
2112 12770 100         if(SvOK(args[i]))
    50          
    50          
2113 12768           {
2114             HE *he;
2115 12768 50         SvSetSV_nosteal(tmp, args[i]);
2116 12768           he = hv_fetch_ent(hv, tmp, 0, 0);
2117 12768 50         if (he)
2118 12768 100         if( 1 < SvIVX(HeVAL(he)) )
2119 8384           args[cnt++] = args[i];
2120             }
2121 2 100         else if(1 < seen_undef) {
2122 1           args[cnt++] = args[i];
2123             }
2124             }
2125              
2126 8           XSRETURN(cnt);
2127             }
2128              
2129             void
2130             frequency (...)
2131             PROTOTYPE: @
2132             CODE:
2133             {
2134             I32 i;
2135 17           IV count = 0, seen_undef = 0;
2136 17           HV *hv = newHV();
2137 17           SV **args = &PL_stack_base[ax];
2138 17           SV *tmp = sv_newmortal();
2139              
2140 17           sv_2mortal(newRV_noinc((SV*)hv));
2141              
2142 42321 100         COUNT_ARGS
    50          
    100          
    50          
    50          
    50          
    100          
    100          
    100          
2143              
2144 13 50         i = HvUSEDKEYS(hv);
2145 13 100         if(seen_undef)
2146 1           ++i;
2147              
2148             /* don't build return list in scalar context */
2149 13 50         if (GIMME_V == G_SCALAR)
    100          
2150             {
2151 6           ST(0) = sv_2mortal(newSViv(i));
2152 6           XSRETURN(1);
2153             }
2154              
2155 7 50         EXTEND(SP, i * 2);
    100          
2156              
2157 7           i = 0;
2158 7           hv_iterinit(hv);
2159             for(;;)
2160             {
2161 12771           HE *he = hv_iternext(hv);
2162             SV *key, *val;
2163 12771 100         if(NULL == he)
2164 7           break;
2165              
2166 12764 50         if(UNLIKELY(( NULL == (key = HeSVKEY_force(he)) ) || ( NULL == (val = HeVAL(he)) )))
    50          
    50          
    50          
    50          
2167 0           continue;
2168              
2169 12764           ST(i++) = key;
2170 12764           ST(i++) = val;
2171 12764           }
2172              
2173 7 100         if(seen_undef)
2174             {
2175 1           ST(i++) = sv_2mortal(newRV(newSVsv(&PL_sv_undef)));
2176 1           ST(i++) = sv_2mortal(newSViv(seen_undef));;
2177             }
2178              
2179 7           XSRETURN(i);
2180             }
2181              
2182             void
2183             occurrences (...)
2184             PROTOTYPE: @
2185             CODE:
2186             {
2187             I32 i;
2188 12           IV count = 0, seen_undef = 0, max = items > 0 ? 1 : 0;
2189 12           HV *hv = newHV();
2190 12           SV **args = &PL_stack_base[ax];
2191 12           SV *tmp = sv_newmortal();
2192              
2193 12           sv_2mortal(newRV_noinc((SV*)hv));
2194              
2195 427 50         COUNT_ARGS_MAX;
    0          
    100          
    50          
    50          
    50          
    100          
    100          
    100          
    100          
    50          
2196              
2197             /* don't build return list in scalar context */
2198 8 50         if (GIMME_V == G_SCALAR)
    100          
2199             {
2200 2           ST(0) = sv_2mortal(newSViv(i));
2201 2           XSRETURN(1);
2202             }
2203              
2204 6 50         EXTEND(SP, max + 1);
    50          
2205 60 100         for(i = 0; i <= max; ++i)
2206 54           ST(i) = &PL_sv_undef;
2207              
2208 6           hv_iterinit(hv);
2209             for(;;)
2210             {
2211 112           HE *he = hv_iternext(hv);
2212             SV *key, *val;
2213             AV *store;
2214 112 100         if(NULL == he)
2215 6           break;
2216              
2217 106 50         if(UNLIKELY(( NULL == (key = HeSVKEY_force(he)) ) || ( NULL == (val = HeVAL(he)) )))
    50          
    50          
    50          
    50          
2218 0           continue;
2219              
2220 106           i = SvIVX(val);
2221 106 100         if(ST(i) == &PL_sv_undef)
2222             {
2223 28           store = newAV();
2224 28           ST(i) = sv_2mortal(newRV_noinc((SV *)store));
2225             }
2226             else
2227 78           store = (AV *)SvRV(ST(i));
2228 106           av_push(store, newSVsv(key));
2229 106           }
2230              
2231 6 100         if(seen_undef)
2232             {
2233             AV *store;
2234 1 50         if(ST(seen_undef) == &PL_sv_undef)
2235             {
2236 1           store = newAV();
2237 1           ST(seen_undef) = sv_2mortal(newRV_noinc((SV *)store));
2238             }
2239             else
2240             {
2241 0           store = (AV *)SvRV(ST(seen_undef));
2242             }
2243 1           av_push(store, &PL_sv_undef);
2244             }
2245              
2246 6           XSRETURN(max+1);
2247             }
2248              
2249             void
2250             mode (...)
2251             PROTOTYPE: @
2252             CODE:
2253             {
2254             I32 i;
2255 32           IV count = 0, seen_undef = 0, max = items > 0 ? 1 : 0;
2256 32           HV *hv = newHV();
2257 32           SV **args = &PL_stack_base[ax];
2258 32           SV *tmp = sv_newmortal();
2259              
2260 32           sv_2mortal(newRV_noinc((SV*)hv));
2261              
2262 1200 50         COUNT_ARGS_MAX;
    0          
    50          
    0          
    0          
    50          
    100          
    100          
    0          
    100          
    50          
2263              
2264 20 50         EXTEND(SP, count = 1);
2265 20           ST(0) = sv_2mortal(newSViv(max));
2266              
2267             /* don't build return list in scalar context */
2268 20 50         if (GIMME_V == G_SCALAR)
    100          
2269 10           XSRETURN(1);
2270              
2271              
2272 10           hv_iterinit(hv);
2273             for(;;)
2274             {
2275 178           HE *he = hv_iternext(hv);
2276             SV *key, *val;
2277 178 100         if(NULL == he)
2278 10           break;
2279              
2280 168 50         if(UNLIKELY(( NULL == (key = HeSVKEY_force(he)) ) || ( NULL == (val = HeVAL(he)) )))
    50          
    50          
    50          
    50          
2281 0           continue;
2282              
2283 168           i = SvIVX(val);
2284 168 100         if(max == i)
2285             {
2286 18           ++count;
2287 18 50         EXTEND(SP, count);
    50          
2288 18           ST(count-1) = sv_mortalcopy(key);
2289             }
2290 168           }
2291              
2292 10 50         if(seen_undef == max)
2293             {
2294 0           ++count;
2295 0 0         EXTEND(SP, count);
    0          
2296 0           ST(count-1) = &PL_sv_undef;
2297             }
2298              
2299 10           XSRETURN(count);
2300             }
2301              
2302             void
2303             samples (k, ...)
2304             I32 k;
2305             PROTOTYPE: $@
2306             CODE:
2307             {
2308             I32 i;
2309              
2310 5 100         if( k > (items - 1) )
2311 2           croak("Cannot get %" IVdf " samples from %" IVdf " elements", (IV)k, (IV)(items-1));
2312              
2313             /* Initialize Drand01 unless rand() or srand() has already been called */
2314 3 100         if(!PL_srand_called)
2315             {
2316             #ifdef HAVE_TIME
2317             /* using time(NULL) as seed seems to get better random numbers ... */
2318 1           (void)seedDrand01((Rand_seed_t)time(NULL));
2319             #else
2320             (void)seedDrand01((Rand_seed_t)Perl_seed(aTHX));
2321             #endif
2322 1           PL_srand_called = TRUE;
2323             }
2324              
2325             /* optimzed Knuth-Shuffle since we move our stack one item downwards
2326             with each exchange */
2327 33 100         for (i = items ; items - i < k ; )
2328             {
2329 30           I32 index = items - i + 1;
2330 30           I32 swap = index + (I32)(Drand01() * (double)(--i));
2331 30           ST(index-1) = ST(swap);
2332 30           ST(swap) = ST(index);
2333             }
2334              
2335 3           XSRETURN(k);
2336             }
2337              
2338             void
2339             minmax (...)
2340             PROTOTYPE: @
2341             CODE:
2342             {
2343             I32 i;
2344             SV *minsv, *maxsv;
2345              
2346 31 50         if (!items)
2347 0           XSRETURN_EMPTY;
2348              
2349 31 100         if (items == 1)
2350             {
2351 21 50         EXTEND(SP, 1);
2352 21           ST(1) = sv_2mortal(newSVsv(ST(0)));
2353 21           XSRETURN(2);
2354             }
2355              
2356 10           minsv = maxsv = ST(0);
2357              
2358 10057 100         for (i = 1; i < items; i += 2)
2359             {
2360 10047           SV *asv = ST(i-1);
2361 10047           SV *bsv = ST(i);
2362 10047           int cmp = ncmp(asv, bsv);
2363 10047 100         if (cmp < 0)
2364             {
2365 28           int min_cmp = ncmp(minsv, asv);
2366 28           int max_cmp = ncmp(maxsv, bsv);
2367 28 100         if (min_cmp > 0)
2368 1           minsv = asv;
2369 28 100         if (max_cmp < 0)
2370 28           maxsv = bsv;
2371             }
2372             else
2373             {
2374 10019           int min_cmp = ncmp(minsv, bsv);
2375 10019           int max_cmp = ncmp(maxsv, asv);
2376 10019 100         if (min_cmp > 0)
2377 10016           minsv = bsv;
2378 10019 100         if (max_cmp < 0)
2379 6           maxsv = asv;
2380             }
2381             }
2382              
2383 10 100         if (items & 1)
2384             {
2385 4           SV *rsv = ST(items-1);
2386 4 100         if (ncmp(minsv, rsv) > 0)
2387 3           minsv = rsv;
2388 1 50         else if (ncmp(maxsv, rsv) < 0)
2389 1           maxsv = rsv;
2390             }
2391              
2392 10           ST(0) = minsv;
2393 10           ST(1) = maxsv;
2394              
2395 10           XSRETURN(2);
2396             }
2397              
2398             void
2399             minmaxstr (...)
2400             PROTOTYPE: @
2401             CODE:
2402             {
2403             I32 i;
2404             SV *minsv, *maxsv;
2405              
2406 25 50         if (!items)
2407 0           XSRETURN_EMPTY;
2408              
2409 25 100         if (items == 1)
2410             {
2411 21 50         EXTEND(SP, 1);
2412 21           ST(1) = sv_2mortal(newSVsv(ST(0)));
2413 21           XSRETURN(2);
2414             }
2415              
2416 4           minsv = maxsv = ST(0);
2417              
2418 1356 100         for (i = 1; i < items; i += 2)
2419             {
2420 1352           SV *asv = ST(i-1);
2421 1352           SV *bsv = ST(i);
2422 1352           int cmp = sv_cmp_locale(asv, bsv);
2423 1352 50         if (cmp < 0)
2424             {
2425 0           int min_cmp = sv_cmp_locale(minsv, asv);
2426 0           int max_cmp = sv_cmp_locale(maxsv, bsv);
2427 0 0         if (min_cmp > 0)
2428 0           minsv = asv;
2429 0 0         if (max_cmp < 0)
2430 0           maxsv = bsv;
2431             }
2432             else
2433             {
2434 1352           int min_cmp = sv_cmp_locale(minsv, bsv);
2435 1352           int max_cmp = sv_cmp_locale(maxsv, asv);
2436 1352 50         if (min_cmp > 0)
2437 1352           minsv = bsv;
2438 1352 50         if (max_cmp < 0)
2439 0           maxsv = asv;
2440             }
2441             }
2442              
2443 4 100         if (items & 1)
2444             {
2445 3           SV *rsv = ST(items-1);
2446 3 100         if (sv_cmp_locale(minsv, rsv) > 0)
2447 2           minsv = rsv;
2448 1 50         else if (sv_cmp_locale(maxsv, rsv) < 0)
2449 1           maxsv = rsv;
2450             }
2451              
2452 4           ST(0) = minsv;
2453 4           ST(1) = maxsv;
2454              
2455 4           XSRETURN(2);
2456             }
2457              
2458             void
2459             part (code, ...)
2460             SV *code;
2461             PROTOTYPE: &@
2462             CODE:
2463             {
2464             dMULTICALL;
2465 12           dMULTICALLSVCV;
2466             int i;
2467 12           SV **args = &PL_stack_base[ax];
2468 12           AV *tmp = newAV();
2469 12           sv_2mortal(newRV_noinc((SV*)tmp));
2470              
2471 12 50         if(!codelike(code))
2472 0           croak_xs_usage(cv, "code, ...");
2473              
2474 12 100         if (items == 1)
2475 2           XSRETURN_EMPTY;
2476              
2477 10 50         PUSH_MULTICALL(mc_cv);
    50          
2478 10           SAVESPTR(GvSV(PL_defgv));
2479              
2480 96 100         for(i = 1 ; i < items ; ++i)
2481             {
2482             IV idx;
2483             SV **inner;
2484             AV *av;
2485              
2486 87 50         ASSERT_PL_defgv
2487 87           GvSV(PL_defgv) = args[i];
2488 87           MULTICALL;
2489 87 50         idx = SvIV(*PL_stack_sp);
2490              
2491 87 100         if (UNLIKELY(idx < 0 && (idx += (AvFILLp(tmp)+1)) < 0))
    100          
2492 1           croak("Modification of non-creatable array value attempted, subscript %" IVdf, idx);
2493              
2494 86 100         if(UNLIKELY(NULL == (inner = av_fetch(tmp, idx, FALSE))))
2495             {
2496 24           av = newAV();
2497 24           av_push(av, newSVsv(args[i]));
2498 24           av_store(tmp, idx, newRV_noinc((SV *)av));
2499             }
2500             else
2501             {
2502 62           av = (AV*)SvRV(*inner);
2503 62           av_push(av, newSVsv(args[i]));
2504             }
2505             }
2506 9 50         POP_MULTICALL;
    50          
2507              
2508 9 50         EXTEND(SP, AvFILLp(tmp)+1);
    100          
2509 12085 100         for(i = AvFILLp(tmp); i >= 0; --i)
2510             {
2511 12076           SV *v = AvARRAY(tmp)[i];
2512 12076 100         ST(i) = v && is_array(v) ? sv_2mortal(v) : &PL_sv_undef;
    50          
2513 12076           AvARRAY(tmp)[i] = NULL;
2514             }
2515              
2516 9           i = AvFILLp(tmp) + 1;
2517 9           AvFILLp(tmp) = -1;
2518              
2519 11           XSRETURN(i);
2520             }
2521              
2522             void
2523             bsearch (code, ...)
2524             SV *code;
2525             PROTOTYPE: &@
2526             CODE:
2527             {
2528 2029 100         I32 ret_gimme = GIMME_V;
2529 2029 100         if(!codelike(code))
2530 1           croak_xs_usage(cv, "code, ...");
2531              
2532 2028 50         if (items > 1)
2533             {
2534             dMULTICALL;
2535 2028           dMULTICALLSVCV;
2536 2028           ssize_t count = items - 1, first = 1;
2537 2028           int cmprc = -1;
2538 2028           SV **args = &PL_stack_base[ax];
2539              
2540 2028 50         PUSH_MULTICALL(mc_cv);
    50          
2541 2028           SAVESPTR(GvSV(PL_defgv));
2542              
2543 18254 50         LOWER_BOUND_QUICK(args[it])
    50          
    100          
    100          
    100          
2544              
2545 2026 100         if(cmprc < 0 && first < items)
    50          
2546             {
2547 0 0         ASSERT_PL_defgv
2548 0           GvSV(PL_defgv) = args[first];
2549 0           MULTICALL;
2550 0 0         cmprc = SvIV(*PL_stack_sp);
2551             }
2552              
2553 2026 50         POP_MULTICALL;
    50          
2554              
2555 2026 100         if(0 == cmprc)
2556             {
2557 2004 100         if (ret_gimme != G_ARRAY)
2558 2004           XSRETURN_YES;
2559 1000           ST(0) = args[first];
2560 1022           XSRETURN(1);
2561             }
2562             }
2563              
2564 22 50         if(ret_gimme == G_ARRAY)
2565 0           XSRETURN_EMPTY;
2566 22           XSRETURN_UNDEF;
2567             }
2568              
2569             int
2570             bsearchidx (code, ...)
2571             SV *code;
2572             PROTOTYPE: &@
2573             CODE:
2574             {
2575 1029 100         I32 ret_gimme = GIMME_V;
2576 1029 100         if(!codelike(code))
2577 1           croak_xs_usage(cv, "code, ...");
2578              
2579 1028           RETVAL = -1;
2580 1028 50         if (items > 1)
2581             {
2582             dMULTICALL;
2583 1028           dMULTICALLSVCV;
2584 1028           ssize_t count = items - 1, first = 1;
2585 1028           int cmprc = -1;
2586 1028           SV **args = &PL_stack_base[ax];
2587              
2588 1028 50         PUSH_MULTICALL(mc_cv);
    50          
2589 1028           SAVESPTR(GvSV(PL_defgv));
2590              
2591 9270 50         LOWER_BOUND_QUICK(args[it])
    50          
    100          
    100          
    100          
2592              
2593 1026 100         if(cmprc < 0 && first < items)
    50          
2594             {
2595 0 0         ASSERT_PL_defgv
2596 0           GvSV(PL_defgv) = args[first];
2597 0           MULTICALL;
2598 0 0         cmprc = SvIV(*PL_stack_sp);
2599             }
2600              
2601 1026 50         POP_MULTICALL;
    50          
2602              
2603 1026 100         if(0 == cmprc)
2604 1026           RETVAL = --first;
2605             }
2606             }
2607             OUTPUT:
2608             RETVAL
2609              
2610             int
2611             lower_bound (code, ...)
2612             SV *code;
2613             PROTOTYPE: &@
2614             CODE:
2615             {
2616 234 100         if(!codelike(code))
2617 1           croak_xs_usage(cv, "code, ...");
2618              
2619 233 50         if (items > 1)
2620             {
2621             dMULTICALL;
2622 233           dMULTICALLSVCV;
2623 233           ssize_t count = items - 1, first = 1;
2624 233           int cmprc = -1;
2625 233           SV **args = &PL_stack_base[ax];
2626              
2627 233 50         PUSH_MULTICALL(mc_cv);
    50          
2628 233           SAVESPTR(GvSV(PL_defgv));
2629              
2630 1787 50         LOWER_BOUND(args[it])
    50          
    100          
    100          
2631              
2632 233 50         POP_MULTICALL;
    50          
2633              
2634 233           RETVAL = --first;
2635             }
2636             else
2637 0           RETVAL = -1;
2638             }
2639             OUTPUT:
2640             RETVAL
2641              
2642             int
2643             upper_bound (code, ...)
2644             SV *code;
2645             PROTOTYPE: &@
2646             CODE:
2647             {
2648 234 100         if(!codelike(code))
2649 1           croak_xs_usage(cv, "code, ...");
2650              
2651 233 50         if (items > 1)
2652             {
2653             dMULTICALL;
2654 233           dMULTICALLSVCV;
2655 233           ssize_t count = items - 1, first = 1;
2656 233           int cmprc = -1;
2657 233           SV **args = &PL_stack_base[ax];
2658              
2659 233 50         PUSH_MULTICALL(mc_cv);
    50          
2660 233           SAVESPTR(GvSV(PL_defgv));
2661              
2662 1786 50         UPPER_BOUND(args[it])
    50          
    100          
    100          
2663              
2664 233 50         POP_MULTICALL;
    50          
2665              
2666 233           RETVAL = --first;
2667             }
2668             else
2669 0           RETVAL = -1;
2670             }
2671             OUTPUT:
2672             RETVAL
2673              
2674             void
2675             equal_range (code, ...)
2676             SV *code;
2677             PROTOTYPE: &@
2678             CODE:
2679             {
2680 12 100         if(!codelike(code))
2681 1           croak_xs_usage(cv, "code, ...");
2682              
2683 11 50         if (items > 1)
2684             {
2685             dMULTICALL;
2686 11           dMULTICALLSVCV;
2687 11           ssize_t count = items - 1, first = 1;
2688             ssize_t lb;
2689 11           int cmprc = -1;
2690 11           SV **args = &PL_stack_base[ax];
2691              
2692 11 50         PUSH_MULTICALL(mc_cv);
    50          
2693 11           SAVESPTR(GvSV(PL_defgv));
2694              
2695 73 50         LOWER_BOUND(args[it])
    50          
    100          
    100          
2696 9           lb = first - 1;
2697              
2698 9           count = items - first;
2699 49 50         UPPER_BOUND(args[it])
    50          
    100          
    100          
2700              
2701 9 50         POP_MULTICALL;
    50          
2702              
2703 9 50         EXTEND(SP, 2);
2704 9           ST(0) = sv_2mortal(newSViv(lb));
2705 9           ST(1) = sv_2mortal(newSViv(first - 1));
2706 9           XSRETURN(2);
2707             }
2708              
2709 0           XSRETURN_EMPTY;
2710             }
2711              
2712             int
2713             binsert(code, item, list)
2714             SV *code;
2715             SV *item;
2716             AV *list;
2717             PROTOTYPE: &$\@
2718             CODE:
2719             {
2720 1810 50         if(!codelike(code))
2721 0           croak_xs_usage(cv, "code, val, list");
2722              
2723 1810           RETVAL = -1;
2724              
2725 1810 100         if (AvFILLp(list) == -1)
2726             {
2727 1           av_push(list, newSVsv(item));
2728 1           RETVAL = 0;
2729             }
2730 1809 50         else if (AvFILLp(list) >= 0)
2731             {
2732             dMULTICALL;
2733 1809           dMULTICALLSVCV;
2734 1809           ssize_t count = AvFILLp(list) + 1, first = 0;
2735 1809           int cmprc = -1;
2736 1809           SV **btree = AvARRAY(list);
2737              
2738 1809 50         PUSH_MULTICALL(mc_cv);
    50          
2739 1809           SAVESPTR(GvSV(PL_defgv));
2740              
2741 14997 50         LOWER_BOUND(btree[it])
    50          
    100          
    100          
2742              
2743 1809 50         POP_MULTICALL;
    50          
2744              
2745 1809           SvREFCNT_inc(item);
2746 1809           insert_after(aTHX_ (RETVAL = first) - 1, item, list);
2747             }
2748             }
2749             OUTPUT:
2750             RETVAL
2751              
2752             void
2753             bremove(code, list)
2754             SV *code;
2755             AV *list;
2756             PROTOTYPE: &\@
2757             CODE:
2758             {
2759 419 100         I32 ret_gimme = GIMME_V;
2760 419 50         if(!codelike(code))
2761 0           croak_xs_usage(cv, "code, ...");
2762              
2763 419 50         if (AvFILLp(list) >= 0)
2764             {
2765             dMULTICALL;
2766 419           dMULTICALLSVCV;
2767 419           ssize_t count = AvFILLp(list) + 1, first = 0;
2768 419           int cmprc = -1;
2769 419           SV **btree = AvARRAY(list);
2770              
2771 419 50         PUSH_MULTICALL(mc_cv);
    50          
2772 419           SAVESPTR(GvSV(PL_defgv));
2773              
2774 2650 50         LOWER_BOUND_QUICK(btree[it])
    50          
    100          
    100          
    50          
2775              
2776 413 50         if(cmprc < 0 && first < items)
    0          
2777             {
2778 0 0         ASSERT_PL_defgv
2779 0           GvSV(PL_defgv) = btree[first];
2780 0           MULTICALL;
2781 0 0         cmprc = SvIV(*PL_stack_sp);
2782             }
2783              
2784 413 50         POP_MULTICALL;
    50          
2785              
2786 413 50         if(0 == cmprc)
2787             {
2788 413 100         if(AvFILLp(list) == first)
2789             {
2790 7           ST(0) = sv_2mortal(av_pop(list));
2791 413           XSRETURN(1);
2792             }
2793              
2794 406 100         if(0 == first)
2795             {
2796 6           ST(0) = sv_2mortal(av_shift(list));
2797 6           XSRETURN(1);
2798             }
2799              
2800 400           ST(0) = av_delete(list, first, 0);
2801 400           count = AvFILLp(list);
2802 30301 100         while(first < count)
2803             {
2804 29901           btree[first] = btree[first+1];
2805 29901           ++first;
2806             }
2807 400           SvREFCNT_inc(btree[count]);
2808 400           av_delete(list, count, G_DISCARD);
2809             #if PERL_VERSION_LE(5,8,5)
2810             sv_2mortal(ST(0));
2811             #endif
2812 400           XSRETURN(1);
2813             }
2814             }
2815              
2816 0 0         if (ret_gimme == G_ARRAY)
2817 0           XSRETURN_EMPTY;
2818             else
2819 0           XSRETURN_UNDEF;
2820             }
2821              
2822             void
2823             qsort(code, list)
2824             SV *code;
2825             AV *list;
2826             PROTOTYPE: &\@
2827             CODE:
2828             {
2829 2 50         I32 gimme = GIMME_V; /* perl-5.5.4 bus-errors out later when using GIMME
2830             therefore we save its value in a fresh variable */
2831             dMULTICALL;
2832              
2833 2 50         if(!codelike(code))
2834 0           croak_xs_usage(cv, "code, ...");
2835              
2836 2 50         if (in_pad(aTHX_ code))
2837 0           croak("Can't use lexical $a or $b in qsort's cmp code block");
2838            
2839 2 50         if (av_len(list) > 0)
2840             {
2841             HV *stash;
2842             GV *gv;
2843 2           CV *_cv = sv_2cv(code, &stash, &gv, 0);
2844              
2845 2 50         PUSH_MULTICALL(_cv);
    50          
2846              
2847 2           SAVEGENERICSV(PL_firstgv);
2848 2           SAVEGENERICSV(PL_secondgv);
2849 2           PL_firstgv = MUTABLE_GV(SvREFCNT_inc(
2850             gv_fetchpvs("a", GV_ADD|GV_NOTQUAL, SVt_PV)
2851             ));
2852 2           PL_secondgv = MUTABLE_GV(SvREFCNT_inc(
2853             gv_fetchpvs("b", GV_ADD|GV_NOTQUAL, SVt_PV)
2854             ));
2855             /* make sure the GP isn't removed out from under us for
2856             * the SAVESPTR() */
2857 2           save_gp(PL_firstgv, 0);
2858 2           save_gp(PL_secondgv, 0);
2859             /* we don't want modifications localized */
2860 2           GvINTRO_off(PL_firstgv);
2861 2           GvINTRO_off(PL_secondgv);
2862 2           SAVEGENERICSV(GvSV(PL_firstgv));
2863 2           SvREFCNT_inc(GvSV(PL_firstgv));
2864 2           SAVEGENERICSV(GvSV(PL_secondgv));
2865 2           SvREFCNT_inc(GvSV(PL_secondgv));
2866              
2867 2           bsd_qsort_r(aTHX_ AvARRAY(list), av_len(list) + 1, multicall_cop);
2868 2 50         POP_MULTICALL;
    50          
2869             }
2870             }
2871              
2872             void
2873             _XScompiled ()
2874             CODE:
2875 0           XSRETURN_YES;