osrm-backend/include/contractor/crc32_processor.hpp

132 lines
3.3 KiB
C++
Raw Normal View History

2014-11-28 04:07:06 -05:00
#ifndef ITERATOR_BASED_CRC32_H
#define ITERATOR_BASED_CRC32_H
#if defined(__x86_64__) && !defined(__MINGW64__)
#include <cpuid.h>
#endif
#include <boost/crc.hpp> // for boost::crc_32_type
#include <iterator>
2016-01-05 10:51:13 -05:00
namespace osrm
{
namespace contractor
{
2014-11-28 04:07:06 -05:00
class IteratorbasedCRC32
{
public:
bool UsingHardware() const { return use_hardware_implementation; }
2014-11-28 04:07:06 -05:00
IteratorbasedCRC32() : crc(0) { use_hardware_implementation = DetectHardwareSupport(); }
2014-11-28 04:07:06 -05:00
template <class Iterator> unsigned operator()(Iterator iter, const Iterator end)
{
unsigned crc = 0;
while (iter != end)
{
using value_type = typename std::iterator_traits<Iterator>::value_type;
2015-02-10 06:26:57 -05:00
const char *data = reinterpret_cast<const char *>(&(*iter));
2014-11-28 04:07:06 -05:00
if (use_hardware_implementation)
{
crc = ComputeInHardware(data, sizeof(value_type));
2014-11-28 04:07:06 -05:00
}
else
{
crc = ComputeInSoftware(data, sizeof(value_type));
2014-11-28 04:07:06 -05:00
}
++iter;
}
return crc;
}
private:
bool DetectHardwareSupport() const
2014-11-28 04:07:06 -05:00
{
static const int sse42_bit = 0x00100000;
const unsigned ecx = cpuid();
const bool sse42_found = (ecx & sse42_bit) != 0;
return sse42_found;
}
unsigned ComputeInSoftware(const char *str, unsigned len)
2014-11-28 04:07:06 -05:00
{
crc_processor.process_bytes(str, len);
return crc_processor.checksum();
}
// adapted from http://byteworm.com/2010/10/13/crc32/
unsigned ComputeInHardware(const char *str, unsigned len)
2014-11-28 04:07:06 -05:00
{
#if defined(__x86_64__)
unsigned q = len / sizeof(unsigned);
unsigned r = len % sizeof(unsigned);
unsigned *p = (unsigned *)str;
// crc=0;
while (q--)
{
__asm__ __volatile__(".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
: "=S"(crc)
: "0"(crc), "c"(*p));
++p;
}
2015-02-10 06:12:05 -05:00
str = reinterpret_cast<char *>(p);
2014-11-28 04:07:06 -05:00
while (r--)
{
__asm__ __volatile__(".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
: "=S"(crc)
: "0"(crc), "c"(*str));
++str;
}
2016-06-05 12:32:27 -04:00
#else
(void)str;
(void)len;
2014-11-28 04:07:06 -05:00
#endif
return crc;
}
inline unsigned cpuid() const
{
unsigned eax = 0, ebx = 0, ecx = 0, edx = 0;
// on X64 this calls hardware cpuid(.) instr. otherwise a dummy impl.
__get_cpuid(1, &eax, &ebx, &ecx, &edx);
return ecx;
}
#if defined(__MINGW64__) || defined(_MSC_VER) || !defined(__x86_64__)
2016-06-05 12:32:27 -04:00
inline void __get_cpuid(int /*param*/,
unsigned * /*eax*/,
unsigned * /*ebx*/,
unsigned *ecx,
unsigned * /*edx*/) const
2014-11-28 04:07:06 -05:00
{
*ecx = 0;
}
#endif
boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> crc_processor;
unsigned crc;
bool use_hardware_implementation;
};
struct RangebasedCRC32
{
2015-02-10 06:12:05 -05:00
template <typename Iteratable> unsigned operator()(const Iteratable &iterable)
2014-11-28 04:07:06 -05:00
{
return crc32(std::begin(iterable), std::end(iterable));
}
bool UsingHardware() const { return crc32.UsingHardware(); }
2014-11-28 04:07:06 -05:00
private:
IteratorbasedCRC32 crc32;
};
2016-01-05 10:51:13 -05:00
}
}
2014-11-28 04:07:06 -05:00
#endif /* ITERATOR_BASED_CRC32_H */