У меня есть много строк размером 8 или меньше.
Мне нужно сделать много сравнений там, используя memcmp()
/ strcmp()
,
Интересно, будут ли сравнения работать быстрее, если я преобразую все их в std::uint64_t
, В этом случае, по крайней мере, по теории сравнение будет без ветвления и произойдет в одной операции ЦП.
Кто-нибудь пробовал что-то подобное?
Вот некоторый тестовый код, который генерирует эти числа. Я предполагаю, что машина с прямым порядком байтов
Я знаю, что код может быть значительно упрощен, если я использую htobe32()
/ htobe64()
,
#include <cstdint>
#include <algorithm> // std::reverse_copy
namespace rev_impl{
template<typename T>
T rev(const char *s){
T t;
char *pt = reinterpret_cast<char *>(&t);
std::reverse_copy(s, s + sizeof(T), pt);
return t;
}
}
inline uint32_t rev32(const char *s){
return rev_impl::rev<uint32_t>(s);
}
inline uint64_t rev64(const char *s){
return rev_impl::rev<uint64_t>(s);
}#include <iostream>
#include <iomanip>
template<typename T>
void print_rev(const char *s){
constexpr auto w = sizeof(T) * 2;
std::cout << std::setw(w) << std::setfill('.') << std::hex << rev_impl::rev<T>(s) << '\n';
}
inline void print_rev32(const char *s){
return print_rev<uint32_t>(s);
}
inline void print_rev64(const char *s){
return print_rev<uint64_t>(s);
}
int main(){
print_rev64("\0\0\0\0\0\0\0a");
print_rev64("a\0\0\0\0\0\0\0");
print_rev32("Niki");
print_rev32("Nika");
print_rev32("Nikz");
}
вот тестовый вывод:
..............61
6100000000000000
4e696b69
4e696b61
4e696b7a
Если вам нужно конвертировать только строковые литералы, вы можете написать rev
принять массив char
следующим образом
template <typename T, std::size_t N,
typename = typename std::enable_if<(N<=sizeof(T)+1U)>::type>
constexpr T rev (char const (&arr)[N])
{
T ret = 0;
std::size_t ui = -1;
while ( ++ui < N-1U )
ret <<= CHAR_BIT, ret |= arr[ui];
while ( ++ui < sizeof(T) )
ret <<= CHAR_BIT;
return ret;
}
Заметьте, что начиная с C ++ 14 эту функцию можно определить constexpr
, так что вы можете написать что-то как
constexpr auto fb = rev<std::uint64_t>("foobar");
Ниже вы переписали код для использования строковых литералов
#include <cstdint>
#include <climits>
#include <iostream>
#include <iomanip>
#include <type_traits>
namespace rev_impl
{
template <typename T, std::size_t N,
typename = typename std::enable_if<(N<=sizeof(T)+1U)>::type>
T rev (char const (&arr)[N])
{
T ret = 0;
std::size_t ui = -1;
while ( ++ui < N-1U )
ret <<= CHAR_BIT, ret |= arr[ui];
while ( ++ui < sizeof(T) )
ret <<= CHAR_BIT;
return ret;
}
}
template <typename T, std::size_t N>
inline uint32_t rev32 (char const (&s)[N])
{ return rev_impl::rev<uint32_t>(s); }
template <typename T, std::size_t N>
inline uint64_t rev64 (char const (&s)[N])
{ return rev_impl::rev<uint64_t>(s); }
template<typename T, std::size_t N>
void print_rev (char const (&s)[N])
{
constexpr auto w = sizeof(T) * 2;
std::cout << std::setw(w) << std::setfill('.') << std::hex
<< rev_impl::rev<T>(s) << '\n';
}
template <std::size_t N>
inline void print_rev32 (char const (&s)[N])
{ return print_rev<uint32_t>(s); }
template <std::size_t N>
inline void print_rev64 (char const (&s)[N])
{ return print_rev<uint64_t>(s); }
int main ()
{
print_rev64("\0\0\0\0\0\0\0a");
print_rev64("a\0\0\0\0\0\0\0");
print_rev32("Niki");
print_rev32("Nika");
print_rev32("Nikz");
}
Других решений пока нет …