ClickHouse
158 строк · 4.5 Кб
1#include <zlib.h>2#include <DataTypes/DataTypeString.h>3#include <Functions/FunctionFactory.h>4#include <Functions/FunctionStringOrArrayToT.h>5
6
7namespace
8{
9
10template <class T>11struct CRCBase12{
13T tab[256];14explicit CRCBase(T polynomial)15{16for (size_t i = 0; i < 256; ++i)17{18T c = static_cast<T>(i);19for (size_t j = 0; j < 8; ++j)20c = c & 1 ? polynomial ^ (c >> 1) : c >> 1;21tab[i] = c;22}23}24};25
26template <class T, T polynomial>27struct CRCImpl28{
29using ReturnType = T;30
31static T makeCRC(const unsigned char *buf, size_t size)32{33static CRCBase<ReturnType> base(polynomial);34
35T crc = 0;36for (size_t i = 0; i < size; ++i)37crc = base.tab[(crc ^ buf[i]) & 0xff] ^ (crc >> 8);38return crc;39}40};41
42constexpr UInt64 CRC64_ECMA = 0xc96c5795d7870f42ULL;43struct CRC64ECMAImpl : public CRCImpl<UInt64, CRC64_ECMA>44{
45static constexpr auto name = "CRC64";46};47
48constexpr UInt32 CRC32_IEEE = 0xedb88320;49struct CRC32IEEEImpl : public CRCImpl<UInt32, CRC32_IEEE>50{
51static constexpr auto name = "CRC32IEEE";52};53
54struct CRC32ZLibImpl55{
56using ReturnType = UInt32;57static constexpr auto name = "CRC32";58
59static UInt32 makeCRC(const unsigned char *buf, size_t size)60{61return static_cast<UInt32>(crc32_z(0L, buf, size));62}63};64
65}
66
67namespace DB68{
69
70namespace ErrorCodes71{
72extern const int ILLEGAL_TYPE_OF_ARGUMENT;73}
74
75namespace
76{
77
78template <class Impl>79struct CRCFunctionWrapper80{
81static constexpr auto is_fixed_to_constant = true;82using ReturnType = typename Impl::ReturnType;83
84static void vector(const ColumnString::Chars & data, const ColumnString::Offsets & offsets, PaddedPODArray<ReturnType> & res)85{86size_t size = offsets.size();87
88ColumnString::Offset prev_offset = 0;89for (size_t i = 0; i < size; ++i)90{91res[i] = doCRC(data, prev_offset, offsets[i] - prev_offset - 1);92prev_offset = offsets[i];93}94}95
96static void vectorFixedToConstant(const ColumnString::Chars & data, size_t n, ReturnType & res) { res = doCRC(data, 0, n); }97
98static void vectorFixedToVector(const ColumnString::Chars & data, size_t n, PaddedPODArray<ReturnType> & res)99{100size_t size = data.size() / n;101
102for (size_t i = 0; i < size; ++i)103{104res[i] = doCRC(data, i * n, n);105}106}107
108[[noreturn]] static void array(const ColumnString::Offsets & /*offsets*/, PaddedPODArray<ReturnType> & /*res*/)109{110throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Cannot apply function {} to Array argument", std::string(Impl::name));111}112
113[[noreturn]] static void uuid(const ColumnUUID::Container & /*offsets*/, size_t /*n*/, PaddedPODArray<ReturnType> & /*res*/)114{115throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Cannot apply function {} to UUID argument", std::string(Impl::name));116}117
118[[noreturn]] static void ipv6(const ColumnIPv6::Container & /*offsets*/, size_t /*n*/, PaddedPODArray<ReturnType> & /*res*/)119{120throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Cannot apply function {} to IPv6 argument", std::string(Impl::name));121}122
123[[noreturn]] static void ipv4(const ColumnIPv4::Container & /*offsets*/, size_t /*n*/, PaddedPODArray<ReturnType> & /*res*/)124{125throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Cannot apply function {} to IPv4 argument", std::string(Impl::name));126}127
128private:129static ReturnType doCRC(const ColumnString::Chars & buf, size_t offset, size_t size)130{131const unsigned char * p = reinterpret_cast<const unsigned char *>(buf.data()) + offset;132return Impl::makeCRC(p, size);133}134};135
136template <typename T>137using FunctionCRC = FunctionStringOrArrayToT<CRCFunctionWrapper<T>, T, typename T::ReturnType>;138
139// The same as IEEE variant, but uses 0xffffffff as initial value
140// This is the default
141//
142// (And ZLib is used here, since it has optimized version)
143using FunctionCRC32ZLib = FunctionCRC<CRC32ZLibImpl>;144// Uses CRC-32-IEEE 802.3 polynomial
145using FunctionCRC32IEEE = FunctionCRC<CRC32IEEEImpl>;146// Uses CRC-64-ECMA polynomial
147using FunctionCRC64ECMA = FunctionCRC<CRC64ECMAImpl>;148
149}
150
151REGISTER_FUNCTION(CRC)152{
153factory.registerFunction<FunctionCRC32ZLib>({}, FunctionFactory::CaseInsensitive);154factory.registerFunction<FunctionCRC32IEEE>({}, FunctionFactory::CaseInsensitive);155factory.registerFunction<FunctionCRC64ECMA>({}, FunctionFactory::CaseInsensitive);156}
157
158}
159