#ifndef INCLUDE_GUARD_UTILS_H
#define INCLUDE_GUARD_UTILS_H

#include <cstdint>
#include <cstdlib>  // for strto* (instead of std::strto*)
#include <vector>
#include <string>
#include <sstream>
#include <cassert>
#include <iostream>
#include <iomanip>

#include "types.h"

// Helpfull in debugging
template <typename T>
inline std::string rbits(T mask, char sepByte = 0, char sep = 0,
    Index mark = -1, char marker = 'X'
) {
    std::ostringstream out;

    for (unsigned i = 0; i < sizeof(T); i++) {
        out << sep;
        for (unsigned j = 0; j < 8; j++) {
            Index index = 8 * i + j;
            if (index == mark) {
                out << marker;
            } else {
                out << ((static_cast<T>(1) << index) & mask ? '1' : '.');
            }
            if (sep) out << sep;
        }
        if (sepByte && (i < (sizeof(T) - 1))) out << sepByte;
    }

    return out.str();
}

template <typename T>
inline std::string bits(T mask, char sepByte = 0, char sep = 0,
    Index mark = -1, char marker = 'X'
) {
    std::string str(rbits<T>(mask, sepByte, sep, mark, marker));
    return std::string(str.rbegin(), str.rend());
}

inline std::vector<std::string> split(const std::string& str, char delim = ' ') {
    std::vector<std::string> parts;
    std::istringstream iss(str);
    std::string part;
    while (std::getline(iss, part, delim)) {
        if (!part.empty()) {
            parts.push_back(part);
        }
    }
    return parts;
}
inline std::vector<std::string> parse(const std::string& str, const std::string& format) {
    std::vector<std::string> parts;
    std::string part;
    unsigned start = 0, end = 0, len = 0;
    for (const std::string& delim : split(format, '*')) {
        while (end + delim.length() < str.length()) {
            for (len = 0; len < delim.length(); len++) {
                if (str[end + len] != delim[len]) {
                    break;
                }
            }
            if (len == delim.length()) {
                parts.push_back(str.substr(start, end - start));
                end += len;
                start = end;
                break;
            } else {
                end++;
            }
        }
    }
    parts.push_back(str.substr(end));
    return parts;
}

inline std::string aside(std::string lhs, std::string rhs) {
    std::ostringstream out;

    std::vector<std::string> lLines = split(lhs, '\n');
    std::vector<std::string> rLines = split(rhs, '\n');

    std::size_t lMax = 0;
    for (std::size_t i = 0; i < lLines.size(); i++) {
        lMax = std::max(lMax, lLines[i].length());
    }

    for (std::size_t i = 0, n = std::min(lLines.size(), rLines.size()); i < n; i++) {
        out << lLines[i]
            << std::string(lMax - lLines[i].length() + 1, ' ')
            << rLines[i] << '\n';
    }

    if (lLines.size() < rLines.size()) {
        for (std::size_t i = lLines.size(); i < rLines.size(); i++) {
            out << std::string(lMax + 1, ' ')
                << rLines[i] << '\n';
        }
    } else {
        for (std::size_t i = rLines.size(); i < lLines.size(); i++) {
            out << lLines[i] << '\n';
        }
    }

    return out.str();
}

template <typename... Args>
inline std::string aside(std::string col1, std::string col2, Args... cols) {
    return aside(
        col1,
        aside(col2, cols...)
    );
}


inline void fourBitBoards(
    const std::string& title1, const u64 bb1,
    const std::string& title2, const u64 bb2,
    const std::string& title3, const u64 bb3,
    const std::string& title4, const u64 bb4,
    Index mark = -1, char marker = 'X'
) {
    std::string lRanks("  8\n  7\n  6\n  5\n  4\n  3\n  2\n  1");
    std::string rRanks("8\n7\n6\n5\n4\n3\n2\n1");

    cout << std::endl << "     "
         << std::left << std::setw(18) << title1
         << std::left << std::setw(18) << title2
         << std::left << std::setw(18) << title3
         << std::left << std::setw(18) << title4
         << std::endl
         << aside(
             lRanks,
             rbits(bb1, '\n', ' ', mark, marker),
             rbits(bb2, '\n', ' ', mark, marker),
             rbits(bb3, '\n', ' ', mark, marker),
             rbits(bb4, '\n', ' ', mark, marker),
             rRanks
         ) << std::endl
         << "     a b c d e f g h   a b c d e f g h"
         << "   a b c d e f g h   a b c d e f g h" << std::endl;
}

