/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: auBitsUtils.hpp Date: 2022-2-1 Author: Reece ***/ #pragma once template static auline bool AuTestBit(T value, AuUInt8 idx) { return value & (T(1) << T(idx)); } template static auline bool AuBitTest(T value, AuUInt8 idx) { return value & (T(1) << T(idx)); } template static auline void AuSetBit(T &value, AuUInt8 idx) { value |= T(1) << T(idx); } template static auline void AuBitSet(T &value, AuUInt8 idx) { value |= T(1) << T(idx); } template static auline void AuClearBit(T &value, AuUInt8 idx) { value &= ~(T(1) << T(idx)); } template static auline void AuBitClear(T &value, AuUInt8 idx) { value &= ~(T(1) << T(idx)); } template static auline bool AuBitScanForward(AuUInt8 &index, T value) { unsigned long ret; bool success; success = false; index = 0; #if defined(AURORA_COMPILER_MSVC) if constexpr (sizeof(T) == sizeof(AuUInt64)) { #if defined(AURORA_IS_32BIT) if (!(success = _BitScanForward(&ret, static_cast(value & 0xffffffff)))) { if (!_BitScanForward(&ret, static_cast((value >> 32) & 0xffffffff))) { return false; } ret += 32; } #else success = _BitScanForward64(&ret, static_cast(value)); #endif } else { success = _BitScanForward(&ret, static_cast(value)); } #elif defined(AURORA_COMPILER_GCC) || defined(AURORA_COMPILER_CLANG) if (value == 0) { return false; } if constexpr (sizeof(T) == sizeof(AuUInt64)) { #if defined(AURORA_IS_32BIT) auto lower = static_cast(value & 0xffffffff)); if (lower == 0) { ret = __builtin_ctzl(static_cast((value >> 32) & 0xffffffff)); ret += 32; } else { ret = __builtin_ctzl(static_cast(lower)); } #else ret = __builtin_ctzll(static_cast(value)); #endif } else if constexpr (sizeof(T) == sizeof(unsigned long)) { ret = __builtin_ctzl(static_cast(value)); } else if constexpr (sizeof(T) == sizeof(unsigned int)) { ret = __builtin_ctz(static_cast(value)); } success = true; #endif index = ret; return success; } template static auline bool AuBitScanReverse(AuUInt8 &index, T value) { unsigned long ret; bool success; success = false; index = 0; #if defined(AURORA_COMPILER_MSVC) if constexpr (sizeof(T) == sizeof(AuUInt64)) { #if defined(AURORA_IS_32BIT) if (!(success = _BitScanReverse(&ret, static_cast((value >> 32) & 0xffffffff)))) { if (!_BitScanReverse(&ret, static_cast(value & 0xffffffff))) { return false; } ret += 32; } #else success = _BitScanReverse64(&ret, static_cast(value)); #endif } else { success = _BitScanReverse(&ret, static_cast(value)); } #elif defined(AURORA_COMPILER_GCC) || defined(AURORA_COMPILER_CLANG) if (value == 0) { return false; } if constexpr (sizeof(T) == sizeof(AuUInt64)) { #if defined(AURORA_IS_32BIT) auto lower = static_cast((value >> 32) & 0xffffffff); if (lower == 0) { ret = __builtin_clzl(static_cast(value & 0xffffffff))); ret = 63 - ret; } else { ret = __builtin_clzl(static_cast(lower)); ret = 31 - ret; } #else ret = __builtin_clzll(static_cast(value)); ret = 63 - ret; #endif } else if constexpr (sizeof(T) == sizeof(unsigned long)) { ret = __builtin_clzl(static_cast(value)); if constexpr (sizeof(unsigned long) == 4) { ret = 31 - ret; } else if constexpr (sizeof(unsigned long) == 8) { ret = 63 - ret; } } else// if constexpr (sizeof(T) == sizeof(unsigned int)) { ret = __builtin_clz(static_cast(value)); if constexpr (sizeof(unsigned int) == 4) { ret = 31 - ret; } else if constexpr (sizeof(unsigned int) == 8) { ret = 63 - ret; } } success = true; #endif index = ret; return success; } template struct AuHalfWord { using ReturnType_t = AuConditional_t, AuUInt32, AuConditional_t, AuUInt32, AuConditional_t, AuUInt8, AuFalseType>>>; static ReturnType_t ToLower(T in) { if constexpr (AuIsSame_v) { return in & AuUInt64(0xFFFFFFFF); } else if constexpr (AuIsSame_v) { return in & 0xFFFF; } else if constexpr (AuIsSame_v) { return in & 0xFF; } else { return {}; } } static ReturnType_t ToHigher(T in) { if constexpr (AuIsSame_v) { return (in >> AuUInt64(32)) & AuUInt64(0xFFFFFFFF); } else if constexpr (AuIsSame_v) { return (in >> 16) & 0xFFFF; } else if constexpr (AuIsSame_v) { return (in >> 8) & 0xFF; } else { return {}; } } }; template static auto AuBitsToLower(T in) { return AuHalfWord::ToLower(in); } template static auto AuBitsToHigher(T in) { return AuHalfWord::ToHigher(in); } template static AuUInt8 AuPopCnt(T in) { #if defined(AURORA_COMPILER_MSVC) #if defined(AURORA_ARCH_X64) || defined(AURORA_ARCH_X86) #if defined(AURORA_ARCH_X64) if constexpr (sizeof(T) == sizeof(AuUInt64)) { return _mm_popcnt_u64(static_cast(in)); } else #endif if constexpr (sizeof(T) == sizeof(unsigned int)) { return __popcnt(static_cast(in)); } else if constexpr (sizeof(T) <= sizeof(AuUInt16)) { return __popcnt16(static_cast(in)); } #endif #else if constexpr (sizeof(T) == sizeof(unsigned long long)) { return __builtin_popcountll(static_cast(in)); } else if constexpr (sizeof(T) == sizeof(unsigned long)) { return __builtin_popcountl(static_cast(in)); } else if constexpr (sizeof(T) == sizeof(unsigned int)) { return __builtin_popcount(static_cast(in)); } #endif #if defined(AU_CPU_ENDIAN_LITTLE) if constexpr (sizeof(T) == sizeof(AuUInt64)) { const AuUInt64 m1 = 0x5555555555555555ll; const AuUInt64 m2 = 0x3333333333333333ll; const AuUInt64 m4 = 0x0F0F0F0F0F0F0F0Fll; const AuUInt64 h01 = 0x0101010101010101ll; in -= (in >> 1) & m1; in = (in & m2) + ((in >> 2) & m2); in = (in + (in >> 4)) & m4; return (in * h01) >> 56; } else if constexpr (sizeof(T) == sizeof(AuUInt32)) { const AuUInt32 m1 = 0x55555555l; const AuUInt32 m2 = 0x33333333l; const AuUInt32 m4 = 0x0F0F0F0Fl; const AuUInt32 h01 = 0x01010101l; in -= (in >> 1) & m1; in = (in & m2) + ((in >> 2) & m2); in = (in + (in >> 4)) & m4; return (in * h01) >> 24; } #endif if constexpr ((sizeof(T) == sizeof(AuUInt16)) || (sizeof(T) == sizeof(AuUInt8))) { return AuPopCnt(AuUInt32(in)); } return {}; }