2010-09-12 44 views
7

我需要從給定的boost dynamic_bitset提取和解碼位(idx,idx + 1,... idx + n_bits)。 我創建了以下解決方案:從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(); 

它運作良好,但由於這個代碼是我的應用程序的性能是至關重要的,我如果存在更好的方式來實現這一目標好奇?

回答

8

解決辦法很簡單:

#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))); 

要撥打:

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

有一個在dynamic_bitset沒有直接的,原生支持。

要獲得一系列位數,您必須進入dynamic_bitset,訪問底層存儲並自行提取數據。

執行此操作的代碼很簡單,但數據(dynamic_bitset::m_bits)位於類的專用部分內。有三種方法可以破解私人牆:

  1. 假裝你的編譯器不符合要求。
    #define BOOST_DYNAMIC_BITSET_DONT_USE_FRIENDS。這通過更改BOOST_DYNAMIC_BITSET_PRIVATEprivate更改爲public
  2. 黑客dynamic_bitset.hpp標題暴露m_bits
  3. 第三種解決方法是解決當前的代碼。

(1)和(2)是脆弱的,正面的攻擊,這將是一個維修的噩夢。

幸運的是,(3)的模板函數爲dynamic_bitsetfriend s。我們可以用我們自己的函數替代(專門化)這個模板來做我們自己的提取。

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); 
} 

的規範模板函數將整個位集到迭代器BlockOutputIterator這是我們想要的。

我們將使用代替BlockOutputIterator一個自定義類型將舉行所有3個I/O參數專門boost::to_block_range:即

  • begin_bit
  • length_of_range
  • 目的地。

提供你叫to_block_range以必要的類型,它會調用自己的函數,而不是標準的模板,但完全進入內部也是如此。你基本上已經顛覆了C++訪問規範體系!

N.B.示例代碼不會檢查錯誤。沒有嘗試,以確保

  • 的範圍unsigned long類型適合或
  • 該範圍不超過此位集或
  • 的界限位集使用無符號多頭內部。