inline char toLower(const char c) {
    if ('A' <= c && c <= 'Z') {
        return c + ' ';
    }
    return c;
}
inline char toUpper(const char c) {
    if ('a' <= c && c <= 'z') {
        return c - ' ';
    }
    return c;
}
inline bool isUpper(const char c) {
    return ('A' <= c && c <= 'Z');
}
inline bool isLower(const char c) {
    return ('a' <= c && c <= 'z');
}
inline bool startsWith(const std::string& str, const std::string& prefix) {
    if (str.length() < prefix.length()) {
        return false;
    }
    for (unsigned i = 0; i < prefix.length(); i++) {
        if (str[i] != prefix[i]) {
            return false;
        }
    }
    return true;
}

// see: https://stackoverflow.com/questions/194465/how-to-parse-a-string-to-an-int-in-c
// see: https://en.cppreference.com/w/cpp/string/byte/strtol
// Note: T must be a unsigned type
// Only applicable for types smaller/equal to unsigned long long.
// (only used for uint8_t, uint16_t, uint32_t and uint64_t)
template <typename T>
T parseUnsigned(const std::string& str, bool& parseError) {
    if (str.empty()) {
        parseError = true;
        return static_cast<T>(-1);
    }

    char* end;
    errno = 0;
    unsigned long long num = strtoull(str.c_str(), &end, 10);

    if (errno == ERANGE) {
        errno = 0;
        parseError = true;
        return static_cast<T>(-1);
    }
    if (*end != '\0') {
        parseError = true;
        return static_cast<T>(-1);
    }
    // check overflow (using complement trick for unsigned integer types)
    if (num > static_cast<unsigned long long>(static_cast<T>(-1))) {
        parseError = true;
        return static_cast<T>(-1);
    }

    return static_cast<T>(num);
}

template <enum location>
constexpr u64 bitMask();

template <enum location>
constexpr u64 bitMask(Index);

template <enum location L>
inline constexpr u64 bitMask(Index file, Index rank) {
    return bitMask<L>(8 * rank + file);
}

template <>
inline constexpr u64 bitMask<Square>(Index sq) {
    return static_cast<u64>(1) << sq;
}

template <>
inline constexpr u64 bitMask<File>(Index sq) {
    return static_cast<u64>(0x0101010101010101) << (sq & 7);
}
template <>
inline constexpr u64 bitMask<Rank>(Index sq) {
    return static_cast<u64>(0xFF) << (sq & 56);
}

template <>
inline constexpr u64 bitMask<Left>(Index sq) {
    return bitMask<Rank>(sq) & (bitMask<Square>(sq) - 1);
}
template <>
inline constexpr u64 bitMask<Right>(Index sq) {
    return bitMask<Rank>(sq) & (static_cast<u64>(-2) << sq);
}
template <>
inline constexpr u64 bitMask<Up>(Index sq) {
    return bitMask<File>(sq) & (bitMask<Square>(sq) - 1);
}
template <>
inline constexpr u64 bitMask<Down>(Index sq) {
    return bitMask<File>(sq) & (static_cast<u64>(-2) << sq);
}

template <>
inline constexpr u64 bitMask<Diag>(Index sq) {
    const u64 diag = static_cast<u64>(0x8040201008040201);
    int offset = 8 * static_cast<int>(sq & 7) - static_cast<int>(sq & 56);
    int nort = -offset & ( offset >> 31);
    int sout =  offset & (-offset >> 31);
    return (diag >> sout) << nort;
}
template <>
inline constexpr u64 bitMask<AntiDiag>(Index sq) {
    const u64 diag = static_cast<u64>(0x0102040810204080);
    int offset = 56 - 8 * static_cast<int>(sq & 7) - static_cast<int>(sq & 56);
    int nort = -offset & ( offset >> 31);
    int sout =  offset & (-offset >> 31);
    return (diag >> sout) << nort;
}

template <>
inline constexpr u64 bitMask<WhiteSquares>() {
    return 0x55AA55AA55AA55AA;
}
template <>
inline constexpr u64 bitMask<BlackSquares>() {
    return 0xAA55AA55AA55AA55;
}

