Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Help with templatizing byteswapping function, performance hit?

template<int size>
inline void* byteswap(void* __x);

template<>
inline void* byteswap<2>(void* __x)
{
    return (*(uint16*)__x >> 8) | (*(uint16*)__x << 8);
}

template<>
inline void* byteswap<4>(void* __x)
{
    return (byteswap<4>(__x & 0xffff) << 16) | (bswap_16 (__x >> 16));
}

template<typename T>
inline T byteswap(T& swapIt)
{
    return (T*)byteswap<sizeof(T)>(swapIt);
}    

int main() {
    uint32 i32 = 0x01020304;
    uint16 i16 = 0x0102;

    byteswap(i32);
    byteswap(i16);

    return 0;
}

The above obviously doesn't even compile. I'm confused as it seems that I need void* as parameter for the function and things kinda get ugly in byteswap<4> when I need to call byteswap<2> but with a reference.

Any idea how to make this look pretty? Is it possible for it to achieve (using inlining or other tricks) to make it as performance as doing the bit-operations directly?

like image 817
chriskirk Avatar asked Feb 03 '11 14:02

chriskirk


2 Answers

This is how I'd code it:

#include <iostream>

typedef unsigned short uint16;
typedef unsigned int uint32;

template<typename T> T byteswap(T value);

template<>
uint16 byteswap<uint16>(uint16 value)
{
    return (value >> 8)|(value << 8);
}

template<>
uint32 byteswap<uint32>(uint32 value)
{
    return uint32(byteswap<uint16>(value) << 16) | byteswap<uint16>(value >> 16);
}

int main() {
    uint32 i32 = 0x11223344;
    uint16 i16 = 0x2142;

    std::cout << std::hex << byteswap(i32) << std::endl; // prints 44332211
    std::cout << std::hex << byteswap(i16) << std::endl; // prints 4221
}

in other words, I wouldn't use size as template parameter as you were doing.

EDIT
sorry, my first code was plain wrong wrt/ uint32 swapping.

like image 53
Simone Avatar answered Nov 15 '22 09:11

Simone


Borrowing from some code:

template<int N>
void byteswap_array(char (&bytes)[N]) {
  // Optimize this with a platform-specific API as desired.
  for (char *p = bytes, *end = bytes + N - 1; p < end; ++p, --end) {
    char tmp = *p;
    *p = *end;
    *end = tmp;
  }
}

template<typename T>
T byteswap(T value) {
  byteswap_array(*reinterpret_cast<char (*)[sizeof(value)]>(&value));
  return value;
}
like image 36
Fred Nurk Avatar answered Nov 15 '22 08:11

Fred Nurk