/*
 * This file was generated automatically by ExtUtils::ParseXS version 3.44 from the
 * contents of Combinatorics.xs. Do not edit this file, edit Combinatorics.xs instead.
 *
 *    ANY CHANGES MADE HERE WILL BE LOST!
 *
 */

#line 1 "Combinatorics.xs"
/**
 * These subroutines implement the actual iterators.
 *
 * The real combinatorics are done in-place on a private array of indices
 * that is guaranteed to hold integers. We cannot assume they are IVs though,
 * because in a few places in the Perl side there's some simple arithmetic
 * that is enough to give NVs in 5.6.x.
 *
 * Once the next tuple has been computed the corresponding slice of data is
 * copied in the Perl side. I tried to slice data here in C but it was in
 * fact slightly slower. I think we would need to pass aliases to gain
 * some more speed.
 *
 * All the subroutines return -1 when the sequence has been exhausted.
 */

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#define SETIV(av, i, n) (sv_setiv(*av_fetch(av, i, 0), n))
#define GETIV(av, i)    (SvIV(*av_fetch(av, i, 0)))
#define INCR(av, i)     (SETIV(av, i, 1 + GETIV(av, i)))
#define GETAV(avptr)    ((AV*) SvRV(avptr))


/**
 * Swap the ith and jth elements in av.
 *
 * Assumes av contains IVs.
 */
void __swap(AV* av, int i, int j)
{
    IV tmp = GETIV(av, i);
    SETIV(av, i, GETIV(av, j));
    SETIV(av, j, tmp);
}

/**
 * This implementation emulates what we do by hand. It is faster than
 * Algorithm T from [2], which gives another lexicographic ordering.
 */
int __next_combination(SV* tuple_avptr, int max_n)
{
    AV* tuple = GETAV(tuple_avptr);
    int i, j;
    IV  n;
    I32 offset, len_tuple;
    SV* e;

    len_tuple = av_len(tuple);
    offset = max_n - len_tuple;
    for (i = len_tuple; i >= 0; --i) {
        e = *av_fetch(tuple, i, 0);
        n = SvIV(e);
        if (n < i + offset) {
            sv_setiv(e, ++n);
            for (j = i+1; j <= len_tuple; ++j)
                SETIV(tuple, j, ++n);
            return i;
        }
    }

    return -1;
}


/**
 * This provisional implementation emulates what we do by hand.
 */
int __next_combination_with_repetition(SV* tuple_avptr, int max_n)
{
    AV* tuple = GETAV(tuple_avptr);
    int i, j;
    IV  n;
    I32 len_tuple;

    len_tuple = av_len(tuple);
    for (i = len_tuple; i >= 0; --i) {
        n = GETIV(tuple, i);
        if (n < max_n) {
            ++n;
            for (j = i; j <= len_tuple; ++j)
                SETIV(tuple, j, n);
            return i;
        }
    }

    return -1;
}


/**
 * This provisional implementation emulates what we do by hand, keeping
 * and array of booleans (used) to keep track of the indices in use.
 * That is, used[n] == 1 if and only if tuple[i] == n for some i.
 *
 */
int __next_variation(SV* tuple_avptr, SV* used_avptr, int max_n)
{
    AV* tuple = GETAV(tuple_avptr);
    AV* used  = GETAV(used_avptr);
    int i, j;
    I32 len_tuple;
    SV* e;
    IV  n;

    len_tuple = av_len(tuple);
    for (i = len_tuple; i >= 0; --i) {
        /* from right to left, find the first position that can be incremented */
        e = *av_fetch(tuple, i, 0);
        n = SvIV(e);
        SETIV(used, n, 0);
        while (++n <= max_n) {
            if (!GETIV(used, n)) {
                /* if we get here we nececessarily exit the subrutine, so forget about the outer while and for */
                sv_setiv(e, n);
                SETIV(used, n, 1);
                for (j = i+1; j <= len_tuple; ++j) {
                    /* from there to the right, fill the tuple with the lowest available numbers */
                    n = -1;
                    while (++n <= max_n) {
                         if (!GETIV(used, n)) {
                              SETIV(tuple, j, n);
                              SETIV(used, n, 1);
                              break;
                         }
                    }
                }
                return i;
             }
        }
    }

    return -1;
}

/**
 * This provisional implementation emulates what we do by hand.
 */
int __next_variation_with_repetition(SV* tuple_avptr, int max_n)
{
    AV* tuple = GETAV(tuple_avptr);
    int i;
    I32 len_tuple;
    SV* e;

    len_tuple = av_len(tuple);
    for (i = len_tuple; i >= 0; --i) {
        e = *av_fetch(tuple, i, 0);
        if (SvIV(e) < max_n) {
            sv_setiv(e, 1 + SvIV(e));
            return i;
        }
        sv_setiv(e, 0);
    }

    return -1;
}

/**
 * Algorithm H (Loopless reflected mixed-radix Gray generation), from [1].
 *
 * [Initialize.] and [Visit.] are done in the Perl side.
 */
int __next_variation_with_repetition_gray_code(SV* tuple_avptr, SV* f_avptr, SV* o_avptr, int max_m)
{
    AV* tuple = GETAV(tuple_avptr);
    AV* f     = GETAV(f_avptr);
    AV* o     = GETAV(o_avptr);
    I32 n;
    IV j, aj;

    n = av_len(tuple) + 1;

    /* [Choose j.] */
    j = GETIV(f, 0);
    SETIV(f, 0, 0);

    /* [Change coordinate j.] */
    if (j == n)
        return -1;
    else
        SETIV(tuple, j, GETIV(tuple, j) + GETIV(o, j));

    /* [Reflect?] */
    aj = GETIV(tuple, j);
    if (aj == 0 || aj == max_m) {
        SETIV(o, j, -GETIV(o, j));
        SETIV(f, j, GETIV(f, j+1));
        SETIV(f, j+1, j+1);
    }

    return j;
}


/**
 * Algorithm L (Lexicographic permutation generation), adapted from [1].
 * I used "h" instead of the letter "l" for the sake of readability.
 *
 * This algorithm goes back at least to the 18th century, and has been rediscovered
 * ever since.
 */
int __next_permutation(SV* tuple_avptr)
{
    AV* tuple = GETAV(tuple_avptr);
    I32 max_n, j, h, k;
    IV aj;

    max_n = av_len(tuple);

    /* [Find j.] Find the element a(j) behind the longest decreasing tail. */
    for (j = max_n-1; j >= 0 && GETIV(tuple, j) > GETIV(tuple, j+1); --j)
        ;
    if (j == -1)
        return -1;

    /* [Increase a(j).] Find the rightmost element a(h) greater than a(j) and swap them. */
    aj = GETIV(tuple, j);
    for (h = max_n; aj > GETIV(tuple, h); --h)
        ;
    __swap(tuple, j, h);

    /* [Reverse a(j+1)...a(max_n)] Reverse the tail. */
    for (k = j+1, h = max_n; k < h; ++k, --h)
        __swap(tuple, k, h);

    /* Done. */
    return 1;
}


int __next_permutation_heap(SV* a_avptr, SV* c_avptr)
{
    AV* a = GETAV(a_avptr);
    AV* c = GETAV(c_avptr);
    int k;
    I32 n;
    IV ck;

    n = av_len(a) + 1;

    for (k = 1, ck = GETIV(c, k); ck == k; ++k, ck = GETIV(c, k))
        SETIV(c, k, 0);

    if (k == n)
        return -1;

    ++ck;
    SETIV(c, k, ck);

    k % 2 == 0 ? __swap(a, k, 0) : __swap(a, k, ck-1);

    return k;
}


/**
 * The only algorithms I have found by now are either recursive, or a
 * naive wrapper around permutations() that loops over all of them and
 * discards the ones with fixed-points.
 *
 * We take here a mixed-approach, which consists on starting with the
 * algorithm in __next_permutation() and tweak a couple of places that
 * allow us to skip a significant number of permutations sometimes.
 *
 * Benchmarking shows this subroutine makes derangements() more than
 * two and a half times faster than permutations() for n = 8.
 */
int __next_derangement(SV* tuple_avptr)
{
    AV* tuple = GETAV(tuple_avptr);
    I32 max_n, min_j, j, h, k;
    IV aj;

    max_n = av_len(tuple);
    min_j = max_n;

    THERE_IS_A_FIXED_POINT:
    /* Find the element a(j) behind the longest decreasing tail. */
    for (j = max_n-1; j >= 0 && GETIV(tuple, j) > GETIV(tuple, j+1); --j)
          ;
    if (j == -1)
        return -1;

    if (min_j > j)
        min_j = j;

    /* Find the rightmost element a(h) greater than a(j) and swap them. */
    aj = GETIV(tuple, j);
    for (h = max_n; aj > GETIV(tuple, h); --h)
        ;
    __swap(tuple, j, h);

    /* If a(h) was j leave the tail in decreasing order and try again. */
    if (GETIV(tuple, j) == j)
        goto THERE_IS_A_FIXED_POINT;

    /* I tried an alternative approach that would in theory avoid the
    generation of some permutations with fixed-points: keeping track of
    the leftmost fixed-point, and reversing the elements to its right.
    But benchmarks up to n = 11 showed no difference whatsoever.
    Thus, I left this version, which is simpler.

    That n = 11 does not mean there was a difference for n = 12, it
    means I stopped benchmarking at n = 11. */

    /* Otherwise reverse the tail and return if there's no fixed point. */
    for (k = j+1, h = max_n; k < h; ++k, --h)
        __swap(tuple, k, h);
    for (k = max_n; k > min_j; --k)
        if (GETIV(tuple, k) == k)
            goto THERE_IS_A_FIXED_POINT;

    return 1;
}

/*
 * This is a transcription of algorithm 3 from [3].
 *
 * It is a classical approach based on restricted growth strings, which are
 * introduced in the paper.
 */
int __next_partition(SV* k_avptr, SV* M_avptr)
{
    AV* k = GETAV(k_avptr); /* follows notation in [3] */
    AV* M = GETAV(M_avptr); /* follows notation in [3] */
    int i, j;
    IV mi;
    I32 len_k;

    len_k = av_len(k);
    for (i = len_k; i > 0; --i) {
        if (GETIV(k, i) <= GETIV(M, i-1)) {
            INCR(k, i);

            if (GETIV(k, i) > GETIV(M, i))
                SETIV(M, i, GETIV(k, i));

            mi = GETIV(M, i);
            for (j = i+1; j <= len_k; ++j) {
                SETIV(k, j, 0);
                SETIV(M, j, mi);
            }
            return i;
        }
    }

    return -1;
}

/*
 * This is a transcription of algorithm 8 from [3].
 *
 * It is an adaptation of the previous one.
 */
int __next_partition_of_size_p(SV* k_avptr, SV* M_avptr, int p)
{
    AV* k = GETAV(k_avptr); /* follows notation in [3] */
    AV* M = GETAV(M_avptr); /* follows notation in [3] */
    int i, j;
    IV mi, x;
    I32 len_k, n_minus_p;

    len_k = av_len(k);
    for (i = len_k; i > 0; --i) {
        if (GETIV(k, i) < p-1 && GETIV(k, i) <= GETIV(M, i-1)) {
            INCR(k, i);

            if (GETIV(k, i) > GETIV(M, i))
                SETIV(M, i, GETIV(k, i));

            n_minus_p = len_k + 1 - p;
            mi = GETIV(M, i);
            x = n_minus_p + mi;
            for (j = i+1; j <= x; ++j) {
                SETIV(k, j, 0);
                SETIV(M, j, mi);
            }
            for (j = x+1; j <= len_k; ++j) {
                SETIV(k, j, j - n_minus_p);
                SETIV(M, j, j - n_minus_p);
            }
            return i;
        }
    }

    return -1;
}

/*
 * This subroutine has been copied from List::PowerSet.
 *
 * It uses a vector of bits "odometer" to indicate which elements to include
 * in each iteration. The odometer runs and eventually exhausts all possible
 * combinations of 0s and 1s.
 */
AV* __next_subset(SV* data_avptr, SV* odometer_avptr)
{
    AV* data     = GETAV(data_avptr);
    AV* odometer = GETAV(odometer_avptr);
    I32 len_data = av_len(data);
    AV* subset   = newAV();
    IV adjust    = 1;
    int i;
    IV n;

    for (i = 0; i <= len_data; ++i) {
        n = GETIV(odometer, i);
        if (n) {
            av_push(subset, newSVsv(*av_fetch(data, i, 0)));
        }
        if (adjust) {
            adjust = 1 - n;
            SETIV(odometer, i, adjust);
        }
    }

    return (AV*) sv_2mortal((SV*) subset);
}

/** -------------------------------------------------------------------
 *
 * XS stuff starts here.
 *
 */

#line 439 "Combinatorics.c"
#ifndef PERL_UNUSED_VAR
#  define PERL_UNUSED_VAR(var) if (0) var = var
#endif

#ifndef dVAR
#  define dVAR		dNOOP
#endif


/* This stuff is not part of the API! You have been warned. */
#ifndef PERL_VERSION_DECIMAL
#  define PERL_VERSION_DECIMAL(r,v,s) (r*1000000 + v*1000 + s)
#endif
#ifndef PERL_DECIMAL_VERSION
#  define PERL_DECIMAL_VERSION \
	  PERL_VERSION_DECIMAL(PERL_REVISION,PERL_VERSION,PERL_SUBVERSION)
#endif
#ifndef PERL_VERSION_GE
#  define PERL_VERSION_GE(r,v,s) \
	  (PERL_DECIMAL_VERSION >= PERL_VERSION_DECIMAL(r,v,s))
#endif
#ifndef PERL_VERSION_LE
#  define PERL_VERSION_LE(r,v,s) \
	  (PERL_DECIMAL_VERSION <= PERL_VERSION_DECIMAL(r,v,s))
#endif

/* XS_INTERNAL is the explicit static-linkage variant of the default
 * XS macro.
 *
 * XS_EXTERNAL is the same as XS_INTERNAL except it does not include
 * "STATIC", ie. it exports XSUB symbols. You probably don't want that
 * for anything but the BOOT XSUB.
 *
 * See XSUB.h in core!
 */


/* TODO: This might be compatible further back than 5.10.0. */
#if PERL_VERSION_GE(5, 10, 0) && PERL_VERSION_LE(5, 15, 1)
#  undef XS_EXTERNAL
#  undef XS_INTERNAL
#  if defined(__CYGWIN__) && defined(USE_DYNAMIC_LOADING)
#    define XS_EXTERNAL(name) __declspec(dllexport) XSPROTO(name)
#    define XS_INTERNAL(name) STATIC XSPROTO(name)
#  endif
#  if defined(__SYMBIAN32__)
#    define XS_EXTERNAL(name) EXPORT_C XSPROTO(name)
#    define XS_INTERNAL(name) EXPORT_C STATIC XSPROTO(name)
#  endif
#  ifndef XS_EXTERNAL
#    if defined(HASATTRIBUTE_UNUSED) && !defined(__cplusplus)
#      define XS_EXTERNAL(name) void name(pTHX_ CV* cv __attribute__unused__)
#      define XS_INTERNAL(name) STATIC void name(pTHX_ CV* cv __attribute__unused__)
#    else
#      ifdef __cplusplus
#        define XS_EXTERNAL(name) extern "C" XSPROTO(name)
#        define XS_INTERNAL(name) static XSPROTO(name)
#      else
#        define XS_EXTERNAL(name) XSPROTO(name)
#        define XS_INTERNAL(name) STATIC XSPROTO(name)
#      endif
#    endif
#  endif
#endif

/* perl >= 5.10.0 && perl <= 5.15.1 */


/* The XS_EXTERNAL macro is used for functions that must not be static
 * like the boot XSUB of a module. If perl didn't have an XS_EXTERNAL
 * macro defined, the best we can do is assume XS is the same.
 * Dito for XS_INTERNAL.
 */
#ifndef XS_EXTERNAL
#  define XS_EXTERNAL(name) XS(name)
#endif
#ifndef XS_INTERNAL
#  define XS_INTERNAL(name) XS(name)
#endif

/* Now, finally, after all this mess, we want an ExtUtils::ParseXS
 * internal macro that we're free to redefine for varying linkage due
 * to the EXPORT_XSUB_SYMBOLS XS keyword. This is internal, use
 * XS_EXTERNAL(name) or XS_INTERNAL(name) in your code if you need to!
 */

#undef XS_EUPXS
#if defined(PERL_EUPXS_ALWAYS_EXPORT)
#  define XS_EUPXS(name) XS_EXTERNAL(name)
#else
   /* default to internal */
#  define XS_EUPXS(name) XS_INTERNAL(name)
#endif

#ifndef PERL_ARGS_ASSERT_CROAK_XS_USAGE
#define PERL_ARGS_ASSERT_CROAK_XS_USAGE assert(cv); assert(params)

/* prototype to pass -Wmissing-prototypes */
STATIC void
S_croak_xs_usage(const CV *const cv, const char *const params);

STATIC void
S_croak_xs_usage(const CV *const cv, const char *const params)
{
    const GV *const gv = CvGV(cv);

    PERL_ARGS_ASSERT_CROAK_XS_USAGE;

    if (gv) {
        const char *const gvname = GvNAME(gv);
        const HV *const stash = GvSTASH(gv);
        const char *const hvname = stash ? HvNAME(stash) : NULL;

        if (hvname)
	    Perl_croak_nocontext("Usage: %s::%s(%s)", hvname, gvname, params);
        else
	    Perl_croak_nocontext("Usage: %s(%s)", gvname, params);
    } else {
        /* Pants. I don't think that it should be possible to get here. */
	Perl_croak_nocontext("Usage: CODE(0x%" UVxf ")(%s)", PTR2UV(cv), params);
    }
}
#undef  PERL_ARGS_ASSERT_CROAK_XS_USAGE

#define croak_xs_usage        S_croak_xs_usage

#endif

/* NOTE: the prototype of newXSproto() is different in versions of perls,
 * so we define a portable version of newXSproto()
 */
#ifdef newXS_flags
#define newXSproto_portable(name, c_impl, file, proto) newXS_flags(name, c_impl, file, proto, 0)
#else
#define newXSproto_portable(name, c_impl, file, proto) (PL_Sv=(SV*)newXS(name, c_impl, file), sv_setpv(PL_Sv, proto), (CV*)PL_Sv)
#endif /* !defined(newXS_flags) */

#if PERL_VERSION_LE(5, 21, 5)
#  define newXS_deffile(a,b) Perl_newXS(aTHX_ a,b,file)
#else
#  define newXS_deffile(a,b) Perl_newXS_deffile(aTHX_ a,b)
#endif

#line 583 "Combinatorics.c"

XS_EUPXS(XS_Algorithm__Combinatorics___next_combination); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Algorithm__Combinatorics___next_combination)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "tuple_avptr, max_n");
    {
	SV*	tuple_avptr = ST(0)
;
	int	max_n = (int)SvIV(ST(1))
;
	int	RETVAL;
	dXSTARG;

	RETVAL = __next_combination(tuple_avptr, max_n);
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Algorithm__Combinatorics___next_combination_with_repetition); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Algorithm__Combinatorics___next_combination_with_repetition)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "tuple_avptr, max_n");
    {
	SV*	tuple_avptr = ST(0)
;
	int	max_n = (int)SvIV(ST(1))
;
	int	RETVAL;
	dXSTARG;

	RETVAL = __next_combination_with_repetition(tuple_avptr, max_n);
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Algorithm__Combinatorics___next_variation); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Algorithm__Combinatorics___next_variation)
{
    dVAR; dXSARGS;
    if (items != 3)
       croak_xs_usage(cv,  "tuple_avptr, used_avptr, max_n");
    {
	SV*	tuple_avptr = ST(0)
;
	SV*	used_avptr = ST(1)
;
	int	max_n = (int)SvIV(ST(2))
;
	int	RETVAL;
	dXSTARG;

	RETVAL = __next_variation(tuple_avptr, used_avptr, max_n);
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Algorithm__Combinatorics___next_variation_with_repetition); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Algorithm__Combinatorics___next_variation_with_repetition)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "tuple_avptr, max_n");
    {
	SV*	tuple_avptr = ST(0)
;
	int	max_n = (int)SvIV(ST(1))
;
	int	RETVAL;
	dXSTARG;

	RETVAL = __next_variation_with_repetition(tuple_avptr, max_n);
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Algorithm__Combinatorics___next_variation_with_repetition_gray_code); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Algorithm__Combinatorics___next_variation_with_repetition_gray_code)
{
    dVAR; dXSARGS;
    if (items != 4)
       croak_xs_usage(cv,  "tuple_avptr, f_avptr, o_avptr, max_m");
    {
	SV*	tuple_avptr = ST(0)
;
	SV*	f_avptr = ST(1)
;
	SV*	o_avptr = ST(2)
;
	int	max_m = (int)SvIV(ST(3))
;
	int	RETVAL;
	dXSTARG;

	RETVAL = __next_variation_with_repetition_gray_code(tuple_avptr, f_avptr, o_avptr, max_m);
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Algorithm__Combinatorics___next_permutation); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Algorithm__Combinatorics___next_permutation)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "tuple_avptr");
    {
	SV*	tuple_avptr = ST(0)
;
	int	RETVAL;
	dXSTARG;

	RETVAL = __next_permutation(tuple_avptr);
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Algorithm__Combinatorics___next_permutation_heap); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Algorithm__Combinatorics___next_permutation_heap)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "a_avptr, c_avptr");
    {
	SV*	a_avptr = ST(0)
;
	SV*	c_avptr = ST(1)
;
	int	RETVAL;
	dXSTARG;

	RETVAL = __next_permutation_heap(a_avptr, c_avptr);
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Algorithm__Combinatorics___next_derangement); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Algorithm__Combinatorics___next_derangement)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "tuple_avptr");
    {
	SV*	tuple_avptr = ST(0)
;
	int	RETVAL;
	dXSTARG;

	RETVAL = __next_derangement(tuple_avptr);
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Algorithm__Combinatorics___next_partition); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Algorithm__Combinatorics___next_partition)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "k_avptr, M_avptr");
    {
	SV*	k_avptr = ST(0)
;
	SV*	M_avptr = ST(1)
;
	int	RETVAL;
	dXSTARG;

	RETVAL = __next_partition(k_avptr, M_avptr);
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Algorithm__Combinatorics___next_partition_of_size_p); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Algorithm__Combinatorics___next_partition_of_size_p)
{
    dVAR; dXSARGS;
    if (items != 3)
       croak_xs_usage(cv,  "k_avptr, M_avptr, p");
    {
	SV*	k_avptr = ST(0)
;
	SV*	M_avptr = ST(1)
;
	int	p = (int)SvIV(ST(2))
;
	int	RETVAL;
	dXSTARG;

	RETVAL = __next_partition_of_size_p(k_avptr, M_avptr, p);
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Algorithm__Combinatorics___next_subset); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Algorithm__Combinatorics___next_subset)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "data_avptr, odometer_avptr");
    {
	SV*	data_avptr = ST(0)
;
	SV*	odometer_avptr = ST(1)
;
	AV *	RETVAL;

	RETVAL = __next_subset(data_avptr, odometer_avptr);
	{
	    SV * RETVALSV;
	    RETVALSV = newRV((SV*)RETVAL);
	    RETVALSV = sv_2mortal(RETVALSV);
	    ST(0) = RETVALSV;
	}
    }
    XSRETURN(1);
}

