149 lines
4.3 KiB
C++
149 lines
4.3 KiB
C++
/*
|
|
|
|
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without modification,
|
|
are permitted provided that the following conditions are met:
|
|
|
|
Redistributions of source code must retain the above copyright notice, this list
|
|
of conditions and the following disclaimer.
|
|
Redistributions in binary form must reproduce the above copyright notice, this
|
|
list of conditions and the following disclaimer in the documentation and/or
|
|
other materials provided with the distribution.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
#ifndef ITERATOR_BASED_CRC32_H
|
|
#define ITERATOR_BASED_CRC32_H
|
|
|
|
#include "../Util/SimpleLogger.h"
|
|
|
|
#include <iostream>
|
|
|
|
#if defined(__x86_64__)
|
|
#include <cpuid.h>
|
|
#else
|
|
#include <boost/crc.hpp> // for boost::crc_32_type
|
|
|
|
inline void __get_cpuid(
|
|
int param,
|
|
unsigned *eax,
|
|
unsigned *ebx,
|
|
unsigned *ecx,
|
|
unsigned *edx
|
|
) { *ecx = 0; }
|
|
#endif
|
|
|
|
template<class ContainerT>
|
|
class IteratorbasedCRC32 {
|
|
private:
|
|
typedef typename ContainerT::iterator IteratorType;
|
|
unsigned crc;
|
|
|
|
bool use_SSE42_CRC_function;
|
|
|
|
#if !defined(__x86_64__)
|
|
boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> CRC32_processor;
|
|
#endif
|
|
unsigned SoftwareBasedCRC32( char *str, unsigned len )
|
|
{
|
|
#if !defined(__x86_64__)
|
|
CRC32_processor.process_bytes( str, len);
|
|
return CRC32_processor.checksum();
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
// adapted from http://byteworm.com/2010/10/13/crc32/
|
|
unsigned SSE42BasedCRC32( char *str, unsigned len )
|
|
{
|
|
#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;
|
|
}
|
|
|
|
str=(char*)p;
|
|
while (r--) {
|
|
__asm__ __volatile__(
|
|
".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
|
|
:"=S"(crc)
|
|
:"0"(crc), "c"(*str)
|
|
);
|
|
++str;
|
|
}
|
|
#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;
|
|
}
|
|
|
|
bool DetectNativeCRC32Support()
|
|
{
|
|
static const int SSE42_BIT = 0x00100000;
|
|
const unsigned ecx = cpuid();
|
|
const bool has_SSE42 = ecx & SSE42_BIT;
|
|
if (has_SSE42) {
|
|
SimpleLogger().Write() << "using hardware based CRC32 computation";
|
|
} else {
|
|
SimpleLogger().Write() << "using software based CRC32 computation";
|
|
}
|
|
return has_SSE42;
|
|
}
|
|
|
|
public:
|
|
IteratorbasedCRC32() : crc(0)
|
|
{
|
|
use_SSE42_CRC_function = DetectNativeCRC32Support();
|
|
}
|
|
|
|
unsigned operator()( IteratorType iter, const IteratorType end )
|
|
{
|
|
unsigned crc = 0;
|
|
while(iter != end) {
|
|
char * data = reinterpret_cast<char*>(&(*iter) );
|
|
|
|
if (use_SSE42_CRC_function)
|
|
{
|
|
crc = SSE42BasedCRC32( data, sizeof(typename ContainerT::value_type) );
|
|
}
|
|
else
|
|
{
|
|
crc = SoftwareBasedCRC32( data, sizeof(typename ContainerT::value_type) );
|
|
}
|
|
++iter;
|
|
}
|
|
return crc;
|
|
}
|
|
};
|
|
|
|
#endif /* ITERATOR_BASED_CRC32_H */
|