How can I shuffle bits efficiently?

前端 未结 7 1237
闹比i
闹比i 2020-12-29 06:15

I need to shuffle a 16 bit unsigned integer in a way that the even indexes land in the lower byte, and the odd indexes land in the upper byte.

input:
fedcba9         


        
7条回答
  •  难免孤独
    2020-12-29 06:53

    Tables. But generate them at compile time!

    namespace details {
      constexpr uint8_t bit( unsigned byte, unsigned n ) {
        return (byte>>n)&1;
      }
      constexpr uint8_t even_bits(uint8_t byte) {
        return bit(byte, 0) | (bit(byte, 2)<<1) | (bit(byte, 4)<<2) | (bit(byte, 6)<<3);
      }
      constexpr uint8_t odd_bits(uint8_t byte) {
        return even_bits(byte/2);
      }
      templatestruct indexes{using type=indexes;};
      templatestruct make_indexes:make_indexes{};
      templatestruct make_indexes<0,Is...>:indexes{};
      templateusing make_indexes_t=typename make_indexes::type;
    
      template
      constexpr std::array< uint8_t, 256 > even_bit_table( indexes ) {
        return { even_bits(Is)... };
      }
      template
      constexpr std::array< uint8_t, 256 > odd_bit_table( indexes ) {
        return { odd_bits(Is)... };
      }
      constexpr std::array< uint8_t, 256 > even_bit_table() {
        return even_bit_table( make_indexes_t<256>{} );
      }
      constexpr std::array< uint8_t, 256 > odd_bit_table() {
        return odd_bit_table( make_indexes_t<256>{} );
      }
    
      static constexpr auto etable = even_bit_table();
      static constexpr auto otable = odd_bit_table();
    }
    
    uint8_t constexpr even_bits( uint16_t in ) {
      return details::etable[(uint8_t)in] | ((details::etable[(uint8_t)(in>>8)])<<4);
    }
    uint8_t constexpr odd_bits( uint16_t in ) {
      return details::otable[(uint8_t)in] | ((details::otable[(uint8_t)(in>>8)])<<4);
    }
    

    live example

提交回复
热议问题