Estou tentando converter dados integrais não assinados em sua representação binária na memória da maneira mais eficiente possível.
Escrevi quatro funções de modelo para converter os inteiros em little endian e big endian, duas delas usam operações de bits e as outras duas usam ponteiros para copiar dados.
Eles foram verificados como corretos e também muito eficientes, pois determinei que as funções little endian são tão rápidas quanto std::memcpy
, mas as funções big endian de alguma forma demoram um pouco mais.
Essas funções são:
#include <vector>
using std::vector;
typedef vector<uint8_t> bytes;
template<class T>
inline bytes LittleEndian(const T& data) {
size_t size = sizeof(T);
bytes _bytes(size);
uint8_t mask = 255;
for (size_t i = 0, shift = 0; i < size; i++, shift += 8) {
_bytes[i] = (data >> shift) & mask;
}
return _bytes;
}
template<class T>
inline bytes BigEndian(const T& data) {
size_t size = sizeof(T);
bytes _bytes(size);
uint8_t mask = 255;
for (size_t i = size, shift = 0; i-- > 0; shift += 8) {
_bytes[i] = (data >> shift) & mask;
}
return _bytes;
}
template<class T>
inline bytes CPU_Endian(const T& data) {
size_t size = sizeof(T);
bytes _bytes(size);
uint8_t* dst = (uint8_t *)_bytes.data(), * src = (uint8_t *) & data;
for (size_t i = 0; i < size; i++) {
*dst++ = *src++;
}
return _bytes;
}
template<class T>
inline bytes Flip_CPU_Endian(const T& data) {
size_t size = sizeof(T);
bytes _bytes(size);
uint8_t* dst = (uint8_t *)_bytes.data(), * src = (uint8_t *)&data + size - 1;
for (size_t i = 0; i < size; i++) {
*dst++ = *src--;
}
return _bytes;
}
E eu quero desenrolar os loops for usando std::index_sequence
, e como eles estão relacionados, coloquei-os em uma pergunta. Tratam-se de três coisas: fazer algo repetidamente N vezes, criar uma sequência de índice que diminui em vez de aumentar e usar o índice para definir valores.
Eu tentei fazer isso sozinho, mas não funciona:
template<class T>
inline bytes CPU_Endian2(const T& data) {
size_t size = sizeof(T);
bytes _bytes(size);
uint8_t* dst = (uint8_t*)_bytes.data(), * src = (uint8_t*)&data;
[&]<std::size_t...N>(std::index_sequence<N...>){
((*dst++ = *src++),...);
}(std::make_index_sequence<size>{});
return _bytes;
}
Não compila, log de erros:
Build started at 18:54...
1>------ Build started: Project: hexlify_test, Configuration: Release x64 ------
1>hexlify_test.cpp
1>C:\Users\Estranger\source\repos\hexlify_test\hexlify_test.cpp(98,3): error C7515: a fold expression must contain an unexpanded parameter pack
1>C:\Users\Estranger\source\repos\hexlify_test\hexlify_test.cpp(99,3): error C3878: syntax error: unexpected token '(' following 'expression'
1>C:\Users\Estranger\source\repos\hexlify_test\hexlify_test.cpp(99,3): message : error recovery skipped: '( identifier :: . . . {'
1>C:\Users\Estranger\source\repos\hexlify_test\hexlify_test.cpp(99,35): error C2760: syntax error: '}' was unexpected here; expected ';'
1>Done building project "hexlify_test.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
========== Build completed at 18:54 and took 01.796 seconds ==========
Como posso converter essas funções para aquelas que usam std::index_sequence
em vez de loops for?
Adicionar constexpr
a size_t size = sizeof(T);
falhou ao compilá-lo.
Você tem 2 problemas:
size
não éconstexpr
, portanto não pode ser usado como argumento de modelo.->
constexpr size_t size = sizeof(T);
Sua expressão fold não usa nenhum pacote
Então também
ou
Juntos, seria
Demonstração