How to write a maintainable, fast, compile-time bit-mask in C++?How do you set, clear, and toggle a single...

How bad is a Computer Science course that doesn't teach Design Patterns?

Identical projects by students at two different colleges: still plagiarism?

Why Third 'Reich'? Why is 'reich' not translated when 'third' is? What is the English synonym of reich?

Failing PhD, how to go forward?

How can I get results over the whole domain of my non-linear differential equations?

Why isn't there any EEPROM in STM32F4 MCUs?

Why is opening a file faster than reading variable content?

Ethernet cable only works in certain positions

Which was the first story to feature space elevators?

How to assess the susceptibility of a U.S. company to go bankrupt?

What prevents people from lying about where they live in order to reduce state income taxes?

MySQL: Is it a security risk to deactivate the setting "bind-address"?

Why is Shelob considered evil?

QGIS 3.4.4 sorts numerical values as text, solution?

How to not forget my phone in the bathroom?

find command cannot find my files which do exist

Is 'bad luck' with former employees a red flag?

Manager has noticed coworker's excessive breaks. Should I warn him?

Someone wants me to use my credit card at a card-only gas/petrol pump in return for cash

Ramanujan's radical and how we define an infinite nested radical

Was Opportunity's last message to Earth "My battery is low and it's getting dark"?

Is it possible to detect 100% of SQLi with a simple regex?

Why does finding small effects in large studies indicate publication bias?

How do I add a strong "onion flavor" to the biryani (in restaurant style)?



How to write a maintainable, fast, compile-time bit-mask in C++?


How do you set, clear, and toggle a single bit?How to count the number of set bits in a 32-bit integer?What are bitwise shift (bit-shift) operators and how do they work?How can I profile C++ code running on Linux?Why does my program consume 100% CPU under nVidia NView?C++11 introduced a standardized memory model. What does it mean? And how is it going to affect C++ programming?Error: bad register name `%rax' MinGW, Windows 7, x64 CPU, C++Tracing call stack in disassembled codeg++ bug? (bool_val ? 0 : 1) returns neither 0 nor 1GCC optimizer emits strange conditional jumps, why?













8















I have some code that is morally like this:



#include <bitset>

enum Flags { A = 1, B = 2, C = 3, D = 5,
E = 8, F = 13, G = 21, H,
I, J, K, L, M, N, O };

void apply_known_mask(std::bitset<64> &bits) {
const Flags important_bits[] = { B, D, E, H, K, M, L, O };
std::remove_reference<decltype(bits)>::type mask{};
for (const auto& bit : important_bits) {
mask.set(bit);
}

bits &= mask;
}


Clang >= 3.6 does the smart thing and compiles this to a single and instruction (which then gets inlined everywhere else):



apply_known_mask(std::bitset<64ul>&):  # @apply_known_mask(std::bitset<64ul>&)
and qword ptr [rdi], 775946532
ret


But every version of GCC I've tried compiles this to an enormous mess that includes error handling that should be statically DCE'd. In other code, it will even place the important_bits equivalent as data in line with the code!



.LC0:
.string "bitset::set"
.LC1:
.string "%s: __position (which is %zu) >= _Nb (which is %zu)"
apply_known_mask(std::bitset<64ul>&):
sub rsp, 40
xor esi, esi
mov ecx, 2
movabs rax, 21474836482
mov QWORD PTR [rsp], rax
mov r8d, 1
movabs rax, 94489280520
mov QWORD PTR [rsp+8], rax
movabs rax, 115964117017
mov QWORD PTR [rsp+16], rax
movabs rax, 124554051610
mov QWORD PTR [rsp+24], rax
mov rax, rsp
jmp .L2
.L3:
mov edx, DWORD PTR [rax]
mov rcx, rdx
cmp edx, 63
ja .L7
.L2:
mov rdx, r8
add rax, 4
sal rdx, cl
lea rcx, [rsp+32]
or rsi, rdx
cmp rax, rcx
jne .L3
and QWORD PTR [rdi], rsi
add rsp, 40
ret
.L7:
mov ecx, 64
mov esi, OFFSET FLAT:.LC0
mov edi, OFFSET FLAT:.LC1
xor eax, eax
call std::__throw_out_of_range_fmt(char const*, ...)


My question is: how should I write this code so that both compilers can do the right thing? Failing that, how should I write this so that it remains clear, fast, and maintainable?










share|improve this question

























  • Rather than using a loop, can't you construct a mask with B | D | E | ... | O?

    – HolyBlackCat
    1 hour ago






  • 1





    The enum has bit positions rather than already expanded bits, so I could do (1ULL << B) | ... | (1ULL << O)

    – Alex Reinking
    1 hour ago











  • The downside being that the actual names are long and irregular and it's not nearly as easy to see which flags are in the mask with all that line noise.

    – Alex Reinking
    1 hour ago
















8















I have some code that is morally like this:



#include <bitset>

enum Flags { A = 1, B = 2, C = 3, D = 5,
E = 8, F = 13, G = 21, H,
I, J, K, L, M, N, O };

void apply_known_mask(std::bitset<64> &bits) {
const Flags important_bits[] = { B, D, E, H, K, M, L, O };
std::remove_reference<decltype(bits)>::type mask{};
for (const auto& bit : important_bits) {
mask.set(bit);
}

bits &= mask;
}


Clang >= 3.6 does the smart thing and compiles this to a single and instruction (which then gets inlined everywhere else):



apply_known_mask(std::bitset<64ul>&):  # @apply_known_mask(std::bitset<64ul>&)
and qword ptr [rdi], 775946532
ret


But every version of GCC I've tried compiles this to an enormous mess that includes error handling that should be statically DCE'd. In other code, it will even place the important_bits equivalent as data in line with the code!



.LC0:
.string "bitset::set"
.LC1:
.string "%s: __position (which is %zu) >= _Nb (which is %zu)"
apply_known_mask(std::bitset<64ul>&):
sub rsp, 40
xor esi, esi
mov ecx, 2
movabs rax, 21474836482
mov QWORD PTR [rsp], rax
mov r8d, 1
movabs rax, 94489280520
mov QWORD PTR [rsp+8], rax
movabs rax, 115964117017
mov QWORD PTR [rsp+16], rax
movabs rax, 124554051610
mov QWORD PTR [rsp+24], rax
mov rax, rsp
jmp .L2
.L3:
mov edx, DWORD PTR [rax]
mov rcx, rdx
cmp edx, 63
ja .L7
.L2:
mov rdx, r8
add rax, 4
sal rdx, cl
lea rcx, [rsp+32]
or rsi, rdx
cmp rax, rcx
jne .L3
and QWORD PTR [rdi], rsi
add rsp, 40
ret
.L7:
mov ecx, 64
mov esi, OFFSET FLAT:.LC0
mov edi, OFFSET FLAT:.LC1
xor eax, eax
call std::__throw_out_of_range_fmt(char const*, ...)


My question is: how should I write this code so that both compilers can do the right thing? Failing that, how should I write this so that it remains clear, fast, and maintainable?










share|improve this question

























  • Rather than using a loop, can't you construct a mask with B | D | E | ... | O?

    – HolyBlackCat
    1 hour ago






  • 1





    The enum has bit positions rather than already expanded bits, so I could do (1ULL << B) | ... | (1ULL << O)

    – Alex Reinking
    1 hour ago











  • The downside being that the actual names are long and irregular and it's not nearly as easy to see which flags are in the mask with all that line noise.

    – Alex Reinking
    1 hour ago














8












8








8


1






I have some code that is morally like this:



#include <bitset>

enum Flags { A = 1, B = 2, C = 3, D = 5,
E = 8, F = 13, G = 21, H,
I, J, K, L, M, N, O };

void apply_known_mask(std::bitset<64> &bits) {
const Flags important_bits[] = { B, D, E, H, K, M, L, O };
std::remove_reference<decltype(bits)>::type mask{};
for (const auto& bit : important_bits) {
mask.set(bit);
}

bits &= mask;
}


Clang >= 3.6 does the smart thing and compiles this to a single and instruction (which then gets inlined everywhere else):



apply_known_mask(std::bitset<64ul>&):  # @apply_known_mask(std::bitset<64ul>&)
and qword ptr [rdi], 775946532
ret


But every version of GCC I've tried compiles this to an enormous mess that includes error handling that should be statically DCE'd. In other code, it will even place the important_bits equivalent as data in line with the code!



.LC0:
.string "bitset::set"
.LC1:
.string "%s: __position (which is %zu) >= _Nb (which is %zu)"
apply_known_mask(std::bitset<64ul>&):
sub rsp, 40
xor esi, esi
mov ecx, 2
movabs rax, 21474836482
mov QWORD PTR [rsp], rax
mov r8d, 1
movabs rax, 94489280520
mov QWORD PTR [rsp+8], rax
movabs rax, 115964117017
mov QWORD PTR [rsp+16], rax
movabs rax, 124554051610
mov QWORD PTR [rsp+24], rax
mov rax, rsp
jmp .L2
.L3:
mov edx, DWORD PTR [rax]
mov rcx, rdx
cmp edx, 63
ja .L7
.L2:
mov rdx, r8
add rax, 4
sal rdx, cl
lea rcx, [rsp+32]
or rsi, rdx
cmp rax, rcx
jne .L3
and QWORD PTR [rdi], rsi
add rsp, 40
ret
.L7:
mov ecx, 64
mov esi, OFFSET FLAT:.LC0
mov edi, OFFSET FLAT:.LC1
xor eax, eax
call std::__throw_out_of_range_fmt(char const*, ...)


My question is: how should I write this code so that both compilers can do the right thing? Failing that, how should I write this so that it remains clear, fast, and maintainable?










share|improve this question
















I have some code that is morally like this:



#include <bitset>

enum Flags { A = 1, B = 2, C = 3, D = 5,
E = 8, F = 13, G = 21, H,
I, J, K, L, M, N, O };

void apply_known_mask(std::bitset<64> &bits) {
const Flags important_bits[] = { B, D, E, H, K, M, L, O };
std::remove_reference<decltype(bits)>::type mask{};
for (const auto& bit : important_bits) {
mask.set(bit);
}

bits &= mask;
}


Clang >= 3.6 does the smart thing and compiles this to a single and instruction (which then gets inlined everywhere else):



apply_known_mask(std::bitset<64ul>&):  # @apply_known_mask(std::bitset<64ul>&)
and qword ptr [rdi], 775946532
ret


But every version of GCC I've tried compiles this to an enormous mess that includes error handling that should be statically DCE'd. In other code, it will even place the important_bits equivalent as data in line with the code!



.LC0:
.string "bitset::set"
.LC1:
.string "%s: __position (which is %zu) >= _Nb (which is %zu)"
apply_known_mask(std::bitset<64ul>&):
sub rsp, 40
xor esi, esi
mov ecx, 2
movabs rax, 21474836482
mov QWORD PTR [rsp], rax
mov r8d, 1
movabs rax, 94489280520
mov QWORD PTR [rsp+8], rax
movabs rax, 115964117017
mov QWORD PTR [rsp+16], rax
movabs rax, 124554051610
mov QWORD PTR [rsp+24], rax
mov rax, rsp
jmp .L2
.L3:
mov edx, DWORD PTR [rax]
mov rcx, rdx
cmp edx, 63
ja .L7
.L2:
mov rdx, r8
add rax, 4
sal rdx, cl
lea rcx, [rsp+32]
or rsi, rdx
cmp rax, rcx
jne .L3
and QWORD PTR [rdi], rsi
add rsp, 40
ret
.L7:
mov ecx, 64
mov esi, OFFSET FLAT:.LC0
mov edi, OFFSET FLAT:.LC1
xor eax, eax
call std::__throw_out_of_range_fmt(char const*, ...)


My question is: how should I write this code so that both compilers can do the right thing? Failing that, how should I write this so that it remains clear, fast, and maintainable?







c++ c++11 bit-manipulation






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 1 hour ago







Alex Reinking

















asked 1 hour ago









Alex ReinkingAlex Reinking

2,6641530




2,6641530













  • Rather than using a loop, can't you construct a mask with B | D | E | ... | O?

    – HolyBlackCat
    1 hour ago






  • 1





    The enum has bit positions rather than already expanded bits, so I could do (1ULL << B) | ... | (1ULL << O)

    – Alex Reinking
    1 hour ago











  • The downside being that the actual names are long and irregular and it's not nearly as easy to see which flags are in the mask with all that line noise.

    – Alex Reinking
    1 hour ago



















  • Rather than using a loop, can't you construct a mask with B | D | E | ... | O?

    – HolyBlackCat
    1 hour ago






  • 1





    The enum has bit positions rather than already expanded bits, so I could do (1ULL << B) | ... | (1ULL << O)

    – Alex Reinking
    1 hour ago











  • The downside being that the actual names are long and irregular and it's not nearly as easy to see which flags are in the mask with all that line noise.

    – Alex Reinking
    1 hour ago

















Rather than using a loop, can't you construct a mask with B | D | E | ... | O?

– HolyBlackCat
1 hour ago





Rather than using a loop, can't you construct a mask with B | D | E | ... | O?

– HolyBlackCat
1 hour ago




1




1





The enum has bit positions rather than already expanded bits, so I could do (1ULL << B) | ... | (1ULL << O)

– Alex Reinking
1 hour ago





The enum has bit positions rather than already expanded bits, so I could do (1ULL << B) | ... | (1ULL << O)

– Alex Reinking
1 hour ago













The downside being that the actual names are long and irregular and it's not nearly as easy to see which flags are in the mask with all that line noise.

– Alex Reinking
1 hour ago





The downside being that the actual names are long and irregular and it's not nearly as easy to see which flags are in the mask with all that line noise.

– Alex Reinking
1 hour ago












2 Answers
2






active

oldest

votes


















12














template< unsigned char... indexes >
constexpr unsigned long long mask(){
return ((1ull<<indexes)|...|0ull);
}


Then



void apply_known_mask(std::bitset<64> &bits) {
constexpr auto m = mask<B,D,E,H,K,M,L,O>();
bits &= m;
}


or in c++14:



template< unsigned char... indexes >
constexpr unsigned long long mask(){
auto r = 0ull;
using discard = int[];
(void)discard{0,((
r |= (1ull << indexes)
),0)...};
return r;
}


or in c++11:



constexpr unsigned long long mask(){
return 0;
}
template<class...Tail>
constexpr unsigned long long mask(unsigned char b0, Tail...tail){
return (1ull<<b0) | mask(tail...);
}
template< unsigned char... indexes >
constexpr unsigned long long mask(){
return mask(indexes...);
}


Godbolt with all 3 -- you can switch CPP_VERSION define, and get identical assembly.



In practice I'd use the most modern I could. 14 beats 11 because we don't have recursion and hence O(n^2) symbol length (which can explode compile time and compiler memory usage); 17 beats 14 because the compiler doesn't have to dead-code-eliminate that array, and that array trick is just ugly.



Of these 14 is the most confusing. Here we create an anonymous array of all 0s, meanwhile as a side effect construct our result, then discard the array. It has a number of 0s in it equal to the size of our pack, plus 1 (which we add so we can handle empty packs).






share|improve this answer


























  • Pack fold is C++17, though -- I failed to specify that we're stuck on C++11, sorry!

    – Alex Reinking
    1 hour ago











  • If you can't use a fold expression, just write the old-style recursive version instead. It's verbose but not difficult.

    – Useless
    17 mins ago






  • 1





    @AlexReinking 11 and 14 versions added.

    – Yakk - Adam Nevraumont
    14 mins ago



















1














In C++11:



template <std::size_t N>
constexpr unsigned long long generate_mask(Flags const (&a)[N], std::size_t i = 0U){
return i < N ? (1ull << a[i] | generate_mask(a, i + 1U)) : 0ull;
}

void apply_known_mask(std::bitset<64>& bits) {
constexpr const Flags important_bits[] = { B, D, E, H, K, M, L, O };
constexpr auto m = generate_mask(important_bits);
bits &= m;
}




test



int main() {
std::bitset<64> b;
b.flip();
apply_known_mask(b);
std::cout << b.to_string() << 'n';
}


output



0000000000000000000000000000000000101110010000000000000100100100                 
// ^ ^^^ ^ ^ ^ ^
// O MLK H E D B





share|improve this answer

























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54786278%2fhow-to-write-a-maintainable-fast-compile-time-bit-mask-in-c%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    12














    template< unsigned char... indexes >
    constexpr unsigned long long mask(){
    return ((1ull<<indexes)|...|0ull);
    }


    Then



    void apply_known_mask(std::bitset<64> &bits) {
    constexpr auto m = mask<B,D,E,H,K,M,L,O>();
    bits &= m;
    }


    or in c++14:



    template< unsigned char... indexes >
    constexpr unsigned long long mask(){
    auto r = 0ull;
    using discard = int[];
    (void)discard{0,((
    r |= (1ull << indexes)
    ),0)...};
    return r;
    }


    or in c++11:



    constexpr unsigned long long mask(){
    return 0;
    }
    template<class...Tail>
    constexpr unsigned long long mask(unsigned char b0, Tail...tail){
    return (1ull<<b0) | mask(tail...);
    }
    template< unsigned char... indexes >
    constexpr unsigned long long mask(){
    return mask(indexes...);
    }


    Godbolt with all 3 -- you can switch CPP_VERSION define, and get identical assembly.



    In practice I'd use the most modern I could. 14 beats 11 because we don't have recursion and hence O(n^2) symbol length (which can explode compile time and compiler memory usage); 17 beats 14 because the compiler doesn't have to dead-code-eliminate that array, and that array trick is just ugly.



    Of these 14 is the most confusing. Here we create an anonymous array of all 0s, meanwhile as a side effect construct our result, then discard the array. It has a number of 0s in it equal to the size of our pack, plus 1 (which we add so we can handle empty packs).






    share|improve this answer


























    • Pack fold is C++17, though -- I failed to specify that we're stuck on C++11, sorry!

      – Alex Reinking
      1 hour ago











    • If you can't use a fold expression, just write the old-style recursive version instead. It's verbose but not difficult.

      – Useless
      17 mins ago






    • 1





      @AlexReinking 11 and 14 versions added.

      – Yakk - Adam Nevraumont
      14 mins ago
















    12














    template< unsigned char... indexes >
    constexpr unsigned long long mask(){
    return ((1ull<<indexes)|...|0ull);
    }


    Then



    void apply_known_mask(std::bitset<64> &bits) {
    constexpr auto m = mask<B,D,E,H,K,M,L,O>();
    bits &= m;
    }


    or in c++14:



    template< unsigned char... indexes >
    constexpr unsigned long long mask(){
    auto r = 0ull;
    using discard = int[];
    (void)discard{0,((
    r |= (1ull << indexes)
    ),0)...};
    return r;
    }


    or in c++11:



    constexpr unsigned long long mask(){
    return 0;
    }
    template<class...Tail>
    constexpr unsigned long long mask(unsigned char b0, Tail...tail){
    return (1ull<<b0) | mask(tail...);
    }
    template< unsigned char... indexes >
    constexpr unsigned long long mask(){
    return mask(indexes...);
    }


    Godbolt with all 3 -- you can switch CPP_VERSION define, and get identical assembly.



    In practice I'd use the most modern I could. 14 beats 11 because we don't have recursion and hence O(n^2) symbol length (which can explode compile time and compiler memory usage); 17 beats 14 because the compiler doesn't have to dead-code-eliminate that array, and that array trick is just ugly.



    Of these 14 is the most confusing. Here we create an anonymous array of all 0s, meanwhile as a side effect construct our result, then discard the array. It has a number of 0s in it equal to the size of our pack, plus 1 (which we add so we can handle empty packs).






    share|improve this answer


























    • Pack fold is C++17, though -- I failed to specify that we're stuck on C++11, sorry!

      – Alex Reinking
      1 hour ago











    • If you can't use a fold expression, just write the old-style recursive version instead. It's verbose but not difficult.

      – Useless
      17 mins ago






    • 1





      @AlexReinking 11 and 14 versions added.

      – Yakk - Adam Nevraumont
      14 mins ago














    12












    12








    12







    template< unsigned char... indexes >
    constexpr unsigned long long mask(){
    return ((1ull<<indexes)|...|0ull);
    }


    Then



    void apply_known_mask(std::bitset<64> &bits) {
    constexpr auto m = mask<B,D,E,H,K,M,L,O>();
    bits &= m;
    }


    or in c++14:



    template< unsigned char... indexes >
    constexpr unsigned long long mask(){
    auto r = 0ull;
    using discard = int[];
    (void)discard{0,((
    r |= (1ull << indexes)
    ),0)...};
    return r;
    }


    or in c++11:



    constexpr unsigned long long mask(){
    return 0;
    }
    template<class...Tail>
    constexpr unsigned long long mask(unsigned char b0, Tail...tail){
    return (1ull<<b0) | mask(tail...);
    }
    template< unsigned char... indexes >
    constexpr unsigned long long mask(){
    return mask(indexes...);
    }


    Godbolt with all 3 -- you can switch CPP_VERSION define, and get identical assembly.



    In practice I'd use the most modern I could. 14 beats 11 because we don't have recursion and hence O(n^2) symbol length (which can explode compile time and compiler memory usage); 17 beats 14 because the compiler doesn't have to dead-code-eliminate that array, and that array trick is just ugly.



    Of these 14 is the most confusing. Here we create an anonymous array of all 0s, meanwhile as a side effect construct our result, then discard the array. It has a number of 0s in it equal to the size of our pack, plus 1 (which we add so we can handle empty packs).






    share|improve this answer















    template< unsigned char... indexes >
    constexpr unsigned long long mask(){
    return ((1ull<<indexes)|...|0ull);
    }


    Then



    void apply_known_mask(std::bitset<64> &bits) {
    constexpr auto m = mask<B,D,E,H,K,M,L,O>();
    bits &= m;
    }


    or in c++14:



    template< unsigned char... indexes >
    constexpr unsigned long long mask(){
    auto r = 0ull;
    using discard = int[];
    (void)discard{0,((
    r |= (1ull << indexes)
    ),0)...};
    return r;
    }


    or in c++11:



    constexpr unsigned long long mask(){
    return 0;
    }
    template<class...Tail>
    constexpr unsigned long long mask(unsigned char b0, Tail...tail){
    return (1ull<<b0) | mask(tail...);
    }
    template< unsigned char... indexes >
    constexpr unsigned long long mask(){
    return mask(indexes...);
    }


    Godbolt with all 3 -- you can switch CPP_VERSION define, and get identical assembly.



    In practice I'd use the most modern I could. 14 beats 11 because we don't have recursion and hence O(n^2) symbol length (which can explode compile time and compiler memory usage); 17 beats 14 because the compiler doesn't have to dead-code-eliminate that array, and that array trick is just ugly.



    Of these 14 is the most confusing. Here we create an anonymous array of all 0s, meanwhile as a side effect construct our result, then discard the array. It has a number of 0s in it equal to the size of our pack, plus 1 (which we add so we can handle empty packs).







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited 7 mins ago

























    answered 1 hour ago









    Yakk - Adam NevraumontYakk - Adam Nevraumont

    186k19194379




    186k19194379













    • Pack fold is C++17, though -- I failed to specify that we're stuck on C++11, sorry!

      – Alex Reinking
      1 hour ago











    • If you can't use a fold expression, just write the old-style recursive version instead. It's verbose but not difficult.

      – Useless
      17 mins ago






    • 1





      @AlexReinking 11 and 14 versions added.

      – Yakk - Adam Nevraumont
      14 mins ago



















    • Pack fold is C++17, though -- I failed to specify that we're stuck on C++11, sorry!

      – Alex Reinking
      1 hour ago











    • If you can't use a fold expression, just write the old-style recursive version instead. It's verbose but not difficult.

      – Useless
      17 mins ago






    • 1





      @AlexReinking 11 and 14 versions added.

      – Yakk - Adam Nevraumont
      14 mins ago

















    Pack fold is C++17, though -- I failed to specify that we're stuck on C++11, sorry!

    – Alex Reinking
    1 hour ago





    Pack fold is C++17, though -- I failed to specify that we're stuck on C++11, sorry!

    – Alex Reinking
    1 hour ago













    If you can't use a fold expression, just write the old-style recursive version instead. It's verbose but not difficult.

    – Useless
    17 mins ago





    If you can't use a fold expression, just write the old-style recursive version instead. It's verbose but not difficult.

    – Useless
    17 mins ago




    1




    1





    @AlexReinking 11 and 14 versions added.

    – Yakk - Adam Nevraumont
    14 mins ago





    @AlexReinking 11 and 14 versions added.

    – Yakk - Adam Nevraumont
    14 mins ago













    1














    In C++11:



    template <std::size_t N>
    constexpr unsigned long long generate_mask(Flags const (&a)[N], std::size_t i = 0U){
    return i < N ? (1ull << a[i] | generate_mask(a, i + 1U)) : 0ull;
    }

    void apply_known_mask(std::bitset<64>& bits) {
    constexpr const Flags important_bits[] = { B, D, E, H, K, M, L, O };
    constexpr auto m = generate_mask(important_bits);
    bits &= m;
    }




    test



    int main() {
    std::bitset<64> b;
    b.flip();
    apply_known_mask(b);
    std::cout << b.to_string() << 'n';
    }


    output



    0000000000000000000000000000000000101110010000000000000100100100                 
    // ^ ^^^ ^ ^ ^ ^
    // O MLK H E D B





    share|improve this answer






























      1














      In C++11:



      template <std::size_t N>
      constexpr unsigned long long generate_mask(Flags const (&a)[N], std::size_t i = 0U){
      return i < N ? (1ull << a[i] | generate_mask(a, i + 1U)) : 0ull;
      }

      void apply_known_mask(std::bitset<64>& bits) {
      constexpr const Flags important_bits[] = { B, D, E, H, K, M, L, O };
      constexpr auto m = generate_mask(important_bits);
      bits &= m;
      }




      test



      int main() {
      std::bitset<64> b;
      b.flip();
      apply_known_mask(b);
      std::cout << b.to_string() << 'n';
      }


      output



      0000000000000000000000000000000000101110010000000000000100100100                 
      // ^ ^^^ ^ ^ ^ ^
      // O MLK H E D B





      share|improve this answer




























        1












        1








        1







        In C++11:



        template <std::size_t N>
        constexpr unsigned long long generate_mask(Flags const (&a)[N], std::size_t i = 0U){
        return i < N ? (1ull << a[i] | generate_mask(a, i + 1U)) : 0ull;
        }

        void apply_known_mask(std::bitset<64>& bits) {
        constexpr const Flags important_bits[] = { B, D, E, H, K, M, L, O };
        constexpr auto m = generate_mask(important_bits);
        bits &= m;
        }




        test



        int main() {
        std::bitset<64> b;
        b.flip();
        apply_known_mask(b);
        std::cout << b.to_string() << 'n';
        }


        output



        0000000000000000000000000000000000101110010000000000000100100100                 
        // ^ ^^^ ^ ^ ^ ^
        // O MLK H E D B





        share|improve this answer















        In C++11:



        template <std::size_t N>
        constexpr unsigned long long generate_mask(Flags const (&a)[N], std::size_t i = 0U){
        return i < N ? (1ull << a[i] | generate_mask(a, i + 1U)) : 0ull;
        }

        void apply_known_mask(std::bitset<64>& bits) {
        constexpr const Flags important_bits[] = { B, D, E, H, K, M, L, O };
        constexpr auto m = generate_mask(important_bits);
        bits &= m;
        }




        test



        int main() {
        std::bitset<64> b;
        b.flip();
        apply_known_mask(b);
        std::cout << b.to_string() << 'n';
        }


        output



        0000000000000000000000000000000000101110010000000000000100100100                 
        // ^ ^^^ ^ ^ ^ ^
        // O MLK H E D B






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 14 mins ago

























        answered 25 mins ago









        Stack DannyStack Danny

        1,668522




        1,668522






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54786278%2fhow-to-write-a-maintainable-fast-compile-time-bit-mask-in-c%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            ORA-01691 (unable to extend lob segment) even though my tablespace has AUTOEXTEND onORA-01692: unable to...

            Always On Availability groups resolving state after failover - Remote harden of transaction...

            Circunscripción electoral de Guipúzcoa Referencias Menú de navegaciónLas claves del sistema electoral en...