/**
 * Shifts with respect to "off board" shifting
 *
 *    bits              shift<Left>(bits)  shift<Up>(bits)
 * 8  . . . 1 . . . .   . . 1 . . . . .   . . . . . . . .  8
 * 7  . . . . . . . .   . . . . . . . .   . . . . . . . .  7
 * 6  . . . . . . . .   . . . . . . . .   1 . . . . 1 . .  6
 * 5  1 . . . . 1 . .   . . . . 1 . . .   . . . . . . . .  5
 * 4  . . . . . . . .   . . . . . . . .   . . 1 . . . . .  4
 * 3  . . 1 . . . . .   . 1 . . . . . .   . . . . . . . .  3
 * 2  . . . . . . . .   . . . . . . . .   . . . . . . . .  2
 * 1  . . . . . . . .   . . . . . . . .   . . . . . . . .  1
 *    a b c d e f g h   a b c d e f g h   a b c d e f g h
 */
template <enum location>
constexpr u64 shift(u64);

template <>
inline constexpr u64 shift<Left>(u64 bits) {
    return (bits >> 1) & ~bitMask<File>(h1);
}
template <>
inline constexpr u64 shift<Right>(u64 bits) {
    return (bits << 1) & ~bitMask<File>(a1);
}
template <>
inline constexpr u64 shift<Down>(u64 bits) {
    return bits << 8;
}
template <>
inline constexpr u64 shift<Up>(u64 bits) {
    return bits >> 8;
}
template <>
inline constexpr u64 shift<RightUp>(u64 bits) {
    return (bits >> 7) & ~bitMask<File>(a1);
}
template <>
inline constexpr u64 shift<RightDown>(u64 bits) {
    return (bits << 9) & ~bitMask<File>(a1);
}
template <>
inline constexpr u64 shift<LeftUp>(u64 bits) {
    return (bits >> 9) & ~bitMask<File>(h1);
}
template <>
inline constexpr u64 shift<LeftDown>(u64 bits) {
    return (bits << 7) & ~bitMask<File>(h1);
}

/**
 * Fills (including) start square till the end of the board.
 */
template <enum location>
constexpr u64 fill(u64);

/**
 *    bits              fill<File>(bits)  fill<Rank>(bits)
 * 8  . . . . . . . .   . . 1 . . 1 . .   . . . . . . . .  8
 * 7  . . . . . . . .   . . 1 . . 1 . .   . . . . . . . .  7
 * 6  . . . . . . . .   . . 1 . . 1 . .   . . . . . . . .  6
 * 5  . . 1 . . 1 . .   . . 1 . . 1 . .   1 1 1 1 1 1 1 1  5
 * 4  . . . . . . . .   . . 1 . . 1 . .   . . . . . . . .  4
 * 3  . . 1 . . . . .   . . 1 . . 1 . .   1 1 1 1 1 1 1 1  3
 * 2  . . . . . . . .   . . 1 . . 1 . .   . . . . . . . .  2
 * 1  . . . . . . . .   . . 1 . . 1 . .   . . . . . . . .  1
 *    a b c d e f g h   a b c d e f g h   a b c d e f g h
 */
template <>
inline constexpr u64 fill<Up>(u64 bits) {
    bits |= bits >> 8;
    bits |= bits >> 16;
    return bits | (bits >> 32);
}
template <>
inline constexpr u64 fill<Down>(u64 bits) {
    bits |= bits << 8;
    bits |= bits << 16;
    return bits | (bits << 32);
}
template <>
inline constexpr u64 fill<Left>(u64 bits) {
    bits |= ((bits & 0xFEFEFEFEFEFEFEFE) >> 1);
    bits |= ((bits & 0xFCFCFCFCFCFCFCFC) >> 2);
    return bits | ((bits & 0xF0F0F0F0F0F0F0F0) >> 4);
}
template <>
inline constexpr u64 fill<Right>(u64 bits) {
    bits |= ((bits & 0x7F7F7F7F7F7F7F7F) << 1);
    bits |= ((bits & 0x3F3F3F3F3F3F3F3F) << 2);
    return bits | ((bits & 0x0F0F0F0F0F0F0F0F) << 4);
}

template <>
inline constexpr u64 fill<File>(u64 bits) {
    return fill<Up>(bits) | fill<Down>(bits);
}
template <>
inline constexpr u64 fill<Rank>(u64 bits) {
    return fill<Left>(bits) | fill<Right>(bits);
}

/**
 * An attack fill (excludes the attacker but includes blocking pieces)
 * see: https://www.chessprogramming.org/Dumb7Fill
 */
