Байт-вектор в целочисленный тип: сдвиг и добавление или неявное преобразование через объединение?

Я в настоящее время внедряю CBOR и многократно необходимо считывать 1, 2, 4 или 8 байтов из байтового массива, который затем необходимо объединить в целочисленный тип из 1, 2, 4 или 8 байтов.

Для 4-байтового случая я сейчас использую эту функцию шаблона (vec это байтовый вектор, с которого я читаю, current_idx отмечает позицию в векторе, откуда я хочу начать чтение 4 байта):

template<typename T, typename std::enable_if<sizeof(T) == 4, int>::type = 0>
static T get_from_vector(const std::vector<uint8_t>& vec, const size_t current_idx)
{
return static_cast<T>((static_cast<T>(vec[current_idx]) << 030) +
(static_cast<T>(vec[current_idx + 1]) << 020) +
(static_cast<T>(vec[current_idx + 2]) << 010) +
static_cast<T>(vec[current_idx + 3]));
}

(У меня есть три аналогичные функции для случая 1, 2 и 8 байтов соответственно.)

Пример вызова будет

std::vector<uint8_t> vec {0x01, 0x00, 0x00, 0xff};
auto num = get_from_vector<uint32_t>(vec, 0);
assert(num == 0x10000FF);

Хотя производительность здесь не является проблемой, но мне все же интересно, может ли следующий код быть более эффективным или, по крайней мере, более читабельным:

template<typename T, typename std::enable_if<sizeof(T) == 4, int>::type = 0>
static T get_from_vector(const std::vector<uint8_t>& vec, const size_t current_idx)
{
union U
{
T result_type;
uint8_t bytes[4];
} u;
u.bytes[3] = vec[current_idx];
u.bytes[2] = vec[current_idx + 1];
u.bytes[1] = vec[current_idx + 2];
u.bytes[0] = vec[current_idx + 3];
return u.result_type;
}

Есть мысли по этому поводу?

1

Решение

Лично я предпочитаю ваш второй выбор (с помощью союзов), потому что он кажется немного быстрее и более читабельным.

Но есть и другой способ определения вашей функции: использование указателей. Преимущество заключается в том, что вам нужно определить только одну функцию, а не перегружать ее.

template<typename T>
static T get_from_vector(const std::vector<uint8_t>& vec, const size_t current_index){
T result;
uint8_t *ptr = (uint8_t *) &result;
size_t idx = current_index + sizeof(T);
while(idx > current_index)
*ptr++ = vec[--idx];
return result;
}

Изменение вашего примера звонка:

int main(){
std::vector<uint8_t> vec {0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xff};

auto byte1 = get_from_vector<uint8_t>(vec, 3);
assert(byte1 == 0xff);

auto byte2 = get_from_vector<uint16_t>(vec, 3);
assert(byte2 == 0xff01);

auto byte4 = get_from_vector<uint32_t>(vec, 4);
assert(byte4 == 0x010000ff);

auto byte8 = get_from_vector<uint64_t>(vec, 0);
assert(byte8 == 0x010000ff010000ffUL);
}
1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector