mirror of
https://github.com/claunia/findcrcs.git
synced 2025-12-16 10:44:25 +00:00
308 lines
9.4 KiB
C++
308 lines
9.4 KiB
C++
// Copyright 2010 Google Inc. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
// This is the only file where all details of CRC implementation are buried.
|
|
|
|
#include "interface.h"
|
|
|
|
#include "aligned_alloc.h"
|
|
#include "crc32c_sse4.h"
|
|
#include "generic_crc.h"
|
|
#include "protected_crc.h"
|
|
#include "rolling_crc.h"
|
|
|
|
// Align all CRC tables on kAlign boundary.
|
|
// Shall be exact power of 2.
|
|
static size_t kAlign = 4 * 1024;
|
|
|
|
using namespace crcutil;
|
|
|
|
#if defined(__GNUC__)
|
|
// Suppress 'invalid access to non-static data member ... of NULL object'
|
|
#undef offsetof
|
|
#define offsetof(TYPE, MEMBER) (reinterpret_cast <size_t> \
|
|
((&reinterpret_cast <const char &>( \
|
|
reinterpret_cast <const TYPE *>(1)->MEMBER))) - 1)
|
|
#endif // defined(__GNUC__)
|
|
|
|
namespace crcutil_interface {
|
|
|
|
template<typename CrcImplementation, typename RollingCrcImplementation>
|
|
class Implementation : public CRC {
|
|
public:
|
|
typedef typename CrcImplementation::Crc Crc;
|
|
typedef Implementation<CrcImplementation, RollingCrcImplementation> Self;
|
|
|
|
Implementation(const Crc &poly,
|
|
size_t degree,
|
|
bool canonical,
|
|
const Crc &roll_start_value,
|
|
size_t roll_length)
|
|
: crc_(poly, degree, canonical),
|
|
rolling_crc_(crc_, roll_length, roll_start_value) {
|
|
}
|
|
|
|
static Self *Create(const Crc &poly,
|
|
size_t degree,
|
|
bool canonical,
|
|
const Crc &roll_start_value,
|
|
size_t roll_length,
|
|
const void **allocated_memory) {
|
|
void *memory = AlignedAlloc(sizeof(Self),
|
|
offsetof(Self, crc_),
|
|
kAlign,
|
|
allocated_memory);
|
|
return new(memory) Self(poly,
|
|
degree,
|
|
canonical,
|
|
roll_start_value,
|
|
roll_length);
|
|
}
|
|
|
|
virtual void Delete() {
|
|
AlignedFree(this);
|
|
}
|
|
|
|
void *operator new(size_t, void *p) {
|
|
return p;
|
|
}
|
|
|
|
virtual void GeneratingPolynomial(/* OUT */ UINT64 *lo,
|
|
/* OUT */ UINT64 *hi = NULL) const {
|
|
SetValue(crc_.Base().GeneratingPolynomial(), lo, hi);
|
|
}
|
|
|
|
virtual size_t Degree() const {
|
|
return crc_.Base().Degree();
|
|
}
|
|
|
|
virtual void CanonizeValue(/* OUT */ UINT64 *lo,
|
|
/* OUT */ UINT64 *hi = NULL) const {
|
|
SetValue(crc_.Base().Canonize(), lo, hi);
|
|
}
|
|
|
|
virtual void RollStartValue(/* OUT */ UINT64 *lo,
|
|
/* OUT */ UINT64 *hi = NULL) const {
|
|
SetValue(rolling_crc_.StartValue(), lo, hi);
|
|
}
|
|
|
|
virtual size_t RollWindowBytes() const {
|
|
return rolling_crc_.WindowBytes();
|
|
}
|
|
|
|
virtual void SelfCheckValue(/* OUT */ UINT64 *lo,
|
|
/* OUT */ UINT64 *hi = NULL) const {
|
|
Crc crc = crc_.CrcDefault(&crc_, sizeof(crc_), 0);
|
|
crc = crc_.CrcDefault(&rolling_crc_, sizeof(rolling_crc_), crc);
|
|
SetValue(crc, lo, hi);
|
|
}
|
|
|
|
virtual void Compute(const void *data,
|
|
size_t bytes,
|
|
/* INOUT */ UINT64 *lo,
|
|
/* INOUT */ UINT64 *hi = NULL) const {
|
|
SetValue(crc_.CrcDefault(data, bytes, GetValue(lo, hi)), lo, hi);
|
|
}
|
|
|
|
virtual void RollStart(const void *data,
|
|
/* INOUT */ UINT64 *lo,
|
|
/* INOUT */ UINT64 *hi = NULL) const {
|
|
SetValue(rolling_crc_.Start(data), lo, hi);
|
|
}
|
|
|
|
virtual void Roll(size_t byte_out,
|
|
size_t byte_in,
|
|
/* INOUT */ UINT64 *lo,
|
|
/* INOUT */ UINT64 *hi = NULL) const {
|
|
SetValue(rolling_crc_.Roll(GetValue(lo, hi), byte_out, byte_in), lo, hi);
|
|
}
|
|
|
|
virtual void CrcOfZeroes(UINT64 bytes,
|
|
/* INOUT */ UINT64 *lo,
|
|
/* INOUT */ UINT64 *hi = NULL) const {
|
|
SetValue(crc_.Base().CrcOfZeroes(bytes, GetValue(lo, hi)), lo, hi);
|
|
}
|
|
|
|
virtual void ChangeStartValue(
|
|
UINT64 start_old_lo, UINT64 start_old_hi,
|
|
UINT64 start_new_lo, UINT64 start_new_hi,
|
|
UINT64 bytes,
|
|
/* INOUT */ UINT64 *lo,
|
|
/* INOUT */ UINT64 *hi = NULL) const {
|
|
SetValue(crc_.Base().ChangeStartValue(
|
|
GetValue(lo, hi),
|
|
bytes,
|
|
GetValue(start_old_lo, start_old_hi),
|
|
GetValue(start_new_lo, start_new_hi)),
|
|
lo,
|
|
hi);
|
|
}
|
|
|
|
virtual void Concatenate(UINT64 crcB_lo, UINT64 crcB_hi,
|
|
UINT64 bytes_B,
|
|
/* INOUT */ UINT64* crcA_lo,
|
|
/* INOUT */ UINT64* crcA_hi = NULL) const {
|
|
SetValue(crc_.Base().Concatenate(GetValue(crcA_lo, crcA_hi),
|
|
GetValue(crcB_lo, crcB_hi),
|
|
bytes_B),
|
|
crcA_lo,
|
|
crcA_hi);
|
|
}
|
|
|
|
virtual size_t StoreComplementaryCrc(
|
|
void *dst,
|
|
UINT64 message_crc_lo, UINT64 message_crc_hi,
|
|
UINT64 result_crc_lo, UINT64 result_crc_hi = 0) const {
|
|
return crc_.Base().StoreComplementaryCrc(
|
|
dst,
|
|
GetValue(message_crc_lo, message_crc_hi),
|
|
GetValue(result_crc_lo, result_crc_hi));
|
|
}
|
|
|
|
virtual size_t StoreCrc(void *dst,
|
|
UINT64 lo,
|
|
UINT64 hi = 0) const {
|
|
return crc_.Base().StoreCrc(dst, GetValue(lo, hi));
|
|
}
|
|
|
|
virtual void CrcOfCrc(/* OUT */ UINT64 *lo,
|
|
/* OUT */ UINT64 *hi = NULL) const {
|
|
SetValue(crc_.Base().CrcOfCrc(), lo, hi);
|
|
}
|
|
|
|
private:
|
|
static Crc GetValue(UINT64 *lo, UINT64 *hi) {
|
|
if (sizeof(Crc) <= sizeof(*lo)) {
|
|
return CrcFromUint64<Crc>(*lo);
|
|
} else {
|
|
return CrcFromUint64<Crc>(*lo, *hi);
|
|
}
|
|
}
|
|
|
|
static Crc GetValue(UINT64 lo, UINT64 hi) {
|
|
return CrcFromUint64<Crc>(lo, hi);
|
|
}
|
|
|
|
static void SetValue(const Crc &crc, UINT64 *lo, UINT64 *hi) {
|
|
Uint64FromCrc<Crc>(crc,
|
|
reinterpret_cast<crcutil::uint64 *>(lo),
|
|
reinterpret_cast<crcutil::uint64 *>(hi));
|
|
}
|
|
|
|
const CrcImplementation crc_;
|
|
const RollingCrcImplementation rolling_crc_;
|
|
|
|
const Self &operator =(const Self &) {}
|
|
};
|
|
|
|
#if defined(_MSC_VER)
|
|
// 'use_sse4_2' : unreferenced formal parameter
|
|
#pragma warning(disable: 4100)
|
|
#endif // defined(_MSC_VER)
|
|
|
|
bool CRC::IsSSE42Available() {
|
|
#if HAVE_AMD64 || HAVE_I386
|
|
return Crc32cSSE4::IsSSE42Available();
|
|
#else
|
|
return false;
|
|
#endif // HAVE_AMD64 || HAVE_I386
|
|
}
|
|
|
|
CRC::~CRC() {}
|
|
CRC::CRC() {}
|
|
|
|
CRC *CRC::Create(UINT64 poly_lo,
|
|
UINT64 poly_hi,
|
|
size_t degree,
|
|
bool canonical,
|
|
UINT64 roll_start_value_lo,
|
|
UINT64 roll_start_value_hi,
|
|
size_t roll_length,
|
|
bool use_sse4_2,
|
|
const void **allocated_memory) {
|
|
if (degree == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
if (degree > 64) {
|
|
#if !HAVE_SSE2
|
|
return NULL;
|
|
#else
|
|
if (degree > 128) {
|
|
return NULL;
|
|
}
|
|
uint128_sse2 poly = CrcFromUint64<uint128_sse2>(poly_lo, poly_hi);
|
|
if (degree != 128 && (poly >> degree) != 0) {
|
|
return NULL;
|
|
}
|
|
uint128_sse2 roll_start_value =
|
|
CrcFromUint64<uint128_sse2>(roll_start_value_lo, roll_start_value_hi);
|
|
if (degree != 128 && (roll_start_value >> degree) != 0) {
|
|
return NULL;
|
|
}
|
|
#if HAVE_I386
|
|
typedef GenericCrc<uint128_sse2, uint128_sse2, crcutil::uint32, 3> Crc128;
|
|
#elif defined(__GNUC__) && GCC_VERSION_AVAILABLE(4, 5)
|
|
typedef GenericCrc<uint128_sse2, uint128_sse2, crcutil::uint64, 6> Crc128;
|
|
#else
|
|
typedef GenericCrc<uint128_sse2, uint128_sse2, crcutil::uint64, 4> Crc128;
|
|
#endif // HAVE_I386
|
|
return Implementation<Crc128, RollingCrc<Crc128> >::Create(
|
|
poly,
|
|
degree,
|
|
canonical,
|
|
roll_start_value,
|
|
roll_length,
|
|
allocated_memory);
|
|
#endif // !HAVE_SSE2
|
|
}
|
|
|
|
#if CRCUTIL_USE_MM_CRC32 && (HAVE_I386 || HAVE_AMD64)
|
|
if (use_sse4_2 &&
|
|
degree == Crc32cSSE4::FixedDegree() &&
|
|
poly_lo == Crc32cSSE4::FixedGeneratingPolynomial() &&
|
|
poly_hi == 0) {
|
|
if (roll_start_value_hi != 0 || (roll_start_value_lo >> 32) != 0) {
|
|
return NULL;
|
|
}
|
|
return Implementation<Crc32cSSE4, RollingCrc32cSSE4>::Create(
|
|
static_cast<size_t>(poly_lo),
|
|
degree,
|
|
canonical,
|
|
static_cast<size_t>(roll_start_value_lo),
|
|
static_cast<size_t>(roll_length),
|
|
allocated_memory);
|
|
}
|
|
#endif // CRCUTIL_USE_MM_CRC32 && (HAVE_I386 || HAVE_AMD64)
|
|
|
|
if (poly_hi != 0 || (degree != 64 && (poly_lo >> degree) != 0)) {
|
|
return NULL;
|
|
}
|
|
if (roll_start_value_hi != 0 ||
|
|
(degree != 64 && (roll_start_value_lo >> degree) != 0)) {
|
|
return NULL;
|
|
}
|
|
typedef GenericCrc<crcutil::uint64, crcutil::uint64, crcutil::uint64, 4>
|
|
Crc64;
|
|
return Implementation<Crc64, RollingCrc<Crc64> >::Create(
|
|
poly_lo,
|
|
degree,
|
|
canonical,
|
|
roll_start_value_lo,
|
|
roll_length,
|
|
allocated_memory);
|
|
}
|
|
|
|
} // namespace crcutil_interface
|