Я хочу использовать кеш, реализованный unordered_map
от boost, от dynamic_bitset
до dynamic_bitset
. Проблема, конечно, в том, что не существует хеш-функции по умолчанию из битового набора. Это не похоже на концептуальную проблему, но я не знаю, как выработать технику. Как мне это сделать?Unordered (hash) map from bitset to bitset on boost
ответ
я нашел неожиданное решение. Оказывается, у boost есть опция #define BOOST_DYNAMIC_BITSET_DONT_USE_FRIENDS
. Когда это определено, частные члены, включая m_bits
, становятся общедоступными (я думаю, что там есть дело со старыми компиляторами или чем-то еще).
Так что теперь я могу использовать @ ответ KennyTM, в видоизменилась:
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);
}
}
to_block_range
Функция копирует слова, которые битовый набор состоит из некоторого буфера. Чтобы избежать фактического копирования, вы можете определить свой собственный «выходной итератор», который просто обрабатывает отдельные слова и вычисляет хэш из них. Число рейнольдса как вычислить хеш: см., например, функция хеша FNV.
К сожалению, дизайн dynamic_bitset
является IMHO, braindead, потому что он не дает вам прямого доступа к базовому буферу (даже не как const
).
Должно ли быть действительно сложно просто скопировать-вставить заголовочный файл dynamic_bitset и заменить его на «my_dynamic_bitset», где все отличие в том, что он больше не является приватным? –
Это проблема обслуживания. Вы должны повторять ту же процедуру каждый раз, когда основной файл обновляется по любой причине. – zvrba
Это feature request.
Можно реализовать не так эффективно уникальный хеш путем преобразования BitSet к вектору временной:
namespace boost {
template <typename B, typename A>
std::size_t hash_value(const boost::dynamic_bitset<B, A>& bs) {
std::vector<B, A> v;
boost::to_block_range(bs, std::back_inserter(v));
return boost::hash_value(v);
}
}
Как это использовать? Я попытался «unordered_map
@RS: http://www.ideone.com/c2CsK – kennytm
Мы не можем непосредственно вычислить хэш, поскольку исходные данные в dynamic_bitset
является частным (m_bits
)
Но мы можем легко утонченность мимо (подрывать!) C++ спецификации системы доступа без любой
- взлома в коде или
- притворяясь ваш компилятор несоответствующего (
BOOST_DYNAMIC_BITSET_DONT_USE_FRIENDS
)
Ключ шаблон функции to_block_range
который является friend
к dynamic_bitset
. Таким образом, специализации этой функции также имеют доступ к ее личным данным (т. Е. m_bits
).
Полученный код не может быть проще
namespace boost {
// specialise dynamic bitset for size_t& to return the hash of the underlying data
template <>
inline void
to_block_range(const dynamic_bitset<>& b, size_t& hash_result)
{
hash_result = boost::hash_value(bs.m_bits);
}
std::size_t hash_value(const boost::dynamic_bitset<B, A>& bs)
{
size_t hash_result;
to_block_range(bs, hash_result);
return hash_result;
}
}
К сожалению, это не похоже на правду. Конкретная специализация функции to_block_range является другом dynamic_bitset. Невозможно иметь другую функцию с тем же именем с разными параметрами, сохраняя при этом доступ к функции друга. – BSchlinker
@BSchlinker Я не согласен: 'повышение :: dynamic_bitset' объявлен как: ' шаблона
@BSchlinker: Оригинальный шаблон функция _befriended_ является: 'шаблон <Ьурепате в, Ьурепат А, Ьурепате BlockOutputIterator> друг недействительного to_block_range (Const dynamic_bitset & Ь, BlockOutputIterator результата);' Таким образом, специализацию в 'шаблон <> инлайн недействительными \t to_block_range (минусы t dynamic_bitset <> и, tuple
предлагаемое решение создает тот же хэш в следующей ситуации.
#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 байта со всеми нулями и содержит размер бит (в этом случае размер равен 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: flip m_num_bits% bits_per_block th бит. переверните бит в зависимости от размера бит. Я считаю, что этот подход выполняется быстрее, чем 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;
}
}
- 1. bitset to dynamic bitset
- 2. BitSet to и from integer/long
- 3. convert dynamic_bitset to std :: bitset
- 4. Java Hex string to BitSet
- 5. Does BitSet flip() влияет на длину BitSet?
- 6. Конкатенация boost :: dynamic_bitset или std :: bitset
- 7. bitset :: operator [] == false/true или bitset :: test?
- 8. Подписанный int from bitset <n>
- 9. Создать большой BITSET
- 10. Преобразование BitSet в целое
- 11. Назначить значение Bitset
- 12. Сдвиг Java BitSet
- 13. Java - BitSet Замена
- 14. Класс BitSet в java
- 15. Как обрабатывать таблицу типа BitSet с помощью методов BitSet?
- 16. Какова производительность std :: bitset?
- 17. Инициализация Java Bitset
- 18. Флип Scala BitSet
- 19. JavaFX недвижимости для BitSet
- 20. Bit Порядок Java BITSET
- 21. Поле бит vs Bitset
- 22. Преобразовать байт [] в BitSet
- 23. работа с стандом :: BitSet
- 24. Изменение размера java BitSet
- 25. Java BitSet странное поведение
- 26. JAVA BitSet setting
- 27. Почему BitSet не Iterable?
- 28. BITSET разделить на голец
- 29. Java: сравнение BitSet
- 30. BITSET в объявлении шаблона
См. Https://svn.boost.org/trac/boost/ticket/2841. – kennytm
Я не могу использовать это, так как m.bits является частным членом (предложение для изменения в dynamic_bitset). –
m.bits должно быть публичным const, это довольно глупо! Можете ли вы уйти с использованием вектора (который является битрейтом, но тот, который работает MUCH nicer) в качестве ключа? –