Last active
November 29, 2023 21:26
-
-
Save michihupf/18edc991f3132f5b72e9dbddcd83f77f to your computer and use it in GitHub Desktop.
efficient C++ subset impl with pop_lsb() using ctz compiler intrinsics for MSVC, GCC and Clang.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <vector> | |
#include <cassert> | |
#include <cmath> | |
#include <iostream> | |
#if defined _MSC_VER | |
// include MSVC compiler intrinsics | |
// for _BitScanForward | |
#include <intrin.h> | |
// https://learn.microsoft.com/en-us/cpp/intrinsics/bitscanforward-bitscanforward64?view=msvc-170 | |
// https://www.felixcloutier.com/x86/bsf | |
#pragma intrinsic(_BitScanForward) | |
#endif | |
// pops least significant bit from `bits` and | |
// returns its index. Uses ctz compiler intrinsics | |
// to count trailing zeros. Supported compilers are | |
// MSVC, GCC and Clang. Do not pass 0, will lead to | |
// UB or out-of-bounds index. | |
unsigned int pop_lsb(unsigned int &bits) { | |
// __builtin_ctz(0) is UB | |
// _BitScanForward(0) results in out-of-bounds index | |
assert(bits != 0); | |
#if defined __GNUC__ || defined __clang__ | |
// https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#:~:text=in%20Function%3A%20int-,__builtin_ctz,-(unsigned%20int%20x | |
// https://clang.llvm.org/docs/LanguageExtensions.html#:~:text=__builtin_clzs-,__builtin_ctz,-__builtin_ctzl | |
unsigned int b = __builtin_ctz(bits); | |
#elif defined _MSC_VER | |
unsigned long b; | |
_BitScanForward(&b, bits); | |
#endif | |
bits &= bits - 1; | |
return b; | |
} | |
int main() { | |
// number or elements to subset | |
std::vector<int> elements {10, 2, 5}; | |
for (unsigned int i = 0; i < pow(2, elements.size()); i++) { | |
unsigned int bits = i; | |
std::cout << "( "; | |
while (bits) { | |
// every iteration here is an index to the original data structure | |
std::cout << elements[pop_lsb(bits)] << " "; | |
} | |
std::cout << ")" << std::endl; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment