Чтение целых чисел с различным порядком байтов из двоичного файла в C ++ - PullRequest
0 голосов
/ 29 ноября 2018

Я читаю ESRI Shapefile , и, к моему ужасу, в разных точках он использует порядковый и обратный порядковый номер (см., Например, таблицу на странице 4, а также таблицы со страницы 5 до8).

Итак, я создал две функции в C ++, по одной для каждой endianness .

uint32_t readBig(ifstream& f) {
    uint32_t num;
    uint8_t buf[4];
    f.read((char*)buf,4);
    num = buf[3] | buf[2]<<8 | buf[1]<<16 | buf[0]<<24;
    return num;
}

uint32_t readLittle(ifstream& f) {
    uint32_t num;
    f.read(reinterpret_cast<char *>(&num),4);
    //f.read((char*)&num,4);
    return num;
}

Но я не уверен, что это самый эффективный способсделай это. Можно ли улучшить этот код? Имейте в виду, что он будет работать тысячи, а может и миллионы раз для одного шейп-файла.Поэтому даже одна из функций, вызывающих другую, кажется хуже, чем две отдельные функции.Есть ли разница в производительности между использованием reinterpret_cast или явным преобразованием типов (char *)?Должен ли я использовать то же самое в обеих функциях?

Ответы [ 2 ]

0 голосов
/ 29 ноября 2018

В большинстве случаев компилятор должен генерировать инструкцию bswap, что, вероятно, достаточно.Однако если вам нужно что-то более быстрое, vpshufb - ваш друг ...

#include <immintrin.h>
#include <cstdint>

// swap byte order in 16 x int16
inline void swap_16xi16(uint16_t input[16])
{
  constexpr uint8_t mask_data[] = {
    1, 0, 
    3, 2,
    5, 4,
    7, 6,
    9, 8, 
    11, 10,
    13, 12,
    15, 14,
    1, 0, 
    3, 2,
    5, 4, 
    7, 6,
    9, 8, 
    11, 10,
    13, 12,
    15, 14
  };
  const __m256i swapped = _mm256_shuffle_epi8(
    _mm256_loadu_si256((const __m256i*)input), 
    _mm256_loadu_si256((const __m256i*)mask_data)
  );
  _mm256_storeu_si256((__m256i*)input, swapped);
}

// swap byte order in 8 x int32
inline void swap_8xi32(uint32_t input[8])
{
  constexpr uint8_t mask_data[] = {
    3, 2, 1, 0,
    7, 6, 5, 4,
    11, 10, 9, 8,
    15, 14, 13, 12,
    3, 2, 1, 0,
    7, 6, 5, 4,
    11, 10, 9, 8,
    15, 14, 13, 12
  };
  const __m256i swapped = _mm256_shuffle_epi8(
    _mm256_loadu_si256((const __m256i*)input), 
    _mm256_loadu_si256((const __m256i*)mask_data)
  );
  _mm256_storeu_si256((__m256i*)input, swapped);
}

// swap byte order in 4 x int64
inline void swap_4xi64(uint64_t input[4])
{
  constexpr uint8_t mask_data[] = {
    7, 6, 5, 4, 3, 2, 1, 0,
    15, 14, 13, 12, 11, 10, 9, 8,
    7, 6, 5, 4, 3, 2, 1, 0,
    15, 14, 13, 12, 11, 10, 9, 8
  };
  const __m256i swapped = _mm256_shuffle_epi8(
    _mm256_loadu_si256((const __m256i*)input), 
    _mm256_loadu_si256((const __m256i*)mask_data)
  );
  _mm256_storeu_si256((__m256i*)input, swapped);
}

inline void swap_16xi16(int16_t input[16])
  { swap_16xi16((uint16_t*)input); }
inline void swap_8xi32(int32_t input[8])
  { swap_8xi32((uint32_t*)input); }
inline void swap_4xi64(int64_t input[4])
  { swap_4xi64((uint64_t*)input); }
inline void swap_8f(float input[8])
  { swap_8xi32((uint32_t*)input); }
inline void swap_4d(double input[4])
  { swap_4xi64((uint64_t*)input); }
0 голосов
/ 29 ноября 2018
  1. Приведение между типами указателей не влияет на производительность - в этом случае это просто техническая возможность осчастливить компилятор.
  2. Если вы действительно делаете отдельный вызов read дляКаждое 32-битное значение время, затрачиваемое операцией перестановки байтов, скорее всего будет в шуме.Для скорости вам, вероятно, нужен собственный слой буферизации, чтобы внутренний цикл не вызывал никаких функций.
  3. Хорошо, если подкачка компилируется в один код операции (например, bswap), но неили это не возможно, или самый быстрый вариант, зависит от процессора.
  4. Если вы действительно заинтересованы в максимизации скорости, рассмотрите возможность использования встроенных функций SIMD.
...