#include "int_utils.h"

#if (defined(__GNUC__) && defined(__BMI2__))
    #include <x86intrin.h>
    #include <bmi2intrin.h>     // _pdep_u32
#endif

int ilog2(uint64_t x) {
    int log = 0;
    while (x >>= 1) {
        log++;
    }
    return log;
}

uint64_t isqrt(uint64_t x) {
    // implements a binary search
    uint64_t root = 0;
    uint64_t left = 0;          // left boundary
    uint64_t right = x + 1;     // right boundary

    while(left + 1UL < right) {
        root = (left + right) / 2UL;
        if (root * root <= x) {
            left = root;
        } else {
            right = root;
        }
    }
    return left;
}

uint32_t invTriag(uint32_t x) {
    uint64_t root = isqrt(8UL * static_cast<uint64_t>(x) + 1UL);
    if (root * root != 8UL * x + 1UL) {
        return 0;
    }
    return (root - 1) / 2;
}

uint64_t nrSubSets(uint64_t n, uint64_t k) {
    uint64_t sum = 1, binom = 1;

    for (uint64_t i = 1; i <= k; ++i) {
        binom *= n--;
        binom /= i;
        sum += binom;
    }

    return sum;
}