#ifdef __cplusplus
extern "C"
#endif
XS_EXTERNAL(boot_Algorithm__Combinatorics); /* prototype to pass -Wmissing-prototypes */
XS_EXTERNAL(boot_Algorithm__Combinatorics)
{
#if PERL_VERSION_LE(5, 21, 5)
    dVAR; dXSARGS;
#else
    dVAR; dXSBOOTARGSXSAPIVERCHK;
#endif
#if PERL_VERSION_LE(5, 8, 999) /* PERL_VERSION_LT is 5.33+ */
    char* file = __FILE__;
#else
    const char* file = __FILE__;
#endif

    PERL_UNUSED_VAR(file);

    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
#if PERL_VERSION_LE(5, 21, 5)
    XS_VERSION_BOOTCHECK;
#  ifdef XS_APIVERSION_BOOTCHECK
    XS_APIVERSION_BOOTCHECK;
#  endif
#endif

        newXS_deffile("Algorithm::Combinatorics::__next_combination", XS_Algorithm__Combinatorics___next_combination);
        newXS_deffile("Algorithm::Combinatorics::__next_combination_with_repetition", XS_Algorithm__Combinatorics___next_combination_with_repetition);
        newXS_deffile("Algorithm::Combinatorics::__next_variation", XS_Algorithm__Combinatorics___next_variation);
        newXS_deffile("Algorithm::Combinatorics::__next_variation_with_repetition", XS_Algorithm__Combinatorics___next_variation_with_repetition);
        newXS_deffile("Algorithm::Combinatorics::__next_variation_with_repetition_gray_code", XS_Algorithm__Combinatorics___next_variation_with_repetition_gray_code);
        newXS_deffile("Algorithm::Combinatorics::__next_permutation", XS_Algorithm__Combinatorics___next_permutation);
        newXS_deffile("Algorithm::Combinatorics::__next_permutation_heap", XS_Algorithm__Combinatorics___next_permutation_heap);
        newXS_deffile("Algorithm::Combinatorics::__next_derangement", XS_Algorithm__Combinatorics___next_derangement);
        newXS_deffile("Algorithm::Combinatorics::__next_partition", XS_Algorithm__Combinatorics___next_partition);
        newXS_deffile("Algorithm::Combinatorics::__next_partition_of_size_p", XS_Algorithm__Combinatorics___next_partition_of_size_p);
        newXS_deffile("Algorithm::Combinatorics::__next_subset", XS_Algorithm__Combinatorics___next_subset);
#if PERL_VERSION_LE(5, 21, 5)
#  if PERL_VERSION_GE(5, 9, 0)
    if (PL_unitcheckav)
        call_list(PL_scopestack_ix, PL_unitcheckav);
#  endif
    XSRETURN_YES;
#else
    Perl_xs_boot_epilog(aTHX_ ax);
#endif
}

