2010-09-12 17 views
7

Necesito extraer y decodificar los bits (idx, idx + 1, ... idx + n_bits) de un impulso determinado dynamic_bitset. He creado la siguiente solución:Extraer subconjunto de boost dynamic_bitset

boost::dynamic_bitset<> mybitset(...); 
// build mask 2^{idx+n_bits} - 2^{idx} 
const boost::dynamic_bitset<> mask(mybitset.size(), (1 << idx+n_bits) - (1 << idx)); 
// shift the masked result idx times and get long 
unsigned long u = ((mybitset & mask) >> idx).to_ulong(); 

Funciona bien, pero a medida que este código es crítica para el desempeño de mi solicitud, estoy ansioso por ver si existe una mejor manera de lograr esto?

Respuesta

8

La solución es fácil:

#include <tuple> 
    using std::get; 
    using std::tuple; 
    using std::make_tuple; 
#include <boost/dynamic_bitset.hpp> 
    using boost::dynamic_bitset; 

template <typename Block, typename Allocator> 
unsigned block_index(const boost::dynamic_bitset<Block, Allocator>& b, unsigned pos) 
{ return pos/b.bits_per_block; } 

namespace boost { 
template <> 
inline void 
to_block_range(const dynamic_bitset<>& b, tuple<unsigned, unsigned, unsigned long&> param) 
{ 

    { 
     unsigned beg = get<0>(param); 
     unsigned len = get<1>(param); 
     unsigned block1 = block_index(b, beg); 
     unsigned block2 = block_index(b, beg + len -1); 
     unsigned bit_index = beg % b.bits_per_block; 
     unsigned long bitmask = (1 << len) - 1; 
     get<2>(param) = ((b.m_bits[block1] >> bit_index) | 
           (b.m_bits[block2] << (b.bits_per_block - bit_index) )) & 
           bitmask; 
     return; 
    } 
} 
} 


unsigned long res; 
to_block_range(bits, make_tuple(pos, len, std::ref(res))); 

para llamar:

boost::dynamic_bitset<> bits; 
unsigned long result; 
to_block_range(bits, t_extract_range{begin_bit, length_bits, result}); 

no hay apoyo directo, nativo en dynamic_bitset.

Para obtener una gama de bits, debe ingresar al dynamic_bitset, obtener acceso al almacenamiento subyacente y extraer los bits usted mismo.

El código para hacer esto es trivial pero los datos (dynamic_bitset::m_bits) están dentro de la parte privada de la clase. Hay tres formas de hackear el muro privado:

  1. Finja que el compilador no es conforme.
    #define BOOST_DYNAMIC_BITSET_DONT_USE_FRIENDS. Esto cambia private a public cambiando BOOST_DYNAMIC_BITSET_PRIVATE.
  2. Hackear el encabezado dynamic_bitset.hpp para exponer m_bits.
  3. La tercera solución es trabajar alrededor del código actual.

(1) y (2) son asaltos frágiles y frontales que serán una pesadilla de mantenimiento.

Afortunadamente para (3), hay funciones de plantilla que son friend s de dynamic_bitset. Podemos sustituir nuestra propia función para hacer nuestra propia extracción asumiendo (especializando) esta plantilla.

template <typename Block, typename Allocator, typename BlockOutputIterator> 
inline void 
to_block_range(const dynamic_bitset<Block, Allocator>& b, 
       BlockOutputIterator result) 
{ 
    std::copy(b.m_bits.begin(), b.m_bits.end(), result); 
} 

La plantilla copias función canónica del bitset toda a iterador BlockOutputIterator que es no lo que queremos.

vamos a especializarse boost::to_block_range utilizando un único tipo personalizado en lugar del BlockOutputIterator que mantendrá la totalidad 3 i/o parámetros, a saber:

  • begin_bit,
  • length_of_range y
  • destino.

Siempre que llame to_block_range con el tipo requerido, se llamará a su propia función en lugar de la plantilla estándar, pero con pleno acceso a los componentes internos también. ¡Usted esencialmente ha subvertido el sistema de especificación de acceso de C++!

N.B.El código de ejemplo no verifica errores. Ningún intento para asegurarse de

  • que el rango se ajusta a largo sin signo o
  • que el rango no excede los límites de la bitset o
  • que el bitset utiliza largos sin signo internamente.
Cuestiones relacionadas