memcmp / strcmp vs uint64_t Сравнение

У меня есть много строк размером 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

2

Решение

Если вам нужно конвертировать только строковые литералы, вы можете написать 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");
}
0

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

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

По вопросам рекламы [email protected]