предлагаемое решение генерирует тот же хэш в следующей ситуации.
#define BOOST_DYNAMIC_BITSET_DONT_USE_FRIENDS
namespace boost {
template <typename B, typename A>
std::size_t hash_value(const boost::dynamic_bitset<B, A>& bs) {
return boost::hash_value(bs.m_bits);
}
}
boost::dynamic_biset<> test(1,false);
auto hash1 = boost::hash_value(test);
test.push_back(false);
auto hash2 = boost::hash_value(test);
// keep continue...
test.push_back(false);
auto hash31 = boost::hash_value(test);
// magically all hash1 to hash31 are the same!
предлагаемое решение иногда не подходит для отображения хеша.
Я прочитал исходный код dynamic_bitset, почему это произошлои понял, что dynamic_bitset хранит один бит на значение так же, как vector<bool>
.Например, вы вызываете dynamic_bitset<> test(1, false)
, затем dynamic_bitset первоначально выделяет 4 байта со всеми нулями, и он содержит размер битов (в этом случае size равен 1).Обратите внимание, что если размер битов становится больше 32, то он снова выделяет 4 байта и возвращает его обратно в dynamic_bitsets<>::m_bits
(поэтому m_bits - это вектор из 4 байтовых блоков).
Если я вызываю test.push_back(x)
устанавливает второй бит в x и увеличивает размер битов до 2. Если x
ложно, то m_bits[0]
не изменяется вообще!Чтобы правильно вычислить хеш, нам нужно взять m_num_bits при вычислении хеша.
Тогда вопрос в том, как?
1: Использовать boost::hash_combine
Этот подход прост и понятен.Я не проверял этот компилятор или нет.
namespace boost {
template <typename B, typename A>
std::size_t hash_value(const boost::dynamic_bitset<B, A>& bs) {
size_t tmp = 0;
boost::hash_combine(tmp,bs.m_num_bits);
boost::hash_combine(tmp,bs.m_bits);
return tmp;
}
}
2: перевернуть m_num_bits% bits_per_block-й бит.перевернуть немного в зависимости от размера.Я считаю, что этот подход быстрее, чем 1.
namespace boost {
template <typename B, typename A>
std::size_t hash_value(const boost::dynamic_bitset<B, A>& bs) {
// you may need more sophisticated bit shift approach.
auto bit = 1u << (bs.m_num_bits % bs.bits_per_block);
auto return_val = boost::hash_value(bs.m_bits);
// sorry this was wrong
//return (return_val & bit) ? return_val | bit : return_val & (~bit);
return (return_val & bit) ? return_val & (~bit) : return_val | bit;
}
}