Quiero usar una memoria caché, implementada por boost unordered_map
, desde dynamic_bitset
hasta dynamic_bitset
. El problema, por supuesto, es que no hay una función hash predeterminada del conjunto de bits. No parece ser un problema conceptual, pero no sé cómo resolver los aspectos técnicos. ¿Cómo debo hacer eso?Desordenada (hash) map from bitset to bitset on boost
Respuesta
He encontrado una solución inesperada. Resulta que boost tiene una opción para #define BOOST_DYNAMIC_BITSET_DONT_USE_FRIENDS
. Cuando esto se define, los miembros privados que incluyen m_bits
se hacen públicos (creo que está ahí para tratar con compiladores antiguos o algo así).
Así que ahora puedo utilizar @ respuesta de KennyTM, cambiado un poco:
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);
}
}
Hay to_block_range
función que copia las palabras que el conjunto de bits consiste en un búfer. Para evitar la copia real, puede definir su propio "iterador de salida" que solo procesa palabras individuales y calcula el hash de ellas. Re. cómo calcular el hash: ver p. la función hash FNV.
Desafortunadamente, el diseño de dynamic_bitset
es en mi humilde opinión, braindead porque no le da acceso directo al búfer subyacente (ni siquiera como const
).
¿Debería ser realmente difícil simplemente copiar y pegar el archivo de encabezado dynamic_bitset y reemplazarlo por "my_dynamic_bitset", donde la diferencia es que ya no es privado? –
Es un problema de mantenimiento. Debe repetir el mismo procedimiento cada vez que se actualice el archivo convencional por algún motivo. – zvrba
Es un feature request.
Se podría implementar un control único, no tan eficiente mediante la conversión de la bitset a un vector temporal:
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);
}
}
¿Cómo uso eso? Intenté "unordered_map
@RS: http://www.ideone.com/c2CsK – kennytm
No podemos calcular directamente el hash debido a que los datos subyacentes en dynamic_bitset
es privada (m_bits
)
Pero podemos fácilmente pasado finura (subvertir!) ++ c sistema de especificación de acceso sin que ninguna de
- la piratería en el código o
- pretendiendo que el compilador no es conforme (
BOOST_DYNAMIC_BITSET_DONT_USE_FRIENDS
)
La clave es la función de plantilla to_block_range
que es un friend
a dynamic_bitset
. Las especializaciones de esta función, por lo tanto, también tienen acceso a sus datos privados (es decir, m_bits
).
El código resultante no puede ser más sencillo
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;
}
}
Desafortunadamente, esto no parece ser cierto. La especialización específica de la función to_block_range es amiga de dynamic_bitset. No es posible tener otra función con el mismo nombre con diferentes parámetros mientras se mantiene el acceso de una función amiga. – BSchlinker
@BSchlinker discrepo: 'impulso :: dynamic_bitset' se declara como: ' plantilla
@BSchlinker: El función de plantilla _befriended_ original es: 'plantilla
la solución propuesta genera el mismo hash en la siguiente situación.
#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!
la solución propuesta a veces es incorrecta para el hash map.
Leí el código fuente de dynamic_bitset por qué sucedió esto y me di cuenta de que dynamic_bitset almacena un bit por valor igual que vector<bool>
. Por ejemplo, llame al dynamic_bitset<> test(1, false)
, luego dynamic_bitset inicialmente asigna 4 bytes con todo cero y contiene el tamaño de bits (en este caso, el tamaño es 1).Tenga en cuenta que si el tamaño de los bits pasa a ser mayor que 32, entonces asigna 4 bytes nuevamente y lo vuelve a insertar en dynamic_bitsets<>::m_bits
(entonces m_bits es un vector de 4 bloques de bytes).
Si llamo a test.push_back(x)
, establece el segundo bit en x y aumenta el tamaño de los bits a 2. Si x
es falso, entonces m_bits[0]
no cambia en absoluto! Para calcular correctamente hash, necesitamos tomar m_num_bits en cálculo hash.
Entonces, la pregunta es ¿cómo?
1: Use boost::hash_combine
Este enfoque es simple y directo. No revisé esta compilación o no.
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 bit. voltear un poco según el tamaño del bit. Creo que este enfoque es más rápido que 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. Concatenate boost :: dynamic_bitset o std :: bitset
- 2. Bitset Referencia
- 3. Convierte BitSet a int
- 4. Bit campo vs Bitset
- 5. Java BitSet Ejemplo
- 6. usando recipiente bitset en C++
- 7. binario serialización de std :: bitset
- 8. Guardar BitSet de Java en DB
- 9. booleano [] vs. BitSet: ¿Cuál es más eficiente?
- 10. BitSet hacia y desde entero/largo
- 11. Python equivalente al BitSet de Java
- 12. BitSet uso de memoria en Scala
- 13. Convertir matriz de bytes en Bitset
- 14. Convertir un byte o int a BitSet
- 15. Inicializar al azar BitSet en JAVA
- 16. Map from integer ranges to arbitrary single integers
- 17. Scala mutable BitSet, ¿dónde están las operaciones de mutación?
- 18. ¿Alternativa a Java Bitset con rendimiento tipo array?
- 19. ¿Cómo puedo convertir bitset en abreviado en C++?
- 20. escribiendo un BitSet en un archivo en java
- 21. Java BitSet que permite la fácil Concatenación de BitSets
- 22. ¿Manera eficiente de iterar sobre bits verdaderos en std :: bitset?
- 23. ¿Cómo convierto bitset a una matriz de bytes/uint8?
- 24. Tool to Map # include's
- 25. Hash Map en Python
- 26. load std :: map from text file
- 27. Port Boost to Android
- 28. Map to String en Java
- 29. Porting std :: map to C?
- 30. Mapping std :: map to Python
Ver https://svn.boost.org/trac/boost/ticket/2841. – kennytm
No puedo usar esto porque m.bits es un miembro privado (la sugerencia es para un cambio en dynamic_bitset). –
m.bits debe ser público, ¡eso es bastante estúpido! ¿Puedes salirte con la suya usando el vector (que es un conjunto de bits, pero que funciona MUCHO mejor) como la clave? –