template <enum location>
inline u64 fill7dump(u64, u64);

template <>
inline u64 fill7dump<Left>(u64 attacker, u64 empty) {
    u64 flood = attacker;
    empty &= ~bitMask<File>(h1);    // block fill (avoid wrap)
    flood |= attacker = (attacker >> 1) & empty;
    flood |= attacker = (attacker >> 1) & empty;
    flood |= attacker = (attacker >> 1) & empty;
    flood |= attacker = (attacker >> 1) & empty;
    flood |= attacker = (attacker >> 1) & empty;
    flood |= attacker = (attacker >> 1) & empty;
    return (flood >> 1) & ~bitMask<File>(h1);
}
template <>
inline u64 fill7dump<Right>(u64 attacker, u64 empty) {
    u64 flood = attacker;
    empty &= ~bitMask<File>(a1);    // block fill (avoid wrap)
    flood |= attacker = (attacker << 1) & empty;
    flood |= attacker = (attacker << 1) & empty;
    flood |= attacker = (attacker << 1) & empty;
    flood |= attacker = (attacker << 1) & empty;
    flood |= attacker = (attacker << 1) & empty;
    flood |= attacker = (attacker << 1) & empty;
    return (flood << 1) & ~bitMask<File>(a1);
}
template <>
inline u64 fill7dump<Down>(u64 attacker, u64 empty) {
    u64 flood = attacker;
    flood |= attacker = (attacker << 8) & empty;
    flood |= attacker = (attacker << 8) & empty;
    flood |= attacker = (attacker << 8) & empty;
    flood |= attacker = (attacker << 8) & empty;
    flood |= attacker = (attacker << 8) & empty;
    flood |= attacker = (attacker << 8) & empty;
    return flood << 8;
}
template <>
inline u64 fill7dump<Up>(u64 attacker, u64 empty) {
    u64 flood = attacker;
    flood |= attacker = (attacker >> 8) & empty;
    flood |= attacker = (attacker >> 8) & empty;
    flood |= attacker = (attacker >> 8) & empty;
    flood |= attacker = (attacker >> 8) & empty;
    flood |= attacker = (attacker >> 8) & empty;
    flood |= attacker = (attacker >> 8) & empty;
    return flood >> 8;
}
template <>
inline u64 fill7dump<RightUp>(u64 attacker, u64 empty) {
    u64 flood = attacker;
    empty &= ~bitMask<File>(a1);    // block fill (avoid wrap)
    flood |= attacker = (attacker >> 7) & empty;
    flood |= attacker = (attacker >> 7) & empty;
    flood |= attacker = (attacker >> 7) & empty;
    flood |= attacker = (attacker >> 7) & empty;
    flood |= attacker = (attacker >> 7) & empty;
    flood |= attacker = (attacker >> 7) & empty;
    return (flood >> 7) & ~bitMask<File>(a1);
}
template <>
inline u64 fill7dump<RightDown>(u64 attacker, u64 empty) {
    u64 flood = attacker;
    empty &= ~bitMask<File>(a1);    // block fill (avoid wrap)
    flood |= attacker = (attacker << 9) & empty;
    flood |= attacker = (attacker << 9) & empty;
    flood |= attacker = (attacker << 9) & empty;
    flood |= attacker = (attacker << 9) & empty;
    flood |= attacker = (attacker << 9) & empty;
    flood |= attacker = (attacker << 9) & empty;
    return (flood << 9) & ~bitMask<File>(a1);
}
template <>
inline u64 fill7dump<LeftUp>(u64 attacker, u64 empty) {
    u64 flood = attacker;
    empty &= ~bitMask<File>(h1);    // block fill (avoid wrap)
    flood |= attacker = (attacker >> 9) & empty;
    flood |= attacker = (attacker >> 9) & empty;
    flood |= attacker = (attacker >> 9) & empty;
    flood |= attacker = (attacker >> 9) & empty;
    flood |= attacker = (attacker >> 9) & empty;
    flood |= attacker = (attacker >> 9) & empty;
    return (flood >> 9) & ~bitMask<File>(h1);
}
template <>
inline u64 fill7dump<LeftDown>(u64 attacker, u64 empty) {
    u64 flood = attacker;
    empty &= ~bitMask<File>(h1);    // block fill (avoid wrap)
    flood |= attacker = (attacker << 7) & empty;
    flood |= attacker = (attacker << 7) & empty;
    flood |= attacker = (attacker << 7) & empty;
    flood |= attacker = (attacker << 7) & empty;
    flood |= attacker = (attacker << 7) & empty;
    flood |= attacker = (attacker << 7) & empty;
    return (flood << 7) & ~bitMask<File>(h1);
}
template <>
inline u64 fill7dump<Plus>(u64 attacker, u64 empty) {
    return fill7dump<Up>   (attacker, empty)
         | fill7dump<Down> (attacker, empty)
         | fill7dump<Left> (attacker, empty)
         | fill7dump<Right>(attacker, empty);
}
template <>
inline u64 fill7dump<Cross>(u64 attacker, u64 empty) {
    return fill7dump<LeftUp>   (attacker, empty)
         | fill7dump<LeftDown> (attacker, empty)
         | fill7dump<RightUp>  (attacker, empty)
         | fill7dump<RightDown>(attacker, empty);
}
template <>
inline u64 fill7dump<Star>(u64 attacker, u64 empty) {
    return fill7dump<Plus> (attacker, empty)
         | fill7dump<Cross>(attacker, empty);
}

