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?
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
add a comment |
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
Rather than using a loop, can't you construct a mask withB | 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
add a comment |
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
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
c++ c++11 bit-manipulation
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 withB | 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
add a comment |
Rather than using a loop, can't you construct a mask withB | 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
add a comment |
2 Answers
2
active
oldest
votes
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).
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
add a comment |
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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).
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
add a comment |
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).
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
add a comment |
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).
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).
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
add a comment |
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
add a comment |
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
add a comment |
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
add a comment |
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
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
edited 14 mins ago
answered 25 mins ago
Stack DannyStack Danny
1,668522
1,668522
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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