ClickHouse/src/Functions/CRC.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

164 lines
4.5 KiB
C++
Raw Normal View History

#include <zlib.h>
#include <DataTypes/DataTypeString.h>
#include <Functions/FunctionFactory.h>
#include <Functions/FunctionStringOrArrayToT.h>
2019-12-29 01:13:17 +00:00
namespace
{
template <class T>
struct CRCBase
{
T tab[256];
2020-03-18 03:27:32 +00:00
explicit CRCBase(T polynomial)
{
for (size_t i = 0; i < 256; ++i)
{
T c = static_cast<T>(i);
for (size_t j = 0; j < 8; ++j)
c = c & 1 ? polynomial ^ (c >> 1) : c >> 1;
tab[i] = c;
}
}
};
template <class T, T polynomial>
struct CRCImpl
{
using ReturnType = T;
static T makeCRC(const unsigned char *buf, size_t size)
{
static CRCBase<ReturnType> base(polynomial);
2020-03-18 19:17:35 +00:00
T crc = 0;
2021-12-20 12:55:07 +00:00
for (size_t i = 0; i < size; ++i)
crc = base.tab[(crc ^ buf[i]) & 0xff] ^ (crc >> 8);
return crc;
}
};
2020-03-09 03:38:43 +00:00
constexpr UInt64 CRC64_ECMA = 0xc96c5795d7870f42ULL;
struct CRC64ECMAImpl : public CRCImpl<UInt64, CRC64_ECMA>
{
static constexpr auto name = "CRC64";
};
2020-03-09 03:38:43 +00:00
constexpr UInt32 CRC32_IEEE = 0xedb88320;
struct CRC32IEEEImpl : public CRCImpl<UInt32, CRC32_IEEE>
{
static constexpr auto name = "CRC32IEEE";
};
struct CRC32ZLIBImpl
{
using ReturnType = UInt32;
static constexpr auto name = "CRC32";
static UInt32 makeCRC(const unsigned char *buf, size_t size)
2020-03-18 19:17:35 +00:00
{
return static_cast<UInt32>(crc32_z(0L, buf, size));
2020-03-18 19:17:35 +00:00
}
};
2020-03-18 19:17:35 +00:00
}
namespace DB
{
namespace ErrorCodes
{
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
}
2020-09-07 18:00:37 +00:00
namespace
{
template <class Impl>
struct CRCFunctionWrapper
{
static constexpr auto is_fixed_to_constant = true;
using ReturnType = typename Impl::ReturnType;
static void vector(const ColumnString::Chars & data, const ColumnString::Offsets & offsets, PaddedPODArray<ReturnType> & res)
{
size_t size = offsets.size();
ColumnString::Offset prev_offset = 0;
for (size_t i = 0; i < size; ++i)
{
res[i] = doCRC(data, prev_offset, offsets[i] - prev_offset - 1);
prev_offset = offsets[i];
}
}
static void vectorFixedToConstant(const ColumnString::Chars & data, size_t n, ReturnType & res) { res = doCRC(data, 0, n); }
static void vectorFixedToVector(const ColumnString::Chars & data, size_t n, PaddedPODArray<ReturnType> & res)
{
size_t size = data.size() / n;
for (size_t i = 0; i < size; ++i)
{
res[i] = doCRC(data, i * n, n);
}
}
[[noreturn]] static void array(const ColumnString::Offsets & /*offsets*/, PaddedPODArray<ReturnType> & /*res*/)
{
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Cannot apply function {} to Array argument", std::string(Impl::name));
}
2021-07-04 14:26:09 +00:00
[[noreturn]] static void uuid(const ColumnUUID::Container & /*offsets*/, size_t /*n*/, PaddedPODArray<ReturnType> & /*res*/)
{
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Cannot apply function {} to UUID argument", std::string(Impl::name));
2021-07-04 14:26:09 +00:00
}
[[noreturn]] static void ipv6(const ColumnIPv6::Container & /*offsets*/, size_t /*n*/, PaddedPODArray<ReturnType> & /*res*/)
{
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Cannot apply function {} to IPv6 argument", std::string(Impl::name));
}
[[noreturn]] static void ipv4(const ColumnIPv4::Container & /*offsets*/, size_t /*n*/, PaddedPODArray<ReturnType> & /*res*/)
{
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Cannot apply function {} to IPv4 argument", std::string(Impl::name));
}
private:
static ReturnType doCRC(const ColumnString::Chars & buf, size_t offset, size_t size)
{
2022-05-27 20:51:37 +00:00
const unsigned char * p = reinterpret_cast<const unsigned char *>(buf.data()) + offset;
return Impl::makeCRC(p, size);
}
};
template <class T>
using FunctionCRC = FunctionStringOrArrayToT<CRCFunctionWrapper<T>, T, typename T::ReturnType>;
// The same as IEEE variant, but uses 0xffffffff as initial value
// This is the default
//
// (And zlib is used here, since it has optimized version)
using FunctionCRC32ZLIB = FunctionCRC<CRC32ZLIBImpl>;
// Uses CRC-32-IEEE 802.3 polynomial
using FunctionCRC32IEEE = FunctionCRC<CRC32IEEEImpl>;
// Uses CRC-64-ECMA polynomial
using FunctionCRC64ECMA = FunctionCRC<CRC64ECMAImpl>;
2020-09-07 18:00:37 +00:00
}
template <class T>
void registerFunctionCRCImpl(FunctionFactory & factory)
{
2022-08-27 20:06:03 +00:00
factory.registerFunction<T>(T::name, {}, FunctionFactory::CaseInsensitive);
}
REGISTER_FUNCTION(CRC)
{
registerFunctionCRCImpl<FunctionCRC32ZLIB>(factory);
registerFunctionCRCImpl<FunctionCRC32IEEE>(factory);
registerFunctionCRCImpl<FunctionCRC64ECMA>(factory);
}
}