inline Index fileIndex(const Index squareIndex) {
    assert(squareIndex < 64);

    return squareIndex & 7;
}
inline Index rankIndex(const Index squareIndex) {
    assert(squareIndex < 64);

    return squareIndex >> 3;
}
inline Index squareIndex(const Index fileIndex, const Index rankIndex) {
    assert(fileIndex < 8);
    assert(rankIndex < 8);

    return 8 * rankIndex + fileIndex;
}

inline u64 lineMask(Index sq1, Index sq2) {
    int r1 = static_cast<int>(rankIndex(sq1));
    int r2 = static_cast<int>(rankIndex(sq2));

    int f1 = static_cast<int>(fileIndex(sq1));
    int f2 = static_cast<int>(fileIndex(sq2));

    assert((-1 < r1) && (r1 < 8));
    assert((-1 < r2) && (r2 < 8));
    assert((-1 < f1) && (f1 < 8));
    assert((-1 < f2) && (f2 < 8));

    if (r1 == r2) { return bitMask<Rank>(sq1); }
    if (f1 == f2) { return bitMask<File>(sq1); }
    if ((r1 - r2) == (f1 - f2)) { return bitMask<Diag>(sq1); }
    if ((r1 - r2) == (f2 - f1)) { return bitMask<AntiDiag>(sq1); }

    assert(false);

    return bitMask<Square>(sq1) | bitMask<Square>(sq2);
}

inline u64 bitReverse(u64 x) {
    x = (((x & static_cast<u64>(0xAAAAAAAAAAAAAAAA)) >>  1)
       | ((x & static_cast<u64>(0x5555555555555555)) <<  1));
    x = (((x & static_cast<u64>(0xCCCCCCCCCCCCCCCC)) >>  2)
       | ((x & static_cast<u64>(0x3333333333333333)) <<  2));
    x = (((x & static_cast<u64>(0xF0F0F0F0F0F0F0F0)) >>  4)
       | ((x & static_cast<u64>(0x0F0F0F0F0F0F0F0F)) <<  4));
#ifdef __GNUC__
    return __builtin_bswap64(x);
#else
    x = (((x & static_cast<u64>(0xFF00FF00FF00FF00)) >>  8)
       | ((x & static_cast<u64>(0x00FF00FF00FF00FF)) <<  8));
    x = (((x & static_cast<u64>(0xFFFF0000FFFF0000)) >> 16)
       | ((x & static_cast<u64>(0x0000FFFF0000FFFF)) << 16));
    return((x >> 32) | (x << 32));
#endif
}

template <enum location>
inline u64 bitFlip(u64 x);

// Reverses byte order, aka rank 8 <-> rank 1, rank 7 <-> rank 2, ...
template <>
inline u64 bitFlip<Rank>(u64 x) {
#ifdef __GNUC__
    return __builtin_bswap64(x);
#elif
    x = (((x & static_cast<u64>(0xFF00FF00FF00FF00)) >>  8)
       | ((x & static_cast<u64>(0x00FF00FF00FF00FF)) <<  8));
    x = (((x & static_cast<u64>(0xFFFF0000FFFF0000)) >> 16)
       | ((x & static_cast<u64>(0x0000FFFF0000FFFF)) << 16));
    return((x >> 32) | (x << 32));
#endif
}

