#pragma once /** @file @brief bit operation */ #include #include #if (CYBOZU_HOST == CYBOZU_HOST_INTEL) #if defined(_WIN32) #include #elif defined(__linux__) || defined(__CYGWIN__) || defined(__clang__) #include #elif defined(__GNUC__) #include #endif #endif namespace cybozu { namespace bit_op_local { template struct Tag {}; // sizeof(T) < 8 template<> struct Tag { template static inline int bsf(T x) { #if defined(_MSC_VER) unsigned long out; _BitScanForward(&out, x); #pragma warning(suppress: 6102) return out; #else return __builtin_ctz(x); #endif } template static inline int bsr(T x) { #if defined(_MSC_VER) unsigned long out; _BitScanReverse(&out, x); #pragma warning(suppress: 6102) return out; #else return __builtin_clz(x) ^ 0x1f; #endif } }; // sizeof(T) == 8 template<> struct Tag { template static inline int bsf(T x) { #if defined(_MSC_VER) && defined(_WIN64) unsigned long out; _BitScanForward64(&out, x); #pragma warning(suppress: 6102) return out; #elif defined(__x86_64__) return __builtin_ctzll(x); #else const uint32_t L = uint32_t(x); if (L) return Tag::bsf(L); const uint32_t H = uint32_t(x >> 32); return Tag::bsf(H) + 32; #endif } template static inline int bsr(T x) { #if defined(_MSC_VER) && defined(_WIN64) unsigned long out; _BitScanReverse64(&out, x); #pragma warning(suppress: 6102) return out; #elif defined(__x86_64__) return __builtin_clzll(x) ^ 0x3f; #else const uint32_t H = uint32_t(x >> 32); if (H) return Tag::bsr(H) + 32; const uint32_t L = uint32_t(x); return Tag::bsr(L); #endif } }; } // bit_op_local template int bsf(T x) { return bit_op_local::Tag::bsf(x); } template int bsr(T x) { return bit_op_local::Tag::bsr(x); } template uint64_t makeBitMask64(T x) { assert(x < 64); return (uint64_t(1) << x) - 1; } template uint32_t popcnt(T x); template<> inline uint32_t popcnt(uint32_t x) { #if defined(_MSC_VER) return static_cast(_mm_popcnt_u32(x)); #else return static_cast(__builtin_popcount(x)); #endif } template<> inline uint32_t popcnt(uint64_t x) { #if defined(__x86_64__) return static_cast(__builtin_popcountll(x)); #elif defined(_WIN64) return static_cast(_mm_popcnt_u64(x)); #else return popcnt(static_cast(x)) + popcnt(static_cast(x >> 32)); #endif } } // cybozu