Search code examples
c++arraystype-conversiondeflate

How to traverse a character array storing {int, short, ushort,...} more efficiently?


I have a char data[len] populated from unzipped data that is read off of a binary file. I know that data can only be of these types: char, uchar, short, ushort, int, uint, float, double for which I know exact number of bits needed to represent (elesize = {8, 16, 32, 64}).

I just want to traverse the data list and, say, find the max(), min() or number of occurrences of a given number. and I want to do this without creating another array for memory space concerns.

I have come up with the following but it is slow for example for len == 34560000

So I was wondering if anyone has a 'one-liner' or a more efficient way for doing this (either C or C++).

char data[len];
double mymax = -std::numeric_limits<double>::max()
for (size_t i=0; i<len; i += elesize)
{
    double x;
    char *r = data+i;
    if (elementtype == "char")
        x = static_cast<double>(*r);
    else if (elementtype == "uchar")
        x = static_cast<double>(*((unsigned char *)r));
    else if (elementtype == "short")
        x = static_cast<double>(*((int16_t *)r));
    else if (elementtype == "ushort")
        x = static_cast<double>(*((uint16_t *)r));
    else if (elementtype == "int")
        x = static_cast<double>(*((int32_t *)r));
    else if (elementtype == "uint")
        x = static_cast<double>(*((uint32_t *)r));
    else if (elementtype == "float")
        x = static_cast<double>(*((float *)r));
    else if (elementtype == "double")
        x = *((double *)r);
    if (x > mymax)
        mymax = x;
}

Solution

  • A template should do nicely:

    #include <algorithm>
    
    template <typename T>
    T read_and_advance(const unsigned char * & p)
    {
      T x;
      unsigned char * const px = reinterpret_cast<unsigned char *>(&x);
    
      std::copy(p, p + sizeof(T), px);
      P += sizeof(T);
    
      return x;
    }
    

    Usage:

    const unsigned char * p = the_data;
    unsigned int max = 0;
    
    while (p != the_data + data_length)
    {
      max = std::max(max, read_and_advance<unsigned int>(p));
    }
    

    Scrap this, I thought originally the question was for C.

    Here's a macro:

    #define READ_TYPE(T, buf, res) do { memcpy(&res, buf, sizeof(T)); buf += sizeof(T); } while (false)
    

    Usage:

    int max = 0;
    unsigned char * p = data;
    
    while (true)
    {
      unsigned int res;
      READ_TYPE(unsigned int, p, res);
      if (res > max) max = res;
    }
    

    You don't really get around specifying the type, though. In C++ this could be done a bit more elegantly.

    Alternatively you can wrap it all in one:

    #define READ_TYPE_AND_MAX(T, buf, max)  \
      do { T x; memcpy(&x, buf, sizeof(T)); \
           buf += sizeof(T);                \
           if (max < x) max = x;            \
      } while (false)
    
    // Usage:
    unsigned int max = 0;
    unsigned char * p = data;
    while (true) { READ_TYPE_AND_MAX(unsigned int, p, max); }