#ifndef POPCNT_HPP
#define POPCNT_HPP
#include <stdint.h>
#if defined(__has_include)
#define HAS_INCLUDE(header) __has_include(header)
#else
#define HAS_INCLUDE(header) 1
#endif
#if !defined(__has_builtin)
#define __has_builtin(x) 0
#endif
#if defined(__GNUC__) || \
__has_builtin(__builtin_popcountl)
namespace {
inline uint64_t popcnt64(uint64_t x)
{
#if __cplusplus >= 201703L
if constexpr(sizeof(int) >= sizeof(uint64_t))
return (uint64_t) __builtin_popcount(x);
else if constexpr(sizeof(long) >= sizeof(uint64_t))
return (uint64_t) __builtin_popcountl(x);
else if constexpr(sizeof(long long) >= sizeof(uint64_t))
return (uint64_t) __builtin_popcountll(x);
#else
return (uint64_t) __builtin_popcountll(x);
#endif
}
}
#elif defined(_MSC_VER) && \
!defined(DISABLE_POPCNT) && \
defined(_M_X64) && \
HAS_INCLUDE(<intrin.h>)
#include <intrin.h>
namespace {
inline uint64_t popcnt64(uint64_t x)
{
return __popcnt64(x);
}
}
#elif defined(_MSC_VER) && \
!defined(DISABLE_POPCNT) && \
defined(_M_IX86) && \
HAS_INCLUDE(<intrin.h>)
#include <intrin.h>
namespace {
inline uint64_t popcnt64(uint64_t x)
{
return __popcnt((uint32_t) x) +
__popcnt((uint32_t)(x >> 32));
}
}
#elif __cplusplus >= 202002L
#include <bit>
namespace {
inline uint64_t popcnt64(uint64_t x)
{
return std::popcount(x);
}
}
#elif defined(DISABLE_POPCNT)
namespace {
inline uint64_t popcnt64(uint64_t x)
{
uint64_t m1 = 0x5555555555555555ull;
uint64_t m2 = 0x3333333333333333ull;
uint64_t m4 = 0x0F0F0F0F0F0F0F0Full;
uint64_t h01 = 0x0101010101010101ull;
x -= (x >> 1) & m1;
x = (x & m2) + ((x >> 2) & m2);
x = (x + (x >> 4)) & m4;
return (x * h01) >> 56;
}
}
#endif
#endif