File Coverage

XS.xs
Criterion Covered Total %
statement 3362 3782 88.8
branch 3455 4866 71.0
condition n/a
subroutine n/a
pod n/a
total 6817 8648 78.8


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT 1 /* Define at top for more efficiency. */
2              
3             #if defined(__clang__) && defined(__clang_major__) && __clang_major__ > 11
4             #pragma clang diagnostic ignored "-Wcompound-token-split-by-macro"
5             #endif
6              
7             #include "EXTERN.h"
8             #include "perl.h"
9             #include "XSUB.h"
10             #include "multicall.h" /* only works in 5.6 and newer */
11             #include /* For fileno and stdout */
12              
13             #define NEED_newCONSTSUB
14             #define NEED_newRV_noinc
15             #define NEED_sv_2pv_flags
16             #define NEED_HvNAME_get
17             #include "ppport.h"
18              
19             #define FUNC_gcd_ui 1
20             #define FUNC_isqrt 1
21             #define FUNC_ipow 1
22             #define FUNC_popcnt 1
23             #include "ptypes.h"
24             #include "cache.h"
25             #include "sieve.h"
26             #include "sieve_cluster.h"
27             #include "util.h"
28             #include "sort.h"
29             #include "primality.h"
30             #include "lucas_seq.h"
31             #include "factor.h"
32             #include "totients.h"
33             #include "lehmer.h"
34             #include "lmo.h"
35             #include "legendre_phi.h"
36             #include "aks.h"
37             #include "constants.h"
38             #include "mulmod.h"
39             #include "entropy.h"
40             #include "csprng.h"
41             #include "random_prime.h"
42             #include "perfect_powers.h"
43             #include "prime_powers.h"
44             #include "ramanujan_primes.h"
45             #include "semi_primes.h"
46             #include "twin_primes.h"
47             #include "almost_primes.h"
48             #include "omega_primes.h"
49             #include "prime_counts.h"
50             #include "prime_sums.h"
51             #include "congruent_numbers.h"
52             #include "powerfree.h"
53             #include "powerful.h"
54             #include "lucky_numbers.h"
55             #include "goldbach.h"
56             #include "rootmod.h"
57             #include "rational.h"
58             #include "real.h"
59             #include "ds_iset.h" /* Used for sumset, setbinop, is_sidon_set, vecuniq */
60              
61             #ifdef FACTORING_HARNESSES
62             #include
63             static double my_difftime (struct timeval * start, struct timeval * end) {
64             double secs, usecs;
65             if (start->tv_sec == end->tv_sec) {
66             secs = 0;
67             usecs = end->tv_usec - start->tv_usec;
68             } else {
69             usecs = 1000000 - start->tv_usec;
70             secs = end->tv_sec - (start->tv_sec + 1);
71             usecs += end->tv_usec;
72             if (usecs >= 1000000) {
73             usecs -= 1000000;
74             secs += 1;
75             }
76             }
77             return secs + usecs / 1000000.;
78             }
79             #endif
80              
81             #if BITS_PER_WORD == 64
82             #if defined(_MSC_VER)
83             #include
84             #define strtoull _strtoui64
85             #define strtoll _strtoi64
86             #endif
87             #define PSTRTOULL(str, end, base) strtoull (str, end, base)
88             #define PSTRTOLL(str, end, base) strtoll (str, end, base)
89             #else
90             #define PSTRTOULL(str, end, base) strtoul (str, end, base)
91             #define PSTRTOLL(str, end, base) strtol (str, end, base)
92             #endif
93             #if defined(_MSC_VER) && !defined(strtold)
94             #define strtold strtod
95             #endif
96              
97             #ifdef USE_QUADMATH
98             #define STRTONV(t) strtoflt128(t,NULL)
99             #elif defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE)
100             #define STRTONV(t) strtold(t,NULL)
101             #else
102             #define STRTONV(t) strtod(t,NULL)
103             #endif
104              
105             #if PERL_VERSION_LT(5,7,0) && BITS_PER_WORD == 64
106             /* Workaround perl 5.6 UVs and bigints */
107             #define my_svuv(sv) PSTRTOULL(SvPV_nolen(sv), NULL, 10)
108             #define my_sviv(sv) PSTRTOLL(SvPV_nolen(sv), NULL, 10)
109             #elif PERL_VERSION_LT(5,14,0) && BITS_PER_WORD == 64
110             /* Workaround RT 49569 in Math::BigInt::FastCalc (pre 5.14.0) */
111             /* TODO: Math::BigInt::Pari has the same problem with negs pre-5.18.0 */
112             #define my_svuv(sv) ( (!SvROK(sv)) ? SvUV(sv) : PSTRTOULL(SvPV_nolen(sv),NULL,10) )
113             #define my_sviv(sv) ( (!SvROK(sv)) ? SvIV(sv) : PSTRTOLL(SvPV_nolen(sv),NULL,10) )
114             #else
115             #define my_svuv(sv) SvUV(sv)
116             #define my_sviv(sv) SvIV(sv)
117             #endif
118              
119             #if PERL_VERSION_GE(5,9,4) || PERL_VERSION_EQ(5,8,9)
120             #define SVf_MAGTEST SVf_ROK
121             #else
122             #define SVf_MAGTEST SVf_AMAGIC
123             #define GV_NOTQUAL 0
124             #endif
125              
126             #define SVNUMTEST(n) \
127             ((SvFLAGS(n) & (SVf_IOK | SVf_MAGTEST | SVs_GMG )) == SVf_IOK)
128              
129             /* multicall compatibility stuff */
130             #if PERL_VERSION_LT(5,7,0) || !defined(dMULTICALL)
131             # define USE_MULTICALL 0 /* Too much trouble to work around it */
132             #else
133             # define USE_MULTICALL 1
134             #endif
135             #if PERL_VERSION_LT(5,13,9)
136             # define FIX_MULTICALL_REFCOUNT \
137             if (CvDEPTH(multicall_cv) > 1) SvREFCNT_inc(multicall_cv);
138             #else
139             # define FIX_MULTICALL_REFCOUNT
140             #endif
141              
142             /* Perl globals we use for setting a and b inside the called block */
143             #define plAgv PL_firstgv
144             #define plBgv PL_secondgv
145              
146             #ifndef CvISXSUB
147             # define CvISXSUB(cv) CvXSUB(cv)
148             #endif
149              
150             /* Not right, but close. We don't use it ourselves, but core macros do. */
151             #if !defined cxinc && PERL_VERSION_GE(5,8,1) && PERL_VERSION_LT(5,11,0)
152             # define cxinc() Perl_cxinc(aTHX)
153             #endif
154              
155             #if PERL_VERSION_LT(5,17,7)
156             # define SvREFCNT_dec_NN(sv) SvREFCNT_dec(sv)
157             #endif
158              
159             #if PERL_VERSION_LT(5,20,0)
160             # define EXTEND_TYPE int
161             #else
162             # define EXTEND_TYPE SSize_t
163             #endif
164             #define MAX_EXTEND ((Size_t)((EXTEND_TYPE)-1))
165              
166             /******************************************************************************/
167             /******************************************************************************/
168              
169             /* Information about the GMP back end.
170             *
171             * This is not ideal in a couple ways.
172             *
173             * - The return type info would be useful for non-GMP functions also. The
174             * thought was to use this to automatically apply objectify. The PP
175             * backend should take care of the result itself.
176             *
177             * - The versioning is limited. Having more fine grain info, e.g. the GMP
178             * module provides semantics 20210808 of modint, while we need 20250212.
179             *
180             * No matter what we do it's going to be tricky with things like adding
181             * support for negative inputs, while positive ones remain unchanged.
182             */
183              
184             typedef enum {
185             R_VOID,
186             R_BOOL,
187             R_NATIVE,
188             R_BIGINT,
189             R_OTHER,
190             } gmp_return_type_t;
191              
192             typedef struct {
193             const char *name;
194             uint32_t version;
195             uint16_t nretvals;
196             gmp_return_type_t rettype;
197             } gmp_info_t;
198              
199             static const gmp_info_t gmp_info[] = {
200             { "sqrtint", 40, 1, R_BIGINT },
201             { "addint", 52, 1, R_BIGINT },
202             { "subint", 52, 1, R_BIGINT },
203             { "mulint", 52, 1, R_BIGINT },
204             { "divint", 52, 1, R_BIGINT },
205             { "modint", 52, 1, R_BIGINT },
206             { "powint", 52, 1, R_BIGINT },
207             { "absint", 52, 1, R_BIGINT },
208             { "negint", 52, 1, R_BIGINT },
209             { "cdivint", 53, 1, R_BIGINT },
210             { "add1int", 53, 1, R_BIGINT },
211             { "sub1int", 53, 1, R_BIGINT },
212             { "lshiftint", 53, 1, R_BIGINT },
213             { "rshiftint", 53, 1, R_BIGINT },
214             { "rashiftint", 53, 1, R_BIGINT },
215             { "logint", 47, 1, R_BIGINT }, /* no root return */
216             { "rootint", 40, 1, R_BIGINT }, /* no root return */
217              
218             { "invmod", 20, 1, R_BIGINT },
219             { "znorder", 22, 1, R_BIGINT },
220             { "zinprimroot", 22, 1, R_BIGINT },
221             { "addmod", 53, 1, R_BIGINT }, /* 36 with n > 0 */
222             { "submod", 53, 1, R_BIGINT },
223             { "mulmod", 53, 1, R_BIGINT }, /* 36 with n > 0 */
224             { "powmod", 53, 1, R_BIGINT }, /* 36 with n > 0 */
225             { "divmod", 53, 1, R_BIGINT }, /* 36 with n > 0 */
226             { "muladdmod", 53, 1, R_BIGINT },
227             { "mulsubmod", 53, 1, R_BIGINT },
228             { "factorialmod", 53, 1, R_BIGINT }, /* 47 with m > 0 */
229             { "binomialmod", 53, 1, R_BIGINT },
230             { "sqrtmod", 53, 1, R_BIGINT }, /* 53 for composites */
231             { "divrem", 52, 2, R_BIGINT },
232             { "tdivrem", 52, 2, R_BIGINT },
233             { "fdivrem", 53, 2, R_BIGINT },
234             { "cdivrem", 53, 2, R_BIGINT },
235              
236             { "is_primitive_root", 36, 1, R_BOOL },
237             { "is_semiprime", 42, 1, R_BOOL },
238             { "is_square", 47, 1, R_BOOL },
239             { "is_carmichael", 47, 1, R_BOOL },
240             { "is_perfect_power", 47, 1, R_BOOL },
241             { "is_fundamental", 47, 1, R_BOOL },
242             { "is_totient", 47, 1, R_BOOL },
243             { "is_lucky", 48, 1, R_BOOL },
244             { "is_practical", 53, 1, R_BOOL },
245             { "is_perfect_number", 53, 1, R_BOOL },
246             { "is_square_free", 53, 1, R_BOOL },
247             { "is_powerfree", 53, 1, R_BOOL },
248             { "is_smooth", 53, 1, R_BOOL },
249             { "is_rough", 53, 1, R_BOOL },
250             { "is_almost_prime", 53, 1, R_BOOL },
251             { "is_divisible", 53, 1, R_BOOL },
252             { "is_congruent", 53, 1, R_BOOL },
253             { "is_powerful", 53, 1, R_BOOL },
254             { "is_qr", 53, 1, R_BOOL },
255              
256             { "is_prime", 1, 1, R_BOOL },
257             { "is_prob_prime", 1, 1, R_BOOL },
258             { "is_provable_prime", 4, 1, R_BOOL },
259             { "is_bpsw_prime", 17, 1, R_BOOL },
260             { "is_aks_prime", 16, 1, R_BOOL },
261             { "is_mersenne_prime", 28, 1, R_BOOL },
262             { "is_gaussian_prime", 52, 1, R_BOOL },
263             { "is_pseudoprime", 53, 1, R_BOOL }, /* v0.41 with bases */
264             { "is_euler_pseudoprime", 53, 1, R_BOOL }, /* v0.41 with bases */
265             { "is_strong_pseudoprime", 53, 1, R_BOOL }, /* v0.41 with bases */
266             { "is_euler_plumb_pseudoprime", 39, 1, R_BOOL },
267             { "is_perrin_pseudoprime", 40, 1, R_BOOL },
268             { "is_lucas_pseudoprime", 1, 1, R_BOOL },
269             { "is_strong_lucas_pseudoprime", 1, 1, R_BOOL },
270             { "is_extra_strong_lucas_pseudoprime", 1, 1, R_BOOL },
271             { "is_almost_extra_strong_lucas_pseudoprime", 13, 1, R_BOOL },
272             { "is_frobenius_pseudoprime", 24, 1, R_BOOL },
273             { "is_frobenius_underwood_pseudoprime", 13, 1, R_BOOL },
274             { "is_frobenius_khashin_pseudoprime", 30, 1, R_BOOL },
275             { "miller_rabin_random", 46, 1, R_BOOL },
276              
277             { "next_prime", 1, 1, R_BIGINT },
278             { "prev_prime", 1, 1, R_BIGINT },
279              
280             { "kronecker", 17, 1, R_NATIVE },
281             { "valuation", 20, 1, R_NATIVE },
282             { "liouville", 22, 1, R_NATIVE },
283             { "hammingweight", 47, 1, R_NATIVE },
284             { "moebius", 49, 1, R_NATIVE }, /* v0.22 with non-neg */
285             { "prime_omega", 53, 1, R_NATIVE },
286             { "prime_bigomega", 53, 1, R_NATIVE },
287              
288             { "consecutive_integer_lcm", 4, 1, R_BIGINT },
289             { "partitions", 16, 1, R_BIGINT },
290             { "gcd", 17, 1, R_BIGINT },
291             { "lcm", 17, 1, R_BIGINT },
292             { "exp_mangoldt", 19, 1, R_BIGINT },
293             { "jordan_totient", 22, 1, R_BIGINT },
294             { "carmichael_lambda", 22, 1, R_BIGINT },
295             { "binomial", 22, 1, R_BIGINT },
296             { "stirling", 26, 1, R_BIGINT },
297             { "lucasu", 29, 1, R_BIGINT },
298             { "lucasv", 29, 1, R_BIGINT },
299             { "chinese", 32, 1, R_BIGINT },
300             { "ramanujan_tau", 53, 1, R_BIGINT }, /* v0.53 much faster */
301             { "gcdext", 35, 3, R_BIGINT },
302             { "primorial", 37, 1, R_BIGINT },
303             { "pn_primorial", 37, 1, R_BIGINT },
304             { "permtonum", 47, 1, R_BIGINT },
305             { "subfactorial", 51, 1, R_BIGINT },
306             { "falling_factorial", 51, 1, R_BIGINT },
307             { "rising_factorial", 51, 1, R_BIGINT },
308             { "lucasumod", 53, 1, R_BIGINT },
309             { "lucasvmod", 53, 1, R_BIGINT },
310             { "lucasuv", 53, 2, R_BIGINT },
311             { "lucasuvmod", 53, 2, R_BIGINT },
312             { "pisano_period", 53, 1, R_BIGINT },
313             { "powersum", 53, 1, R_BIGINT },
314             { "fromdigits", 53, 1, R_BIGINT },
315              
316             { "urandomb", 43, 1, R_BIGINT },
317             { "urandomm", 44, 1, R_BIGINT },
318             { "random_nbit_prime", 42, 1, R_BIGINT },
319             { "random_ndigit_prime", 42, 1, R_BIGINT },
320             { "random_strong_prime", 43, 1, R_BIGINT },
321             { "random_maurer_prime", 43, 1, R_BIGINT },
322             {"random_shawe_taylor_prime", 43, 1, R_BIGINT },
323             { "random_prime", 44, 1, R_BIGINT },
324             { "random_safe_prime", 52, 1, R_BIGINT },
325              
326             { "sieve_range", 36, 0xFF, R_BIGINT }, /* needs objectify */
327             { "sieve_prime_cluster", 34, 0xFF, R_BIGINT }, /* needs objectify */
328             { "divisors", 53, 0xFF, R_BIGINT }, /* needs objectify */
329              
330             { "numtoperm", 47, 0xFF, R_NATIVE },
331             { "todigits", 41, 0xFF, R_NATIVE },
332              
333             { "powerful_count", 53, 1, R_BIGINT },
334             { "powerfree_count", 53, 1, R_BIGINT },
335             { "prime_power_count", 53, 1, R_BIGINT },
336             { "perfect_power_count", 53, 1, R_BIGINT },
337             { "nth_powerfree", 53, 1, R_BIGINT },
338             { "nth_perfect_power", 53, 1, R_BIGINT },
339             { "nth_perfect_power_approx", 53, 1, R_BIGINT },
340             { "next_perfect_power", 53, 1, R_BIGINT },
341             { "prev_perfect_power", 53, 1, R_BIGINT },
342              
343             { "is_power", 42, 1, R_NATIVE }, /* no root return */
344             { "is_prime_power", 40, 1, R_NATIVE }, /* no root return */
345             { "is_polygonal", 47, 1, R_BOOL }, /* no root return */
346              
347             { "bernfrac", 24, 2, R_BIGINT },
348             { "harmfrac", 30, 2, R_BIGINT },
349              
350             /* if the input is already a bigint type, we want to use that */
351             /* { "factorial", 24, 1, R_BIGINT }, */
352             #if 0 /* need to objectify a return list */
353             { "factor", 41, 0xFF, R_BIGINT },
354             #endif
355             #if 0 /* objectify list, and the API isn't identical */
356             { "trial_factor", 47, 0xFF, R_BIGINT },
357             { "holf_factor", 47, 0xFF, R_BIGINT },
358             { "squfof_factor", 47, 0xFF, R_BIGINT },
359             { "phro_factor", 47, 0xFF, R_BIGINT },
360             { "pplus1_factor", 47, 0xFF, R_BIGINT },
361             { "pbrent_factor", 47, 0xFF, R_BIGINT },
362             { "pminus1_factor", 47, 0xFF, R_BIGINT },
363             { "ecm_factor", 47, 0xFF, R_BIGINT },
364             { "cheb_factor", 53, 0xFF, R_BIGINT },
365             #endif
366             };
367              
368             /******************************************************************************/
369              
370             #if BITS_PER_WORD == 32
371             static const unsigned int uvmax_maxlen = 10;
372             static const unsigned int ivmax_maxlen = 10;
373             static const char uvmax_str[] = "4294967295";
374             /* static const char ivmax_str[] = "2147483648"; */
375             static const char ivmin_str[] = "2147483648";
376             #else
377             static const unsigned int uvmax_maxlen = 20;
378             static const unsigned int ivmax_maxlen = 19;
379             static const char uvmax_str[] = "18446744073709551615";
380             /* static const char ivmax_str[] = "9223372036854775808"; */
381             static const char ivmin_str[] = "9223372036854775808";
382             #endif
383              
384             #define MY_CXT_KEY "Math::Prime::Util::API_guts"
385             #define CINTS 100
386             typedef struct {
387             HV* MPUroot;
388             HV* MPUGMP;
389             HV* MPUPP;
390             SV* const_int[CINTS+1]; /* -1, 0, 1, ..., 99 */
391             void* randcxt; /* per-thread csprng context */
392             uint16_t forcount; /* Track nesting level of for loops */
393             char forexit; /* Boolean whether we should exit early */
394             } my_cxt_t;
395              
396             START_MY_CXT
397              
398 391920           static int _is_sv_bigint(pTHX_ SV* n)
399             {
400 391920 100         if (sv_isobject(n)) {
401 390993 50         const char *hvname = HvNAME_get(SvSTASH(SvRV(n)));
    50          
    50          
    0          
    50          
    50          
402 390993 50         if (hvname != 0) {
403 390993 100         if (strEQ(hvname, "Math::BigInt") || /* BigFloat not here, force to PP */
404 8 50         strEQ(hvname, "Math::GMPz") || strEQ(hvname, "Math::GMP") ||
    50          
405 8 50         strEQ(hvname, "Math::GMPq") || strEQ(hvname, "Math::AnyNum") ||
    50          
406 8 50         strEQ(hvname, "Math::Pari") || strEQ(hvname, "Math::BigInt::Lite"))
    50          
407 390985           return 1;
408             }
409             }
410 935           return 0;
411             }
412              
413             /******************************************************************************/
414              
415             /* Is this a pedantically valid integer?
416             * Croaks if undefined or invalid.
417             * Returns 0 if it is an object or a string too large for a UV.
418             * Returns 1/-1 if it is good to process by XS.
419             * TODO: it would be useful to know the sign even if returning 0 for bigint.
420             */
421 286854           static int _validate_int(pTHX_ SV* n, int negok)
422             {
423 286854 100         const char* mustbe = (negok) ? "must be an integer" : "must be a non-negative integer";
424             const char* maxstr;
425             char* ptr;
426             STRLEN i, len, maxlen;
427 286854           int ret, isbignum = 0, isneg = 0;
428              
429             /* TODO: magic, grok_number, etc. */
430 286854 50         if (SVNUMTEST(n)) { /* If defined as number, use it */
431 0 0         if (SvIsUV(n) || SvIVX(n) >= 0) return 1; /* The normal case */
    0          
432 0 0         if (negok) return -1;
433 0           else croak("Parameter '%" SVf "' %s", n, mustbe);
434             }
435 286854 100         if (sv_isobject(n)) {
436 278228           isbignum = _is_sv_bigint(aTHX_ n);
437 278228 100         if (!isbignum) return 0;
438             }
439 286849 100         if (!SvOK(n)) croak("Parameter must be defined");
440 286829 100         if (SvGAMAGIC(n) && !isbignum) ptr = SvPV(n, len);
    100          
    50          
    50          
    100          
441 286828           else ptr = SvPV_nomg(n, len);
442 286829 100         if (len == 0 || ptr == 0) croak("Parameter %s", mustbe);
    50          
443 286828 100         if (ptr[0] == '-' && negok) {
    100          
444 2103           isneg = 1; ptr++; len--; /* Read negative sign */
445 284725 100         } else if (ptr[0] == '+') {
446 5           ptr++; len--; /* Allow a single plus sign */
447             }
448             /* Empty string or non-numeric */
449 286828 100         if (len == 0 || !isDIGIT(ptr[0])) croak("Parameter '%" SVf "' %s", n, mustbe);
    100          
450             /* Leading zeros and if left with only zero */
451 287033 100         while (len > 0 && *ptr == '0') /* Strip all leading zeros */
    100          
452 230           { ptr++; len--; }
453 286803 100         if (len == 0) /* 0 or -0 */
454 223           return 1;
455             /* We're going to look more carefully at the string to ensure it's a number */
456 286580 100         if (isneg) { ret = -1; maxlen = ivmax_maxlen; maxstr = ivmin_str; }
457 284479           else { ret = 1; maxlen = uvmax_maxlen; maxstr = uvmax_str; }
458 21751170 100         for (i = 0; i < len; i++) /* Ensure all characters are digits */
459 21464602 100         if (!isDIGIT(ptr[i]))
460 12           croak("Parameter '%" SVf "' %s", n, mustbe);
461 286568 100         if (len > maxlen) return 0; /* Obvious bigint */
462 48815 100         if (len < maxlen) return ret; /* Valid small integer */
463 229899 100         for (i = 0; i < maxlen; i++) /* Check if in range */
464 229764 100         if (ptr[i] != maxstr[i])
465 41754 100         return ptr[i] < maxstr[i] ? ret : 0;
466 135           return ret; /* value = UV_MAX/UV_MIN. That's ok */
467             }
468              
469             #define IFLAG_ANY 0x00000000U
470             #define IFLAG_POS 0x00000001U /* Must be non-negative */
471             #define IFLAG_NONZERO 0x00000002U /* Must not be zero */
472             #define IFLAG_ABS 0x00000004U /* Absolute value returned */
473             #define IFLAG_IV 0x00000008U /* Value returned as IV */
474              
475 5311135           static int _validate_and_set(UV* val, pTHX_ SV* svn, uint32_t mask) {
476             int status;
477              
478 5311135 50         if (svn == 0) croak("Parameter must be defined");
479             /* Streamline the typical path of input being a native integer. */
480 5311135 100         if (SVNUMTEST(svn)) {
481 5024281           IV n = SvIVX(svn);
482 5024281 100         if (n >= 0) {
483 4121759 100         if (n == 0 && (mask & IFLAG_NONZERO))
    100          
484 1           croak("Parameter '%" SVf "' must be a positive integer", svn);
485 4121758           *val = (UV)n;
486 4121758           return 1;
487             }
488 902522 100         if (SvIsUV(svn)) {
489 127250 100         if (mask & IFLAG_IV)
490 27           return 0;
491 127223           *val = (UV)n;
492 127223           return 1;
493             }
494 775272 100         if (mask & IFLAG_ABS) { *val = (UV)(-n); return 1; }
495 414238 100         if (mask & IFLAG_POS) croak("Parameter '%" SVf "' must be a non-negative integer", svn);
496 414222           *val = n;
497 414222           return -1;
498             }
499              
500 286854           status = _validate_int( aTHX_ svn, !(mask & IFLAG_POS) );
501 286796 100         if (status == 1) {
502 7613           UV n = my_svuv(svn);
503 7613 100         if (n == 0 && (mask & IFLAG_NONZERO))
    50          
504 0           croak("Parameter '%" SVf "' must be a positive integer", svn);
505 7613 100         if (n > (UV)IV_MAX && (mask & IFLAG_IV))
    50          
506 0           return 0;
507 7613           *val = n;
508 279183 100         } else if (status == -1) {
509 257           IV n = my_sviv(svn);
510 257 100         if (mask & IFLAG_ABS) { *val = (UV)(-n); status = 1; }
511 226           else { *val = (UV)n; }
512             }
513 286796           return status;
514             }
515              
516             /******************************************************************************/
517              
518             #if 1
519             /* This is NEGATE_2UV(iv) from handy.h */
520             #define neg_iv(n) ((UV)-((n)+1) + 1U)
521             #else
522             static UV neg_iv(UV n) {
523             if ((IV)n == IV_MIN) return (UV_MAX >> 1) + 1;
524             else return (UV) (-(IV)n);
525             }
526             #endif
527              
528             /* Given 'a' and astatus (-1 means 'a' is an IV), properly mod with n */
529 160652           static void _mod_with(UV *a, int astatus, UV n) {
530 160652 50         if (n == 0) return;
531 160652 100         if (astatus != -1) {
532 140456           *a %= n;
533             } else {
534 20196           UV r = neg_iv(*a) % n;
535 20196 50         *a = (r == 0) ? 0 : n-r;
536             }
537             }
538              
539             /******************************************************************************/
540              
541             #define VCALL_ROOT 0x0
542             #define VCALL_PP 0x1
543             #define VCALL_GMP 0x2
544             /* Call a Perl sub to handle work for us. */
545 115115           static int _vcallsubn(pTHX_ I32 flags, I32 stashflags, const char* name, int nargs, int minversion)
546             {
547 115115           GV* gv = NULL;
548             dMY_CXT;
549 115115           Size_t namelen = strlen(name);
550             /* If given a GMP function, and GMP enabled, and function exists, use it. */
551 115115 100         int use_gmp = stashflags & VCALL_GMP && _XS_get_callgmp() && _XS_get_callgmp() >= minversion;
    50          
    0          
552             assert(!(stashflags & ~(VCALL_PP|VCALL_GMP)));
553 115115 50         if (use_gmp && hv_exists(MY_CXT.MPUGMP,name,namelen)) {
    0          
554 0           GV ** gvp = (GV**)hv_fetch(MY_CXT.MPUGMP,name,namelen,0);
555 0 0         if (gvp) gv = *gvp;
556             }
557 115115 50         if (!gv && (stashflags & VCALL_PP))
    100          
558 115114           perl_require_pv("Math/Prime/Util/PP.pm");
559 115115 50         if (!gv) {
560 115115 100         GV ** gvp = (GV**)hv_fetch(stashflags & VCALL_PP? MY_CXT.MPUPP : MY_CXT.MPUroot, name,namelen,0);
561 115115 50         if (gvp) gv = *gvp;
562             }
563             /* use PL_stack_sp in PUSHMARK macro directly it will be read after
564             the possible mark stack extend */
565 115115 50         PUSHMARK(PL_stack_sp-nargs);
566             /* no PUTBACK bc we didn't move global SP */
567 115115           return call_sv((SV*)gv, flags);
568             }
569              
570 283           static NOINLINE const char* _subname(pTHX_ const CV *cv) { return GvNAME(CvGV(cv)); }
571             #define SUBNAME _subname(aTHX_ cv)
572              
573             /* -1 if not found, array entry if found */
574 115092           static int find_gmp_info(const char *name) {
575 115092           const int ngmpinfo = sizeof(gmp_info)/sizeof(gmp_info[0]);
576             int i;
577             /* Stupid linear scan */
578 2694497 100         for (i = 0; i < ngmpinfo; i++)
579 2690376 100         if (strcmp(gmp_info[i].name, name) == 0)
580 110971           return i;
581 4121           return -1;
582             }
583 115092           static NOINLINE void dispatch_external(pTHX_ const CV* thiscv, I32 context, int nitems, bool gmp_is_ok)
584             {
585 115092           const char *name = GvNAME(CvGV(thiscv));
586 115092           const int ginfoi = find_gmp_info(name);
587 115092           I32 callflags = VCALL_PP;
588 115092           uint32_t ver = 0;
589 115092 100         bool usegmp = ginfoi >= 0 && gmp_is_ok;
    100          
590              
591 115092 100         if (usegmp) {
592 107650           ver = gmp_info[ginfoi].version;
593 107650           callflags |= VCALL_GMP;
594             }
595              
596 115092           _vcallsubn(aTHX_ context, callflags, name, nitems, ver);
597              
598             /* TODO: _vcallsubn returns the number of values we got back. Use this
599             * together with the gmp_info type to decide what to objectify.
600             * We're missing the input sv that gives us the desired return class.
601             */
602 115091           }
603             #define DISPATCHPP() dispatch_external(aTHX_ cv, GIMME_V, items, TRUE)
604              
605             #define DISPATCHPP_GMPONLYIF(expr) \
606             dispatch_external(aTHX_ cv, GIMME_V, items, !!(expr))
607              
608             #define DISPATCH_VOIDPP() \
609             (void)_vcallsubn(aTHX_ G_VOID|G_DISCARD, VCALL_PP, SUBNAME, items, 0)
610              
611             #define CALLROOTSUB(fn) \
612             (void)_vcallsubn(aTHX_ GIMME_V, VCALL_ROOT, fn, items, 0)
613             #define CALLROOTSUB_ONE_SCALAR(fn) \
614             (void)_vcallsubn(aTHX_ G_SCALAR, VCALL_ROOT, fn, 1, 0)
615             #define CALLROOTSUB_VOID(fn) \
616             (void)_vcallsubn(aTHX_ G_VOID|G_DISCARD, VCALL_ROOT, fn, items, 0)
617              
618             #define OBJECTIFY_STACK(n) \
619             do { \
620             uint32_t i_, nargs_ = n; \
621             for (i_ = 0; i_ < nargs_; i_++) \
622             if (SvOK(ST(i_)) && !sv_isobject(ST(i_)) && !SVNUMTEST(ST(i_))) \
623             break; \
624             if (i_ < nargs_) \
625             _vcallsubn(aTHX_ G_ARRAY,VCALL_ROOT,"_maybe_bigint_allargs",nargs_,0); \
626             } while (0)
627              
628             /* Returns 0 if we see no reason to wrap this sub inside it's own scope.
629             Returns 1 if we need to because of locals created.
630             Returns 1 if it's too complicated (long, infinite loop, deep branches) */
631 1246           static bool cv_needs_scope(pTHX_ const CV *cv) {
632 1246           OP *o = CvSTART(cv);
633 1246           size_t nops = 0;
634             OP *branches[8];
635 1246           int nbranch = 0;
636 5171 100         for (; nops < 500; o = o->op_next) {
637 5169 100         if (!o) {
638 56 50         if (nbranch > 0) { o = branches[--nbranch]; continue; }
639 56           break;
640             }
641             /* printf(" %s\n",PL_op_name[o->op_type]); */
642 5113           nops++;
643 5113           switch (o->op_type) {
644 1188           case OP_PADSV: case OP_PADAV: case OP_PADHV:
645             case OP_ANONCODE:
646             #if PERL_VERSION_GE(5,17,6)
647             case OP_PADRANGE:
648             #endif
649             #if PERL_VERSION_GE(5,27,6)
650             case OP_MULTICONCAT: /* This could hide a PADSV -- we don't know */
651             #endif
652             #if PERL_VERSION_GE(5,37,3)
653             case OP_PADSV_STORE:
654             #endif
655 1188           return 1;
656              
657 28           case OP_AND: case OP_OR: case OP_COND_EXPR:
658             case OP_ANDASSIGN: case OP_ORASSIGN:
659             #if PERL_VERSION_GE(5,9,0)
660             case OP_DOR:
661             case OP_DORASSIGN:
662             #endif
663 28 50         if (nbranch >= 8) return 1; /* Too deep */
664 28           branches[nbranch++] = cLOGOPx(o)->op_other;
665 28           break;
666 78           case OP_LEAVESUB:
667 78 100         if (nbranch > 0) { o = branches[--nbranch]; continue; }
668 56           break;
669             }
670             }
671 58 100         if (nops >= 500) return 1;
672 56           return 0;
673             }
674             #define DECL_MULTICALL_SCOPE(cv) bool addscope = cv_needs_scope(aTHX_ cv)
675             #define SCOPED_MULTICALL \
676             do { if(addscope) {ENTER;} MULTICALL; if(addscope) {LEAVE;} } while(0)
677              
678             /******************************************************************************/
679              
680             #define SETSUBREF(cv, block) \
681             do { \
682             GV *gv_; \
683             HV *stash_; \
684             cv = sv_2cv(block, &stash_, &gv_, 0); \
685             if (cv == Nullcv) croak("%s: Not a subroutine reference", SUBNAME); \
686             } while (0)
687              
688             /* In my testing, this constant return works fine with threads, but to be
689             * correct (see perlxs) one has to make a context, store separate copies in
690             * each one, then retrieve them from a struct using a hash index. This
691             * defeats the purpose if only done once. */
692             #define RETURN_NPARITY(ret) \
693             do { int r_ = ret; \
694             dMY_CXT; \
695             if (r_ >= -1 && r_
696             else { XSRETURN_IV(r_); } \
697             } while (0)
698             #define PUSH_NPARITY(ret) \
699             do { int r_ = ret; \
700             if (r_ >= -1 && r_
701             else { PUSHs(sv_2mortal(newSViv(r_))); } \
702             } while (0)
703              
704 108154           static void objectify_result(pTHX_ SV* input, SV* output) {
705             /* Leave unchanged: undef, objects, small integers */
706 108154 100         if (!SvOK(output) || sv_isobject(output) || SVNUMTEST(output))
    100          
    100          
707 108153           return;
708             /* If they didn't give us a bigint, then try to be smart */
709 1 50         if (!input || !sv_isobject(input)) {
    50          
710 1           CALLROOTSUB_ONE_SCALAR("_to_bigint_if_needed");
711             } else {
712 0 0         const char *iname = HvNAME_get(SvSTASH(SvRV(input)));
    0          
    0          
    0          
    0          
    0          
713 0 0         if (strEQ(iname, "Math::BigInt")) {
714 0           CALLROOTSUB_ONE_SCALAR("_to_bigint");
715 0 0         } else if (strEQ(iname, "Math::GMPz")) {
716 0           CALLROOTSUB_ONE_SCALAR("_to_gmpz");
717 0 0         } else if (strEQ(iname, "Math::GMP")) {
718 0           CALLROOTSUB_ONE_SCALAR("_to_gmp");
719             } else { /* Return it as: ref(input)->new(result) */
720 0 0         dSP; (void)POPs; ENTER; PUSHMARK(SP);
721 0 0         XPUSHs(sv_2mortal(newSVpv(iname, 0))); XPUSHs(output);
    0          
722 0           PUTBACK; call_method("new", G_SCALAR); LEAVE;
723             }
724             }
725             }
726              
727 2575           static SV* call_sv_to_func(pTHX_ SV* r, const char* name) {
728 2575 50         dSP; ENTER; PUSHMARK(SP);
729 2575 50         XPUSHs(r);
730 2575           PUTBACK;
731 2575           call_pv(name, G_SCALAR);
732 2574           SPAGAIN;
733 2574           r = POPs;
734 2574           PUTBACK; LEAVE;
735 2574           return r;
736             }
737 876           static SV* sv_to_bigint(pTHX_ SV* r) {
738 876           return call_sv_to_func(aTHX_ r, "Math::Prime::Util::_to_bigint");
739             }
740 1650           static SV* sv_to_bigint_abs(pTHX_ SV* r) {
741 1650           return call_sv_to_func(aTHX_ r, "Math::Prime::Util::_to_bigint_abs");
742             }
743 49           static SV* sv_to_bigint_nonneg(pTHX_ SV* r) {
744 49           return call_sv_to_func(aTHX_ r, "Math::Prime::Util::_to_bigint_nonneg");
745             }
746              
747             #define NEWSVINT(sign,v) (((sign) > 0) ? newSVuv(v) : newSViv(v))
748             #define SETSVINT(sv,setpos,posv,negv) \
749             do { if (setpos) sv_setuv(sv,posv); \
750             else sv_setiv(sv,negv); } while(0)
751             #if 1
752             #define FASTSETSVINT(sv,setpos,val) \
753             do { \
754             const UV val_ = val; \
755             if ((setpos) && (UV)(val_) > (UV)IV_MAX) { \
756             if (SvTYPE(sv) != SVt_IV) sv_setuv(sv,val_); \
757             else { SvUV_set(sv,val_); SvIsUV_on(sv); } \
758             } else { \
759             if (SvTYPE(sv) != SVt_IV) sv_setiv(sv,(IV)val_); \
760             else { SvIV_set(sv,(IV)val_); SvIsUV_off(sv); } \
761             } \
762             } while(0)
763             #else
764             #define FASTSETSVINT(sv,setpos,val) SETSVINT(sv,setpos,val,(IV)val)
765             #endif
766              
767             #define RETURN_128(hi,lo) \
768             do { char str_[40]; \
769             uint32_t slen_ = to_string_128(str_, hi, lo); \
770             ST(0) = sv_to_bigint( aTHX_ sv_2mortal(newSVpv(str_,slen_)) ); \
771             XSRETURN(1); } while(0)
772              
773             #define CREATE_RETURN_AV(av) \
774             do { \
775             av = newAV(); \
776             { \
777             SV * retsv = sv_2mortal(newRV_noinc( (SV*) av )); \
778             PUSHs(retsv); \
779             PUTBACK; \
780             SP = NULL; /* never use SP again, poison */ \
781             } \
782             } while(0)
783              
784             #define PUSH_2ELEM_AREF(p, q) \
785             do { \
786             AV* av_ = newAV(); \
787             av_push(av_, newSVuv(p)); \
788             av_push(av_, newSVuv(q)); \
789             PUSHs(sv_2mortal(newRV_noinc((SV*) av_))); \
790             } while (0)
791              
792             #define RETURN_LIST_VALS(in_alen,arr,sign) /* Return array values */ \
793             { \
794             size_t k_, alen_ = in_alen; \
795             if (GIMME_V == G_SCALAR) { \
796             Safefree(arr); \
797             XSRETURN_UV(alen_); \
798             } \
799             EXTEND(SP,(EXTEND_TYPE)alen_); \
800             for (k_ = 0; k_ < alen_; k_++) \
801             ST(k_) = sv_2mortal(NEWSVINT(sign,arr[k_])); \
802             Safefree(arr); \
803             XSRETURN(alen_); \
804             }
805              
806             #define RETURN_LIST_REF(in_alen,arr,sign) /* Return array values as ref */ \
807             { \
808             size_t k_, alen_ = in_alen; \
809             AV* av_ = newAV(); \
810             av_extend(av_, (SSize_t)alen_-1); \
811             SV **ar_ = AvARRAY(av_); \
812             for (k_ = 0; k_ < alen_; k_++) \
813             ar_[k_] = NEWSVINT(sign,arr[k_]); \
814             AvFILLp(av_) = (SSize_t)alen_-1; \
815             Safefree(arr); \
816             ST(0) = sv_2mortal(newRV_noinc((SV*) av_)); \
817             XSRETURN(1); \
818             }
819              
820             #define RETURN_EMPTY_LIST_REF() \
821             { \
822             AV* av_ = newAV(); \
823             ST(0) = sv_2mortal(newRV_noinc((SV*) av_)); \
824             XSRETURN(1); \
825             }
826              
827             /******************************************************************************/
828              
829              
830             #define IARR_TYPE_ANY 0x00
831             #define IARR_TYPE_NEG 0x01
832             #define IARR_TYPE_POS 0x02
833             #define IARR_TYPE_BAD 0x03
834              
835             /* BAD always bad, ANY with ANY/POS/NEG, POS and NEG only with ANY and self. */
836             #define CAN_COMBINE_IARR_TYPES(t1,t2) ( ((t1) | (t2)) != IARR_TYPE_BAD )
837             /* Convert to 0/1/-1 status */
838             #define IARR_TYPE_TO_STATUS(t) \
839             (((t) == IARR_TYPE_BAD) ? 0 : ((t) == IARR_TYPE_NEG) ? -1 : 1)
840             #define STATUS_TO_IARR_TYPE(s,n) \
841             (((s) == 0) ? IARR_TYPE_BAD : ((s) == -1) ? IARR_TYPE_NEG : ((n) > (UV)IV_MAX) ? IARR_TYPE_POS : IARR_TYPE_ANY)
842              
843             /* Compare using first argument non-zero to indicate UV, otherwise IV */
844             #define SIGNED_CMP_LE(pos,x,y) ((pos) ? (x <= y) : ((IV)x <= (IV)y))
845             #define SIGNED_CMP_LT(pos,x,y) ((pos) ? (x < y) : ((IV)x < (IV)y))
846             #define SIGNED_CMP_GT(pos,x,y) ((pos) ? (x > y) : ((IV)x > (IV)y))
847              
848             /* Given values and a sign indicating IV or UV, returns -1 (<), 0 (eq), 1 (>) */
849 1035           static int _sign_cmp(int xsign, UV x, int ysign, UV y) {
850             /* Convert sign to -1 (neg), 0 (small pos), 1 (big pos) */
851 1035 100         if (x <= (UV)IV_MAX) xsign = 0;
852 1035 100         if (y <= (UV)IV_MAX) ysign = 0;
853 1035 100         if (xsign == ysign && x == y) return 0;
    100          
854             /* neg < small pos < big pos */
855 947 100         if (xsign != ysign) return (xsign < ysign) ? -1 : 1;
    100          
856             /* Numerical comparison as IV or UV */
857 880 100         return ((xsign == -1 && (IV)x < (IV)y) || (xsign != -1 && x < y)) ? -1 : 1;
    100          
    100          
    100          
858             }
859              
860             /******************************************************************************/
861              
862             #define CHECK_ARRAYREF1(sv,name) \
863             do { \
864             if ( !SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVAV ) \
865             croak("%s: expected array reference", name); \
866             } while (0)
867             #define CHECK_ARRAYREF(sv) CHECK_ARRAYREF1(sv,SUBNAME)
868              
869             #define CHECK_AV_NOT_READONLY1(av,name) \
870             do { \
871             if (SvREADONLY(av)) \
872             croak("%s: array reference is readonly", name); \
873             } while (0)
874             #define CHECK_AV_NOT_READONLY(av) CHECK_AV_NOT_READONLY1(av, SUBNAME)
875              
876             #define DECL_ARREF(name) \
877             AV * avp_ ## name; \
878             SV ** svarr_ ## name; \
879             Size_t len_ ## name
880              
881             #define AR_READ 0
882             #define AR_WRITE 1
883             #define USE_ARREF(name, sv, subname, will_modify) \
884             do { \
885             CHECK_ARRAYREF1(sv, subname); \
886             avp_ ## name = (AV*) SvRV(sv); \
887             len_ ## name = av_count(avp_ ## name); \
888             if (will_modify) \
889             CHECK_AV_NOT_READONLY1(avp_ ## name, subname); \
890             if (SvMAGICAL(avp_ ## name) || (will_modify && !AvREAL(avp_ ## name) && AvREIFY(avp_ ## name))) \
891             svarr_ ## name = 0; \
892             else \
893             svarr_ ## name = AvARRAY(avp_ ## name); \
894             } while(0)
895              
896 2314           static SV* _fetch_arref(pTHX_ AV* av, SV** svarr, size_t i) {
897 2314 50         if (svarr == 0) {
898 0           SV **svp = av_fetch(av, i, 0);
899 0 0         return svp ? *svp : &PL_sv_undef;
900             }
901 2314           return svarr[i];
902             }
903             #define FETCH_ARREF(name,i) _fetch_arref(aTHX_ avp_ ## name, svarr_ ## name, i)
904              
905             #define STORE_ARREF(name, i, sv) \
906             do { (use_direct_ ## name ? (svarr_ ## name)[i] = sv : av_store(avp_ ## name, i, sv)) } while(0)
907              
908             #define DEBUG_PRINT_ARRAY(name,av) \
909             { Size_t j_; SV** arr_ = AvARRAY(av); printf("%s: [",name); for(j_=0; j_
910              
911             #define READ_UV_IARR(dst, src, itype) \
912             { \
913             UV n; \
914             int istatus = _validate_and_set(&n, aTHX_ src, IFLAG_ANY); \
915             if (istatus == -1) itype |= IARR_TYPE_NEG; \
916             else if (istatus == 1 && n > (UV)IV_MAX) itype |= IARR_TYPE_POS; \
917             if (istatus == 0 || itype == IARR_TYPE_BAD) break; \
918             dst = n; \
919             }
920              
921 462           static int arrayref_to_int_array(pTHX_ size_t *retlen, UV** ret, bool want_sort, SV* sva, const char* fstr)
922             {
923             Size_t len, i;
924 462           int itype = IARR_TYPE_ANY;
925             UV *r;
926             DECL_ARREF(avp);
927              
928 462 50         USE_ARREF(avp, sva, fstr, AR_READ);
    50          
    50          
929 462           len = len_avp;
930 462           *retlen = len;
931 462 100         if (len == 0) {
932 50           *ret = 0;
933 50           return itype;
934             }
935 412 50         New(0, r, len, UV);
936 2488 100         for (i = 0; i < len; i++) {
937 2159           SV *iv = FETCH_ARREF(avp,i);
938 2159 50         if (iv == 0) continue;
939 2159 100         if (SVNUMTEST(iv)) {
940 1903           IV n = SvIVX(iv);
941 1903 100         if (n < 0) {
942 424 100         if (SvIsUV(iv)) itype |= IARR_TYPE_POS;
943 351           else itype |= IARR_TYPE_NEG;
944 424 100         if (itype == IARR_TYPE_BAD) break;
945             }
946 1883           r[i] = (UV)n;
947             } else {
948 256 100         READ_UV_IARR(r[i], iv, itype);
    100          
    100          
    100          
    100          
949             }
950             }
951 412 100         if (i < len) {
952 83           Safefree(r);
953 83           *ret = 0;
954 83           return IARR_TYPE_BAD;
955             }
956 329           *ret = r;
957 329 100         if (want_sort) {
958 318 100         if (itype == IARR_TYPE_NEG) {
959 637 100         for (i = 1; i < len; i++)
960 555 100         if ( (IV)r[i] <= (IV)r[i-1] )
961 17           break;
962             } else {
963 1240 100         for (i = 1; i < len; i++)
964 1042 100         if (r[i] <= r[i-1])
965 21           break;
966             }
967 318 100         if (i < len)
968 38           sort_dedup_uv_array(r, itype == IARR_TYPE_NEG, retlen);
969             }
970 329           return itype;
971             }
972              
973             /* Check whether an SV is a non-magical arrayref whose elements are all native
974             * non-negative integers in strictly increasing order (i.e. sorted and unique).
975             * On success returns the AvARRAY pointer and sets *lenp; otherwise NULL.
976             * Used by the set-op fast path to skip intermediate UV array allocation. */
977 70           static SV** _check_sorted_nonneg_arrayref(pTHX_ SV *sv, size_t *lenp)
978             {
979             AV *av;
980             SV **arr;
981             size_t len, i;
982 70 50         if (!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVAV) return NULL;
    50          
983 70           av = (AV*)SvRV(sv);
984 70 50         if (SvMAGICAL(av)) return NULL;
985 70           arr = AvARRAY(av);
986 70           len = av_count(av);
987 150 100         for (i = 0; i < len; i++) {
988 116           SV *elem = arr[i];
989 116 100         if (!SVNUMTEST(elem) || (!SvIsUV(elem) && SvIVX(elem) < 0)) return NULL;
    100          
    100          
990 88 100         if (i > 0 && SvUVX(elem) <= SvUVX(arr[i-1])) return NULL;
    100          
991             }
992 34           *lenp = len;
993 34           return arr;
994             }
995              
996 202           static int array_to_int_array(pTHX_ size_t *retlen, UV** ret, bool want_sort, SV** svbase, size_t len)
997             {
998             size_t i;
999 202           int itype = IARR_TYPE_ANY;
1000             UV *r;
1001 202           *retlen = len;
1002 202 50         if (len == 0) {
1003 0           *ret = 0;
1004 0           return itype;
1005             }
1006 202 50         New(0, r, len, UV);
1007 1070 100         for (i = 0; i < len; i++) {
1008 923           SV *iv = svbase[i];
1009 923 100         if (SVNUMTEST(iv)) {
1010 800           IV n = SvIVX(iv);
1011 800 100         if (n < 0) {
1012 85 100         if (SvIsUV(iv)) itype |= IARR_TYPE_POS;
1013 49           else itype |= IARR_TYPE_NEG;
1014 85 100         if (itype == IARR_TYPE_BAD) break;
1015             }
1016 794           r[i] = (UV)n;
1017             } else {
1018 123 100         READ_UV_IARR(r[i], iv, itype);
    100          
    100          
    100          
    100          
1019             }
1020             }
1021 202 100         if (i < len) {
1022 55           Safefree(r);
1023 55           *ret = 0;
1024 55           return IARR_TYPE_BAD;
1025             }
1026 147           *ret = r;
1027 147 100         if (want_sort) {
1028 87 100         if (itype == IARR_TYPE_NEG) {
1029 45 100         for (i = 1; i < len; i++)
1030 32 100         if ( (IV)r[i] <= (IV)r[i-1] )
1031 10           break;
1032             } else {
1033 204 100         for (i = 1; i < len; i++)
1034 160 100         if (r[i] <= r[i-1])
1035 20           break;
1036             }
1037 87 100         if (i < len)
1038 30           sort_dedup_uv_array(r, itype == IARR_TYPE_NEG, retlen);
1039             }
1040 147           return itype;
1041             }
1042              
1043 14           static int arrayref_to_digit_array(pTHX_ UV** ret, AV* av, int base)
1044             {
1045             SSize_t len, i;
1046 14           UV *r, carry = 0;
1047 14 50         if (SvTYPE((SV*)av) != SVt_PVAV)
1048 0           croak("fromdigits first argument must be a string or array reference");
1049 14           len = av_count(av);
1050 14 50         New(0, r, len, UV);
1051 122 100         for (i = len-1; i >= 0; i--) {
1052 108           SV** psvd = av_fetch(av, i, 0);
1053 108 50         if (_validate_and_set(r+i, aTHX_ *psvd, IFLAG_ANY) != 1) break;
1054 108           r[i] += carry;
1055 108 100         if (r[i] >= (UV)base && i > 0) {
    100          
1056 11           carry = r[i] / base;
1057 11           r[i] -= carry * base;
1058             } else {
1059 97           carry = 0;
1060             }
1061             }
1062 14 50         if (i >= 0) {
1063 0           Safefree(r);
1064 0           return -1;
1065             }
1066             /* printf("array is ["); for(i=0;i
1067 14           *ret = r;
1068 14           return len;
1069             }
1070              
1071             /******************************************************************************/
1072              
1073 28           static int type_of_sumset(int typea, int typeb, UV amin, UV amax, UV bmin, UV bmax) {
1074 28 50         if (typea == IARR_TYPE_BAD || typeb == IARR_TYPE_BAD)
    50          
1075 0           return IARR_TYPE_BAD;
1076 28 100         if (typea != IARR_TYPE_NEG && typeb != IARR_TYPE_NEG) {
    50          
1077             /* ANY+ANY ANY+POS POS+ANY POS+POS */
1078 17 100         if (UV_MAX-amax < bmax) return IARR_TYPE_BAD;
1079 14 100         if (amax+bmax > (UV)IV_MAX) return IARR_TYPE_POS;
1080 12           return IARR_TYPE_ANY;
1081             }
1082             /* For simplicity, throw out NEG+POS to avoid UV+IV */
1083 11 50         if (typea == IARR_TYPE_POS || typeb == IARR_TYPE_POS)
    100          
1084 3           return IARR_TYPE_BAD;
1085             /* NEG+NEG NEG+ANY ANY+NEG */
1086 8 100         if ((IV)amax > 0 && (IV)bmax > 0 && amax + bmax > (UV)IV_MAX)
    50          
    100          
1087 2           return IARR_TYPE_BAD; /* overflow */
1088 6 50         if ((IV)amin < 0 && (IV)bmin < 0 && (UV)(-(IV)amin) + (UV)(-(IV)bmin) > (UV)IV_MAX)
    100          
    100          
1089 2           return IARR_TYPE_BAD; /* underflow */
1090 4 50         if (((IV)amin > 0 || (IV)bmin > 0) && (IV)(amin+bmin) >= 0)
    100          
    100          
1091 1           return IARR_TYPE_ANY; /* Result is all positive */
1092 3           return IARR_TYPE_NEG;
1093             }
1094              
1095             /******************************************************************************/
1096              
1097             #define MPU_SC_SIZE 257 /* Choose 131, 257, 521, 1031, 2053 */
1098             typedef struct { /* lo in 0, hi in 1, cached values in rest */
1099             UV value[2+MPU_SC_SIZE];
1100             size_t index[2+MPU_SC_SIZE];
1101             signed char status[2+MPU_SC_SIZE];
1102             } set_data_t;
1103              
1104 36           static void _sc_clear_cache(set_data_t *cache) {
1105 36           memset(cache->status, 0, sizeof(signed char) * (2+MPU_SC_SIZE));
1106 36           }
1107              
1108             #define _SC_GET_VALUE(statvar, var, arr, i) \
1109             statvar = _validate_and_set(&var, aTHX_ arr[i], IFLAG_ANY); \
1110             if (statvar == 0) return -1;
1111              
1112             #define SC_SET_MID_VALUE(statvar, var, arr, i, cache) \
1113             do { \
1114             if (cache == 0) { \
1115             _SC_GET_VALUE(statvar, var, arr, i) \
1116             } else { \
1117             unsigned int imod_ = 2 + ((i) % MPU_SC_SIZE); \
1118             if (cache->status[imod_] != 0 && cache->index[imod_] == i) { \
1119             statvar = cache->status[imod_]; \
1120             var = cache->value[imod_]; \
1121             } else { \
1122             _SC_GET_VALUE(statvar, var, arr, i) \
1123             cache->status[imod_] = statvar; \
1124             cache->value[imod_] = var; \
1125             cache->index[imod_] = i; \
1126             } \
1127             } \
1128             } while (0)
1129              
1130 166           static int _sc_set_lohi(pTHX_ SV** avarr, set_data_t *cache, int loindex, int hiindex, int *lostatus, int *histatus, UV *loval, UV *hival)
1131             {
1132 166 100         if (cache && cache->status[0] != 0) {
    100          
1133 45           *lostatus = cache->status[0]; *loval = cache->value[0];
1134             } else {
1135 121 100         _SC_GET_VALUE(*lostatus, *loval, avarr, loindex);
1136 117 100         if (cache) {
1137 23           cache->status[0] = *lostatus;
1138 23           cache->value[0] = *loval;
1139             }
1140             }
1141 162 100         if (cache && cache->status[1] != 0) {
    100          
1142 45           *histatus = cache->status[1]; *hival = cache->value[1];
1143             } else {
1144 117 50         _SC_GET_VALUE(*histatus, *hival, avarr, hiindex);
1145 117 100         if (cache) {
1146 23           cache->status[1] = *histatus;
1147 23           cache->value[1] = *hival;
1148             }
1149             }
1150 162           return 1;
1151             }
1152              
1153              
1154              
1155             /* index of val in a set (array ref of sorted unique integers)
1156             * -1 bigint
1157             * n nth-position (0 .. count-1)
1158             * eq will be set to 1 if the element in that position is the input value.
1159             */
1160 169           static int index_for_set(pTHX_ AV* av, set_data_t *cache, int sign, UV val, int *eq)
1161             {
1162             Size_t len;
1163             int lo, hi, lostatus, histatus, midstatus, cmp;
1164             UV rlo, rhi, rmid;
1165             SV** arr;
1166              
1167 169 100         if (sign != 1 && sign != -1)
    100          
1168 3           return -1;
1169 166           len = av_count(av);
1170 166 100         if (len == 0) {
1171 3           *eq = 0;
1172 3           return 0;
1173             }
1174 163           arr = AvARRAY(av);
1175              
1176 163           lo = 0;
1177 163           hi = len-1;
1178 163 100         if (_sc_set_lohi(aTHX_ arr, cache, lo, hi, &lostatus, &histatus, &rlo, &rhi) < 0)
1179 4           return -1;
1180              
1181 159           cmp = _sign_cmp(sign, val, lostatus, rlo);
1182 159 100         if (cmp <= 0) { *eq = cmp==0; return lo; }
1183             /* val > rlo */
1184 108           cmp = _sign_cmp(sign, val, histatus, rhi);
1185 108 100         if (cmp >= 0) { *eq = cmp==0; return hi + (cmp>0); }
1186             /* val < rhi */
1187              
1188 247 100         while (hi-lo > 1) {
1189 218           int mid = lo + ((hi-lo) >> 1);
1190 218 100         SC_SET_MID_VALUE(midstatus, rmid, arr, (size_t)mid, cache);
    50          
    100          
    50          
    50          
1191 218           cmp = _sign_cmp(midstatus, rmid, sign, val);
1192 218 100         if (cmp == 0) { *eq = 1; return mid; }
1193 173 100         if (cmp < 0) { lo = mid; rlo = rmid; lostatus = midstatus; }
1194 84           else { hi = mid; rhi = rmid; histatus = midstatus; }
1195             }
1196 29 100         if (sign == histatus && rhi == val)
    50          
1197 0           *eq = 1;
1198 29 50         else if (_sign_cmp(sign,val, histatus,rhi) > 0)
1199 0           croak("internal index error");
1200 29           return hi;
1201             }
1202              
1203             /* Find index to insert in a set (array ref of sorted unique integers)
1204             * -1 bigint
1205             * 0 already in set
1206             * n should be in n-th position (1 means should be first element)
1207             */
1208 64           static int insert_index_in_set(pTHX_ AV* av, set_data_t *cache, int sign, UV val) {
1209 64           int eq = 0;
1210 64           int index = index_for_set(aTHX_ av, cache, sign, val, &eq);
1211 64 50         return (index < 0) ? index : eq ? 0 : index+1;
    100          
1212             }
1213              
1214             /* Find index of element in a set (array ref of sorted unique integers)
1215             * -1 bigint
1216             * 0 not in set
1217             * n in n-th position (1 means first element)
1218             */
1219 33           static int index_in_set(pTHX_ AV* av, set_data_t *cache, int sign, UV val) {
1220 33           int eq = 0;
1221 33           int index = index_for_set(aTHX_ av, cache, sign, val, &eq);
1222 33 50         return (index < 0) ? index : eq ? index+1 : 0;
    100          
1223             }
1224              
1225             /* See if an element is in a set (array ref of sorted unique integers) */
1226             /* -1 = bigint, 0 = not found, 1 = found */
1227 72           static int is_in_set(pTHX_ AV* av, set_data_t *cache, int sign, UV val)
1228             {
1229 72           int eq = 0;
1230 72           int index = index_for_set(aTHX_ av, cache, sign, val, &eq);
1231 72 100         return (index < 0) ? index : eq ? 1 : 0;
1232             }
1233              
1234             /* 1 if deleted, 0 if not deleted, -1 if need to punt to PP */
1235 33           static int del_from_set(pTHX_ AV* ava, int bstatus, UV b) {
1236 33           int index = index_in_set(aTHX_ ava, 0, bstatus, b);
1237 33 100         if (index <= 0)
1238 8           return index;
1239             {
1240 25           SV **arr = AvARRAY(ava);
1241 25           SV *savep = arr[index-1];
1242 25           Size_t pos = index, alen = av_count(ava);
1243 25 100         if (pos > alen/2) {
1244 13 100         if (pos < alen) {
1245 5           memmove(arr+pos-1, arr+pos, sizeof(SV*) * (alen-pos));
1246 5           arr[alen-1] = savep;
1247             }
1248 13           SvREFCNT_dec_NN(av_pop(ava));
1249             } else {
1250 12 50         if (pos > 1) {
1251 0           memmove(arr+1, arr+0, sizeof(SV*) * (pos-1));
1252 0           arr[0] = savep;
1253             }
1254 12           SvREFCNT_dec_NN(av_shift(ava));
1255             }
1256             }
1257 25           return 1;
1258             }
1259             /* 1 if inserted, 0 if not inserted, -1 if need to punt to PP */
1260 49           static int ins_into_set(pTHX_ AV* ava, int bstatus, UV b) {
1261 49           int index = insert_index_in_set(aTHX_ ava, 0, bstatus, b);
1262 49 100         if (index <= 0)
1263 2           return index;
1264             {
1265             SV *newb, **arr;
1266 47 100         SV* newsvb = NEWSVINT(bstatus, b);
1267 47           Size_t alen = av_count(ava);
1268 47 100         if ((Size_t)index > alen/2) {
1269 38           av_push(ava, newsvb);
1270 38 100         if ((Size_t)index <= alen) {
1271 19           arr = AvARRAY(ava);
1272 19           newb = arr[alen];
1273 19           memmove(arr+index, arr+index-1, sizeof(SV*) * (alen-(index-1)));
1274 19           arr[index-1] = newb;
1275             }
1276             } else {
1277 9           av_unshift(ava, 1);
1278 9           av_store(ava, 0, newsvb);
1279 9 100         if (index > 1) {
1280 3           arr = AvARRAY(ava);
1281 3           newb = arr[0];
1282 3           memmove(arr+0, arr+1, sizeof(SV*) * index);
1283 3           arr[index-1] = newb;
1284             }
1285             }
1286             }
1287 47           return 1;
1288             }
1289              
1290             /******************************************************************************/
1291              
1292 39           static int _compare_array_refs(pTHX_ SV* a, SV* b)
1293             {
1294             AV *ava, *avb;
1295             SSize_t i, alen, blen;
1296 39 50         if ( ((!SvROK(a)) || (SvTYPE(SvRV(a)) != SVt_PVAV)) ||
    50          
1297 39 50         ((!SvROK(b)) || (SvTYPE(SvRV(b)) != SVt_PVAV)) )
    50          
1298 0           return -1;
1299 39           ava = (AV*) SvRV(a);
1300 39           avb = (AV*) SvRV(b);
1301 39           alen = av_len(ava);
1302 39           blen = av_len(avb);
1303 39 100         if (alen != blen)
1304 3           return 0;
1305 214 100         for (i = 0; i <= alen; i++) {
1306 184           SV** iva = av_fetch(ava, i, 0);
1307 184           SV** ivb = av_fetch(avb, i, 0);
1308             SV *sva, *svb;
1309             int res;
1310              
1311 184 50         if (!iva || !ivb) return -1;
    50          
1312 184           sva = *iva;
1313 184           svb = *ivb;
1314              
1315 184 100         if (!SvOK(sva) && !SvOK(svb)) /* Two undefs are fine. */
    100          
1316 2           continue;
1317 182 100         if (!SvOK(sva) || !SvOK(svb)) /* One undef isn't ok. */
    50          
1318 1           return 0;
1319             /* Hashes, I/O, etc. are not ok. */
1320 181 50         if (SvTYPE(sva) >= SVt_PVAV || SvTYPE(svb) >= SVt_PVAV)
    50          
1321 0           return -1;
1322              
1323             /* One of them is a non-object reference */
1324 181 100         if ( (SvROK(sva) && !sv_isobject(sva)) ||
    100          
1325 160 100         (SvROK(svb) && !sv_isobject(svb)) ) {
    100          
1326             /* Always error if either one is not an array reference. */
1327 22 100         if ( (SvROK(sva) && SvTYPE(SvRV(sva)) != SVt_PVAV) ||
    100          
1328 21 50         (SvROK(svb) && SvTYPE(SvRV(svb)) != SVt_PVAV) )
    50          
1329 1           return -1;
1330             /* One reference, one non-reference = not equal */
1331 21 100         if (SvROK(sva) != SvROK(svb))
1332 1           return 0;
1333             /* Now we know both are array references. Compare. */
1334 20           res = _compare_array_refs(aTHX_ sva, svb);
1335 20 50         if (res == 1) continue;
1336 0           return res;
1337             }
1338              
1339             /* Common case: two simple integers */
1340 159 100         if ( SVNUMTEST(sva) && SVNUMTEST(svb)
    100          
1341 116 50         && (SvTYPE(sva) == SVt_IV || SvTYPE(sva) == SVt_PVIV)
    0          
1342 116 50         && (SvTYPE(svb) == SVt_IV || SvTYPE(svb) == SVt_PVIV) ) {
    0          
1343 116           UV va = my_svuv(sva), vb = my_svuv(svb);
1344 116 100         if (va != vb) return 0;
1345 115           continue;
1346             }
1347              
1348             /* This function is more useful if we allow more than strictly integers */
1349             { /* Compare the string representation */
1350             STRLEN alen, blen;
1351 43           const char* stra = SvPV(sva, alen);
1352 43           const char* strb = SvPV(svb, blen);
1353 43 100         if (alen != blen || strcmp(stra,strb) != 0)
    100          
1354 2           return 0;
1355             }
1356             }
1357 30           return 1;
1358             }
1359              
1360 121           static void csprng_init_seed(void* ctx) {
1361             unsigned char* data;
1362 121           New(0, data, 64, unsigned char);
1363 121           get_entropy_bytes(64, data);
1364 121           csprng_seed(ctx, 64, data);
1365 121           Safefree(data);
1366 121           }
1367              
1368 39           static void _comb_init(UV* cm, UV k, int derangement) {
1369             UV i;
1370 39           cm[0] = UV_MAX;
1371 142 100         for (i = 0; i < k; i++)
1372 103           cm[i] = k-i;
1373 39 100         if (derangement && k >= 2) { /* Make derangements start deranged */
    100          
1374 23 100         for (i = 0; i < k; i++)
1375 19 100         cm[k-i-1] = (i&1) ? i : i+2;
1376 4 100         if (k & 1) {
1377 3           cm[0] = k-2;
1378 3           cm[1] = k;
1379             }
1380             }
1381 39           }
1382              
1383 22534           static int _comb_iterate(UV* cm, UV k, UV n, int ix) {
1384             UV i, j, m;
1385 22534 100         if (ix == 0) {
1386 15584 100         if (cm[0]++ < n) return 0; /* Increment last value */
1387 38836 100         for (i = 1; i < k && cm[i] >= n-i; i++) ; /* Find next index to incr */
    100          
1388 11674 100         if (i >= k) return 1; /* Done! */
1389 11649           cm[i]++; /* Increment this one */
1390 50423 100         while (i-- > 0) cm[i] = cm[i+1] + 1; /* Set the rest */
1391 6950 100         } else if (ix == 1) {
1392 8736 100         for (j = 1; j < k && cm[j] > cm[j-1]; j++) ; /* Find last decrease */
    100          
1393 5086 100         if (j >= k) return 1; /* Done! */
1394 6898 100         for (m = 0; cm[j] > cm[m]; m++) ; /* Find next greater */
1395 5080           { UV t = cm[j]; cm[j] = cm[m]; cm[m] = t; } /* Swap */
1396 7833 100         for (i = j-1, m = 0; m < i; i--, m++) /* Reverse the end */
1397 2753           { UV t = cm[i]; cm[i] = cm[m]; cm[m] = t; }
1398             } else {
1399 2737           REDERANGE:
1400 5005 100         for (j = 1; j < k && cm[j] > cm[j-1]; j++) ; /* Find last decrease */
    100          
1401 2737 100         if (j >= k) return 1; /* Done! */
1402 3866 100         for (m = 0; cm[j] > cm[m]; m++) ; /* Find next greater */
1403 2732           { UV t = cm[j]; cm[j] = cm[m]; cm[m] = t; } /* Swap */
1404 2732 100         if (cm[j] == k-j) goto REDERANGE; /* Skip? */
1405 3567 100         for (i = j-1, m = 0; m < i; i--, m++) /* Reverse the end */
1406 1371           { UV t = cm[i]; cm[i] = cm[m]; cm[m] = t; }
1407 17120 100         for (i = 0; i < k; i++) /* Check deranged */
1408 15261 100         if (cm[k-i-1]-1 == i)
1409 337           break;
1410 2196 100         if (i != k) goto REDERANGE;
1411             }
1412 18588           return 0;
1413             }
1414              
1415             /******************************************************************************/
1416             /******************************************************************************/
1417              
1418             MODULE = Math::Prime::Util PACKAGE = Math::Prime::Util
1419              
1420             PROTOTYPES: ENABLE
1421              
1422             BOOT:
1423             {
1424             int i;
1425 120           HV * stash = gv_stashpv("Math::Prime::Util", TRUE);
1426              
1427 120           newCONSTSUB(stash, "_XS_prime_maxbits", newSViv(BITS_PER_WORD));
1428 120           newCONSTSUB(stash, "_ivsize", newSViv(IVSIZE));
1429 120           newCONSTSUB(stash, "_uvsize", newSViv(UVSIZE));
1430 120           newCONSTSUB(stash, "_uvbits", newSViv(UVSIZE * 8));
1431 120           newCONSTSUB(stash, "_nvsize", newSViv(NVSIZE));
1432 120           newCONSTSUB(stash, "_nvmantbits", newSViv(NVMANTBITS));
1433 120           newCONSTSUB(stash, "_nvmantdigits", newSViv((IV)((NVMANTBITS+1) / 3.322)));
1434              
1435             {
1436             MY_CXT_INIT;
1437 120           MY_CXT.MPUroot = stash;
1438 120           MY_CXT.MPUGMP = gv_stashpv("Math::Prime::Util::GMP", TRUE);
1439 120           MY_CXT.MPUPP = gv_stashpv("Math::Prime::Util::PP", TRUE);
1440 12240 100         for (i = 0; i <= CINTS; i++) {
1441 12120           MY_CXT.const_int[i] = newSViv(i-1);
1442 12120           SvREADONLY_on(MY_CXT.const_int[i]);
1443             }
1444 120           New(0, MY_CXT.randcxt, csprng_context_size(), char);
1445 120           csprng_init_seed(MY_CXT.randcxt);
1446 120           MY_CXT.forcount = 0;
1447 120           MY_CXT.forexit = 0;
1448             }
1449             }
1450              
1451             #if defined(USE_ITHREADS) && defined(MY_CXT_KEY)
1452              
1453             void
1454             CLONE(...)
1455             PREINIT:
1456             int i;
1457             PPCODE:
1458             {
1459             MY_CXT_CLONE; /* possible declaration */
1460             MY_CXT.MPUroot = gv_stashpv("Math::Prime::Util", TRUE);
1461             MY_CXT.MPUGMP = gv_stashpv("Math::Prime::Util::GMP", TRUE);
1462             MY_CXT.MPUPP = gv_stashpv("Math::Prime::Util::PP", TRUE);
1463             /* These should be shared between threads, but that's dodgy. */
1464             for (i = 0; i <= CINTS; i++) {
1465             MY_CXT.const_int[i] = newSViv(i-1);
1466             SvREADONLY_on(MY_CXT.const_int[i]);
1467             }
1468             /* Make a new CSPRNG context for this thread */
1469             New(0, MY_CXT.randcxt, csprng_context_size(), char);
1470             csprng_init_seed(MY_CXT.randcxt);
1471             /* NOTE: There is no thread destroy, so these never get freed... */
1472             MY_CXT.forcount = 0;
1473             MY_CXT.forexit = 0;
1474             }
1475             return; /* skip implicit PUTBACK, returning @_ to caller, more efficient*/
1476              
1477             #endif
1478              
1479             void
1480             END(...)
1481             PREINIT:
1482             dMY_CXT;
1483             int i;
1484             PPCODE:
1485 120           _prime_memfreeall();
1486 120           MY_CXT.MPUroot = NULL;
1487 120           MY_CXT.MPUGMP = NULL;
1488 120           MY_CXT.MPUPP = NULL;
1489 12240 100         for (i = 0; i <= CINTS; i++) {
1490 12120           SV * const sv = MY_CXT.const_int[i];
1491 12120           MY_CXT.const_int[i] = NULL;
1492 12120           SvREFCNT_dec_NN(sv);
1493             } /* stashes are owned by stash tree, no refcount on them in MY_CXT */
1494 120           Safefree(MY_CXT.randcxt); MY_CXT.randcxt = 0;
1495 120           return; /* skip implicit PUTBACK, returning @_ to caller, more efficient*/
1496              
1497              
1498             void csrand(IN SV* seed = 0)
1499             PREINIT:
1500             unsigned char* data;
1501             STRLEN size;
1502             dMY_CXT;
1503             PPCODE:
1504 11 100         if (items == 0) {
1505 1           csprng_init_seed(MY_CXT.randcxt);
1506 10 50         } else if (_XS_get_secure()) {
1507 0           croak("secure option set, manual seeding disabled");
1508             } else {
1509 10           data = (unsigned char*) SvPV(seed, size);
1510 10           csprng_seed(MY_CXT.randcxt, size, data);
1511             }
1512 11 50         if (_XS_get_callgmp() >= 42) CALLROOTSUB("_csrand_p");
1513 11           return;
1514              
1515             UV srand(IN UV seedval = 0)
1516             PREINIT:
1517             dMY_CXT;
1518             CODE:
1519 5 50         if (_XS_get_secure())
1520 0           croak("secure option set, manual seeding disabled");
1521 5 100         if (items == 0)
1522 1           get_entropy_bytes(sizeof(UV), (unsigned char*) &seedval);
1523 5           csprng_srand(MY_CXT.randcxt, seedval);
1524 5 50         if (_XS_get_callgmp() >= 42) CALLROOTSUB("_srand_p");
1525 5 50         RETVAL = seedval;
1526             OUTPUT:
1527             RETVAL
1528              
1529             UV irand()
1530             ALIAS:
1531             irand64 = 1
1532             PREINIT:
1533             dMY_CXT;
1534             CODE:
1535             #if BITS_PER_WORD == 32
1536             /* TODO: what should irand64 on 32-bit perl do? */
1537             RETVAL = irand32(MY_CXT.randcxt);
1538             #else
1539 120116 100         RETVAL = ix == 0 ? irand32(MY_CXT.randcxt) : irand64(MY_CXT.randcxt);
    100          
1540             #endif
1541             OUTPUT:
1542             RETVAL
1543              
1544             NV drand(NV m = 0.0)
1545             ALIAS:
1546             rand = 1
1547             PREINIT:
1548             dMY_CXT;
1549             CODE:
1550             PERL_UNUSED_VAR(ix);
1551 6037           RETVAL = drand64(MY_CXT.randcxt);
1552 6037 100         if (m != 0) RETVAL *= m;
1553             OUTPUT:
1554             RETVAL
1555              
1556             SV* random_bytes(IN UV n)
1557             PREINIT:
1558             char* sptr;
1559             dMY_CXT;
1560             CODE:
1561 33 100         RETVAL = newSV(n == 0 ? 1 : n);
1562 33           SvPOK_only(RETVAL);
1563 33           SvCUR_set(RETVAL, n);
1564 33           sptr = SvPVX(RETVAL);
1565 33           csprng_rand_bytes(MY_CXT.randcxt, n, (unsigned char*)sptr);
1566 33           sptr[n] = '\0';
1567             OUTPUT:
1568             RETVAL
1569              
1570             SV* entropy_bytes(IN UV n)
1571             PREINIT:
1572             char* sptr;
1573             CODE:
1574 2 50         RETVAL = newSV(n == 0 ? 1 : n);
1575 2           SvPOK_only(RETVAL);
1576 2           SvCUR_set(RETVAL, n);
1577 2           sptr = SvPVX(RETVAL);
1578 2           get_entropy_bytes(n, (unsigned char*)sptr);
1579 2           sptr[n] = '\0';
1580             OUTPUT:
1581             RETVAL
1582              
1583             UV _is_csprng_well_seeded()
1584             ALIAS:
1585             _XS_get_verbose = 1
1586             _XS_get_callgmp = 2
1587             _XS_get_secure = 3
1588             _XS_set_secure = 4
1589             _get_forexit = 5
1590             _start_for_loop = 6
1591             _get_prime_cache_size = 7
1592             CODE:
1593 2408           switch (ix) {
1594 1           case 0: { dMY_CXT; RETVAL = is_csprng_well_seeded(MY_CXT.randcxt); } break;
1595 0           case 1: RETVAL = _XS_get_verbose(); break;
1596 0           case 2: RETVAL = _XS_get_callgmp(); break;
1597 0           case 3: RETVAL = _XS_get_secure(); break;
1598 0           case 4: _XS_set_secure(); RETVAL = 1; break;
1599 158           case 5: { dMY_CXT; RETVAL = MY_CXT.forexit; } break;
1600 17           case 6: { dMY_CXT; MY_CXT.forcount++; RETVAL = MY_CXT.forexit; MY_CXT.forexit = 0; } break;
1601 2232           case 7:
1602 2232           default: RETVAL = get_prime_cache(0,0); break;
1603             }
1604             OUTPUT:
1605             RETVAL
1606              
1607             bool _validate_integer(SV* svn)
1608             ALIAS:
1609             _validate_integer_nonneg = 1
1610             _validate_integer_positive = 2
1611             _validate_integer_abs = 3
1612             PREINIT:
1613             uint32_t mask;
1614             int status;
1615             UV n;
1616             CODE:
1617             /* Flag: 0 neg ok, 1 neg err, 2 zero or neg err, 3 abs */
1618 225972           switch (ix) {
1619 209639           case 0: mask = IFLAG_ANY; break;
1620 8018           case 1: mask = IFLAG_POS; break;
1621 4820           case 2: mask = IFLAG_POS | IFLAG_NONZERO; break;
1622 3495           case 3: mask = IFLAG_ABS; break;
1623 0           default: croak("_validate_integer unknown flag value");
1624             }
1625 225972           status = _validate_and_set(&n, aTHX_ svn, mask);
1626 225966 100         if (status != 0) {
1627 110638 100         SETSVINT(svn, status == 1, n, (IV)n);
1628             #if PERL_VERSION_LT(5,8,0) && BITS_PER_WORD == 64
1629             if (status == 1 && n > 562949953421312UL)
1630             sv_setpvf(svn, "%"UVuf, n);
1631             if (status == -1 && (IV)n < -562949953421312)
1632             sv_setpvf(svn, "%"IVdf, n);
1633             #endif
1634             } else { /* Status 0 = bigint */
1635 115328 100         if (mask & IFLAG_ABS) {
1636             /* TODO: if given a positive bigint, no need for this */
1637 1650           sv_setsv(svn, sv_to_bigint_abs(aTHX_ svn));
1638 113678 100         } else if (mask & IFLAG_POS) {
1639 4639 100         if (!_is_sv_bigint(aTHX_ svn))
1640 49           sv_setsv(svn, sv_to_bigint_nonneg(aTHX_ svn));
1641             } else {
1642 109039 100         if (!_is_sv_bigint(aTHX_ svn))
1643 867           sv_setsv(svn, sv_to_bigint(aTHX_ svn));
1644             }
1645             }
1646 225965 50         RETVAL = TRUE;
1647             OUTPUT:
1648             RETVAL
1649              
1650             void prime_memfree()
1651             PREINIT:
1652             dMY_CXT;
1653             PPCODE:
1654 10           prime_memfree();
1655             /* (void) _vcallgmpsubn(aTHX_ G_VOID|G_DISCARD, "_GMP_memfree", 0, 49); */
1656 10 50         if (MY_CXT.MPUPP != NULL) DISPATCH_VOIDPP();
1657 10           XSRETURN(0);
1658              
1659             void
1660             prime_precalc(IN UV n)
1661             ALIAS:
1662             _XS_set_verbose = 1
1663             _XS_set_callgmp = 2
1664             _end_for_loop = 3
1665             PPCODE:
1666 272           PUTBACK; /* SP is never used again, the 3 next func calls are tailcall
1667             friendly since this XSUB has nothing to do after the 3 calls return */
1668 272           switch (ix) {
1669 127           case 0: prime_precalc(n); break;
1670 8           case 1: _XS_set_verbose(n); break;
1671 120           case 2: _XS_set_callgmp(n); break;
1672 17           case 3:
1673 17           default: { dMY_CXT; MY_CXT.forcount--; MY_CXT.forexit = n>0; } break;
1674             }
1675 272           return; /* skip implicit PUTBACK */
1676              
1677              
1678             void prime_count(IN SV* svlo, IN SV* svhi = 0)
1679             ALIAS:
1680             semiprime_count = 1
1681             twin_prime_count = 2
1682             ramanujan_prime_count = 3
1683             perfect_power_count = 4
1684             prime_power_count = 5
1685             lucky_count = 6
1686             PREINIT:
1687 3238 100         UV lo = 0, hi, count = 0;
1688             PPCODE:
1689 3238 100         if ((items == 1 && _validate_and_set(&hi, aTHX_ svlo, IFLAG_POS)) ||
    50          
    50          
1690 1833 100         (items == 2 && _validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) && _validate_and_set(&hi, aTHX_ svhi, IFLAG_POS))) {
    50          
1691 3237 100         if (lo <= hi) {
1692 2416           switch (ix) {
1693 150           case 0: count = prime_count_range(lo, hi); break;
1694 20           case 1: count = semiprime_count_range(lo, hi); break;
1695 11           case 2: count = twin_prime_count_range(lo, hi); break;
1696 10           case 3: count = ramanujan_prime_count_range(lo, hi); break;
1697 59           case 4: count = perfect_power_count_range(lo, hi); break;
1698 206           case 5: count = prime_power_count_range(lo, hi); break;
1699 1960           case 6: count = lucky_count_range(lo, hi); break;
1700             }
1701             }
1702 3237           XSRETURN_UV(count);
1703             }
1704 1           DISPATCHPP();
1705 1           XSRETURN(1);
1706              
1707              
1708             void prime_count_upper(IN SV* svn)
1709             ALIAS:
1710             prime_count_lower = 1
1711             prime_count_approx = 2
1712             prime_power_count_upper = 3
1713             prime_power_count_lower = 4
1714             prime_power_count_approx = 5
1715             perfect_power_count_upper = 6
1716             perfect_power_count_lower = 7
1717             perfect_power_count_approx = 8
1718             ramanujan_prime_count_upper = 9
1719             ramanujan_prime_count_lower = 10
1720             ramanujan_prime_count_approx = 11
1721             twin_prime_count_approx = 12
1722             semiprime_count_approx = 13
1723             lucky_count_upper = 14
1724             lucky_count_lower = 15
1725             lucky_count_approx = 16
1726             PREINIT:
1727             UV n, ret;
1728             PPCODE:
1729 871 100         if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) {
1730 849           switch (ix) {
1731 35           case 0: ret = prime_count_upper(n); break;
1732 35           case 1: ret = prime_count_lower(n); break;
1733 36           case 2: ret = prime_count_approx(n); break;
1734 41           case 3: ret = prime_power_count_upper(n); break;
1735 41           case 4: ret = prime_power_count_lower(n); break;
1736 41           case 5: ret = prime_power_count_approx(n); break;
1737 57           case 6: ret = perfect_power_count_upper(n); break;
1738 57           case 7: ret = perfect_power_count_lower(n); break;
1739 3           case 8: ret = perfect_power_count_approx(n); break;
1740 74           case 9: ret = ramanujan_prime_count_upper(n); break;
1741 74           case 10: ret = ramanujan_prime_count_lower(n); break;
1742 2           case 11: ret = ramanujan_prime_count_approx(n); break;
1743 7           case 12: ret = twin_prime_count_approx(n); break;
1744 4           case 13: ret = semiprime_count_approx(n); break;
1745 114           case 14: ret = lucky_count_upper(n); break;
1746 114           case 15: ret = lucky_count_lower(n); break;
1747 114           case 16:
1748 114           default: ret = lucky_count_approx(n); break;
1749             }
1750 849           XSRETURN_UV(ret);
1751             }
1752 22           DISPATCHPP();
1753 22           objectify_result(aTHX_ svn, ST(0));
1754 22           XSRETURN(1);
1755              
1756              
1757             void sum_primes(IN SV* svlo, IN SV* svhi = 0)
1758             PREINIT:
1759 1030 100         UV lo = 2, hi;
1760             PPCODE:
1761 1030 100         if ((items == 1 && _validate_and_set(&hi, aTHX_ svlo, IFLAG_POS)) ||
    50          
    50          
1762 29 50         (items == 2 && _validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) && _validate_and_set(&hi, aTHX_ svhi, IFLAG_POS))) {
    50          
1763 1030           UV count = 0;
1764 1030           int retok = 1;
1765             /* 32/64-bit, Legendre or table-accelerated sieving. */
1766 1030           retok = sum_primes(lo, hi, &count);
1767             /* If that didn't work, try the 128-bit version if supported. */
1768 1030 100         if (retok == 0 && HAVE_SUM_PRIMES128) {
1769             UV hicount, lo_hic, lo_loc;
1770 1           retok = sum_primes128(hi, &hicount, &count);
1771 1 50         if (retok == 1 && lo > 2) {
    50          
1772 0           retok = sum_primes128(lo-1, &lo_hic, &lo_loc);
1773 0           hicount -= lo_hic;
1774 0 0         if (count < lo_loc) hicount--;
1775 0           count -= lo_loc;
1776             }
1777 1 50         if (retok == 1 && hicount > 0)
    50          
1778 1           RETURN_128(hicount, count);
1779             }
1780 1029 50         if (retok == 1)
1781 1029           XSRETURN_UV(count);
1782             }
1783 0           DISPATCHPP();
1784 0           XSRETURN(1);
1785              
1786             void random_prime(IN SV* svlo, IN SV* svhi = 0)
1787             PREINIT:
1788 11041 100         UV lo = 2, hi, ret;
1789             dMY_CXT;
1790             PPCODE:
1791 11041 100         if ((items == 1 && _validate_and_set(&hi, aTHX_ svlo, IFLAG_POS)) ||
    50          
    50          
1792 36 100         (items == 2 && _validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) && _validate_and_set(&hi, aTHX_ svhi, IFLAG_POS))) {
    50          
1793 11027           ret = random_prime(MY_CXT.randcxt,lo,hi);
1794 11027 100         if (ret) XSRETURN_UV(ret);
1795 6           else XSRETURN_UNDEF;
1796             }
1797 1           DISPATCHPP();
1798 1           objectify_result(aTHX_ svlo, ST(0));
1799 1           XSRETURN(1);
1800              
1801             void print_primes(IN SV* svlo, IN SV* svhi = 0, IN int infd = -1)
1802             PREINIT:
1803 0 0         UV lo = 2, hi;
1804             PPCODE:
1805 0 0         if ((items == 1 && _validate_and_set(&hi, aTHX_ svlo, IFLAG_POS)) ||
    0          
    0          
1806 0 0         (items >= 2 && _validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) && _validate_and_set(&hi, aTHX_ svhi, IFLAG_POS))) {
    0          
1807 0 0         if (lo <= hi) {
1808 0 0         int fd = (infd == -1) ? fileno(stdout) : infd;
1809 0           print_primes(lo, hi, fd);
1810             }
1811             } else {
1812 0           DISPATCH_VOIDPP();
1813             }
1814 0           return;
1815              
1816             UV
1817             _LMO_pi(IN UV n)
1818             ALIAS:
1819             _legendre_pi = 1
1820             _meissel_pi = 2
1821             _lehmer_pi = 3
1822             _LMOS_pi = 4
1823             _segment_pi = 5
1824             PREINIT:
1825             UV ret;
1826             CODE:
1827 6           switch (ix) {
1828 1           case 0: ret = LMO_prime_count(n); break;
1829 1           case 1: ret = legendre_prime_count(n); break;
1830 1           case 2: ret = meissel_prime_count(n); break;
1831 1           case 3: ret = lehmer_prime_count(n); break;
1832 1           case 4: ret = LMOS_prime_count(n); break;
1833 1           default:ret = segment_prime_count(2,n); break;
1834             }
1835 6 50         RETVAL = ret;
1836             OUTPUT:
1837             RETVAL
1838              
1839              
1840              
1841              
1842             void
1843             sieve_primes(IN UV low, IN UV high)
1844             ALIAS:
1845             trial_primes = 1
1846             erat_primes = 2
1847             segment_primes = 3
1848             PREINIT:
1849             AV* av;
1850             PPCODE:
1851 52           CREATE_RETURN_AV(av);
1852 52 100         if ((low <= 2) && (high >= 2)) av_push(av, newSVuv( 2 ));
    100          
1853 52 100         if ((low <= 3) && (high >= 3)) av_push(av, newSVuv( 3 ));
    100          
1854 52 100         if ((low <= 5) && (high >= 5)) av_push(av, newSVuv( 5 ));
    100          
1855 52 100         if (low < 7) low = 7;
1856 52 100         if (low <= high) {
1857 36 100         if (ix == 0) { /* Sieve with primary cache */
1858 555 50         START_DO_FOR_EACH_PRIME(low, high) {
    50          
    50          
    0          
    0          
    100          
    50          
    100          
    50          
    50          
    100          
1859 538           av_push(av,newSVuv(p));
1860             } END_DO_FOR_EACH_PRIME
1861 27 100         } else if (ix == 1) { /* Trial */
1862 9           for (low = next_prime(low-1);
1863 547 100         low <= high && low != 0;
    50          
1864 538           low = next_prime(low) ) {
1865 538           av_push(av,newSVuv(low));
1866             }
1867 18 100         } else if (ix == 2) { /* Erat with private memory */
1868 9           unsigned char* sieve = sieve_erat30(high);
1869 665 50         START_DO_FOR_EACH_SIEVE_PRIME( sieve, 0, low, high ) {
    100          
    100          
    100          
    100          
1870 538           av_push(av,newSVuv(p));
1871 26           } END_DO_FOR_EACH_SIEVE_PRIME
1872 9           Safefree(sieve);
1873 9 50         } else if (ix == 3) { /* Segment */
1874             unsigned char* segment;
1875             UV seg_base, seg_low, seg_high;
1876 9           void* ctx = start_segment_primes(low, high, &segment);
1877 18 100         while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) {
1878 583 50         START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_base, seg_low, seg_high )
    100          
    100          
    100          
    100          
1879 538           av_push(av,newSVuv( p ));
1880 23           END_DO_FOR_EACH_SIEVE_PRIME
1881             }
1882 9           end_segment_primes(ctx);
1883             }
1884             }
1885 52           return; /* skip implicit PUTBACK */
1886              
1887              
1888             void primes(IN SV* svlo, IN SV* svhi = 0)
1889             PREINIT:
1890             AV* av;
1891 1179 100         UV lo = 0, hi, i;
1892             PPCODE:
1893 1179 100         if ((items == 1 && _validate_and_set(&hi, aTHX_ svlo, IFLAG_POS)) ||
    50          
    50          
1894 102 100         (items == 2 && _validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) && _validate_and_set(&hi, aTHX_ svhi, IFLAG_POS))) {
    50          
1895 1163           CREATE_RETURN_AV(av);
1896 1163 100         if ((lo <= 2) && (hi >= 2)) av_push(av, newSVuv( 2 ));
    100          
1897 1163 100         if ((lo <= 3) && (hi >= 3)) av_push(av, newSVuv( 3 ));
    100          
1898 1163 100         if ((lo <= 5) && (hi >= 5)) av_push(av, newSVuv( 5 ));
    100          
1899 1163 100         if (lo < 7) lo = 7;
1900 1163 100         if (lo <= hi) {
1901 1126 100         if ( hi-lo <= 10
1902 1106 100         || (hi > 100000000UL && hi-lo <= 330)
    50          
1903 1106 100         || (hi > 4000000000UL && hi-lo <= 1500)
    100          
1904             ) {
1905 729 100         for (i = !(lo&1); i <= hi-lo; i += 2)
1906 708 100         if (is_prime(lo+i))
1907 47           av_push(av,newSVuv(lo+i));
1908 1105 100         } else if (hi < (65536*30) || hi <= get_prime_cache(0,0)) {
    50          
1909 586736 50         START_DO_FOR_EACH_PRIME(lo, hi) {
    50          
    50          
    0          
    0          
    100          
    100          
    100          
    100          
    50          
    100          
1910 576865           av_push(av,newSVuv(p));
1911             } END_DO_FOR_EACH_PRIME
1912             } else {
1913             unsigned char* segment;
1914             UV seg_base, seg_low, seg_high;
1915 9           void* ctx = start_segment_primes(lo, hi, &segment);
1916 21 100         while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) {
1917 325969 50         START_DO_FOR_EACH_SIEVE_PRIME(segment, seg_base, seg_low, seg_high)
    100          
    100          
    100          
    100          
1918 307612           av_push(av,newSVuv( p ));
1919 18329           END_DO_FOR_EACH_SIEVE_PRIME
1920             }
1921 9           end_segment_primes(ctx);
1922             }
1923             }
1924             } else {
1925 1           DISPATCHPP();
1926             }
1927 1164           return;
1928              
1929             void almost_primes(IN UV k, IN SV* svlo, IN SV* svhi = 0)
1930             ALIAS:
1931             omega_primes = 1
1932             PREINIT:
1933             AV* av;
1934 22           UV lo = 1, hi, i, n, *S;
1935             PPCODE:
1936 22 100         if ((items == 2 && _validate_and_set(&hi, aTHX_ svlo, IFLAG_POS)) ||
    50          
    50          
1937 8 100         (items >= 3 && _validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) && _validate_and_set(&hi, aTHX_ svhi, IFLAG_POS))) {
    50          
1938 20           CREATE_RETURN_AV(av);
1939 20           S = 0;
1940 20 100         if (ix == 0) n = generate_almost_primes(&S, k, lo, hi);
1941 5           else n = range_omega_prime_sieve(&S, k, lo, hi);
1942 432 100         for (i = 0; i < n; i++)
1943 412           av_push(av, newSVuv(S[i]));
1944 20 100         if (S != 0) Safefree(S);
1945             } else {
1946 2           DISPATCHPP();
1947             }
1948 22           return;
1949              
1950              
1951             void prime_powers(IN SV* svlo, IN SV* svhi = 0)
1952             ALIAS:
1953             twin_primes = 1
1954             semi_primes = 2
1955             ramanujan_primes = 3
1956             PREINIT:
1957             AV* av;
1958 102 100         UV lo = 0, hi, i, num, *L;
1959             PPCODE:
1960 102 100         if ((items == 1 && _validate_and_set(&hi, aTHX_ svlo, IFLAG_POS)) ||
    50          
    50          
1961 48 100         (items == 2 && _validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) && _validate_and_set(&hi, aTHX_ svhi, IFLAG_POS))) {
    50          
1962 101           CREATE_RETURN_AV(av);
1963 101 100         if (ix == 0) { /* Prime power */
1964 52 100         if ((lo <= 2) && (hi >= 2)) av_push(av, newSVuv( 2 ));
    100          
1965 52 100         if ((lo <= 3) && (hi >= 3)) av_push(av, newSVuv( 3 ));
    100          
1966 52 100         if ((lo <= 4) && (hi >= 4)) av_push(av, newSVuv( 4 ));
    100          
1967 52 100         if ((lo <= 5) && (hi >= 5)) av_push(av, newSVuv( 5 ));
    100          
1968 49 100         } else if (ix == 1) { /* Twin */
1969 16 100         if ((lo <= 3) && (hi >= 3)) av_push(av, newSVuv( 3 ));
    50          
1970 16 100         if ((lo <= 5) && (hi >= 5)) av_push(av, newSVuv( 5 ));
    50          
1971 33 100         } else if (ix == 2) { /* Semi */
1972 18 100         if ((lo <= 4) && (hi >= 4)) av_push(av, newSVuv( 4 ));
    50          
1973 18 100         if ((lo <= 6) && (hi >= 6)) av_push(av, newSVuv( 6 ));
    50          
1974 15 50         } else if (ix == 3) { /* Ramanujan */
1975 15 100         if ((lo <= 2) && (hi >= 2)) av_push(av, newSVuv( 2 ));
    50          
1976             }
1977 101 100         if (lo < 7) lo = 7;
1978 101 100         if (lo <= hi) {
1979 95           switch (ix) {
1980 46           case 0: num = prime_power_sieve(&L,lo,hi); break;
1981 16           case 1: num = range_twin_prime_sieve(&L,lo,hi); break;
1982 18           case 2: num = range_semiprime_sieve(&L,lo,hi); break;
1983 15           case 3: num = range_ramanujan_prime_sieve(&L,lo,hi); break;
1984 0           default: num = 0; L = 0; break;
1985             }
1986 1059 100         for (i = 0; i < num; i++)
1987 964           av_push(av,newSVuv(L[i]));
1988 95           Safefree(L);
1989             }
1990             } else {
1991 1           DISPATCHPP();
1992             }
1993 102           return;
1994              
1995             void
1996             lucky_numbers(IN SV* svlo, IN SV* svhi = 0)
1997             PREINIT:
1998             AV* av;
1999 207 100         UV lo = 0, hi, i, nlucky = 0;
2000             PPCODE:
2001 207 100         if ((items == 1 && _validate_and_set(&hi, aTHX_ svlo, IFLAG_POS)) ||
    50          
    50          
2002 1 50         (items == 2 && _validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) && _validate_and_set(&hi, aTHX_ svhi, IFLAG_POS))) {
    50          
2003 207           CREATE_RETURN_AV(av);
2004 413 100         if (lo == 0 && hi <= UVCONST(4000000000)) {
    50          
2005 206           uint32_t* lucky = lucky_sieve32(&nlucky, hi);
2006 45922 100         for (i = 0; i < nlucky; i++)
2007 45716           av_push(av,newSVuv(lucky[i]));
2008 206           Safefree(lucky);
2009             } else {
2010 1           UV* lucky = lucky_sieve_range(&nlucky, lo, hi);
2011 7 100         for (i = 0; i < nlucky; i++)
2012 6           av_push(av,newSVuv(lucky[i]));
2013 1           Safefree(lucky);
2014             }
2015             } else {
2016 0           DISPATCHPP();
2017             }
2018 207           return;
2019              
2020             void minimal_goldbach_pair(IN SV* svn)
2021             ALIAS:
2022             goldbach_pair_count = 1
2023             PREINIT:
2024             UV n, res;
2025             PPCODE:
2026 80 100         if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) {
2027 79 100         if (ix == 0) {
2028 41           res = minimal_goldbach_pair(n);
2029 41 100         if (res == 0) XSRETURN_UNDEF;
2030             } else {
2031 38           res = goldbach_pair_count(n);
2032             }
2033 70           XSRETURN_UV(res);
2034             }
2035 1           DISPATCHPP();
2036 1           XSRETURN(1);
2037              
2038             void goldbach_pairs(IN SV* svn)
2039             PREINIT:
2040             size_t npairs, i;
2041             UV n, *L;
2042             PPCODE:
2043 38 50         if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS) == 1) {
2044 38 50         if (GIMME_V != G_ARRAY)
2045 0           XSRETURN_UV(goldbach_pair_count(n));
2046 38           L = goldbach_pairs(&npairs, n);
2047 38 100         if (L == 0) XSRETURN_EMPTY;
2048 29 50         EXTEND(SP, (EXTEND_TYPE)npairs);
    50          
2049 142 100         for (i = 0; i < npairs; i++)
2050 113           PUSHs(sv_2mortal(newSVuv(L[i])));
2051 29           Safefree(L);
2052             } else {
2053 0           DISPATCHPP();
2054 0           return;
2055             }
2056              
2057             void powerful_numbers(IN SV* svlo, IN SV* svhi = 0, IN UV k = 2)
2058             PREINIT:
2059             AV* av;
2060 10 100         UV lo = 1, hi, i, npowerful, *powerful;
2061             PPCODE:
2062 10 100         if ((items == 1 && _validate_and_set(&hi, aTHX_ svlo, IFLAG_POS)) ||
    50          
    50          
2063 9 50         (items >= 2 && _validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) && _validate_and_set(&hi, aTHX_ svhi, IFLAG_POS))) {
    50          
2064 10           CREATE_RETURN_AV(av);
2065 10           powerful = powerful_numbers_range(&npowerful, lo, hi, k);
2066 111 100         for (i = 0; i < npowerful; i++)
2067 101           av_push(av,newSVuv(powerful[i]));
2068 10           Safefree(powerful);
2069             } else {
2070 0           DISPATCHPP();
2071             }
2072 10           return;
2073              
2074             void
2075             sieve_range(IN SV* svn, IN UV width, IN UV depth)
2076             PREINIT:
2077             int status;
2078             UV i, n;
2079             PPCODE:
2080             /* Return index of every n unless it is a composite with factor > depth */
2081 10           status = _validate_and_set(&n, aTHX_ svn, IFLAG_POS);
2082 10 50         if (status == 1) {
2083 10 50         if ((n+width) < n) {
2084 0           status = 0; /* range will overflow */
2085             } else { /* TODO: actually sieve */
2086 1620 100         for (i = (n<2)?2-n:0; i < width; i++)
    100          
2087 1610 100         if (is_rough(n+i, (depth+1) >= (n+i) ? n+i : depth+1))
2088 316 50         XPUSHs(sv_2mortal(newSVuv( i )));
2089             }
2090             }
2091 10 50         if (status != 1) {
2092 0           DISPATCHPP();
2093 0           return;
2094             }
2095              
2096             void
2097             sieve_prime_cluster(IN SV* svlo, IN SV* svhi, ...)
2098             PREINIT:
2099             uint32_t nc, cl[100];
2100             UV i, lo, hi, cval, nprimes, *list;
2101             int done;
2102             PPCODE:
2103 41           nc = items-1;
2104 41 50         if (items > 100) croak("sieve_prime_cluster: too many entries");
2105 41           cl[0] = 0;
2106 256 100         for (i = 1; i < nc; i++) {
2107 215 50         if (!_validate_and_set(&cval, aTHX_ ST(1+i), IFLAG_POS))
2108 0           croak("sieve_prime_cluster: cluster values must be standard integers");
2109 215 50         if (cval & 1) croak("sieve_prime_cluster: values must be even");
2110 215 50         if (cval > 2147483647UL) croak("sieve_prime_cluster: values must be 31-bit");
2111 215 50         if (cval <= cl[i-1]) croak("sieve_prime_cluster: values must be increasing");
2112 215           cl[i] = cval;
2113             }
2114 41           done = 0;
2115 73           if (_validate_and_set(&lo, aTHX_ svlo, IFLAG_POS) &&
2116 32           _validate_and_set(&hi, aTHX_ svhi, IFLAG_POS)) {
2117 32           list = sieve_cluster(lo, hi, nc, cl, &nprimes);
2118 32 50         if (list != 0) {
2119 32           done = 1;
2120 32 50         EXTEND(SP, (EXTEND_TYPE)nprimes);
    100          
2121 12308 100         for (i = 0; i < nprimes; i++)
2122 12276           PUSHs(sv_2mortal(newSVuv( list[i] )));
2123 32           Safefree(list);
2124             }
2125             }
2126 41 100         if (!done) {
2127 9           DISPATCHPP();
2128 9           return;
2129             }
2130              
2131             void is_pseudoprime(IN SV* svn, ...)
2132             ALIAS:
2133             is_euler_pseudoprime = 1
2134             is_strong_pseudoprime = 2
2135             PREINIT:
2136 14937           int i, status, ret = 0;
2137             UV n, base;
2138             PPCODE:
2139 14937           status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
2140 14937 100         if (status == 1) {
2141 14813 100         if (n < 3) {
2142 4           ret = (n == 2);
2143 14809 100         } else if (ix == 2 && !(n&1)) {
    100          
2144 7031           ret = 0;
2145 7778 100         } else if (items == 1) {
2146 4106 100         ret = (ix == 0) ? is_pseudoprime(n, 2) :
2147 2051 100         (ix == 1) ? is_euler_pseudoprime(n, 2) :
2148 2015           is_strong_pseudoprime(n, 2);
2149             } else {
2150 12249 100         for (i = 1, ret = 1; i < items && ret == 1; i++) {
    100          
2151 6526           status = _validate_and_set(&base, aTHX_ ST(i), IFLAG_POS);
2152 6526 50         if (status != 1) break;
2153 12952 100         ret = (ix == 0) ? is_pseudoprime(n, base) :
2154 6426 100         (ix == 1) ? is_euler_pseudoprime(n, base) :
2155 6353           is_strong_pseudoprime(n, base);
2156             }
2157             }
2158             }
2159 14937 100         if (status != 0) RETURN_NPARITY(ret);
    50          
    50          
2160 126           DISPATCHPP();
2161 124           XSRETURN(1);
2162              
2163              
2164             void is_prime(IN SV* svn)
2165             ALIAS:
2166             is_prob_prime = 1
2167             is_provable_prime = 2
2168             is_bpsw_prime = 3
2169             is_aks_prime = 4
2170             is_lucas_pseudoprime = 5
2171             is_strong_lucas_pseudoprime = 6
2172             is_extra_strong_lucas_pseudoprime = 7
2173             is_frobenius_underwood_pseudoprime = 8
2174             is_frobenius_khashin_pseudoprime = 9
2175             is_catalan_pseudoprime = 10
2176             is_euler_plumb_pseudoprime = 11
2177             is_ramanujan_prime = 12
2178             is_semiprime = 13
2179             is_chen_prime = 14
2180             is_mersenne_prime = 15
2181             PREINIT:
2182             int status, ret;
2183             UV n;
2184             PPCODE:
2185 49722           ret = 0;
2186 49722           status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
2187 49719 100         if (status == 1) {
2188 48475           switch (ix) {
2189 29560           case 0: ret = 2*is_prime(n); break;
2190 3969           case 1: ret = 2*is_prob_prime(n); break;
2191 2           case 2: ret = 2*is_prime(n); break;
2192 0           case 3: ret = BPSW(n); break;
2193 11           case 4: ret = is_aks_prime(n); break;
2194 29           case 5: ret = is_lucas_pseudoprime(n, 0); break;
2195 20           case 6: ret = is_lucas_pseudoprime(n, 1); break;
2196 121           case 7: ret = is_lucas_pseudoprime(n, 3); break;
2197 48           case 8: ret = is_frobenius_underwood_pseudoprime(n); break;
2198 48           case 9: ret = is_frobenius_khashin_pseudoprime(n); break;
2199 3           case 10: ret = is_catalan_pseudoprime(n); break;
2200 29           case 11: ret = is_euler_plumb_pseudoprime(n); break;
2201 984           case 12: ret = is_ramanujan_prime(n); break;
2202 11165           case 13: ret = is_semiprime(n); break;
2203 202           case 14: ret = is_chen_prime(n); break;
2204 2284 50         case 15: ret = is_mersenne_prime(n); if (ret == -1) status = 0; break;
2205 0           default: break;
2206             }
2207             }
2208 49719 100         if (status != 0) RETURN_NPARITY(ret);
    50          
    50          
2209 1076           DISPATCHPP();
2210 1076           XSRETURN(1);
2211              
2212             void
2213             is_perrin_pseudoprime(IN SV* svn, IN UV k = 0)
2214             ALIAS:
2215             is_almost_extra_strong_lucas_pseudoprime = 1
2216             is_delicate_prime = 2
2217             PREINIT:
2218             int status, ret;
2219             UV n;
2220             PPCODE:
2221             /* k is a UV, so always positive. */
2222             /* ix = 0 k = 0 - 3 n below 2 returns 0 for all k
2223             * ix = 1 k = 0 - 256 n below 2 returns 0 for all k
2224             * ix = 2 k = 0 - 2^32 n below 2 returns 0 for all k
2225             */
2226 1066161           status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
2227 1066161           ret = 0;
2228 1066161 100         if (status == 1) {
2229 1066160           switch (ix) {
2230 20 100         case 0: if (items == 1) k = 0;
2231 20           ret = is_perrin_pseudoprime(n, k); break;
2232 49 100         case 1: if (items == 1) k = 1;
2233 49           ret = is_almost_extra_strong_lucas_pseudoprime(n, k); break;
2234 1066091 100         case 2: if (items == 1) k = 10;
2235 1066091           ret = is_delicate_prime(n, k);
2236 1066091 50         if (ret < 0) status = 0; break;
2237 0           default: break;
2238             }
2239             }
2240 1066161 100         if (status != 0) RETURN_NPARITY(ret);
    50          
    50          
2241 1           DISPATCHPP();
2242 1           XSRETURN(1);
2243              
2244             void
2245             is_frobenius_pseudoprime(IN SV* svn, IN IV P = 0, IN IV Q = 0)
2246             PREINIT:
2247             int status;
2248             UV n;
2249             PPCODE:
2250 28           status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
2251 28 50         if (status != 0)
2252 28 50         RETURN_NPARITY((status == 1) ? is_frobenius_pseudoprime(n, P, Q) : 0);
    50          
    50          
2253 0           DISPATCHPP();
2254 0           XSRETURN(1);
2255              
2256             void
2257             miller_rabin_random(IN SV* svn, IN IV bases = 1, IN char* seed = 0)
2258             PREINIT:
2259             int status;
2260             UV n;
2261             dMY_CXT;
2262             PPCODE:
2263 8 100         if (bases < 0) croak("miller_rabin_random: expected positive number of bases");
2264 7           status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
2265 6 50         if (status == -1) RETURN_NPARITY(0);
    0          
    0          
2266 6 50         if (seed == 0 && status == 1)
    100          
2267 4 50         RETURN_NPARITY( is_mr_random(MY_CXT.randcxt, n, bases) );
    50          
2268 2           DISPATCHPP();
2269 2           XSRETURN(1);
2270              
2271             void is_gaussian_prime(IN SV* sva, IN SV* svb)
2272             PREINIT:
2273             UV a, b;
2274             PPCODE:
2275 14           if (_validate_and_set(&a, aTHX_ sva, IFLAG_ABS) &&
2276 7           _validate_and_set(&b, aTHX_ svb, IFLAG_ABS)) {
2277 7 100         if (a == 0) RETURN_NPARITY( ((b % 4) == 3) ? 2*is_prime(b) : 0 );
    100          
    50          
    50          
2278 5 100         if (b == 0) RETURN_NPARITY( ((a % 4) == 3) ? 2*is_prime(a) : 0 );
    100          
    50          
    50          
2279 3 50         if (a < HALF_WORD && b < HALF_WORD) {
    50          
2280 3           UV aa = a*a, bb = b*b;
2281 3 50         if (UV_MAX-aa >= bb)
2282 3 50         RETURN_NPARITY( 2*is_prime(aa+bb) );
    50          
2283             }
2284             }
2285 0           DISPATCHPP();
2286 0           XSRETURN(1);
2287              
2288              
2289             void
2290             gcd(...)
2291             PROTOTYPE: @
2292             ALIAS:
2293             lcm = 1
2294             vecmin = 2
2295             vecmax = 3
2296             vecsum = 4
2297             vecprod = 5
2298             PREINIT:
2299 63070           int i, status = 1;
2300             UV ret, nullv, n;
2301             PPCODE:
2302 63076 100         if (ix == 2 || ix == 3) {
    100          
2303 145           UV retindex = 0;
2304 145           int sign, minmax = (ix == 2);
2305 145 100         if (items == 0) XSRETURN_UNDEF;
2306 143 100         if (items == 1) XSRETURN(1);
2307 81 50         if (items > 1 && (status = _validate_and_set(&ret, aTHX_ ST(0), IFLAG_ANY))) {
    100          
2308 75           sign = status;
2309 248 100         for (i = 1; i < items; i++) {
2310 173           status = _validate_and_set(&n, aTHX_ ST(i), IFLAG_ANY);
2311 173 50         if (status == 0) break;
2312 340 100         if (( (sign == -1 && status == 1) ||
    100          
    100          
2313 167 100         (n >= ret && sign == status)
    100          
2314             ) ? !minmax : minmax ) {
2315 83           sign = status;
2316 83           ret = n;
2317 83           retindex = i;
2318             }
2319             }
2320             }
2321 81 100         if (status != 0) {
2322 75           ST(0) = ST(retindex);
2323 75           XSRETURN(1);
2324             }
2325 62925 100         } else if (ix == 4) {
2326 4706           UV lo = 0;
2327 4706           IV hi = 0;
2328 207394 100         for (ret = i = 0; i < items; i++) {
2329 202706           status = _validate_and_set(&n, aTHX_ ST(i), IFLAG_ANY);
2330 202706 100         if (status == 0) break;
2331 202688 100         if (status == 1) hi += (n > (UV_MAX - lo));
2332 83           else hi -= ((UV_MAX-n) >= lo);
2333 202688           lo += n;
2334             }
2335 4706 100         if (status != 0 && hi != 0) {
    100          
2336 15 100         if (hi == -1 && lo > IV_MAX) XSRETURN_IV((IV)lo);
    100          
2337 7           else RETURN_128(hi, lo);
2338             }
2339 4691           ret = lo;
2340 58219 100         } else if (ix == 5) {
2341 470           int sign = 1;
2342 470           ret = 1;
2343 2800 100         for (i = 0; i < items; i++) {
2344 2660           status = _validate_and_set(&n, aTHX_ ST(i), IFLAG_ANY);
2345 2660 100         if (status == 0) break;
2346 2560 50         if (ret > 0 && n > UV_MAX/ret) { status = 0; break; }
    100          
2347 2330           sign *= status;
2348 2330           ret *= n;
2349             }
2350 470 100         if (sign == -1 && status != 0) {
    100          
2351 2 50         if (ret <= (UV)IV_MAX) XSRETURN_IV(neg_iv(ret));
2352 2           else status = 0;
2353             }
2354             } else {
2355             /* For each arg, while valid input, validate+gcd/lcm. Shortcut stop. */
2356 57749 100         if (ix == 0) { ret = 0; nullv = 1; }
2357 35           else { ret = 1; nullv = 0; }
2358 153946 100         for (i = 0; i < items && ret != nullv && status != 0; i++) {
    100          
    100          
2359 101190           status = _validate_and_set(&n, aTHX_ ST(i), IFLAG_ABS);
2360 101190 100         if (status == 0) break;
2361 96197 100         if (i == 0) {
2362 53267           ret = n;
2363             } else {
2364 42930           UV gcd = gcd_ui(ret, n);
2365 42930 100         if (ix == 0) {
2366 42883           ret = gcd;
2367             } else {
2368 47           n /= gcd;
2369 47 100         if (n <= (UV_MAX / ret) ) ret *= n;
2370 4           else status = 0; /* Overflow */
2371             }
2372             }
2373             }
2374             }
2375 62916 100         if (status != 0)
2376 57563           XSRETURN_UV(ret);
2377             /* For min/max, use string compare if not an object */
2378 5353 100         if ((ix == 2 || ix == 3) && !sv_isobject(ST(0))) {
    100          
    100          
2379 2           int retindex = 0;
2380 2           int minmax = (ix == 2);
2381             STRLEN alen, blen;
2382             char *aptr, *bptr;
2383 2           aptr = SvPV(ST(0), alen);
2384 2           (void) strnum_minmax(minmax, 0, 0, aptr, alen);
2385 4 100         for (i = 1; i < items; i++) {
2386 2           bptr = SvPV(ST(i), blen);
2387 2 50         if (strnum_minmax(minmax, aptr, alen, bptr, blen)) {
2388 2           aptr = bptr;
2389 2           alen = blen;
2390 2           retindex = i;
2391             }
2392             }
2393 2           ST(0) = ST(retindex);
2394 2           XSRETURN(1);
2395             }
2396 5351           DISPATCHPP();
2397 5351 100         if (ix == 0 || ix == 1) objectify_result(aTHX_ 0, ST(0));
    100          
2398 5351           XSRETURN(1);
2399              
2400             void
2401             vecextract(IN SV* x, IN SV* svm)
2402             PREINIT:
2403             AV* av;
2404 2 50         UV mask, i = 0;
2405             PPCODE:
2406 2 50         CHECK_ARRAYREF(x);
    50          
2407 2           av = (AV*) SvRV(x);
2408 3 100         if (SvROK(svm) && SvTYPE(SvRV(svm)) == SVt_PVAV) {
    50          
2409             SSize_t j, index;
2410             DECL_ARREF(mav);
2411 1 50         USE_ARREF(mav, svm, SUBNAME, AR_READ);
    50          
    50          
2412 6 100         for (j = 0; (Size_t)j < len_mav; j++) {
2413 5           SV* v = FETCH_ARREF(mav, j);
2414 5 50         if (_validate_and_set(&mask, aTHX_ v, IFLAG_IV) == 0)
2415 0           croak("vecextract invalid index");
2416 5           index = (SSize_t)mask;
2417 5 50         { SV **v = av_fetch(av, index, 0); if (v) XPUSHs(*v); }
    50          
2418             }
2419 1 50         } else if (_validate_and_set(&mask, aTHX_ svm, IFLAG_POS)) {
2420 25 100         while (mask) {
2421 24 100         if (mask & 1) {
2422 13           SV** v = av_fetch(av, i, 0);
2423 13 50         if (v) XPUSHs(*v);
    50          
2424             }
2425 24           i++;
2426 24           mask >>= 1;
2427             }
2428             } else {
2429 0           DISPATCHPP();
2430 0           return;
2431             }
2432              
2433             void
2434             vecequal(IN SV* a, IN SV* b)
2435             PREINIT:
2436             int res;
2437             PPCODE:
2438 19           res = _compare_array_refs(aTHX_ a, b);
2439 19 100         if (res == -1)
2440 1           croak("vecequal: expected scalar or array reference");
2441 18 50         RETURN_NPARITY(res);
    50          
2442             XSRETURN(1);
2443              
2444             void
2445             vecmex(...)
2446             ALIAS:
2447             vecpmex = 1
2448             PROTOTYPE: @
2449             PREINIT:
2450             char *setv;
2451 154           int i, status = 1;
2452             UV min, n;
2453             uint32_t mask;
2454             PPCODE:
2455 154 100         if (ix == 0) {
2456 8           min = 0;
2457 8           mask = IFLAG_POS;
2458             } else {
2459 146           min = 1;
2460 146           mask = IFLAG_POS | IFLAG_NONZERO;
2461             }
2462 154 100         if (items == 0)
2463 2           XSRETURN_UV(min);
2464 152           Newz(0, setv, items, char);
2465 731 100         for (i = 0; i < items; i++) {
2466 579           status = _validate_and_set(&n, aTHX_ ST(i), mask);
2467             /* Ignore any bigint */
2468 579 100         if (status == 1 && n-min < (UV)items)
    100          
2469 493           setv[n-min] = 1;
2470             }
2471 327 100         for (i = 0; i < items; i++)
2472 321 100         if (setv[i] == 0)
2473 146           break;
2474 152           Safefree(setv);
2475 152           XSRETURN_UV(i+min);
2476              
2477             void
2478             frobenius_number(...)
2479             PROTOTYPE: @
2480             PREINIT:
2481 67           int i, found1 = 0;
2482             UV fn, n, *A;
2483             PPCODE:
2484 67 100         if (items == 0) XSRETURN_UNDEF;
2485 66           Newz(0, A, items, UV);
2486 503 100         for (i = 0; i < items; i++) {
2487 439 50         if (!_validate_and_set(&n, aTHX_ ST(i), IFLAG_POS | IFLAG_NONZERO)) break;
2488 439 100         if (n == 1) { found1 = 1; break; }
2489 437           A[i] = n;
2490             }
2491 66 100         if (i == items) {
2492 64           fn = frobenius_number(A, i);
2493 63           Safefree(A);
2494 63 100         if (fn == 0) XSRETURN_UNDEF;
2495 62 100         if (fn != UV_MAX) XSRETURN_UV(fn);
2496             } else {
2497 2           Safefree(A);
2498 2 50         if (found1) XSRETURN_IV(-1);
2499             }
2500 2           DISPATCHPP();
2501 2           XSRETURN(1);
2502              
2503             void
2504             chinese(...)
2505             ALIAS:
2506             chinese2 = 1
2507             PROTOTYPE: @
2508             PREINIT:
2509             int i, status, astatus, nstatus;
2510             UV ret, lcm, *an;
2511             SV **psva, **psvn;
2512             SV *svfirstmod;
2513             PPCODE:
2514 68           status = 1;
2515 68           New(0, an, 2*items, UV);
2516 68           ret = 0;
2517 68           svfirstmod = 0;
2518 198 100         for (i = 0; i < items; i++) {
2519             AV* av;
2520 140 50         CHECK_ARRAYREF(ST(i));
    50          
2521 140           av = (AV*) SvRV(ST(i));
2522 140 50         if (av_count(av) != 2) croak("%s: expected 2-element array reference",SUBNAME);
2523 140           psva = av_fetch(av, 0, 0);
2524 140           psvn = av_fetch(av, 1, 0);
2525 140 50         if (psva == 0 || psvn == 0) { status = 0; break; }
    50          
2526 140 100         if (i == 0) svfirstmod = *psvn;
2527 140           astatus = _validate_and_set(an+i, aTHX_ *psva, IFLAG_ANY);
2528 140           nstatus = _validate_and_set(an+i+items, aTHX_ *psvn, IFLAG_ABS);
2529 140 50         if (astatus == 0 || nstatus == 0) { status = 0; break; }
    50          
2530 140 100         if (an[i+items] == 0) {
2531 10 50         XPUSHs(&PL_sv_undef);
2532 10 100         if (ix == 1) XPUSHs(&PL_sv_undef);
    50          
2533 10           XSRETURN(1 + ix);
2534             }
2535 130           _mod_with(an+i, astatus, an[i+items]);
2536             }
2537 58 50         if (status)
2538 58           status = chinese(&ret, &lcm, an, an+items, items);
2539 58           Safefree(an);
2540 58 100         if (status) {
2541 46 100         if (ix == 0) {
2542 23 100         if (status < 0) XSRETURN_UNDEF;
2543 21           else XSRETURN_UV(ret);
2544             } else {
2545 23 100         if (status < 0) {
2546 2 50         XPUSHs(&PL_sv_undef);
2547 2 50         XPUSHs(&PL_sv_undef);
2548             } else {
2549 21 50         XPUSHs(sv_2mortal(newSVuv( ret )));
2550 21 50         XPUSHs(sv_2mortal(newSVuv( lcm )));
2551             }
2552 23           XSRETURN(2);
2553             }
2554             }
2555 12           DISPATCHPP();
2556 12 100         if (ix == 0) objectify_result(aTHX_ svfirstmod, ST(0));
2557 12           XSRETURN(1 + ix);
2558              
2559             void cornacchia(IN SV* svd, IN SV* svn)
2560             PREINIT:
2561             UV d, n, x, y;
2562             PPCODE:
2563 30           if (_validate_and_set(&d, aTHX_ svd, IFLAG_POS) &&
2564 15           _validate_and_set(&n, aTHX_ svn, IFLAG_POS) ) {
2565 15 100         if (!cornacchia(&x, &y, d, n)) XSRETURN_UNDEF;
2566 14           PUSHs(sv_2mortal(newSVuv( x )));
2567 14           PUSHs(sv_2mortal(newSVuv( y )));
2568             } else {
2569 0           DISPATCHPP();
2570 0           return; /* Can return undef or two values */
2571             }
2572              
2573             void lucas_sequence(...)
2574             PREINIT:
2575             UV U, V, Qk, n, P, Q, k;
2576             PPCODE:
2577 0 0         if (items != 4) croak("lucas_sequence: n, P, Q, k");
2578 0           if (_validate_and_set(&n, aTHX_ ST(0), IFLAG_POS | IFLAG_NONZERO) &&
2579 0 0         _validate_and_set(&P, aTHX_ ST(1), IFLAG_ANY | IFLAG_IV) &&
2580 0 0         _validate_and_set(&Q, aTHX_ ST(2), IFLAG_ANY | IFLAG_IV) &&
2581 0           _validate_and_set(&k, aTHX_ ST(3), IFLAG_POS)) {
2582 0           lucas_seq(&U, &V, &Qk, n, (IV)P, (IV)Q, k);
2583 0           PUSHs(sv_2mortal(newSVuv( U ))); /* 4 args in, 3 out, no EXTEND needed */
2584 0           PUSHs(sv_2mortal(newSVuv( V )));
2585 0           PUSHs(sv_2mortal(newSVuv( Qk )));
2586             } else {
2587 0           DISPATCHPP();
2588 0 0         OBJECTIFY_STACK(3);
    0          
    0          
    0          
    0          
2589 0           XSRETURN(3);
2590             }
2591              
2592             void lucasuvmod(IN SV* svp, IN SV* svq, IN SV* svk, IN SV* svn)
2593             ALIAS:
2594             lucasumod = 1
2595             lucasvmod = 2
2596             PREINIT:
2597             int pstatus, qstatus;
2598             UV P, Q, k, n, U, V;
2599             PPCODE:
2600 26708           pstatus = _validate_and_set(&P, aTHX_ svp, IFLAG_ANY);
2601 26708           qstatus = _validate_and_set(&Q, aTHX_ svq, IFLAG_ANY);
2602 53407 100         if ((pstatus != 0) && (qstatus != 0) &&
2603 53394 100         _validate_and_set(&k, aTHX_ svk, IFLAG_POS) &&
2604 26695           _validate_and_set(&n, aTHX_ svn, IFLAG_ABS)
2605             ) {
2606 26692 50         if (n == 0) XSRETURN_UNDEF;
2607 26692 100         P = (pstatus == 1) ? P % n : ivmod((IV)P,n);
2608 26692 100         Q = (qstatus == 1) ? Q % n : ivmod((IV)Q,n);
2609 26692           switch (ix) {
2610 505           case 0: lucasuvmod(&U, &V, P, Q, k, n);
2611 505           PUSHs(sv_2mortal(newSVuv( U )));
2612 505           PUSHs(sv_2mortal(newSVuv( V )));
2613 505           break;
2614 26059           case 1: XSRETURN_UV(lucasumod(P, Q, k, n)); break;
2615 128           case 2:
2616 128           default: XSRETURN_UV(lucasvmod(P, Q, k, n)); break;
2617             }
2618             } else {
2619 16           DISPATCHPP();
2620 35 100         OBJECTIFY_STACK(ix==0 ? 2 : 1);
    50          
    100          
    50          
    100          
    50          
2621 16 100         XSRETURN(ix==0 ? 2 : 1);
2622             }
2623              
2624             void lucasuv(IN SV* svp, IN SV* svq, IN SV* svk)
2625             ALIAS:
2626             lucasu = 1
2627             lucasv = 2
2628             PREINIT:
2629             UV k;
2630             IV P, Q, U, V;
2631             PPCODE:
2632 1398           if (_validate_and_set((UV*)&P, aTHX_ svp, IFLAG_IV) &&
2633 1392 50         _validate_and_set((UV*)&Q, aTHX_ svq, IFLAG_IV) &&
2634 1386 100         _validate_and_set(&k, aTHX_ svk, IFLAG_POS) &&
2635 693           lucasuv(&U, &V, P, Q, k)) {
2636 621 100         if (ix == 1) XSRETURN_IV(U); /* U = lucasu(P,Q,k) */
2637 332 100         if (ix == 2) XSRETURN_IV(V); /* V = lucasv(P,Q,k) */
2638 90           PUSHs(sv_2mortal(newSViv( U ))); /* (U,V) = lucasuv(P,Q,k) */
2639 90           PUSHs(sv_2mortal(newSViv( V )));
2640             } else {
2641 78           DISPATCHPP();
2642 182 100         OBJECTIFY_STACK(ix==0 ? 2 : 1);
    50          
    100          
    50          
    100          
    50          
2643 78 100         XSRETURN(ix==0 ? 2 : 1);
2644             }
2645              
2646              
2647             void is_sum_of_squares(IN SV* svn, IN UV k = 2)
2648             PREINIT:
2649             int status, ret;
2650             UV n;
2651             PPCODE:
2652 299           status = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS);
2653 299 100         if (status != 0) {
2654 298           switch (k) {
2655 21           case 0: ret = (n==0); break;
2656 21           case 1: ret = is_power(n,2); break;
2657 116           case 2: ret = is_sum_of_two_squares(n); break;
2658 119           case 3: ret = is_sum_of_three_squares(n); break;
2659 21           default: ret = 1; break;
2660             }
2661 298 50         RETURN_NPARITY(ret);
    50          
2662             }
2663 1           DISPATCHPP();
2664 1           XSRETURN(1);
2665              
2666              
2667             void is_square(IN SV* svn)
2668             ALIAS:
2669             is_carmichael = 1
2670             is_quasi_carmichael = 2
2671             is_perfect_power = 3
2672             is_fundamental = 4
2673             is_lucky = 5
2674             is_practical = 6
2675             is_perfect_number = 7
2676             is_cyclic = 8
2677             is_totient = 9
2678             PREINIT:
2679             int status, ret;
2680             UV n;
2681             PPCODE:
2682 59773           ret = 0;
2683 59773           status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
2684 59773 100         if (status == 1) {
2685 59577           switch (ix) {
2686 18           case 0: ret = is_power(n,2); break;
2687 20006           case 1: ret = is_carmichael(n); break;
2688 5402           case 2: ret = is_quasi_carmichael(n); break;
2689 113           case 3: ret = is_perfect_power(n); break;
2690 52           case 4: ret = is_fundamental(n,0); break;
2691 218           case 5: ret = is_lucky(n); break;
2692 297           case 6: ret = is_practical(n); break;
2693 517           case 7: ret = is_perfect_number(n); break;
2694 32829           case 8: ret = is_cyclic(n); break;
2695 125           case 9:
2696 125           default:ret = is_totient(n); break;
2697             }
2698 196 100         } else if (status == -1) {
2699 184           switch (ix) {
2700 100           case 3: ret = is_perfect_power_neg(neg_iv(n)); break;
2701 50           case 4: ret = is_fundamental(neg_iv(n),1); break;
2702 34           default:break;
2703             }
2704             }
2705 59773 100         if (status != 0) RETURN_NPARITY(ret);
    50          
    50          
2706 12           DISPATCHPP();
2707 12           XSRETURN(1);
2708              
2709             void squarefree_kernel(IN SV* svn)
2710             PREINIT:
2711             int status;
2712             UV n;
2713             PPCODE:
2714 9           status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
2715 9 100         if (status == -1)
2716 1           XSRETURN_IV( neg_iv(squarefree_kernel(neg_iv(n))) );
2717 8 50         if (status == 1)
2718 8           XSRETURN_UV( squarefree_kernel(n) );
2719 0           DISPATCHPP();
2720 0           XSRETURN(1);
2721              
2722             void is_powerfree(IN SV* svn, IN int k = 2)
2723             ALIAS:
2724             powerfree_sum = 1
2725             powerfree_part = 2
2726             powerfree_part_sum = 3
2727             PREINIT:
2728             int status;
2729             UV n, res;
2730             PPCODE:
2731 116937           status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
2732 116937 100         if (status == -1) {
2733 98           n = neg_iv(n);
2734 98 100         if (ix == 2)
2735 2           XSRETURN_IV( neg_iv(powerfree_part(n,k)) );
2736             }
2737 116935 100         if (status != 0) {
2738 116927           switch (ix) {
2739 111277           case 0: res = is_powerfree(n,k); break;
2740 1115           case 1: res = powerfree_sum(n,k); break;
2741 4263           case 2: res = powerfree_part(n,k); break;
2742 272           case 3:
2743 272           default: res = powerfree_part_sum(n,k); break;
2744             }
2745 116927 100         if (ix == 0)
2746 111277 50         RETURN_NPARITY(res);
    50          
2747 5650 100         if (res != 0 || n == 0)
    100          
2748 4658           XSRETURN_UV(res);
2749             /* res is 0 and n > 0, so we overflowed. Fall through to PP. */
2750             }
2751 1000           DISPATCHPP();
2752 1000           XSRETURN(1);
2753              
2754             void powerfree_count(IN SV* svn, IN int k = 2)
2755             ALIAS:
2756             nth_powerfree = 1
2757             PREINIT:
2758             int status;
2759             UV n, res;
2760             PPCODE:
2761 1122           status = _validate_and_set(&n, aTHX_ svn, (ix==0) ? IFLAG_ANY : IFLAG_POS);
2762 1122 50         if (status != 0) {
2763 1122 50         if (status == -1)
2764 0           XSRETURN_UV(0);
2765 1122 100         if (ix == 0) {
2766 1115           res = powerfree_count(n,k);
2767 1115           XSRETURN_UV(res);
2768             } else {
2769 7 50         if (n == 0 || k < 2)
    50          
2770 0           XSRETURN_UNDEF;
2771 7           res = nth_powerfree(n,k);
2772 7 50         if (res != 0)
2773 7           XSRETURN_UV(res);
2774             /* if res = 0, overflow */
2775             }
2776             }
2777 0           DISPATCHPP();
2778 0           objectify_result(aTHX_ svn, ST(0));
2779 0           XSRETURN(1);
2780              
2781             void
2782             is_power(IN SV* svn, IN UV k = 0, IN SV* svroot = 0)
2783             PREINIT:
2784             int status, ret;
2785             UV n;
2786             uint32_t root;
2787             PPCODE:
2788 10789           status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
2789 10789 100         if (status != 0) {
2790 10500 100         if (k != 0) {
2791 61 100         if (status == -1) {
2792 14 100         if (k % 2 == 0) RETURN_NPARITY(0); /* negative n even k return 0 */
    50          
    50          
2793 12           n = neg_iv(n);
2794             }
2795 59           ret = is_power_ret(n, k, &root);
2796             } else { /* k = 0 */
2797 10439 100         if (status == -1)
2798 61           n = neg_iv(n);
2799             /* Following Pari/GP: ispower(0) = ispower(1) = ispower(-1) = 0 */
2800 10439 100         ret = (n <= 1) ? 0 : powerof_ret(n, &root);
2801 10439 100         if (status == -1 && ret > 0 && ret % 2 == 0) {
    100          
    100          
2802 27           uint32_t v = valuation(ret,2);
2803 27           ret >>= v;
2804 27 100         if (ret == 1) ret = 0;
2805 27 100         if (ret) root = ipow(root,1U << v);
2806             }
2807             }
2808 10498 100         if (ret && svroot != 0) {
    100          
2809 29 50         if (!SvROK(svroot)) croak("is_power: third argument not a scalar reference");
2810 29 100         SETSVINT(SvRV(svroot), status == 1, root, -(IV)root);
2811             }
2812 10498 50         RETURN_NPARITY(ret);
    50          
2813             }
2814 289           DISPATCHPP_GMPONLYIF(svroot == 0);
2815 289           XSRETURN(1);
2816              
2817             void
2818             is_prime_power(IN SV* svn, IN SV* svroot = 0)
2819             PREINIT:
2820             int status, ret;
2821             UV n, root;
2822             PPCODE:
2823 10559           status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
2824 10559 100         if (status != 0) {
2825 10549 50         ret = (status == 1) ? prime_power(n, &root) : 0;
2826 10549 100         if (ret && svroot != 0) {
    100          
2827 14 50         if (!SvROK(svroot))croak("is_prime_power: second argument not a scalar reference");
2828 14           sv_setuv(SvRV(svroot), root);
2829             }
2830 10549 50         RETURN_NPARITY(ret);
    50          
2831             }
2832 10           DISPATCHPP_GMPONLYIF(svroot == 0);
2833 10           XSRETURN(1);
2834              
2835             void
2836             is_polygonal(IN SV* svn, IN UV k, IN SV* svroot = 0)
2837             PREINIT:
2838             UV n;
2839             int status;
2840             PPCODE:
2841 25305 100         if (svroot != 0 && !SvROK(svroot))
    50          
2842 0           croak("is_polygonal: third argument not a scalar reference");
2843 25305 50         if (k < 3)
2844 0           croak("is_polygonal: k must be >= 3");
2845              
2846 25305           status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
2847 25305 100         if (status == -1)
2848 1 50         RETURN_NPARITY(0);
    50          
2849 25304 100         if (status == 1) {
2850 25302           bool overflow = 0;
2851 25302           UV root = polygonal_root(n, k, &overflow);
2852 25302 100         UV result = (n == 0) || root;
    100          
2853 25302 50         if (!overflow) {
2854 25302 100         if (result && svroot != 0)
    100          
2855 232           sv_setuv(SvRV(svroot), root);
2856 25302 50         RETURN_NPARITY(result);
    50          
2857             }
2858             }
2859 2           DISPATCHPP_GMPONLYIF(svroot == 0);
2860 2           XSRETURN(1);
2861              
2862              
2863             void inverse_li(IN SV* svn)
2864             PREINIT:
2865             UV n;
2866             PPCODE:
2867 53 50         if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) {
2868 53 50         if (n < MPU_MAX_PRIME_IDX) /* Fall through to Perl if out of range. */
2869 53           XSRETURN_UV(inverse_li(n));
2870             }
2871 0           DISPATCHPP();
2872 0           XSRETURN(1);
2873              
2874             NV inverse_li_nv(IN NV x)
2875             CODE:
2876 4 50         RETVAL = ld_inverse_li(x);
2877             OUTPUT:
2878             RETVAL
2879              
2880             void nth_prime(IN SV* svn)
2881             ALIAS:
2882             nth_prime_upper = 1
2883             nth_prime_lower = 2
2884             nth_prime_approx = 3
2885             PREINIT:
2886             UV n, ret;
2887             PPCODE:
2888 256 50         if ( _validate_and_set(&n, aTHX_ svn, IFLAG_POS) &&
2889 256 100         n <= MPU_MAX_PRIME_IDX ) {
2890 255 100         if (n == 0) XSRETURN_UNDEF;
2891 253           switch (ix) {
2892 173           case 0: ret = nth_prime(n); break;
2893 28           case 1: ret = nth_prime_upper(n); break;
2894 27           case 2: ret = nth_prime_lower(n); break;
2895 25           case 3:
2896 25           default: ret = nth_prime_approx(n); break;
2897             }
2898 253           XSRETURN_UV(ret);
2899             }
2900 1           DISPATCHPP();
2901 1           XSRETURN(1);
2902              
2903             void nth_prime_power(IN SV* svn)
2904             ALIAS:
2905             nth_prime_power_upper = 1
2906             nth_prime_power_lower = 2
2907             nth_prime_power_approx = 3
2908             PREINIT:
2909             UV n, ret;
2910             PPCODE:
2911 193 50         if ( _validate_and_set(&n, aTHX_ svn, IFLAG_POS) &&
2912 193 50         n <= MPU_MAX_PRIME_IDX ) {
2913 193 100         if (n == 0) XSRETURN_UNDEF;
2914 189           switch (ix) {
2915 69           case 0: ret = nth_prime_power(n); break;
2916 40           case 1: ret = nth_prime_power_upper(n); break;
2917 40           case 2: ret = nth_prime_power_lower(n); break;
2918 40           case 3:
2919 40           default: ret = nth_prime_power_approx(n); break;
2920             }
2921 189           XSRETURN_UV(ret);
2922             }
2923 0           DISPATCHPP();
2924 0           XSRETURN(1);
2925              
2926             void nth_perfect_power(IN SV* svn)
2927             ALIAS:
2928             nth_perfect_power_upper = 1
2929             nth_perfect_power_lower = 2
2930             nth_perfect_power_approx = 3
2931             PREINIT:
2932             UV n, ret;
2933             PPCODE:
2934 181 50         if ( _validate_and_set(&n, aTHX_ svn, IFLAG_POS) &&
2935 181 100         n <= MPU_MAX_PERFECT_POW_IDX ) {
2936 180 50         if (n == 0) XSRETURN_UNDEF;
2937 180           switch (ix) {
2938 63           case 0: ret = nth_perfect_power(n); break;
2939 57           case 1: ret = nth_perfect_power_upper(n); break;
2940 57           case 2: ret = nth_perfect_power_lower(n); break;
2941 3           case 3:
2942 3           default: ret = nth_perfect_power_approx(n); break;
2943             }
2944 180           XSRETURN_UV(ret);
2945             }
2946 1           DISPATCHPP();
2947 1           objectify_result(aTHX_ svn, ST(0));
2948 1           XSRETURN(1);
2949              
2950             void nth_ramanujan_prime(IN SV* svn)
2951             ALIAS:
2952             nth_ramanujan_prime_upper = 1
2953             nth_ramanujan_prime_lower = 2
2954             nth_ramanujan_prime_approx = 3
2955             PREINIT:
2956             UV n, ret;
2957             PPCODE:
2958 225 50         if ( _validate_and_set(&n, aTHX_ svn, IFLAG_POS) &&
2959 225 50         n <= MPU_MAX_RMJN_PRIME_IDX ) {
2960 225 50         if (n == 0) XSRETURN_UNDEF;
2961 225           switch (ix) {
2962 75           case 0: ret = nth_ramanujan_prime(n); break;
2963 74           case 1: ret = nth_ramanujan_prime_upper(n); break;
2964 74           case 2: ret = nth_ramanujan_prime_lower(n); break;
2965 2           case 3:
2966 2           default: ret = nth_ramanujan_prime_approx(n); break;
2967             }
2968 225           XSRETURN_UV(ret);
2969             }
2970 0           DISPATCHPP();
2971 0           XSRETURN(1);
2972              
2973             void nth_twin_prime(IN SV* svn)
2974             ALIAS:
2975             nth_twin_prime_approx = 1
2976             PREINIT:
2977             UV n, ret;
2978             PPCODE:
2979 63 50         if ( _validate_and_set(&n, aTHX_ svn, IFLAG_POS) &&
2980 63 50         n <= MPU_MAX_TWIN_PRIME_IDX ) {
2981 63 100         if (n == 0) XSRETURN_UNDEF;
2982 62 100         switch (ix) {
2983 53           case 0: ret = nth_twin_prime(n); break;
2984 9           case 1:
2985 9           default: ret = nth_twin_prime_approx(n); break;
2986             }
2987 62           XSRETURN_UV(ret);
2988             }
2989 0           DISPATCHPP();
2990 0           XSRETURN(1);
2991              
2992             void nth_semiprime(IN SV* svn)
2993             ALIAS:
2994             nth_semiprime_approx = 1
2995             PREINIT:
2996             UV n, ret;
2997             PPCODE:
2998 2677 50         if ( _validate_and_set(&n, aTHX_ svn, IFLAG_POS) &&
2999 2677 50         n <= MPU_MAX_SEMI_PRIME_IDX ) {
3000 2677 100         if (n == 0) XSRETURN_UNDEF;
3001 2676 100         switch (ix) {
3002 2672           case 0: ret = nth_semiprime(n); break;
3003 4           case 1:
3004 4           default: ret = nth_semiprime_approx(n); break;
3005             }
3006 2676           XSRETURN_UV(ret);
3007             }
3008 0           DISPATCHPP();
3009 0           XSRETURN(1);
3010              
3011             void nth_lucky(IN SV* svn)
3012             ALIAS:
3013             nth_lucky_upper = 1
3014             nth_lucky_lower = 2
3015             nth_lucky_approx = 3
3016             PREINIT:
3017             UV n, ret;
3018             PPCODE:
3019 516 50         if ( _validate_and_set(&n, aTHX_ svn, IFLAG_POS) &&
3020 516 50         n <= MPU_MAX_LUCKY_IDX ) {
3021 516 100         if (n == 0) XSRETURN_UNDEF;
3022 512           switch (ix) {
3023 164           case 0: ret = nth_lucky(n); break;
3024 116           case 1: ret = nth_lucky_upper(n); break;
3025 116           case 2: ret = nth_lucky_lower(n); break;
3026 116           case 3:
3027 116           default: ret = nth_lucky_approx(n); break;
3028             }
3029 512           XSRETURN_UV(ret);
3030             }
3031 0           DISPATCHPP();
3032 0           XSRETURN(1);
3033              
3034              
3035             void next_prime(IN SV* svn)
3036             ALIAS:
3037             prev_prime = 1
3038             PREINIT:
3039             UV n, ret;
3040             PPCODE:
3041 12522 100         if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)
3042 12484 100         && !(ix == 0 && n >= MPU_MAX_PRIME)) {
    100          
3043 12480           ret = 0;
3044 12480           switch (ix) {
3045 8731           case 0: ret = next_prime(n); break;
3046 3749           case 1: ret = prev_prime(n); break;
3047 0           default: break;
3048             }
3049 12480 100         if (ret == 0) XSRETURN_UNDEF;
3050 12475           XSRETURN_UV(ret);
3051             }
3052 22           DISPATCHPP();
3053 21           objectify_result(aTHX_ svn, ST(0));
3054 21           XSRETURN(1);
3055              
3056             void next_prime_power(IN SV* svn)
3057             ALIAS:
3058             prev_prime_power = 1
3059             PREINIT:
3060             UV n, ret;
3061             PPCODE:
3062 110 50         if (_validate_and_set(&n, aTHX_ svn, IFLAG_ABS)
3063 110 100         && !(ix == 0 && n >= MPU_MAX_PRIME)) {
    50          
3064 110           ret = 0;
3065 110           switch (ix) {
3066 54           case 0: ret = next_prime_power(n); break;
3067 56           case 1: ret = prev_prime_power(n); break;
3068 0           default: break;
3069             }
3070 110 100         if (ret == 0) XSRETURN_UNDEF;
3071 106           XSRETURN_UV(ret);
3072             }
3073 0           DISPATCHPP();
3074 0           XSRETURN(1);
3075              
3076             void next_perfect_power(IN SV* svn)
3077             PREINIT:
3078             UV n;
3079             int status;
3080             PPCODE:
3081 67           status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
3082 67 100         if (status == 1) {
3083 49           n = next_perfect_power(n);
3084 49 100         if (n != 0) XSRETURN_UV(n);
3085 18 100         } else if (status == -1) { /* next perfect power: negative n */
3086 17           n = next_perfect_power_neg(neg_iv(n));
3087 17           XSRETURN_IV(neg_iv(n));
3088             }
3089 2           DISPATCHPP();
3090 2           objectify_result(aTHX_ svn, ST(0));
3091 2           XSRETURN(1);
3092              
3093             void prev_perfect_power(IN SV* svn)
3094             PREINIT:
3095             UV n;
3096             int status;
3097             PPCODE:
3098 72           status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
3099 72 100         if (status == 1) {
3100 48 100         if (n == 0) XSRETURN_IV(-1);
3101 45           n = prev_perfect_power(n);
3102 45           XSRETURN_UV(n);
3103 24 100         } else if (status == -1) { /* prev perfect power: negative n */
3104 17           n = prev_perfect_power_neg(neg_iv(n));
3105 17 50         if (n > 0 && n <= (UV)IV_MAX)
    100          
3106 16           XSRETURN_IV(neg_iv(n));
3107             }
3108 8           DISPATCHPP();
3109 8           objectify_result(aTHX_ svn, ST(0));
3110 8           XSRETURN(1);
3111              
3112             void next_chen_prime(IN SV* svn)
3113             PREINIT:
3114             UV n, ret;
3115             PPCODE:
3116 36 50         if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) {
3117 36           ret = next_chen_prime(n);
3118 36 50         if (ret != 0) XSRETURN_UV(ret);
3119             }
3120 0           DISPATCHPP();
3121 0           XSRETURN(1);
3122              
3123             void urandomb(IN UV bits)
3124             ALIAS:
3125             random_ndigit_prime = 1
3126             random_semiprime = 2
3127             random_unrestricted_semiprime = 3
3128             random_safe_prime = 4
3129             random_nbit_prime = 5
3130             random_shawe_taylor_prime = 6
3131             random_maurer_prime = 7
3132             random_proven_prime = 8
3133             random_strong_prime = 9
3134             PREINIT:
3135             UV res, minarg;
3136             dMY_CXT;
3137             void* cs;
3138             PPCODE:
3139 961           switch (ix) {
3140 17           case 1: minarg = 1; break;
3141 11           case 2: minarg = 4; break;
3142 10           case 3: minarg = 3; break;
3143 7           case 4: minarg = 3; break;
3144 70           case 5:
3145             case 6:
3146             case 7:
3147 70           case 8: minarg = 2; break;
3148 2           case 9: minarg = 128; break;
3149 844           default: minarg = 0; break;
3150             }
3151 961 100         if (minarg > 0 && bits < minarg)
    100          
3152 8           croak("%s: input '%d' must be >= %d", SUBNAME, (int)bits, (int)minarg);
3153 953           cs = MY_CXT.randcxt;
3154 953 100         if (bits <= BITS_PER_WORD) {
3155 920           switch (ix) {
3156 820           case 0: res = urandomb(cs,bits); break;
3157 16           case 1: res = random_ndigit_prime(cs,bits); break;
3158 9           case 2: res = random_semiprime(cs,bits); break;
3159 8           case 3: res = random_unrestricted_semiprime(cs,bits); break;
3160 4           case 4: res = random_safe_prime(cs,bits); break;
3161 63           case 5:
3162             case 6:
3163             case 7:
3164             case 8:
3165             case 9:
3166 63           default: res = random_nbit_prime(cs,bits); break;
3167             }
3168 920 100         if (res || ix == 0) XSRETURN_UV(res);
    100          
3169             }
3170 36 100         DISPATCHPP_GMPONLYIF(ix != 1 || bits != uvmax_maxlen);
    100          
3171 36           objectify_result(aTHX_ 0, ST(0));
3172 36           XSRETURN(1);
3173              
3174             void urandomm(IN SV* svn)
3175             PREINIT:
3176             UV n, ret;
3177             PPCODE:
3178 328 100         if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) {
3179             dMY_CXT;
3180 305           ret = urandomm64(MY_CXT.randcxt, n);
3181 305           XSRETURN_UV(ret);
3182             }
3183 23           DISPATCHPP();
3184 23           objectify_result(aTHX_ svn, ST(0));
3185 23           XSRETURN(1);
3186              
3187             void pisano_period(IN SV* svn)
3188             ALIAS:
3189             partitions = 1
3190             consecutive_integer_lcm = 2
3191             PREINIT:
3192 348           UV n, r = 0;
3193             PPCODE:
3194 348 100         if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) {
3195 346           switch (ix) {
3196 187           case 0: r = pisano_period(n); break;
3197 57           case 1: r = npartitions(n); break;
3198 102           case 2: r = consecutive_integer_lcm(n); break;
3199 0           default: break;
3200             }
3201             /* Returns 0 if n=0 or result overflows */
3202 346 100         if (r != 0 || n == 0)
    100          
3203 286           XSRETURN_UV(r);
3204             }
3205 62           DISPATCHPP();
3206 62           objectify_result(aTHX_ svn, ST(0));
3207 62           XSRETURN(1);
3208              
3209             void random_factored_integer(IN SV* svn)
3210             PREINIT:
3211             UV n;
3212             PPCODE:
3213 1 50         if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS | IFLAG_NONZERO)) {
3214             dMY_CXT;
3215             int f, nf, flip;
3216             UV r, F[MPU_MAX_FACTORS+1];
3217 1           AV* av = newAV();
3218 1           r = random_factored_integer(MY_CXT.randcxt, n, &nf, F);
3219 1           flip = (F[0] >= F[nf-1]); /* Handle results in either sort order */
3220 4 100         for (f = 0; f < nf; f++)
3221 3 50         av_push(av, newSVuv(F[flip ? nf-1-f : f]));
3222 1 50         XPUSHs(sv_2mortal(newSVuv( r )));
3223 1 50         XPUSHs(sv_2mortal(newRV_noinc( (SV*) av )));
3224             } else {
3225 0           DISPATCHPP();
3226 0           XSRETURN(1);
3227             }
3228              
3229              
3230              
3231             void contfrac(IN SV* svnum, IN SV* svden)
3232             PREINIT:
3233             UV num, den;
3234             int nstatus;
3235             PPCODE:
3236 53           nstatus = _validate_and_set(&num, aTHX_ svnum, IFLAG_ANY);
3237             /* TODO: handle negative numerator */
3238 91 100         if (nstatus == 1 && _validate_and_set(&den, aTHX_ svden, IFLAG_POS | IFLAG_NONZERO)) {
    50          
3239             UV *cf, rem;
3240 38           int i, steps = contfrac(&cf, &rem, num, den);
3241 38 50         EXTEND(SP, (EXTEND_TYPE)steps);
    50          
3242 318 100         for (i = 0; i < steps; i++)
3243 280           PUSHs(sv_2mortal(newSVuv( cf[i] )));
3244 38           Safefree(cf);
3245             } else {
3246 15           DISPATCHPP();
3247 15           return;
3248             }
3249              
3250             void from_contfrac(...)
3251             PROTOTYPE: @
3252             PREINIT:
3253             size_t i;
3254             UV n, cfA0, cfA1, cfB0, cfB1, cfAn, cfBn;
3255             int nstatus, overflow;
3256             PPCODE:
3257 53           nstatus = 1;
3258 53           overflow = 0;
3259 53           cfA0 = 1; cfA1 = 0;
3260 53           cfB0 = 0; cfB1 = 1;
3261 53 100         if (items > 0) {
3262 52           nstatus = _validate_and_set(&n, aTHX_ ST(0), IFLAG_ANY);
3263             /* TODO: handle negative n */
3264 52           cfA1 = n;
3265 446 100         for (i = 1; nstatus == 1 && i < (size_t) items; i++) {
    100          
3266 398 100         if (!_validate_and_set(&n, aTHX_ ST(i), IFLAG_POS | IFLAG_NONZERO))
3267 1           break;
3268             /* check each step for overflow */
3269 397 100         overflow = (UV_MAX/n < cfA1) || (UV_MAX/n < cfB1);
    100          
3270 397 100         if (overflow) break;
3271 395           cfAn = n * cfA1;
3272 395           cfBn = n * cfB1;
3273 395 50         overflow = (UV_MAX-cfAn < cfA0) || (UV_MAX-cfBn < cfB0);
    100          
3274 395 100         if (overflow) break;
3275 394           cfAn = cfAn + cfA0;
3276 394           cfBn = cfBn + cfB0;
3277 394           cfA0 = cfA1; cfA1 = cfAn;
3278 394           cfB0 = cfB1; cfB1 = cfBn;
3279             }
3280 52 100         if (i < (size_t) items) /* Covers overflow */
3281 13           nstatus = 0;
3282             }
3283 53 100         if (nstatus == 1) {
3284 36 50         XPUSHs(sv_2mortal(newSVuv( cfA1 )));
3285 36 50         XPUSHs(sv_2mortal(newSVuv( cfB1 )));
3286             } else {
3287 17           DISPATCHPP();
3288             }
3289 53           XSRETURN(2);
3290              
3291             void next_calkin_wilf(IN SV* svnum, IN SV* svden)
3292             ALIAS:
3293             next_stern_brocot = 1
3294             PREINIT:
3295             UV num, den;
3296             int status;
3297             PPCODE:
3298 198 50         if (_validate_and_set(&num, aTHX_ svnum, IFLAG_POS | IFLAG_NONZERO) && _validate_and_set(&den, aTHX_ svden, IFLAG_POS | IFLAG_NONZERO)) {
    50          
3299 198           switch (ix) {
3300 99           case 0: status = next_calkin_wilf(&num, &den); break;
3301 99           case 1: status = next_stern_brocot(&num, &den); break;
3302 0           default: status = 0; break;
3303             }
3304 198 50         if (status) {
3305 198 50         XPUSHs(sv_2mortal(newSVuv( num )));
3306 198 50         XPUSHs(sv_2mortal(newSVuv( den )));
3307 198           XSRETURN(2);
3308             }
3309             }
3310 0           DISPATCHPP();
3311 0           XSRETURN(2);
3312              
3313             void calkin_wilf_n(IN SV* svnum, IN SV* svden)
3314             ALIAS:
3315             stern_brocot_n = 1
3316             PREINIT:
3317             UV num, den, n;
3318             PPCODE:
3319 220 50         if (_validate_and_set(&num, aTHX_ svnum, IFLAG_POS | IFLAG_NONZERO) && _validate_and_set(&den, aTHX_ svden, IFLAG_POS | IFLAG_NONZERO)) {
    50          
3320 220           switch (ix) {
3321 110           case 0: n = calkin_wilf_n(num, den); break;
3322 110           case 1: n = stern_brocot_n(num, den); break;
3323 0           default: n = 0; break;
3324             }
3325 220 100         if (n) XSRETURN_UV(n);
3326             }
3327 6           DISPATCHPP();
3328 6           XSRETURN(1);
3329              
3330             void nth_calkin_wilf(IN SV* svn)
3331             ALIAS:
3332             nth_stern_brocot = 1
3333             PREINIT:
3334             UV n, num, den;
3335             int status;
3336             PPCODE:
3337 220 100         if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS | IFLAG_NONZERO)) {
3338 214           switch (ix) {
3339 107           case 0: status = nth_calkin_wilf(&num, &den, n); break;
3340 107           case 1: status = nth_stern_brocot(&num, &den, n); break;
3341 0           default: status = 0; break;
3342             }
3343 214 50         if (status) {
3344 214 50         XPUSHs(sv_2mortal(newSVuv( num )));
3345 214 50         XPUSHs(sv_2mortal(newSVuv( den )));
3346 214           XSRETURN(2);
3347             }
3348             }
3349 6           DISPATCHPP();
3350 6           XSRETURN(2);
3351              
3352             void nth_stern_diatomic(IN SV* svn)
3353             PREINIT:
3354             UV n;
3355             PPCODE:
3356 340 50         if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS))
3357 340           XSRETURN_UV(nth_stern_diatomic(n));
3358 0           DISPATCHPP();
3359 0           XSRETURN(1);
3360              
3361             void farey(IN SV* svn, IN SV* svk = 0)
3362             PREINIT:
3363             UV n, k;
3364             int wantsingle, kresult;
3365             PPCODE:
3366 151           wantsingle = svk != 0;
3367 151 100         if (wantsingle) {
3368 128 50         if (!_validate_and_set(&k, aTHX_ svk, IFLAG_POS))
3369 0           k = UV_MAX;
3370             }
3371 151 50         if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS | IFLAG_NONZERO)) {
3372 151 100         if (!wantsingle && GIMME_V != G_ARRAY)
    100          
3373 13           XSRETURN_UV(farey_length(n));
3374 138 50         if (n <= UVCONST(4294967295)) {
3375 138 100         if (wantsingle) {
3376             uint32_t p, q;
3377 128           kresult = kth_farey(n, k, &p, &q);
3378 247 100         if (kresult == 0) XSRETURN_UNDEF;
3379 119 50         if (kresult == 1) {
3380 119           PUSH_2ELEM_AREF(p, q);
3381 119           XSRETURN(1);
3382             }
3383             } else {
3384             uint32_t *num, *den;
3385 10           UV i, len = farey_array(n, &num, &den);
3386 10 50         if (len > 0) {
3387 10 50         EXTEND(SP, (EXTEND_TYPE)len);
    50          
3388 124 100         for (i = 0; i < len; i++)
3389 114           PUSH_2ELEM_AREF(num[i], den[i]);
3390 10           Safefree(num);
3391 10           Safefree(den);
3392 10           XSRETURN(len);
3393             }
3394             }
3395             }
3396             }
3397 0           DISPATCHPP();
3398 0           return;
3399              
3400             void next_farey(IN SV* svn, IN SV* svfrac)
3401             ALIAS:
3402             farey_rank = 1
3403             PREINIT:
3404             SV **psvp, **psvq;
3405             AV* av;
3406             UV n, p64, q64;
3407             uint32_t p, q;
3408             int status;
3409             PPCODE:
3410 1009 50         if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS | IFLAG_NONZERO) &&
3411 1009 50         n <= UVCONST(4294967295)) {
3412 1009 50         CHECK_ARRAYREF(svfrac);
    50          
3413 1009           av = (AV*) SvRV(svfrac);
3414 1009 50         if (av_count(av) != 2) croak("%s: expected 2-element array reference", SUBNAME);
3415 1009           psvp = av_fetch(av, 0, 0);
3416 1009           psvq = av_fetch(av, 1, 0);
3417 1009           status = 1;
3418 1009 50         if (psvp == 0 || psvq == 0)
    50          
3419 0           status = 0;
3420 1009 50         if (status != 0)
3421 1009           status = _validate_and_set(&p64, aTHX_ *psvp, IFLAG_POS);
3422 1009 50         if (status != 0)
3423 1009           status = _validate_and_set(&q64, aTHX_ *psvq, IFLAG_POS | IFLAG_NONZERO);
3424 1009 50         if (status != 0 && p64 >= q64) {
    100          
3425 22 100         if (ix == 0) XSRETURN_UNDEF;
3426 11           else XSRETURN_UV(farey_length(n) - (p64 == q64));
3427             }
3428 987 50         if (status != 0) {
3429 987           p = p64; q = q64;
3430 987 50         if (p != p64 || q != q64)
    50          
3431 0           status = 0; /* We only do 32-bit here */
3432             }
3433 987 50         if (status != 0) {
3434 987 100         if (ix == 1)
3435 110           XSRETURN_UV(farey_rank(n, p, q));
3436             else {
3437 877 50         if (next_farey(n, &p, &q)) {
3438 877           PUSH_2ELEM_AREF(p, q);
3439 877           XSRETURN(1);
3440             }
3441             /* Possibly drop through */
3442             }
3443             }
3444             }
3445 0           DISPATCHPP();
3446 0           XSRETURN(1);
3447              
3448              
3449              
3450             void Pi(IN UV digits = 0)
3451             PREINIT:
3452             #ifdef USE_QUADMATH
3453             const UV mantsize = FLT128_DIG;
3454             const NV pival = 3.141592653589793238462643383279502884197169Q;
3455             #elif defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE)
3456             const UV mantsize = LDBL_DIG;
3457             const NV pival = 3.141592653589793238462643383279502884197169L;
3458             #else
3459 1001           const UV mantsize = DBL_DIG;
3460 1001 50         const NV pival = 3.141592653589793238462643383279502884197169;
3461             #endif
3462             PPCODE:
3463 1001 100         if (digits == 0) {
3464 1           XSRETURN_NV( pival );
3465 1000 100         } else if (digits <= mantsize) {
3466 15           char* out = pidigits(digits);
3467 15           NV pi = STRTONV(out);
3468 15           Safefree(out);
3469 15           XSRETURN_NV( pi );
3470             } else {
3471 985           DISPATCHPP();
3472 985           XSRETURN(1);
3473             }
3474              
3475             void bernfrac(IN SV* svn)
3476             ALIAS:
3477             harmfrac = 1
3478             PREINIT:
3479             UV n;
3480             PPCODE:
3481 114 50         if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS) != 0) {
3482 114 100         if (ix == 0) {
3483             IV num; UV den;
3484 60 100         if (bernfrac(&num, &den, n)) {
3485 41 50         XPUSHs(sv_2mortal(newSViv( num )));
3486 41 50         XPUSHs(sv_2mortal(newSVuv( den )));
3487 41           XSRETURN(2);
3488             }
3489             } else {
3490             UV num, den;
3491 54 100         if (harmfrac(&num, &den, n)) {
3492 52 50         XPUSHs(sv_2mortal(newSVuv( num )));
3493 52 50         XPUSHs(sv_2mortal(newSVuv( den )));
3494 52           XSRETURN(2);
3495             }
3496             }
3497             }
3498 21           DISPATCHPP();
3499 63 50         OBJECTIFY_STACK(2);
    100          
    50          
    100          
    50          
3500 21           XSRETURN(2);
3501              
3502             void
3503             _pidigits(IN int digits)
3504             PREINIT:
3505             char* out;
3506             PPCODE:
3507 972 50         if (digits <= 0) XSRETURN_EMPTY;
3508 972           out = pidigits(digits);
3509 972 50         XPUSHs(sv_2mortal(newSVpvn(out, digits+1)));
3510 972           Safefree(out);
3511              
3512             void inverse_totient(IN SV* svn)
3513             PREINIT:
3514             U32 gimme_v;
3515             int status;
3516             UV i, n, ntotients;
3517             PPCODE:
3518 114           gimme_v = GIMME_V;
3519 114           status = _validate_and_set(&n, aTHX_ svn, IFLAG_POS);
3520 114 50         if (status == 1) {
3521 114 100         if (gimme_v == G_SCALAR) {
3522 104           XSRETURN_UV( inverse_totient_count(n) );
3523 10 50         } else if (gimme_v == G_ARRAY) {
3524 10           UV* tots = inverse_totient_list(&ntotients, n);
3525 10 50         if (ntotients != UV_MAX) {
3526 10 50         EXTEND(SP, (EXTEND_TYPE)ntotients);
    50          
3527 55 100         for (i = 0; i < ntotients; i++)
3528 45           PUSHs(sv_2mortal(newSVuv( tots[i] )));
3529 10           Safefree(tots);
3530 10           XSRETURN(ntotients);
3531             }
3532             }
3533             }
3534 0           DISPATCHPP();
3535 0           return;
3536              
3537             void
3538             factor(IN SV* svn)
3539             ALIAS:
3540             factor_exp = 1
3541             PREINIT:
3542             UV n;
3543             uint32_t i;
3544             U32 gimme_v;
3545             int status;
3546             PPCODE:
3547 1749           gimme_v = GIMME_V;
3548 1749           status = _validate_and_set(&n, aTHX_ svn, IFLAG_POS);
3549 1749 100         if (status == 1) {
3550 1618 100         if (ix == 0) {
3551             UV factors[MPU_MAX_FACTORS];
3552 1031           uint32_t nfactors = factor(n, factors);
3553 1031 100         if (gimme_v == G_SCALAR)
3554 341           XSRETURN_UV(nfactors);
3555 690 50         EXTEND(SP, (EXTEND_TYPE)nfactors);
3556 2161 100         for (i = 0; i < nfactors; i++)
3557 1471           PUSHs(sv_2mortal(newSVuv( factors[i] )));
3558             } else {
3559 587           factored_t nf = factorint(n);
3560 587 100         if (gimme_v == G_SCALAR)
3561 12           XSRETURN_UV(nf.nfactors);
3562 575 50         EXTEND(SP, (EXTEND_TYPE)nf.nfactors);
3563 1891 100         for (i = 0; i < nf.nfactors; i++)
3564 1316           PUSH_2ELEM_AREF( nf.f[i], nf.e[i] );
3565             }
3566             } else {
3567 131           DISPATCHPP();
3568 131           return;
3569             }
3570              
3571             void divisors(IN SV* svn, IN SV* svk = 0)
3572             PREINIT:
3573             int status;
3574             UV n, k, i, ndivisors, *divs;
3575             PPCODE:
3576 981           status = _validate_and_set(&n, aTHX_ svn, IFLAG_POS);
3577 981           k = n;
3578 981 100         if (status == 1 && svk != 0) {
    100          
3579 9           status = _validate_and_set(&k, aTHX_ svk, IFLAG_POS);
3580 9 100         if (k > n) k = n;
3581             }
3582 981 100         if (status != 1) {
3583 8           DISPATCHPP();
3584 8           return;
3585             }
3586 973 50         if (GIMME_V == G_VOID) {
3587             /* Nothing */
3588 973 100         } else if (GIMME_V == G_SCALAR && k >= n) {
    50          
3589 21           ndivisors = divisor_sum(n, 0);
3590 21           PUSHs(sv_2mortal(newSVuv( ndivisors )));
3591             } else {
3592 952           divs = divisor_list(n, &ndivisors, k);
3593 952 50         if (GIMME_V == G_SCALAR) {
3594 0           PUSHs(sv_2mortal(newSVuv( ndivisors )));
3595             } else {
3596 952 50         EXTEND(SP, (EXTEND_TYPE)ndivisors);
    100          
3597 6783 100         for (i = 0; i < ndivisors; i++)
3598 5831           PUSHs(sv_2mortal(newSVuv( divs[i] )));
3599             }
3600 952           Safefree(divs);
3601             }
3602              
3603             void
3604             trial_factor(IN SV* svn, ...)
3605             ALIAS:
3606             fermat_factor = 1
3607             holf_factor = 2
3608             squfof_factor = 3
3609             lehman_factor = 4
3610             prho_factor = 5
3611             cheb_factor = 6
3612             pplus1_factor = 7
3613             pbrent_factor = 8
3614             pminus1_factor = 9
3615             ecm_factor = 10
3616             PREINIT:
3617             UV n, arg1, arg2;
3618             static const UV default_arg1[] =
3619             {0, 64000000, 8000000, 4000000, 1, 4000000, 0, 200, 4000000, 1000000};
3620             /* Trial, Fermat, Holf, SQUFOF, Lmn, PRHO, Cheb, P+1, Brent, P-1 */
3621             PPCODE:
3622 200 100         if (!_validate_and_set(&n, aTHX_ svn, IFLAG_POS) || ix == 10) {
    50          
3623 87           DISPATCHPP();
3624 87           return;
3625             }
3626 113 50         if (n == 0) XSRETURN_UV(0);
3627             /* Must read arguments before pushing anything */
3628 113 100         arg1 = (items >= 2) ? my_svuv(ST(1)) : default_arg1[ix];
3629 113 100         arg2 = (items >= 3) ? my_svuv(ST(2)) : 0;
3630             /* Small factors */
3631 175 50         while ( (n% 2) == 0 ) { n /= 2; XPUSHs(sv_2mortal(newSVuv( 2 ))); }
    100          
3632 173 50         while ( (n% 3) == 0 ) { n /= 3; XPUSHs(sv_2mortal(newSVuv( 3 ))); }
    100          
3633 194 50         while ( (n% 5) == 0 ) { n /= 5; XPUSHs(sv_2mortal(newSVuv( 5 ))); }
    100          
3634 113 100         if (n == 1) { /* done */ }
3635 63 100         else if (is_prime(n)) { XPUSHs(sv_2mortal(newSVuv( n ))); }
    50          
3636             else {
3637             UV factors[MPU_MAX_FACTORS+1];
3638 30           int i, nfactors = 0;
3639 30           switch (ix) {
3640 6           case 0: nfactors = trial_factor (n, factors, 2, arg1); break;
3641 2           case 1: nfactors = fermat_factor (n, factors, arg1); break;
3642 3           case 2: nfactors = holf_factor (n, factors, arg1); break;
3643 2           case 3: nfactors = squfof_factor (n, factors, arg1); break;
3644 2           case 4: nfactors = lehman_factor (n, factors, arg1); break;
3645 2           case 5: nfactors = prho_factor (n, factors, arg1); break;
3646 3           case 6: nfactors = cheb_factor (n, factors, arg1, arg2); break;
3647 2           case 7: nfactors = pplus1_factor (n, factors, arg1); break;
3648 2 50         case 8: if (items < 3) arg2 = 1;
3649 2           nfactors = pbrent_factor (n, factors, arg1, arg2); break;
3650 6           case 9:
3651 6 100         default: if (items < 3) arg2 = 10*arg1;
3652 6           nfactors = pminus1_factor(n, factors, arg1, arg2); break;
3653             }
3654 30 50         EXTEND(SP, (EXTEND_TYPE)nfactors);
    50          
3655 89 100         for (i = 0; i < nfactors; i++)
3656 59           PUSHs(sv_2mortal(newSVuv( factors[i] )));
3657             }
3658              
3659              
3660             void
3661             divisor_sum(IN SV* svn, ...)
3662             PREINIT:
3663             UV n, k, sigma;
3664             PPCODE:
3665 2420 100         if (items == 1) {
3666 92 100         if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) {
3667 91           sigma = divisor_sum(n, 1);
3668 91 100         if (n <= 1 || sigma != 0)
    50          
3669 91           XSRETURN_UV(sigma);
3670             }
3671             } else {
3672 2328           SV* svk = ST(1);
3673 3740 100         if ( (!SvROK(svk) || (SvROK(svk) && SvTYPE(SvRV(svk)) != SVt_PVCV)) &&
    50          
3674 2820 50         _validate_and_set(&n, aTHX_ svn, IFLAG_POS) &&
3675 1408           _validate_and_set(&k, aTHX_ svk, IFLAG_POS) ) {
3676 1408           sigma = divisor_sum(n, k);
3677 1408 100         if (n <= 1 || sigma != 0)
    50          
3678 1408           XSRETURN_UV(sigma);
3679             }
3680             }
3681 921           DISPATCHPP();
3682 921           XSRETURN(1);
3683              
3684             void
3685             jordan_totient(IN SV* sva, IN SV* svn)
3686             ALIAS:
3687             powersum = 1
3688             ramanujan_sum = 2
3689             legendre_phi = 3
3690             smooth_count = 4
3691             rough_count = 5
3692             PREINIT:
3693             int astatus, nstatus;
3694             UV a, n, ret;
3695             PPCODE:
3696 12290           astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_POS);
3697 12290           nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_POS);
3698 12290 100         if (astatus != 0 && nstatus != 0) {
    100          
3699 12287           switch (ix) {
3700 490           case 0: ret = jordan_totient(a, n);
3701 490 100         if (ret == 0 && n > 1)
    50          
3702 22           goto overflow;
3703 468           break;
3704 10801           case 1: ret = powersum(a, n);
3705 10801 100         if (ret == 0 && a > 0)
    100          
3706 12           goto overflow;
3707 10789           break;
3708 902 100         case 2: if (a < 1 || n < 1) XSRETURN_IV(0);
    100          
3709             {
3710 900           UV g = a / gcd_ui(a,n);
3711 900           int m = moebius(g);
3712 900 100         if (m == 0 || a == g) RETURN_NPARITY(m);
    100          
    50          
    50          
3713 285           XSRETURN_IV( m * (totient(a) / totient(g)) );
3714             }
3715             break;
3716 18           case 3: ret = legendre_phi(a, n); break;
3717 39           case 4: ret = debruijn_psi(a, n); break;
3718 37           case 5:
3719 37           default: ret = buchstab_phi(a, n); break;
3720             }
3721 11351           XSRETURN_UV(ret);
3722             }
3723 3           overflow:
3724 37           DISPATCHPP();
3725 37           objectify_result(aTHX_ sva, ST(0));
3726 37           XSRETURN(1);
3727              
3728             void almost_prime_count(IN SV* svk, IN SV* svn)
3729             ALIAS:
3730             almost_prime_count_approx = 1
3731             almost_prime_count_lower = 2
3732             almost_prime_count_upper = 3
3733             omega_prime_count = 4
3734             PREINIT:
3735             UV k, n, ret;
3736             PPCODE:
3737 214           if (_validate_and_set(&k, aTHX_ svk, IFLAG_ABS) &&
3738 107           _validate_and_set(&n, aTHX_ svn, IFLAG_ABS) &&
3739 97 50         k < BITS_PER_WORD) {
3740 97           ret = 0;
3741 97           switch (ix) {
3742 33           case 0: ret = almost_prime_count(k, n); break;
3743 6           case 1: ret = almost_prime_count_approx(k, n); break;
3744 2           case 2: ret = almost_prime_count_lower(k, n); break;
3745 2           case 3: ret = almost_prime_count_upper(k, n); break;
3746 54           case 4: ret = omega_prime_count(k, n); break;
3747 0           default: break;
3748             }
3749 97           XSRETURN_UV(ret);
3750             }
3751 10           DISPATCHPP();
3752 10           objectify_result(aTHX_ svn, ST(0));
3753 10           XSRETURN(1);
3754              
3755             void nth_almost_prime(IN SV* svk, IN SV* svn)
3756             ALIAS:
3757             nth_almost_prime_approx = 1
3758             nth_almost_prime_lower = 2
3759             nth_almost_prime_upper = 3
3760             PREINIT:
3761             UV k, n, max;
3762             PPCODE:
3763 48           if (_validate_and_set(&k, aTHX_ svk, IFLAG_ABS) &&
3764 24           _validate_and_set(&n, aTHX_ svn, IFLAG_ABS) &&
3765 24 100         k < BITS_PER_WORD) {
3766 22           UV ret = 0;
3767 22 50         if (n == 0 || (k == 0 && n > 1)) XSRETURN_UNDEF;
    50          
    0          
3768 22           max = max_almost_prime_count(k);
3769 22 50         if (max > 0 && n <= max) {
    100          
3770 21           switch (ix) {
3771 9           case 0: ret = nth_almost_prime(k, n); break;
3772 8           case 1: ret = nth_almost_prime_approx(k, n); break;
3773 2           case 2: ret = nth_almost_prime_lower(k, n); break;
3774 2           case 3: ret = nth_almost_prime_upper(k, n); break;
3775             }
3776 21 50         if (ret != 0) XSRETURN_UV(ret);
3777             }
3778             }
3779 3           DISPATCHPP();
3780 3           XSRETURN(1);
3781              
3782             void nth_omega_prime(IN SV* svk, IN SV* svn)
3783             PREINIT:
3784             UV k, n, max, ret;
3785             PPCODE:
3786 432           if (_validate_and_set(&k, aTHX_ svk, IFLAG_ABS) &&
3787 216           _validate_and_set(&n, aTHX_ svn, IFLAG_ABS) &&
3788 216 50         k < 16) {
3789 216 100         if (n == 0 || (k == 0 && n > 1)) XSRETURN_UNDEF;
    100          
    100          
3790 202           max = max_omega_prime_count(k);
3791 202 50         if (max > 0 && n <= max) {
    50          
3792 202           ret = nth_omega_prime(k, n);
3793 202           XSRETURN_UV(ret);
3794             }
3795             }
3796 0           DISPATCHPP();
3797 0           XSRETURN(1);
3798              
3799              
3800             void powmod(IN SV* sva, IN SV* svg, IN SV* svn)
3801             ALIAS:
3802             rootmod = 1
3803             PREINIT:
3804             int astatus, gstatus, nstatus, retundef;
3805             UV a, g, n, ret;
3806             PPCODE:
3807 864           astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY);
3808 864           gstatus = _validate_and_set(&g, aTHX_ svg, IFLAG_ANY);
3809 864           nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS);
3810 864 100         if (astatus != 0 && gstatus != 0 && nstatus != 0) {
    100          
    100          
3811 527 100         if (n == 0) XSRETURN_UNDEF;
3812 482 100         if (n == 1) XSRETURN_UV(0);
3813 438           _mod_with(&a, astatus, n);
3814 438           retundef = ret = 0;
3815 438 100         if (ix == 0) {
3816 328           retundef = !prep_pow_inv(&a,&g,gstatus,n);
3817 328 100         if (!retundef) ret = powmod(a, g, n);
3818             } else {
3819 110 100         retundef = !(prep_pow_inv(&a,&g,gstatus,n) && rootmod(&ret,a,g,n));
    100          
3820             }
3821 438 100         if (retundef) XSRETURN_UNDEF;
3822 383           XSRETURN_UV(ret);
3823             }
3824 337           DISPATCHPP();
3825 337           objectify_result(aTHX_ svn, ST(0));
3826 337           XSRETURN(1);
3827              
3828             void addmod(IN SV* sva, IN SV* svb, IN SV* svn)
3829             ALIAS:
3830             submod = 1
3831             mulmod = 2
3832             divmod = 3
3833             znlog = 4
3834             PREINIT:
3835             int astatus, bstatus, nstatus, retundef;
3836             UV a, b, n, ret;
3837             PPCODE:
3838 27559           astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY);
3839 27559           bstatus = _validate_and_set(&b, aTHX_ svb, IFLAG_ANY);
3840 27559           nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS);
3841 27559 100         if (astatus != 0 && bstatus != 0 && nstatus != 0) {
    100          
    100          
3842 14870 100         if (n == 0) XSRETURN_UNDEF;
3843 14758 100         if (n == 1) XSRETURN_UV(0);
3844 14644           _mod_with(&a, astatus, n);
3845 14644           _mod_with(&b, bstatus, n);
3846 14644           retundef = ret = 0;
3847 14644           switch (ix) {
3848 565           case 0: ret = addmod(a, b, n); break;
3849 172           case 1: ret = submod(a, b, n); break;
3850 13777           case 2: ret = mulmod(a, b, n); break;
3851 108           case 3: b = modinverse(b, n);
3852 108 100         if (b == 0) retundef = 1;
3853 80           else ret = mulmod(a, b, n);
3854 108           break;
3855 22           case 4: ret = znlog(a, b, n);
3856 22 100         if (ret == 0 && (b == 0 || a != 1)) retundef = 1;
    50          
    100          
3857 22           break;
3858 0           default: break;
3859             }
3860 14644 100         if (retundef) XSRETURN_UNDEF;
3861 14613           XSRETURN_UV(ret);
3862             }
3863 12689           DISPATCHPP();
3864 12689           objectify_result(aTHX_ svn, ST(0));
3865 12689           XSRETURN(1);
3866              
3867             void muladdmod(IN SV* sva, IN SV* svb, IN SV* svc, IN SV* svn)
3868             ALIAS:
3869             mulsubmod = 1
3870             PREINIT:
3871             int astatus, bstatus, cstatus, nstatus;
3872             UV a, b, c, n, ret;
3873             PPCODE:
3874 45064           astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY);
3875 45064           bstatus = _validate_and_set(&b, aTHX_ svb, IFLAG_ANY);
3876 45064           cstatus = _validate_and_set(&c, aTHX_ svc, IFLAG_ANY);
3877 45064           nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS);
3878 45064 100         if (astatus != 0 && bstatus != 0 && cstatus != 0 && nstatus != 0) {
    100          
    100          
    100          
3879 16774 50         if (n == 0) XSRETURN_UNDEF;
3880 16774 50         if (n == 1) XSRETURN_UV(0);
3881 16774           _mod_with(&a, astatus, n);
3882 16774           _mod_with(&b, bstatus, n);
3883 16774           _mod_with(&c, cstatus, n);
3884 16774 100         ret = (ix==0) ? muladdmod(a,b,c,n) : mulsubmod(a,b,c,n);
3885 16774           XSRETURN_UV(ret);
3886             }
3887 28290           DISPATCHPP();
3888 28290           objectify_result(aTHX_ svn, ST(0));
3889 28290           XSRETURN(1);
3890              
3891             void binomialmod(IN SV* svn, IN SV* svk, IN SV* svm)
3892             PREINIT:
3893             int nstatus, kstatus, mstatus;
3894             UV ret, n, k, m;
3895             PPCODE:
3896 22168           nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
3897 22168           kstatus = _validate_and_set(&k, aTHX_ svk, IFLAG_ANY);
3898 22168           mstatus = _validate_and_set(&m, aTHX_ svm, IFLAG_ABS);
3899 22168 100         if (nstatus != 0 && kstatus != 0 && mstatus != 0) {
    50          
    50          
3900 22167 50         if (m == 0) XSRETURN_UNDEF;
3901 22167 100         if (m == 1) XSRETURN_UV(0);
3902 21347 100         if ( (nstatus == 1 && (kstatus == -1 || k > n)) ||
    100          
    100          
    100          
3903 3 100         (nstatus ==-1 && (kstatus == -1 && k > n)) )
    50          
3904 3           XSRETURN_UV(0);
3905 21344 100         if (kstatus == -1) k = n - k;
3906 21344 100         if (nstatus == -1) n = neg_iv(n) + k - 1;
3907 21344 50         if (binomialmod(&ret, n, k, m)) {
3908 21344 100         if ((nstatus == -1) && (k & 1) && ret != 0) ret = m-ret;
    100          
    50          
3909 21344           XSRETURN_UV(ret);
3910             }
3911             }
3912 1           DISPATCHPP();
3913 1           XSRETURN(1);
3914              
3915             void factorialmod(IN SV* sva, IN SV* svn)
3916             PREINIT:
3917             int astatus, nstatus;
3918             UV a, n;
3919             PPCODE:
3920 825           astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_POS);
3921 825           nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS);
3922 825 100         if (astatus != 0 && nstatus != 0) {
    100          
3923 823 50         if (n == 0) XSRETURN_UNDEF;
3924 823 100         if (n == 1) XSRETURN_UV(0);
3925 822           XSRETURN_UV( factorialmod(a, n) );
3926             }
3927 2           DISPATCHPP_GMPONLYIF(astatus == 1);
3928 2           objectify_result(aTHX_ svn, ST(0));
3929 2           XSRETURN(1);
3930              
3931             void invmod(IN SV* sva, IN SV* svn)
3932             ALIAS:
3933             znorder = 1
3934             sqrtmod = 2
3935             negmod = 3
3936             PREINIT:
3937             int astatus, nstatus;
3938             UV a, n, r, retok;
3939             PPCODE:
3940 406           astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY);
3941 404           nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS);
3942 403 100         if (astatus != 0 && nstatus != 0) {
    100          
3943 269 100         if (n == 0) XSRETURN_UNDEF;
3944 258 100         if (n == 1) XSRETURN_UV((ix==1) ? 1 : 0); /* znorder different */
3945 245           _mod_with(&a, astatus, n);
3946 245           retok = r = 0;
3947 245           switch (ix) {
3948 162           case 0: retok = r = modinverse(a, n); break;
3949 16           case 1: retok = r = znorder(a, n); break;
3950 52           case 2: retok = sqrtmod(&r, a, n); break;
3951 15           case 3:
3952 15           default: retok = 1; r = negmod(a, n); break;
3953             }
3954 245 100         if (retok == 0) XSRETURN_UNDEF;
3955 221           XSRETURN_UV(r);
3956             }
3957 134           DISPATCHPP();
3958 134           objectify_result(aTHX_ svn, ST(0));
3959 134           XSRETURN(1);
3960              
3961             void allsqrtmod(IN SV* sva, IN SV* svn)
3962             PREINIT:
3963             int astatus, nstatus;
3964             UV a, n, i, numr, *roots;
3965             PPCODE:
3966 38           astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY);
3967 38           nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS);
3968 38 100         if (astatus != 0 && nstatus != 0) {
    50          
3969 36 100         if (n == 0) XSRETURN_EMPTY;
3970 34           _mod_with(&a, astatus, n);
3971 34           roots = allsqrtmod(&numr, a, n);
3972 34 100         if (roots != 0) {
3973 27 50         if (GIMME_V != G_ARRAY) {
3974 0           PUSHs(sv_2mortal(newSVuv(numr)));
3975             } else {
3976 27 50         EXTEND(SP, (EXTEND_TYPE)numr);
    50          
3977 107 100         for (i = 0; i < numr; i++)
3978 80           PUSHs(sv_2mortal(newSVuv(roots[i])));
3979             }
3980 27           Safefree(roots);
3981             }
3982             } else {
3983 2           DISPATCHPP();
3984 2           return;
3985             }
3986              
3987             void allrootmod(IN SV* sva, IN SV* svg, IN SV* svn)
3988             PREINIT:
3989             int astatus, gstatus, nstatus;
3990             UV a, g, n, i, numr, *roots;
3991             PPCODE:
3992 52           astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY);
3993 52           gstatus = _validate_and_set(&g, aTHX_ svg, IFLAG_ANY);
3994 52           nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS);
3995 52 100         if (astatus != 0 && gstatus != 0 && nstatus != 0) {
    50          
    100          
3996 50 100         if (n == 0) XSRETURN_EMPTY;
3997 49           _mod_with(&a, astatus, n);
3998 49 100         if (!prep_pow_inv(&a,&g,gstatus,n)) XSRETURN_EMPTY;
3999 47           roots = allrootmod(&numr, a, g, n);
4000 47 100         if (roots != 0) {
4001 36 50         if (GIMME_V != G_ARRAY) {
4002 0           PUSHs(sv_2mortal(newSVuv(numr)));
4003             } else {
4004 36 50         EXTEND(SP, (EXTEND_TYPE)numr);
    50          
4005 260 100         for (i = 0; i < numr; i++)
4006 224           PUSHs(sv_2mortal(newSVuv(roots[i])));
4007             }
4008 36           Safefree(roots);
4009             }
4010             } else {
4011 2           DISPATCHPP();
4012 2           return;
4013             }
4014              
4015             void is_primitive_root(IN SV* sva, IN SV* svn)
4016             PREINIT:
4017             int astatus, nstatus;
4018             UV a, n;
4019             PPCODE:
4020 39           astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY);
4021 39           nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS);
4022 39 50         if (astatus != 0 && nstatus != 0) {
    100          
4023 33 100         if (n == 0) XSRETURN_UNDEF;
4024 32           _mod_with(&a, astatus, n);
4025 32 50         RETURN_NPARITY( is_primitive_root(a,n,0) );
    50          
4026             }
4027 6           DISPATCHPP();
4028 6           XSRETURN(1);
4029              
4030             void qnr(IN SV* svn)
4031             ALIAS:
4032             znprimroot = 1
4033             PREINIT:
4034             UV n, r;
4035             PPCODE:
4036 71 100         if (_validate_and_set(&n, aTHX_ svn, IFLAG_ABS)) {
4037 64 100         if (n == 0) XSRETURN_UNDEF;
4038 63 100         if (ix == 0) {
4039 35           r = qnr(n);
4040             } else {
4041 28           r = znprimroot(n);
4042 28 100         if (r == 0 && n != 1) XSRETURN_UNDEF;
    100          
4043             }
4044 60 100         if (r < 100) RETURN_NPARITY(r);
    50          
    50          
4045 3           else XSRETURN_UV(r);
4046             }
4047 7           DISPATCHPP();
4048 7           objectify_result(aTHX_ svn, ST(0));
4049 7           XSRETURN(1);
4050              
4051             void
4052             is_smooth(IN SV* svn, IN SV* svk)
4053             ALIAS:
4054             is_rough = 1
4055             PREINIT:
4056             UV n, k;
4057             PPCODE:
4058 2374           if (_validate_and_set(&n, aTHX_ svn, IFLAG_ABS) &&
4059 1183           _validate_and_set(&k, aTHX_ svk, IFLAG_POS)) {
4060 1183 100         RETURN_NPARITY( (ix == 0) ? is_smooth(n,k) : is_rough(n,k) );
    50          
    50          
4061             }
4062 8           DISPATCHPP();
4063 8           XSRETURN(1);
4064              
4065             void
4066             is_omega_prime(IN SV* svk, IN SV* svn)
4067             ALIAS:
4068             is_almost_prime = 1
4069             PREINIT:
4070             UV n, k;
4071             int nstatus, kstatus;
4072             PPCODE:
4073 11281           kstatus = _validate_and_set(&k, aTHX_ svk, IFLAG_POS);
4074 11281           nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
4075 11281 50         if (kstatus != 0 && nstatus != 0) {
    100          
4076 11277           int res = (nstatus != 1) ? 0
4077 23169 50         : (ix == 0) ? is_omega_prime(k, n)
4078 11892 100         : is_almost_prime(k, n);
4079 11277 50         RETURN_NPARITY(res);
    50          
4080             }
4081 4           DISPATCHPP();
4082 4           XSRETURN(1);
4083              
4084             void is_divisible(IN SV* svn, IN SV* svd, ...)
4085             PREINIT:
4086             UV n, d, ret;
4087             size_t i;
4088             PPCODE:
4089 901517           if (_validate_and_set(&n, aTHX_ svn, IFLAG_ABS) &&
4090 450336           _validate_and_set(&d, aTHX_ svd, IFLAG_ABS)) {
4091 450335           int status = 1;
4092 450335 100         ret = d==0 ? (n==0) : n % d == 0;
4093 450344 100         for (i = 2; i < (size_t)items && !ret; i++) {
    50          
4094 9 50         if ((status = _validate_and_set(&d, aTHX_ ST(i), IFLAG_ABS)) != 1)
4095 0           break;
4096 9 50         ret = d==0 ? (n==0) : n % d == 0;
4097             }
4098 450335 50         if (status == 1) RETURN_NPARITY(ret);
    50          
    50          
4099             }
4100 846           DISPATCHPP();
4101 846           XSRETURN(1);
4102              
4103             void is_congruent(IN SV* svn, IN SV* svc, IN SV* svd)
4104             PREINIT:
4105             UV n, c, d;
4106             int nstatus, cstatus, dstatus;
4107             PPCODE:
4108 40054           nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
4109 40054           cstatus = _validate_and_set(&c, aTHX_ svc, IFLAG_ANY);
4110 40054           dstatus = _validate_and_set(&d, aTHX_ svd, IFLAG_ABS);
4111 40054 100         if (nstatus != 0 && cstatus != 0 && dstatus != 0) {
    50          
    50          
4112 40048 100         if (d != 0) {
4113 40010           _mod_with(&n, nstatus, d);
4114 40010           _mod_with(&c, cstatus, d);
4115             }
4116 40048 50         RETURN_NPARITY( n == c );
    50          
4117             }
4118 6           DISPATCHPP();
4119 6           XSRETURN(1);
4120              
4121             void valuation(IN SV* svn, IN SV* svk)
4122             PREINIT:
4123             UV n, k;
4124             PPCODE:
4125 309           if (_validate_and_set(&n, aTHX_ svn, IFLAG_ABS) &&
4126 134           _validate_and_set(&k, aTHX_ svk, IFLAG_POS)) {
4127 134 50         if (k <= 1) croak("valuation: k must be > 1");
4128 134 100         if (n == 0) XSRETURN_UNDEF;
4129 133 50         RETURN_NPARITY(valuation(n, k));
    50          
4130             }
4131 41           DISPATCHPP();
4132 41           XSRETURN(1);
4133              
4134             void is_powerful(IN SV* svn, IN SV* svk = 0);
4135             ALIAS:
4136             powerful_count = 1
4137             sumpowerful = 2
4138             nth_powerful = 3
4139             PREINIT:
4140             int nstatus;
4141 1673 100         UV n, ret, k = 2;
4142             PPCODE:
4143 1673           nstatus = _validate_and_set(&n, aTHX_ svn, (ix < 3) ? IFLAG_ANY: IFLAG_POS);
4144 1673 100         if (nstatus != 0 && (!svk || _validate_and_set(&k, aTHX_ svk, IFLAG_POS))) {
    100          
    50          
4145 1667 100         if (nstatus == -1) RETURN_NPARITY(0);
    50          
    50          
4146 1612 100         if (ix == 0) RETURN_NPARITY( is_powerful(n, k) );
    50          
    50          
4147 379 100         if (ix == 1) XSRETURN_UV( powerful_count(n, k) );
4148 186 100         if (ix == 2) {
4149 182 100         if (n == 0) XSRETURN_UV(0);
4150 179           ret = sumpowerful(n, k);
4151             } else {
4152 4 100         if (n == 0) XSRETURN_UNDEF;
4153 3           ret = nth_powerful(n, k);
4154             }
4155             /* ret=0: nth_powerful / sumpowerful result > UV_MAX, so go to PP/GMP */
4156 182 100         if (ret > 0) XSRETURN_UV(ret);
4157             }
4158 10           DISPATCHPP();
4159 10           objectify_result(aTHX_ svn, ST(0));
4160 10           XSRETURN(1);
4161              
4162              
4163             void kronecker(IN SV* sva, IN SV* svb)
4164             PREINIT:
4165             int astatus, bstatus;
4166             UV a, b;
4167             PPCODE:
4168 484           astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY);
4169 484           bstatus = _validate_and_set(&b, aTHX_ svb, IFLAG_ANY);
4170 484 100         if (astatus != 0 && bstatus != 0) {
    100          
4171             int k;
4172 166 100         if (bstatus == 1)
4173 154 100         k = (astatus==1) ? kronecker_uu(a,b) : kronecker_su((IV)a,b);
4174             else
4175 12 100         k = (astatus==1) ? kronecker_uu(a,neg_iv(b)) : -kronecker_su((IV)a,neg_iv(b));
4176 166 50         RETURN_NPARITY( k );
    50          
4177             }
4178 318           DISPATCHPP();
4179 318           XSRETURN(1);
4180              
4181             void is_qr(IN SV* sva, IN SV* svn)
4182             PREINIT:
4183             int astatus, nstatus;
4184             UV a, n;
4185             PPCODE:
4186 103           astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY);
4187 103           nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS);
4188 103 100         if (astatus != 0 && nstatus != 0) {
    50          
4189 101 100         if (n == 0) XSRETURN_UNDEF;
4190 100 100         if (n == 1) RETURN_NPARITY(1);
    50          
    50          
4191 94           _mod_with(&a, astatus, n);
4192 94 50         RETURN_NPARITY( is_qr(a,n) );
    50          
4193             }
4194 2           DISPATCHPP();
4195 2           XSRETURN(1);
4196              
4197             void addint(IN SV* sva, IN SV* svb)
4198             ALIAS:
4199             subint = 1
4200             mulint = 2
4201             divint = 3
4202             modint = 4
4203             cdivint = 5
4204             powint = 7
4205             PREINIT:
4206             int astatus, bstatus, overflow, postneg, nix, smask;
4207             UV a, b, t, ret;
4208             PPCODE:
4209 822654           astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY);
4210 822654 100         bstatus = _validate_and_set(&b, aTHX_ svb, (ix == 7) ? IFLAG_POS : IFLAG_ANY);
4211              
4212 822654 100         if (astatus != 0 && bstatus != 0) {
    100          
4213             /* We will try to do everything with non-negative integers, with overflow
4214             * detection. This means some pre-processing and post-processing for
4215             * negative inputs. */
4216 784845           nix = ix; /* So we can modify */
4217 784845           ret = overflow = postneg = 0;
4218 784845 100         smask = ((astatus == -1) << 1) + (bstatus == -1);
4219             /* smask=0: +a +b smask=1: +a -b smask=2: -a +b smask=3: -a -b */
4220              
4221 784845 100         if (b == 0 && (ix==3 || ix==4 || ix==5))
    100          
    100          
    100          
4222 6           croak("%s: divide by zero", SUBNAME);
4223              
4224 784839 100         if (smask != 0) { /* Manipulate so all arguments are positive */
4225 273751 100         if (smask & 2) a = neg_iv(a);
4226 273751 100         if (smask & 1) b = neg_iv(b);
4227              
4228 273751 100         if (ix == 0) {
4229 239           switch (smask) {
4230 53           case 1: nix=1; break; /* a - |b| */
4231 137           case 2: nix=1; t=a; a=b; b=t; break; /* b - |a| */
4232 49           case 3: postneg=1; break; /* -(|a| + |b|) */
4233 0           default: break;
4234             }
4235 273512 100         } else if (ix == 1) {
4236 804           switch (smask) {
4237 393           case 1: nix=0; break; /* a + |b| */
4238 393           case 2: nix=0; postneg=1; break; /* -(|a| + b) */
4239 18           case 3: t=a; a=b; b=t; break; /* |b| - |a| */
4240 0           default: break;
4241             }
4242 272708 100         } else if (ix == 2) {
4243 516 100         switch (smask) {
4244 500           case 1:
4245 500           case 2: postneg = 1; break;
4246 16           default: break;
4247             }
4248 272192 100         } else if (ix == 3) {
4249 1059 100         switch (smask) {
4250 1051           case 1:
4251 1051           case 2: postneg = 1; nix = 5; break;
4252 8           default: break;
4253             }
4254 271133 100         } else if (ix == 4) {
4255 271093           switch (smask) {
4256 90018           case 1: nix = 6; postneg = 1; break;
4257 91059           case 2: nix = 6; break;
4258 90016           case 3: postneg = 1; break;
4259 0           default: break;
4260             }
4261 40 100         } else if (ix == 5) {
4262 9 100         switch (smask) {
4263 7           case 1:
4264 7           case 2: postneg = 1; nix = 3; break;
4265 2           default: break;
4266             }
4267 31 50         } else if (ix == 6) {
4268             /* ix = 6 is cmodint */
4269 31 50         } else if (ix == 7) {
4270             /* bstatus is never -1 for powint */
4271 31           postneg = (b & 1);
4272             }
4273             }
4274 784839           switch (nix) {
4275 8051           case 0: ret = a + b; /* addint */
4276 8051           overflow = UV_MAX-a < b;
4277 8051           break;
4278 834           case 1: ret = a - b; /* subint */
4279 834 100         if (b > a && (IV)ret < 0) XSRETURN_IV((IV)ret);
    100          
4280 661           overflow = (b > a);
4281 661           break;
4282 105151           case 2: ret = a * b; /* mulint */
4283 105151 100         overflow = a > 0 && UV_MAX/a < b;
    100          
4284 105151           break;
4285 76957           case 3: ret = a / b; break; /* divint */
4286 311535           case 4: ret = a % b; break; /* modint */
4287 1062           case 5: ret = a / b + (a % b != 0); /* cdivint */
4288 1062           break;
4289 181077 100         case 6: ret = (a%b) ? b-(a%b) : 0; /* cmodint */
4290 181077           break;
4291 100172           case 7:
4292 100172           default: ret = ipowsafe(a, b);
4293 100172 100         overflow = (a > 1 && ret == UV_MAX);
    100          
4294 100172           break;
4295             }
4296 784666 100         if (!overflow) {
4297 772456 100         if (!postneg)
4298 590417           XSRETURN_UV(ret);
4299 182039 100         if (ret <= (UV)IV_MAX)
4300 181987           XSRETURN_IV(neg_iv(ret));
4301             }
4302             }
4303 50071           DISPATCHPP();
4304 50071           objectify_result(aTHX_ sva, ST(0));
4305 50071           XSRETURN(1);
4306              
4307             void add1int(IN SV* svn)
4308             ALIAS:
4309             sub1int = 1
4310             PREINIT:
4311             int status;
4312             UV n;
4313             PPCODE:
4314 2149           status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
4315 2149 100         if (status == 1) {
4316 454 100         if (ix == 1 && n == 0) XSRETURN_IV(-1);
    100          
4317 448 100         if (ix == 1 || (ix == 0 && n < UV_MAX))
    50          
    100          
4318 445 100         XSRETURN_UV( (ix==0) ? n+1 : n-1 );
4319 1695 100         } else if (status == -1) {
4320 37 100         if (ix == 0 || (ix == 1 && (IV)n > IV_MIN))
    50          
    50          
4321 37 100         XSRETURN_IV( (ix==0) ? (IV)n+1 : (IV)n-1 );
4322             }
4323 1661           DISPATCHPP();
4324 1661           objectify_result(aTHX_ svn, ST(0));
4325 1661           XSRETURN(1);
4326              
4327             void absint(IN SV* svn)
4328             ALIAS:
4329             negint = 1
4330             PREINIT:
4331             UV n;
4332             PPCODE:
4333 2421 100         if (ix == 0) {
4334 301 100         if (_validate_and_set(&n, aTHX_ svn, IFLAG_ABS))
4335 270           XSRETURN_UV(n);
4336             } else {
4337 2120           int status = _validate_and_set(&n, aTHX_ svn, IFLAG_IV);
4338 2120 100         if (status == -1) XSRETURN_UV(neg_iv(n));
4339 1974 100         else if (status == 1) XSRETURN_IV(neg_iv(n));
4340             }
4341 1570           DISPATCHPP();
4342 1570           objectify_result(aTHX_ svn, ST(0));
4343 1570           XSRETURN(1);
4344              
4345             void signint(IN SV* svn)
4346             ALIAS:
4347             is_odd = 1
4348             is_even = 2
4349             PREINIT:
4350             int status, sign, isodd;
4351             UV n;
4352             const char* s;
4353             STRLEN len;
4354             PPCODE:
4355 2308           status = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
4356 2308 100         if (status == 0) { /* Look at the string input */
4357 1584           s = SvPV(svn, len);
4358 1584 50         if (len == 0 || s == 0) croak("%s: invalid non-empty input", SUBNAME);
    50          
4359 1584 100         sign = (s[0] == '-') ? -1 : (s[0] == '0') ? 0 : 1;
4360 1584 100         isodd = (s[len-1] == '1' || s[len-1] == '3' || s[len-1] == '5' || s[len-1] == '7' || s[len-1] == '9');
    100          
    100          
    100          
    100          
4361             } else {
4362 724 100         sign = (status == -1) ? -1 : (n == 0) ? 0 : 1;
4363 724           isodd = n & 1;
4364             }
4365 2308 100         RETURN_NPARITY( (ix==0) ? sign : (ix==1) ? isodd : !isodd );
    100          
    50          
    50          
4366              
4367             void cmpint(IN SV* sva, IN SV* svb)
4368             PREINIT:
4369 290           int astatus, bstatus, ret = 0;
4370             UV a, b;
4371             PPCODE:
4372 290           astatus = _validate_and_set(&a, aTHX_ sva, IFLAG_ANY);
4373 290           bstatus = _validate_and_set(&b, aTHX_ svb, IFLAG_ANY);
4374 290 100         if (astatus != 0 && bstatus != 0) {
    100          
4375 123 100         if (astatus > bstatus) ret = 1;
4376 105 100         else if (astatus < bstatus) ret = -1;
4377 80 100         else if (a == b) ret = 0;
4378 62 100         else ret = ((astatus == 1 && a > b) || (astatus == -1 && (IV)a > (IV)b)) ? 1 : -1;
    100          
    100          
    100          
4379             } else {
4380             STRLEN alen, blen;
4381             char *aptr, *bptr;
4382 167           aptr = SvPV(sva, alen);
4383 167           bptr = SvPV(svb, blen);
4384 167           ret = strnum_cmp(aptr, alen, bptr, blen);
4385             }
4386 290 50         RETURN_NPARITY(ret);
    50          
4387              
4388             void logint(IN SV* svn, IN UV k, IN SV* svret = 0)
4389             ALIAS:
4390             rootint = 1
4391             PREINIT:
4392             UV n, root;
4393             PPCODE:
4394 35293 100         if (ix == 0 && k <= 1) croak("logint: base must be > 1");
    100          
4395 35291 100         if (ix == 1 && k <= 0) croak("rootint: k must be > 0");
    100          
4396 35290 100         if (svret != 0 && !SvROK(svret))
    50          
4397 0           croak("%s: third argument not a scalar reference",SUBNAME);
4398 35290 100         if (_validate_and_set(&n, aTHX_ svn, ix == 0 ? IFLAG_POS | IFLAG_NONZERO : IFLAG_POS)) {
    100          
4399 31300 100         root = (ix == 0) ? logint(n, k) : rootint(n, k);
4400 31300 100         if (svret) sv_setuv(SvRV(svret), ix == 0 ? ipow(k,root) : ipow(root,k));
    100          
4401 31300           XSRETURN_UV(root);
4402             }
4403 3987           DISPATCHPP_GMPONLYIF(svret == 0);
4404 3987           objectify_result(aTHX_ svn, ST(0));
4405 3987           XSRETURN(1);
4406              
4407             void divrem(IN SV* sva, IN SV* svb)
4408             ALIAS:
4409             fdivrem = 1
4410             cdivrem = 2
4411             tdivrem = 3
4412             PREINIT:
4413             int astatus, bstatus;
4414             UV D, d;
4415             IV iD, id;
4416             PPCODE:
4417 985           astatus = _validate_and_set(&D, aTHX_ sva, IFLAG_ANY);
4418 985           bstatus = _validate_and_set(&d, aTHX_ svb, IFLAG_ANY);
4419 985 100         if (astatus != 0 && bstatus != 0 && d == 0)
    50          
    100          
4420 8           croak("%s: divide by zero", SUBNAME);
4421 977 100         if (astatus == 1 && bstatus == 1 && (ix != 2 || D % d == 0)) {
    100          
    100          
    100          
4422 681 50         XPUSHs(sv_2mortal(newSVuv( D / d )));
4423 681 50         XPUSHs(sv_2mortal(newSVuv( D % d )));
4424 681           XSRETURN(2);
4425 296 100         } else if (ix == 2 && astatus == 1 && bstatus == 1 && d <= (UV)IV_MAX) {
    100          
    100          
    100          
4426             /* Exact division was handled above */
4427 8 50         XPUSHs(sv_2mortal(newSVuv( D/d + 1 )));
4428 8 50         XPUSHs(sv_2mortal(newSViv( ((IV)D%d) - d )));
4429 8           XSRETURN(2);
4430 361 100         } else if (astatus != 0 && bstatus != 0 &&
4431 146 100         _validate_and_set((UV*)&iD, aTHX_ sva, IFLAG_IV) != 0 &&
4432 73           _validate_and_set((UV*)&id, aTHX_ svb, IFLAG_IV) != 0) {
4433             /* Both values fit in an IV */
4434             IV q, r;
4435 72           switch (ix) {
4436 18           case 0: edivrem(&q, &r, iD, id); break;
4437 21           case 1: fdivrem(&q, &r, iD, id); break;
4438 18           case 2: cdivrem(&q, &r, iD, id); break;
4439 15           case 3:
4440 15           default: tdivrem(&q, &r, D, d); break;
4441             }
4442 72 50         XPUSHs(sv_2mortal(newSViv( q )));
4443 72 50         XPUSHs(sv_2mortal(newSViv( r )));
4444 72           XSRETURN(2);
4445             }
4446 216           DISPATCHPP();
4447 648 50         OBJECTIFY_STACK(2);
    100          
    50          
    100          
    50          
4448 216           XSRETURN(2);
4449              
4450             void lshiftint(IN SV* svn, IN SV* svk = 0)
4451             ALIAS:
4452             rshiftint = 1
4453             rashiftint = 2
4454             PREINIT:
4455             int nstatus, kstatus, nix;
4456             UV n, k, nk;
4457             PPCODE:
4458 4465           nix = ix;
4459 4465 100         if (items == 1) {
4460 2710           kstatus = 1;
4461 2710           k = 1;
4462             } else {
4463 1755           kstatus = _validate_and_set(&k, aTHX_ svk, IFLAG_ANY);
4464 1755 100         if (kstatus == -1) {
4465 96           k = neg_iv(k);
4466 96           nix = !ix; /* 0 => 1, 1 => 0, 2 => 0 */
4467             }
4468             }
4469 4465 50         if (kstatus != 0) {
4470 4465           nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
4471 4465 100         if (k == 0)
4472 57           XSRETURN(1);
4473 4408 100         if (nstatus != 0 && nix > 0 && k >= BITS_PER_WORD) /* Big right shift */
    100          
    100          
4474 114 100         XSRETURN_IV(nstatus == -1 && nix==2 ? -1 : 0);
    100          
4475 4294 100         if (nstatus == 1 && k < BITS_PER_WORD) {
    100          
4476 954 100         if (nix > 0) XSRETURN_UV(n >> k); /* Right shift */
4477 389 100         if ( ((n << k) >> k) == n) XSRETURN_UV(n << k); /* Left shift */
4478             /* Fall through -- left shift needs more bits */
4479 3340 100         } else if (nstatus == -1 && nix > 0 && k < BITS_PER_WORD) {
    100          
    50          
4480 59           n = neg_iv(n);
4481 59           nk = n >> k;
4482 59 100         XSRETURN_IV( nix == 1 ? -nk : (nk<
    100          
4483 3281 100         } else if (nstatus == -1 && nix == 0 && k+1 < BITS_PER_WORD) {
    50          
    100          
4484 130           n = neg_iv(n);
4485 130           nk = n << k;
4486 130 100         if ((nk << 1) >> (k+1) == n)
4487 125           XSRETURN_IV(-nk);
4488             /* Fall through -- left shift needs more bits */
4489             }
4490             }
4491 3319           DISPATCHPP();
4492 3319           objectify_result(aTHX_ svn, ST(0));
4493 3319           XSRETURN(1);
4494              
4495             void
4496             gcdext(IN SV* sva, IN SV* svb)
4497             PREINIT:
4498             IV u, v, d, a, b;
4499             PPCODE:
4500 26           if (_validate_and_set((UV*)&a, aTHX_ sva, IFLAG_IV) &&
4501 12           _validate_and_set((UV*)&b, aTHX_ svb, IFLAG_IV)) {
4502 12           d = gcdext(a, b, &u, &v, 0, 0);
4503 12 50         XPUSHs(sv_2mortal(newSViv( u )));
4504 12 50         XPUSHs(sv_2mortal(newSViv( v )));
4505 12 50         XPUSHs(sv_2mortal(newSViv( d )));
4506             } else {
4507 2           DISPATCHPP();
4508 8 50         OBJECTIFY_STACK(3);
    100          
    50          
    100          
    50          
4509 2           XSRETURN(3);
4510             }
4511              
4512             void
4513             stirling(IN UV n, IN UV m, IN UV type = 1)
4514             PPCODE:
4515 894 100         if (type != 1 && type != 2 && type != 3)
    100          
    100          
4516 1           croak("stirling: type must be 1, 2, or 3");
4517 893 100         if (n == m)
4518 70           XSRETURN_UV(1);
4519 823 100         else if (n == 0 || m == 0 || m > n)
    100          
    100          
4520 123           XSRETURN_UV(0);
4521 700 100         else if (type == 3) {
4522 190           UV s = stirling3(n, m);
4523 190 100         if (s != 0) XSRETURN_UV(s);
4524 510 100         } else if (type == 2) {
4525 318           IV s = stirling2(n, m);
4526 318 100         if (s != 0) XSRETURN_IV(s);
4527 192 50         } else if (type == 1) {
4528 192           IV s = stirling1(n, m);
4529 192 100         if (s != 0) XSRETURN_IV(s);
4530             }
4531 161           DISPATCHPP();
4532 161           objectify_result(aTHX_ 0, ST(0));
4533 161           XSRETURN(1);
4534              
4535             NV
4536             _XS_ExponentialIntegral(IN SV* x)
4537             ALIAS:
4538             _XS_LogarithmicIntegral = 1
4539             _XS_RiemannZeta = 2
4540             _XS_RiemannR = 3
4541             _XS_LambertW = 4
4542             PREINIT:
4543             NV nv, ret;
4544             CODE:
4545 108 50         nv = !SvROK(x) ? SvNV(x) : STRTONV(SvPV_nolen(x));
4546 108           switch (ix) {
4547 19           case 0: ret = Ei(nv); break;
4548 65           case 1: ret = Li(nv); break;
4549 6           case 2: ret = (NV) ld_riemann_zeta(nv); break;
4550 9           case 3: ret = (NV) RiemannR(nv,0); break;
4551 9           case 4:
4552 9           default:ret = lambertw(nv); break;
4553             }
4554 108 100         RETVAL = ret;
4555             OUTPUT:
4556             RETVAL
4557              
4558              
4559             void euler_phi(IN SV* svlo, IN SV* svhi = 0)
4560             ALIAS:
4561             moebius = 1
4562             PREINIT:
4563             UV lo, hi;
4564             int lostatus, histatus;
4565             uint32_t mask;
4566             PPCODE:
4567 28364 100         mask = (ix == 1 && items == 1) ? IFLAG_ABS : IFLAG_ANY;
    100          
4568 28364           lostatus = _validate_and_set(&lo, aTHX_ svlo, mask);
4569 28364 100         if (svhi == 0 && lostatus != 0) {
    100          
4570 28297 100         if (ix == 0) XSRETURN_UV( (lostatus == -1) ? 0 : totient(lo) );
    100          
4571 28223 50         else RETURN_NPARITY( moebius(lo) );
    50          
4572             }
4573 67 100         histatus = (svhi == 0) ? 0 : _validate_and_set(&hi, aTHX_ svhi, IFLAG_ANY);
4574             /* - If range is larger than MAX_EXTEND, reduce it to fit.
4575             * Arguably we should croak as invalid input.
4576             * - If range includes UV_MAX, pull it off and handle separately.
4577             * This makes count never underflow (e.g. lo=0,hi=max, hi-lo+1 => 0)
4578             * It also simplifies loop overflow logic in the range function.
4579             */
4580 107 100         if (lostatus == 1 && histatus == 1) {
    100          
4581             UV i, count;
4582 41           int appendmax = (hi == UV_MAX);
4583 41 100         if (lo > hi) XSRETURN(0);
4584              
4585 40 100         if (appendmax) hi--;
4586             if ((hi-lo+1) > MAX_EXTEND) hi = lo + MAX_EXTEND - 1;
4587 40           count = hi-lo+1;
4588 40 50         if (count > 0) {
4589 40 50         EXTEND(SP, (EXTEND_TYPE)count);
    100          
4590 40 100         if (ix == 0) {
4591 14 100         UV arrlo = (lo < 100) ? 0 : lo;
4592 14           UV *totients = range_totient(arrlo, hi);
4593 385 100         for (i = 0; i < count; i++)
4594 371           PUSHs(sv_2mortal(newSVuv(totients[i+lo-arrlo])));
4595 14           Safefree(totients);
4596             } else {
4597 26           signed char* mu = range_moebius(lo, hi);
4598             dMY_CXT;
4599 27562 100         for (i = 0; i < count; i++)
4600 27536 50         PUSH_NPARITY(mu[i]);
    50          
4601 26           Safefree(mu);
4602             }
4603             }
4604 40 100         if (appendmax) {
4605 2 50         EXTEND(SP, 1);
4606 2 100         if (ix == 0) {
4607 1           PUSHs(sv_2mortal(newSVuv(totient(UV_MAX))));
4608             } else {
4609             dMY_CXT;
4610 1 50         PUSH_NPARITY(-1); /* moebius of 2^32-1, 2^64-1, 2^128-1 => -1 */
    50          
4611             }
4612             }
4613             } else {
4614 26           DISPATCHPP();
4615 26           return;
4616             }
4617              
4618             void sqrtint(IN SV* svn)
4619             ALIAS:
4620             carmichael_lambda = 1
4621             exp_mangoldt = 2
4622             PREINIT:
4623             UV n, r;
4624             PPCODE:
4625 65715 100         if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) {
4626 65668           r = 0;
4627 65668           switch (ix) {
4628 65447           case 0: r = isqrt(n); break;
4629 201           case 1: r = carmichael_lambda(n); break;
4630 20           case 2: r = exp_mangoldt(n); break;
4631 0           default: break;
4632             }
4633 65668           XSRETURN_UV(r);
4634             }
4635 46           DISPATCHPP();
4636 46           objectify_result(aTHX_ svn, ST(0));
4637 46           XSRETURN(1);
4638              
4639             void prime_omega(IN SV* svn)
4640             ALIAS:
4641             prime_bigomega = 1
4642             hammingweight = 2
4643             is_square_free = 3
4644             PREINIT:
4645             UV n, ret;
4646             PPCODE:
4647 37173 100         if (_validate_and_set(&n, aTHX_ svn, IFLAG_ABS)) {
4648 37150           ret = 0;
4649 37150           switch (ix) {
4650 14           case 0: ret = prime_omega(n); break;
4651 14           case 1: ret = prime_bigomega(n); break;
4652 11           case 2: ret = popcnt(n); break;
4653 37111           case 3: ret = is_square_free(n); break;
4654 0           default: break;
4655             }
4656 37150 50         RETURN_NPARITY(ret);
    50          
4657             }
4658 23 100         if (ix == 2 && _XS_get_callgmp() < 47) {
    50          
4659 3           char* ptr; STRLEN len; ptr = SvPV(svn, len);
4660 3           XSRETURN_UV(mpu_popcount_string(ptr, len));
4661             }
4662 20           DISPATCHPP();
4663 20           XSRETURN(1);
4664              
4665             void factorial(IN SV* svn)
4666             ALIAS:
4667             subfactorial = 1
4668             fubini = 2
4669             primorial = 3
4670             pn_primorial = 4
4671             sumtotient = 5
4672             PREINIT:
4673             UV n, r;
4674             PPCODE:
4675 1322 50         if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) {
4676 1320           r = 0;
4677 1320           switch(ix) {
4678 1161           case 0: r = factorial(n); break;
4679 25           case 1: r = subfactorial(n); break;
4680 24           case 2: r = fubini(n); break;
4681 62           case 3: r = primorial(n); break;
4682 35           case 4: r = pn_primorial(n); break;
4683 13           case 5: r = sumtotient(n); break;
4684 0           default: break;
4685             }
4686 1320 100         if (n == 0 || r > 0) XSRETURN_UV(r);
    100          
4687 418 50         if (ix == 5) { /* Probably an overflow, try 128-bit. */
4688             UV hicount, count;
4689 0           int retok = sumtotient128(n, &hicount, &count);
4690 0 0         if (retok == 1 && hicount > 0)
    0          
4691 0           RETURN_128(hicount, count);
4692 0 0         if (retok == 1)
4693 0           XSRETURN_UV(count);
4694             }
4695             }
4696 418           DISPATCHPP();
4697 418           objectify_result(aTHX_ svn, ST(0));
4698 418           XSRETURN(1);
4699              
4700             void binomial(IN SV* svn, IN SV* svk)
4701             PREINIT:
4702             int nstatus, kstatus;
4703             UV n, k, ret;
4704             PPCODE:
4705 3578           nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY);
4706 3578           kstatus = _validate_and_set(&k, aTHX_ svk, IFLAG_ANY);
4707 3578 100         if (nstatus != 0 && kstatus != 0) {
    50          
4708 3568 100         if ( (nstatus == 1 && (kstatus == -1 || k > n)) ||
    100          
    100          
    100          
4709 367 100         (nstatus ==-1 && (kstatus == -1 && k > n)) )
    100          
4710 241           XSRETURN_UV(0);
4711 3327 100         if (kstatus == -1)
4712 81           k = n - k; /* n<0,k<=n: (-1)^(n-k) * binomial(-k-1,n-k) */
4713 3327 100         if (nstatus == -1) {
4714 310           ret = binomial( neg_iv(n)+k-1, k );
4715 310 100         if (ret > 0 && ret <= (UV)IV_MAX)
    50          
4716 245 100         XSRETURN_IV( (IV)ret * ((k&1) ? -1 : 1) );
4717 3017 50         } else if (nstatus == 1) {
4718 3017           ret = binomial(n, k);
4719 3017 100         if (ret != 0) XSRETURN_UV(ret);
4720             }
4721             }
4722 192 100         DISPATCHPP_GMPONLYIF(nstatus == 1 && kstatus != 0);
    50          
4723 192           objectify_result(aTHX_ svn, ST(0));
4724 192           XSRETURN(1);
4725              
4726             void falling_factorial(IN SV* svn, IN SV* svk)
4727             ALIAS:
4728             rising_factorial = 1
4729             PREINIT:
4730             int nstatus, kstatus;
4731             UV n, k;
4732             PPCODE:
4733 482           nstatus = _validate_and_set(&n, aTHX_ svn, IFLAG_ANY | IFLAG_IV);
4734 482           kstatus = _validate_and_set(&k, aTHX_ svk, IFLAG_POS);
4735 486 100         if (nstatus == 1 && kstatus == 1) {
    50          
4736 252 100         UV ret = (ix==0) ? falling_factorial(n,k) : rising_factorial(n,k);
4737 252 100         if (ret != UV_MAX) XSRETURN_UV(ret);
4738 230 100         } else if (nstatus == -1 && kstatus == 1) {
    50          
4739 220           IV in = (IV)n;
4740 220 100         IV ret = (ix==0) ? falling_factorial_s(in,k) : rising_factorial_s(in,k);
4741 220 50         if (ret != IV_MAX) XSRETURN_IV(ret);
4742             }
4743 14           DISPATCHPP();
4744 14           objectify_result(aTHX_ svn, ST(0));
4745 14           XSRETURN(1);
4746              
4747             void mertens(IN SV* svn)
4748             ALIAS:
4749             liouville = 1
4750             sumliouville = 2
4751             is_pillai = 3
4752             is_congruent_number = 4
4753             hclassno = 5
4754             ramanujan_tau = 6
4755             PREINIT:
4756             UV n;
4757             int status;
4758             PPCODE:
4759 1458 100         status = _validate_and_set(&n, aTHX_ svn, (ix < 5) ? IFLAG_POS : IFLAG_ANY);
4760 1458 100         if (status == -1)
4761 1           XSRETURN_IV(0);
4762 1457 100         if (status == 1) {
4763 1455           IV r = 0;
4764 1455           switch(ix) {
4765 52           case 0: r = mertens(n); break;
4766 60           case 1: r = liouville(n); break;
4767 57           case 2: r = sumliouville(n); break;
4768 993           case 3: r = pillai_v(n); break;
4769 210           case 4: r = is_congruent_number(n); break;
4770 73           case 5: r = hclassno(n); break;
4771 10           case 6: r = ramanujan_tau(n);
4772 10 100         if (r == 0 && n != 0)
    100          
4773 4           status = 0;
4774 10           break;
4775 0           default: break;
4776             }
4777 1455 100         if (status != 0) RETURN_NPARITY(r);
    100          
    100          
4778             }
4779 6           DISPATCHPP();
4780 6           objectify_result(aTHX_ svn, ST(0));
4781 6           XSRETURN(1);
4782              
4783             int _is_congruent_number_filter(IN UV n)
4784             CODE:
4785 247           RETVAL = is_congruent_number_filter(n);
4786             OUTPUT:
4787             RETVAL
4788              
4789             bool _is_congruent_number_tunnell(IN UV n)
4790             CODE:
4791 200           RETVAL = is_congruent_number_tunnell(n);
4792             OUTPUT:
4793             RETVAL
4794              
4795             void chebyshev_theta(IN SV* svn)
4796             ALIAS:
4797             chebyshev_psi = 1
4798             PREINIT:
4799             UV n;
4800             PPCODE:
4801 19 50         if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) {
4802 19 100         NV r = (ix==0) ? chebyshev_theta(n) : chebyshev_psi(n);
4803 19           XSRETURN_NV(r);
4804             }
4805 0           DISPATCHPP();
4806             /* Result is FP */
4807 0           XSRETURN(1);
4808              
4809              
4810             #define RETURN_SET_REF(s) /* Return sorted set values */ \
4811             { \
4812             UV *sdata; \
4813             unsigned long slen = iset_size(s); \
4814             int sign = iset_sign(s); \
4815             New(0, sdata, slen, UV); \
4816             iset_allvals(s, sdata); \
4817             iset_destroy(&s); \
4818             RETURN_LIST_REF( slen, sdata, sign ); \
4819             }
4820             #define RETURN_EMPTY_SET_REF() RETURN_EMPTY_LIST_REF()
4821              
4822             void sumset(IN SV* sva, IN SV* svb = 0)
4823             PROTOTYPE: $;$
4824             PREINIT:
4825             int atype, btype, stype, sign;
4826             UV *ra, *rb;
4827             size_t alen, blen, i, j;
4828             iset_t s;
4829             PPCODE:
4830 31           atype = arrayref_to_int_array(aTHX_ &alen, &ra, 1, sva, "sumset arg 1");
4831 31 100         if (svb == 0 || atype == IARR_TYPE_BAD) {
    50          
4832 7           rb = ra;
4833 7           blen = alen;
4834 7           btype = atype;
4835             } else {
4836 24           btype = arrayref_to_int_array(aTHX_ &blen, &rb, 1, svb, "sumset arg 2");
4837             }
4838 31 100         if (alen == 0 || blen == 0) {
    100          
4839 2 50         if (rb != ra) Safefree(rb);
4840 2           Safefree(ra);
4841 2           RETURN_EMPTY_SET_REF();
4842             }
4843 29 50         if (atype == IARR_TYPE_BAD || btype == IARR_TYPE_BAD)
    100          
4844 1           stype = IARR_TYPE_BAD;
4845             else
4846 28           stype = type_of_sumset(atype, btype, ra[0],ra[alen-1], rb[0],rb[blen-1]);
4847 29 100         if (stype == IARR_TYPE_BAD) {
4848 11 50         if (rb != ra) Safefree(rb);
4849 11           Safefree(ra);
4850 11           DISPATCHPP();
4851 11           XSRETURN(1);
4852             }
4853 18 50         sign = IARR_TYPE_TO_STATUS(stype);
    100          
4854             /* Sumset */
4855 18           s = iset_create( 10UL * (alen+blen) );
4856 143 100         for (i = 0; i < alen; i++)
4857 2801 100         for (j = 0; j < blen; j++)
4858 2676           iset_add(&s, ra[i]+rb[j], sign);
4859 18 100         if (rb != ra) Safefree(rb);
4860 18           Safefree(ra);
4861 467 50         RETURN_SET_REF(s);
    100          
    100          
4862              
4863             void setbinop(IN SV* block, IN SV* sva, IN SV* svb = 0)
4864             PROTOTYPE: &$;$
4865             PREINIT:
4866             int atype, btype;
4867             UV *ra, *rb;
4868             Size_t alen, blen;
4869             CODE:
4870             /* Must be CODE and not PPCODE */
4871             #if PERL_VERSION_GE(5,10,1)
4872 26           atype = arrayref_to_int_array(aTHX_ &alen, &ra, 1, sva, "setbinop arg 1");
4873 26 100         if (svb == 0 || atype == IARR_TYPE_BAD) {
    50          
4874 3           rb = ra;
4875 3           blen = alen;
4876 3           btype = atype;
4877             } else {
4878 23           btype = arrayref_to_int_array(aTHX_ &blen, &rb, 1, svb, "setbinop arg 2");
4879             }
4880 26 100         if (alen == 0 || blen == 0) {
    50          
4881 1 50         if (rb != ra) Safefree(rb);
4882 1           Safefree(ra);
4883 1           RETURN_EMPTY_SET_REF();
4884             }
4885 25 50         if (atype != IARR_TYPE_BAD && btype != IARR_TYPE_BAD) {
    50          
4886             iset_t s;
4887             Size_t i, j;
4888             GV *agv, *bgv;
4889             SV *asv, *bsv;
4890             UV ret;
4891             CV *subcv;
4892 25           int status = 0;
4893              
4894 25 50         SETSUBREF(subcv, block);
4895              
4896 25           agv = gv_fetchpv("a", GV_ADD, SVt_PV);
4897 25           bgv = gv_fetchpv("b", GV_ADD, SVt_PV);
4898 25           SAVESPTR(GvSV(agv));
4899 25           SAVESPTR(GvSV(bgv));
4900 25           asv = NEWSVINT(0,0);
4901 25           bsv = NEWSVINT(0,0);
4902 25           GvSV(agv) = asv;
4903 25           GvSV(bgv) = bsv;
4904 25           s = iset_create( 4UL * ((size_t)alen + (size_t)blen + 2) );
4905             #ifdef dMULTICALL
4906 25 50         if (!CvISXSUB(subcv)) {
4907             dMULTICALL;
4908 25           I32 gimme = G_SCALAR;
4909 25           DECL_MULTICALL_SCOPE(subcv);
4910 25 50         PUSH_MULTICALL(subcv);
4911 90 100         for (i = 0; i < alen; i++) {
4912 300 100         for (j = 0; j < blen; j++) {
4913 235 100         FASTSETSVINT(asv, atype == IARR_TYPE_POS, ra[i]);
    100          
    50          
    50          
4914 235 100         FASTSETSVINT(bsv, btype == IARR_TYPE_POS, rb[j]);
    100          
    50          
    50          
4915 235 50         SCOPED_MULTICALL;
    50          
4916 235           status = _validate_and_set(&ret, aTHX_ *PL_stack_sp, IFLAG_ANY);
4917 235 100         if (status != 0) iset_add(&s, ret, status);
4918 235 100         if (status == 0 || iset_is_invalid(s)) break;
    100          
4919             }
4920 70 100         if (j < blen) break;
4921             }
4922             FIX_MULTICALL_REFCOUNT;
4923 25 50         POP_MULTICALL;
4924             }
4925             else
4926             #endif
4927             {
4928 0 0         for (i = 0; i < alen; i++) {
4929 0 0         for (j = 0; j < blen; j++) {
4930 0           dSP;
4931 0 0         FASTSETSVINT(asv, atype == IARR_TYPE_POS, ra[i]);
    0          
    0          
    0          
4932 0 0         FASTSETSVINT(bsv, btype == IARR_TYPE_POS, rb[j]);
    0          
    0          
    0          
4933 0 0         PUSHMARK(SP);
4934 0           call_sv((SV*)subcv, G_SCALAR);
4935 0           status = _validate_and_set(&ret, aTHX_ *PL_stack_sp, IFLAG_ANY);
4936 0 0         if (status != 0) iset_add(&s, ret, status);
4937 0 0         if (status == 0 || iset_is_invalid(s)) break;
    0          
4938             }
4939 0 0         if (j < blen) break;
4940             }
4941             }
4942             /* asv and bsv are going to be freed with agv and bgv. */
4943 25 100         if (status != 0 && !iset_is_invalid(s)) {
    100          
4944 20 100         if (rb != ra) Safefree(rb);
4945 20           Safefree(ra);
4946 176 50         RETURN_SET_REF(s);
    100          
    100          
4947             }
4948 5           iset_destroy(&s);
4949             }
4950 5 50         if (rb != ra) Safefree(rb);
4951 5           Safefree(ra);
4952             #endif
4953 5           DISPATCHPP();
4954 5           XSRETURN(1);
4955              
4956             void setunion(IN SV* sva, IN SV* svb)
4957             PROTOTYPE: $$
4958             ALIAS:
4959             setintersect = 1
4960             setminus = 2
4961             setdelta = 3
4962             PREINIT:
4963             int atype, btype;
4964             UV *ra, *rb;
4965             size_t alen, blen;
4966             PPCODE:
4967             /* Fast path: both inputs are arrayrefs of native non-negative sorted
4968             * unique integers. Merge SV* directly with SvREFCNT_inc, skipping
4969             * intermediate UV array allocations and per-element newSVuv calls. */
4970             {
4971             size_t fa, fb;
4972 56           SV **aa = _check_sorted_nonneg_arrayref(aTHX_ sva, &fa);
4973 56 100         SV **bb = aa ? _check_sorted_nonneg_arrayref(aTHX_ svb, &fb) : NULL;
4974 56 100         if (aa && bb) {
    100          
4975 8 100         int inc_eq = (ix == 0 || ix == 1); /* union, intersect */
    100          
4976 8           int inc_lt = (ix != 1); /* union, minus, delta */
4977 8 100         int inc_gt = (ix == 0 || ix == 3); /* union, delta */
    100          
4978 8 100         size_t maxlen = (ix == 1) ? (fa < fb ? fa : fb) : fa + fb;
4979 8           AV *res = newAV();
4980 8           size_t rlen = 0, ia = 0, ib = 0;
4981 8           av_extend(res, (SSize_t)maxlen - 1);
4982 8           SV **ar = AvARRAY(res);
4983 32 100         while (ia < fa && ib < fb) {
    50          
4984 24           UV va = SvUVX(aa[ia]), vb = SvUVX(bb[ib]);
4985 24 100         if (va==vb) {if (inc_eq) ar[rlen++]=SvREFCNT_inc(aa[ia]); ia++; ib++;}
    100          
4986 12 50         else if (va< vb) {if (inc_lt) ar[rlen++]=SvREFCNT_inc(aa[ia]); ia++;}
    100          
4987 0 0         else {if (inc_gt) ar[rlen++]=SvREFCNT_inc(bb[ib]); ib++;}
4988             }
4989 8 100         if (inc_lt) while (ia < fa) ar[rlen++] = SvREFCNT_inc(aa[ia++]);
    50          
4990 16 100         if (inc_gt) while (ib < fb) ar[rlen++] = SvREFCNT_inc(bb[ib++]);
    100          
4991 8           AvFILLp(res) = (SSize_t)rlen - 1;
4992 8           ST(0) = sv_2mortal(newRV_noinc((SV*)res));
4993 8           XSRETURN(1);
4994             }
4995             }
4996             /* Get the integers and ensure they are sorted unique integers first. */
4997 48           atype = arrayref_to_int_array(aTHX_ &alen, &ra, 1, sva, SUBNAME);
4998 48           btype = arrayref_to_int_array(aTHX_ &blen, &rb, 1, svb, SUBNAME);
4999              
5000 48 100         if (CAN_COMBINE_IARR_TYPES(atype,btype)) {
5001 30           UV *r = 0;
5002 30           size_t rlen = 0, ia = 0, ib = 0;
5003 30 100         int pcmp = (atype == IARR_TYPE_NEG || btype == IARR_TYPE_NEG) ? 0 : 1;
    100          
5004              
5005 30 100         if (ix == 0) { /* union */
5006 8 50         New(0, r, alen + blen, UV);
5007 40 100         while (ia < alen && ib < blen) {
    100          
5008 32 100         if (ra[ia] == rb[ib]) {
5009 9           r[rlen++] = ra[ia];
5010 9           ia++; ib++;
5011             } else {
5012 23 100         if (SIGNED_CMP_LT(pcmp, ra[ia], rb[ib])) r[rlen++] = ra[ia++];
    100          
5013 8           else r[rlen++] = rb[ib++];
5014             }
5015             }
5016 8 100         if (ia < alen) { Copy(ra+ia, r+rlen, alen-ia, UV); rlen += alen-ia; }
    50          
5017 8 100         if (ib < blen) { Copy(rb+ib, r+rlen, blen-ib, UV); rlen += blen-ib; }
    50          
5018 22 100         } else if (ix == 1) { /* intersect */
5019 7 50         New(0, r, (alen < blen) ? alen : blen, UV);
5020 34 100         while (ia < alen && ib < blen) {
    100          
5021 27 100         if (ra[ia] == rb[ib]) {
5022 9           r[rlen++] = ra[ia];
5023 9           ia++; ib++;
5024             } else {
5025 18 100         if (SIGNED_CMP_LT(pcmp, ra[ia], rb[ib])) ia++;
    100          
5026 6           else ib++;
5027             }
5028             }
5029 15 100         } else if (ix == 2) { /* minus (difference) */
5030 7 50         New(0, r, alen, UV);
5031 34 100         while (ia < alen && ib < blen) {
    100          
5032 27 100         if (ra[ia] == rb[ib]) {
5033 9           ia++; ib++;
5034             } else {
5035 18 100         if (SIGNED_CMP_LT(pcmp, ra[ia], rb[ib])) r[rlen++] = ra[ia++];
    100          
5036 6           else ib++;
5037             }
5038             }
5039 7 100         if (ia < alen) { Copy(ra+ia, r+rlen, alen-ia, UV); rlen += alen-ia; }
    50          
5040 8 50         } else if (ix == 3) { /* delta (symmetric difference) */
5041 8 50         New(0, r, alen + blen, UV);
5042 39 100         while (ia < alen && ib < blen) {
    100          
5043 31 100         if (ra[ia] == rb[ib]) {
5044 11           ia++; ib++;
5045             } else {
5046 20 100         if (SIGNED_CMP_LT(pcmp, ra[ia], rb[ib])) r[rlen++] = ra[ia++];
    100          
5047 6           else r[rlen++] = rb[ib++];
5048             }
5049             }
5050 8 100         if (ia < alen) { Copy(ra+ia, r+rlen, alen-ia, UV); rlen += alen-ia; }
    50          
5051 8 100         if (ib < blen) { Copy(rb+ib, r+rlen, blen-ib, UV); rlen += blen-ib; }
    50          
5052             }
5053 30           Safefree(ra);
5054 30           Safefree(rb);
5055 135 100         RETURN_LIST_REF(rlen, r, pcmp);
    100          
5056             }
5057             /* if (atype != IARR_TYPE_BAD && btype != IARR_TYPE_BAD) { .. isets .. } */
5058 18           Safefree(ra);
5059 18           Safefree(rb);
5060 18           DISPATCHPP();
5061 18           XSRETURN(1);
5062              
5063             void set_is_disjoint(IN SV* sva, IN SV* svb)
5064             PROTOTYPE: $$
5065             ALIAS:
5066             set_is_equal = 1
5067             set_is_subset = 2
5068             set_is_proper_subset = 3
5069             set_is_superset = 4
5070             set_is_proper_superset = 5
5071             set_is_proper_intersection = 6
5072             PREINIT:
5073             int atype, btype, ret;
5074             UV *ra, *rb;
5075             size_t alen, blen, inalen, inblen;
5076             PPCODE:
5077             /* If one set is much smaller than the other, it would be faster using
5078             * is_in_set(). We'll keep things simple and slurp in both sets. */
5079              
5080             /* THIS ASSUMES THE INPUT LISTS HAVE NO DUPLICATES */
5081 90           inalen = inblen = 0;
5082 90 50         if (SvROK(sva) && SvTYPE(SvRV(sva)) == SVt_PVAV && SvROK(svb) && SvTYPE(SvRV(svb)) == SVt_PVAV) {
    50          
    50          
    50          
5083             /* Shortcut on length if we can to skip intersection. */
5084 90           inalen = av_count((AV*) SvRV(sva));
5085 90           inblen = av_count((AV*) SvRV(svb));
5086 90 100         if ( (ix == 1 && inalen != inblen) ||
    100          
    100          
5087 85 100         (ix == 2 && inalen < inblen) || (ix == 3 && inalen <= inblen) ||
    100          
    100          
    100          
5088 78 100         (ix == 4 && inalen > inblen) || (ix == 5 && inalen >= inblen) )
    100          
    100          
5089 19 50         RETURN_NPARITY(0);
    50          
5090             }
5091              
5092             /* Get the integers as sorted arrays of IV or UV */
5093 71           atype = arrayref_to_int_array(aTHX_ &alen, &ra, 1, sva, SUBNAME);
5094 71           btype = arrayref_to_int_array(aTHX_ &blen, &rb, 1, svb, SUBNAME);
5095              
5096 71 100         if (CAN_COMBINE_IARR_TYPES(atype,btype)) {
5097 57           size_t rlen = 0, ia = 0, ib = 0;
5098 57 100         int pcmp = (atype == IARR_TYPE_NEG || btype == IARR_TYPE_NEG) ? 0 : 1;
    100          
5099              
5100 338 100         while (ia < alen && ib < blen) {
    100          
5101 281 100         if (ra[ia] == rb[ib]) {
5102 207           rlen++;
5103 207           ia++; ib++;
5104             } else {
5105 74 100         if (SIGNED_CMP_LT(pcmp, ra[ia], rb[ib])) ia++;
    100          
5106 30           else ib++;
5107             }
5108             }
5109 57           Safefree(ra);
5110 57           Safefree(rb);
5111 57           ret = 0;
5112 57           switch (ix) {
5113 8 100         case 0: if (rlen == 0) ret = 1; break;
5114 4 50         case 1: if (alen == blen && rlen == blen) ret = 1; break;
    100          
5115 23 50         case 2: if (alen >= blen && rlen == blen) ret = 1; break;
    100          
5116 3 50         case 3: if (alen > blen && rlen == blen) ret = 1; break;
    100          
5117 7 50         case 4: if (alen <= blen && rlen == alen) ret = 1; break;
    100          
5118 3 50         case 5: if (alen < blen && rlen == alen) ret = 1; break;
    100          
5119 9           case 6:
5120 9 100         default:if (rlen > 0 && rlen < alen && rlen < blen) ret = 1; break;
    100          
    100          
5121             }
5122 57 50         RETURN_NPARITY(ret);
    50          
5123             }
5124 14           Safefree(ra);
5125 14           Safefree(rb);
5126 14           DISPATCHPP();
5127 14           XSRETURN(1);
5128              
5129             void setcontains(IN SV* sva, ...)
5130             ALIAS:
5131             setcontainsany = 1
5132             PROTOTYPE: $@
5133             PREINIT:
5134             UV b;
5135             AV *ava;
5136             int bstatus, subset, findall;
5137             Size_t alen, blen, i;
5138             DECL_ARREF(arb);
5139             PPCODE:
5140 52 50         CHECK_ARRAYREF(sva); /* First argument is a set as array ref */
    50          
5141 52           ava = (AV*) SvRV(sva);
5142 52           alen = av_count(ava);
5143 52 50         if (items < 2) RETURN_NPARITY(1);
    0          
    0          
5144 52 50         if (SvMAGICAL(ava) || !AvREAL(ava)) { /* Punt these to Perl */
    50          
5145 0           DISPATCHPP();
5146 0           XSRETURN(1);
5147             }
5148 52           findall = ix == 0 ? 1 : 0;
5149 85 100         if (items == 2 && SvROK(ST(1)) && SvTYPE(SvRV(ST(1))) == SVt_PVAV) {
    100          
    100          
5150             set_data_t svcache;
5151 33 50         USE_ARREF(arb, ST(1), SUBNAME, AR_READ);
    50          
    50          
5152             /* If setcontainsany and B is bigger than A, swap them for performance. */
5153 33 100         if (ix == 1 && len_arb > alen && svarr_arb != 0) {
    100          
    50          
5154 1           ava = avp_arb;
5155 1           alen = len_arb;
5156 1 50         USE_ARREF(arb, ST(0), SUBNAME, AR_READ);
    50          
    50          
5157             }
5158 33           blen = len_arb;
5159 33 100         subset = ix == 0 && blen > alen ? 0 : findall;
    100          
5160 33           _sc_clear_cache(&svcache);
5161             /* setcontains: if we find anything that is NOT in SETA, return 0
5162             * setcontainsany: if we find anything that IS in SETA, return 1 */
5163 88 100         for (i = 0; i < blen && subset == findall; i++) {
    100          
5164 55           bstatus = _validate_and_set(&b, aTHX_ FETCH_ARREF(arb,i), IFLAG_ANY);
5165 55           subset = is_in_set(aTHX_ ava, &svcache, bstatus, b);
5166             }
5167             } else {
5168             UV *rb;
5169 19           int btype = array_to_int_array(aTHX_ &blen, &rb, 1, &ST(1), items-1);
5170 19 100         bstatus = IARR_TYPE_TO_STATUS(btype);
    100          
5171 19 100         subset = bstatus == 0 ? -1 : ix == 0 && blen > alen ? 0 : findall;
    100          
    50          
5172 19 50         if (blen <= 4) {
5173 36 100         for (i = 0; i < blen && subset == findall; i++)
    100          
5174 17           subset = is_in_set(aTHX_ ava, 0, bstatus, rb[i]);
5175             } else {
5176             set_data_t svcache;
5177 0           _sc_clear_cache(&svcache);
5178 0 0         for (i = 0; i < blen && subset == findall; i++)
    0          
5179 0           subset = is_in_set(aTHX_ ava, &svcache, bstatus, rb[i]);
5180             }
5181 19           Safefree(rb);
5182             }
5183 52 100         if (subset != -1)
5184 40 50         RETURN_NPARITY(subset);
    50          
5185 12           DISPATCHPP();
5186 12           XSRETURN(1);
5187              
5188             void setinsert(IN SV* sva, ...)
5189             PROTOTYPE: $@
5190             PREINIT:
5191             AV *ava;
5192             Size_t alen, blen, i;
5193             UV *rb;
5194             int btype, bstatus;
5195             PPCODE:
5196 40 50         CHECK_ARRAYREF(sva); /* First argument is a set as array ref */
    50          
5197 40           ava = (AV*) SvRV(sva);
5198 40           alen = av_count(ava);
5199 40 100         if (items < 2)
5200 2 50         RETURN_NPARITY(0);
    50          
5201 38 50         CHECK_AV_NOT_READONLY(ava); /* We intend to modify it */
5202 38 50         if (SvMAGICAL(ava) || !AvREAL(ava)) { /* Punt these to Perl */
    50          
5203 0           DISPATCHPP();
5204 0           XSRETURN(1);
5205             }
5206              
5207 38 100         if (SvROK(ST(1)) && SvTYPE(SvRV(ST(1))) == SVt_PVAV) {
    50          
5208 13 50         if (items != 2)
5209 0           croak("setinsert: expected integer list or single array reference");
5210 13           btype = arrayref_to_int_array(aTHX_ &blen, &rb, 1, ST(1), "setinsert");
5211             } else {
5212 25           btype = array_to_int_array(aTHX_ &blen, &rb, 1, &ST(1), items-1);
5213             }
5214 38 100         bstatus = IARR_TYPE_TO_STATUS(btype);
    100          
5215              
5216 38 100         if (bstatus != 0 && blen <= 4) {
    100          
5217 34           int res = 0;
5218 34           size_t nins = 0;
5219 78 50         for (i = 0; res >= 0 && i < blen; i++) {
    100          
5220 44           res = ins_into_set(aTHX_ ava, bstatus, rb[i]);
5221 44           nins += (res > 0);
5222             }
5223 34 50         if (res >= 0) { Safefree(rb); RETURN_NPARITY(nins); }
    50          
    50          
5224 4 100         } else if (bstatus != 0) {
5225             size_t nbeg, nmid, nend, nmidcheck;
5226             int alostatus, ahistatus;
5227             UV alo, ahi;
5228             set_data_t svcache;
5229              
5230             /* 1. ava is empty. push everything and we're done. */
5231 3 50         if (alen == 0) {
5232 0           av_extend(ava, blen);
5233 0 0         for (i = 0; i < blen; i++)
5234 0 0         av_push(ava, NEWSVINT(bstatus, rb[i]));
5235 0           Safefree(rb);
5236 3 0         RETURN_NPARITY(blen);
    0          
5237             }
5238 3           _sc_clear_cache(&svcache);
5239             /* Get hi and lo values of set. */
5240 3 50         if (_sc_set_lohi(aTHX_ AvARRAY(ava), &svcache, 0, alen-1, &alostatus, &ahistatus, &alo, &ahi) >= 0) {
5241 3 50         if (_sign_cmp(alostatus,alo,ahistatus,ahi) > 0)
5242 0           croak("%s: expected numerically ascending sorted input", SUBNAME);
5243             /* Both lo/hi are not bigint, so there are no bigints in the set. */
5244 3           nbeg = nend = nmid = 0;
5245             /* 1. Find out how many elements go in front. */
5246 10 50         while (nbeg < blen && _sign_cmp(bstatus,rb[nbeg],alostatus,alo) < 0)
    100          
5247 7           nbeg++;
5248             /* 2. Find out how many elements go at the end. */
5249 509 100         while (nend < blen-nbeg && _sign_cmp(bstatus,rb[blen-1-nend],ahistatus,ahi) > 0)
    100          
5250 506           nend++;
5251             /* 3. In-place insert everything in the middle. */
5252 3           nmidcheck = blen - nbeg - nend;
5253 3 100         if (nmidcheck > 0) {
5254             size_t *insert_idx;
5255             SV **insert_sv;
5256 2 50         New(0, insert_idx, nmidcheck, size_t);
5257 2 50         New(0, insert_sv, nmidcheck, SV*);
5258 17 50         for (i = nbeg; bstatus != 0 && i < blen-nend; i++) {
    100          
5259 15           int index = insert_index_in_set(aTHX_ ava,&svcache,bstatus,rb[i]);
5260 15 50         if (index < 0)
5261 0           croak("%s: expected sorted input, found bigint value in interior", SUBNAME);
5262 15 100         if (index > 0) {
5263 4 50         insert_sv[nmid] = NEWSVINT(bstatus,rb[i]);/* Value to insert */
5264 4           insert_idx[nmid] = index-1; /* Where to insert */
5265 4           nmid++;
5266             }
5267             }
5268 2           av_extend(ava, alen + nmid + nbeg + nend);
5269 2 100         if (nmid > 0) {
5270             SV** arr;
5271 1           unsigned long index_lastorig = alen-1;
5272 1           unsigned long index_moveto = index_lastorig + nmid;
5273              
5274             /* Push new values on end so Perl calculates array correctly. */
5275 5 100         for (i = 0; i < nmid; i++)
5276 4           av_push(ava, insert_sv[i]);
5277 1           arr = AvARRAY(ava);
5278             /* SV* pointer manipulation to insert new values in place. */
5279 5 100         for (i = 0; i < nmid; i++) {
5280 4           size_t j = nmid-1-i;
5281 4           size_t idx = insert_idx[j];
5282 4           size_t nmove = index_lastorig - idx + 1;
5283 4 100         if (nmove > 0) {
5284 2           size_t moveto = index_moveto - nmove + 1;
5285 2           memmove(arr+moveto, arr+idx, sizeof(SV*) * nmove);
5286 2           index_lastorig -= nmove;
5287 2           index_moveto -= nmove;
5288             }
5289 4           arr[index_moveto--] = insert_sv[j];
5290             }
5291             }
5292 2           Safefree(insert_sv);
5293 2           Safefree(insert_idx);
5294             }
5295             /* 4. Insert at front */
5296 3 100         if (nbeg > 0) {
5297 2           av_unshift(ava, nbeg);
5298 9 100         for (i = 0; i < nbeg; i++)
5299 7 100         av_store(ava, i, NEWSVINT(bstatus, rb[i]));
5300             }
5301             /* 5. Push onto back */
5302 3 50         if (nend > 0) {
5303 509 100         for (i = 0; i < nend; i++)
5304 506 100         av_push(ava, NEWSVINT(bstatus, rb[blen-nend+i]));
5305             }
5306 3           Safefree(rb);
5307 3 50         RETURN_NPARITY(nbeg+nmid+nend);
    100          
5308             }
5309             }
5310 1           Safefree(rb);
5311 1           DISPATCHPP();
5312 1           XSRETURN(1);
5313              
5314             void setremove(IN SV* sva, ...)
5315             PROTOTYPE: $@
5316             PREINIT:
5317             AV *ava;
5318             Size_t alen, blen, i;
5319             UV *rb;
5320             int btype, bstatus;
5321             PPCODE:
5322 12 50         CHECK_ARRAYREF(sva); /* First argument is a set as array ref */
    50          
5323 12           ava = (AV*) SvRV(sva);
5324 12           alen = av_count(ava);
5325 12 100         if (alen == 0 || items < 2)
    50          
5326 2 50         RETURN_NPARITY(0);
    50          
5327 10 50         CHECK_AV_NOT_READONLY(ava); /* We intend to modify it */
5328 10 50         if (SvMAGICAL(ava) || !AvREAL(ava)) { /* Punt these to Perl */
    50          
5329 0           DISPATCHPP();
5330 0           XSRETURN(1);
5331             }
5332 10 100         if (SvROK(ST(1)) && SvTYPE(SvRV(ST(1))) == SVt_PVAV) {
    50          
5333 7 50         if (items != 2)
5334 0           croak("setremove: expected integer list or single array reference");
5335 7           btype = arrayref_to_int_array(aTHX_ &blen, &rb, 1, ST(1), "setremove");
5336             } else {
5337 3           btype = array_to_int_array(aTHX_ &blen, &rb, 1, &ST(1), items-1);
5338             }
5339 10 50         if (btype != IARR_TYPE_BAD) {
5340 10 50         bstatus = IARR_TYPE_TO_STATUS(btype);
    100          
5341 10 50         if (blen <= 5 || alen <= 20) { /* SIMPLE DELETE LOOP */
    0          
5342 10           int res = 0;
5343 10           size_t ndel = 0;
5344 25 50         for (i = 0; res >= 0 && i < blen; i++) {
    100          
5345 15           res = del_from_set(aTHX_ ava, bstatus, rb[i]);
5346 15 100         if (res > 0) ndel++;
5347             }
5348 10 50         if (res >= 0) { Safefree(rb); RETURN_NPARITY(ndel); }
    50          
    50          
5349 0 0         } else if (blen < 500 || (blen*100) < alen) { /* ONE PASS DELETE */
    0          
5350 0           Size_t *del_idx, ndel = 0;
5351             set_data_t svcache;
5352 0           _sc_clear_cache(&svcache);
5353             /* Create index list to remove */
5354 0 0         New(0, del_idx, blen, Size_t);
5355 0 0         for (i = 0; i < blen; i++) {
5356 0           int index = index_in_set(aTHX_ ava, &svcache, bstatus, rb[i]);
5357 0 0         if (index < 0)
5358 0           croak("%s: expected sorted input, found bigint value in interior", SUBNAME);
5359 0 0         if (index > 0)
5360 0           del_idx[ndel++] = index-1;
5361             }
5362 0           Safefree(rb);
5363 0 0         if (ndel > 0) {
5364 0           SV **arr = AvARRAY(ava);
5365 0           size_t to = del_idx[0];
5366 0 0         for (i = 0; i < ndel; i++) {
5367 0           size_t idx = del_idx[i];
5368 0           size_t beg = idx+1;
5369 0 0         size_t len = (i+1) >= ndel ? alen-beg : del_idx[i+1]-beg;
5370 0           SvREFCNT_dec_NN(arr[idx]);
5371 0 0         if (len > 0) {
5372 0           memmove(arr+to, arr+beg, sizeof(SV*) * len);
5373 0           to += len;
5374             }
5375             }
5376 0 0         Zero(arr + alen - ndel, ndel, SV*);
5377 0           av_fill(ava, alen-ndel-1);
5378             }
5379 0           Safefree(del_idx);
5380 0 0         RETURN_NPARITY(ndel);
    0          
5381             } else { /* CLEAR AND GREP */
5382 0           int atype, astatus, del_complete = 0;
5383 0           UV *ra = 0;
5384 0           atype = arrayref_to_int_array(aTHX_ &alen, &ra, 1, sva, SUBNAME);
5385 0 0         if (CAN_COMBINE_IARR_TYPES(atype,btype)) {
5386 0           size_t ia = 0, ib = 0;
5387 0 0         int pcmp = (atype == IARR_TYPE_NEG || btype == IARR_TYPE_NEG) ? 0 : 1;
    0          
5388              
5389 0 0         astatus = IARR_TYPE_TO_STATUS(atype);
    0          
5390 0           av_clear(ava);
5391 0 0         while (ia < alen && ib < blen) {
    0          
5392 0 0         if (ra[ia] == rb[ib]) {
5393 0           ia++; ib++;
5394             } else {
5395 0 0         if (SIGNED_CMP_LT(pcmp, ra[ia], rb[ib])) av_push(ava, NEWSVINT(astatus, ra[ia++]));
    0          
    0          
5396 0           else ib++;
5397             }
5398             }
5399 0 0         while (ia < alen) av_push(ava, NEWSVINT(astatus, ra[ia++]));
    0          
5400 0           del_complete = 1;
5401             }
5402 0           Safefree(ra);
5403 0           Safefree(rb);
5404 0 0         if (del_complete) RETURN_NPARITY(alen - av_count(ava));
    0          
    0          
5405             }
5406             }
5407 0           DISPATCHPP();
5408 0           XSRETURN(1);
5409              
5410              
5411             void setinvert(IN SV* sva, ...)
5412             PROTOTYPE: $@
5413             PREINIT:
5414             AV *ava;
5415             Size_t alen, blen, i;
5416             UV *rb;
5417             int btype, bstatus;
5418             PPCODE:
5419 12 50         CHECK_ARRAYREF(sva);
    50          
5420 12           ava = (AV*) SvRV(sva);
5421 12           alen = av_count(ava);
5422 12 100         if (items < 2)
5423 2 50         RETURN_NPARITY(0);
    50          
5424 10 50         CHECK_AV_NOT_READONLY(ava);
5425 10 50         if (SvMAGICAL(ava) || !AvREAL(ava)) {
    50          
5426 0           DISPATCHPP();
5427 0           XSRETURN(1);
5428             }
5429 10 100         if (SvROK(ST(1)) && SvTYPE(SvRV(ST(1))) == SVt_PVAV) {
    50          
5430 5 50         if (items != 2)
5431 0           croak("setinvert: expected integer list or single array reference");
5432 5           btype = arrayref_to_int_array(aTHX_ &blen, &rb, 1, ST(1), "setinvert");
5433             } else {
5434 5           btype = array_to_int_array(aTHX_ &blen, &rb, 1, &ST(1), items-1);
5435             }
5436 10 50         if (btype != IARR_TYPE_BAD) {
5437 10 100         if (blen == 0) {
5438 2           Safefree(rb);
5439 2 50         RETURN_NPARITY(0);
    50          
5440             }
5441 8 50         bstatus = IARR_TYPE_TO_STATUS(btype);
    100          
5442 8 50         if (blen <= 4 || alen <= 20) { /* SIMPLE TOGGLE LOOP */
    0          
5443 8           IV ndelta = 0;
5444 8           int res = 0;
5445 26 50         for (i = 0; res >= 0 && i < blen; i++) {
    100          
5446 18           res = del_from_set(aTHX_ ava, bstatus, rb[i]);
5447 18 100         if (res > 0) { ndelta--; } /* found and removed */
5448 5 50         else if (res == 0) { /* not found, insert */
5449 5           res = ins_into_set(aTHX_ ava, bstatus, rb[i]);
5450 5 50         if (res > 0) ndelta++;
5451             }
5452             }
5453 8 50         if (res >= 0) {
5454 8           Safefree(rb);
5455 8           ST(0) = sv_2mortal(newSViv(ndelta));
5456 8           XSRETURN(1);
5457             }
5458             } else { /* MERGE-STYLE SYMMETRIC DIFFERENCE */
5459 0           int atype, astatus, done = 0;
5460 0           UV *ra = 0;
5461 0           Size_t old_alen = alen;
5462 0           atype = arrayref_to_int_array(aTHX_ &alen, &ra, 1, sva, SUBNAME);
5463 0 0         if (CAN_COMBINE_IARR_TYPES(atype, btype)) {
5464 0           size_t ia = 0, ib = 0;
5465 0 0         int pcmp = (atype == IARR_TYPE_NEG || btype == IARR_TYPE_NEG) ? 0 : 1;
    0          
5466 0 0         astatus = IARR_TYPE_TO_STATUS(atype);
    0          
5467 0           av_clear(ava);
5468 0 0         while (ia < alen && ib < blen) {
    0          
5469 0 0         if (ra[ia] == rb[ib]) { ia++; ib++; }
5470 0 0         else if (SIGNED_CMP_LT(pcmp, ra[ia], rb[ib])) av_push(ava, NEWSVINT(astatus, ra[ia++]));
    0          
    0          
5471 0 0         else av_push(ava, NEWSVINT(bstatus, rb[ib++]));
5472             }
5473 0 0         while (ia < alen) av_push(ava, NEWSVINT(astatus, ra[ia++]));
    0          
5474 0 0         while (ib < blen) av_push(ava, NEWSVINT(bstatus, rb[ib++]));
    0          
5475 0           done = 1;
5476             }
5477 0           Safefree(ra);
5478 0 0         if (done) {
5479 0           Safefree(rb);
5480 0           ST(0) = sv_2mortal(newSViv((IV)av_count(ava) - (IV)old_alen));
5481 0           XSRETURN(1);
5482             }
5483             }
5484             }
5485 0           Safefree(rb);
5486 0           DISPATCHPP();
5487 0           XSRETURN(1);
5488              
5489              
5490             void is_sidon_set(IN SV* sva)
5491             PROTOTYPE: $
5492             PREINIT:
5493             int itype, is_sidon;
5494             size_t len, i, j;
5495             UV *data;
5496             iset_t s;
5497             PPCODE:
5498 19           itype = arrayref_to_int_array(aTHX_ &len, &data, 1, sva,"is_sidon_set");
5499 19 100         if (itype == IARR_TYPE_NEG) { /* All elements must be non-negative. */
5500 3           Safefree(data);
5501 3 50         RETURN_NPARITY(0);
    50          
5502             }
5503             /* If any bigints or we cannot add the values in 64-bits, call PP. */
5504 16 50         if (itype == IARR_TYPE_BAD || itype == IARR_TYPE_POS) {
    100          
5505 1           Safefree(data);
5506 1           DISPATCHPP();
5507 1           XSRETURN(1);
5508             }
5509             /* Check if the set is a Sidon set. */
5510 15           is_sidon = 1;
5511 15           s = iset_create( 20UL * len );
5512 128 100         for (i = 0; i < len && is_sidon; i++)
    100          
5513 2397 100         for (j = i; j < len; j++)
5514 2288 100         if (!iset_add(&s, data[i] + data[j], 1))
5515 4           { is_sidon = 0; break; }
5516 15           Safefree(data);
5517 15           iset_destroy(&s);
5518 15 50         RETURN_NPARITY(is_sidon);
    50          
5519              
5520             void is_sumfree_set(IN SV* sva)
5521             PROTOTYPE: $
5522             PREINIT:
5523             UV *data;
5524             size_t len, i, j;
5525             int itype;
5526             bool is_sumfree;
5527             PPCODE:
5528 35           itype = arrayref_to_int_array(aTHX_ &len, &data,1,sva,"is_sumfree_set");
5529 35 50         if (itype != IARR_TYPE_BAD && len <= 1) { /* Degenerate cases: len 0 or 1 */
    100          
5530 5 100         is_sumfree = len == 0 || data[0] != 0;
    100          
5531 5           Safefree(data);
5532 5 50         RETURN_NPARITY(is_sumfree);
    50          
5533             }
5534             /* Check for IV overflow on sum */
5535 30 100         if (itype == IARR_TYPE_NEG) {
5536 9           IV min = data[0], max = data[len-1]; /* Array is sorted */
5537 9 100         if (min < IV_MIN/2 || max > IV_MAX/2) itype = IARR_TYPE_BAD;
    50          
5538             }
5539 30           is_sumfree = 1;
5540 30 100         if (itype == IARR_TYPE_ANY) {
5541 71 100         for (i = 0; i < len && is_sumfree; i++)
    100          
5542 168 100         for (j = i; j < len; j++)
5543 126 100         if (is_in_sorted_uv_array(data[i]+data[j], data, len))
5544 9           { is_sumfree = 0; break; }
5545 10 100         } else if (itype == IARR_TYPE_NEG) {
5546 24 100         for (i = 0; i < len && is_sumfree; i++)
    100          
5547 48 100         for (j = i; j < len; j++)
5548 35 100         if (is_in_sorted_iv_array((IV)data[i]+(IV)data[j], (IV*)data, len))
5549 3           { is_sumfree = 0; break; }
5550             }
5551 30           Safefree(data);
5552              
5553 30 100         if (itype == IARR_TYPE_ANY || itype == IARR_TYPE_NEG)
    100          
5554 28 50         RETURN_NPARITY(is_sumfree);
    50          
5555              
5556             /* We're here because one of:
5557             * 1) itype is TYPE_BAD because there were bigints.
5558             * 2) itype is TYPE_BAD because summed IVs would overflow.
5559             * 3) itype is TYPE_POS.
5560             * At least one element is >= 2^63, so we would overflow on sum.
5561             */
5562 2           DISPATCHPP();
5563 2           XSRETURN(1);
5564              
5565             void toset(...)
5566             PROTOTYPE: @
5567             PREINIT:
5568             int type;
5569             size_t len;
5570             UV *L;
5571             PPCODE:
5572 77 100         if (items == 0) RETURN_EMPTY_SET_REF();
5573 73           type = array_to_int_array(aTHX_ &len, &L, 1, &ST(0), items);
5574 73 100         if (type != IARR_TYPE_BAD)
5575 299 100         RETURN_LIST_REF(len, L, type != IARR_TYPE_NEG);
    100          
5576 32           Safefree(L);
5577 32           DISPATCHPP();
5578 32           XSRETURN(1);
5579              
5580              
5581             void vecsort(...)
5582             PROTOTYPE: @
5583             PREINIT:
5584             int type;
5585             size_t len;
5586             UV *L;
5587             PPCODE:
5588 87 100         if (items == 0)
5589 1           XSRETURN_EMPTY;
5590 86 100         if (SvROK(ST(0)) && SvTYPE(SvRV(ST(0))) == SVt_PVAV) {
    100          
5591 9 50         if (items != 1)
5592 0           croak("vecsort: expected integer list or single array reference");
5593 9           type = arrayref_to_int_array(aTHX_ &len, &L, 0, ST(0), "vecsort");
5594             } else {
5595 77           type = array_to_int_array(aTHX_ &len, &L, 0, &ST(0), items);
5596             }
5597 86 100         if (GIMME_V != G_ARRAY) /* In scalar context, return number of elements */
5598 3           XSRETURN_UV(len);
5599 83 100         if (type == IARR_TYPE_ANY || type == IARR_TYPE_POS) {
    100          
5600 62           sort_uv_array(L, len);
5601 21 100         } else if (type == IARR_TYPE_NEG) {
5602 1           sort_iv_array((IV*)L, len);
5603             } else {
5604 20           Safefree(L);
5605 20           DISPATCHPP();
5606 20           return;
5607             }
5608 451 50         RETURN_LIST_VALS( len, L, (type != IARR_TYPE_NEG) );
    50          
    50          
    100          
    100          
5609              
5610             void vecsorti(IN SV* sva)
5611             PROTOTYPE: $
5612             PREINIT:
5613             int type;
5614             size_t i, len;
5615             UV *L;
5616             SV **arr;
5617             AV *ava;
5618             PPCODE:
5619 32 50         CHECK_ARRAYREF(sva);
    50          
5620 32           ava = (AV*) SvRV(sva);
5621 32 50         CHECK_AV_NOT_READONLY(ava); /* We intend to modify it */
5622 32 50         if (SvMAGICAL(ava) || !AvREAL(ava)) { /* Punt these to Perl */
    50          
5623 0           DISPATCHPP();
5624 0           XSRETURN(1);
5625             }
5626 32           type = arrayref_to_int_array(aTHX_ &len, &L, 0, sva, "vecsorti");
5627             /* If we really wanted to optimize small values, the reading function
5628             * could create a mask like:
5629             * mask |= (istatus == 1) ? n : (n ^ (n<<1));
5630             * then we know if the input is 8-bit, 16-bit, 32-bit, etc.
5631             */
5632 32 100         if (type == IARR_TYPE_ANY || type == IARR_TYPE_POS) {
    100          
5633 7           sort_uv_array(L, len);
5634 25 50         } else if (type == IARR_TYPE_NEG) {
5635 0           sort_iv_array((IV*)L, len);
5636             } else {
5637 25           Safefree(L);
5638 25           DISPATCHPP();
5639 25           XSRETURN(1);
5640             }
5641 7           arr = AvARRAY(ava);
5642 25 100         for (i = 0; i < len; i++)
5643 18 100         FASTSETSVINT(arr[i], type == IARR_TYPE_POS, L[i]);
    100          
    50          
    100          
5644 7           Safefree(L);
5645 7           XSRETURN(1);
5646              
5647              
5648             void numtoperm(IN UV n, IN SV* svk)
5649             PREINIT:
5650             UV k;
5651             int i, S[32];
5652             PPCODE:
5653 6 100         if (n == 0)
5654 1           XSRETURN_EMPTY;
5655 5 50         if (n < 32 && _validate_and_set(&k, aTHX_ svk, IFLAG_ABS) == 1) {
    50          
5656 5 50         if (num_to_perm(k, n, S)) {
5657             dMY_CXT;
5658 5 50         EXTEND(SP, (EXTEND_TYPE)n);
    50          
5659 50 100         for (i = 0; i < (int)n; i++)
5660 45 50         PUSH_NPARITY( S[i] );
    50          
5661 5           XSRETURN(n);
5662             }
5663             }
5664 0           DISPATCHPP();
5665 0           XSRETURN(1);
5666              
5667             void permtonum(IN SV* svp)
5668             PREINIT:
5669             UV val, num;
5670             Size_t i, plen;
5671             DECL_ARREF(avp);
5672             PPCODE:
5673 6 50         USE_ARREF(avp, svp, SUBNAME, AR_READ);
    50          
    50          
5674 6           plen = len_avp;
5675 6 100         if (plen <= 20) {
5676 5           int V[21], A[21] = {0};
5677 47 100         for (i = 0; i < plen; i++) {
5678 42           SV *iv = FETCH_ARREF(avp,i);
5679 42 50         if (_validate_and_set(&val, aTHX_ iv, IFLAG_POS) != 1)
5680 0           break;
5681 42 50         if (val >= plen || A[val] != 0) break;
    50          
5682 42           A[val] = i+1;
5683 42           V[i] = val;
5684             }
5685 5 50         if (i >= plen && perm_to_num(plen, V, &num))
    100          
5686 4           XSRETURN_UV(num);
5687             }
5688 2           DISPATCHPP();
5689 2           objectify_result(aTHX_ svp, ST(0));
5690 2           XSRETURN(1);
5691              
5692             void randperm(IN UV n, IN UV k = 0)
5693             PREINIT:
5694             UV i, *S;
5695             dMY_CXT;
5696             PPCODE:
5697 75 100         if (items == 1) k = n;
5698 75 100         if (k > n) k = n;
5699 75 100         if (k == 0) XSRETURN_EMPTY;
5700 73 50         New(0, S, k, UV);
5701 73           randperm(MY_CXT.randcxt, n, k, S);
5702 73 50         EXTEND(SP, (EXTEND_TYPE)k);
    50          
5703 662 100         for (i = 0; i < k; i++) {
5704 589 100         if (n < 2*CINTS) PUSH_NPARITY(S[i]);
    50          
    100          
5705 106           else PUSHs(sv_2mortal(newSVuv(S[i])));
5706             }
5707 73           Safefree(S);
5708              
5709             void shuffle(...)
5710             PROTOTYPE: @
5711             PREINIT:
5712             SSize_t i, j;
5713             void* randcxt;
5714             dMY_CXT;
5715             PPCODE:
5716 31 100         if (items == 0)
5717 1           XSRETURN_EMPTY;
5718 713 100         for (i = 0, randcxt = MY_CXT.randcxt; i < items-1; i++) {
5719 683           j = urandomm64(randcxt, items-i);
5720 683           { SV* t = ST(i); ST(i) = ST(i+j); ST(i+j) = t; }
5721             }
5722 30           XSRETURN(items);
5723              
5724             void vecsample(IN SV* svk, ...)
5725             PROTOTYPE: $@
5726             PREINIT:
5727             void *randcxt;
5728             UV k;
5729             Size_t nitems, i;
5730             dMY_CXT;
5731             PPCODE:
5732 28 100         if (items == 1)
5733 6           XSRETURN_EMPTY;
5734 22           randcxt = MY_CXT.randcxt;
5735             /*
5736             * Fisher-Yates shuffle with first 'k' selections returned.
5737             *
5738             * There is only one algorithm here, no shortcuts other than
5739             * detecting an empty list.
5740             *
5741             * With a list input, the input is on the stack ST(1),ST(2),...
5742             * We move the last item to ST(0) then shuffle 'k' iterations.
5743             *
5744             * With an array reference input, we cannot modify the input at all.
5745             * We create an index array and shuffle using that. Remembering to
5746             * act like the last item is at the front so we match the list results.
5747             * We optimize by pushing each selection onto the return stack as
5748             * we find it rather than pushing them all at the end with another loop.
5749             */
5750 22 100         if (items > 2 || !SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV) {
    100          
    50          
5751             /* Standard form, where we are given an array of items */
5752 7           nitems = items-1;
5753 7 50         if (_validate_and_set(&k, aTHX_ svk, IFLAG_POS) == 0 || k > nitems)
    50          
5754 0           k = nitems;
5755 7           ST(0) = ST(items-1); /* Move last value to the first stack entry. */
5756 10019 100         for (i = 0; i < k; i++) {
5757 10012           uint32_t j = urandomm32(randcxt, nitems-i);
5758 10012           { SV* t = ST(i); ST(i) = ST(i+j); ST(i+j) = t; }
5759             }
5760             } else { /* We are given a single array reference. Select from it. */
5761             DECL_ARREF(avp);
5762 15 50         USE_ARREF(avp, ST(1), SUBNAME, AR_READ);
    50          
    50          
5763 15           nitems = len_avp;
5764              
5765 15 50         if (_validate_and_set(&k, aTHX_ svk, IFLAG_POS) == 0 || k > nitems)
    100          
5766 3           k = nitems;
5767 15 100         if (k == 0)
5768 3           XSRETURN_EMPTY;
5769 12 50         if (nitems < 65536) {
5770             uint16_t *I;
5771 12 50         New(0, I, nitems, uint16_t);
5772 85 100         I[0] = nitems-1; for (i = 1; i < nitems; i++) I[i] = i-1;
5773 12 50         EXTEND(SP, (EXTEND_TYPE)k);
    50          
5774 42 100         for (i = 0; i < k; i++) {
5775 30           uint32_t j = urandomm32(randcxt, nitems-i);
5776 30           uint16_t t = I[i+j]; I[i+j] = I[i];
5777 30           PUSHs(FETCH_ARREF(avp,t));
5778             }
5779 12           Safefree(I);
5780             } else {
5781             size_t *I;
5782 0 0         New(0, I, nitems, size_t);
5783 0 0         I[0] = nitems-1; for (i = 1; i < nitems; i++) I[i] = i-1;
5784 0 0         EXTEND(SP, (EXTEND_TYPE)k);
    0          
5785 0 0         for (i = 0; i < k; i++) {
5786 0           size_t j = urandomm64(randcxt, nitems-i);
5787 0           size_t t = I[i+j]; I[i+j] = I[i];
5788 0           PUSHs(FETCH_ARREF(avp,t));
5789             }
5790 0           Safefree(I);
5791             }
5792             }
5793 19           XSRETURN(k);
5794              
5795             void is_happy(SV* svn, UV base = 10, UV k = 2)
5796             PREINIT:
5797             UV n, sum;
5798             int h, status;
5799             PPCODE:
5800 4974 50         if (base < 2 || base > 36) croak("is_happy: invalid base %"UVuf, base);
    50          
5801 4974 50         if (k > 10) croak("is_happy: invalid exponent %"UVuf, k);
5802 4974           status = _validate_and_set(&n, aTHX_ svn, IFLAG_POS);
5803 4974 100         if (status == 0 && base == 10) { /* String op to reduce into range. */
    50          
5804             STRLEN i, len;
5805 14           const char* s = SvPV(svn, len);
5806 14 50         if (len <= UV_MAX/ipow(9,k)) {
5807 1316 100         for (sum = 0, i = 0; i < len; i++)
5808 1302           sum += ipow(s[i]-'0',k);
5809 14           h = happy_height(sum, base, k);
5810 14 50         RETURN_NPARITY( (h>0) ? h+1 : 0);
    50          
    50          
5811             }
5812             }
5813 4960 50         if (status != 0)
5814 4960 50         RETURN_NPARITY(happy_height(n, base, k));
    50          
5815 0           DISPATCHPP();
5816 0           XSRETURN(1);
5817              
5818             void
5819             sumdigits(SV* svn, UV ibase = 255)
5820             PREINIT:
5821             UV base, sum;
5822             STRLEN i, len;
5823             const char* s;
5824             PPCODE:
5825 1007 50         base = (ibase == 255) ? 10 : ibase;
5826 1007 50         if (base < 2 || base > 36) croak("sumdigits: invalid base %"UVuf, base);
    50          
5827 1007           sum = 0;
5828             /* faster for integer input in base 10 */
5829 1007 50         if (base == 10 && SVNUMTEST(svn) && (SvIsUV(svn) || SvIVX(svn) >= 0)) {
    100          
    50          
    100          
5830 1001           UV n, t = my_svuv(svn);
5831 3894 100         while ((n=t)) {
5832 2893           t = n / base;
5833 2893           sum += n - base*t;
5834             }
5835 1001           XSRETURN_UV(sum);
5836             }
5837 6           s = SvPV(svn, len);
5838             /* If no base given and input is 0x... or 0b..., select base. */
5839 6 50         if (ibase == 255 && len > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'b')){
    50          
    100          
    50          
    0          
5840 1 50         base = (s[1] == 'x') ? 16 : 2;
5841 1           s += 2;
5842 1           len -= 2;
5843             }
5844 38296 100         for (i = 0; i < len; i++) {
5845 38290           UV d = 0;
5846 38290           const char c = s[i];
5847 38290 100         if (c >= '0' && c <= '9') { d = c - '0'; }
    100          
5848 5 100         else if (c >= 'a' && c <= 'z') { d = c - 'a' + 10; }
    50          
5849 4 100         else if (c >= 'A' && c <= 'Z') { d = c - 'A' + 10; }
    50          
5850 38290 50         if (d < base)
5851 38290           sum += d;
5852             }
5853 6           XSRETURN_UV(sum);
5854              
5855             void todigits(SV* svn, int base=10, int length=-1)
5856             ALIAS:
5857             todigitstring = 1
5858             fromdigits = 2
5859             PREINIT:
5860             int i, status;
5861             UV n;
5862             char *str;
5863             PPCODE:
5864 293 50         if (base < 2) croak("%s: invalid base: %d", SUBNAME, base);
5865 293           status = 0;
5866 293 100         if (ix == 0 || ix == 1) {
    100          
5867 262           status = _validate_and_set(&n, aTHX_ svn, IFLAG_ABS);
5868             }
5869             /* todigits with native input */
5870 293 100         if (ix == 0 && status != 0 && length < 128) {
    100          
    50          
5871             int digits[128];
5872 158           IV len = to_digit_array(digits, n, base, length);
5873 158 50         if (len >= 0) {
5874             dMY_CXT;
5875 158 50         EXTEND(SP, (EXTEND_TYPE)len);
    50          
5876 3901 100         for (i = 0; i < len; i++)
5877 3743 50         PUSH_NPARITY( digits[len-i-1] );
    50          
5878 158           XSRETURN(len);
5879             }
5880             }
5881             /* todigitstring with native input */
5882 135 100         if (ix == 1 && status != 0 && length < 128) {
    100          
    50          
5883             char s[128+1];
5884 5           IV len = to_digit_string(s, n, base, length);
5885 5 50         if (len >= 0) {
5886 5 50         XPUSHs(sv_2mortal(newSVpv(s, len)));
5887 5           XSRETURN(1);
5888             }
5889             }
5890             /* todigits or todigitstring base 10 (large size) */
5891 130 100         if ((ix == 0 || ix == 1) && base == 10 && length < 0) {
    100          
    100          
    50          
5892             STRLEN len;
5893 1           str = SvPV(svn, len);
5894 1 50         if (ix == 1) {
5895 0 0         XPUSHs(sv_2mortal(newSVpv(str, len)));
5896 0           XSRETURN(1);
5897             }
5898 1 50         if (len == 1 && str[0] == '0') XSRETURN(0);
    0          
5899             {
5900             dMY_CXT;
5901 1 50         EXTEND(SP, (EXTEND_TYPE)len);
    50          
5902 46 100         for (i = 0; i < (int)len; i++)
5903 45 50         PUSH_NPARITY(str[i]-'0');
    50          
5904             }
5905 1           XSRETURN(len);
5906             }
5907 129 100         if (ix == 2) { /* fromdigits */
5908 31 100         if (!SvROK(svn)) { /* string */
5909 17 100         if (from_digit_string(&n, SvPV_nolen(svn), base)) {
5910 6           XSRETURN_UV(n);
5911             }
5912 14 50         } else if (!_is_sv_bigint(aTHX_ svn)) { /* array ref of digits */
5913 14           UV* r = 0;
5914 14           int len = arrayref_to_digit_array(aTHX_ &r, (AV*) SvRV(svn), base);
5915 14 100         if (from_digit_to_UV(&n, r, len, base)) {
5916 13           Safefree(r);
5917 14           XSRETURN_UV(n);
5918 1 50         } else if (from_digit_to_str(&str, r, len, base)){
5919 1           Safefree(r);
5920 1 50         XPUSHs( sv_to_bigint(aTHX_ sv_2mortal(newSVpv(str,0))) );
5921 1           Safefree(str);
5922 1           XSRETURN(1);
5923             }
5924 0           Safefree(r);
5925             }
5926             }
5927 109           DISPATCHPP();
5928 109 100         if (ix == 2) objectify_result(aTHX_ 0, ST(0));
5929 109           return;
5930              
5931             void tozeckendorf(SV* svn)
5932             PREINIT:
5933             UV n;
5934             PPCODE:
5935 28 100         if (_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) {
5936 27           char *str = to_zeckendorf(n);
5937 27 50         XPUSHs(sv_2mortal(newSVpv(str, 0)));
5938 27           Safefree(str);
5939 27           XSRETURN(1);
5940             }
5941 1           DISPATCHPP();
5942 1           XSRETURN(1);
5943              
5944             void fromzeckendorf(IN char* str)
5945             PREINIT:
5946             int status;
5947             PPCODE:
5948 27           status = validate_zeckendorf(str);
5949 27 50         if (status == 0)
5950 0           croak("fromzeckendorf: expected binary string");
5951 27 50         if (status == -1)
5952 0           croak("fromzeckendorf: expected binary string in canonical Zeckendorf form");
5953 27 100         if (status == 1)
5954 26           XSRETURN_UV(from_zeckendorf(str));
5955 1           DISPATCHPP();
5956 1           XSRETURN(1);
5957              
5958             void
5959             lastfor()
5960             PREINIT:
5961             dMY_CXT;
5962             PPCODE:
5963             /* printf("last for with count = %u\n", MY_CXT.forcount); */
5964 90 50         if (MY_CXT.forcount == 0) croak("lastfor called outside a loop");
5965 90           MY_CXT.forexit = 1;
5966             /* In some ideal world this would also act like a last */
5967 90           return;
5968              
5969             #define START_FORCOUNT \
5970             do { \
5971             oldforloop = ++MY_CXT.forcount; \
5972             oldforexit = MY_CXT.forexit; \
5973             forexit = &MY_CXT.forexit; \
5974             *forexit = 0; \
5975             } while(0)
5976              
5977             #define CHECK_FORCOUNT \
5978             if (*forexit) break;
5979              
5980             #define END_FORCOUNT \
5981             do { \
5982             /* Put back outer loop's exit request, if any. */ \
5983             *forexit = oldforexit; \
5984             /* Ensure loops are nested and not woven. */ \
5985             if (MY_CXT.forcount-- != oldforloop) croak("for loop mismatch"); \
5986             } while (0)
5987              
5988             #define DECL_FORCOUNT \
5989             uint16_t oldforloop; \
5990             char oldforexit; \
5991             char *forexit
5992              
5993             void
5994             forprimes (SV* block, IN SV* svbeg, IN SV* svend = 0)
5995             PROTOTYPE: &$;$
5996             PREINIT:
5997             SV* svarg;
5998             CV *subcv;
5999             unsigned char* segment;
6000             UV beg, end, seg_base, seg_low, seg_high;
6001             DECL_FORCOUNT;
6002             dMY_CXT;
6003             PPCODE:
6004 79 50         SETSUBREF(subcv, block);
6005              
6006 79 100         if (!_validate_and_set(&beg, aTHX_ svbeg, IFLAG_POS) ||
    100          
6007 35 50         (svend && !_validate_and_set(&end, aTHX_ svend, IFLAG_POS))) {
6008 2           DISPATCH_VOIDPP();
6009 2           XSRETURN(0);
6010             }
6011 69 100         if (!svend) { end = beg; beg = 2; }
6012              
6013 69           START_FORCOUNT;
6014 69           SAVESPTR(GvSV(PL_defgv));
6015 69           svarg = newSVuv(beg);
6016 69           GvSV(PL_defgv) = svarg;
6017             /* Handle early part */
6018             #if USE_MULTICALL
6019 69 50         if (!CvISXSUB(subcv) && beg <= end) {
    100          
6020             dMULTICALL;
6021 68           I32 gimme = G_VOID;
6022 68           DECL_MULTICALL_SCOPE(subcv);
6023 68 50         PUSH_MULTICALL(subcv);
6024 68 100         if (beg < 6) {
6025 47 100         beg = (beg <= 2) ? 2 : (beg <= 3) ? 3 : 5;
    100          
6026 168 100         for ( ; beg < 6 && beg <= end; beg += 1+(beg>2) ) {
    100          
    100          
6027 122 100         CHECK_FORCOUNT;
6028 121           sv_setuv(svarg, beg);
6029 121 50         SCOPED_MULTICALL;
    50          
6030             }
6031             }
6032 68 100         if (beg <= end) {
6033 60           if (
6034             #if BITS_PER_WORD == 64
6035 60 50         (beg >= UVCONST( 100000000000000) && end-beg < 100000) ||
    0          
6036 60 50         (beg >= UVCONST( 10000000000000) && end-beg < 40000) ||
    0          
6037 60 50         (beg >= UVCONST( 1000000000000) && end-beg < 17000) ||
    0          
6038             #endif
6039 60 100         ((end-beg) < 500) ) { /* MULTICALL next prime */
6040 306 100         for (beg = next_prime(beg-1); beg <= end && beg != 0; beg = next_prime(beg)) {
    50          
6041 274 100         CHECK_FORCOUNT;
6042 273           sv_setuv(svarg, beg);
6043 273 50         SCOPED_MULTICALL;
    50          
6044             }
6045             } else { /* MULTICALL segment sieve */
6046 27           void* ctx = start_segment_primes(beg, end, &segment);
6047 29 100         while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) {
6048 27 50         int crossuv = (seg_high > IV_MAX) && !SvIsUV(svarg);
    0          
6049 1310 50         START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_base, seg_low, seg_high )
    100          
    100          
    100          
    100          
6050 1261 100         CHECK_FORCOUNT;
6051             /* sv_setuv(svarg, p); */
6052 1147 100         if (SvTYPE(svarg) != SVt_IV) { sv_setuv(svarg, p); }
6053 982 50         else if (crossuv && p > IV_MAX) { sv_setuv(svarg, p); crossuv=0; }
    0          
6054 982           else { SvUV_set(svarg, p); }
6055 1147 50         SCOPED_MULTICALL;
    50          
6056 133           END_DO_FOR_EACH_SIEVE_PRIME
6057 27 100         CHECK_FORCOUNT;
6058             }
6059 27           end_segment_primes(ctx);
6060             }
6061             }
6062             FIX_MULTICALL_REFCOUNT;
6063 68 50         POP_MULTICALL;
6064             }
6065             else
6066             #endif
6067             {
6068 1 50         if (beg < 6) {
6069 1 50         beg = (beg <= 2) ? 2 : (beg <= 3) ? 3 : 5;
    0          
6070 1 0         for ( ; beg < 6 && beg <= end; beg += 1+(beg>2) ) {
    50          
    50          
6071 0           sv_setuv(svarg, beg);
6072 0 0         PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN;
6073 0 0         CHECK_FORCOUNT;
6074             }
6075             }
6076 1 50         if (beg <= end) { /* NO-MULTICALL segment sieve */
6077 0           void* ctx = start_segment_primes(beg, end, &segment);
6078 0 0         while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) {
6079 0 0         START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_base, seg_low, seg_high )
    0          
    0          
    0          
    0          
6080 0 0         CHECK_FORCOUNT;
6081 0           sv_setuv(svarg, p);
6082 0 0         PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN;
6083 0           END_DO_FOR_EACH_SIEVE_PRIME
6084 0 0         CHECK_FORCOUNT;
6085             }
6086 0           end_segment_primes(ctx);
6087             }
6088             }
6089 69           SvREFCNT_dec(svarg);
6090 69 50         END_FORCOUNT;
6091              
6092             #define FORCOMPTEST(ix,n) \
6093             ( (ix==1) || (ix==0 && n&1) )
6094              
6095             void
6096             foroddcomposites (SV* block, IN SV* svbeg, IN SV* svend = 0)
6097             ALIAS:
6098             forcomposites = 1
6099             PROTOTYPE: &$;$
6100             PREINIT:
6101             UV beg, end;
6102             SV* svarg; /* We use svarg to prevent clobbering $_ outside the block */
6103             CV *subcv;
6104             DECL_FORCOUNT;
6105             dMY_CXT;
6106             PPCODE:
6107 61 50         SETSUBREF(subcv, block);
6108              
6109 61 100         if (!_validate_and_set(&beg, aTHX_ svbeg, IFLAG_POS) ||
    100          
6110 2 50         (svend && !_validate_and_set(&end, aTHX_ svend, IFLAG_POS))) {
6111 2           DISPATCH_VOIDPP();
6112 2           XSRETURN(0);
6113             }
6114 59 100         if (!svend) { end = beg; beg = ix ? 4 : 9; }
    100          
6115              
6116 59           START_FORCOUNT;
6117 59           SAVESPTR(GvSV(PL_defgv));
6118 59           svarg = newSVuv(0);
6119 59           GvSV(PL_defgv) = svarg;
6120             #if USE_MULTICALL
6121 59 50         if (!CvISXSUB(subcv) && end >= beg) {
    100          
6122             unsigned char* segment;
6123             UV seg_base, seg_low, seg_high, c, cbeg, cend, cinc, prevprime, nextprime;
6124             void* ctx;
6125             dMULTICALL;
6126 57           I32 gimme = G_VOID;
6127 57           DECL_MULTICALL_SCOPE(subcv);
6128 57 50         PUSH_MULTICALL(subcv);
6129 57 50         if (beg >= MPU_MAX_PRIME ||
6130             #if BITS_PER_WORD == 64
6131 57 50         (beg >= UVCONST( 100000000000000) && end-beg < 120000) ||
    0          
6132 57 50         (beg >= UVCONST( 10000000000000) && end-beg < 50000) ||
    0          
6133 57 50         (beg >= UVCONST( 1000000000000) && end-beg < 20000) ||
    0          
6134             #endif
6135 57 100         end-beg < 1000 ) {
6136 55           beg = (beg <= 4) ? 3 : beg-1;
6137 55           nextprime = next_prime(beg);
6138 3933 100         while (beg++ < end) {
6139 3928 100         if (beg == nextprime)
6140 907           nextprime = next_prime(beg);
6141 3021 100         else if (FORCOMPTEST(ix,beg)) {
    50          
    100          
6142 1716           sv_setuv(svarg, beg);
6143 1716 50         SCOPED_MULTICALL;
    50          
6144             }
6145 3928 100         CHECK_FORCOUNT;
6146             }
6147             } else {
6148 2 100         if (!ix) {
6149 1 50         if (beg < 8) beg = 8;
6150 1 50         } else if (beg <= 4) { /* sieve starts at 7, so handle this here */
6151 1           sv_setuv(svarg, 4);
6152 1 50         SCOPED_MULTICALL;
    50          
6153 1           beg = 6;
6154             }
6155             /* Find the two primes that bound their interval. */
6156             /* beg must be < max_prime, and end >= max_prime is special. */
6157 2           prevprime = prev_prime(beg);
6158 2 50         nextprime = (end >= MPU_MAX_PRIME) ? MPU_MAX_PRIME : next_prime(end);
6159 2           ctx = start_segment_primes(beg, nextprime, &segment);
6160 4 100         while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) {
6161 2 50         int crossuv = (seg_high > IV_MAX) && !SvIsUV(svarg);
    0          
6162 9083 50         START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_base, seg_low, seg_high )
    100          
    100          
    100          
    100          
6163 8726           cbeg = prevprime+1;
6164 8726 100         if (cbeg < beg)
6165 1 50         cbeg = beg - (ix == 0 && (beg % 2));
    50          
6166 8726           prevprime = p;
6167 8726 100         cend = prevprime-1; if (cend > end) cend = end;
6168             /* If ix=0, skip evens by starting 1 farther and skipping by 2 */
6169 8726 100         cinc = 1 + (ix==0);
6170 36294 100         for (c = cbeg + (ix==0); c <= cend; c += cinc) {
6171 29528 100         CHECK_FORCOUNT;
6172 27568 50         if (SvTYPE(svarg) != SVt_IV) { sv_setuv(svarg,c); }
6173 27568 50         else if (crossuv && c > IV_MAX) { sv_setuv(svarg,c); crossuv=0;}
    0          
6174 27568           else { SvUV_set(svarg,c); }
6175 27568 50         SCOPED_MULTICALL;
    50          
6176             }
6177 354           END_DO_FOR_EACH_SIEVE_PRIME
6178             }
6179 2           end_segment_primes(ctx);
6180 2 50         if (end > nextprime) /* Complete the case where end > max_prime */
6181 0 0         while (nextprime++ < end)
6182 0 0         if (FORCOMPTEST(ix,nextprime)) {
    0          
    0          
6183 0 0         CHECK_FORCOUNT;
6184 0           sv_setuv(svarg, nextprime);
6185 0 0         SCOPED_MULTICALL;
    0          
6186             }
6187             }
6188             FIX_MULTICALL_REFCOUNT;
6189 57 50         POP_MULTICALL;
6190             }
6191             else
6192             #endif
6193 2 50         if (beg <= end) {
6194 0           beg = (beg <= 4) ? 3 : beg-1;
6195 0 0         while (beg++ < end) {
6196 0 0         if (FORCOMPTEST(ix,beg) && !is_prob_prime(beg)) {
    0          
    0          
    0          
6197 0           sv_setuv(svarg, beg);
6198 0 0         PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN;
6199 0 0         CHECK_FORCOUNT;
6200             }
6201             }
6202             }
6203 59           SvREFCNT_dec(svarg);
6204 59 50         END_FORCOUNT;
6205              
6206             void
6207             forsemiprimes (SV* block, IN SV* svbeg, IN SV* svend = 0)
6208             PROTOTYPE: &$;$
6209             PREINIT:
6210             UV beg, end;
6211             SV* svarg; /* We use svarg to prevent clobbering $_ outside the block */
6212             CV *subcv;
6213             DECL_FORCOUNT;
6214             dMY_CXT;
6215             PPCODE:
6216 2 50         SETSUBREF(subcv, block);
6217              
6218 2 100         if (!_validate_and_set(&beg, aTHX_ svbeg, IFLAG_POS) ||
    50          
6219 0 0         (svend && !_validate_and_set(&end, aTHX_ svend, IFLAG_POS))) {
6220 1           DISPATCH_VOIDPP();
6221 1           XSRETURN(0);
6222             }
6223 1 50         if (!svend) { end = beg; beg = 4; }
6224              
6225 1 50         if (beg < 4) beg = 4;
6226 1 50         if (end > MPU_MAX_SEMI_PRIME) end = MPU_MAX_SEMI_PRIME;
6227              
6228 1           START_FORCOUNT;
6229 1           SAVESPTR(GvSV(PL_defgv));
6230 1           svarg = newSVuv(0);
6231 1           GvSV(PL_defgv) = svarg;
6232             #if USE_MULTICALL
6233 1 50         if (!CvISXSUB(subcv) && end >= beg) {
    50          
6234             UV c, seg_beg, seg_end, *S, count;
6235             dMULTICALL;
6236 1           I32 gimme = G_VOID;
6237 1           DECL_MULTICALL_SCOPE(subcv);
6238 1 50         PUSH_MULTICALL(subcv);
6239 1 50         if (beg >= MPU_MAX_SEMI_PRIME ||
6240             #if BITS_PER_WORD == 64
6241 1 50         (beg >= UVCONST(10000000000000000000) && end-beg < 1400000) ||
    0          
6242 1 50         (beg >= UVCONST( 1000000000000000000) && end-beg < 950000) ||
    0          
6243 1 50         (beg >= UVCONST( 100000000000000000) && end-beg < 440000) ||
    0          
6244 1 50         (beg >= UVCONST( 10000000000000000) && end-beg < 240000) ||
    0          
6245 1 50         (beg >= UVCONST( 1000000000000000) && end-beg < 65000) ||
    0          
6246 1 50         (beg >= UVCONST( 100000000000000) && end-beg < 29000) ||
    0          
6247 1 50         (beg >= UVCONST( 10000000000000) && end-beg < 11000) ||
    0          
6248 1 50         (beg >= UVCONST( 1000000000000) && end-beg < 5000) ||
    0          
6249             #endif
6250 1 50         end-beg < 200 ) {
6251 0 0         for (c = beg; c <= end && c >= beg; c++) {
    0          
6252 0 0         if (is_semiprime(c)) {
6253 0           sv_setuv(svarg, c);
6254 0 0         SCOPED_MULTICALL;
    0          
6255             }
6256 0 0         CHECK_FORCOUNT;
6257             }
6258             } else {
6259 2 100         while (beg < end) {
6260 1           seg_beg = beg;
6261 1           seg_end = end;
6262 1 50         if ((seg_end - seg_beg) > 50000000) seg_end = seg_beg + 50000000 - 1;
6263 1           count = range_semiprime_sieve(&S, seg_beg, seg_end);
6264 300 100         for (c = 0; c < count; c++) {
6265 299           sv_setuv(svarg, S[c]);
6266 299 50         SCOPED_MULTICALL;
    50          
6267 299 50         CHECK_FORCOUNT;
6268             }
6269 1           Safefree(S);
6270 1           beg = seg_end+1;
6271 1 50         CHECK_FORCOUNT;
6272             }
6273             }
6274             FIX_MULTICALL_REFCOUNT;
6275 1 50         POP_MULTICALL;
6276             }
6277             else
6278             #endif
6279 0 0         if (beg <= end) {
6280 0           beg = (beg <= 4) ? 3 : beg-1;
6281 0 0         while (beg++ < end) {
6282 0 0         if (is_semiprime(beg)) {
6283 0           sv_setuv(svarg, beg);
6284 0 0         PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN;
6285 0 0         CHECK_FORCOUNT;
6286             }
6287             }
6288             }
6289 1           SvREFCNT_dec(svarg);
6290 1 50         END_FORCOUNT;
6291              
6292             void
6293             foralmostprimes (SV* block, IN UV k, IN SV* svbeg, IN SV* svend = 0)
6294             PROTOTYPE: &$$;$
6295             PREINIT:
6296             UV c, beg, end, shiftres;
6297             SV* svarg; /* We use svarg to prevent clobbering $_ outside the block */
6298             CV *subcv;
6299             DECL_FORCOUNT;
6300             dMY_CXT;
6301             PPCODE:
6302 12 50         SETSUBREF(subcv, block);
6303              
6304 12 100         if (!_validate_and_set(&beg, aTHX_ svbeg, IFLAG_POS) ||
    100          
6305 1 50         (svend && !_validate_and_set(&end, aTHX_ svend, IFLAG_POS))) {
6306 1           DISPATCH_VOIDPP();
6307 1           XSRETURN(0);
6308             }
6309 11 100         if (!svend) { end = beg; beg = 1; }
6310              
6311             /* If k is over 63 but the beg/end points are UVs, then we're empty. */
6312 11 100         if (k == 0 || k >= BITS_PER_WORD) XSRETURN(0);
    50          
6313              
6314 10 50         if (beg < (UVCONST(1) << k)) beg = UVCONST(1) << k;
6315 10 50         if (end > max_nth_almost_prime(k)) end = max_nth_almost_prime(k);
6316 10 100         if (beg > end) XSRETURN(0);
6317              
6318             /* We might be able to reduce the k value. */
6319 9           shiftres = 0;
6320 9 50         if (k > MPU_MAX_POW3)
6321 0           shiftres = k - MPU_MAX_POW3;
6322 24 100         while ((k-shiftres) > 1 && (end >> shiftres) < ipow(3, k - shiftres))
    100          
6323 15           shiftres++;
6324 9           beg = (beg >> shiftres) + (((beg >> shiftres) << shiftres) < beg);
6325 9           end = end >> shiftres;
6326 9           k -= shiftres;
6327             /* k <= 40 (64-bit) or 20 (32-bit). */
6328              
6329 9           START_FORCOUNT;
6330 9           SAVESPTR(GvSV(PL_defgv));
6331 9           svarg = newSVuv(0);
6332 9           GvSV(PL_defgv) = svarg;
6333             #if USE_MULTICALL
6334 9 50         if (!CvISXSUB(subcv) && end >= beg) {
    50          
6335 9           UV seg_beg, seg_end, *S, count, k3 = ipow(3,k);
6336             dMULTICALL;
6337 9           I32 gimme = G_VOID;
6338 9           DECL_MULTICALL_SCOPE(subcv);
6339 9 50         PUSH_MULTICALL(subcv);
6340 18 100         while (beg <= end) {
6341             /* TODO: Tuning this better would be nice */
6342 9           UV ssize = 65536 * 256;
6343 9           seg_beg = beg;
6344 9           seg_end = end;
6345 9 50         if (k > 12) ssize *= 16;
6346 9 50         if (k > 18 || seg_beg > 9*k3) ssize *= 4;
    50          
6347 9 50         if (k > 24 || seg_beg > 81*k3) ssize *= 3;
    50          
6348 9 50         if ((seg_end - seg_beg) > ssize) seg_end = seg_beg + ssize - 1;
6349 9           count = generate_almost_primes(&S, k, seg_beg, seg_end);
6350 1008 100         for (c = 0; c < count; c++) {
6351 999           sv_setuv(svarg, S[c] << shiftres);
6352 999 50         SCOPED_MULTICALL;
    50          
6353 999 50         CHECK_FORCOUNT;
6354             }
6355 9           Safefree(S);
6356 9 50         if (seg_end == UV_MAX) break;
6357 9           beg = seg_end+1;
6358 9 50         CHECK_FORCOUNT;
6359             }
6360             FIX_MULTICALL_REFCOUNT;
6361 9 50         POP_MULTICALL;
6362             }
6363             else
6364             #endif
6365 0 0         if (beg <= end) {
6366 0 0         for (c = beg; c <= end && c >= beg; c++) {
    0          
6367 0 0         if (is_almost_prime(k,c)) {
6368 0           sv_setuv(svarg, c << shiftres);
6369 0 0         PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN;
6370 0 0         CHECK_FORCOUNT;
6371             }
6372             }
6373             }
6374 9           SvREFCNT_dec(svarg);
6375 9 50         END_FORCOUNT;
6376              
6377             void
6378             fordivisors (SV* block, IN SV* svn)
6379             PROTOTYPE: &$
6380             PREINIT:
6381             UV i, n, ndivisors;
6382             UV *divs;
6383             SV* svarg; /* We use svarg to prevent clobbering $_ outside the block */
6384             CV *subcv;
6385             DECL_FORCOUNT;
6386             dMY_CXT;
6387             PPCODE:
6388 72 50         SETSUBREF(subcv, block);
6389              
6390 72 100         if (!_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) {
6391 1           DISPATCH_VOIDPP();
6392 1           XSRETURN(0);
6393             }
6394              
6395 71           divs = divisor_list(n, &ndivisors, UV_MAX);
6396              
6397 71           START_FORCOUNT;
6398 71           SAVESPTR(GvSV(PL_defgv));
6399 71           svarg = newSVuv(0);
6400 71           GvSV(PL_defgv) = svarg;
6401             #if USE_MULTICALL
6402 71 50         if (!CvISXSUB(subcv)) {
6403             dMULTICALL;
6404 71           I32 gimme = G_VOID;
6405 71           DECL_MULTICALL_SCOPE(subcv);
6406 71 50         PUSH_MULTICALL(subcv);
6407 336 100         for (i = 0; i < ndivisors; i++) {
6408 272           sv_setuv(svarg, divs[i]);
6409 272 50         SCOPED_MULTICALL;
    50          
6410 272 100         CHECK_FORCOUNT;
6411             }
6412             FIX_MULTICALL_REFCOUNT;
6413 71 50         POP_MULTICALL;
6414             }
6415             else
6416             #endif
6417             {
6418 0 0         for (i = 0; i < ndivisors; i++) {
6419 0           sv_setuv(svarg, divs[i]);
6420 0 0         PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN;
6421 0 0         CHECK_FORCOUNT;
6422             }
6423             }
6424 71           SvREFCNT_dec(svarg);
6425 71           Safefree(divs);
6426 71 50         END_FORCOUNT;
6427              
6428             void
6429             forpart (SV* block, IN SV* svn, IN SV* svh = 0)
6430             ALIAS:
6431             forcomp = 1
6432             PROTOTYPE: &$;$
6433             PREINIT:
6434             UV i, n, amin, amax, nmin, nmax;
6435             int primeq;
6436             CV *subcv;
6437             SV** svals;
6438             DECL_FORCOUNT;
6439             dMY_CXT;
6440             PPCODE:
6441 44 50         SETSUBREF(subcv, block);
6442 44 50         if (!_validate_and_set(&n, aTHX_ svn, IFLAG_POS)) {
6443 0           DISPATCH_VOIDPP();
6444 0           XSRETURN(0);
6445             }
6446 44 50         if (n > (UV_MAX-2)) croak("%s: argument overflow", SUBNAME);
6447              
6448 44 50         New(0, svals, n+1, SV*);
6449 782 100         for (i = 0; i <= n; i++) {
6450 738           svals[i] = newSVuv(i);
6451 738           SvREADONLY_on(svals[i]);
6452             }
6453              
6454 44           amin = 1; amax = n; nmin = 1; nmax = n; primeq = -1;
6455 44 100         if (svh != 0) {
6456             HV* rhash;
6457             SV** svp;
6458 16 50         if (!SvROK(svh) || SvTYPE(SvRV(svh)) != SVt_PVHV)
    50          
6459 0           croak("%s: expected hash reference", SUBNAME);
6460 16           rhash = (HV*) SvRV(svh);
6461 16 100         if ((svp = hv_fetchs(rhash, "n", 0)) != NULL)
6462 8           { nmin = my_svuv(*svp); nmax = nmin; }
6463 16 100         if ((svp = hv_fetchs(rhash, "amin", 0)) != NULL) amin = my_svuv(*svp);
6464 16 100         if ((svp = hv_fetchs(rhash, "amax", 0)) != NULL) amax = my_svuv(*svp);
6465 16 100         if ((svp = hv_fetchs(rhash, "nmin", 0)) != NULL) nmin = my_svuv(*svp);
6466 16 100         if ((svp = hv_fetchs(rhash, "nmax", 0)) != NULL) nmax = my_svuv(*svp);
6467 16 100         if ((svp = hv_fetchs(rhash, "prime",0)) != NULL) primeq=my_svuv(*svp);
6468              
6469 16 50         if (amin < 1) amin = 1;
6470 16 50         if (amax > n) amax = n;
6471 16 50         if (nmin < 1) nmin = 1;
6472 16 50         if (nmax > n) nmax = n;
6473 16 100         if (primeq != 0 && primeq != -1) primeq = 1; /* -1, 0, or 1 */
    100          
6474             }
6475              
6476 44 100         if (primeq == 1) {
6477 2           UV prev = prev_prime(amax+1);
6478 2 100         UV next = amin <= 2 ? 2 : next_prime(amin-1);
6479 2 50         if (amin < next) amin = next;
6480 2 50         if (amax > prev) amax = prev;
6481             }
6482              
6483 44 100         if (n==0 && nmin <= 1) {
    50          
6484             /* Nothing */
6485 2 50         PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN;
6486             }
6487 44 100         if (n >= nmin && nmin <= nmax && amin <= amax && nmax > 0 && amax > 0)
    50          
    100          
    50          
    50          
6488             { /* RuleAsc algorithm from Kelleher and O'Sullivan 2009/2014) */
6489             UV *a, k, x, y, r;
6490 41 50         New(0, a, n+1, UV);
6491 41           k = 1;
6492 41           a[0] = amin-1;
6493 41           a[1] = n-amin+1;
6494 41           START_FORCOUNT;
6495 16008 100         while (k != 0) {
6496 15981           x = a[k-1]+1;
6497 15981           y = a[k]-1;
6498 15981           k--;
6499 15981 100         r = (ix == 0) ? x : 1;
6500 36483 100         while (r <= y) {
6501 20502           a[k++] = x;
6502 20502           x = r;
6503 20502           y -= x;
6504             }
6505 15981           a[k] = x + y;
6506              
6507             /* ------ length restrictions ------ */
6508 20529 100         while (k+1 > nmax) { /* Skip range if over max size */
6509 4548           a[k-1] += a[k];
6510 4548           k--;
6511             }
6512             /* Look into: quick skip over nmin range */
6513 15981 100         if (k+1 < nmin) { /* Skip if not over min size */
6514 3617 100         if (a[0] >= n-nmin+1 && a[k] > 1) break; /* early exit check */
    50          
6515 3608           continue;
6516             }
6517              
6518             /* ------ value restrictions ------ */
6519 12364 100         if (amin > 1 || amax < n) {
    100          
6520             /* Lexical order allows us to start at amin, and exit early */
6521 3452 100         if (a[0] > amax) break;
6522              
6523 3449 100         if (ix == 0) { /* value restrictions for partitions */
6524 3428 100         if (a[k] > amax) continue;
6525             } else { /* restrictions for compositions */
6526             /* TODO: maybe skip forward? */
6527 58 100         for (i = 0; i <= k; i++)
6528 51 100         if (a[i] < amin || a[i] > amax)
    100          
6529             break;
6530 21 100         if (i <= k) continue;
6531             }
6532             }
6533 11769 100         if (primeq != -1) {
6534 3791 100         for (i = 0; i <= k; i++) if (is_prime(a[i]) != primeq) break;
    100          
6535 2602 100         if (i <= k) continue;
6536             }
6537              
6538 9259 50         PUSHMARK(SP); EXTEND(SP, (EXTEND_TYPE)k+1);
    50          
    50          
6539 85795 100         for (i = 0; i <= k; i++) { PUSHs(svals[a[i]]); }
6540 9259           PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN;
6541 9259 100         CHECK_FORCOUNT;
6542             }
6543 41           Safefree(a);
6544 41 50         END_FORCOUNT;
6545             }
6546 782 100         for (i = 0; i <= n; i++)
6547 738           SvREFCNT_dec(svals[i]);
6548 44           Safefree(svals);
6549              
6550             void
6551             forcomb (SV* block, IN SV* svn, IN SV* svk = 0)
6552             ALIAS:
6553             forperm = 1
6554             forderange = 2
6555             PROTOTYPE: &$;$
6556             PREINIT:
6557             UV i, n, k, begk, endk;
6558             CV *subcv;
6559             SV** svals;
6560             UV* cm;
6561             DECL_FORCOUNT;
6562             dMY_CXT;
6563             PPCODE:
6564 34 50         SETSUBREF(subcv, block);
6565 34 100         if (ix > 0 && svk != 0)
    50          
6566 0           croak("%s: too many arguments", SUBNAME);
6567              
6568 34 50         if (!_validate_and_set(&n, aTHX_ svn, IFLAG_POS) ||
    100          
6569 17 50         (svk && !_validate_and_set(&k, aTHX_ svk, IFLAG_POS))) {
6570 0           DISPATCH_VOIDPP();
6571 0           XSRETURN(0);
6572             }
6573              
6574 34 100         if (svk == 0) {
6575 17 100         begk = (ix == 0) ? 0 : n;
6576 17           endk = n;
6577             } else {
6578 17           begk = endk = k;
6579 17 100         if (begk > n)
6580 1           XSRETURN(0);
6581             }
6582              
6583 33 50         New(0, svals, n, SV*);
6584 167 100         for (i = 0; i < n; i++) {
6585 134           svals[i] = newSVuv(i);
6586 134           SvREADONLY_on(svals[i]);
6587             }
6588 33 50         New(0, cm, endk+1, UV);
6589              
6590 33           START_FORCOUNT;
6591             #if USE_MULTICALL
6592 33 50         if (!CvISXSUB(subcv)) {
6593             dMULTICALL;
6594 33           I32 gimme = G_VOID;
6595 33           DECL_MULTICALL_SCOPE(subcv);
6596 33           AV *av = save_ary(PL_defgv);
6597 33           AvREAL_off(av);
6598 33 50         PUSH_MULTICALL(subcv);
6599 69 100         for (k = begk; k <= endk; k++) {
6600 39           _comb_init(cm, k, ix == 2);
6601             while (1) {
6602 22537 100         if (ix < 2 || k != 1) {
    100          
6603             IV j;
6604 22536           av_extend(av, k-1);
6605 22536           av_fill(av, k-1);
6606 303801 100         for (j = k-1; j >= 0; j--)
6607 281265           AvARRAY(av)[j] = svals[ cm[k-j-1]-1 ];
6608 22536 50         SCOPED_MULTICALL;
    50          
6609             }
6610 22537 100         CHECK_FORCOUNT;
6611 22534 100         if (_comb_iterate(cm, k, n, ix)) break;
6612             }
6613 39 100         CHECK_FORCOUNT;
6614             }
6615             FIX_MULTICALL_REFCOUNT;
6616 33 50         POP_MULTICALL;
6617             } else
6618             #endif
6619             {
6620 0 0         for (k = begk; k <= endk; k++) {
6621 0           _comb_init(cm, k, ix == 2);
6622             while (1) {
6623 0 0         if (ix < 2 || k != 1) {
    0          
6624 0 0         PUSHMARK(SP); EXTEND(SP, (EXTEND_TYPE)k);
    0          
    0          
6625 0 0         for (i = 0; i < k; i++) { PUSHs(svals[ cm[k-i-1]-1 ]); }
6626 0           PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN;
6627             }
6628 0 0         CHECK_FORCOUNT;
6629 0 0         if (_comb_iterate(cm, k, n, ix)) break;
6630             }
6631 0 0         CHECK_FORCOUNT;
6632             }
6633             }
6634              
6635 33           Safefree(cm);
6636 167 100         for (i = 0; i < n; i++)
6637 134           SvREFCNT_dec(svals[i]);
6638 33           Safefree(svals);
6639 33 50         END_FORCOUNT;
6640              
6641             void forsetproduct (SV* block, ...)
6642             PROTOTYPE: &@
6643             PREINIT:
6644             SSize_t narrays, i, j, *arlen, *arcnt;
6645             SV ***arsvs;
6646             CV *subcv;
6647             DECL_FORCOUNT;
6648             dMY_CXT;
6649             PPCODE:
6650 9 50         SETSUBREF(subcv, block);
6651              
6652 9           narrays = items-1;
6653 9 100         if (narrays < 1) XSRETURN(0);
6654              
6655 22 100         for (i = 1; i <= narrays; i++) {
6656 17 50         SvGETMAGIC(ST(i));
    0          
6657 17 100         CHECK_ARRAYREF(ST(i));
    50          
6658 16 100         if (av_count((AV *)SvRV(ST(i))) == 0)
6659 2           XSRETURN(0);
6660             }
6661              
6662 5 50         Newz(0, arcnt, narrays, SSize_t);
6663 5 50         New(0, arlen, narrays, SSize_t);
6664 5 50         New(0, arsvs, narrays, SV**);
6665             /* Make local copies of the SV pointers. Allows magic/tied inputs. */
6666 17 100         for (i = 0; i < narrays; i++) {
6667             DECL_ARREF(inav);
6668 12 50         USE_ARREF(inav, ST(i+1), SUBNAME, AR_READ);
    50          
    50          
6669 12           arlen[i] = len_inav;
6670 12 50         New(0, arsvs[i], len_inav, SV*);
6671 35 100         for (j = 0; j < (SSize_t)len_inav; j++) {
6672 23           SV* v = FETCH_ARREF(inav,j);
6673 23 50         arsvs[i][j] = v ? v : &PL_sv_undef;
6674             }
6675             }
6676 5           START_FORCOUNT;
6677             #if USE_MULTICALL
6678 5 50         if (!CvISXSUB(subcv)) {
6679             dMULTICALL;
6680             SV **arr;
6681 5           I32 gimme = G_VOID;
6682 5           DECL_MULTICALL_SCOPE(subcv);
6683 5           AV *av = save_ary(PL_defgv);
6684 5           AvREAL_off(av);
6685 5 50         PUSH_MULTICALL(subcv);
6686             do {
6687 22           av_fill(av, narrays-1);
6688 22           arr = AvARRAY(av);
6689 66 100         for (i = narrays-1; i >= 0; i--) /* Faster to fill backwards */
6690 44           arr[i] = arsvs[i][arcnt[i]];
6691 22 50         SCOPED_MULTICALL;
    50          
6692 22 50         CHECK_FORCOUNT;
6693 37 100         for (i = narrays-1; i >= 0; i--) {
6694 32 100         if (++arcnt[i] >= arlen[i]) arcnt[i] = 0;
6695 17           else break;
6696             }
6697 22 100         } while (i >= 0);
6698             FIX_MULTICALL_REFCOUNT;
6699 5 50         POP_MULTICALL;
6700             }
6701             else
6702             #endif
6703             do {
6704 0 0         PUSHMARK(SP); EXTEND(SP, (EXTEND_TYPE)narrays);
    0          
    0          
6705 0 0         for (i = 0; i < narrays; i++) { PUSHs(arsvs[i][arcnt[i]]); }
6706 0           PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN;
6707 0 0         CHECK_FORCOUNT;
6708 0 0         for (i = narrays-1; i >= 0; i--) {
6709 0 0         if (++arcnt[i] >= arlen[i]) arcnt[i] = 0;
6710 0           else break;
6711             }
6712 0 0         } while (i >= 0);
6713              
6714 17 100         for (i = 0; i < narrays; i++)
6715 12           Safefree(arsvs[i]);
6716 5           Safefree(arsvs);
6717 5           Safefree(arlen);
6718 5           Safefree(arcnt);
6719 5 50         END_FORCOUNT;
6720              
6721             void
6722             forfactored (SV* block, IN SV* svbeg, IN SV* svend = 0)
6723             ALIAS:
6724             forsquarefree = 1
6725             PROTOTYPE: &$;$
6726             PREINIT:
6727             UV beg, end, n, *factors;
6728             int i, nfactors, maxfactors;
6729             factor_range_context_t fctx;
6730             SV* svarg; /* We use svarg to prevent clobbering $_ outside the block */
6731             CV *subcv;
6732             SV* svals[64];
6733             DECL_FORCOUNT;
6734             dMY_CXT;
6735             PPCODE:
6736 14 50         SETSUBREF(subcv, block);
6737              
6738 14 100         if (!_validate_and_set(&beg, aTHX_ svbeg, IFLAG_POS) ||
    100          
6739 6 50         (svend && !_validate_and_set(&end, aTHX_ svend, IFLAG_POS))) {
6740 4           DISPATCH_VOIDPP();
6741 4           XSRETURN(0);
6742             }
6743 10 100         if (!svend) { end = beg; beg = 1; }
6744 10 100         if (beg < 1) beg = 1;
6745 10 100         if (beg > end) XSRETURN(0);
6746              
6747 77 100         for (maxfactors = 0, n = end >> 1; n; n >>= 1)
6748 69           maxfactors++;
6749 77 100         for (i = 0; i < maxfactors; i++) {
6750 69           svals[i] = newSVuv(UV_MAX);
6751 69           SvREADONLY_on(svals[i]);
6752             }
6753              
6754 8           START_FORCOUNT;
6755 8           SAVESPTR(GvSV(PL_defgv));
6756 8           svarg = newSVuv(0);
6757 8           GvSV(PL_defgv) = svarg;
6758 8 100         if (beg <= 1) {
6759 6           sv_setuv(svarg, 1);
6760 6 50         PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN;
6761 6           beg = 2;
6762             }
6763 8           fctx = factor_range_init(beg, end, ix);
6764             #if USE_MULTICALL
6765 8 50         if (!CvISXSUB(subcv)) {
6766             dMULTICALL;
6767 8           I32 gimme = G_VOID;
6768 8           DECL_MULTICALL_SCOPE(subcv);
6769 8           AV *av = save_ary(PL_defgv);
6770 8           AvREAL_off(av);
6771 8 50         PUSH_MULTICALL(subcv);
6772 2995 100         for (n = 0; n < end-beg+1; n++) {
6773 2987 50         CHECK_FORCOUNT;
6774 2987           nfactors = factor_range_next(&fctx);
6775 2987 100         if (nfactors > 0) {
6776 1863           sv_setuv(svarg, fctx.n);
6777 1863           factors = fctx.factors;
6778 1863           av_extend(av, nfactors-1);
6779 1863           av_fill(av, nfactors-1);
6780 6499 100         for (i = nfactors-1; i >= 0; i--) {
6781 4636           SV* sv = svals[i];
6782 4636           SvREADONLY_off(sv);
6783 4636           sv_setuv(sv, factors[i]);
6784 4636           SvREADONLY_on(sv);
6785 4636           AvARRAY(av)[i] = sv;
6786             }
6787 1863 50         SCOPED_MULTICALL;
    50          
6788             }
6789             }
6790             FIX_MULTICALL_REFCOUNT;
6791 8 50         POP_MULTICALL;
6792             }
6793             else
6794             #endif
6795 0 0         for (n = 0; n < end-beg+1; n++) {
6796 0 0         CHECK_FORCOUNT;
6797 0           nfactors = factor_range_next(&fctx);
6798 0 0         if (nfactors > 0) {
6799 0 0         PUSHMARK(SP); EXTEND(SP, (EXTEND_TYPE)nfactors);
    0          
    0          
6800 0           sv_setuv(svarg, fctx.n);
6801 0           factors = fctx.factors;
6802 0 0         for (i = 0; i < nfactors; i++) {
6803 0           SV* sv = svals[i];
6804 0           SvREADONLY_off(sv);
6805 0           sv_setuv(sv, factors[i]);
6806 0           SvREADONLY_on(sv);
6807 0           PUSHs(sv);
6808             }
6809 0           PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN;
6810             }
6811             }
6812 8           factor_range_destroy(&fctx);
6813 8           SvREFCNT_dec(svarg);
6814 77 100         for (i = 0; i < maxfactors; i++)
6815 69           SvREFCNT_dec(svals[i]);
6816 8 50         END_FORCOUNT;
6817              
6818             void forsquarefreeint(SV* block, IN SV* svbeg, IN SV* svend = 0)
6819             PROTOTYPE: &$;$
6820             PREINIT:
6821             UV beg, end, i;
6822             unsigned char* isf;
6823             SV* svarg; /* We use svarg to prevent clobbering $_ outside the block */
6824             CV *subcv;
6825             DECL_FORCOUNT;
6826             dMY_CXT;
6827             PPCODE:
6828 5 50         SETSUBREF(subcv, block);
6829              
6830 5 100         if (!_validate_and_set(&beg, aTHX_ svbeg, IFLAG_POS) ||
    100          
6831 3 50         (svend && !_validate_and_set(&end, aTHX_ svend, IFLAG_POS))) {
6832 1           DISPATCH_VOIDPP();
6833 1           XSRETURN(0);
6834             }
6835 4 100         if (!svend) { end = beg; beg = 1; }
6836 4 100         if (beg < 1) beg = 1;
6837 4 100         if (beg > end) XSRETURN(0);
6838              
6839 3           START_FORCOUNT;
6840 3           SAVESPTR(GvSV(PL_defgv));
6841 3           svarg = newSVuv(0);
6842 3           GvSV(PL_defgv) = svarg;
6843 3 100         if (beg <= 1) {
6844 2           sv_setuv(svarg, 1);
6845 2 50         PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN;
6846 2           beg = 2;
6847             }
6848 5 100         while (beg <= end) {
6849 2           UV seglo = beg, seghi = end;
6850 2 50         if (seghi-seglo > (65536*256))
6851 0           seghi = seglo + 65536*256 - 1;
6852 2           isf = range_issquarefree(seglo, seghi);
6853             #if USE_MULTICALL
6854 2 50         if (!CvISXSUB(subcv)) {
6855             dMULTICALL;
6856 2           I32 gimme = G_VOID;
6857 2           DECL_MULTICALL_SCOPE(subcv);
6858 2 50         PUSH_MULTICALL(subcv);
6859 109057 100         for (i = 0; i < seghi-seglo+1; i++) {
6860 109055 50         CHECK_FORCOUNT;
6861 109055 100         if (isf[i]) {
6862 66306           sv_setuv(svarg, seglo+i);
6863 66306 50         SCOPED_MULTICALL;
    50          
6864             }
6865             }
6866             FIX_MULTICALL_REFCOUNT;
6867 2 50         POP_MULTICALL;
6868             }
6869             else
6870             #endif
6871 0 0         for (i = 0; i < seghi-seglo+1; i++) {
6872 0 0         CHECK_FORCOUNT;
6873 0 0         if (isf[i]) {
6874 0           sv_setuv(svarg, seglo+i);
6875 0 0         PUSHMARK(SP); PUTBACK; call_sv((SV*)subcv, G_VOID|G_DISCARD); SPAGAIN;
6876             }
6877             }
6878 2           Safefree(isf);
6879 2 50         if (seghi == UV_MAX) break;
6880 2           beg = seghi+1;
6881 2 50         CHECK_FORCOUNT;
6882             }
6883 3           SvREFCNT_dec(svarg);
6884 3 50         END_FORCOUNT;
6885              
6886             void
6887             vecreduce(SV* block, ...)
6888             PROTOTYPE: &@
6889             CODE:
6890             { /* This is basically reduce from List::Util. Try to maintain compat. */
6891 4           SV *ret = sv_newmortal();
6892             SSize_t i;
6893             GV *agv,*bgv;
6894 4           SV **args = &PL_stack_base[ax];
6895             CV *subcv;
6896              
6897 4 50         SETSUBREF(subcv, block);
6898 4 100         if (items <= 1) XSRETURN_UNDEF;
6899              
6900 3           agv = gv_fetchpv("a", GV_ADD, SVt_PV);
6901 3           bgv = gv_fetchpv("b", GV_ADD, SVt_PV);
6902 3           SAVESPTR(GvSV(agv));
6903 3           SAVESPTR(GvSV(bgv));
6904 3           GvSV(agv) = ret;
6905 3 50         SvSetMagicSV(ret, args[1]);
    50          
6906             #ifdef dMULTICALL
6907 3 50         if (!CvISXSUB(subcv)) {
6908             dMULTICALL;
6909 3           I32 gimme = G_SCALAR;
6910 3           DECL_MULTICALL_SCOPE(subcv);
6911 3 50         PUSH_MULTICALL(subcv);
6912 7 100         for (i = 2; i < items; i++) {
6913 4           GvSV(bgv) = args[i];
6914 4 50         SCOPED_MULTICALL;
    50          
6915 4 50         SvSetMagicSV(ret, *PL_stack_sp);
    50          
6916             }
6917             FIX_MULTICALL_REFCOUNT;
6918 3 50         POP_MULTICALL;
6919             }
6920             else
6921             #endif
6922             {
6923 0 0         for (i = 2; i < items; i++) {
6924 0           dSP;
6925 0           GvSV(bgv) = args[i];
6926 0 0         PUSHMARK(SP);
6927 0           call_sv((SV*)subcv, G_SCALAR);
6928 0 0         SvSetMagicSV(ret, *PL_stack_sp);
    0          
6929             }
6930             }
6931 3           ST(0) = ret;
6932 3           XSRETURN(1);
6933             }
6934              
6935             void
6936             vecslide(SV* block, ...)
6937             PROTOTYPE: &@
6938             CODE:
6939             { /* Similar to slide from List::MoreUtils. */
6940             SSize_t i;
6941 5           SV **args = &PL_stack_base[ax];
6942             CV *subcv;
6943             SV **retsvarr; /* Store results */
6944              
6945 5 50         SETSUBREF(subcv, block);
6946 5 100         if (items <= 2) XSRETURN_EMPTY;
6947              
6948 3           New(0, retsvarr, items-2, SV*);
6949              
6950 3           SAVEGENERICSV(plAgv);
6951 3           SAVEGENERICSV(plBgv);
6952 3           plAgv = MUTABLE_GV(SvREFCNT_inc(gv_fetchpvs("a",GV_ADD|GV_NOTQUAL,SVt_PV)));
6953 3           plBgv = MUTABLE_GV(SvREFCNT_inc(gv_fetchpvs("b",GV_ADD|GV_NOTQUAL,SVt_PV)));
6954 3           save_gp(plAgv, 0);
6955 3           save_gp(plBgv, 0);
6956 3           GvINTRO_off(plAgv);
6957 3           GvINTRO_off(plBgv);
6958 3           SAVEGENERICSV(GvSV(plAgv)); SvREFCNT_inc(GvSV(plAgv));
6959 3           SAVEGENERICSV(GvSV(plBgv)); SvREFCNT_inc(GvSV(plBgv));
6960             #ifdef dMULTICALL
6961 3 50         if (!CvISXSUB(subcv)) {
6962             dMULTICALL;
6963 3           I32 gimme = G_SCALAR;
6964 3           DECL_MULTICALL_SCOPE(subcv);
6965 3 50         PUSH_MULTICALL(subcv);
6966 12 100         for (i = 1; i < items-1; i++) {
6967 9           SV *olda = GvSV(plAgv), *oldb = GvSV(plBgv);
6968 9           GvSV(plAgv) = SvREFCNT_inc_simple_NN(args[i]);
6969 9           GvSV(plBgv) = SvREFCNT_inc_simple_NN(args[i+1]);
6970 9           SvREFCNT_dec(olda); SvREFCNT_dec(oldb);
6971 9 100         SCOPED_MULTICALL;
    100          
6972 9           retsvarr[i-1] = newSVsv(*PL_stack_sp);
6973             }
6974             FIX_MULTICALL_REFCOUNT;
6975 3 50         POP_MULTICALL;
6976             }
6977             else
6978             #endif
6979             {
6980 0 0         for (i = 1; i < items-1; i++) {
6981             SV *olda, *oldb;
6982 0           dSP;
6983 0           olda = GvSV(plAgv); oldb = GvSV(plBgv);
6984 0           GvSV(plAgv) = SvREFCNT_inc_simple_NN(args[i]);
6985 0           GvSV(plBgv) = SvREFCNT_inc_simple_NN(args[i+1]);
6986 0           SvREFCNT_dec(olda); SvREFCNT_dec(oldb);
6987 0 0         PUSHMARK(SP);
6988 0           call_sv((SV*)subcv, G_SCALAR);
6989 0           retsvarr[i-1] = newSVsv(*PL_stack_sp);
6990             }
6991             }
6992 12 100         for (i = 0; i < items-2; i++)
6993 9           { ST(i) = sv_2mortal(retsvarr[i]); retsvarr[i]=0; }
6994 3           Safefree(retsvarr);
6995 3           XSRETURN(items-2);
6996             }
6997              
6998             void
6999             vecnone(SV* block, ...)
7000             ALIAS:
7001             vecall = 1
7002             vecany = 2
7003             vecnotall = 3
7004             vecfirst = 4
7005             vecfirstidx = 6
7006             PROTOTYPE: &@
7007             PPCODE:
7008             { /* This is very similar to List::Util. Try to maintain compat. */
7009 961           int ret_true = !(ix & 2); /* return true at end of loop for none/all; false for any/notall */
7010 961           int invert = (ix & 1); /* invert block test for all/notall */
7011             SSize_t index;
7012 961           SV **args = &PL_stack_base[ax];
7013             CV *subcv;
7014              
7015 961 50         SETSUBREF(subcv, block);
7016              
7017 961           SAVESPTR(GvSV(PL_defgv));
7018             #ifdef dMULTICALL
7019 961 50         if (!CvISXSUB(subcv)) {
7020             dMULTICALL;
7021 961           I32 gimme = G_SCALAR;
7022 961           DECL_MULTICALL_SCOPE(subcv);
7023 961 50         PUSH_MULTICALL(subcv);
7024 6957 100         for (index = 1; index < items; index++) {
7025 6583           GvSV(PL_defgv) = args[index];
7026 6583 100         SCOPED_MULTICALL;
    100          
7027 6583 100         if (SvTRUEx(*PL_stack_sp) ^ invert)
7028 587           break;
7029             }
7030             FIX_MULTICALL_REFCOUNT;
7031 961 50         POP_MULTICALL;
7032             }
7033             else
7034             #endif
7035             {
7036 0 0         for (index = 1; index < items; index++) {
7037 0           dSP;
7038 0           GvSV(PL_defgv) = args[index];
7039 0 0         PUSHMARK(SP);
7040 0           call_sv((SV*)subcv, G_SCALAR);
7041 0 0         if (SvTRUEx(*PL_stack_sp) ^ invert)
7042 0           break;
7043             }
7044             }
7045              
7046 961 100         if (ix == 4) {
7047 5 100         if (index == items)
7048 2           XSRETURN_UNDEF;
7049 3           ST(0) = ST(index);
7050 3           XSRETURN(1);
7051             }
7052 956 100         if (ix == 6) {
7053 5 100         if (index == items)
7054 2           XSRETURN_IV(-1);
7055 3           XSRETURN_UV(index-1);
7056             }
7057              
7058 951 100         if (index != items) /* We exited the loop early */
7059 581           ret_true = !ret_true;
7060              
7061 951 100         if (ret_true) XSRETURN_YES;
7062 585           else XSRETURN_NO;
7063             }
7064              
7065             void vecuniq(...)
7066             PROTOTYPE: @
7067             PREINIT:
7068             iset_t s;
7069             int status, retvals;
7070             SSize_t j;
7071             UV n;
7072             unsigned long sz, nret;
7073             PPCODE:
7074 7 100         retvals = (GIMME_V != G_SCALAR && GIMME_V != G_VOID);
    50          
7075 7           s = iset_create((size_t)items);
7076 93 100         for (status = 1, nret = 0, j = 0; j < items; j++) {
7077 86           status = _validate_and_set(&n, aTHX_ ST(j), IFLAG_ANY);
7078 86 50         if (status == 0) break;
7079 86 100         if (iset_add(&s, n, status) == 0)
7080 48           continue;
7081 38 50         if (iset_sign(s) == 0) { status = 0; break; }
7082 38 100         if (retvals) {
7083 28 100         PUSHs(sv_2mortal(NEWSVINT(status,n)));
7084 28           nret++;
7085             }
7086             }
7087 7           sz = iset_size(s);
7088 7           iset_destroy(&s);
7089 7 50         if (status != 0 && retvals) {
    100          
7090 6 50         if (nret != sz)croak("vecuniq: iset %lu items, pushed %lu items",sz,nret);
7091 6           XSRETURN(nret);
7092 1 50         } else if (status != 0) {
7093 1           ST(0) = sv_2mortal(newSVuv(sz));
7094 1           XSRETURN(1);
7095             } else {
7096             /* This is 100% from List::MoreUtils::XS by Parseval and Rehsack */
7097             I32 i;
7098 0           IV count = 0, seen_undef = 0;
7099 0           HV *hv = newHV();
7100 0           SV **args = &PL_stack_base[ax];
7101 0           SV *tmp = sv_newmortal();
7102 0           sv_2mortal(newRV_noinc((SV*)hv));
7103              
7104 0 0         if (GIMME_V == G_SCALAR) { /* don't build return list if not needed */
7105 0 0         for (i = 0; i < items; i++) {
7106 0 0         SvGETMAGIC(args[i]);
    0          
7107 0 0         if (SvOK(args[i])) {
7108 0           sv_setsv_nomg(tmp, args[i]);
7109 0 0         if (!hv_exists_ent(hv, tmp, 0)) {
7110 0           ++count;
7111 0           hv_store_ent(hv, tmp, &PL_sv_yes, 0);
7112             }
7113 0 0         } else if (0 == seen_undef++)
7114 0           ++count;
7115             }
7116 0           ST(0) = sv_2mortal(newSVuv(count));
7117 0           XSRETURN(1);
7118             }
7119             /* list context: populate SP with mortal copies */
7120 0 0         for (i = 0; i < items; i++) {
7121 0 0         SvGETMAGIC(args[i]);
    0          
7122 0 0         if (SvOK(args[i])) {
7123 0 0         SvSetSV_nosteal(tmp, args[i]);
7124 0 0         if (!hv_exists_ent(hv, tmp, 0)) {
7125 0           args[count++] = args[i];
7126 0           hv_store_ent(hv, tmp, &PL_sv_yes, 0);
7127             }
7128 0 0         } else if (0 == seen_undef++)
7129 0           args[count++] = args[i];
7130             }
7131 0           XSRETURN(count);
7132             }
7133              
7134             void vecfreq(...)
7135             PROTOTYPE: @
7136             PREINIT:
7137             int itype;
7138             size_t len, i, retlen;
7139             UV *L, count;
7140             PPCODE:
7141 14 100         if (items == 0) {
7142 2 100         if (GIMME_V == G_SCALAR) XSRETURN_UV(0);
7143 1           else XSRETURN_EMPTY;
7144             }
7145             /* Try to read native integers. Bail to PP if something else. */
7146 12           len = (size_t) items;
7147 12 50         New(0, L, len, UV);
7148 12           itype = IARR_TYPE_ANY;
7149 48 100         for (i = 0; i < len && itype != IARR_TYPE_BAD && SVNUMTEST(ST(i)); i++) {
    50          
    100          
7150 36           IV n = SvIVX(ST(i));
7151 36 100         if (n < 0) {
7152 8 100         if (SvIsUV(ST(i))) itype |= IARR_TYPE_POS;
7153 7           else itype |= IARR_TYPE_NEG;
7154             }
7155 36           L[i] = n;
7156             }
7157 12 100         if (i < len || itype == IARR_TYPE_BAD) {
    100          
7158 4           Safefree(L);
7159 4           DISPATCHPP();
7160 4           return;
7161             }
7162 8 100         if (itype == IARR_TYPE_NEG)
7163 4           sort_iv_array((IV*)L, len);
7164             else
7165 4           sort_uv_array(L, len);
7166             /* 2. Walk the sorted integers */
7167 8 100         if (GIMME_V == G_SCALAR) {
7168 4           count = 0;
7169 17 100         for (i = 1; i < len; i++)
7170 13 100         if (L[i] != L[i-1])
7171 7           count++;
7172 4           ST(0) = sv_2mortal(newSVuv(count+1));
7173 4           retlen = 1;
7174             } else {
7175 4 100         int sign = itype == IARR_TYPE_NEG ? -1 : 1;
7176 4 50         EXTEND(SP, (EXTEND_TYPE)len*2);
    50          
7177 4           retlen = 0;
7178 4           count = 1;
7179 17 100         for (i = 1; i < len; i++) {
7180 13 100         if (L[i] == L[i-1]) { count++; continue; }
7181 7 50         PUSHs(sv_2mortal(NEWSVINT(sign,L[i-1]))); /* key */
7182 7           PUSHs(sv_2mortal(newSVuv(count))); /* val */
7183 7           retlen += 2;
7184 7           count = 1;
7185             }
7186 4 100         PUSHs(sv_2mortal(NEWSVINT(sign,L[i-1]))); /* key */
7187 4           PUSHs(sv_2mortal(newSVuv(count))); /* val */
7188 4           retlen += 2;
7189             }
7190 8           Safefree(L);
7191 8           XSRETURN(retlen);
7192              
7193             void vecsingleton(...)
7194             PROTOTYPE: @
7195             PREINIT:
7196             int itype;
7197             size_t len, i, retlen, count;
7198             UV *L;
7199             iset_t seen, dups;
7200             PPCODE:
7201 8 100         if (items == 0) {
7202 1 50         if (GIMME_V == G_SCALAR) XSRETURN_UV(0);
7203 1           else XSRETURN_EMPTY;
7204             }
7205             /* Try to read native integers. Bail to PP if something else. */
7206 7           len = (size_t) items;
7207 7 50         New(0, L, len, UV);
7208 7           seen = iset_create(len);
7209 7           dups = iset_create(len>>1);
7210 7           itype = IARR_TYPE_ANY;
7211 55 100         for (i = 0; i < len && itype != IARR_TYPE_BAD && SVNUMTEST(ST(i)); i++) {
    50          
    100          
7212 48           IV n = SvIVX(ST(i));
7213 48           int sign = 1;
7214 48 100         if (n < 0) {
7215 2 50         if (SvIsUV(ST(i))) itype |= IARR_TYPE_POS;
7216 2           else { itype |= IARR_TYPE_NEG; sign = -1; }
7217             }
7218 48           L[i] = n;
7219 48 100         if (!iset_add(&seen, n, sign))
7220 22           iset_add(&dups, n, sign);
7221             }
7222 7 50         if (iset_is_invalid(seen)) itype = IARR_TYPE_BAD; /* Poison the type */
7223 7           iset_destroy(&seen);
7224 7 100         if (i < len || itype == IARR_TYPE_BAD) {
    50          
7225 4           iset_destroy(&dups);
7226 4           Safefree(L);
7227 4           DISPATCHPP();
7228 4           return;
7229             }
7230 3 100         if (GIMME_V != G_ARRAY) {
7231 24 100         for (i = 0, count = 0; i < len; i++)
7232 23 100         if (!iset_contains(dups, L[i]))
7233 2           count++;
7234 1           ST(0) = sv_2mortal(newSVuv(count));
7235 1           retlen = 1;
7236             } else {
7237 26 100         for (i = 0, retlen = 0; i < len; i++)
7238 24 100         if (!iset_contains(dups, L[i]))
7239 3           ST(retlen++) = ST(i);
7240             }
7241 3           iset_destroy(&dups);
7242 3           Safefree(L);
7243 3           XSRETURN(retlen);