// Reverses bits in bytes, aka file a <-> file h, file b <-> file g, ...
template <>
inline u64 bitFlip<File> (u64 x) {
    constexpr u64 a = 0x5555555555555555;
    constexpr u64 b = 0x3333333333333333;
    constexpr u64 c = 0x0F0F0F0F0F0F0F0F;

    x = ((x >> 1) & a) | ((x & a) << 1);
    x = ((x >> 2) & b) | ((x & b) << 2);
    x = ((x >> 4) & c) | ((x & c) << 4);

    return x;
}

// see: https://chessprogramming.org/Flipping_Mirroring_and_Rotating

// Flips bits about the diagonal (transposition of the board)
template <>
inline u64 bitFlip<Diag>(u64 x) {
    u64 t;  // Temporary Value
    constexpr u64 a = 0x5500550055005500;
    constexpr u64 b = 0x3333000033330000;
    constexpr u64 c = 0x0F0F0F0F00000000;

    t  = c & (x ^ (x << 28));
    x ^=      t ^ (t >> 28);
    t  = b & (x ^ (x << 14));
    x ^=      t ^ (t >> 14);
    t  = a & (x ^ (x <<  7));
    x ^=      t ^ (t >>  7);

    return x;
}

// Flips bits about the anti-diagonal
template <>
inline u64 bitFlip<AntiDiag>(u64 x) {
    u64 t;  // Temporary Value
    constexpr u64 a = 0xAA00AA00AA00AA00;
    constexpr u64 b = 0xCCCC0000CCCC0000;
    constexpr u64 c = 0xF0F0F0F00F0F0F0F;

    t  =      x ^ (x << 36);
    x ^= c & (t ^ (x >> 36));
    t  = b & (x ^ (x << 18));
    x ^=      t ^ (t >> 18);
    t  = a & (x ^ (x <<  9));
    x ^=      t ^ (t >>  9);

    return x;
}

inline Index bitCount(u64 x) {
#ifdef __GNUC__
    return __builtin_popcountll(x); // `POPulation COUNT` (Long Long)
#elif
    Index count = 0; // counts set bits

    // increment count until there are no bits set in x
    for (; x; count++) {
        x &= x - 1; // unset least significant bit
    }

    return count;
#endif
}

#ifdef __GNUC__
inline Index bitScanLS(u64 bb) {
    return __builtin_ctzll(bb); // Count Trailing Zeros (Long Long)
}
#elif
/**
 * `de Brujin` sequence and lookup for bitScanLS and bitScanMS.
 */
constexpr u64 debruijn64Seq = static_cast<u64>(0x03f79d71b4cb0a89);
constexpr Index debruijn64Lookup[64] = {
    0, 47,  1, 56, 48, 27,  2, 60,
   57, 49, 41, 37, 28, 16,  3, 61,
   54, 58, 35, 52, 50, 42, 21, 44,
   38, 32, 29, 23, 17, 11,  4, 62,
   46, 55, 26, 59, 40, 36, 15, 53,
   34, 51, 20, 43, 31, 22, 10, 45,
   25, 39, 14, 33, 19, 30,  9, 24,
   13, 18,  8, 12,  7,  6,  5, 63
};
/**
 * Gets the least significant 1 bit `bitScanLS` and most significant
 * `bitScanMS` index on a 64-bit board.
 *
 * Using a `de Brujin` sequence to index a 1 in a 64-bit word.
 *
 * @param `bb` 64-bit word (a bit board)
 * @condition `bb` != 0
 * @return index 0 to 63 of least significant one bit
 * 
 * @see Original authors: `Martin Läuter (1997), Charles E. Leiserson,`
 *                        `Harald Prokop, Keith H. Randall`
 * @see https://www.chessprogramming.org/BitScan
 */
inline Index bitScanLS(u64 bb) {
    assert(bb != 0);
    return debruijn64Lookup[((bb ^ (bb - 1)) * debruijn64Seq) >> 58];
}
inline Index bitScanMS(u64 bb) {
    assert(bb != 0);

    bb |= bb >> 1;
    bb |= bb >> 2;
    bb |= bb >> 4;
    bb |= bb >> 8;
    bb |= bb >> 16;
    bb |= bb >> 32;

    return debruijn64Lookup[(bb * debruijn64Seq) >> 58];
}
#endif

#endif /*  INCLUDE_GUARD_UTILS_H */
