ClickHouse

Форк
0
158 строк · 4.5 Кб
1
#include <zlib.h>
2
#include <DataTypes/DataTypeString.h>
3
#include <Functions/FunctionFactory.h>
4
#include <Functions/FunctionStringOrArrayToT.h>
5

6

7
namespace
8
{
9

10
template <class T>
11
struct CRCBase
12
{
13
    T tab[256];
14
    explicit CRCBase(T polynomial)
15
    {
16
        for (size_t i = 0; i < 256; ++i)
17
        {
18
            T c = static_cast<T>(i);
19
            for (size_t j = 0; j < 8; ++j)
20
                c = c & 1 ? polynomial ^ (c >> 1) : c >> 1;
21
            tab[i] = c;
22
        }
23
    }
24
};
25

26
template <class T, T polynomial>
27
struct CRCImpl
28
{
29
    using ReturnType = T;
30

31
    static T makeCRC(const unsigned char *buf, size_t size)
32
    {
33
        static CRCBase<ReturnType> base(polynomial);
34

35
        T crc = 0;
36
        for (size_t i = 0; i < size; ++i)
37
            crc = base.tab[(crc ^ buf[i]) & 0xff] ^ (crc >> 8);
38
        return crc;
39
    }
40
};
41

42
constexpr UInt64 CRC64_ECMA = 0xc96c5795d7870f42ULL;
43
struct CRC64ECMAImpl : public CRCImpl<UInt64, CRC64_ECMA>
44
{
45
    static constexpr auto name = "CRC64";
46
};
47

48
constexpr UInt32 CRC32_IEEE = 0xedb88320;
49
struct CRC32IEEEImpl : public CRCImpl<UInt32, CRC32_IEEE>
50
{
51
    static constexpr auto name = "CRC32IEEE";
52
};
53

54
struct CRC32ZLibImpl
55
{
56
    using ReturnType = UInt32;
57
    static constexpr auto name = "CRC32";
58

59
    static UInt32 makeCRC(const unsigned char *buf, size_t size)
60
    {
61
        return static_cast<UInt32>(crc32_z(0L, buf, size));
62
    }
63
};
64

65
}
66

67
namespace DB
68
{
69

70
namespace ErrorCodes
71
{
72
    extern const int ILLEGAL_TYPE_OF_ARGUMENT;
73
}
74

75
namespace
76
{
77

78
template <class Impl>
79
struct CRCFunctionWrapper
80
{
81
    static constexpr auto is_fixed_to_constant = true;
82
    using ReturnType = typename Impl::ReturnType;
83

84
    static void vector(const ColumnString::Chars & data, const ColumnString::Offsets & offsets, PaddedPODArray<ReturnType> & res)
85
    {
86
        size_t size = offsets.size();
87

88
        ColumnString::Offset prev_offset = 0;
89
        for (size_t i = 0; i < size; ++i)
90
        {
91
            res[i] = doCRC(data, prev_offset, offsets[i] - prev_offset - 1);
92
            prev_offset = offsets[i];
93
        }
94
    }
95

96
    static void vectorFixedToConstant(const ColumnString::Chars & data, size_t n, ReturnType & res) { res = doCRC(data, 0, n); }
97

98
    static void vectorFixedToVector(const ColumnString::Chars & data, size_t n, PaddedPODArray<ReturnType> & res)
99
    {
100
        size_t size = data.size() / n;
101

102
        for (size_t i = 0; i < size; ++i)
103
        {
104
            res[i] = doCRC(data, i * n, n);
105
        }
106
    }
107

108
    [[noreturn]] static void array(const ColumnString::Offsets & /*offsets*/, PaddedPODArray<ReturnType> & /*res*/)
109
    {
110
        throw 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
    {
115
        throw 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
    {
120
        throw 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
    {
125
        throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Cannot apply function {} to IPv4 argument", std::string(Impl::name));
126
    }
127

128
private:
129
    static ReturnType doCRC(const ColumnString::Chars & buf, size_t offset, size_t size)
130
    {
131
        const unsigned char * p = reinterpret_cast<const unsigned char *>(buf.data()) + offset;
132
        return Impl::makeCRC(p, size);
133
    }
134
};
135

136
template <typename T>
137
using 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)
143
using FunctionCRC32ZLib = FunctionCRC<CRC32ZLibImpl>;
144
// Uses CRC-32-IEEE 802.3 polynomial
145
using FunctionCRC32IEEE = FunctionCRC<CRC32IEEEImpl>;
146
// Uses CRC-64-ECMA polynomial
147
using FunctionCRC64ECMA = FunctionCRC<CRC64ECMAImpl>;
148

149
}
150

151
REGISTER_FUNCTION(CRC)
152
{
153
    factory.registerFunction<FunctionCRC32ZLib>({}, FunctionFactory::CaseInsensitive);
154
    factory.registerFunction<FunctionCRC32IEEE>({}, FunctionFactory::CaseInsensitive);
155
    factory.registerFunction<FunctionCRC64ECMA>({}, FunctionFactory::CaseInsensitive);
156
}
157

158
}
159

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.